From c7a6fdffa69dab8350e80c8c6b12c94ec5fe13b8 Mon Sep 17 00:00:00 2001 From: Jiang Yi Date: Fri, 3 Nov 2023 17:25:37 +0800 Subject: [PATCH] Add HiSilicon SPI Controller Driver for Kunpeng SoCs Signed-off-by: Jiang Yi --- kernel.spec | 13 +- ...eporting-the-effectivly-used-speed_h.patch | 67 ++ ...vice-managed-SPI-controller-allocati.patch | 183 ++++++ ...-use-after-free-with-devm_spi_alloc_.patch | 101 +++ ...i.h-add-missing-struct-kernel-doc-en.patch | 59 ++ ...tation-devres-add-missing-SPI-helper.patch | 47 ++ ...n-SPI-Controller-Driver-for-Kunpeng-.patch | 606 ++++++++++++++++++ ...-Fix-Woverflow-warning-on-conversion.patch | 51 ++ ...spi-hisi-kunpeng-Add-debugfs-support.patch | 142 ++++ ...-Fix-the-debugfs-directory-name-inco.patch | 93 +++ series.conf | 9 + 11 files changed, 1370 insertions(+), 1 deletion(-) create mode 100644 patches/0101-spi-core-allow-reporting-the-effectivly-used-speed_h.patch create mode 100644 patches/0102-spi-Introduce-device-managed-SPI-controller-allocati.patch create mode 100644 patches/0103-spi-Fix-use-after-free-with-devm_spi_alloc_.patch create mode 100644 patches/0104-spi-linux-spi-spi.h-add-missing-struct-kernel-doc-en.patch create mode 100644 patches/0105-Documentation-devres-add-missing-SPI-helper.patch create mode 100644 patches/0106-spi-Add-HiSilicon-SPI-Controller-Driver-for-Kunpeng-.patch create mode 100644 patches/0107-spi-hisi-kunpeng-Fix-Woverflow-warning-on-conversion.patch create mode 100644 patches/0108-spi-hisi-kunpeng-Add-debugfs-support.patch create mode 100644 patches/0109-spi-hisi-kunpeng-Fix-the-debugfs-directory-name-inco.patch diff --git a/kernel.spec b/kernel.spec index 3047a91..1903cce 100644 --- a/kernel.spec +++ b/kernel.spec @@ -32,7 +32,7 @@ Name: kernel Version: 4.19.90 -Release: %{hulkrelease}.0233 +Release: %{hulkrelease}.0234 Summary: Linux Kernel License: GPLv2 URL: http://www.kernel.org/ @@ -832,6 +832,17 @@ fi %changelog +* Mon Nov 6 2023 Jiang Yi - 4.19.90-2311.1.0.0234 +- spi: hisi-kunpeng: Fix the debugfs directory name incorrect +- spi: hisi-kunpeng: Add debugfs support +- spi: hisi-kunpeng: Fix Woverflow warning on conversion +- spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs +- Documentation: devres: add missing SPI helper +- spi: : add missing struct kernel-doc entry +- spi: Fix use-after-free with devm_spi_alloc_* +- spi: Introduce device-managed SPI controller allocation +- spi: core: allow reporting the effectivly used speed_hz for a transfer + * Fri Nov 3 2023 Yu Liao - 4.19.90-2310.4.0.0233 - arm64: HWCAP: add support for AT_HWCAP2 - arm64: Expose SVE2 features for userspace diff --git a/patches/0101-spi-core-allow-reporting-the-effectivly-used-speed_h.patch b/patches/0101-spi-core-allow-reporting-the-effectivly-used-speed_h.patch new file mode 100644 index 0000000..37822db --- /dev/null +++ b/patches/0101-spi-core-allow-reporting-the-effectivly-used-speed_h.patch @@ -0,0 +1,67 @@ +From 1df3aa945b6da52d88e2bcfd53a103a55366c4d7 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sat, 23 Feb 2019 08:49:49 +0000 +Subject: [PATCH 101/109] spi: core: allow reporting the effectivly used + speed_hz for a transfer + +mainline inclusion +from mainline-v5.3-rc1 +commit 5d7e2b5ed5858fe739d4cb8ad22dcce7bd9dbe7b +category: feature +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5d7e2b5ed5858fe739d4cb8ad22dcce7bd9dbe7b + +---------------------------------------------------------------------- + +Provide a means for the spi bus driver to report the effectively used +spi clock frequency used for each spi_transfer. + +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +Signed-off-by: YunYi Yang + + Conflicts: + include/linux/spi/spi.h +--- + drivers/spi/spi.c | 1 + + include/linux/spi/spi.h | 5 +++++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index f0f21f93d293..c79bf015b4b2 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -2892,6 +2892,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) + */ + message->frame_length = 0; + list_for_each_entry(xfer, &message->transfers, transfer_list) { ++ xfer->effective_speed_hz = 0; + message->frame_length += xfer->len; + if (!xfer->bits_per_word) + xfer->bits_per_word = spi->bits_per_word; +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index a64235e05321..ec795c5304f0 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -711,6 +711,9 @@ extern void spi_res_release(struct spi_controller *ctlr, + * @delay_usecs: microseconds to delay after this transfer before + * (optionally) changing the chipselect status, then starting + * the next transfer or completing this @spi_message. ++ * @effective_speed_hz: the effective SCK-speed that was used to ++ * transfer this transfer. Set to 0 if the spi bus driver does ++ * not support it. + * @transfer_list: transfers are sequenced through @spi_message.transfers + * @tx_sg: Scatterlist for transmit, currently not for client use + * @rx_sg: Scatterlist for receive, currently not for client use +@@ -794,6 +797,8 @@ struct spi_transfer { + u16 delay_usecs; + u32 speed_hz; + ++ u32 effective_speed_hz; ++ + struct list_head transfer_list; + }; + +-- +2.23.0 + diff --git a/patches/0102-spi-Introduce-device-managed-SPI-controller-allocati.patch b/patches/0102-spi-Introduce-device-managed-SPI-controller-allocati.patch new file mode 100644 index 0000000..d974c39 --- /dev/null +++ b/patches/0102-spi-Introduce-device-managed-SPI-controller-allocati.patch @@ -0,0 +1,183 @@ +From edc0e47f43d73d9164c69688932d989971738b20 Mon Sep 17 00:00:00 2001 +From: Lukas Wunner +Date: Wed, 11 Nov 2020 20:07:10 +0100 +Subject: [PATCH 102/109] spi: Introduce device-managed SPI controller + allocation + +mainline inclusion +from mainline-v5.10-rc5 +commit 5e844cc37a5cbaa460e68f9a989d321d63088a89 +category: feature +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5e844cc37a5cbaa460e68f9a989d321d63088a89 + +---------------------------------------------------------------------- + +SPI driver probing currently comprises two steps, whereas removal +comprises only one step: + + spi_alloc_master() + spi_register_controller() + + spi_unregister_controller() + +That's because spi_unregister_controller() calls device_unregister() +instead of device_del(), thereby releasing the reference on the +spi_controller which was obtained by spi_alloc_master(). + +An SPI driver's private data is contained in the same memory allocation +as the spi_controller struct. Thus, once spi_unregister_controller() +has been called, the private data is inaccessible. But some drivers +need to access it after spi_unregister_controller() to perform further +teardown steps. + +Introduce devm_spi_alloc_master() and devm_spi_alloc_slave(), which +release a reference on the spi_controller struct only after the driver +has unbound, thereby keeping the memory allocation accessible. Change +spi_unregister_controller() to not release a reference if the +spi_controller was allocated by one of these new devm functions. + +The present commit is small enough to be backportable to stable. +It allows fixing drivers which use the private data in their ->remove() +hook after it's been freed. It also allows fixing drivers which neglect +to release a reference on the spi_controller in the probe error path. + +Long-term, most SPI drivers shall be moved over to the devm functions +introduced herein. The few that can't shall be changed in a treewide +commit to explicitly release the last reference on the controller. +That commit shall amend spi_unregister_controller() to no longer release +a reference, thereby completing the migration. + +As a result, the behaviour will be less surprising and more consistent +with subsystems such as IIO, which also includes the private data in the +allocation of the generic iio_dev struct, but calls device_del() in +iio_device_unregister(). + +Signed-off-by: Lukas Wunner +Link: https://lore.kernel.org/r/272bae2ef08abd21388c98e23729886663d19192.1605121038.git.lukas@wunner.de +Signed-off-by: Mark Brown +Signed-off-by: YunYi Yang + + Conflicts: + drivers/spi/spi.c +--- + drivers/spi/spi.c | 58 ++++++++++++++++++++++++++++++++++++++++- + include/linux/spi/spi.h | 19 ++++++++++++++ + 2 files changed, 76 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index c79bf015b4b2..aa50cc5380cf 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -2051,6 +2051,49 @@ struct spi_controller *__spi_alloc_controller(struct device *dev, + } + EXPORT_SYMBOL_GPL(__spi_alloc_controller); + ++static void devm_spi_release_controller(struct device *dev, void *ctlr) ++{ ++ spi_controller_put(*(struct spi_controller **)ctlr); ++} ++ ++/** ++ * __devm_spi_alloc_controller - resource-managed __spi_alloc_controller() ++ * @dev: physical device of SPI controller ++ * @size: how much zeroed driver-private data to allocate ++ * @slave: whether to allocate an SPI master (false) or SPI slave (true) ++ * Context: can sleep ++ * ++ * Allocate an SPI controller and automatically release a reference on it ++ * when @dev is unbound from its driver. Drivers are thus relieved from ++ * having to call spi_controller_put(). ++ * ++ * The arguments to this function are identical to __spi_alloc_controller(). ++ * ++ * Return: the SPI controller structure on success, else NULL. ++ */ ++struct spi_controller *__devm_spi_alloc_controller(struct device *dev, ++ unsigned int size, ++ bool slave) ++{ ++ struct spi_controller **ptr, *ctlr; ++ ++ ptr = devres_alloc(devm_spi_release_controller, sizeof(*ptr), ++ GFP_KERNEL); ++ if (!ptr) ++ return NULL; ++ ++ ctlr = __spi_alloc_controller(dev, size, slave); ++ if (ctlr) { ++ *ptr = ctlr; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ ++ return ctlr; ++} ++EXPORT_SYMBOL_GPL(__devm_spi_alloc_controller); ++ + static int __spi_register_controller(struct spi_controller *ctlr) + { + int nb, i, *cs; +@@ -2301,6 +2344,11 @@ int devm_spi_register_controller(struct device *dev, + } + EXPORT_SYMBOL_GPL(devm_spi_register_controller); + ++static int devm_spi_match_controller(struct device *dev, void *res, void *ctlr) ++{ ++ return *(struct spi_controller **)res == ctlr; ++} ++ + static int __unregister(struct device *dev, void *null) + { + spi_unregister_device(to_spi_device(dev)); +@@ -2342,7 +2390,15 @@ void spi_unregister_controller(struct spi_controller *ctlr) + list_del(&ctlr->list); + mutex_unlock(&board_lock); + +- device_unregister(&ctlr->dev); ++ device_del(&ctlr->dev); ++ ++ /* Release the last reference on the controller if its driver ++ * has not yet been converted to devm_spi_alloc_master/slave(). ++ */ ++ if (!devres_find(ctlr->dev.parent, devm_spi_release_controller, ++ devm_spi_match_controller, ctlr)) ++ put_device(&ctlr->dev); ++ + /* free bus id */ + mutex_lock(&board_lock); + if (found == ctlr) +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index ec795c5304f0..085c8e0e0864 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -634,6 +634,25 @@ static inline struct spi_controller *spi_alloc_slave(struct device *host, + return __spi_alloc_controller(host, size, true); + } + ++struct spi_controller *__devm_spi_alloc_controller(struct device *dev, ++ unsigned int size, ++ bool slave); ++ ++static inline struct spi_controller *devm_spi_alloc_master(struct device *dev, ++ unsigned int size) ++{ ++ return __devm_spi_alloc_controller(dev, size, false); ++} ++ ++static inline struct spi_controller *devm_spi_alloc_slave(struct device *dev, ++ unsigned int size) ++{ ++ if (!IS_ENABLED(CONFIG_SPI_SLAVE)) ++ return NULL; ++ ++ return __devm_spi_alloc_controller(dev, size, true); ++} ++ + extern int spi_register_controller(struct spi_controller *ctlr); + extern int devm_spi_register_controller(struct device *dev, + struct spi_controller *ctlr); +-- +2.23.0 + diff --git a/patches/0103-spi-Fix-use-after-free-with-devm_spi_alloc_.patch b/patches/0103-spi-Fix-use-after-free-with-devm_spi_alloc_.patch new file mode 100644 index 0000000..35f4da4 --- /dev/null +++ b/patches/0103-spi-Fix-use-after-free-with-devm_spi_alloc_.patch @@ -0,0 +1,101 @@ +From c52d8916b34838e6d6dcd72b7712e6aa28c8daf4 Mon Sep 17 00:00:00 2001 +From: "William A. Kennington III" +Date: Wed, 7 Apr 2021 02:55:27 -0700 +Subject: [PATCH 103/109] spi: Fix use-after-free with devm_spi_alloc_* + +mainline inclusion +from mainline-v5.13-rc1 +commit 794aaf01444d4e765e2b067cba01cc69c1c68ed9 +category: bugfix +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=794aaf01444d4e765e2b067cba01cc69c1c68ed9 + +---------------------------------------------------------------------- + +We can't rely on the contents of the devres list during +spi_unregister_controller(), as the list is already torn down at the +time we perform devres_find() for devm_spi_release_controller. This +causes devices registered with devm_spi_alloc_{master,slave}() to be +mistakenly identified as legacy, non-devm managed devices and have their +reference counters decremented below 0. + +------------[ cut here ]------------ +WARNING: CPU: 1 PID: 660 at lib/refcount.c:28 refcount_warn_saturate+0x108/0x174 +[] (refcount_warn_saturate) from [] (kobject_put+0x90/0x98) +[] (kobject_put) from [] (put_device+0x20/0x24) + r4:b6700140 +[] (put_device) from [] (devm_spi_release_controller+0x3c/0x40) +[] (devm_spi_release_controller) from [] (release_nodes+0x84/0xc4) + r5:b6700180 r4:b6700100 +[] (release_nodes) from [] (devres_release_all+0x5c/0x60) + r8:b1638c54 r7:b117ad94 r6:b1638c10 r5:b117ad94 r4:b163dc10 +[] (devres_release_all) from [] (__device_release_driver+0x144/0x1ec) + r5:b117ad94 r4:b163dc10 +[] (__device_release_driver) from [] (device_driver_detach+0x84/0xa0) + r9:00000000 r8:00000000 r7:b117ad94 r6:b163dc54 r5:b1638c10 r4:b163dc10 +[] (device_driver_detach) from [] (unbind_store+0xe4/0xf8) + +Instead, determine the devm allocation state as a flag on the +controller which is guaranteed to be stable during cleanup. + +Fixes: 5e844cc37a5c ("spi: Introduce device-managed SPI controller allocation") +Signed-off-by: William A. Kennington III +Link: https://lore.kernel.org/r/20210407095527.2771582-1-wak@google.com +Signed-off-by: Mark Brown +Signed-off-by: Jiang Yi +--- + drivers/spi/spi.c | 9 ++------- + include/linux/spi/spi.h | 3 +++ + 2 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index aa50cc5380cf..d2334bfae076 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -2084,6 +2084,7 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev, + + ctlr = __spi_alloc_controller(dev, size, slave); + if (ctlr) { ++ ctlr->devm_allocated = true; + *ptr = ctlr; + devres_add(dev, ptr); + } else { +@@ -2344,11 +2345,6 @@ int devm_spi_register_controller(struct device *dev, + } + EXPORT_SYMBOL_GPL(devm_spi_register_controller); + +-static int devm_spi_match_controller(struct device *dev, void *res, void *ctlr) +-{ +- return *(struct spi_controller **)res == ctlr; +-} +- + static int __unregister(struct device *dev, void *null) + { + spi_unregister_device(to_spi_device(dev)); +@@ -2395,8 +2391,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) + /* Release the last reference on the controller if its driver + * has not yet been converted to devm_spi_alloc_master/slave(). + */ +- if (!devres_find(ctlr->dev.parent, devm_spi_release_controller, +- devm_spi_match_controller, ctlr)) ++ if (!ctlr->devm_allocated) + put_device(&ctlr->dev); + + /* free bus id */ +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index 085c8e0e0864..3e51ae8bb26e 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -450,6 +450,9 @@ struct spi_controller { + + #define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ + ++ /* flag indicating this is a non-devres managed controller */ ++ bool devm_allocated; ++ + /* flag indicating this is an SPI slave controller */ + bool slave; + +-- +2.23.0 + diff --git a/patches/0104-spi-linux-spi-spi.h-add-missing-struct-kernel-doc-en.patch b/patches/0104-spi-linux-spi-spi.h-add-missing-struct-kernel-doc-en.patch new file mode 100644 index 0000000..7a0f3aa --- /dev/null +++ b/patches/0104-spi-linux-spi-spi.h-add-missing-struct-kernel-doc-en.patch @@ -0,0 +1,59 @@ +From 7c836f45222529e7ad99ae667b099ec747e87bd6 Mon Sep 17 00:00:00 2001 +From: Randy Dunlap +Date: Mon, 28 Jun 2021 14:05:20 -0700 +Subject: [PATCH 104/109] spi: : add missing struct kernel-doc + entry + +mainline inclusion +from mainline-v5.15-rc1 +commit 8dd591ad0104593f315b6b2ab636a18c002f7d86 +category: bugfix +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8dd591ad0104593f315b6b2ab636a18c002f7d86 + +---------------------------------------------------------------------- + +Fix kernel-doc warning in spi.h by adding the missing kernel-doc entry +and also correct the original comment so that they both indicate the +correct polarity of the flag. + +../include/linux/spi/spi.h:673: warning: Function parameter or member 'devm_allocated' not described in 'spi_controller' + +Fixes: 794aaf01444d ("spi: Fix use-after-free with devm_spi_alloc_*") +Signed-off-by: Randy Dunlap +Cc: William A. Kennington III +Cc: Mark Brown +Cc: linux-spi@vger.kernel.org +Cc: Lukas Wunner +Reviewed-by: Lukas Wunner +Link: https://lore.kernel.org/r/20210628210520.5712-1-rdunlap@infradead.org +Signed-off-by: Mark Brown +Signed-off-by: Jiang Yi +--- + include/linux/spi/spi.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index 3e51ae8bb26e..1c0a0fa34586 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -314,6 +314,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) + * @max_speed_hz: Highest supported transfer speed + * @flags: other constraints relevant to this driver + * @slave: indicates that this is an SPI slave controller ++ * @devm_allocated: whether the allocation of this struct is devres-managed + * @max_transfer_size: function that returns the max transfer size for + * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used. + * @max_message_size: function that returns the max message size for +@@ -450,7 +451,7 @@ struct spi_controller { + + #define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ + +- /* flag indicating this is a non-devres managed controller */ ++ /* flag indicating if the allocation of this struct is devres-managed */ + bool devm_allocated; + + /* flag indicating this is an SPI slave controller */ +-- +2.23.0 + diff --git a/patches/0105-Documentation-devres-add-missing-SPI-helper.patch b/patches/0105-Documentation-devres-add-missing-SPI-helper.patch new file mode 100644 index 0000000..6e040bd --- /dev/null +++ b/patches/0105-Documentation-devres-add-missing-SPI-helper.patch @@ -0,0 +1,47 @@ +From 651036c4c9f6e429306275103b6546a61a8362f7 Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Fri, 23 Sep 2022 22:18:03 +0800 +Subject: [PATCH 105/109] Documentation: devres: add missing SPI helper + +mainline inclusion +from mainline-v6.1-rc1 +commit 49beeea7ebdb1d86ba8465e5021d72ad9e9474b8 +category: bugfix +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=49beeea7ebdb1d86ba8465e5021d72ad9e9474b8 + +---------------------------------------------------------------------- + +Add devm_spi_alloc_master() and devm_spi_alloc_slave() to devres.rst. +They are introduced by +commit 5e844cc37a5c ("spi: Introduce device-managed SPI controller allocation"). + +Signed-off-by: Yang Yingliang +Reviewed-by: Lukas Wunner +Link: https://lore.kernel.org/r/20220923141803.75734-1-yangyingliang@huawei.com +Signed-off-by: Jonathan Corbet + +Conflicts: + Documentation/driver-api/driver-model/devres.rst + +Signed-off-by: Jiang Yi +--- + Documentation/driver-model/devres.txt | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt +index 43681ca0837f..c9b019c06f3b 100644 +--- a/Documentation/driver-model/devres.txt ++++ b/Documentation/driver-model/devres.txt +@@ -392,6 +392,8 @@ SLAVE DMA ENGINE + devm_acpi_dma_controller_register() + + SPI ++ devm_spi_alloc_master() ++ devm_spi_alloc_slave() + devm_spi_register_master() + + WATCHDOG +-- +2.23.0 + diff --git a/patches/0106-spi-Add-HiSilicon-SPI-Controller-Driver-for-Kunpeng-.patch b/patches/0106-spi-Add-HiSilicon-SPI-Controller-Driver-for-Kunpeng-.patch new file mode 100644 index 0000000..33fc6ce --- /dev/null +++ b/patches/0106-spi-Add-HiSilicon-SPI-Controller-Driver-for-Kunpeng-.patch @@ -0,0 +1,606 @@ +From 7df3c74b37355c06afee870ace0a8eb1491130dc Mon Sep 17 00:00:00 2001 +From: Jay Fang +Date: Mon, 9 Aug 2021 20:18:16 +0800 +Subject: [PATCH 106/109] spi: Add HiSilicon SPI Controller Driver for Kunpeng + SoCs + +mainline inclusion +from mainline-v5.13-rc1 +commit c770d8631e1810d8f1ce21b18ad5dd67eeb39e5c +category: feature +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c770d8631e1810d8f1ce21b18ad5dd67eeb39e5c + +---------------------------------------------------------------------- + +This driver supports SPI Controller for HiSilicon Kunpeng SoCs. This +driver supports SPI operations using FIFO mode of transfer. + +DMA is not supported, and we just use IRQ mode for operation completion +notification. + +Only ACPI firmware is supported. + +Signed-off-by: Jay Fang +Link: https://lore.kernel.org/r/1616836200-45827-1-git-send-email-f.fangjian@huawei.com +Signed-off-by: Mark Brown +Reviewed-by: Chengwen Feng +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang + + Conflicts: + MAINTAINERS + drivers/spi/Kconfig + drivers/spi/Makefile +--- + MAINTAINERS | 7 + + drivers/spi/Kconfig | 10 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-hisi-kunpeng.c | 504 +++++++++++++++++++++++++++++++++ + 4 files changed, 522 insertions(+) + create mode 100644 drivers/spi/spi-hisi-kunpeng.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 3ad1e1b1da4a..29d7531d0595 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -6679,6 +6679,13 @@ S: Maintained + F: drivers/infiniband/hw/hns/Makefile + F: drivers/infiniband/hw/hns/roce-customer/ + ++HISILICON SPI Controller DRIVER FOR KUNPENG SOCS ++M: Jay Fang ++L: linux-spi@vger.kernel.org ++S: Maintained ++W: http://www.hisilicon.com ++F: drivers/spi/spi-hisi-kunpeng.c ++ + HISILICON WARPDRIVE USER + M: Zaibo Xu + M: Zhou Wang +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 0a7fd56c1ed9..7bfdf8d2cbf9 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -251,6 +251,16 @@ config SPI_FSL_LPSPI + help + This enables Freescale i.MX LPSPI controllers in master mode. + ++config SPI_HISI_KUNPENG ++ tristate "HiSilicon SPI Controller for Kunpeng SoCs" ++ depends on (ARM64 && ACPI) || COMPILE_TEST ++ help ++ This enables support for HiSilicon SPI controller found on ++ Kunpeng SoCs. ++ ++ This driver can also be built as a module. If so, the module ++ will be called hisi-kunpeng-spi. ++ + config SPI_GPIO + tristate "GPIO-based bitbanging SPI Master" + depends on GPIOLIB || COMPILE_TEST +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index a90d55970036..49c499d5e1a2 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o + obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o + obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o + obj-$(CONFIG_SPI_GPIO) += spi-gpio.o ++obj-$(CONFIG_SPI_HISI_KUNPENG) += spi-hisi-kunpeng.o + obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o + obj-$(CONFIG_SPI_IMX) += spi-imx.o + obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +new file mode 100644 +index 000000000000..ea87b4fba5d6 +--- /dev/null ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -0,0 +1,504 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// ++// HiSilicon SPI Controller Driver for Kunpeng SoCs ++// ++// Copyright (c) 2021 HiSilicon Technologies Co., Ltd. ++// Author: Jay Fang ++// ++// This code is based on spi-dw-core.c. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Register offsets */ ++#define HISI_SPI_CSCR 0x00 /* cs control register */ ++#define HISI_SPI_CR 0x04 /* spi common control register */ ++#define HISI_SPI_ENR 0x08 /* spi enable register */ ++#define HISI_SPI_FIFOC 0x0c /* fifo level control register */ ++#define HISI_SPI_IMR 0x10 /* interrupt mask register */ ++#define HISI_SPI_DIN 0x14 /* data in register */ ++#define HISI_SPI_DOUT 0x18 /* data out register */ ++#define HISI_SPI_SR 0x1c /* status register */ ++#define HISI_SPI_RISR 0x20 /* raw interrupt status register */ ++#define HISI_SPI_ISR 0x24 /* interrupt status register */ ++#define HISI_SPI_ICR 0x28 /* interrupt clear register */ ++#define HISI_SPI_VERSION 0xe0 /* version register */ ++ ++/* Bit fields in HISI_SPI_CR */ ++#define CR_LOOP_MASK GENMASK(1, 1) ++#define CR_CPOL_MASK GENMASK(2, 2) ++#define CR_CPHA_MASK GENMASK(3, 3) ++#define CR_DIV_PRE_MASK GENMASK(11, 4) ++#define CR_DIV_POST_MASK GENMASK(19, 12) ++#define CR_BPW_MASK GENMASK(24, 20) ++#define CR_SPD_MODE_MASK GENMASK(25, 25) ++ ++/* Bit fields in HISI_SPI_FIFOC */ ++#define FIFOC_TX_MASK GENMASK(5, 3) ++#define FIFOC_RX_MASK GENMASK(11, 9) ++ ++/* Bit fields in HISI_SPI_IMR, 4 bits */ ++#define IMR_RXOF BIT(0) /* Receive Overflow */ ++#define IMR_RXTO BIT(1) /* Receive Timeout */ ++#define IMR_RX BIT(2) /* Receive */ ++#define IMR_TX BIT(3) /* Transmit */ ++#define IMR_MASK (IMR_RXOF | IMR_RXTO | IMR_RX | IMR_TX) ++ ++/* Bit fields in HISI_SPI_SR, 5 bits */ ++#define SR_TXE BIT(0) /* Transmit FIFO empty */ ++#define SR_TXNF BIT(1) /* Transmit FIFO not full */ ++#define SR_RXNE BIT(2) /* Receive FIFO not empty */ ++#define SR_RXF BIT(3) /* Receive FIFO full */ ++#define SR_BUSY BIT(4) /* Busy Flag */ ++ ++/* Bit fields in HISI_SPI_ISR, 4 bits */ ++#define ISR_RXOF BIT(0) /* Receive Overflow */ ++#define ISR_RXTO BIT(1) /* Receive Timeout */ ++#define ISR_RX BIT(2) /* Receive */ ++#define ISR_TX BIT(3) /* Transmit */ ++#define ISR_MASK (ISR_RXOF | ISR_RXTO | ISR_RX | ISR_TX) ++ ++/* Bit fields in HISI_SPI_ICR, 2 bits */ ++#define ICR_RXOF BIT(0) /* Receive Overflow */ ++#define ICR_RXTO BIT(1) /* Receive Timeout */ ++#define ICR_MASK (ICR_RXOF | ICR_RXTO) ++ ++#define DIV_POST_MAX 0xFF ++#define DIV_POST_MIN 0x00 ++#define DIV_PRE_MAX 0xFE ++#define DIV_PRE_MIN 0x02 ++#define CLK_DIV_MAX ((1 + DIV_POST_MAX) * DIV_PRE_MAX) ++#define CLK_DIV_MIN ((1 + DIV_POST_MIN) * DIV_PRE_MIN) ++ ++#define DEFAULT_NUM_CS 1 ++ ++#define HISI_SPI_WAIT_TIMEOUT_MS 10UL ++ ++enum hisi_spi_rx_level_trig { ++ HISI_SPI_RX_1, ++ HISI_SPI_RX_4, ++ HISI_SPI_RX_8, ++ HISI_SPI_RX_16, ++ HISI_SPI_RX_32, ++ HISI_SPI_RX_64, ++ HISI_SPI_RX_128 ++}; ++ ++enum hisi_spi_tx_level_trig { ++ HISI_SPI_TX_1_OR_LESS, ++ HISI_SPI_TX_4_OR_LESS, ++ HISI_SPI_TX_8_OR_LESS, ++ HISI_SPI_TX_16_OR_LESS, ++ HISI_SPI_TX_32_OR_LESS, ++ HISI_SPI_TX_64_OR_LESS, ++ HISI_SPI_TX_128_OR_LESS ++}; ++ ++enum hisi_spi_frame_n_bytes { ++ HISI_SPI_N_BYTES_NULL, ++ HISI_SPI_N_BYTES_U8, ++ HISI_SPI_N_BYTES_U16, ++ HISI_SPI_N_BYTES_U32 = 4 ++}; ++ ++/* Slave spi_dev related */ ++struct hisi_chip_data { ++ u32 cr; ++ u32 speed_hz; /* baud rate */ ++ u16 clk_div; /* baud rate divider */ ++ ++ /* clk_div = (1 + div_post) * div_pre */ ++ u8 div_post; /* value from 0 to 255 */ ++ u8 div_pre; /* value from 2 to 254 (even only!) */ ++}; ++ ++struct hisi_spi { ++ struct device *dev; ++ ++ void __iomem *regs; ++ int irq; ++ u32 fifo_len; /* depth of the FIFO buffer */ ++ ++ /* Current message transfer state info */ ++ const void *tx; ++ unsigned int tx_len; ++ void *rx; ++ unsigned int rx_len; ++ u8 n_bytes; /* current is a 1/2/4 bytes op */ ++}; ++ ++static u32 hisi_spi_busy(struct hisi_spi *hs) ++{ ++ return readl(hs->regs + HISI_SPI_SR) & SR_BUSY; ++} ++ ++static u32 hisi_spi_rx_not_empty(struct hisi_spi *hs) ++{ ++ return readl(hs->regs + HISI_SPI_SR) & SR_RXNE; ++} ++ ++static u32 hisi_spi_tx_not_full(struct hisi_spi *hs) ++{ ++ return readl(hs->regs + HISI_SPI_SR) & SR_TXNF; ++} ++ ++static void hisi_spi_flush_fifo(struct hisi_spi *hs) ++{ ++ unsigned long limit = loops_per_jiffy << 1; ++ ++ do { ++ while (hisi_spi_rx_not_empty(hs)) ++ readl(hs->regs + HISI_SPI_DOUT); ++ } while (hisi_spi_busy(hs) && limit--); ++} ++ ++/* Disable the controller and all interrupts */ ++static void hisi_spi_disable(struct hisi_spi *hs) ++{ ++ writel(0, hs->regs + HISI_SPI_ENR); ++ writel(IMR_MASK, hs->regs + HISI_SPI_IMR); ++ writel(ICR_MASK, hs->regs + HISI_SPI_ICR); ++} ++ ++static u8 hisi_spi_n_bytes(struct spi_transfer *transfer) ++{ ++ if (transfer->bits_per_word <= 8) ++ return HISI_SPI_N_BYTES_U8; ++ else if (transfer->bits_per_word <= 16) ++ return HISI_SPI_N_BYTES_U16; ++ else ++ return HISI_SPI_N_BYTES_U32; ++} ++ ++static void hisi_spi_reader(struct hisi_spi *hs) ++{ ++ u32 max = min_t(u32, hs->rx_len, hs->fifo_len); ++ u32 rxw; ++ ++ while (hisi_spi_rx_not_empty(hs) && max--) { ++ rxw = readl(hs->regs + HISI_SPI_DOUT); ++ /* Check the transfer's original "rx" is not null */ ++ if (hs->rx) { ++ switch (hs->n_bytes) { ++ case HISI_SPI_N_BYTES_U8: ++ *(u8 *)(hs->rx) = rxw; ++ break; ++ case HISI_SPI_N_BYTES_U16: ++ *(u16 *)(hs->rx) = rxw; ++ break; ++ case HISI_SPI_N_BYTES_U32: ++ *(u32 *)(hs->rx) = rxw; ++ break; ++ } ++ hs->rx += hs->n_bytes; ++ } ++ --hs->rx_len; ++ } ++} ++ ++static void hisi_spi_writer(struct hisi_spi *hs) ++{ ++ u32 max = min_t(u32, hs->tx_len, hs->fifo_len); ++ u32 txw = 0; ++ ++ while (hisi_spi_tx_not_full(hs) && max--) { ++ /* Check the transfer's original "tx" is not null */ ++ if (hs->tx) { ++ switch (hs->n_bytes) { ++ case HISI_SPI_N_BYTES_U8: ++ txw = *(u8 *)(hs->tx); ++ break; ++ case HISI_SPI_N_BYTES_U16: ++ txw = *(u16 *)(hs->tx); ++ break; ++ case HISI_SPI_N_BYTES_U32: ++ txw = *(u32 *)(hs->tx); ++ break; ++ } ++ hs->tx += hs->n_bytes; ++ } ++ writel(txw, hs->regs + HISI_SPI_DIN); ++ --hs->tx_len; ++ } ++} ++ ++static void __hisi_calc_div_reg(struct hisi_chip_data *chip) ++{ ++ chip->div_pre = DIV_PRE_MAX; ++ while (chip->div_pre >= DIV_PRE_MIN) { ++ if (chip->clk_div % chip->div_pre == 0) ++ break; ++ ++ chip->div_pre -= 2; ++ } ++ ++ if (chip->div_pre > chip->clk_div) ++ chip->div_pre = chip->clk_div; ++ ++ chip->div_post = (chip->clk_div / chip->div_pre) - 1; ++} ++ ++static u32 hisi_calc_effective_speed(struct spi_controller *master, ++ struct hisi_chip_data *chip, u32 speed_hz) ++{ ++ u32 effective_speed; ++ ++ /* Note clock divider doesn't support odd numbers */ ++ chip->clk_div = DIV_ROUND_UP(master->max_speed_hz, speed_hz) + 1; ++ chip->clk_div &= 0xfffe; ++ if (chip->clk_div > CLK_DIV_MAX) ++ chip->clk_div = CLK_DIV_MAX; ++ ++ effective_speed = master->max_speed_hz / chip->clk_div; ++ if (chip->speed_hz != effective_speed) { ++ __hisi_calc_div_reg(chip); ++ chip->speed_hz = effective_speed; ++ } ++ ++ return effective_speed; ++} ++ ++static u32 hisi_spi_prepare_cr(struct spi_device *spi) ++{ ++ u32 cr = FIELD_PREP(CR_SPD_MODE_MASK, 1); ++ ++ cr |= FIELD_PREP(CR_CPHA_MASK, (spi->mode & SPI_CPHA) ? 1 : 0); ++ cr |= FIELD_PREP(CR_CPOL_MASK, (spi->mode & SPI_CPOL) ? 1 : 0); ++ cr |= FIELD_PREP(CR_LOOP_MASK, (spi->mode & SPI_LOOP) ? 1 : 0); ++ ++ return cr; ++} ++ ++static void hisi_spi_hw_init(struct hisi_spi *hs) ++{ ++ hisi_spi_disable(hs); ++ ++ /* FIFO default config */ ++ writel(FIELD_PREP(FIFOC_TX_MASK, HISI_SPI_TX_64_OR_LESS) | ++ FIELD_PREP(FIFOC_RX_MASK, HISI_SPI_RX_16), ++ hs->regs + HISI_SPI_FIFOC); ++ ++ hs->fifo_len = 256; ++} ++ ++static irqreturn_t hisi_spi_irq(int irq, void *dev_id) ++{ ++ struct spi_controller *master = dev_id; ++ struct hisi_spi *hs = spi_controller_get_devdata(master); ++ u32 irq_status = readl(hs->regs + HISI_SPI_ISR) & ISR_MASK; ++ ++ if (!irq_status) ++ return IRQ_NONE; ++ ++ if (!master->cur_msg) ++ return IRQ_HANDLED; ++ ++ /* Error handling */ ++ if (irq_status & ISR_RXOF) { ++ dev_err(hs->dev, "interrupt_transfer: fifo overflow\n"); ++ master->cur_msg->status = -EIO; ++ goto finalize_transfer; ++ } ++ ++ /* ++ * Read data from the Rx FIFO every time. If there is ++ * nothing left to receive, finalize the transfer. ++ */ ++ hisi_spi_reader(hs); ++ if (!hs->rx_len) ++ goto finalize_transfer; ++ ++ /* Send data out when Tx FIFO IRQ triggered */ ++ if (irq_status & ISR_TX) ++ hisi_spi_writer(hs); ++ ++ return IRQ_HANDLED; ++ ++finalize_transfer: ++ hisi_spi_disable(hs); ++ spi_finalize_current_transfer(master); ++ return IRQ_HANDLED; ++} ++ ++static int hisi_spi_transfer_one(struct spi_controller *master, ++ struct spi_device *spi, struct spi_transfer *transfer) ++{ ++ struct hisi_spi *hs = spi_controller_get_devdata(master); ++ struct hisi_chip_data *chip = spi_get_ctldata(spi); ++ u32 cr = chip->cr; ++ ++ /* Update per transfer options for speed and bpw */ ++ transfer->effective_speed_hz = ++ hisi_calc_effective_speed(master, chip, transfer->speed_hz); ++ cr |= FIELD_PREP(CR_DIV_PRE_MASK, chip->div_pre); ++ cr |= FIELD_PREP(CR_DIV_POST_MASK, chip->div_post); ++ cr |= FIELD_PREP(CR_BPW_MASK, transfer->bits_per_word - 1); ++ writel(cr, hs->regs + HISI_SPI_CR); ++ ++ hisi_spi_flush_fifo(hs); ++ ++ hs->n_bytes = hisi_spi_n_bytes(transfer); ++ hs->tx = transfer->tx_buf; ++ hs->tx_len = transfer->len / hs->n_bytes; ++ hs->rx = transfer->rx_buf; ++ hs->rx_len = hs->tx_len; ++ ++ /* ++ * Ensure that the transfer data above has been updated ++ * before the interrupt to start. ++ */ ++ smp_mb(); ++ ++ /* Enable all interrupts and the controller */ ++ writel(~IMR_MASK, hs->regs + HISI_SPI_IMR); ++ writel(1, hs->regs + HISI_SPI_ENR); ++ ++ return 1; ++} ++ ++static void hisi_spi_handle_err(struct spi_controller *master, ++ struct spi_message *msg) ++{ ++ struct hisi_spi *hs = spi_controller_get_devdata(master); ++ ++ hisi_spi_disable(hs); ++ ++ /* ++ * Wait for interrupt handler that is ++ * already in timeout to complete. ++ */ ++ msleep(HISI_SPI_WAIT_TIMEOUT_MS); ++} ++ ++static int hisi_spi_setup(struct spi_device *spi) ++{ ++ struct hisi_chip_data *chip; ++ ++ /* Only alloc on first setup */ ++ chip = spi_get_ctldata(spi); ++ if (!chip) { ++ chip = kzalloc(sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ spi_set_ctldata(spi, chip); ++ } ++ ++ chip->cr = hisi_spi_prepare_cr(spi); ++ ++ return 0; ++} ++ ++static void hisi_spi_cleanup(struct spi_device *spi) ++{ ++ struct hisi_chip_data *chip = spi_get_ctldata(spi); ++ ++ kfree(chip); ++ spi_set_ctldata(spi, NULL); ++} ++ ++static int hisi_spi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct spi_controller *master; ++ struct hisi_spi *hs; ++ int ret, irq; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ master = devm_spi_alloc_master(dev, sizeof(*hs)); ++ if (!master) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, master); ++ ++ hs = spi_controller_get_devdata(master); ++ hs->dev = dev; ++ hs->irq = irq; ++ ++ hs->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(hs->regs)) ++ return PTR_ERR(hs->regs); ++ ++ /* Specify maximum SPI clocking speed (master only) by firmware */ ++ ret = device_property_read_u32(dev, "spi-max-frequency", ++ &master->max_speed_hz); ++ if (ret) { ++ dev_err(dev, "failed to get max SPI clocking speed, ret=%d\n", ++ ret); ++ return -EINVAL; ++ } ++ ++ ret = device_property_read_u16(dev, "num-cs", ++ &master->num_chipselect); ++ if (ret) ++ master->num_chipselect = DEFAULT_NUM_CS; ++ ++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; ++ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); ++ master->bus_num = pdev->id; ++ master->setup = hisi_spi_setup; ++ master->cleanup = hisi_spi_cleanup; ++ master->transfer_one = hisi_spi_transfer_one; ++ master->handle_err = hisi_spi_handle_err; ++ master->dev.fwnode = dev->fwnode; ++ ++ hisi_spi_hw_init(hs); ++ ++ ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev), ++ master); ++ if (ret < 0) { ++ dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret); ++ return ret; ++ } ++ ++ ret = spi_register_controller(master); ++ if (ret) { ++ dev_err(dev, "failed to register spi master, ret=%d\n", ret); ++ return ret; ++ } ++ ++ dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", ++ readl(hs->regs + HISI_SPI_VERSION), ++ master->max_speed_hz / 1000); ++ ++ return 0; ++} ++ ++static int hisi_spi_remove(struct platform_device *pdev) ++{ ++ struct spi_controller *master = platform_get_drvdata(pdev); ++ ++ spi_unregister_controller(master); ++ ++ return 0; ++} ++ ++static const struct acpi_device_id hisi_spi_acpi_match[] = { ++ {"HISI03E1", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match); ++ ++static struct platform_driver hisi_spi_driver = { ++ .probe = hisi_spi_probe, ++ .remove = hisi_spi_remove, ++ .driver = { ++ .name = "hisi-kunpeng-spi", ++ .acpi_match_table = hisi_spi_acpi_match, ++ }, ++}; ++module_platform_driver(hisi_spi_driver); ++ ++MODULE_AUTHOR("Jay Fang "); ++MODULE_DESCRIPTION("HiSilicon SPI Controller Driver for Kunpeng SoCs"); ++MODULE_LICENSE("GPL v2"); +-- +2.23.0 + diff --git a/patches/0107-spi-hisi-kunpeng-Fix-Woverflow-warning-on-conversion.patch b/patches/0107-spi-hisi-kunpeng-Fix-Woverflow-warning-on-conversion.patch new file mode 100644 index 0000000..60b7c8b --- /dev/null +++ b/patches/0107-spi-hisi-kunpeng-Fix-Woverflow-warning-on-conversion.patch @@ -0,0 +1,51 @@ +From 95f7eaa29a23fb4d0a47962a43f6d72db89b03a7 Mon Sep 17 00:00:00 2001 +From: Jay Fang +Date: Mon, 9 Aug 2021 20:18:17 +0800 +Subject: [PATCH 107/109] spi: hisi-kunpeng: Fix Woverflow warning on + conversion + +mainline inclusion +from mainline-v5.13-rc1 +commit 9a446cf97af70ee81ba177703b67ac4955a5edcc +category: bugfix +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9a446cf97af70ee81ba177703b67ac4955a5edcc + +---------------------------------------------------------------------- + +Fix warning Woverflow on type conversion reported on x86_64: + + drivers/spi/spi-hisi-kunpeng.c:361:9: warning: conversion from 'long unsigned int' to 'u32' + {aka 'unsigned int'} changes value from '18446744073709551600' to '4294967280' [-Woverflow] + +The registers are 32 bit, so fix by casting to u32. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Cc: Stephen Rothwell +Reported-by: kernel test robot +Signed-off-by: Jay Fang +Link: https://lore.kernel.org/r/1617762660-54681-1-git-send-email-f.fangjian@huawei.com +Signed-off-by: Mark Brown +Reviewed-by: Chengwen Feng +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/spi/spi-hisi-kunpeng.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index ea87b4fba5d6..c0db9b5e37ea 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -358,7 +358,7 @@ static int hisi_spi_transfer_one(struct spi_controller *master, + smp_mb(); + + /* Enable all interrupts and the controller */ +- writel(~IMR_MASK, hs->regs + HISI_SPI_IMR); ++ writel(~(u32)IMR_MASK, hs->regs + HISI_SPI_IMR); + writel(1, hs->regs + HISI_SPI_ENR); + + return 1; +-- +2.23.0 + diff --git a/patches/0108-spi-hisi-kunpeng-Add-debugfs-support.patch b/patches/0108-spi-hisi-kunpeng-Add-debugfs-support.patch new file mode 100644 index 0000000..e37e741 --- /dev/null +++ b/patches/0108-spi-hisi-kunpeng-Add-debugfs-support.patch @@ -0,0 +1,142 @@ +From 595343f586ead33c62480e1369d1ba3f22f908a0 Mon Sep 17 00:00:00 2001 +From: Jay Fang +Date: Tue, 19 Apr 2022 17:06:40 +0800 +Subject: [PATCH 108/109] spi: hisi-kunpeng: Add debugfs support + +mainline inclusion +from mainline-v5.14-rc1 +commit 2b2142f247ebeef74aaadc1a646261c19627fd7e +category: feature +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2b2142f247ebeef74aaadc1a646261c19627fd7e + +----------------------------------------------------------------------- + +This patch uses debugfs_regset32 interface to create the registers dump +file. Use it instead of creating a generic debugfs file with manually +written read callback function. + +With these entries, users can check all the SPI controller registers +during run time. + +Signed-off-by: Jay Fang +Link: https://lore.kernel.org/r/1622789718-13977-1-git-send-email-f.fangjian@huawei.com +Signed-off-by: Mark Brown +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/spi/spi-hisi-kunpeng.c | 51 +++++++++++++++++++++++++++++++++- + 1 file changed, 50 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index c0db9b5e37ea..4595044a530b 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -9,6 +9,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -126,6 +127,7 @@ struct hisi_spi { + void __iomem *regs; + int irq; + u32 fifo_len; /* depth of the FIFO buffer */ ++ u16 bus_num; + + /* Current message transfer state info */ + const void *tx; +@@ -133,8 +135,49 @@ struct hisi_spi { + void *rx; + unsigned int rx_len; + u8 n_bytes; /* current is a 1/2/4 bytes op */ ++ ++ struct dentry *debugfs; ++ struct debugfs_regset32 regset; ++}; ++ ++#define HISI_SPI_DBGFS_REG(_name, _off) \ ++{ \ ++ .name = _name, \ ++ .offset = _off, \ ++} ++ ++static const struct debugfs_reg32 hisi_spi_regs[] = { ++ HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR), ++ HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR), ++ HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR), ++ HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC), ++ HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR), ++ HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN), ++ HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT), ++ HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR), ++ HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR), ++ HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR), ++ HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR), ++ HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION), + }; + ++static int hisi_spi_debugfs_init(struct hisi_spi *hs) ++{ ++ char name[32]; ++ ++ snprintf(name, 32, "hisi_spi%d", hs->bus_num); ++ hs->debugfs = debugfs_create_dir(name, NULL); ++ if (!hs->debugfs) ++ return -ENOMEM; ++ ++ hs->regset.regs = hisi_spi_regs; ++ hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs); ++ hs->regset.base = hs->regs; ++ debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset); ++ ++ return 0; ++} ++ + static u32 hisi_spi_busy(struct hisi_spi *hs) + { + return readl(hs->regs + HISI_SPI_SR) & SR_BUSY; +@@ -424,6 +467,7 @@ static int hisi_spi_probe(struct platform_device *pdev) + hs = spi_controller_get_devdata(master); + hs->dev = dev; + hs->irq = irq; ++ hs->bus_num = pdev->id; + + hs->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hs->regs)) +@@ -445,7 +489,7 @@ static int hisi_spi_probe(struct platform_device *pdev) + + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); +- master->bus_num = pdev->id; ++ master->bus_num = hs->bus_num; + master->setup = hisi_spi_setup; + master->cleanup = hisi_spi_cleanup; + master->transfer_one = hisi_spi_transfer_one; +@@ -461,6 +505,9 @@ static int hisi_spi_probe(struct platform_device *pdev) + return ret; + } + ++ if (hisi_spi_debugfs_init(hs)) ++ dev_info(dev, "failed to create debugfs dir\n"); ++ + ret = spi_register_controller(master); + if (ret) { + dev_err(dev, "failed to register spi master, ret=%d\n", ret); +@@ -477,7 +524,9 @@ static int hisi_spi_probe(struct platform_device *pdev) + static int hisi_spi_remove(struct platform_device *pdev) + { + struct spi_controller *master = platform_get_drvdata(pdev); ++ struct hisi_spi *hs = spi_controller_get_devdata(master); + ++ debugfs_remove_recursive(hs->debugfs); + spi_unregister_controller(master); + + return 0; +-- +2.23.0 + diff --git a/patches/0109-spi-hisi-kunpeng-Fix-the-debugfs-directory-name-inco.patch b/patches/0109-spi-hisi-kunpeng-Fix-the-debugfs-directory-name-inco.patch new file mode 100644 index 0000000..a8a46bc --- /dev/null +++ b/patches/0109-spi-hisi-kunpeng-Fix-the-debugfs-directory-name-inco.patch @@ -0,0 +1,93 @@ +From 12c5d4361e40e06999e4e0e9865fc61052841424 Mon Sep 17 00:00:00 2001 +From: oujiefeng +Date: Tue, 19 Apr 2022 17:06:41 +0800 +Subject: [PATCH 109/109] spi: hisi-kunpeng: Fix the debugfs directory name + incorrect + +mainline inclusion +from mainline-v5.17-rc1 +commit 40fafc8eca3f0d41b9dade5c10afb2dad723aad7 +category: bugfix +bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8DDF5 +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=40fafc8eca3f0d41b9dade5c10afb2dad723aad7 + +---------------------------------------------------------------------------- + +Change the debugfs directory name from hisi_spi65535 to hisi_spi0. + +Fixes: 2b2142f247eb ("spi: hisi-kunpeng: Add debugfs support") +Signed-off-by: oujiefeng +Signed-off-by: Jay Fang +Link: https://lore.kernel.org/r/20211117012119.55558-1-f.fangjian@huawei.com +Signed-off-by: Mark Brown +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/spi/spi-hisi-kunpeng.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index 4595044a530b..9832faadb324 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -127,7 +127,6 @@ struct hisi_spi { + void __iomem *regs; + int irq; + u32 fifo_len; /* depth of the FIFO buffer */ +- u16 bus_num; + + /* Current message transfer state info */ + const void *tx; +@@ -165,7 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs) + { + char name[32]; + +- snprintf(name, 32, "hisi_spi%d", hs->bus_num); ++ struct spi_controller *master; ++ ++ master = container_of(hs->dev, struct spi_controller, dev); ++ snprintf(name, 32, "hisi_spi%d", master->bus_num); + hs->debugfs = debugfs_create_dir(name, NULL); + if (!hs->debugfs) + return -ENOMEM; +@@ -467,7 +469,6 @@ static int hisi_spi_probe(struct platform_device *pdev) + hs = spi_controller_get_devdata(master); + hs->dev = dev; + hs->irq = irq; +- hs->bus_num = pdev->id; + + hs->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hs->regs)) +@@ -489,7 +490,7 @@ static int hisi_spi_probe(struct platform_device *pdev) + + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); +- master->bus_num = hs->bus_num; ++ master->bus_num = pdev->id; + master->setup = hisi_spi_setup; + master->cleanup = hisi_spi_cleanup; + master->transfer_one = hisi_spi_transfer_one; +@@ -505,15 +506,15 @@ static int hisi_spi_probe(struct platform_device *pdev) + return ret; + } + +- if (hisi_spi_debugfs_init(hs)) +- dev_info(dev, "failed to create debugfs dir\n"); +- + ret = spi_register_controller(master); + if (ret) { + dev_err(dev, "failed to register spi master, ret=%d\n", ret); + return ret; + } + ++ if (hisi_spi_debugfs_init(hs)) ++ dev_info(dev, "failed to create debugfs dir\n"); ++ + dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", + readl(hs->regs + HISI_SPI_VERSION), + master->max_speed_hz / 1000); +-- +2.23.0 + diff --git a/series.conf b/series.conf index b4c8a39..5f1ee18 100644 --- a/series.conf +++ b/series.conf @@ -101,3 +101,12 @@ patches/0097-arm64-HWCAP-add-support-for-AT_HWCAP2.patch patches/0098-arm64-Expose-SVE2-features-for-userspace.patch patches/0099-arm64-cpufeature-Fix-missing-ZFR0-in-__read_sysreg_b.patch patches/0100-arm64-cpufeature-Treat-ID_AA64ZFR0_EL1-as-RAZ-when-S.patch +patches/0101-spi-core-allow-reporting-the-effectivly-used-speed_h.patch +patches/0102-spi-Introduce-device-managed-SPI-controller-allocati.patch +patches/0103-spi-Fix-use-after-free-with-devm_spi_alloc_.patch +patches/0104-spi-linux-spi-spi.h-add-missing-struct-kernel-doc-en.patch +patches/0105-Documentation-devres-add-missing-SPI-helper.patch +patches/0106-spi-Add-HiSilicon-SPI-Controller-Driver-for-Kunpeng-.patch +patches/0107-spi-hisi-kunpeng-Fix-Woverflow-warning-on-conversion.patch +patches/0108-spi-hisi-kunpeng-Add-debugfs-support.patch +patches/0109-spi-hisi-kunpeng-Fix-the-debugfs-directory-name-inco.patch