In Qualcomm SoCs, firmware loading for Serial Engines (SE) in the QUP
hardware has traditionally been managed by TrustZone (TZ). This setup
handled Serial Engines(SE) assignments and access control permissions,
ensuring a high level of security but limiting flexibility and
accessibility.
This limitation poses a significant challenge for developers who need more
flexibility to enable any protocol on any of the SEs within the QUP
hardware.
To address this, we are introducing a change that opens the firmware
loading mechanism to the Linux environment. This enhancement increases
flexibility and allows for more streamlined and efficient management. We
can now handle SE assignments and access control permissions directly
within Linux, eliminating the dependency on TZ.
We propose an alternative method for firmware loading and SE
ownership/transfer mode configuration based on device tree configuration.
This method does not rely on other execution environments, making it
accessible to all developers.
For SEs used prior to the kernel, their firmware will be loaded by the
respective image drivers (e.g., Debug UART, Secure or trusted SE).
Additionally, the GSI firmware, which is common to all SEs per QUPV3 core,
will not be loaded by Linux driver but TZ only. At the kernel level, only
the SE protocol driver should load the respective protocol firmware.
---
v1 -> v2:
- Drop the qcom,load-firmware property.
- Remove the fixed firmware path.
- Add the 'firmware-name' property in the QUP common driver.
- Add logic to read the firmware path from the device tree.
- Resolve kernel test robot warnings.
- Update the 'qcom,xfer-mode' property description.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-1-quic_vdadhani@quicinc.com/
---
Viken Dadhaniya (8):
dt-bindings: qcom: geni-se: Add 'firmware-name' property for firmware
loading
dt-bindings: i2c: qcom,i2c-geni: Add support for selecting data
transfer mode
spi: dt-bindings: Add support for selecting data transfer mode
dt-bindings: serial: Add support for selecting data transfer mode
soc: qcom: geni-se: Add support to load QUP SE Firmware via Linux
subsystem
i2c: qcom-geni: Load i2c qup Firmware from linux side
spi: geni-qcom: Load spi qup Firmware from linux side
serial: qcom-geni: Load UART qup Firmware from linux side
.../bindings/i2c/qcom,i2c-geni-qcom.yaml | 7 +
.../serial/qcom,serial-geni-qcom.yaml | 8 +
.../bindings/soc/qcom/qcom,geni-se.yaml | 5 +
.../bindings/spi/qcom,spi-geni-qcom.yaml | 7 +
drivers/i2c/busses/i2c-qcom-geni.c | 7 +-
drivers/soc/qcom/qcom-geni-se.c | 444 ++++++++++++++++++
drivers/spi/spi-geni-qcom.c | 7 +-
drivers/tty/serial/qcom_geni_serial.c | 7 +-
include/linux/soc/qcom/geni-se.h | 17 +
include/linux/soc/qcom/qup-fw-load.h | 179 +++++++
10 files changed, 682 insertions(+), 6 deletions(-)
create mode 100644 include/linux/soc/qcom/qup-fw-load.h
--
2.34.1
Document the 'firmware-name' property in the device tree bindings to
support loading SE (Serial Engine) firmware from the protocol driver,
allowing for more flexible firmware management.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.yaml | 5 +++++
1 file changed, 5 insertions(+)
@@ -54,6 +54,10 @@ properties:dma-coherent:true+firmware-name:+$ref:/schemas/types.yaml#/definitions/string+description:Specify the name of the QUP firmware to load.+required:-compatible-reg
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
I2C controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-2-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/i2c/qcom,i2c-geni-qcom.yaml | 7 +++++++
1 file changed, 7 insertions(+)
@@ -66,6 +66,12 @@ properties:required-opps:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-interrupts
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
SPI controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-3-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/spi/qcom,spi-geni-qcom.yaml | 7 +++++++
1 file changed, 7 insertions(+)
@@ -66,6 +66,12 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-clocks
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++required:-compatible-clocks
Load the firmware to QUP SE based on the 'firmware-name' property specified
in devicetree. Populate Serial engine and base address details in the probe
function of the protocol driver and pass to firmware load routine.
Skip the firmware loading if the firmware is already loaded in Serial
Engine's firmware memory area.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Remove the fixed firmware path and add logic to read the path from the device tree.
- Remove code related to the 'qcom,load-firmware' property.
- Resolve kernel test robot warnings.
- Update the commit message.
- Update Copyright year.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-5-quic_vdadhani@quicinc.com/
---
---
drivers/soc/qcom/qcom-geni-se.c | 444 +++++++++++++++++++++++++++
include/linux/soc/qcom/geni-se.h | 17 +
include/linux/soc/qcom/qup-fw-load.h | 179 +++++++++++
3 files changed, 640 insertions(+)
create mode 100644 include/linux/soc/qcom/qup-fw-load.h
@@ -1,5 +1,6 @@// SPDX-License-Identifier: GPL-2.0// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.+// Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved./* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */#define __DISABLE_TRACE_MMIO__
@@ -110,6 +112,9 @@ struct geni_se_desc {staticconstchar*consticc_path_names[]={"qup-core","qup-config","qup-memory"};+staticconstchar*constprotocol_name[]={"None","SPI","UART",+"I2C","I3C","SPI SLAVE"};+#define QUP_HW_VER_REG 0x4/* Common SE registers */
@@ -891,6 +896,445 @@ int geni_icc_disable(struct geni_se *se)}EXPORT_SYMBOL_GPL(geni_icc_disable);+/**+*elf_phdr_valid:Functiontovalidateelfheader.+*@phdr:Apointertoaelfheader.+*+*Thisfunctionvalidateselfheaderbycomparingfields+*storedinp_flagsandpayloadtype.+*+*return:trueforsuccessandfalseforfailure/errorcase.+*/+staticboolelf_phdr_valid(conststructelf32_phdr*phdr)+{+if(phdr->p_type!=PT_LOAD||!phdr->p_memsz)+returnfalse;++if(phdr->p_type==PT_LOAD&&+(MI_PBT_PAGE_MODE_VALUE(phdr->p_flags)==MI_PBT_NON_PAGED_SEGMENT)&&+(MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags)!=MI_PBT_HASH_SEGMENT)&&+(MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags)!=MI_PBT_NOTUSED_SEGMENT)&&+(MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags)!=MI_PBT_SHARED_SEGMENT))+returntrue;++returnfalse;+}++/**+*valid_seg_size:Functiontovalidatesegmentsize.+*@pelfseg:Apointertoaelfheader.+*@p_filesz:Apointertofilesize.+*+*Thisfunctionvalidateselfsegmentsizebycomparingfilesize+*+*return:Returntrueifsegmentisvalidandfalseifsegmentisinvalid.+*/+staticboolvalid_seg_size(structelf_se_hdr*pelfseg,Elf32_Wordp_filesz)+{+if(p_filesz>=pelfseg->fw_offset++pelfseg->fw_size_in_items*sizeof(u32)&&+p_filesz>=pelfseg->cfg_idx_offset++pelfseg->cfg_size_in_items*sizeof(u8)&&+p_filesz>=pelfseg->cfg_val_offset++pelfseg->cfg_size_in_items*sizeof(u32))+returntrue;+returnfalse;+}++/**+*read_elf:Functiontoreadelffile.+*@rsc:ApointertoSEresourcesstructure.+*@fw:Apointertothefwbuffer.+*@pelfseg:ApointertoSEspecificelfheader.+*@phdr:pointertooneofthevalidheadersfromlistfromfwbuffer.+*+*ThisfunctionreadstheELFfileandoutputsthepointertoheader+*datawhichcontainstheFWdataandanyotherdetails.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintread_elf(structqup_se_rsc*rsc,conststructfirmware*fw,+structelf_se_hdr**pelfseg,structelf32_phdr**phdr)+{+structelf32_phdr*phdrs;+conststructelf32_hdr*ehdr;+constu8*addr;+inti;++ehdr=(structelf32_hdr*)fw->data;++if(ehdr->e_phnum<2)+return-EINVAL;++phdrs=(structelf32_phdr*)(ehdr+1);++for(i=0;i<ehdr->e_phnum;i++){+*phdr=&phdrs[i];+if(!elf_phdr_valid(*phdr))+continue;++if((*phdr)->p_filesz>=sizeof(structelf_se_hdr)){+addr=fw->data+(*phdr)->p_offset;+*pelfseg=(structelf_se_hdr*)addr;++if((*pelfseg)->magic==MAGIC_NUM_SE&&+(*pelfseg)->version==1&&+valid_seg_size(*pelfseg,(*phdr)->p_filesz))+if((*pelfseg)->serial_protocol==rsc->protocol&&+(*pelfseg)->serial_protocol!=GENI_SE_NONE)+return0;+}+}+return-EINVAL;+}++/**+*geni_config_common_control:Functiontoconfigurecommoncgc+*anddisablehighpriorityinterrupt.+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*Thisfunctionconfigurescgcanddisableshighpriorityinterrupt+*untilcurrentlowpriorityinterruptsarehandled.+*+*return:None.+*/+staticvoidgeni_config_common_control(structqup_se_rsc*rsc)+{+/*+*Disablehighpriorityinterruptuntilcurrent+*lowpriorityinterruptsarehandled.+*/+setbits32(rsc->se->wrapper->base+QUPV3_COMMON_CFG,+FAST_SWITCH_TO_HIGH_DISABLE_BMASK);++/*+*SetAHB_M_CLK_CGC_ONtoindicatehardwarecontrols+*se-wrappercgcclock.+*/+setbits32(rsc->se->wrapper->base+QUPV3_SE_AHB_M_CFG,+AHB_M_CLK_CGC_ON_BMASK);++/* Let hardware to control common cgc. */+setbits32(rsc->se->wrapper->base+QUPV3_COMMON_CGC_CTRL,+COMMON_CSR_SLV_CLK_CGC_ON_BMASK);+}++/**+*geni_configure_xfer_mode:Functiontosettransfermode.+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*ThisfunctionsetstransfermodeFIFOorDMAaccordingtomode+*specifiedbyprotocoldriver..+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintgeni_configure_xfer_mode(structqup_se_rsc*rsc)+{+/* Configure SE FIFO, DMA or GSI mode. */+switch(rsc->mode){+caseGENI_GPI_DMA:+setbits32(rsc->se->base+QUPV3_SE_GENI_DMA_MODE_EN,+GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);+writel_relaxed(0x0,rsc->se->base+SE_IRQ_EN);+writel_relaxed(SE_GSI_EVENT_EN_BMSK,rsc->se->base+SE_GSI_EVENT_EN);+break;++caseGENI_SE_FIFO:+clrbits32(rsc->se->base+QUPV3_SE_GENI_DMA_MODE_EN,+GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);+writel_relaxed(SE_IRQ_EN_RMSK,rsc->se->base+SE_IRQ_EN);+writel_relaxed(0x0,rsc->se->base+SE_GSI_EVENT_EN);+break;++caseGENI_SE_DMA:+setbits32(rsc->se->base+QUPV3_SE_GENI_DMA_MODE_EN,+GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);+writel_relaxed(SE_IRQ_EN_RMSK,rsc->se->base+SE_IRQ_EN);+writel_relaxed(0x0,rsc->se->base+SE_GSI_EVENT_EN);+break;++default:+dev_err(rsc->se->dev,"invalid se mode: %d\n",rsc->mode);+return-EINVAL;+}+return0;+}++/**+*geni_enable_interrupts:Functiontoenableinterrupts+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*Thisfunctionenablesrequiredinterruptduringfirmwareloadprocess.+*+*return:None.+*/+staticvoidgeni_enable_interrupts(structqup_se_rsc*rsc)+{+u32reg_value;++/* Enable required interrupts. */+writel_relaxed(M_COMMON_GENI_M_IRQ_EN,rsc->se->base+GENI_M_IRQ_ENABLE);++reg_value=S_CMD_OVERRUN_EN|S_ILLEGAL_CMD_EN|+S_CMD_CANCEL_EN|S_CMD_ABORT_EN|+S_GP_IRQ_0_EN|S_GP_IRQ_1_EN|+S_GP_IRQ_2_EN|S_GP_IRQ_3_EN|+S_RX_FIFO_WR_ERR_EN|S_RX_FIFO_RD_ERR_EN;+writel_relaxed(reg_value,rsc->se->base+GENI_S_IRQ_ENABLE);++/* DMA mode configuration. */+reg_value=DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK|+DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK|+DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;+writel_relaxed(reg_value,rsc->se->base+DMA_TX_IRQ_EN_SET);+reg_value=DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK|+DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK|+DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK|+DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;+writel_relaxed(reg_value,rsc->se->base+DMA_RX_IRQ_EN_SET);+}++/**+*geni_flash_fw_revision:Functiontoflashrevision+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*@hdr:ApointertoELFheaderofSerialEngine.+*Thisfunctionflashfirmwarerevisionandprotocolinrespectiveregister.+*+*return:None.+*/+staticvoidgeni_flash_fw_revision(structqup_se_rsc*rsc,structelf_se_hdr*hdr)+{+u32reg_value;++/* Flash firmware revision register. */+reg_value=(hdr->serial_protocol<<FW_REV_PROTOCOL_SHFT)|+(hdr->fw_version&0xFF<<FW_REV_VERSION_SHFT);+writel_relaxed(reg_value,rsc->se->base+SE_GENI_FW_REVISION);++reg_value=(hdr->serial_protocol<<FW_REV_PROTOCOL_SHFT)|+(hdr->fw_version&0xFF<<FW_REV_VERSION_SHFT);++writel_relaxed(reg_value,rsc->se->base+SE_S_FW_REVISION);+}++/**+*geni_load_se_fw:Functiontoloadserialenginespecificfirmware+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*@fw:ApointertoFirmwarestructure.+*+*ThisfunctionloadstheprotocolFWattheIRAMoftheSE.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintgeni_load_se_fw(structqup_se_rsc*rsc,conststructfirmware*fw)+{+constu32*fw_val_arr,*cfg_val_arr;+constu8*cfg_idx_arr;+u32i,reg_value,mask,ramn_cnt;+intret=0;+structelf_se_hdr*hdr;+structelf32_phdr*phdr;++ret=geni_icc_set_bw(rsc->se);+if(ret){+dev_err(rsc->se->dev,"%s: Failed to set ICC BW %d\n",__func__,ret);+returnret;+}++ret=geni_icc_enable(rsc->se);+if(ret){+dev_err(rsc->se->dev,"%s: Failed to enable ICC %d\n",__func__,ret);+returnret;+}++ret=geni_se_resources_on(rsc->se);+if(ret){+dev_err(rsc->se->dev,"%s: Failed to enable common clocks %d\n",__func__,ret);+gotoerr;+}++ret=read_elf(rsc,fw,&hdr,&phdr);+if(ret){+dev_err(rsc->se->dev,"%s: elf parsing failed ret: %d\n",__func__,ret);+gotoerr;+}++fw_val_arr=(constu32*)((u8*)hdr+hdr->fw_offset);+cfg_idx_arr=(constu8*)hdr+hdr->cfg_idx_offset;+cfg_val_arr=(constu32*)((u8*)hdr+hdr->cfg_val_offset);++geni_config_common_control(rsc);++/* Allows to drive corresponding data according to hardware value. */+writel_relaxed(0x0,rsc->se->base+GENI_OUTPUT_CTRL);++/* Set SCLK and HCLK to program RAM */+setbits32(rsc->se->base+GENI_CGC_CTRL,GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK+|GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);+writel_relaxed(0x0,rsc->se->base+SE_GENI_CLK_CTRL);+clrbits32(rsc->se->base+GENI_CGC_CTRL,GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK+|GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);++/* Enable required clocks for DMA CSR, TX and RX. */+reg_value=DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK|+DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK|+DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK|+DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK;++setbits32(rsc->se->base+DMA_GENERAL_CFG,reg_value);++/* Let hardware to control CGC by default. */+writel_relaxed(DEFAULT_CGC_EN,rsc->se->base+GENI_CGC_CTRL);++/* Set version of the configuration register part of firmware. */+writel_relaxed(hdr->cfg_version,rsc->se->base+GENI_INIT_CFG_REVISION);+writel_relaxed(hdr->cfg_version,rsc->se->base+GENI_S_INIT_CFG_REVISION);++/* Configure geni primitive table. */+for(i=0;i<hdr->cfg_size_in_items;i++)+writel_relaxed(cfg_val_arr[i],rsc->se->base++GENI_CFG_REG0+(cfg_idx_arr[i]*sizeof(u32)));++/* Configure condition for assertion of RX_RFR_WATERMARK condition. */+reg_value=readl_relaxed(rsc->se->base+QUPV3_SE_HW_PARAM_1);+mask=(reg_value>>RX_FIFO_WIDTH_BIT)&RX_FIFO_WIDTH_MASK;+writel_relaxed(mask-2,rsc->se->base+GENI_RX_RFR_WATERMARK_REG);++/* Let hardware to control CGC */+setbits32(rsc->se->base+GENI_OUTPUT_CTRL,DEFAULT_IO_OUTPUT_CTRL_MSK);++ret=geni_configure_xfer_mode(rsc);+if(ret)+gotoerr_resource;++geni_enable_interrupts(rsc);++geni_flash_fw_revision(rsc,hdr);++ramn_cnt=hdr->fw_size_in_items;+if(hdr->fw_size_in_items%2!=0)+ramn_cnt++;++if(ramn_cnt>=MAX_GENI_CFG_RAMn_CNT)+gotoerr_resource;++/* Program RAM address space. */+memcpy((rsc->se->base+SE_GENI_CFG_RAMN),fw_val_arr,+ramn_cnt*sizeof(u32));++/* Put default values on GENI's output pads. */+writel_relaxed(0x1,rsc->se->base+GENI_FORCE_DEFAULT_REG);++/* High to low SCLK and HCLK to finish RAM. */+setbits32(rsc->se->base+GENI_CGC_CTRL,GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK+|GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);+setbits32(rsc->se->base+SE_GENI_CLK_CTRL,GENI_CLK_CTRL_SER_CLK_SEL_BMSK);+clrbits32(rsc->se->base+GENI_CGC_CTRL,+(GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK|+GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK));++/* Serial engine DMA interface is enabled. */+setbits32(rsc->se->base+SE_DMA_IF_EN,DMA_IF_EN_DMA_IF_EN_BMSK);++/* Enable or disable FIFO interface of the serial engine. */+if(rsc->mode==GENI_SE_FIFO)+clrbits32(rsc->se->base+SE_FIFO_IF_DISABLE,FIFO_IF_DISABLE);+else+setbits32(rsc->se->base+SE_FIFO_IF_DISABLE,FIFO_IF_DISABLE);++err_resource:+geni_se_resources_off(rsc->se);+err:+geni_icc_disable(rsc->se);+returnret;+}++/**+*qup_fw_load:Functiontoinitiatefirmwareload+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*Thisfunctioniscalledforloadingthefirmwareintoaparticular+*SE.ThisisachievedbyreadingtheassociatedELFfile,copying+*thedataintheELFfileintobufferinkernelspaceusing+*request_firmwareAPI's.ThedataisthenwrittenintheSE's+*IRAMregisterandthebuffersarefreedafter.Overall,this+*functionhandlesfirmwareloadingandparsingforaspecificprotocol.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintqup_fw_load(structqup_se_rsc*rsc,constchar*fw_name)+{+intret;+conststructfirmware*fw;+structdevice*dev=rsc->se->dev;++ret=request_firmware(&fw,fw_name,dev);+if(ret){+dev_err(dev,"request_firmware failed for %d: %d\n",rsc->protocol,ret);+returnret;+}++ret=(rsc->protocol!=GENI_SE_NONE)?geni_load_se_fw(rsc,fw):-EINVAL;++release_firmware(fw);++returnret;+}++/**+*geni_load_se_firmware:Functiontoinitiatefirmwareloading.+*@se:Serialenginedetails.+*@protocol:protocolfromspi,i2coruartforwhichfirmwareto+*beloaded+*+*Thisfunctioniscalledfromtheprobefunctionofprotocoldriver.+*ifdtsipropertiesareconfiguredtoloadQUPfirmwareandfirmware+*isalreadynotloaded,itwillstartfirmwareloading.ifdtsi+*propertiesarenotdefined,itwillskiploadingfirmwareassuming+*itisalreadyloadedbyTZ.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+intgeni_load_se_firmware(structgeni_se*se,+enumgeni_se_protocol_typeprotocol)+{+structqup_se_rscrsc;+constchar*fw_name;+intret;++ret=device_property_read_string(se->wrapper->dev,"firmware-name",&fw_name);+if(ret)+return-EINVAL;++rsc.se=se;+rsc.protocol=protocol;++/* Set default xfer mode to FIFO*/+rsc.mode=GENI_SE_FIFO;+of_property_read_u32(se->dev->of_node,"qcom,xfer-mode",&rsc.mode);+switch(rsc.mode){+caseGENI_SE_FIFO:+caseGENI_SE_DMA:+caseGENI_GPI_DMA:+break;+default:+dev_err(se->dev,"Invalid xfer mode specified: %d\n",rsc.mode);+return-EINVAL;+}++ret=qup_fw_load(&rsc,fw_name);+if(ret){+dev_err(se->dev,"Firmware Loading failed for proto: %s Error: %d\n",+protocol_name[rsc.protocol],ret);+returnret;+}++dev_dbg(se->dev,"Firmware load for %s protocol is Success for xfer mode %d\n",+protocol_name[rsc.protocol],rsc.mode);+returnret;+}+EXPORT_SYMBOL_GPL(geni_load_se_firmware);+staticintgeni_se_probe(structplatform_device*pdev){structdevice*dev=&pdev->dev;
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-01-24 11:01:02
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted hunk
Document the 'firmware-name' property in the device tree bindings to
support loading SE (Serial Engine) firmware from the protocol driver,
allowing for more flexible firmware management.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.yaml | 5 +++++
1 file changed, 5 insertions(+)
On Fri, Jan 24, 2025 at 04:23:03PM +0530, Viken Dadhaniya wrote:
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
I2C controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Is it possible to load the firmware after it being loaded by TZ? Is it
possible to change the mode at runtime too?
@@ -66,6 +66,12 @@ properties:required-opps:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-interrupts
Document the 'firmware-name' property in the device tree bindings to
support loading SE (Serial Engine) firmware from the protocol driver,
allowing for more flexible firmware management.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.yaml | 5 +++++
1 file changed, 5 insertions(+)
On Fri, Jan 24, 2025 at 04:23:03PM +0530, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
I2C controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Is it possible to load the firmware after it being loaded by TZ? Is it
possible to change the mode at runtime too?
No, firmware can be loaded either from the TZ side or APPS side.
In non-GPI mode, the transfer mode will change runtime between PIO and CPU DMA based on the data length.
We need to update the device tree property(qcom,xfer-mode) to change the mode between non-GPI and GPI.
@@ -66,6 +66,12 @@ properties:required-opps:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-interrupts
On Fri, Jan 24, 2025 at 05:52:24PM +0530, Viken Dadhaniya wrote:
On 1/24/2025 4:48 PM, Dmitry Baryshkov wrote:
quoted
On Fri, Jan 24, 2025 at 04:23:03PM +0530, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
I2C controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Is it possible to load the firmware after it being loaded by TZ? Is it
possible to change the mode at runtime too?
No, firmware can be loaded either from the TZ side or APPS side.
You answer actually reads as "No, yes" (excuse me, non-native here).
Most likely you mean that it can not be reloaded once either TZ or APPS
has loaded it.
In non-GPI mode, the transfer mode will change runtime between PIO and CPU
DMA based on the data length.
We need to update the device tree property(qcom,xfer-mode) to change the
mode between non-GPI and GPI.
So, is it actually possible to change the mode? E.g. if the TZ has
loaded the firmware and configured SE for PIO/SE DMA, is it possible to
change it to GPI DMA?
@@ -66,6 +66,12 @@ properties:required-opps:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-interrupts
On Fri, Jan 24, 2025 at 05:52:24PM +0530, Viken Dadhaniya wrote:
quoted
On 1/24/2025 4:48 PM, Dmitry Baryshkov wrote:
quoted
On Fri, Jan 24, 2025 at 04:23:03PM +0530, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
I2C controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Is it possible to load the firmware after it being loaded by TZ? Is it
possible to change the mode at runtime too?
No, firmware can be loaded either from the TZ side or APPS side.
You answer actually reads as "No, yes" (excuse me, non-native here).
Most likely you mean that it can not be reloaded once either TZ or APPS
has loaded it.
Yes correct. it can not be reloaded once either TZ or APPS has loaded it.
quoted
In non-GPI mode, the transfer mode will change runtime between PIO and CPU
DMA based on the data length.
We need to update the device tree property(qcom,xfer-mode) to change the
mode between non-GPI and GPI.
So, is it actually possible to change the mode? E.g. if the TZ has
loaded the firmware and configured SE for PIO/SE DMA, is it possible to
change it to GPI DMA?
No, if the TZ has loaded the firmware, it is not possible to switch from non-GPI (PIO/SE DMA) to GPI DMA mode.
@@ -66,6 +66,12 @@ properties:required-opps:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-interrupts
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-01-27 06:58:18
On 24/01/2025 16:16, Viken Dadhaniya wrote:
On 1/24/2025 8:33 PM, Dmitry Baryshkov wrote:
quoted
On Fri, Jan 24, 2025 at 05:52:24PM +0530, Viken Dadhaniya wrote:
quoted
On 1/24/2025 4:48 PM, Dmitry Baryshkov wrote:
quoted
On Fri, Jan 24, 2025 at 04:23:03PM +0530, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
I2C controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Is it possible to load the firmware after it being loaded by TZ? Is it
possible to change the mode at runtime too?
No, firmware can be loaded either from the TZ side or APPS side.
You answer actually reads as "No, yes" (excuse me, non-native here).
Most likely you mean that it can not be reloaded once either TZ or APPS
has loaded it.
Yes correct. it can not be reloaded once either TZ or APPS has loaded it.
quoted
quoted
In non-GPI mode, the transfer mode will change runtime between PIO and CPU
DMA based on the data length.
We need to update the device tree property(qcom,xfer-mode) to change the
mode between non-GPI and GPI.
So, is it actually possible to change the mode? E.g. if the TZ has
loaded the firmware and configured SE for PIO/SE DMA, is it possible to
change it to GPI DMA?
No, if the TZ has loaded the firmware, it is not possible to switch from
non-GPI (PIO/SE DMA) to GPI DMA mode.
@@ -66,6 +66,12 @@ properties:required-opps:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]+required:-compatible-interrupts
What does <1> mean? Please provide corresponding defines.
Do we need to add a string instead of a number, like
include/dt-bindings/dma/qcom-gpi.h?
You need to '#define FOO_BAR 1', then another one for 3. String is a
"string", it's not required here (in my opinion).
Sure, I will update it in the next patch.
Well, no. Not 3 but 2, because why having gap there?
But anyway use string and explain what is GPI. I assume that DMA is
present in both cases, you just choose not to use it? If so, then why?
Best regards,
Krzysztof
@@ -66,6 +66,12 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32
Same concerns as for I2C, so discussion going there.
Best regards,
Krzysztof
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-01-27 07:02:20
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted hunk
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Best regards,
Krzysztof
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-01-27 07:06:31
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted hunk
/* Common SE registers */
@@ -891,6 +896,445 @@ int geni_icc_disable(struct geni_se *se) } EXPORT_SYMBOL_GPL(geni_icc_disable);+/**+ * elf_phdr_valid: Function to validate elf header.+ * @phdr: A pointer to a elf header.+ *+ * This function validates elf header by comparing fields
Drop "This function" and use imperative. It's redundant and you keep
using it everywherre here
...
quoted hunk
+static int qup_fw_load(struct qup_se_rsc *rsc, const char *fw_name)+{+ int ret;+ const struct firmware *fw;+ struct device *dev = rsc->se->dev;++ ret = request_firmware(&fw, fw_name, dev);+ if (ret) {+ dev_err(dev, "request_firmware failed for %d: %d\n", rsc->protocol, ret);+ return ret;+ }++ ret = (rsc->protocol != GENI_SE_NONE) ? geni_load_se_fw(rsc, fw) : -EINVAL;
Drop ternary operator. Not easy to read.
quoted hunk
++ release_firmware(fw);++ return ret;+}
quoted hunk
++/**+ * geni_load_se_firmware: Function to initiate firmware loading.+ * @se: Serial engine details.+ * @protocol: protocol from spi, i2c or uart for which firmware to+ * be loaded+ *+ * This function is called from the probe function of protocol driver.+ * if dtsi properties are configured to load QUP firmware and firmware+ * is already not loaded, it will start firmware loading. if dtsi+ * properties are not defined,it will skip loading firmware assuming+ * it is already loaded by TZ.+ *+ * return: Return 0 if no error, else return error value.+ */+int geni_load_se_firmware(struct geni_se *se,+ enum geni_se_protocol_type protocol)+{+ struct qup_se_rsc rsc;+ const char *fw_name;+ int ret;++ ret = device_property_read_string(se->wrapper->dev, "firmware-name", &fw_name);+ if (ret)+ return -EINVAL;++ rsc.se = se;+ rsc.protocol = protocol;++ /* Set default xfer mode to FIFO*/+ rsc.mode = GENI_SE_FIFO;+ of_property_read_u32(se->dev->of_node, "qcom,xfer-mode", &rsc.mode);+ switch (rsc.mode) {+ case GENI_SE_FIFO:+ case GENI_SE_DMA:
How value of 2 is acceptable? Your bindings said it is not.
quoted hunk
+ case GENI_GPI_DMA:+ break;+ default:+ dev_err(se->dev, "Invalid xfer mode specified: %d\n", rsc.mode);+ return -EINVAL;+ }++ ret = qup_fw_load(&rsc, fw_name);+ if (ret) {+ dev_err(se->dev, "Firmware Loading failed for proto: %s Error: %d\n",+ protocol_name[rsc.protocol], ret);
Aren't you printing same error multiple times?
quoted hunk
+ return ret;+ }++ dev_dbg(se->dev, "Firmware load for %s protocol is Success for xfer mode %d\n",+ protocol_name[rsc.protocol], rsc.mode);+ return ret;+}+EXPORT_SYMBOL_GPL(geni_load_se_firmware);+ static int geni_se_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev;
Load the firmware to QUP SE based on the 'firmware-name' property specified
in devicetree. Populate Serial engine and base address details in the probe
function of the protocol driver and pass to firmware load routine.
Skip the firmware loading if the firmware is already loaded in Serial
Engine's firmware memory area.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Remove the fixed firmware path and add logic to read the path from the device tree.
- Remove code related to the 'qcom,load-firmware' property.
- Resolve kernel test robot warnings.
- Update the commit message.
- Update Copyright year.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-5-quic_vdadhani@quicinc.com/
---
---
drivers/soc/qcom/qcom-geni-se.c | 444 +++++++++++++++++++++++++++
include/linux/soc/qcom/geni-se.h | 17 +
include/linux/soc/qcom/qup-fw-load.h | 179 +++++++++++
3 files changed, 640 insertions(+)
create mode 100644 include/linux/soc/qcom/qup-fw-load.h
@@ -1,5 +1,6 @@// SPDX-License-Identifier: GPL-2.0// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.+// Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved./* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */#define __DISABLE_TRACE_MMIO__
@@ -110,6 +112,9 @@ struct geni_se_desc {staticconstchar*consticc_path_names[]={"qup-core","qup-config","qup-memory"};+staticconstchar*constprotocol_name[]={"None","SPI","UART",+"I2C","I3C","SPI SLAVE"};+#define QUP_HW_VER_REG 0x4/* Common SE registers */
@@ -891,6 +896,445 @@ int geni_icc_disable(struct geni_se *se)}EXPORT_SYMBOL_GPL(geni_icc_disable);+/**+*elf_phdr_valid:Functiontovalidateelfheader.+*@phdr:Apointertoaelfheader.+*+*Thisfunctionvalidateselfheaderbycomparingfields+*storedinp_flagsandpayloadtype.+*+*return:trueforsuccessandfalseforfailure/errorcase.+*/+staticboolelf_phdr_valid(conststructelf32_phdr*phdr)+{+if(phdr->p_type!=PT_LOAD||!phdr->p_memsz)+returnfalse;++if(phdr->p_type==PT_LOAD&&+(MI_PBT_PAGE_MODE_VALUE(phdr->p_flags)==MI_PBT_NON_PAGED_SEGMENT)&&+(MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags)!=MI_PBT_HASH_SEGMENT)&&+(MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags)!=MI_PBT_NOTUSED_SEGMENT)&&+(MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags)!=MI_PBT_SHARED_SEGMENT))+returntrue;++returnfalse;+}++/**+*valid_seg_size:Functiontovalidatesegmentsize.+*@pelfseg:Apointertoaelfheader.+*@p_filesz:Apointertofilesize.+*+*Thisfunctionvalidateselfsegmentsizebycomparingfilesize+*+*return:Returntrueifsegmentisvalidandfalseifsegmentisinvalid.+*/+staticboolvalid_seg_size(structelf_se_hdr*pelfseg,Elf32_Wordp_filesz)+{+if(p_filesz>=pelfseg->fw_offset++pelfseg->fw_size_in_items*sizeof(u32)&&+p_filesz>=pelfseg->cfg_idx_offset++pelfseg->cfg_size_in_items*sizeof(u8)&&+p_filesz>=pelfseg->cfg_val_offset++pelfseg->cfg_size_in_items*sizeof(u32))+returntrue;+returnfalse;+}++/**+*read_elf:Functiontoreadelffile.+*@rsc:ApointertoSEresourcesstructure.+*@fw:Apointertothefwbuffer.+*@pelfseg:ApointertoSEspecificelfheader.+*@phdr:pointertooneofthevalidheadersfromlistfromfwbuffer.+*+*ThisfunctionreadstheELFfileandoutputsthepointertoheader+*datawhichcontainstheFWdataandanyotherdetails.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintread_elf(structqup_se_rsc*rsc,conststructfirmware*fw,+structelf_se_hdr**pelfseg,structelf32_phdr**phdr)+{+structelf32_phdr*phdrs;+conststructelf32_hdr*ehdr;+constu8*addr;+inti;++ehdr=(structelf32_hdr*)fw->data;++if(ehdr->e_phnum<2)+return-EINVAL;++phdrs=(structelf32_phdr*)(ehdr+1);++for(i=0;i<ehdr->e_phnum;i++){+*phdr=&phdrs[i];+if(!elf_phdr_valid(*phdr))+continue;++if((*phdr)->p_filesz>=sizeof(structelf_se_hdr)){+addr=fw->data+(*phdr)->p_offset;+*pelfseg=(structelf_se_hdr*)addr;++if((*pelfseg)->magic==MAGIC_NUM_SE&&+(*pelfseg)->version==1&&+valid_seg_size(*pelfseg,(*phdr)->p_filesz))+if((*pelfseg)->serial_protocol==rsc->protocol&&+(*pelfseg)->serial_protocol!=GENI_SE_NONE)+return0;+}+}+return-EINVAL;+}++/**+*geni_config_common_control:Functiontoconfigurecommoncgc+*anddisablehighpriorityinterrupt.+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*Thisfunctionconfigurescgcanddisableshighpriorityinterrupt+*untilcurrentlowpriorityinterruptsarehandled.+*+*return:None.+*/+staticvoidgeni_config_common_control(structqup_se_rsc*rsc)+{+/*+*Disablehighpriorityinterruptuntilcurrent+*lowpriorityinterruptsarehandled.+*/+setbits32(rsc->se->wrapper->base+QUPV3_COMMON_CFG,+FAST_SWITCH_TO_HIGH_DISABLE_BMASK);++/*+*SetAHB_M_CLK_CGC_ONtoindicatehardwarecontrols+*se-wrappercgcclock.+*/+setbits32(rsc->se->wrapper->base+QUPV3_SE_AHB_M_CFG,+AHB_M_CLK_CGC_ON_BMASK);++/* Let hardware to control common cgc. */+setbits32(rsc->se->wrapper->base+QUPV3_COMMON_CGC_CTRL,+COMMON_CSR_SLV_CLK_CGC_ON_BMASK);+}++/**+*geni_configure_xfer_mode:Functiontosettransfermode.+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*ThisfunctionsetstransfermodeFIFOorDMAaccordingtomode+*specifiedbyprotocoldriver..+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintgeni_configure_xfer_mode(structqup_se_rsc*rsc)+{+/* Configure SE FIFO, DMA or GSI mode. */+switch(rsc->mode){+caseGENI_GPI_DMA:+setbits32(rsc->se->base+QUPV3_SE_GENI_DMA_MODE_EN,+GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);+writel_relaxed(0x0,rsc->se->base+SE_IRQ_EN);+writel_relaxed(SE_GSI_EVENT_EN_BMSK,rsc->se->base+SE_GSI_EVENT_EN);+break;++caseGENI_SE_FIFO:+clrbits32(rsc->se->base+QUPV3_SE_GENI_DMA_MODE_EN,+GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);+writel_relaxed(SE_IRQ_EN_RMSK,rsc->se->base+SE_IRQ_EN);+writel_relaxed(0x0,rsc->se->base+SE_GSI_EVENT_EN);+break;++caseGENI_SE_DMA:+setbits32(rsc->se->base+QUPV3_SE_GENI_DMA_MODE_EN,+GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);+writel_relaxed(SE_IRQ_EN_RMSK,rsc->se->base+SE_IRQ_EN);+writel_relaxed(0x0,rsc->se->base+SE_GSI_EVENT_EN);+break;++default:+dev_err(rsc->se->dev,"invalid se mode: %d\n",rsc->mode);+return-EINVAL;+}+return0;+}++/**+*geni_enable_interrupts:Functiontoenableinterrupts+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*Thisfunctionenablesrequiredinterruptduringfirmwareloadprocess.+*+*return:None.+*/+staticvoidgeni_enable_interrupts(structqup_se_rsc*rsc)+{+u32reg_value;++/* Enable required interrupts. */+writel_relaxed(M_COMMON_GENI_M_IRQ_EN,rsc->se->base+GENI_M_IRQ_ENABLE);++reg_value=S_CMD_OVERRUN_EN|S_ILLEGAL_CMD_EN|+S_CMD_CANCEL_EN|S_CMD_ABORT_EN|+S_GP_IRQ_0_EN|S_GP_IRQ_1_EN|+S_GP_IRQ_2_EN|S_GP_IRQ_3_EN|+S_RX_FIFO_WR_ERR_EN|S_RX_FIFO_RD_ERR_EN;+writel_relaxed(reg_value,rsc->se->base+GENI_S_IRQ_ENABLE);++/* DMA mode configuration. */+reg_value=DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK|+DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK|+DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;+writel_relaxed(reg_value,rsc->se->base+DMA_TX_IRQ_EN_SET);+reg_value=DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK|+DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK|+DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK|+DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;+writel_relaxed(reg_value,rsc->se->base+DMA_RX_IRQ_EN_SET);+}++/**+*geni_flash_fw_revision:Functiontoflashrevision+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*@hdr:ApointertoELFheaderofSerialEngine.+*Thisfunctionflashfirmwarerevisionandprotocolinrespectiveregister.+*+*return:None.+*/+staticvoidgeni_flash_fw_revision(structqup_se_rsc*rsc,structelf_se_hdr*hdr)+{+u32reg_value;++/* Flash firmware revision register. */+reg_value=(hdr->serial_protocol<<FW_REV_PROTOCOL_SHFT)|+(hdr->fw_version&0xFF<<FW_REV_VERSION_SHFT);+writel_relaxed(reg_value,rsc->se->base+SE_GENI_FW_REVISION);++reg_value=(hdr->serial_protocol<<FW_REV_PROTOCOL_SHFT)|+(hdr->fw_version&0xFF<<FW_REV_VERSION_SHFT);++writel_relaxed(reg_value,rsc->se->base+SE_S_FW_REVISION);+}++/**+*geni_load_se_fw:Functiontoloadserialenginespecificfirmware+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*@fw:ApointertoFirmwarestructure.+*+*ThisfunctionloadstheprotocolFWattheIRAMoftheSE.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintgeni_load_se_fw(structqup_se_rsc*rsc,conststructfirmware*fw)+{+constu32*fw_val_arr,*cfg_val_arr;+constu8*cfg_idx_arr;+u32i,reg_value,mask,ramn_cnt;+intret=0;+structelf_se_hdr*hdr;+structelf32_phdr*phdr;++ret=geni_icc_set_bw(rsc->se);+if(ret){+dev_err(rsc->se->dev,"%s: Failed to set ICC BW %d\n",__func__,ret);+returnret;+}++ret=geni_icc_enable(rsc->se);+if(ret){+dev_err(rsc->se->dev,"%s: Failed to enable ICC %d\n",__func__,ret);+returnret;+}++ret=geni_se_resources_on(rsc->se);+if(ret){+dev_err(rsc->se->dev,"%s: Failed to enable common clocks %d\n",__func__,ret);+gotoerr;+}++ret=read_elf(rsc,fw,&hdr,&phdr);+if(ret){+dev_err(rsc->se->dev,"%s: elf parsing failed ret: %d\n",__func__,ret);+gotoerr;+}++fw_val_arr=(constu32*)((u8*)hdr+hdr->fw_offset);+cfg_idx_arr=(constu8*)hdr+hdr->cfg_idx_offset;+cfg_val_arr=(constu32*)((u8*)hdr+hdr->cfg_val_offset);++geni_config_common_control(rsc);++/* Allows to drive corresponding data according to hardware value. */+writel_relaxed(0x0,rsc->se->base+GENI_OUTPUT_CTRL);++/* Set SCLK and HCLK to program RAM */+setbits32(rsc->se->base+GENI_CGC_CTRL,GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK+|GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);+writel_relaxed(0x0,rsc->se->base+SE_GENI_CLK_CTRL);+clrbits32(rsc->se->base+GENI_CGC_CTRL,GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK+|GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);++/* Enable required clocks for DMA CSR, TX and RX. */+reg_value=DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK|+DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK|+DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK|+DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK;++setbits32(rsc->se->base+DMA_GENERAL_CFG,reg_value);++/* Let hardware to control CGC by default. */+writel_relaxed(DEFAULT_CGC_EN,rsc->se->base+GENI_CGC_CTRL);++/* Set version of the configuration register part of firmware. */+writel_relaxed(hdr->cfg_version,rsc->se->base+GENI_INIT_CFG_REVISION);+writel_relaxed(hdr->cfg_version,rsc->se->base+GENI_S_INIT_CFG_REVISION);++/* Configure geni primitive table. */+for(i=0;i<hdr->cfg_size_in_items;i++)+writel_relaxed(cfg_val_arr[i],rsc->se->base++GENI_CFG_REG0+(cfg_idx_arr[i]*sizeof(u32)));++/* Configure condition for assertion of RX_RFR_WATERMARK condition. */+reg_value=readl_relaxed(rsc->se->base+QUPV3_SE_HW_PARAM_1);+mask=(reg_value>>RX_FIFO_WIDTH_BIT)&RX_FIFO_WIDTH_MASK;+writel_relaxed(mask-2,rsc->se->base+GENI_RX_RFR_WATERMARK_REG);++/* Let hardware to control CGC */+setbits32(rsc->se->base+GENI_OUTPUT_CTRL,DEFAULT_IO_OUTPUT_CTRL_MSK);++ret=geni_configure_xfer_mode(rsc);+if(ret)+gotoerr_resource;++geni_enable_interrupts(rsc);++geni_flash_fw_revision(rsc,hdr);++ramn_cnt=hdr->fw_size_in_items;+if(hdr->fw_size_in_items%2!=0)+ramn_cnt++;++if(ramn_cnt>=MAX_GENI_CFG_RAMn_CNT)+gotoerr_resource;++/* Program RAM address space. */+memcpy((rsc->se->base+SE_GENI_CFG_RAMN),fw_val_arr,+ramn_cnt*sizeof(u32));++/* Put default values on GENI's output pads. */+writel_relaxed(0x1,rsc->se->base+GENI_FORCE_DEFAULT_REG);++/* High to low SCLK and HCLK to finish RAM. */+setbits32(rsc->se->base+GENI_CGC_CTRL,GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK+|GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);+setbits32(rsc->se->base+SE_GENI_CLK_CTRL,GENI_CLK_CTRL_SER_CLK_SEL_BMSK);+clrbits32(rsc->se->base+GENI_CGC_CTRL,+(GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK|+GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK));++/* Serial engine DMA interface is enabled. */+setbits32(rsc->se->base+SE_DMA_IF_EN,DMA_IF_EN_DMA_IF_EN_BMSK);++/* Enable or disable FIFO interface of the serial engine. */+if(rsc->mode==GENI_SE_FIFO)+clrbits32(rsc->se->base+SE_FIFO_IF_DISABLE,FIFO_IF_DISABLE);+else+setbits32(rsc->se->base+SE_FIFO_IF_DISABLE,FIFO_IF_DISABLE);++err_resource:+geni_se_resources_off(rsc->se);+err:+geni_icc_disable(rsc->se);+returnret;+}++/**+*qup_fw_load:Functiontoinitiatefirmwareload+*@rsc:ApointertoastructurerepresentingSErelatedresources.+*+*Thisfunctioniscalledforloadingthefirmwareintoaparticular+*SE.ThisisachievedbyreadingtheassociatedELFfile,copying+*thedataintheELFfileintobufferinkernelspaceusing+*request_firmwareAPI's.ThedataisthenwrittenintheSE's+*IRAMregisterandthebuffersarefreedafter.Overall,this+*functionhandlesfirmwareloadingandparsingforaspecificprotocol.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+staticintqup_fw_load(structqup_se_rsc*rsc,constchar*fw_name)+{+intret;+conststructfirmware*fw;+structdevice*dev=rsc->se->dev;++ret=request_firmware(&fw,fw_name,dev);+if(ret){+dev_err(dev,"request_firmware failed for %d: %d\n",rsc->protocol,ret);+returnret;+}++ret=(rsc->protocol!=GENI_SE_NONE)?geni_load_se_fw(rsc,fw):-EINVAL;++release_firmware(fw);++returnret;+}++/**+*geni_load_se_firmware:Functiontoinitiatefirmwareloading.+*@se:Serialenginedetails.+*@protocol:protocolfromspi,i2coruartforwhichfirmwareto+*beloaded+*+*Thisfunctioniscalledfromtheprobefunctionofprotocoldriver.+*ifdtsipropertiesareconfiguredtoloadQUPfirmwareandfirmware+*isalreadynotloaded,itwillstartfirmwareloading.ifdtsi+*propertiesarenotdefined,itwillskiploadingfirmwareassuming+*itisalreadyloadedbyTZ.+*+*return:Return0ifnoerror,elsereturnerrorvalue.+*/+intgeni_load_se_firmware(structgeni_se*se,+enumgeni_se_protocol_typeprotocol)+{+structqup_se_rscrsc;+constchar*fw_name;+intret;++ret=device_property_read_string(se->wrapper->dev,"firmware-name",&fw_name);+if(ret)+return-EINVAL;++rsc.se=se;+rsc.protocol=protocol;++/* Set default xfer mode to FIFO*/+rsc.mode=GENI_SE_FIFO;
This needs to be moved after reading "qcom,xfer-mode", there you can override.
Also please mention UART doesn't support GPI_DMA mode hence can override with SE_FIFO.
quoted hunk
+ of_property_read_u32(se->dev->of_node, "qcom,xfer-mode", &rsc.mode);+ switch (rsc.mode) {+ case GENI_SE_FIFO:+ case GENI_SE_DMA:+ case GENI_GPI_DMA:+ break;+ default:+ dev_err(se->dev, "Invalid xfer mode specified: %d\n", rsc.mode);+ return -EINVAL;+ }++ ret = qup_fw_load(&rsc, fw_name);+ if (ret) {+ dev_err(se->dev, "Firmware Loading failed for proto: %s Error: %d\n",+ protocol_name[rsc.protocol], ret);+ return ret;+ }++ dev_dbg(se->dev, "Firmware load for %s protocol is Success for xfer mode %d\n",+ protocol_name[rsc.protocol], rsc.mode);+ return ret;+}+EXPORT_SYMBOL_GPL(geni_load_se_firmware);+ static int geni_se_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev;
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
--
With best wishes
Dmitry
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-01-27 16:24:30
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Anyway, if you need property per node, this has to be shared schema.
Best regards,
Krzysztof
From: Konrad Dybcio <hidden> Date: 2025-01-27 17:50:41
On 27.01.2025 5:24 PM, Krzysztof Kozlowski wrote:
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Anyway, if you need property per node, this has to be shared schema.
I'd rather ask a different question.. Is there *any* reason to not use
DMA for protocols that support it?
Konrad
From: Konrad Dybcio <hidden> Date: 2025-01-28 11:41:00
On 27.01.2025 6:50 PM, Konrad Dybcio wrote:
On 27.01.2025 5:24 PM, Krzysztof Kozlowski wrote:
quoted
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Anyway, if you need property per node, this has to be shared schema.
I'd rather ask a different question.. Is there *any* reason to not use
DMA for protocols that support it?
If not, we can simplify this to:
xfer_mode = protocol == PROTOCOL_UART ? XFER_FIFO : XFER_DMA
Konrad
On Mon, Jan 27, 2025 at 05:24:21PM +0100, Krzysztof Kozlowski wrote:
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Well, I don't have access to the latest sm8550 / sm8650 devcfg sources.
I checked the RB5 ones. As far as I understand out of 14 enabled SEs
only two are configured for the GSI DMA, others should use FIFO / SE
DMA. Same applies to the SM8250 MTP devices. Checking the RB1 / RB2
setup also shows 3 out of 6 SEs being set for GSI.
Anyway, if you need property per node, this has to be shared schema.
Best regards,
Krzysztof
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-01-29 07:23:21
On 29/01/2025 03:21, Dmitry Baryshkov wrote:
On Mon, Jan 27, 2025 at 05:24:21PM +0100, Krzysztof Kozlowski wrote:
quoted
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Well, I don't have access to the latest sm8550 / sm8650 devcfg sources.
I checked the RB5 ones. As far as I understand out of 14 enabled SEs
only two are configured for the GSI DMA, others should use FIFO / SE
DMA. Same applies to the SM8250 MTP devices. Checking the RB1 / RB2
setup also shows 3 out of 6 SEs being set for GSI.
But they are the same serial engines. Again, we do not talk here about
QUP, but serial engines.
Best regards,
Krzysztof
On Mon, Jan 27, 2025 at 05:24:21PM +0100, Krzysztof Kozlowski wrote:
quoted
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Well, I don't have access to the latest sm8550 / sm8650 devcfg sources.
I checked the RB5 ones. As far as I understand out of 14 enabled SEs
only two are configured for the GSI DMA, others should use FIFO / SE
DMA. Same applies to the SM8250 MTP devices. Checking the RB1 / RB2
setup also shows 3 out of 6 SEs being set for GSI.
I think selecting GSI DMA is only for devices needs high speed streaming to the
device, like the touch screen, using GSI DMA for random small access is a non-sense.
But the thing is, in the TZ world the configuration was static so we had no choice
of using GSI DMA when configured, but now we have the choice so we could totally
reconfigure the SE with the transfer type (FIFO, SE DMA or GSI DMA) as runtime and
drop this attribute.
So instead of hardcoding this, add a way to dynamically select either of the 3
transfer types when firmware can be loaded from HLOS.
Neil
quoted
Anyway, if you need property per node, this has to be shared schema.
Best regards,
Krzysztof
On 1/29/2025 1:48 PM, neil.armstrong@linaro.org wrote:
On 29/01/2025 03:21, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 05:24:21PM +0100, Krzysztof Kozlowski wrote:
quoted
On 27/01/2025 15:27, Dmitry Baryshkov wrote:
quoted
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
reg:
maxItems: 1
+ qcom,xfer-mode:
+ description: Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.
+ The default mode is FIFO.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 3]
+
+
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Well, I don't have access to the latest sm8550 / sm8650 devcfg sources.
I checked the RB5 ones. As far as I understand out of 14 enabled SEs
only two are configured for the GSI DMA, others should use FIFO / SE
DMA. Same applies to the SM8250 MTP devices. Checking the RB1 / RB2
setup also shows 3 out of 6 SEs being set for GSI.
I think selecting GSI DMA is only for devices needs high speed streaming to the
device, like the touch screen, using GSI DMA for random small access is a non-sense.
But the thing is, in the TZ world the configuration was static so we had no choice
of using GSI DMA when configured, but now we have the choice so we could totally
reconfigure the SE with the transfer type (FIFO, SE DMA or GSI DMA) as runtime and
drop this attribute.
So instead of hardcoding this, add a way to dynamically select either of the 3
transfer types when firmware can be loaded from HLOS.
Neil
Yes, GSI DMA mode is required for specific use cases only.
Dynamically switching from GSI mode to non-GSI mode is neither possible nor useful. For each SE, the use case is fixed, and based on the use case, the developer can choose the mode via the device tree property.
quoted
quoted
Anyway, if you need property per node, this has to be shared schema.
Best regards,
Krzysztof
From: Krzysztof Kozlowski <krzk@kernel.org> Date: 2025-02-09 10:19:35
On 09/02/2025 11:11, Viken Dadhaniya wrote:
quoted
quoted
quoted
quoted
quoted
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Well, I don't have access to the latest sm8550 / sm8650 devcfg sources.
I checked the RB5 ones. As far as I understand out of 14 enabled SEs
only two are configured for the GSI DMA, others should use FIFO / SE
DMA. Same applies to the SM8250 MTP devices. Checking the RB1 / RB2
setup also shows 3 out of 6 SEs being set for GSI.
I think selecting GSI DMA is only for devices needs high speed streaming
to the
device, like the touch screen, using GSI DMA for random small access is
a non-sense.
But the thing is, in the TZ world the configuration was static so we had
no choice
of using GSI DMA when configured, but now we have the choice so we could
totally
reconfigure the SE with the transfer type (FIFO, SE DMA or GSI DMA) as
runtime and
drop this attribute.
So instead of hardcoding this, add a way to dynamically select either of
the 3
transfer types when firmware can be loaded from HLOS.
Neil
Yes, GSI DMA mode is required for specific use cases only.
Dynamically switching from GSI mode to non-GSI mode is neither possible
nor useful. For each SE, the use case is fixed, and based on the use
case, the developer can choose the mode via the device tree property.
No, it cannot. Do not describe downstream as something set in stone.
Best regards,
Krzysztof
On Mon, Jan 27, 2025 at 08:02:12AM +0100, Krzysztof Kozlowski wrote:
quoted
On 24/01/2025 11:53, Viken Dadhaniya wrote:
quoted
Data transfer mode is fixed by TrustZone (TZ), which currently restricts
developers from modifying the transfer mode from the APPS side.
Document the 'qcom,xfer-mode' properties to select the data transfer mode,
either GPI DMA (Generic Packet Interface) or non-GPI mode (PIO/CPU DMA).
UART controller can operate in one of two modes based on the
'qcom,xfer-mode' property, and the firmware is loaded accordingly.
Co-developed-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Mukesh Kumar Savaliya <redacted>
Signed-off-by: Viken Dadhaniya <redacted>
---
v1 -> v2:
- Drop 'qcom,load-firmware' property and add 'firmware-name' property in
qup common driver.
- Update commit log.
v1 Link: https://lore.kernel.org/linux-kernel/20241204150326.1470749-4-quic_vdadhani@quicinc.com/
---
---
.../devicetree/bindings/serial/qcom,serial-geni-qcom.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -56,6 +56,13 @@ properties:reg:maxItems:1+qcom,xfer-mode:+description:Set the value to 1 for non-GPI (FIFO/CPU DMA) mode and 3 for GPI DMA mode.+The default mode is FIFO.+$ref:/schemas/types.yaml#/definitions/uint32+enum:[1,3]++
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Anyway, if you need property per node, this has to be shared schema.
Yes, this property is required for each SE node.
Can we use qcom,geni-se.yaml as a common YAML for the shared schema? Please suggest.
Just one blank line, but anyway, this property should not be in three
places. Do you really expect that each of serial engines within one
GeniQUP will be configured differently by TZ?
Yes, each SE is configured separately and it's quite frequent when
different SEs have different DMA configuration.
Well, I checked at sm8550 and sm8650 and each pair of SE - which shares
resources - has the same DMAs, so I would not call it frequent. Care to
bring an example where same serial engines have different DMAs and
different TZ? We do not talk about single QUP.
Well, I don't have access to the latest sm8550 / sm8650 devcfg sources.
I checked the RB5 ones. As far as I understand out of 14 enabled SEs
only two are configured for the GSI DMA, others should use FIFO / SE
DMA. Same applies to the SM8250 MTP devices. Checking the RB1 / RB2
setup also shows 3 out of 6 SEs being set for GSI.
I think selecting GSI DMA is only for devices needs high speed streaming
to the
device, like the touch screen, using GSI DMA for random small access is
a non-sense.
But the thing is, in the TZ world the configuration was static so we had
no choice
of using GSI DMA when configured, but now we have the choice so we could
totally
reconfigure the SE with the transfer type (FIFO, SE DMA or GSI DMA) as
runtime and
drop this attribute.
So instead of hardcoding this, add a way to dynamically select either of
the 3
transfer types when firmware can be loaded from HLOS.
Neil
To exactly summarize:
GSI DMA and CPU DMA are mostly same performance unless we have
multiprocessor systems queuing the transfers
together.
GSI DMA to be used when multiprocessor systems (Application processor/TZ/modem/ADSP subsystems) has use cases together.
If only single subsystem or processor is using CPU DMA mode should be used.
Hardware guidance and configuration suggest that CPU DMA and FIFO can be switched but GSI DMA.
CPI DMA : Doesn't work with multiple subsystems.
FIFO : same as CPU DMA but < 64 bytes (FIFO_SIZE)
GSI_DMA: Work with multiple subsystems
Overall, there will be GSI and non-GSI modes. Dynamic switching is only required in PIO mode (FIFO and CPU DMA).
quoted
Yes, GSI DMA mode is required for specific use cases only.
Dynamically switching from GSI mode to non-GSI mode is neither possible
nor useful. For each SE, the use case is fixed, and based on the use
case, the developer can choose the mode via the device tree property.
No, it cannot. Do not describe downstream as something set in stone.
Sorry, I am not referring to downstream but rather to the general process of mode selection.
Please let us know if you need more clarity.
@@ -891,6 +896,445 @@ int geni_icc_disable(struct geni_se *se) } EXPORT_SYMBOL_GPL(geni_icc_disable);+/**+ * elf_phdr_valid: Function to validate elf header.+ * @phdr: A pointer to a elf header.+ *+ * This function validates elf header by comparing fields
Drop "This function" and use imperative. It's redundant and you keep
using it everywherre here
Updated in V3.
...
quoted
+static int qup_fw_load(struct qup_se_rsc *rsc, const char *fw_name)+{+ int ret;+ const struct firmware *fw;+ struct device *dev = rsc->se->dev;++ ret = request_firmware(&fw, fw_name, dev);+ if (ret) {+ dev_err(dev, "request_firmware failed for %d: %d\n", rsc->protocol, ret);+ return ret;+ }++ ret = (rsc->protocol != GENI_SE_NONE) ? geni_load_se_fw(rsc, fw) : -EINVAL;
Drop ternary operator. Not easy to read
Updated in V3.
quoted
++ release_firmware(fw);++ return ret;+}
quoted
++/**+ * geni_load_se_firmware: Function to initiate firmware loading.+ * @se: Serial engine details.+ * @protocol: protocol from spi, i2c or uart for which firmware to+ * be loaded+ *+ * This function is called from the probe function of protocol driver.+ * if dtsi properties are configured to load QUP firmware and firmware+ * is already not loaded, it will start firmware loading. if dtsi+ * properties are not defined,it will skip loading firmware assuming+ * it is already loaded by TZ.+ *+ * return: Return 0 if no error, else return error value.+ */+int geni_load_se_firmware(struct geni_se *se,+ enum geni_se_protocol_type protocol)+{+ struct qup_se_rsc rsc;+ const char *fw_name;+ int ret;++ ret = device_property_read_string(se->wrapper->dev, "firmware-name", &fw_name);+ if (ret)+ return -EINVAL;++ rsc.se = se;+ rsc.protocol = protocol;++ /* Set default xfer mode to FIFO*/+ rsc.mode = GENI_SE_FIFO;+ of_property_read_u32(se->dev->of_node, "qcom,xfer-mode", &rsc.mode);+ switch (rsc.mode) {+ case GENI_SE_FIFO:+ case GENI_SE_DMA:
How value of 2 is acceptable? Your bindings said it is not.
Corrected in V3.
quoted
+ case GENI_GPI_DMA:+ break;+ default:+ dev_err(se->dev, "Invalid xfer mode specified: %d\n", rsc.mode);+ return -EINVAL;+ }++ ret = qup_fw_load(&rsc, fw_name);+ if (ret) {+ dev_err(se->dev, "Firmware Loading failed for proto: %s Error: %d\n",+ protocol_name[rsc.protocol], ret);
Aren't you printing same error multiple times?
Removed in V3.
quoted
+ return ret;+ }++ dev_dbg(se->dev, "Firmware load for %s protocol is Success for xfer mode %d\n",+ protocol_name[rsc.protocol], rsc.mode);+ return ret;+}+EXPORT_SYMBOL_GPL(geni_load_se_firmware);+ static int geni_se_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev;