[PATCH 5/6] tty: serial: qcom_geni_serial: Add interconnect support
Get the interconnect paths for Uart based Serial Engine device and vote accordingly based on maximum supported Uart frequency. Signed-off-by: Alok Chauhan --- drivers/tty/serial/qcom_geni_serial.c | 27 ++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index a72d6d9..e2ea499 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -19,6 +19,7 @@ #include #include #include +#include /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG 0x22c @@ -1348,6 +1349,22 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) return ret; } + /* Set the bus quota to a reasonable value */ + port->se.avg_bw = console ? Bps_to_icc(1000) : Bps_to_icc(2500); + port->se.peak_bw = Bps_to_icc(7680); + ret = geni_interconnect_init(>se); + if (ret) { + dev_err(>dev, "interconnect_init failed %d\n", ret); + return ret; + } + + /* +* Vote for interconnect path early. This has to move as part of +* Runtime PM APIs when implemented for better control betwen +* console and non-console usecases +*/ + geni_icc_update_bw(>se, true); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; @@ -1385,8 +1402,15 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = >uport; + int ret; + + ret = uart_suspend_port(uport->private_data, uport); + if (ret) + return ret; + + geni_icc_update_bw(>se, false); - return uart_suspend_port(uport->private_data, uport); + return 0; } static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) @@ -1394,6 +1418,7 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = >uport; + geni_icc_update_bw(>se, true); return uart_resume_port(uport->private_data, uport); } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 6/6] arm64: dts: sdm845: Add interconnect for GENI QUP
Add interconnect ports for GENI QUPs to set bus capabilities. Signed-off-by: Alok Chauhan --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 ++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index c27cbd3..fb0a8a7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -374,6 +374,13 @@ #address-cells = <1>; #size-cells = <1>; ranges; + + interconnects = <_hlos MASTER_BLSP_1 + _hlos SLAVE_EBI1>, + <_hlos MASTER_APPSS_PROC + _hlos SLAVE_BLSP_1>; + interconnect-names = "qup-memory", "qup-config"; + status = "disabled"; i2c0: i2c@88 { @@ -682,6 +689,13 @@ #address-cells = <1>; #size-cells = <1>; ranges; + + interconnects = <_hlos MASTER_BLSP_2 + _hlos SLAVE_EBI1>, + <_hlos MASTER_APPSS_PROC + _hlos SLAVE_BLSP_2>; + interconnect-names = "qup-memory", "qup-config"; + status = "disabled"; i2c8: i2c@a8 { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 4/6] spi: spi-geni-qcom: Add interconnect support
Get the interconnect paths for SPI based Serial Engine device and vote accordingly based on maximum supported SPI frequency. Signed-off-by: Alok Chauhan --- drivers/spi/spi-geni-qcom.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index fdb7cb88..7bbbe9d 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -12,6 +12,7 @@ #include #include #include +#include /* SPI SE specific registers and respective register fields */ #define SE_SPI_CPHA0x224 @@ -589,6 +590,15 @@ static int spi_geni_probe(struct platform_device *pdev) spin_lock_init(>lock); pm_runtime_enable(>dev); + /* Set the bus quota to a reasonable value */ + mas->se.avg_bw = Bps_to_icc(2500); + mas->se.peak_bw = Bps_to_icc(2); + ret = geni_interconnect_init(>se); + if (ret) { + dev_err(>dev, "interconnect_init failed %d\n", ret); + return ret; + } + ret = spi_geni_init(mas); if (ret) goto spi_geni_probe_runtime_disable; @@ -628,8 +638,15 @@ static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) { struct spi_master *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_master_get_devdata(spi); + int ret; - return geni_se_resources_off(>se); + ret = geni_se_resources_off(>se); + if (ret) + return ret; + + geni_icc_update_bw(>se, false); + + return 0; } static int __maybe_unused spi_geni_runtime_resume(struct device *dev) @@ -637,6 +654,7 @@ static int __maybe_unused spi_geni_runtime_resume(struct device *dev) struct spi_master *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_master_get_devdata(spi); + geni_icc_update_bw(>se, true); return geni_se_resources_on(>se); } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 1/6] dt-bindings: soc: qcom: Add interconnect binding for GENI QUP
Add documentation for the interconnect and interconnect-names bindings for the GENI QUP as detailed by bindings/interconnect/interconnect.txt. Signed-off-by: Alok Chauhan --- Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt | 10 ++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt index dab7ca9..44d7e02 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt @@ -17,6 +17,12 @@ Required properties if child node exists: - #address-cells: Must be <1> for Serial Engine Address - #size-cells: Must be <1> for Serial Engine Address Size - ranges: Must be present +- interconnects: phandle to a interconnect provider. Please refer + ../interconnect/interconnect.txt for details. + Must be 2 paths corresponding to 2 AXI ports. +- interconnect-names: Port names to differentiate between the + 2 interconnect paths defined with interconnect + specifier. Properties for children: @@ -67,6 +73,10 @@ Example: #size-cells = <1>; ranges; + interconnects = < 11 512>, + < 0 543>; + interconnect-names = "qup-memory", "qup-config"; + i2c0: i2c@a94000 { compatible = "qcom,geni-i2c"; reg = <0xa94000 0x4000>; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 2/6] soc: qcom: Add wrapper to support for Interconnect path
Add the wrapper to support for interconnect path voting from GENI QUP. This wrapper provides the functionalities to individual Serial Engine device to get the interconnect path and to vote for bandwidth based on their need. This wrapper maintains bandwidth votes from each Serial Engine and send the aggregated vote from GENI QUP to interconnect framework. Signed-off-by: Alok Chauhan --- drivers/soc/qcom/qcom-geni-se.c | 129 include/linux/qcom-geni-se.h| 11 2 files changed, 140 insertions(+) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 6b8ef01..1d8dcb1 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -11,6 +11,7 @@ #include #include #include +#include /** * DOC: Overview @@ -84,11 +85,21 @@ * @dev: Device pointer of the QUP wrapper core * @base: Base address of this instance of QUP wrapper core * @ahb_clks: Handle to the primary & secondary AHB clocks + * @icc_path: Array of interconnect path handles + * @geni_wrapper_lock: Lock to protect the bus bandwidth request + * @cur_avg_bw:Current Bus Average BW request value from GENI QUP + * @cur_peak_bw: Current Bus Peak BW request value from GENI QUP + * @peak_bw_list_head: Sorted resource list based on peak bus BW */ struct geni_wrapper { struct device *dev; void __iomem *base; struct clk_bulk_data ahb_clks[NUM_AHB_CLKS]; + struct icc_path *icc_path[2]; + struct mutex geni_wrapper_lock; + u32 cur_avg_bw; + u32 cur_peak_bw; + struct list_head peak_bw_list_head; }; #define QUP_HW_VER_REG 0x4 @@ -440,6 +451,71 @@ static void geni_se_clks_off(struct geni_se *se) } /** + * geni_icc_update_bw() - Request to update bw vote on an interconnect path + * @se:Pointer to the concerned serial engine. + * @update:Flag to update bw vote. + * + * This function is used to request set bw vote on interconnect path handle. + */ +void geni_icc_update_bw(struct geni_se *se, bool update) +{ + struct geni_se *temp = NULL; + struct list_head *ins_list_head; + struct geni_wrapper *wrapper; + + mutex_lock(>wrapper->geni_wrapper_lock); + + wrapper = se->wrapper; + + if (update) { + wrapper->cur_avg_bw += se->avg_bw; + ins_list_head = >peak_bw_list_head; + list_for_each_entry(temp, >peak_bw_list_head, + peak_bw_list) { + if (temp->peak_bw < se->peak_bw) + break; + ins_list_head = >peak_bw_list; + } + + list_add(>peak_bw_list, ins_list_head); + + if (ins_list_head == >peak_bw_list_head) + wrapper->cur_peak_bw = se->peak_bw; + } else { + if (unlikely(list_empty(>peak_bw_list))) { + mutex_unlock(>geni_wrapper_lock); + return; + } + + wrapper->cur_avg_bw -= se->avg_bw; + + list_del_init(>peak_bw_list); + temp = list_first_entry_or_null(>peak_bw_list_head, + struct geni_se, peak_bw_list); + if (temp && temp->peak_bw != wrapper->cur_peak_bw) + wrapper->cur_peak_bw = temp->peak_bw; + else if (!temp && wrapper->cur_peak_bw) + wrapper->cur_peak_bw = 0; + } + + /* +* This bw vote is to enable internal QUP core clock as well as to +* enable path towards memory. +*/ + icc_set_bw(wrapper->icc_path[0], wrapper->cur_avg_bw, + wrapper->cur_peak_bw); + + /* +* This is just register configuration path so doesn't need avg bw. +* Set only peak bw to enable this path. +*/ + icc_set_bw(wrapper->icc_path[1], 0, wrapper->cur_peak_bw); + + mutex_unlock(>geni_wrapper_lock); +} +EXPORT_SYMBOL(geni_icc_update_bw); + +/** * geni_se_resources_off() - Turn off resources associated with the serial * engine * @se:Pointer to the concerned serial engine. @@ -707,6 +783,47 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) } EXPORT_SYMBOL(geni_se_rx_dma_unprep); +/** + * geni_interconnect_init() - Request to get interconnect path handle + * @se:Pointer to the concerned serial engine. + * + * This function is used to get interconnect path handle. + */ +int geni_interconnect_init(struct geni_se *se) +{ + struct geni_wrapper *wrapper_rsc; + + if (unlikely(!se || !se->wrapper))
[PATCH 3/6] i2c: i2c-qcom-geni: Add interconnect support
Get the interconnect paths for I2C based Serial Engine device and vote accordingly based on maximum supported I2C frequency. Signed-off-by: Alok Chauhan --- drivers/i2c/busses/i2c-qcom-geni.c | 13 + 1 file changed, 13 insertions(+) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db075bc..e8fe63a 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -14,6 +14,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN0x26c #define SE_I2C_RX_TRANS_LEN0x270 @@ -508,6 +509,15 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + /* Set the bus quota to a reasonable value */ + gi2c->se.avg_bw = Bps_to_icc(1000); + gi2c->se.peak_bw = Bps_to_icc(7680); + ret = geni_interconnect_init(>se); + if (ret) { + dev_err(>dev, "interconnect_init failed %d\n", ret); + return ret; + } + ret = device_property_read_u32(>dev, "clock-frequency", >clk_freq_out); if (ret) { @@ -611,6 +621,8 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) gi2c->suspended = 1; } + geni_icc_update_bw(>se, false); + return 0; } @@ -619,6 +631,7 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) int ret; struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + geni_icc_update_bw(>se, true); ret = geni_se_resources_on(>se); if (ret) return ret; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 0/6] Add interconnect support for GENI QUPs
This patch series contains following: * Add wrapper framework to support interconnect path from GENI QUPs. This wrapper enabled and help individual SEs to put their BW request. Adding this wrapper make sense because we don't want individual SEs to request to interconnect driver separately and put individual bw votes from QUP. This wrapper framework does the following: - Request for interconnect path handle - Maintain record of individual SEs' avg/peak bw. - Aggregated avg/peak bw based on how many SE's are active and put single bw request from QUP * Interconnect wrapper API calling from I2C, SPI & Uart driver * dt binding in sdm845 soc for Interconnect path for GENI QUPs * dt binding documentation Alok Chauhan (6): dt-bindings: soc: qcom: Add interconnect binding for GENI QUP soc: qcom: Add wrapper to support for Interconnect path i2c: i2c-qcom-geni: Add interconnect support spi: spi-geni-qcom: Add interconnect support tty: serial: qcom_geni_serial: Add interconnect support arm64: dts: sdm845: Add interconnect for GENI QUP .../devicetree/bindings/soc/qcom/qcom,geni-se.txt | 10 ++ arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 +++ drivers/i2c/busses/i2c-qcom-geni.c | 13 +++ drivers/soc/qcom/qcom-geni-se.c| 129 + drivers/spi/spi-geni-qcom.c| 20 +++- drivers/tty/serial/qcom_geni_serial.c | 27 - include/linux/qcom-geni-se.h | 11 ++ 7 files changed, 222 insertions(+), 2 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 5/6] tty: serial: qcom_geni_serial: Add interconnect support
Get the interconnect paths for Uart based Serial Engine device and vote accordingly based on maximum supported Uart frequency. Signed-off-by: Alok Chauhan --- drivers/tty/serial/qcom_geni_serial.c | 27 ++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index a72d6d9..e2ea499 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -19,6 +19,7 @@ #include #include #include +#include /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG 0x22c @@ -1348,6 +1349,22 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) return ret; } + /* Set the bus quota to a reasonable value */ + port->se.avg_bw = console ? Bps_to_icc(1000) : Bps_to_icc(2500); + port->se.peak_bw = Bps_to_icc(7680); + ret = geni_interconnect_init(>se); + if (ret) { + dev_err(>dev, "interconnect_init failed %d\n", ret); + return ret; + } + + /* +* Vote for interconnect path early. This has to move as part of +* Runtime PM APIs when implemented for better control betwen +* console and non-console usecases +*/ + geni_icc_update_bw(>se, true); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; @@ -1385,8 +1402,15 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = >uport; + int ret; + + ret = uart_suspend_port(uport->private_data, uport); + if (ret) + return ret; + + geni_icc_update_bw(>se, false); - return uart_suspend_port(uport->private_data, uport); + return 0; } static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) @@ -1394,6 +1418,7 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = >uport; + geni_icc_update_bw(>se, true); return uart_resume_port(uport->private_data, uport); } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 6/6] arm64: dts: sdm845: Add interconnect for GENI QUP
Add interconnect ports for GENI QUPs to set bus capabilities. Signed-off-by: Alok Chauhan --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 ++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index c27cbd3..fb0a8a7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -374,6 +374,13 @@ #address-cells = <1>; #size-cells = <1>; ranges; + + interconnects = <_hlos MASTER_BLSP_1 + _hlos SLAVE_EBI1>, + <_hlos MASTER_APPSS_PROC + _hlos SLAVE_BLSP_1>; + interconnect-names = "qup-memory", "qup-config"; + status = "disabled"; i2c0: i2c@88 { @@ -682,6 +689,13 @@ #address-cells = <1>; #size-cells = <1>; ranges; + + interconnects = <_hlos MASTER_BLSP_2 + _hlos SLAVE_EBI1>, + <_hlos MASTER_APPSS_PROC + _hlos SLAVE_BLSP_2>; + interconnect-names = "qup-memory", "qup-config"; + status = "disabled"; i2c8: i2c@a8 { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 0/6] Add interconnect support for GENI QUPs
This patch series contains following: * Add wrapper framework to support interconnect path from GENI QUPs. This wrapper enabled and help individual SEs to put their BW request. Adding this wrapper make sense because we don't want individual SEs to request to interconnect driver separately and put individual bw votes from QUP. This wrapper framework does the following: - Request for interconnect path handle - Maintain record of individual SEs' avg/peak bw. - Aggregated avg/peak bw based on how many SE's are active and put single bw request from QUP * Interconnect wrapper API calling from I2C, SPI & Uart driver * dt binding in sdm845 soc for Interconnect path for GENI QUPs * dt binding documentation Alok Chauhan (6): dt-bindings: soc: qcom: Add interconnect binding for GENI QUP soc: qcom: Add wrapper to support for Interconnect path i2c: i2c-qcom-geni: Add interconnect support spi: spi-geni-qcom: Add interconnect support tty: serial: qcom_geni_serial: Add interconnect support arm64: dts: sdm845: Add interconnect for GENI QUP .../devicetree/bindings/soc/qcom/qcom,geni-se.txt | 10 ++ arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 +++ drivers/i2c/busses/i2c-qcom-geni.c | 13 +++ drivers/soc/qcom/qcom-geni-se.c| 129 + drivers/spi/spi-geni-qcom.c| 20 +++- drivers/tty/serial/qcom_geni_serial.c | 27 - include/linux/qcom-geni-se.h | 11 ++ 7 files changed, 222 insertions(+), 2 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 4/6] spi: spi-geni-qcom: Add interconnect support
Get the interconnect paths for SPI based Serial Engine device and vote accordingly based on maximum supported SPI frequency. Signed-off-by: Alok Chauhan --- drivers/spi/spi-geni-qcom.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index fdb7cb88..7bbbe9d 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -12,6 +12,7 @@ #include #include #include +#include /* SPI SE specific registers and respective register fields */ #define SE_SPI_CPHA0x224 @@ -589,6 +590,15 @@ static int spi_geni_probe(struct platform_device *pdev) spin_lock_init(>lock); pm_runtime_enable(>dev); + /* Set the bus quota to a reasonable value */ + mas->se.avg_bw = Bps_to_icc(2500); + mas->se.peak_bw = Bps_to_icc(2); + ret = geni_interconnect_init(>se); + if (ret) { + dev_err(>dev, "interconnect_init failed %d\n", ret); + return ret; + } + ret = spi_geni_init(mas); if (ret) goto spi_geni_probe_runtime_disable; @@ -628,8 +638,15 @@ static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) { struct spi_master *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_master_get_devdata(spi); + int ret; - return geni_se_resources_off(>se); + ret = geni_se_resources_off(>se); + if (ret) + return ret; + + geni_icc_update_bw(>se, false); + + return 0; } static int __maybe_unused spi_geni_runtime_resume(struct device *dev) @@ -637,6 +654,7 @@ static int __maybe_unused spi_geni_runtime_resume(struct device *dev) struct spi_master *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_master_get_devdata(spi); + geni_icc_update_bw(>se, true); return geni_se_resources_on(>se); } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 3/6] i2c: i2c-qcom-geni: Add interconnect support
Get the interconnect paths for I2C based Serial Engine device and vote accordingly based on maximum supported I2C frequency. Signed-off-by: Alok Chauhan --- drivers/i2c/busses/i2c-qcom-geni.c | 13 + 1 file changed, 13 insertions(+) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db075bc..e8fe63a 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -14,6 +14,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN0x26c #define SE_I2C_RX_TRANS_LEN0x270 @@ -508,6 +509,15 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + /* Set the bus quota to a reasonable value */ + gi2c->se.avg_bw = Bps_to_icc(1000); + gi2c->se.peak_bw = Bps_to_icc(7680); + ret = geni_interconnect_init(>se); + if (ret) { + dev_err(>dev, "interconnect_init failed %d\n", ret); + return ret; + } + ret = device_property_read_u32(>dev, "clock-frequency", >clk_freq_out); if (ret) { @@ -611,6 +621,8 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) gi2c->suspended = 1; } + geni_icc_update_bw(>se, false); + return 0; } @@ -619,6 +631,7 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) int ret; struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + geni_icc_update_bw(>se, true); ret = geni_se_resources_on(>se); if (ret) return ret; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 2/6] soc: qcom: Add wrapper to support for Interconnect path
Add the wrapper to support for interconnect path voting from GENI QUP. This wrapper provides the functionalities to individual Serial Engine device to get the interconnect path and to vote for bandwidth based on their need. This wrapper maintains bandwidth votes from each Serial Engine and send the aggregated vote from GENI QUP to interconnect framework. Signed-off-by: Alok Chauhan --- drivers/soc/qcom/qcom-geni-se.c | 129 include/linux/qcom-geni-se.h| 11 2 files changed, 140 insertions(+) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 6b8ef01..1d8dcb1 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -11,6 +11,7 @@ #include #include #include +#include /** * DOC: Overview @@ -84,11 +85,21 @@ * @dev: Device pointer of the QUP wrapper core * @base: Base address of this instance of QUP wrapper core * @ahb_clks: Handle to the primary & secondary AHB clocks + * @icc_path: Array of interconnect path handles + * @geni_wrapper_lock: Lock to protect the bus bandwidth request + * @cur_avg_bw:Current Bus Average BW request value from GENI QUP + * @cur_peak_bw: Current Bus Peak BW request value from GENI QUP + * @peak_bw_list_head: Sorted resource list based on peak bus BW */ struct geni_wrapper { struct device *dev; void __iomem *base; struct clk_bulk_data ahb_clks[NUM_AHB_CLKS]; + struct icc_path *icc_path[2]; + struct mutex geni_wrapper_lock; + u32 cur_avg_bw; + u32 cur_peak_bw; + struct list_head peak_bw_list_head; }; #define QUP_HW_VER_REG 0x4 @@ -440,6 +451,71 @@ static void geni_se_clks_off(struct geni_se *se) } /** + * geni_icc_update_bw() - Request to update bw vote on an interconnect path + * @se:Pointer to the concerned serial engine. + * @update:Flag to update bw vote. + * + * This function is used to request set bw vote on interconnect path handle. + */ +void geni_icc_update_bw(struct geni_se *se, bool update) +{ + struct geni_se *temp = NULL; + struct list_head *ins_list_head; + struct geni_wrapper *wrapper; + + mutex_lock(>wrapper->geni_wrapper_lock); + + wrapper = se->wrapper; + + if (update) { + wrapper->cur_avg_bw += se->avg_bw; + ins_list_head = >peak_bw_list_head; + list_for_each_entry(temp, >peak_bw_list_head, + peak_bw_list) { + if (temp->peak_bw < se->peak_bw) + break; + ins_list_head = >peak_bw_list; + } + + list_add(>peak_bw_list, ins_list_head); + + if (ins_list_head == >peak_bw_list_head) + wrapper->cur_peak_bw = se->peak_bw; + } else { + if (unlikely(list_empty(>peak_bw_list))) { + mutex_unlock(>geni_wrapper_lock); + return; + } + + wrapper->cur_avg_bw -= se->avg_bw; + + list_del_init(>peak_bw_list); + temp = list_first_entry_or_null(>peak_bw_list_head, + struct geni_se, peak_bw_list); + if (temp && temp->peak_bw != wrapper->cur_peak_bw) + wrapper->cur_peak_bw = temp->peak_bw; + else if (!temp && wrapper->cur_peak_bw) + wrapper->cur_peak_bw = 0; + } + + /* +* This bw vote is to enable internal QUP core clock as well as to +* enable path towards memory. +*/ + icc_set_bw(wrapper->icc_path[0], wrapper->cur_avg_bw, + wrapper->cur_peak_bw); + + /* +* This is just register configuration path so doesn't need avg bw. +* Set only peak bw to enable this path. +*/ + icc_set_bw(wrapper->icc_path[1], 0, wrapper->cur_peak_bw); + + mutex_unlock(>geni_wrapper_lock); +} +EXPORT_SYMBOL(geni_icc_update_bw); + +/** * geni_se_resources_off() - Turn off resources associated with the serial * engine * @se:Pointer to the concerned serial engine. @@ -707,6 +783,47 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) } EXPORT_SYMBOL(geni_se_rx_dma_unprep); +/** + * geni_interconnect_init() - Request to get interconnect path handle + * @se:Pointer to the concerned serial engine. + * + * This function is used to get interconnect path handle. + */ +int geni_interconnect_init(struct geni_se *se) +{ + struct geni_wrapper *wrapper_rsc; + + if (unlikely(!se || !se->wrapper))
[PATCH 1/6] dt-bindings: soc: qcom: Add interconnect binding for GENI QUP
Add documentation for the interconnect and interconnect-names bindings for the GENI QUP as detailed by bindings/interconnect/interconnect.txt. Signed-off-by: Alok Chauhan --- Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt | 10 ++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt index dab7ca9..44d7e02 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt @@ -17,6 +17,12 @@ Required properties if child node exists: - #address-cells: Must be <1> for Serial Engine Address - #size-cells: Must be <1> for Serial Engine Address Size - ranges: Must be present +- interconnects: phandle to a interconnect provider. Please refer + ../interconnect/interconnect.txt for details. + Must be 2 paths corresponding to 2 AXI ports. +- interconnect-names: Port names to differentiate between the + 2 interconnect paths defined with interconnect + specifier. Properties for children: @@ -67,6 +73,10 @@ Example: #size-cells = <1>; ranges; + interconnects = < 11 512>, + < 0 543>; + interconnect-names = "qup-memory", "qup-config"; + i2c0: i2c@a94000 { compatible = "qcom,geni-i2c"; reg = <0xa94000 0x4000>; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 1/2] spi: spi-geni-qcom: fix nitpicks
fixed the nitpicks. Signed-off-by: Alok Chauhan --- drivers/spi/spi-geni-qcom.c | 15 ++- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 6432ecc..d1830fb 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -64,15 +64,13 @@ #define TIMESTAMP_AFTERBIT(3) #define POST_CMD_DELAY BIT(4) -/* SPI M_COMMAND OPCODE */ -enum spi_mcmd_code { +enum spi_m_cmd_opcode { CMD_NONE, CMD_XFER, CMD_CS, CMD_CANCEL, }; - struct spi_geni_master { struct geni_se se; struct device *dev; @@ -87,7 +85,7 @@ struct spi_geni_master { struct completion xfer_done; unsigned int oversampling; spinlock_t lock; - unsigned int cur_mcmd; + enum spi_m_cmd_opcode cur_mcmd; int irq; }; @@ -129,7 +127,7 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) struct spi_geni_master *mas = spi_master_get_devdata(slv->master); struct spi_master *spi = dev_get_drvdata(mas->dev); struct geni_se *se = >se; - unsigned long timeout; + unsigned long time_left; reinit_completion(>xfer_done); pm_runtime_get_sync(mas->dev); @@ -142,8 +140,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) else geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); - timeout = wait_for_completion_timeout(>xfer_done, HZ); - if (!timeout) + time_left = wait_for_completion_timeout(>xfer_done, HZ); + if (!time_left) handle_fifo_timeout(spi, NULL); pm_runtime_put(mas->dev); @@ -485,7 +483,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data) struct geni_se *se = >se; u32 m_irq; unsigned long flags; - irqreturn_t ret = IRQ_HANDLED; if (mas->cur_mcmd == CMD_NONE) return IRQ_NONE; @@ -533,7 +530,7 @@ static irqreturn_t geni_spi_isr(int irq, void *data) writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); spin_unlock_irqrestore(>lock, flags); - return ret; + return IRQ_HANDLED; } static int spi_geni_probe(struct platform_device *pdev) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 2/2] spi: spi-geni-qcom: Simplify probe function
Re-arrange existing APIs in probe function to avoid using goto and remove redundant variables. Signed-off-by: Alok Chauhan --- drivers/spi/spi-geni-qcom.c | 49 ++--- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index d1830fb..fdb7cb88 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -535,11 +535,30 @@ static irqreturn_t geni_spi_isr(int irq, void *data) static int spi_geni_probe(struct platform_device *pdev) { - int ret; + int ret, irq; struct spi_master *spi; struct spi_geni_master *mas; struct resource *res; - struct geni_se *se; + void __iomem *base; + struct clk *clk; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(>dev, "Err getting IRQ %d\n", irq); + return irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(>dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk = devm_clk_get(>dev, "se"); + if (IS_ERR(clk)) { + dev_err(>dev, "Err getting SE Core clk %ld\n", + PTR_ERR(clk)); + return PTR_ERR(clk); + } spi = spi_alloc_master(>dev, sizeof(*mas)); if (!spi) @@ -547,27 +566,15 @@ static int spi_geni_probe(struct platform_device *pdev) platform_set_drvdata(pdev, spi); mas = spi_master_get_devdata(spi); + mas->irq = irq; mas->dev = >dev; mas->se.dev = >dev; mas->se.wrapper = dev_get_drvdata(pdev->dev.parent); - se = >se; + mas->se.base = base; + mas->se.clk = clk; spi->bus_num = -1; spi->dev.of_node = pdev->dev.of_node; - mas->se.clk = devm_clk_get(>dev, "se"); - if (IS_ERR(mas->se.clk)) { - ret = PTR_ERR(mas->se.clk); - dev_err(>dev, "Err getting SE Core clk %d\n", ret); - goto spi_geni_probe_err; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - se->base = devm_ioremap_resource(>dev, res); - if (IS_ERR(se->base)) { - ret = PTR_ERR(se->base); - goto spi_geni_probe_err; - } - spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); spi->num_chipselect = 4; @@ -586,13 +593,6 @@ static int spi_geni_probe(struct platform_device *pdev) if (ret) goto spi_geni_probe_runtime_disable; - mas->irq = platform_get_irq(pdev, 0); - if (mas->irq < 0) { - ret = mas->irq; - dev_err(>dev, "Err getting IRQ %d\n", ret); - goto spi_geni_probe_runtime_disable; - } - ret = request_irq(mas->irq, geni_spi_isr, IRQF_TRIGGER_HIGH, "spi_geni", spi); if (ret) @@ -607,7 +607,6 @@ static int spi_geni_probe(struct platform_device *pdev) free_irq(mas->irq, spi); spi_geni_probe_runtime_disable: pm_runtime_disable(>dev); -spi_geni_probe_err: spi_master_put(spi); return ret; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 1/2] spi: spi-geni-qcom: fix nitpicks
fixed the nitpicks. Signed-off-by: Alok Chauhan --- drivers/spi/spi-geni-qcom.c | 15 ++- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 6432ecc..d1830fb 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -64,15 +64,13 @@ #define TIMESTAMP_AFTERBIT(3) #define POST_CMD_DELAY BIT(4) -/* SPI M_COMMAND OPCODE */ -enum spi_mcmd_code { +enum spi_m_cmd_opcode { CMD_NONE, CMD_XFER, CMD_CS, CMD_CANCEL, }; - struct spi_geni_master { struct geni_se se; struct device *dev; @@ -87,7 +85,7 @@ struct spi_geni_master { struct completion xfer_done; unsigned int oversampling; spinlock_t lock; - unsigned int cur_mcmd; + enum spi_m_cmd_opcode cur_mcmd; int irq; }; @@ -129,7 +127,7 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) struct spi_geni_master *mas = spi_master_get_devdata(slv->master); struct spi_master *spi = dev_get_drvdata(mas->dev); struct geni_se *se = >se; - unsigned long timeout; + unsigned long time_left; reinit_completion(>xfer_done); pm_runtime_get_sync(mas->dev); @@ -142,8 +140,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) else geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); - timeout = wait_for_completion_timeout(>xfer_done, HZ); - if (!timeout) + time_left = wait_for_completion_timeout(>xfer_done, HZ); + if (!time_left) handle_fifo_timeout(spi, NULL); pm_runtime_put(mas->dev); @@ -485,7 +483,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data) struct geni_se *se = >se; u32 m_irq; unsigned long flags; - irqreturn_t ret = IRQ_HANDLED; if (mas->cur_mcmd == CMD_NONE) return IRQ_NONE; @@ -533,7 +530,7 @@ static irqreturn_t geni_spi_isr(int irq, void *data) writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); spin_unlock_irqrestore(>lock, flags); - return ret; + return IRQ_HANDLED; } static int spi_geni_probe(struct platform_device *pdev) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 2/2] spi: spi-geni-qcom: Simplify probe function
Re-arrange existing APIs in probe function to avoid using goto and remove redundant variables. Signed-off-by: Alok Chauhan --- drivers/spi/spi-geni-qcom.c | 49 ++--- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index d1830fb..fdb7cb88 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -535,11 +535,30 @@ static irqreturn_t geni_spi_isr(int irq, void *data) static int spi_geni_probe(struct platform_device *pdev) { - int ret; + int ret, irq; struct spi_master *spi; struct spi_geni_master *mas; struct resource *res; - struct geni_se *se; + void __iomem *base; + struct clk *clk; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(>dev, "Err getting IRQ %d\n", irq); + return irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(>dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk = devm_clk_get(>dev, "se"); + if (IS_ERR(clk)) { + dev_err(>dev, "Err getting SE Core clk %ld\n", + PTR_ERR(clk)); + return PTR_ERR(clk); + } spi = spi_alloc_master(>dev, sizeof(*mas)); if (!spi) @@ -547,27 +566,15 @@ static int spi_geni_probe(struct platform_device *pdev) platform_set_drvdata(pdev, spi); mas = spi_master_get_devdata(spi); + mas->irq = irq; mas->dev = >dev; mas->se.dev = >dev; mas->se.wrapper = dev_get_drvdata(pdev->dev.parent); - se = >se; + mas->se.base = base; + mas->se.clk = clk; spi->bus_num = -1; spi->dev.of_node = pdev->dev.of_node; - mas->se.clk = devm_clk_get(>dev, "se"); - if (IS_ERR(mas->se.clk)) { - ret = PTR_ERR(mas->se.clk); - dev_err(>dev, "Err getting SE Core clk %d\n", ret); - goto spi_geni_probe_err; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - se->base = devm_ioremap_resource(>dev, res); - if (IS_ERR(se->base)) { - ret = PTR_ERR(se->base); - goto spi_geni_probe_err; - } - spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); spi->num_chipselect = 4; @@ -586,13 +593,6 @@ static int spi_geni_probe(struct platform_device *pdev) if (ret) goto spi_geni_probe_runtime_disable; - mas->irq = platform_get_irq(pdev, 0); - if (mas->irq < 0) { - ret = mas->irq; - dev_err(>dev, "Err getting IRQ %d\n", ret); - goto spi_geni_probe_runtime_disable; - } - ret = request_irq(mas->irq, geni_spi_isr, IRQF_TRIGGER_HIGH, "spi_geni", spi); if (ret) @@ -607,7 +607,6 @@ static int spi_geni_probe(struct platform_device *pdev) free_irq(mas->irq, spi); spi_geni_probe_runtime_disable: pm_runtime_disable(>dev); -spi_geni_probe_err: spi_master_put(spi); return ret; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 3/3] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP
From: Girish Mahadevan This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer. Signed-off-by: Girish Mahadevan Signed-off-by: Dilip Kota Signed-off-by: Alok Chauhan --- drivers/spi/Kconfig | 12 + drivers/spi/Makefile| 1 + drivers/spi/spi-geni-qcom.c | 703 3 files changed, 716 insertions(+) create mode 100644 drivers/spi/spi-geni-qcom.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 671d078..51edc76 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -533,6 +533,18 @@ config SPI_QUP This driver can also be built as a module. If so, the module will be called spi_qup. +config SPI_QCOM_GENI + tristate "Qualcomm GENI based SPI controller" + depends on QCOM_GENI_SE + help + This driver supports GENI serial engine based SPI controller in + master mode on the Qualcomm Technologies Inc.'s SoCs. If you say + yes to this option, support will be included for the built-in SPI + interface on the Qualcomm Technologies Inc.'s SoCs. + + This driver can also be built as a module. If so, the module + will be called spi-geni-qcom. + config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" depends on ARCH_S3C24XX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a90d559..b057c9c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_QCOM_GENI)+= spi-geni-qcom.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_RB4XX)+= spi-rb4xx.o diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c new file mode 100644 index 000..6432ecc --- /dev/null +++ b/drivers/spi/spi-geni-qcom.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SPI SE specific registers and respective register fields */ +#define SE_SPI_CPHA0x224 +#define CPHA BIT(0) + +#define SE_SPI_LOOPBACK0x22c +#define LOOPBACK_ENABLE0x1 +#define NORMAL_MODE0x0 +#define LOOPBACK_MSK GENMASK(1, 0) + +#define SE_SPI_CPOL0x230 +#define CPOL BIT(2) + +#define SE_SPI_DEMUX_OUTPUT_INV0x24c +#define CS_DEMUX_OUTPUT_INV_MSKGENMASK(3, 0) + +#define SE_SPI_DEMUX_SEL 0x250 +#define CS_DEMUX_OUTPUT_SELGENMASK(3, 0) + +#define SE_SPI_TRANS_CFG 0x25c +#define CS_TOGGLE BIT(0) + +#define SE_SPI_WORD_LEN0x268 +#define WORD_LEN_MSK GENMASK(9, 0) +#define MIN_WORD_LEN 4 + +#define SE_SPI_TX_TRANS_LEN0x26c +#define SE_SPI_RX_TRANS_LEN0x270 +#define TRANS_LEN_MSK GENMASK(23, 0) + +#define SE_SPI_PRE_POST_CMD_DLY0x274 + +#define SE_SPI_DELAY_COUNTERS 0x278 +#define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0) +#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) +#define SPI_CS_CLK_DELAY_SHFT 10 + +/* M_CMD OP codes for SPI */ +#define SPI_TX_ONLY1 +#define SPI_RX_ONLY2 +#define SPI_FULL_DUPLEX3 +#define SPI_TX_RX 7 +#define SPI_CS_ASSERT 8 +#define SPI_CS_DEASSERT9 +#define SPI_SCK_ONLY 10 +/* M_CMD params for SPI */ +#define SPI_PRE_CMD_DELAY BIT(0) +#define TIMESTAMP_BEFORE BIT(1) +#define FRAGMENTATION BIT(2) +#define TIMESTAMP_AFTERBIT(3) +#define POST_CMD_DELAY BIT(4) + +/* SPI M_COMMAND OPCODE */ +enum spi_mcmd_code { + CMD_NONE, + CMD_XFER, + CMD_CS, + CMD_CANCEL, +}; + + +struct spi_geni_master { + struct geni_se se; + struct device *dev; + u32 tx_fifo_depth; + u32 fifo_width_bits; + u32 tx_wm; + unsigned long cur_speed_hz; + unsigned int cur_bits_per_word; + unsigned int tx_rem_bytes; + unsigned int rx_rem_bytes; + const struct spi_transfer *cur_xfer; + struct completion xfer_done; + unsigned int oversampling; + spinlock_t lock; + unsigned int cur_mcmd; + int irq; +}; + +static void handle_fifo_timeout(struct spi_master *spi, + str
[PATCH V5 3/3] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP
From: Girish Mahadevan This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer. Signed-off-by: Girish Mahadevan Signed-off-by: Dilip Kota Signed-off-by: Alok Chauhan --- drivers/spi/Kconfig | 12 + drivers/spi/Makefile| 1 + drivers/spi/spi-geni-qcom.c | 703 3 files changed, 716 insertions(+) create mode 100644 drivers/spi/spi-geni-qcom.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 671d078..51edc76 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -533,6 +533,18 @@ config SPI_QUP This driver can also be built as a module. If so, the module will be called spi_qup. +config SPI_QCOM_GENI + tristate "Qualcomm GENI based SPI controller" + depends on QCOM_GENI_SE + help + This driver supports GENI serial engine based SPI controller in + master mode on the Qualcomm Technologies Inc.'s SoCs. If you say + yes to this option, support will be included for the built-in SPI + interface on the Qualcomm Technologies Inc.'s SoCs. + + This driver can also be built as a module. If so, the module + will be called spi-geni-qcom. + config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" depends on ARCH_S3C24XX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a90d559..b057c9c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_QCOM_GENI)+= spi-geni-qcom.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_RB4XX)+= spi-rb4xx.o diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c new file mode 100644 index 000..6432ecc --- /dev/null +++ b/drivers/spi/spi-geni-qcom.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SPI SE specific registers and respective register fields */ +#define SE_SPI_CPHA0x224 +#define CPHA BIT(0) + +#define SE_SPI_LOOPBACK0x22c +#define LOOPBACK_ENABLE0x1 +#define NORMAL_MODE0x0 +#define LOOPBACK_MSK GENMASK(1, 0) + +#define SE_SPI_CPOL0x230 +#define CPOL BIT(2) + +#define SE_SPI_DEMUX_OUTPUT_INV0x24c +#define CS_DEMUX_OUTPUT_INV_MSKGENMASK(3, 0) + +#define SE_SPI_DEMUX_SEL 0x250 +#define CS_DEMUX_OUTPUT_SELGENMASK(3, 0) + +#define SE_SPI_TRANS_CFG 0x25c +#define CS_TOGGLE BIT(0) + +#define SE_SPI_WORD_LEN0x268 +#define WORD_LEN_MSK GENMASK(9, 0) +#define MIN_WORD_LEN 4 + +#define SE_SPI_TX_TRANS_LEN0x26c +#define SE_SPI_RX_TRANS_LEN0x270 +#define TRANS_LEN_MSK GENMASK(23, 0) + +#define SE_SPI_PRE_POST_CMD_DLY0x274 + +#define SE_SPI_DELAY_COUNTERS 0x278 +#define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0) +#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) +#define SPI_CS_CLK_DELAY_SHFT 10 + +/* M_CMD OP codes for SPI */ +#define SPI_TX_ONLY1 +#define SPI_RX_ONLY2 +#define SPI_FULL_DUPLEX3 +#define SPI_TX_RX 7 +#define SPI_CS_ASSERT 8 +#define SPI_CS_DEASSERT9 +#define SPI_SCK_ONLY 10 +/* M_CMD params for SPI */ +#define SPI_PRE_CMD_DELAY BIT(0) +#define TIMESTAMP_BEFORE BIT(1) +#define FRAGMENTATION BIT(2) +#define TIMESTAMP_AFTERBIT(3) +#define POST_CMD_DELAY BIT(4) + +/* SPI M_COMMAND OPCODE */ +enum spi_mcmd_code { + CMD_NONE, + CMD_XFER, + CMD_CS, + CMD_CANCEL, +}; + + +struct spi_geni_master { + struct geni_se se; + struct device *dev; + u32 tx_fifo_depth; + u32 fifo_width_bits; + u32 tx_wm; + unsigned long cur_speed_hz; + unsigned int cur_bits_per_word; + unsigned int tx_rem_bytes; + unsigned int rx_rem_bytes; + const struct spi_transfer *cur_xfer; + struct completion xfer_done; + unsigned int oversampling; + spinlock_t lock; + unsigned int cur_mcmd; + int irq; +}; + +static void handle_fifo_timeout(struct spi_master *spi, + str
[PATCH V5 2/3] dt-bindings: soc: qcom: GENI SE SPI controller device tree binding
From: Dilip Kota Move GENI SE SPI controller device-tree bindings from devicetree/bindings/soc/qcom/qcom,geni-se.txt to devicetree/bindings/spi/qcom,spi-geni-qcom.txt. Signed-off-by: Dilip Kota Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Alok Chauhan --- .../devicetree/bindings/soc/qcom/qcom,geni-se.txt | 27 ++- .../devicetree/bindings/spi/qcom,spi-geni-qcom.txt | 39 ++ 2 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt index b9d0c21..dab7ca9 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt @@ -53,19 +53,8 @@ Required properties: - clocks: Serial engine core clock needed by the device. Qualcomm Technologies Inc. GENI Serial Engine based SPI Controller - -Required properties: -- compatible: Must contain "qcom,geni-spi". -- reg: Must contain SPI register location and length. -- interrupts: Must contain SPI controller interrupts. -- clock-names: Must contain "se". -- clocks: Serial engine core clock needed by the device. -- #address-cells: Must be <1> to define a chip select address on - the SPI bus. -- #size-cells: Must be <0>. - -SPI slave nodes must be children of the SPI master node and conform to SPI bus -binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt. +node binding is described in +Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt. Example: geniqup@8c { @@ -102,16 +91,4 @@ Example: pinctrl-1 = <_1_uart_3_sleep>; }; - spi0: spi@a84000 { - compatible = "qcom,geni-spi"; - reg = <0xa84000 0x4000>; - interrupts = ; - clock-names = "se"; - clocks = <_gcc GCC_QUPV3_WRAP0_S0_CLK>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <_1_spi_2_active>; - pinctrl-1 = <_1_spi_2_sleep>; - #address-cells = <1>; - #size-cells = <0>; - }; } diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt new file mode 100644 index 000..790311a --- /dev/null +++ b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt @@ -0,0 +1,39 @@ +GENI based Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) + +The QUP v3 core is a GENI based AHB slave that provides a common data path +(an output FIFO and an input FIFO) for serial peripheral interface (SPI) +mini-core. + +SPI in master mode supports up to 50MHz, up to four chip selects, programmable +data path from 4 bits to 32 bits and numerous protocol variants. + +Required properties: +- compatible: Must contain "qcom,geni-spi". +- reg: Must contain SPI register location and length. +- interrupts: Must contain SPI controller interrupts. +- clock-names: Must contain "se". +- clocks: Serial engine core clock needed by the device. +- #address-cells: Must be <1> to define a chip select address on + the SPI bus. +- #size-cells: Must be <0>. + +SPI Controller nodes must be child of GENI based Qualcomm Universal +Peripharal. Please refer GENI based QUP wrapper controller node bindings +described in Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt. + +SPI slave nodes must be children of the SPI master node and conform to SPI bus +binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + spi0: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0xa84000 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <_gcc GCC_QUPV3_WRAP0_S0_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <_1_spi_2_active>; + pinctrl-1 = <_1_spi_2_sleep>; + #address-cells = <1>; + #size-cells = <0>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 2/3] dt-bindings: soc: qcom: GENI SE SPI controller device tree binding
From: Dilip Kota Move GENI SE SPI controller device-tree bindings from devicetree/bindings/soc/qcom/qcom,geni-se.txt to devicetree/bindings/spi/qcom,spi-geni-qcom.txt. Signed-off-by: Dilip Kota Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Alok Chauhan --- .../devicetree/bindings/soc/qcom/qcom,geni-se.txt | 27 ++- .../devicetree/bindings/spi/qcom,spi-geni-qcom.txt | 39 ++ 2 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt index b9d0c21..dab7ca9 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt @@ -53,19 +53,8 @@ Required properties: - clocks: Serial engine core clock needed by the device. Qualcomm Technologies Inc. GENI Serial Engine based SPI Controller - -Required properties: -- compatible: Must contain "qcom,geni-spi". -- reg: Must contain SPI register location and length. -- interrupts: Must contain SPI controller interrupts. -- clock-names: Must contain "se". -- clocks: Serial engine core clock needed by the device. -- #address-cells: Must be <1> to define a chip select address on - the SPI bus. -- #size-cells: Must be <0>. - -SPI slave nodes must be children of the SPI master node and conform to SPI bus -binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt. +node binding is described in +Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt. Example: geniqup@8c { @@ -102,16 +91,4 @@ Example: pinctrl-1 = <_1_uart_3_sleep>; }; - spi0: spi@a84000 { - compatible = "qcom,geni-spi"; - reg = <0xa84000 0x4000>; - interrupts = ; - clock-names = "se"; - clocks = <_gcc GCC_QUPV3_WRAP0_S0_CLK>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <_1_spi_2_active>; - pinctrl-1 = <_1_spi_2_sleep>; - #address-cells = <1>; - #size-cells = <0>; - }; } diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt new file mode 100644 index 000..790311a --- /dev/null +++ b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt @@ -0,0 +1,39 @@ +GENI based Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) + +The QUP v3 core is a GENI based AHB slave that provides a common data path +(an output FIFO and an input FIFO) for serial peripheral interface (SPI) +mini-core. + +SPI in master mode supports up to 50MHz, up to four chip selects, programmable +data path from 4 bits to 32 bits and numerous protocol variants. + +Required properties: +- compatible: Must contain "qcom,geni-spi". +- reg: Must contain SPI register location and length. +- interrupts: Must contain SPI controller interrupts. +- clock-names: Must contain "se". +- clocks: Serial engine core clock needed by the device. +- #address-cells: Must be <1> to define a chip select address on + the SPI bus. +- #size-cells: Must be <0>. + +SPI Controller nodes must be child of GENI based Qualcomm Universal +Peripharal. Please refer GENI based QUP wrapper controller node bindings +described in Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt. + +SPI slave nodes must be children of the SPI master node and conform to SPI bus +binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + spi0: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0xa84000 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <_gcc GCC_QUPV3_WRAP0_S0_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <_1_spi_2_active>; + pinctrl-1 = <_1_spi_2_sleep>; + #address-cells = <1>; + #size-cells = <0>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 1/3] dt-bindings: soc: qcom: Remove SPI controller maximum frequency binding
From: Dilip Kota SPI controller driver should maintain the maximum frequency of the controller instead of relying on device tree bindings. Because maximum frequency is specific property of SPI controller. Signed-off-by: Dilip Kota Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Alok Chauhan --- Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt index ff92e5a..b9d0c21 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt @@ -60,7 +60,6 @@ Required properties: - interrupts: Must contain SPI controller interrupts. - clock-names: Must contain "se". - clocks: Serial engine core clock needed by the device. -- spi-max-frequency: Specifies maximum SPI clock frequency, units - Hz. - #address-cells: Must be <1> to define a chip select address on the SPI bus. - #size-cells: Must be <0>. @@ -112,7 +111,6 @@ Example: pinctrl-names = "default", "sleep"; pinctrl-0 = <_1_spi_2_active>; pinctrl-1 = <_1_spi_2_sleep>; - spi-max-frequency = <1920>; #address-cells = <1>; #size-cells = <0>; }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 1/3] dt-bindings: soc: qcom: Remove SPI controller maximum frequency binding
From: Dilip Kota SPI controller driver should maintain the maximum frequency of the controller instead of relying on device tree bindings. Because maximum frequency is specific property of SPI controller. Signed-off-by: Dilip Kota Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Alok Chauhan --- Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt index ff92e5a..b9d0c21 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt @@ -60,7 +60,6 @@ Required properties: - interrupts: Must contain SPI controller interrupts. - clock-names: Must contain "se". - clocks: Serial engine core clock needed by the device. -- spi-max-frequency: Specifies maximum SPI clock frequency, units - Hz. - #address-cells: Must be <1> to define a chip select address on the SPI bus. - #size-cells: Must be <0>. @@ -112,7 +111,6 @@ Example: pinctrl-names = "default", "sleep"; pinctrl-0 = <_1_spi_2_active>; pinctrl-1 = <_1_spi_2_sleep>; - spi-max-frequency = <1920>; #address-cells = <1>; #size-cells = <0>; }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 0/3] spi-geni-qcom: QUP SPI GENI driver and SPI device tree bindings
This patch series adds the driver for GENI based Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) and SPI device tree bindings. An overview of the GENI SE SPI controller device tree components are in patch 2 and 1. Patch 3 adds the SPI driver for GENI QUP HW. changes from v4: - Patch 1/3 and 2/3 are unchanged - squashed patch 4/4 into 3/4 as suggested - Patch 3/3 changes are follows: * Add SPI M_COMMAND OPCODE to handle different geni command handling * Remove forward declaration of ISR * Remove unused variable rx_fifo_depth in spi_master structure * Declare cur_speed_hz as unsigned long to match clock framework * Declare cur_xfer as const pointer * Newline in error print * Correct consecutive spelling * Rename trans_len to len and restructure the lines in setup_fifo_xfer() * Rename timeout to time_left and restructure the handle_fifo_timeout() * Add check for '0' bytes transfer as part of spi_geni_transfer_one() * Correct if-else check in geni_byte_per_fifo_word() * Remove NULL current transfer check in geni_spi_handle_tx()/geni_spi_handle_rx() and make these functions as void. * Hoist rx_last_byte_valid variable into function scope * Remove RT check in ISR and add cur_mcmd handling * Correct the error prints in ISR * In spi_alloc_master() pass 2nd arg as sizeof(*mas) for code clarity * Use ret = PTR_ERR(se->base) for devm_ioremap_resource() err return * Move request irq code to probe() and used request_irq() in place of devm_request_irq() * Rewrite suspend/resume function * Add MODULE_DEVICE_TABLE(of, spi_geni_dt_match); * Remove include/linux/spi/spi-geni-qcom.h file Dilip Kota (2): dt-bindings: soc: qcom: Remove SPI controller maximum frequency binding dt-bindings: soc: qcom: GENI SE SPI controller device tree binding Girish Mahadevan (1): spi: spi-geni-qcom: Add SPI driver support for GENI based QUP .../devicetree/bindings/soc/qcom/qcom,geni-se.txt | 29 +- .../devicetree/bindings/spi/qcom,spi-geni-qcom.txt | 39 ++ drivers/spi/Kconfig| 12 + drivers/spi/Makefile | 1 + drivers/spi/spi-geni-qcom.c| 703 + 5 files changed, 757 insertions(+), 27 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt create mode 100644 drivers/spi/spi-geni-qcom.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH V5 0/3] spi-geni-qcom: QUP SPI GENI driver and SPI device tree bindings
This patch series adds the driver for GENI based Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) and SPI device tree bindings. An overview of the GENI SE SPI controller device tree components are in patch 2 and 1. Patch 3 adds the SPI driver for GENI QUP HW. changes from v4: - Patch 1/3 and 2/3 are unchanged - squashed patch 4/4 into 3/4 as suggested - Patch 3/3 changes are follows: * Add SPI M_COMMAND OPCODE to handle different geni command handling * Remove forward declaration of ISR * Remove unused variable rx_fifo_depth in spi_master structure * Declare cur_speed_hz as unsigned long to match clock framework * Declare cur_xfer as const pointer * Newline in error print * Correct consecutive spelling * Rename trans_len to len and restructure the lines in setup_fifo_xfer() * Rename timeout to time_left and restructure the handle_fifo_timeout() * Add check for '0' bytes transfer as part of spi_geni_transfer_one() * Correct if-else check in geni_byte_per_fifo_word() * Remove NULL current transfer check in geni_spi_handle_tx()/geni_spi_handle_rx() and make these functions as void. * Hoist rx_last_byte_valid variable into function scope * Remove RT check in ISR and add cur_mcmd handling * Correct the error prints in ISR * In spi_alloc_master() pass 2nd arg as sizeof(*mas) for code clarity * Use ret = PTR_ERR(se->base) for devm_ioremap_resource() err return * Move request irq code to probe() and used request_irq() in place of devm_request_irq() * Rewrite suspend/resume function * Add MODULE_DEVICE_TABLE(of, spi_geni_dt_match); * Remove include/linux/spi/spi-geni-qcom.h file Dilip Kota (2): dt-bindings: soc: qcom: Remove SPI controller maximum frequency binding dt-bindings: soc: qcom: GENI SE SPI controller device tree binding Girish Mahadevan (1): spi: spi-geni-qcom: Add SPI driver support for GENI based QUP .../devicetree/bindings/soc/qcom/qcom,geni-se.txt | 29 +- .../devicetree/bindings/spi/qcom,spi-geni-qcom.txt | 39 ++ drivers/spi/Kconfig| 12 + drivers/spi/Makefile | 1 + drivers/spi/spi-geni-qcom.c| 703 + 5 files changed, 757 insertions(+), 27 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt create mode 100644 drivers/spi/spi-geni-qcom.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] soc: qcom: Add irq clear handling during SE init
when the kernel inits a SE, its quite possible we have pending interrupts from bootloaders which did not handle/clear them. So do this in kernel at the SE init, to avoid some of it causing bad behavior, while at it also club all the register writes needed to clear the se irqs into a function to avoid repeating it over. Signed-off-by: Alok Chauhan --- drivers/soc/qcom/qcom-geni-se.c | 25 + 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index feed3db2..1422fc5 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -215,6 +215,16 @@ static void geni_se_io_init(void __iomem *base) writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); } +static void geni_se_irq_clear(struct geni_se *se) +{ + writel_relaxed(0, se->base + SE_GSI_EVENT_EN); + writel_relaxed(0x, se->base + SE_GENI_M_IRQ_CLEAR); + writel_relaxed(0x, se->base + SE_GENI_S_IRQ_CLEAR); + writel_relaxed(0x, se->base + SE_DMA_TX_IRQ_CLR); + writel_relaxed(0x, se->base + SE_DMA_RX_IRQ_CLR); + writel_relaxed(0x, se->base + SE_IRQ_EN); +} + /** * geni_se_init() - Initialize the GENI serial engine * @se:Pointer to the concerned serial engine. @@ -228,6 +238,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) { u32 val; + geni_se_irq_clear(se); geni_se_io_init(se->base); geni_se_io_set_mode(se->base); @@ -249,12 +260,7 @@ static void geni_se_select_fifo_mode(struct geni_se *se) u32 proto = geni_se_read_proto(se); u32 val; - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); - writel_relaxed(0x, se->base + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_DMA_TX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_DMA_RX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_IRQ_EN); + geni_se_irq_clear(se); val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); if (proto != GENI_SE_UART) { @@ -277,12 +283,7 @@ static void geni_se_select_dma_mode(struct geni_se *se) { u32 val; - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); - writel_relaxed(0x, se->base + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_DMA_TX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_DMA_RX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_IRQ_EN); + geni_se_irq_clear(se); val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); val |= GENI_DMA_MODE_EN; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] soc: qcom: Add irq clear handling during SE init
when the kernel inits a SE, its quite possible we have pending interrupts from bootloaders which did not handle/clear them. So do this in kernel at the SE init, to avoid some of it causing bad behavior, while at it also club all the register writes needed to clear the se irqs into a function to avoid repeating it over. Signed-off-by: Alok Chauhan --- drivers/soc/qcom/qcom-geni-se.c | 25 + 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index feed3db2..1422fc5 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -215,6 +215,16 @@ static void geni_se_io_init(void __iomem *base) writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); } +static void geni_se_irq_clear(struct geni_se *se) +{ + writel_relaxed(0, se->base + SE_GSI_EVENT_EN); + writel_relaxed(0x, se->base + SE_GENI_M_IRQ_CLEAR); + writel_relaxed(0x, se->base + SE_GENI_S_IRQ_CLEAR); + writel_relaxed(0x, se->base + SE_DMA_TX_IRQ_CLR); + writel_relaxed(0x, se->base + SE_DMA_RX_IRQ_CLR); + writel_relaxed(0x, se->base + SE_IRQ_EN); +} + /** * geni_se_init() - Initialize the GENI serial engine * @se:Pointer to the concerned serial engine. @@ -228,6 +238,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) { u32 val; + geni_se_irq_clear(se); geni_se_io_init(se->base); geni_se_io_set_mode(se->base); @@ -249,12 +260,7 @@ static void geni_se_select_fifo_mode(struct geni_se *se) u32 proto = geni_se_read_proto(se); u32 val; - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); - writel_relaxed(0x, se->base + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_DMA_TX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_DMA_RX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_IRQ_EN); + geni_se_irq_clear(se); val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); if (proto != GENI_SE_UART) { @@ -277,12 +283,7 @@ static void geni_se_select_dma_mode(struct geni_se *se) { u32 val; - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); - writel_relaxed(0x, se->base + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(0x, se->base + SE_DMA_TX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_DMA_RX_IRQ_CLR); - writel_relaxed(0x, se->base + SE_IRQ_EN); + geni_se_irq_clear(se); val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); val |= GENI_DMA_MODE_EN; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project