Devicetree
 help / color / mirror / Atom feed
* [PATCH 1/2] dt-bindings: iio: chemical: pms7003: convert bindings to yaml
From: Tomasz Duszynski @ 2019-07-10 19:21 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-kernel, devicetree, jic23, robh+dt, Tomasz Duszynski
In-Reply-To: <20190710192155.11489-1-tduszyns@gmail.com>

Convert existing device tree bindings to yaml.

Signed-off-by: Tomasz Duszynski <tduszyns@gmail.com>
---
 .../iio/chemical/plantower,pms7003.txt        | 26 ----------
 .../iio/chemical/plantower,pms7003.yaml       | 51 +++++++++++++++++++
 2 files changed, 51 insertions(+), 26 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt
 create mode 100644 Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml

diff --git a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt
deleted file mode 100644
index c52ea2126eaa..000000000000
--- a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-* Plantower PMS7003 particulate matter sensor
-
-Required properties:
-- compatible: must one of:
-   "plantower,pms1003"
-   "plantower,pms3003"
-   "plantower,pms5003"
-   "plantower,pms6003"
-   "plantower,pms7003"
-   "plantower,pmsa003"
-- vcc-supply: phandle to the regulator that provides power to the sensor
-
-Optional properties:
-- plantower,set-gpios: phandle to the GPIO connected to the SET line
-- reset-gpios: phandle to the GPIO connected to the RESET line
-
-Refer to serial/slave-device.txt for generic serial attached device bindings.
-
-Example:
-
-&uart0 {
-	air-pollution-sensor {
-		compatible = "plantower,pms7003";
-		vcc-supply = <&reg_vcc5v0>;
-	};
-};
diff --git a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
new file mode 100644
index 000000000000..a551d3101f93
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/chemical/plantower,pms7003.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Plantower PMS7003 air pollution sensor
+
+maintainers:
+  - Tomasz Duszynski <tduszyns@gmail.com>
+
+description: |
+  Air pollution sensor capable of measuring mass concentration of dust
+  particles.
+
+properties:
+  compatible:
+    enum:
+      - plantower,pms1003
+      - plantower,pms3003
+      - plantower,pms5003
+      - plantower,pms6003
+      - plantower,pms7003
+      - plantower,pmsa003
+
+  vcc-supply:
+    description: regulator that provides power to the sensor
+    maxItems: 1
+
+  plantower,set-gpios:
+    description: GPIO connected to the SET line
+    maxItems: 1
+
+  reset-gpios:
+    description: GPIO connected to the RESET line
+    maxItems: 1
+
+required:
+  - compatible
+  - vcc-supply
+
+examples:
+  - |
+    serial {
+      air-pollution-sensor {
+        compatible = "plantower,pms7003";
+        vcc-supply = <&reg_vcc5v0>;
+      };
+    };
+
+...
-- 
2.22.0

^ permalink raw reply related

* [PATCH 0/2] iio: chemical: pms7003: convert bindings to yaml
From: Tomasz Duszynski @ 2019-07-10 19:21 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-kernel, devicetree, jic23, robh+dt, Tomasz Duszynski

Convert plantower pms7003 air pollution sensor bindings to yaml and
while at it add myself as a driver maintainer.

Tomasz Duszynski (2):
  dt-bindings: iio: chemical: pms7003: convert bindings to yaml
  MAINTAINERS: add entry for plantower pms7003 driver

 .../iio/chemical/plantower,pms7003.txt        | 26 ----------
 .../iio/chemical/plantower,pms7003.yaml       | 51 +++++++++++++++++++
 MAINTAINERS                                   |  6 +++
 3 files changed, 57 insertions(+), 26 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt
 create mode 100644 Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml

--
2.22.0

^ permalink raw reply

* Re: [PATCH V13 12/12] PCI: tegra: Add Tegra194 PCIe support
From: Vidya Sagar @ 2019-07-10 17:26 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: mark.rutland, devicetree, mperttunen, mmaddireddy, linux-pci,
	catalin.marinas, will.deacon, linux-kernel, kthota, kishon,
	linux-tegra, robh+dt, thierry.reding, gustavo.pimentel,
	jingoohan1, bhelgaas, digetx, jonathanh, linux-arm-kernel,
	sagar.tv
In-Reply-To: <20190710170200.GC8781@e121166-lin.cambridge.arm.com>

On 7/10/2019 10:32 PM, Lorenzo Pieralisi wrote:
> On Wed, Jul 10, 2019 at 11:52:12AM +0530, Vidya Sagar wrote:
> 
> [...]
> 
>> +#if defined(CONFIG_PCIEASPM)
>> +static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
>> +{
>> +	u32 val;
>> +
>> +	val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
>> +	val &= ~PCI_L1SS_CAP_ASPM_L1_1;
>> +	dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
>> +}
>> +
>> +static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
>> +{
>> +	u32 val;
>> +
>> +	val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
>> +	val &= ~PCI_L1SS_CAP_ASPM_L1_2;
>> +	dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
>> +}
>> +
>> +static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
>> +{
>> +	u32 val;
>> +
>> +	val = dw_pcie_readl_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid]);
>> +	val &= ~(EVENT_COUNTER_EVENT_SEL_MASK << EVENT_COUNTER_EVENT_SEL_SHIFT);
>> +	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
>> +	val |= event << EVENT_COUNTER_EVENT_SEL_SHIFT;
>> +	val |= EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
>> +	dw_pcie_writel_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid], val);
>> +	val = dw_pcie_readl_dbi(&pcie->pci, event_cntr_data_offset[pcie->cid]);
>> +	return val;
>> +}
>> +
>> +static int aspm_state_cnt(struct seq_file *s, void *data)
>> +{
>> +	struct tegra_pcie_dw *pcie = (struct tegra_pcie_dw *)
>> +				     dev_get_drvdata(s->private);
>> +	u32 val;
>> +
>> +	seq_printf(s, "Tx L0s entry count : %u\n",
>> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_Tx_L0S));
>> +
>> +	seq_printf(s, "Rx L0s entry count : %u\n",
>> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_Rx_L0S));
>> +
>> +	seq_printf(s, "Link L1 entry count : %u\n",
>> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1));
>> +
>> +	seq_printf(s, "Link L1.1 entry count : %u\n",
>> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1_1));
>> +
>> +	seq_printf(s, "Link L1.2 entry count : %u\n",
>> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1_2));
>> +
>> +	/* Clear all counters */
>> +	dw_pcie_writel_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid],
>> +			   EVENT_COUNTER_ALL_CLEAR);
>> +
>> +	/* Re-enable counting */
>> +	val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
>> +	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
>> +	dw_pcie_writel_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid], val);
>> +
>> +	return 0;
>> +}
>> +#endif
>> +
>> +static int init_debugfs(struct tegra_pcie_dw *pcie)
>> +{
>> +#if defined(CONFIG_PCIEASPM)
>> +	struct dentry *d;
>> +
>> +	d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt",
>> +					pcie->debugfs, aspm_state_cnt);
>> +	if (IS_ERR_OR_NULL(d))
>> +		dev_err(pcie->dev,
>> +			"Failed to create debugfs file \"aspm_state_cnt\"\n");
>> +#endif
>> +	return 0;
>> +}
> 
> I prefer writing it:
> 
> #if defined(CONFIG_PCIEASPM)
> static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
> {
> ...
> }
> 
> static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
> {
> ...
> }
> 
> static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
> {
> ...
> }
> 
> static int aspm_state_cnt(struct seq_file *s, void *data)
> {
> ...
> }
> 
> static int init_debugfs(struct tegra_pcie_dw *pcie)
> {
> 	struct dentry *d;
> 
> 	d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt",
> 					pcie->debugfs, aspm_state_cnt);
> 	if (IS_ERR_OR_NULL(d))
> 		dev_err(pcie->dev,
> 			"Failed to create debugfs file \"aspm_state_cnt\"\n");
> 	return 0;
> }
> #else
> static inline int init_debugfs(struct tegra_pcie_dw *pcie) { return 0; }
> #endif
I'll address it in the next patch.

> 
>> +
>> +static void tegra_pcie_enable_system_interrupts(struct pcie_port *pp)
>> +{
>> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
>> +	u32 val;
>> +	u16 val_w;
>> +
>> +	val = appl_readl(pcie, APPL_INTR_EN_L0_0);
>> +	val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN;
>> +	appl_writel(pcie, val, APPL_INTR_EN_L0_0);
>> +
>> +	val = appl_readl(pcie, APPL_INTR_EN_L1_0_0);
>> +	val |= APPL_INTR_EN_L1_0_0_LINK_REQ_RST_NOT_INT_EN;
>> +	appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
>> +
>> +	if (pcie->enable_cdm_check) {
>> +		val = appl_readl(pcie, APPL_INTR_EN_L0_0);
>> +		val |= APPL_INTR_EN_L0_0_CDM_REG_CHK_INT_EN;
>> +		appl_writel(pcie, val, APPL_INTR_EN_L0_0);
>> +
>> +		val = appl_readl(pcie, APPL_INTR_EN_L1_18);
>> +		val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_CMP_ERR;
>> +		val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_LOGIC_ERR;
>> +		appl_writel(pcie, val, APPL_INTR_EN_L1_18);
>> +	}
>> +
>> +	val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
>> +				  PCI_EXP_LNKSTA);
>> +	pcie->init_link_width = (val_w & PCI_EXP_LNKSTA_NLW) >>
>> +				PCI_EXP_LNKSTA_NLW_SHIFT;
>> +
>> +	val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
>> +				  PCI_EXP_LNKCTL);
>> +	val_w |= PCI_EXP_LNKCTL_LBMIE;
>> +	dw_pcie_writew_dbi(&pcie->pci, pcie->pcie_cap_base + PCI_EXP_LNKCTL,
>> +			   val_w);
>> +}
>> +
>> +static void tegra_pcie_enable_legacy_interrupts(struct pcie_port *pp)
>> +{
>> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
>> +	u32 val;
>> +
>> +	/* Enable legacy interrupt generation */
>> +	val = appl_readl(pcie, APPL_INTR_EN_L0_0);
>> +	val |= APPL_INTR_EN_L0_0_SYS_INTR_EN;
>> +	val |= APPL_INTR_EN_L0_0_INT_INT_EN;
>> +	appl_writel(pcie, val, APPL_INTR_EN_L0_0);
>> +
>> +	val = appl_readl(pcie, APPL_INTR_EN_L1_8_0);
>> +	val |= APPL_INTR_EN_L1_8_INTX_EN;
>> +	val |= APPL_INTR_EN_L1_8_AUTO_BW_INT_EN;
>> +	val |= APPL_INTR_EN_L1_8_BW_MGT_INT_EN;
>> +	if (IS_ENABLED(CONFIG_PCIEAER))
>> +		val |= APPL_INTR_EN_L1_8_AER_INT_EN;
>> +	appl_writel(pcie, val, APPL_INTR_EN_L1_8_0);
>> +}
>> +
>> +static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
>> +{
>> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
>> +	u32 val;
>> +
>> +	dw_pcie_msi_init(pp);
>> +
>> +	/* Enable MSI interrupt generation */
>> +	val = appl_readl(pcie, APPL_INTR_EN_L0_0);
>> +	val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
>> +	val |= APPL_INTR_EN_L0_0_MSI_RCV_INT_EN;
>> +	appl_writel(pcie, val, APPL_INTR_EN_L0_0);
>> +}
>> +
>> +static void tegra_pcie_enable_interrupts(struct pcie_port *pp)
>> +{
>> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
>> +
>> +	/* Clear interrupt statuses before enabling interrupts */
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15);
>> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17);
>> +
>> +	tegra_pcie_enable_system_interrupts(pp);
>> +	tegra_pcie_enable_legacy_interrupts(pp);
>> +	if (IS_ENABLED(CONFIG_PCI_MSI))
>> +		tegra_pcie_enable_msi_interrupts(pp);
>> +}
>> +
>> +static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
>> +{
>> +	struct dw_pcie *pci = &pcie->pci;
>> +	u32 val, offset, i;
>> +
>> +	/* Program init preset */
>> +	for (i = 0; i < pcie->num_lanes; i++) {
>> +		dw_pcie_read(pci->dbi_base + CAP_SPCIE_CAP_OFF
>> +				 + (i * 2), 2, &val);
>> +		val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK;
>> +		val |= GEN3_GEN4_EQ_PRESET_INIT;
>> +		val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK;
>> +		val |= (GEN3_GEN4_EQ_PRESET_INIT <<
>> +			   CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT);
>> +		dw_pcie_write(pci->dbi_base + CAP_SPCIE_CAP_OFF
>> +				 + (i * 2), 2, val);
>> +
>> +		offset = dw_pcie_find_ext_capability(pci,
>> +						     PCI_EXT_CAP_ID_PL_16GT) +
>> +				PCI_PL_16GT_LE_CTRL;
>> +		dw_pcie_read(pci->dbi_base + offset + i, 1, &val);
>> +		val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK;
>> +		val |= GEN3_GEN4_EQ_PRESET_INIT;
>> +		val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK;
>> +		val |= (GEN3_GEN4_EQ_PRESET_INIT <<
>> +			PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT);
>> +		dw_pcie_write(pci->dbi_base + offset + i, 1, val);
>> +	}
>> +
>> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
>> +	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
>> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
>> +
>> +	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
>> +	val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK;
>> +	val |= (0x3ff << GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT);
>> +	val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE_MASK;
>> +	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
>> +
>> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
>> +	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
>> +	val |= (0x1 << GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT);
>> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
>> +
>> +	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
>> +	val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK;
>> +	val |= (0x360 << GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT);
>> +	val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE_MASK;
>> +	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
>> +
>> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
>> +	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
>> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
>> +}
>> +
>> +static int tegra_pcie_dw_host_init(struct pcie_port *pp)
>> +{
>> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
>> +	u32 val, tmp, offset, speed;
>> +	unsigned int count;
>> +	u16 val_w;
>> +
>> +core_init:
> 
> Why should we restart from here ? What's the effect of the reset
> on following registers set-up ?
before jumping to 'core_init' label, PCIe IP core is put through reset cycle and
registers in the core get their default values and hence need to be programmed again.

> 
>> +	count = 200;
>> +#if defined(CONFIG_PCIEASPM)
>> +	offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
>> +	pcie->cfg_link_cap_l1sub = offset + PCI_L1SS_CAP;
>> +#endif
> 
> Can we group it in the #ifdef above ?
I'll address it in the next patch.

> 
>> +	val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
>> +	val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
>> +	dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
>> +
>> +	val = dw_pcie_readl_dbi(pci, PCI_PREF_MEMORY_BASE);
>> +	val |= CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE;
>> +	val |= CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE;
>> +	dw_pcie_writel_dbi(pci, PCI_PREF_MEMORY_BASE, val);
>> +
>> +	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
>> +
>> +	/* Configure FTS */
>> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
>> +	val &= ~(N_FTS_MASK << N_FTS_SHIFT);
>> +	val |= N_FTS_VAL << N_FTS_SHIFT;
>> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
>> +
>> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
>> +	val &= ~FTS_MASK;
>> +	val |= FTS_VAL;
>> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
>> +
>> +	/* Enable as 0xFFFF0001 response for CRS */
>> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
>> +	val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT);
>> +	val |= (AMBA_ERROR_RESPONSE_CRS_OKAY_FFFF0001 <<
>> +		AMBA_ERROR_RESPONSE_CRS_SHIFT);
>> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
>> +
>> +	/* Configure Max Speed from DT */
>> +	if (pcie->max_speed && pcie->max_speed != -EINVAL) {
>> +		val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
>> +					PCI_EXP_LNKCAP);
>> +		val &= ~PCI_EXP_LNKCAP_SLS;
>> +		val |= pcie->max_speed;
>> +		dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
>> +				   val);
>> +	}
>> +
>> +	/* Configure Max lane width from DT */
>> +	val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
>> +	val &= ~PCI_EXP_LNKCAP_MLW;
>> +	val |= (pcie->num_lanes << PCI_EXP_LNKSTA_NLW_SHIFT);
>> +	dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, val);
>> +
>> +	config_gen3_gen4_eq_presets(pcie);
>> +
>> +#if defined(CONFIG_PCIEASPM)
>> +	/* Enable ASPM counters */
>> +	val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
>> +	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
>> +	dw_pcie_writel_dbi(pci, event_cntr_ctrl_offset[pcie->cid], val);
>> +
>> +	/* Program T_cmrt and T_pwr_on values */
>> +	val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
>> +	val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
>> +	val |= (pcie->aspm_cmrt << 8);
>> +	val |= (pcie->aspm_pwr_on_t << 19);
>> +	dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
>> +
>> +	/* Program L0s and L1 entrance latencies */
>> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
>> +	val &= ~L0S_ENTRANCE_LAT_MASK;
>> +	val |= (pcie->aspm_l0s_enter_lat << L0S_ENTRANCE_LAT_SHIFT);
>> +	val |= ENTER_ASPM;
>> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
>> +#endif
> 
> It would be good to group all init guarded in CONFIG_PCIEASPM in
> one function and related ifdef guard.
> 
>> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
>> +	val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
>> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
>> +
>> +	if (pcie->update_fc_fixup) {
>> +		val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
>> +		val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
>> +		dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
>> +	}
>> +
>> +	dw_pcie_setup_rc(pp);
>> +
>> +	clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
>> +
>> +	/* Assert RST */
>> +	val = appl_readl(pcie, APPL_PINMUX);
>> +	val &= ~APPL_PINMUX_PEX_RST;
>> +	appl_writel(pcie, val, APPL_PINMUX);
> 
> What's the effect of this RST on the registers programmed above ?
This register is software interface to toggle PERST sideband signal going to
downstream devices. Nothing happens to the registers programmed above because
of applying fundamental reset to downstream devices.

> 
>> +	usleep_range(100, 200);
>> +
>> +	/* Enable LTSSM */
>> +	val = appl_readl(pcie, APPL_CTRL);
>> +	val |= APPL_CTRL_LTSSM_EN;
>> +	appl_writel(pcie, val, APPL_CTRL);
>> +
>> +	/* De-assert RST */
>> +	val = appl_readl(pcie, APPL_PINMUX);
>> +	val |= APPL_PINMUX_PEX_RST;
>> +	appl_writel(pcie, val, APPL_PINMUX);
>> +
>> +	msleep(100);
>> +
>> +	val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
>> +	while (!(val_w & PCI_EXP_LNKSTA_DLLLA)) {
>> +		if (count) {
>> +			dev_dbg(pci->dev, "Waiting for link up\n");
>> +			usleep_range(1000, 2000);
>> +			val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
>> +						  PCI_EXP_LNKSTA);
>> +			count--;
>> +			continue;
>> +		}
>> +
>> +		val = appl_readl(pcie, APPL_DEBUG);
>> +		val &= APPL_DEBUG_LTSSM_STATE_MASK;
>> +		val >>= APPL_DEBUG_LTSSM_STATE_SHIFT;
>> +		tmp = appl_readl(pcie, APPL_LINK_STATUS);
>> +		tmp &= APPL_LINK_STATUS_RDLH_LINK_UP;
>> +		if (!(val == 0x11 && !tmp)) {
>> +			dev_info(pci->dev, "Link is down\n");
>> +			return 0;
>> +		}
>> +
>> +		dev_info(pci->dev, "Link is down in DLL");
>> +		dev_info(pci->dev, "Trying again with DLFE disabled\n");
>> +		/* Disable LTSSM */
>> +		val = appl_readl(pcie, APPL_CTRL);
>> +		val &= ~APPL_CTRL_LTSSM_EN;
>> +		appl_writel(pcie, val, APPL_CTRL);
>> +
>> +		reset_control_assert(pcie->core_rst);
>> +		reset_control_deassert(pcie->core_rst);
>> +
>> +		offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_DLF);
>> +		val = dw_pcie_readl_dbi(pci, offset + PCI_DLF_CAP);
>> +		val &= ~PCI_DLF_EXCHANGE_ENABLE;
>> +		dw_pcie_writel_dbi(pci, offset, val);
>> +
>> +		/* Retry now with DLF Exchange disabled */
>> +		goto core_init;
> 
> See above.
> 
>> +	}
>> +	dev_dbg(pci->dev, "Link is up\n");
>> +
>> +	speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
>> +		PCI_EXP_LNKSTA_CLS;
>> +	clk_set_rate(pcie->core_clk, pcie_gen_freq[speed - 1]);
>> +
>> +	tegra_pcie_enable_interrupts(pp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
>> +{
>> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
>> +	u32 val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
>> +
>> +	return !!(val & PCI_EXP_LNKSTA_DLLLA);
>> +}
>> +
>> +static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
>> +{
>> +	pp->num_vectors = MAX_MSI_IRQS;
>> +}
>> +
>> +static const struct dw_pcie_ops tegra_dw_pcie_ops = {
>> +	.link_up = tegra_pcie_dw_link_up,
>> +};
>> +
>> +static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
>> +	.rd_own_conf = tegra_pcie_dw_rd_own_conf,
>> +	.wr_own_conf = tegra_pcie_dw_wr_own_conf,
>> +	.host_init = tegra_pcie_dw_host_init,
>> +	.set_num_vectors = tegra_pcie_set_msi_vec_num,
>> +};
>> +
>> +static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
>> +{
>> +	unsigned int phy_count = pcie->phy_count;
>> +
>> +	while (phy_count--) {
>> +		phy_power_off(pcie->phys[phy_count]);
>> +		phy_exit(pcie->phys[phy_count]);
>> +	}
>> +}
>> +
>> +static int tegra_pcie_enable_phy(struct tegra_pcie_dw *pcie)
>> +{
>> +	unsigned int i;
>> +	int ret;
>> +
>> +	for (i = 0; i < pcie->phy_count; i++) {
>> +		ret = phy_init(pcie->phys[i]);
>> +		if (ret < 0)
>> +			goto phy_power_off;
>> +
>> +		ret = phy_power_on(pcie->phys[i]);
>> +		if (ret < 0)
>> +			goto phy_exit;
>> +	}
>> +
>> +	return 0;
>> +
>> +phy_power_off:
>> +	while (i--) {
>> +		phy_power_off(pcie->phys[i]);
>> +phy_exit:
>> +		phy_exit(pcie->phys[i]);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
>> +{
>> +	struct device_node *np = pcie->dev->of_node;
>> +	int ret;
>> +
>> +	ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt);
>> +	if (ret < 0) {
>> +		dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = of_property_read_u32(np, "nvidia,aspm-pwr-on-t-us",
>> +				   &pcie->aspm_pwr_on_t);
>> +	if (ret < 0)
>> +		dev_info(pcie->dev, "Failed to read ASPM Power On time: %d\n",
>> +			 ret);
>> +
>> +	ret = of_property_read_u32(np, "nvidia,aspm-l0s-entrance-latency-us",
>> +				   &pcie->aspm_l0s_enter_lat);
>> +	if (ret < 0)
>> +		dev_info(pcie->dev,
>> +			 "Failed to read ASPM L0s Entrance latency: %d\n", ret);
>> +
>> +	ret = of_property_read_u32(np, "num-lanes", &pcie->num_lanes);
>> +	if (ret < 0) {
>> +		dev_err(pcie->dev, "Failed to read num-lanes: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	pcie->max_speed = of_pci_get_max_link_speed(np);
>> +
>> +	ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	pcie->phy_count = of_property_count_strings(np, "phy-names");
>> +	if (pcie->phy_count < 0) {
>> +		dev_err(pcie->dev, "Failed to find PHY entries: %d\n",
>> +			pcie->phy_count);
>> +		return pcie->phy_count;
>> +	}
>> +
>> +	if (of_property_read_bool(np, "nvidia,update-fc-fixup"))
>> +		pcie->update_fc_fixup = true;
>> +
>> +	pcie->supports_clkreq =
>> +		of_property_read_bool(pcie->dev->of_node, "supports-clkreq");
>> +
>> +	pcie->enable_cdm_check =
>> +		of_property_read_bool(np, "snps,enable-cdm-check");
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
>> +					  bool enable)
>> +{
>> +	struct mrq_uphy_response resp;
>> +	struct tegra_bpmp_message msg;
>> +	struct mrq_uphy_request req;
>> +	int err;
>> +
>> +	if (pcie->cid == 5)
>> +		return 0;
>> +
>> +	memset(&req, 0, sizeof(req));
>> +	memset(&resp, 0, sizeof(resp));
>> +
>> +	req.cmd = CMD_UPHY_PCIE_CONTROLLER_STATE;
>> +	req.controller_state.pcie_controller = pcie->cid;
>> +	req.controller_state.enable = enable;
>> +
>> +	memset(&msg, 0, sizeof(msg));
>> +	msg.mrq = MRQ_UPHY;
>> +	msg.tx.data = &req;
>> +	msg.tx.size = sizeof(req);
>> +	msg.rx.data = &resp;
>> +	msg.rx.size = sizeof(resp);
>> +
>> +	if (irqs_disabled())
>> +		err = tegra_bpmp_transfer_atomic(pcie->bpmp, &msg);
>> +	else
>> +		err = tegra_bpmp_transfer(pcie->bpmp, &msg);
>> +
>> +	return err;
>> +}
>> +
>> +static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
>> +{
>> +	struct pcie_port *pp = &pcie->pci.pp;
>> +	struct pci_dev *pdev;
>> +	struct pci_bus *child;
>> +
>> +	list_for_each_entry(child, &pp->root_bus->children, node) {
>> +		/* Bring downstream devices to D0 if they are not already in */
>> +		if (child->parent == pp->root_bus)
>> +			break;
>> +	}
>> +	list_for_each_entry(pdev, &child->devices, bus_list) {
>> +		if (PCI_SLOT(pdev->devfn) == 0) {
>> +			if (pci_set_power_state(pdev, PCI_D0))
>> +				dev_err(pcie->dev,
>> +					"Failed to transition %s to D0 state\n",
>> +					dev_name(&pdev->dev));
>> +		}
>> +	}
>> +}
>> +
>> +static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
>> +					bool en_hw_hot_rst)
>> +{
>> +	int ret;
>> +	u32 val;
>> +
>> +	ret = tegra_pcie_bpmp_set_ctrl_state(pcie, true);
>> +	if (ret) {
>> +		dev_err(pcie->dev,
>> +			"Failed to enable controller %u: %d\n", pcie->cid, ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_enable(pcie->pex_ctl_supply);
>> +	if (ret < 0) {
>> +		dev_err(pcie->dev, "Failed to enable regulator: %d\n", ret);
>> +		goto fail_reg_en;
>> +	}
>> +
>> +	ret = clk_prepare_enable(pcie->core_clk);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to enable core clock: %d\n", ret);
>> +		goto fail_core_clk;
>> +	}
>> +
>> +	ret = reset_control_deassert(pcie->core_apb_rst);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to deassert core APB reset: %d\n",
>> +			ret);
>> +		goto fail_core_apb_rst;
>> +	}
>> +
>> +	if (en_hw_hot_rst) {
>> +		/* Enable HW_HOT_RST mode */
>> +		val = appl_readl(pcie, APPL_CTRL);
>> +		val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK <<
>> +			 APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
>> +		val |= APPL_CTRL_HW_HOT_RST_EN;
>> +		appl_writel(pcie, val, APPL_CTRL);
>> +	}
>> +
>> +	ret = tegra_pcie_enable_phy(pcie);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to enable PHY: %d\n", ret);
>> +		goto fail_phy;
>> +	}
>> +
>> +	/* Update CFG base address */
>> +	appl_writel(pcie, pcie->dbi_res->start & APPL_CFG_BASE_ADDR_MASK,
>> +		    APPL_CFG_BASE_ADDR);
>> +
>> +	/* Configure this core for RP mode operation */
>> +	appl_writel(pcie, APPL_DM_TYPE_RP, APPL_DM_TYPE);
>> +
>> +	appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE);
>> +
>> +	val = appl_readl(pcie, APPL_CTRL);
>> +	appl_writel(pcie, val | APPL_CTRL_SYS_PRE_DET_STATE, APPL_CTRL);
>> +
>> +	val = appl_readl(pcie, APPL_CFG_MISC);
>> +	val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT);
>> +	appl_writel(pcie, val, APPL_CFG_MISC);
>> +
>> +	if (!pcie->supports_clkreq) {
>> +		val = appl_readl(pcie, APPL_PINMUX);
>> +		val |= APPL_PINMUX_CLKREQ_OUT_OVRD_EN;
>> +		val |= APPL_PINMUX_CLKREQ_OUT_OVRD;
>> +		appl_writel(pcie, val, APPL_PINMUX);
>> +	}
>> +
>> +	/* Update iATU_DMA base address */
>> +	appl_writel(pcie,
>> +		    pcie->atu_dma_res->start & APPL_CFG_IATU_DMA_BASE_ADDR_MASK,
>> +		    APPL_CFG_IATU_DMA_BASE_ADDR);
>> +
>> +	reset_control_deassert(pcie->core_rst);
>> +
>> +	pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
>> +						      PCI_CAP_ID_EXP);
>> +
>> +#if defined(CONFIG_PCIEASPM)
>> +	/* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
>> +	if (!pcie->supports_clkreq) {
>> +		disable_aspm_l11(pcie);
>> +		disable_aspm_l12(pcie);
>> +	}
>> +#endif
>> +	return ret;
>> +
>> +fail_phy:
>> +	reset_control_assert(pcie->core_apb_rst);
>> +fail_core_apb_rst:
>> +	clk_disable_unprepare(pcie->core_clk);
>> +fail_core_clk:
>> +	regulator_disable(pcie->pex_ctl_supply);
>> +fail_reg_en:
>> +	tegra_pcie_bpmp_set_ctrl_state(pcie, false);
>> +
>> +	return ret;
>> +}
>> +
>> +static int __deinit_controller(struct tegra_pcie_dw *pcie)
>> +{
>> +	int ret;
>> +
>> +	ret = reset_control_assert(pcie->core_rst);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
>> +			ret);
>> +		return ret;
>> +	}
>> +	tegra_pcie_disable_phy(pcie);
>> +	ret = reset_control_assert(pcie->core_apb_rst);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
>> +		return ret;
>> +	}
>> +	clk_disable_unprepare(pcie->core_clk);
>> +	ret = regulator_disable(pcie->pex_ctl_supply);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
>> +		return ret;
>> +	}
>> +	ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
>> +	if (ret) {
>> +		dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
>> +			pcie->cid, ret);
>> +		return ret;
>> +	}
>> +	return ret;
>> +}
>> +
>> +static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
>> +{
>> +	struct dw_pcie *pci = &pcie->pci;
>> +	struct pcie_port *pp = &pci->pp;
>> +	int ret;
>> +
>> +	ret = tegra_pcie_config_controller(pcie, false);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	pp->root_bus_nr = -1;
> 
> Useless, drop it, it is initialized in dw_pcie_host_init().
Ok.

> 
>> +	pp->ops = &tegra_pcie_dw_host_ops;
>> +
>> +	ret = dw_pcie_host_init(pp);
>> +	if (ret < 0) {
>> +		dev_err(pcie->dev, "Failed to add PCIe port: %d\n", ret);
>> +		goto fail_host_init;
>> +	}
>> +
>> +	return 0;
>> +
>> +fail_host_init:
>> +	return __deinit_controller(pcie);
>> +}
>> +
>> +static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
>> +{
>> +	u32 val;
>> +
>> +	if (!tegra_pcie_dw_link_up(&pcie->pci))
>> +		return 0;
>> +
>> +	val = appl_readl(pcie, APPL_RADM_STATUS);
>> +	val |= APPL_PM_XMT_TURNOFF_STATE;
>> +	appl_writel(pcie, val, APPL_RADM_STATUS);
>> +
>> +	return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val,
>> +				 val & APPL_DEBUG_PM_LINKST_IN_L2_LAT,
>> +				 1, PME_ACK_TIMEOUT);
>> +}
>> +
>> +static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
>> +{
>> +	u32 data;
>> +	int err;
>> +
>> +	if (!tegra_pcie_dw_link_up(&pcie->pci)) {
>> +		dev_dbg(pcie->dev, "PCIe link is not up...!\n");
>> +		return;
>> +	}
>> +
>> +	if (tegra_pcie_try_link_l2(pcie)) {
>> +		dev_info(pcie->dev, "Link didn't transition to L2 state\n");
>> +		/*
>> +		 * TX lane clock freq will reset to Gen1 only if link is in L2
>> +		 * or detect state.
>> +		 * So apply pex_rst to end point to force RP to go into detect
>> +		 * state
>> +		 */
>> +		data = appl_readl(pcie, APPL_PINMUX);
>> +		data &= ~APPL_PINMUX_PEX_RST;
>> +		appl_writel(pcie, data, APPL_PINMUX);
>> +
>> +		err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
>> +						data,
>> +						((data &
>> +						APPL_DEBUG_LTSSM_STATE_MASK) >>
>> +						APPL_DEBUG_LTSSM_STATE_SHIFT) ==
>> +						LTSSM_STATE_PRE_DETECT,
>> +						1, LTSSM_TIMEOUT);
>> +		if (err) {
>> +			dev_info(pcie->dev, "Link didn't go to detect state\n");
>> +		} else {
>> +			/* Disable LTSSM after link is in detect state */
>> +			data = appl_readl(pcie, APPL_CTRL);
>> +			data &= ~APPL_CTRL_LTSSM_EN;
>> +			appl_writel(pcie, data, APPL_CTRL);
>> +		}
>> +	}
>> +	/*
>> +	 * DBI registers may not be accessible after this as PLL-E would be
>> +	 * down depending on how CLKREQ is pulled by end point
>> +	 */
>> +	data = appl_readl(pcie, APPL_PINMUX);
>> +	data |= (APPL_PINMUX_CLKREQ_OVERRIDE_EN | APPL_PINMUX_CLKREQ_OVERRIDE);
>> +	/* Cut REFCLK to slot */
>> +	data |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN;
>> +	data &= ~APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE;
>> +	appl_writel(pcie, data, APPL_PINMUX);
>> +}
>> +
>> +static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
>> +{
>> +	/*
>> +	 * link doesn't go into L2 state with some of the endpoints with Tegra
>> +	 * if they are not in D0 state. So, need to make sure that immediate
>> +	 * downstream devices are in D0 state before sending PME_TurnOff to put
>> +	 * link into L2 state
>> +	 */
>> +	tegra_pcie_downstream_dev_to_D0(pcie);
>> +	dw_pcie_host_deinit(&pcie->pci.pp);
>> +	tegra_pcie_dw_pme_turnoff(pcie);
>> +	return __deinit_controller(pcie);
>> +}
>> +
>> +static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
>> +{
>> +	struct pcie_port *pp = &pcie->pci.pp;
>> +	struct device *dev = pcie->dev;
>> +	char *name;
>> +	int ret;
>> +
>> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> +		pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
>> +		if (!pp->msi_irq) {
>> +			dev_err(dev, "Failed to get MSI interrupt\n");
>> +			return -ENODEV;
>> +		}
>> +	}
>> +
>> +	pm_runtime_enable(dev);
>> +	ret = pm_runtime_get_sync(dev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to get runtime sync for PCIe dev: %d\n",
>> +			ret);
>> +		pm_runtime_disable(dev);
>> +		return ret;
>> +	}
>> +
>> +	tegra_pcie_init_controller(pcie);
>> +
>> +	pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
>> +
>> +	if (!pcie->link_state) {
>> +		ret = -ENOMEDIUM;
>> +		goto fail_host_init;
>> +	}
>> +
>> +	name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node);
>> +	if (!name) {
>> +		ret = -ENOMEM;
>> +		goto fail_host_init;
>> +	}
>> +
>> +	pcie->debugfs = debugfs_create_dir(name, NULL);
>> +	if (!pcie->debugfs)
>> +		dev_err(dev, "Failed to create debugfs\n");
>> +	else
>> +		init_debugfs(pcie);
>> +
>> +	return ret;
>> +
>> +fail_host_init:
>> +	tegra_pcie_deinit_controller(pcie);
>> +	pm_runtime_put_sync(dev);
>> +	pm_runtime_disable(dev);
>> +	return ret;
>> +}
>> +
>> +static const struct tegra_pcie_soc tegra_pcie_rc_of_data = {
>> +	.mode = DW_PCIE_RC_TYPE,
>> +};
>> +
>> +static const struct of_device_id tegra_pcie_dw_of_match[] = {
>> +	{
>> +		.compatible = "nvidia,tegra194-pcie",
>> +		.data = &tegra_pcie_rc_of_data,
>> +	},
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match);
> 
> Move it closer to end of file where MODULE_DESCRIPTION() et al are.
Ok.

> 
>> +
>> +static int tegra_pcie_dw_probe(struct platform_device *pdev)
>> +{
>> +	const struct tegra_pcie_soc *data;
>> +	struct device *dev = &pdev->dev;
>> +	struct resource *atu_dma_res;
>> +	struct tegra_pcie_dw *pcie;
>> +	struct resource *dbi_res;
>> +	struct pcie_port *pp;
>> +	struct dw_pcie *pci;
>> +	struct phy **phys;
>> +	char *name;
>> +	int ret;
>> +	u32 i;
>> +
>> +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
>> +	if (!pcie)
>> +		return -ENOMEM;
>> +
>> +	pci = &pcie->pci;
>> +	pci->dev = &pdev->dev;
>> +	pci->ops = &tegra_dw_pcie_ops;
>> +	pp = &pci->pp;
>> +	pcie->dev = &pdev->dev;
>> +
>> +	data = (struct tegra_pcie_soc *)of_device_get_match_data(dev);
>> +	if (!data)
>> +		return -EINVAL;
>> +	pcie->mode = (enum dw_pcie_device_mode)data->mode;
>> +
>> +	ret = tegra_pcie_dw_parse_dt(pcie);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to parse device tree: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl");
>> +	if (IS_ERR(pcie->pex_ctl_supply)) {
>> +		dev_err(dev, "Failed to get regulator: %ld\n",
>> +			PTR_ERR(pcie->pex_ctl_supply));
>> +		return PTR_ERR(pcie->pex_ctl_supply);
>> +	}
>> +
>> +	pcie->core_clk = devm_clk_get(dev, "core");
>> +	if (IS_ERR(pcie->core_clk)) {
>> +		dev_err(dev, "Failed to get core clock: %ld\n",
>> +			PTR_ERR(pcie->core_clk));
>> +		return PTR_ERR(pcie->core_clk);
>> +	}
>> +
>> +	pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>> +						      "appl");
>> +	if (!pcie->appl_res) {
>> +		dev_err(dev, "Failed to find \"appl\" region\n");
>> +		return PTR_ERR(pcie->appl_res);
>> +	}
> 
> Add an empty line.
Ok.

> 
>> +	pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res);
>> +	if (IS_ERR(pcie->appl_base))
>> +		return PTR_ERR(pcie->appl_base);
>> +
>> +	pcie->core_apb_rst = devm_reset_control_get(dev, "apb");
>> +	if (IS_ERR(pcie->core_apb_rst)) {
>> +		dev_err(dev, "Failed to get APB reset: %ld\n",
>> +			PTR_ERR(pcie->core_apb_rst));
>> +		return PTR_ERR(pcie->core_apb_rst);
>> +	}
>> +
>> +	phys = devm_kcalloc(dev, pcie->phy_count, sizeof(*phys), GFP_KERNEL);
>> +	if (!phys)
>> +		return PTR_ERR(phys);
>> +
>> +	for (i = 0; i < pcie->phy_count; i++) {
>> +		name = kasprintf(GFP_KERNEL, "p2u-%u", i);
>> +		if (!name) {
>> +			dev_err(dev, "Failed to create P2U string\n");
>> +			return -ENOMEM;
>> +		}
>> +		phys[i] = devm_phy_get(dev, name);
>> +		kfree(name);
>> +		if (IS_ERR(phys[i])) {
>> +			ret = PTR_ERR(phys[i]);
>> +			dev_err(dev, "Failed to get PHY: %d\n", ret);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	pcie->phys = phys;
>> +
>> +	dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
>> +	if (!dbi_res) {
>> +		dev_err(dev, "Failed to find \"dbi\" region\n");
>> +		return PTR_ERR(dbi_res);
>> +	}
>> +	pcie->dbi_res = dbi_res;
>> +
>> +	pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
>> +	if (IS_ERR(pci->dbi_base))
>> +		return PTR_ERR(pci->dbi_base);
>> +
>> +	/* Tegra HW locates DBI2 at a fixed offset from DBI */
>> +	pci->dbi_base2 = pci->dbi_base + 0x1000;
>> +
>> +	atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>> +						   "atu_dma");
>> +	if (!atu_dma_res) {
>> +		dev_err(dev, "Failed to find \"atu_dma\" region\n");
>> +		return PTR_ERR(atu_dma_res);
>> +	}
>> +	pcie->atu_dma_res = atu_dma_res;
> 
> Add an empty line.
> 
> I have just skimmed over it, I need more time to review the driver more
> thoroughly, I will try to go over it tomorrow and we can see if we can
> hit v5.3 but I can't guarantee anything, sorry but there was a
> significant backlog on the PCI patch queue.
> 
> The rest of the series is fine but it is useless to merge it
> without this patch so let's see how it goes.
Ok. I'll wait for your thorough review and then push next patch.
Thanks for the review.

> 
> Lorenzo
> 
>> +	pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
>> +	if (IS_ERR(pci->atu_base))
>> +		return PTR_ERR(pci->atu_base);
>> +
>> +	pcie->core_rst = devm_reset_control_get(dev, "core");
>> +	if (IS_ERR(pcie->core_rst)) {
>> +		dev_err(dev, "Failed to get core reset: %ld\n",
>> +			PTR_ERR(pcie->core_rst));
>> +		return PTR_ERR(pcie->core_rst);
>> +	}
>> +
>> +	pp->irq = platform_get_irq_byname(pdev, "intr");
>> +	if (!pp->irq) {
>> +		dev_err(dev, "Failed to get \"intr\" interrupt\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	ret = devm_request_irq(dev, pp->irq, tegra_pcie_irq_handler,
>> +			       IRQF_SHARED, "tegra-pcie-intr", pcie);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, ret);
>> +		return ret;
>> +	}
>> +
>> +	pcie->bpmp = tegra_bpmp_get(dev);
>> +	if (IS_ERR(pcie->bpmp))
>> +		return PTR_ERR(pcie->bpmp);
>> +
>> +	platform_set_drvdata(pdev, pcie);
>> +
>> +	if (pcie->mode == DW_PCIE_RC_TYPE) {
>> +		ret = tegra_pcie_config_rp(pcie);
>> +		if (ret && ret != -ENOMEDIUM)
>> +			goto fail;
>> +		else
>> +			return 0;
>> +	}
>> +
>> +fail:
>> +	tegra_bpmp_put(pcie->bpmp);
>> +	return ret;
>> +}
>> +
>> +static int tegra_pcie_dw_remove(struct platform_device *pdev)
>> +{
>> +	struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev);
>> +
>> +	if (pcie->mode != DW_PCIE_RC_TYPE)
>> +		return 0;
>> +
>> +	if (!pcie->link_state)
>> +		return 0;
>> +
>> +	debugfs_remove_recursive(pcie->debugfs);
>> +	tegra_pcie_deinit_controller(pcie);
>> +	pm_runtime_put_sync(pcie->dev);
>> +	pm_runtime_disable(pcie->dev);
>> +	tegra_bpmp_put(pcie->bpmp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra_pcie_dw_suspend_late(struct device *dev)
>> +{
>> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
>> +	u32 val;
>> +
>> +	if (!pcie->link_state)
>> +		return 0;
>> +
>> +	/* Enable HW_HOT_RST mode */
>> +	val = appl_readl(pcie, APPL_CTRL);
>> +	val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK <<
>> +		 APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
>> +	val |= APPL_CTRL_HW_HOT_RST_EN;
>> +	appl_writel(pcie, val, APPL_CTRL);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra_pcie_dw_suspend_noirq(struct device *dev)
>> +{
>> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
>> +
>> +	if (!pcie->link_state)
>> +		return 0;
>> +
>> +	/* Save MSI interrupt vector */
>> +	pcie->msi_ctrl_int = dw_pcie_readl_dbi(&pcie->pci,
>> +					       PORT_LOGIC_MSI_CTRL_INT_0_EN);
>> +	tegra_pcie_downstream_dev_to_D0(pcie);
>> +	tegra_pcie_dw_pme_turnoff(pcie);
>> +	return __deinit_controller(pcie);
>> +}
>> +
>> +static int tegra_pcie_dw_resume_noirq(struct device *dev)
>> +{
>> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
>> +	int ret;
>> +
>> +	if (!pcie->link_state)
>> +		return 0;
>> +
>> +	ret = tegra_pcie_config_controller(pcie, true);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	ret = tegra_pcie_dw_host_init(&pcie->pci.pp);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to init host: %d\n", ret);
>> +		goto fail_host_init;
>> +	}
>> +
>> +	/* Restore MSI interrupt vector */
>> +	dw_pcie_writel_dbi(&pcie->pci, PORT_LOGIC_MSI_CTRL_INT_0_EN,
>> +			   pcie->msi_ctrl_int);
>> +
>> +	return 0;
>> +fail_host_init:
>> +	return __deinit_controller(pcie);
>> +}
>> +
>> +static int tegra_pcie_dw_resume_early(struct device *dev)
>> +{
>> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
>> +	u32 val;
>> +
>> +	if (!pcie->link_state)
>> +		return 0;
>> +
>> +	/* Disable HW_HOT_RST mode */
>> +	val = appl_readl(pcie, APPL_CTRL);
>> +	val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK <<
>> +		 APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
>> +	val |= APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST <<
>> +	       APPL_CTRL_HW_HOT_RST_MODE_SHIFT;
>> +	val &= ~APPL_CTRL_HW_HOT_RST_EN;
>> +	appl_writel(pcie, val, APPL_CTRL);
>> +
>> +	return 0;
>> +}
>> +
>> +static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
>> +{
>> +	struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev);
>> +
>> +	if (pcie->mode != DW_PCIE_RC_TYPE)
>> +		return;
>> +
>> +	if (!pcie->link_state)
>> +		return;
>> +
>> +	debugfs_remove_recursive(pcie->debugfs);
>> +	tegra_pcie_downstream_dev_to_D0(pcie);
>> +
>> +	disable_irq(pcie->pci.pp.irq);
>> +	if (IS_ENABLED(CONFIG_PCI_MSI))
>> +		disable_irq(pcie->pci.pp.msi_irq);
>> +
>> +	tegra_pcie_dw_pme_turnoff(pcie);
>> +	__deinit_controller(pcie);
>> +}
>> +
>> +static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
>> +	.suspend_late = tegra_pcie_dw_suspend_late,
>> +	.suspend_noirq = tegra_pcie_dw_suspend_noirq,
>> +	.resume_noirq = tegra_pcie_dw_resume_noirq,
>> +	.resume_early = tegra_pcie_dw_resume_early,
>> +};
>> +
>> +static struct platform_driver tegra_pcie_dw_driver = {
>> +	.probe = tegra_pcie_dw_probe,
>> +	.remove = tegra_pcie_dw_remove,
>> +	.shutdown = tegra_pcie_dw_shutdown,
>> +	.driver = {
>> +		.name	= "tegra194-pcie",
>> +		.pm = &tegra_pcie_dw_pm_ops,
>> +		.of_match_table = tegra_pcie_dw_of_match,
>> +	},
>> +};
>> +module_platform_driver(tegra_pcie_dw_driver);
>> +
>> +MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
>> +MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
>> +MODULE_LICENSE("GPL v2");
>> -- 
>> 2.17.1
>>

^ permalink raw reply

* Re: [PATCH V13 08/12] dt-bindings: Add PCIe supports-clkreq property
From: Vidya Sagar @ 2019-07-10 17:14 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: bhelgaas, robh+dt, mark.rutland, thierry.reding, jonathanh,
	kishon, catalin.marinas, will.deacon, jingoohan1,
	gustavo.pimentel, digetx, mperttunen, linux-pci, devicetree,
	linux-tegra, linux-kernel, linux-arm-kernel, kthota, mmaddireddy,
	sagar.tv
In-Reply-To: <20190710152856.GB8781@e121166-lin.cambridge.arm.com>

On 7/10/2019 8:58 PM, Lorenzo Pieralisi wrote:
> On Wed, Jul 10, 2019 at 11:52:08AM +0530, Vidya Sagar wrote:
>> Some host controllers need to know the existence of clkreq signal routing to
>> downstream devices to be able to advertise low power features like ASPM L1
>> substates. Without clkreq signal routing being present, enabling ASPM L1 sub
>> states might lead to downstream devices falling off the bus. Hence a new device
> 
> You mean "being disconnected from the bus" right ? I will update it.
Yes. I meant the same.

> 
> Lorenzo
> 
>> tree property 'supports-clkreq' is added to make such host controllers
>> aware of clkreq signal routing to downstream devices.
>>
>> Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
>> Reviewed-by: Rob Herring <robh@kernel.org>
>> Reviewed-by: Thierry Reding <treding@nvidia.com>
>> ---
>> V13:
>> * None
>>
>> V12:
>> * Rebased on top of linux-next top of the tree
>>
>> V11:
>> * None
>>
>> V10:
>> * None
>>
>> V9:
>> * None
>>
>> V8:
>> * None
>>
>> V7:
>> * None
>>
>> V6:
>> * s/Documentation\/devicetree/dt-bindings/ in the subject
>>
>> V5:
>> * None
>>
>> V4:
>> * Rebased on top of linux-next top of the tree
>>
>> V3:
>> * None
>>
>> V2:
>> * This is a new patch in v2 series
>>
>>   Documentation/devicetree/bindings/pci/pci.txt | 5 +++++
>>   1 file changed, 5 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
>> index 2a5d91024059..29bcbd88f457 100644
>> --- a/Documentation/devicetree/bindings/pci/pci.txt
>> +++ b/Documentation/devicetree/bindings/pci/pci.txt
>> @@ -27,6 +27,11 @@ driver implementation may support the following properties:
>>   - reset-gpios:
>>      If present this property specifies PERST# GPIO. Host drivers can parse the
>>      GPIO and apply fundamental reset to endpoints.
>> +- supports-clkreq:
>> +   If present this property specifies that CLKREQ signal routing exists from
>> +   root port to downstream device and host bridge drivers can do programming
>> +   which depends on CLKREQ signal existence. For example, programming root port
>> +   not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal.
>>   
>>   PCI-PCI Bridge properties
>>   -------------------------
>> -- 
>> 2.17.1
>>

^ permalink raw reply

* Re: [PATCH 1/6] dt-bindings: irqchip: Add PRUSS interrupt controller bindings
From: David Lechner @ 2019-07-10 17:08 UTC (permalink / raw)
  To: Suman Anna, Andrew F. Davis, Marc Zyngier, Rob Herring,
	Thomas Gleixner, Jason Cooper
  Cc: devicetree, Grygorii Strashko, Tony Lindgren, Sekhar Nori,
	linux-kernel, Lokesh Vutla, Murali Karicheri, linux-omap,
	linux-arm-kernel, Roger Quadros
In-Reply-To: <53868885-a78d-448a-1f2a-03a16251d028@ti.com>


>>> +- interrupts           : all the interrupts generated towards the main host
>>> +                         processor in the SoC. The format depends on the
>>> +                         interrupt specifier for the particular SoC's ARM GIC
>>> +                         parent interrupt controller. A shared interrupt can
>>> +                         be skipped if the desired destination and usage is by
>>> +                         a different processor/device.
>>> +- interrupt-names      : should use one of the following names for each valid
>>> +                         interrupt connected to ARM GIC, the name should match
>>> +                         the corresponding host interrupt number,
>>> +                             "host0", "host1", "host2", "host3", "host4",
>>> +                             "host5", "host6" or "host7"
>>> +- interrupt-controller : mark this node as an interrupt controller
>>> +- #interrupt-cells     : should be 1. Client users shall use the PRU System
>>> +                         event number (the interrupt source that the client
>>> +                         is interested in) as the value of the interrupts
>>> +                         property in their node
>>> +
>>> +Optional Properties:
>>> +--------------------
>>> +The following properties are _required_ only for some SoCs. If none of the below
>>> +properties are defined, it implies that all the host interrupts 2 through 9 are
>>> +connected exclusively to the ARM GIC.
>>> +
>>> +- ti,irqs-reserved     : an array of 8-bit elements of host interrupts between
>>> +                         0 and 7 (corresponding to PRUSS INTC output interrupts
>>> +                         2 through 9) that are not connected to the ARM GIC.
>>
>> The reason for 0-7 mapping to 2-9 is not instantly clear to someone
>> reading this. If you respin this could you note that reason is
>> interrupts 0 and 1 are always routed back into the PRUSS.
> 
> Yeah, this is always going to be somewhat confusing since the driver has
> to deal with all hosts from channel-mapping perspective, but only the 8
> interrupts at most that reach MPU for handling interrupts. TRM has
> 
> Anyway, I have already mentioned the first 2 interrupt routing in the
> first paragraph above.
> 
> Thinking more
>> on that, the same is true for interrupt 7 ("host5") on AM437x/66AK2G yet
>> we don't skip that in the naming.. now that we have the reserved IRQ
>> mechanism above, why not leave the one-to-one interrupt to name mapping,
>> but always have at least the first two marked as reserved for all the
>> current devices:
>>
>> ti,irqs-reserved = /bits/ 8 <0 1>;
>>
>> Then any "hostx" listed as reserved need not be present in the host
>> interrupts property array. To me that would solve the "managing
>> interrupts not targeting the Linux running core" problem and keep the
>> names consistent, e.g.:
> 
> I had actually used the interrupt-names always starting from "host2"
> through "host9" (names from PRU perspective) previously, and I have
> changed this to start indexing from 0 in this series to address an
> internal review comment from Grygorii and to align with TRM. All the
> TRMs (except for AM572x) actually use the names/signals "host_intr0",
> "host_intr1".."host_intr7" etc for the interrupts going towards MPU.
> Maybe I should actually rename the interrupt-names to be host_intrX
> instead of hostX to avoid confusion and be exactly aligned with the TRM
> names. I will file a bug against AM57xx TRM to align the names with all
> other SoC TRMs.
> 
> I am using "output interrupt lines" to imply names w.r.t PRU vs "host
> interrupt" to imply ARM GIC names.
> 
> regards
> Suman
> 

FWIW, the AM1808 TRM only uses PRU_EVTOUT0 to PRU_EVTOUT7 and does not
mention "host" in relation to these interrupts. The AM3xxx and AM4xxx
also use similar names (PRU_ICSS_EVTOUT0, PRU_ICSS1_EVTOUT0) although
they do mention that the source is "pr1_host[0] output/events exported
from PRU_ICSS1". (Also, the older processors have AINTC instead of GIC).

Maybe to help clarify here we could mention "event" in the docs:


+- interrupt-names      : should use one of the following names for each valid
+                         host event interrupt connected to ARM interrupt
+                         controller,the name should match the corresponding
+                         host event interrupt number,
+                             "host0", "host1", "host2", "host3", "host4",
+                             "host5", "host6" or "host7"



...

>>> +
>>> +Example:
>>> +--------
>>> +
>>> +1.	/* AM33xx PRU-ICSS */
>>> +	pruss: pruss@0 {

I don't suppose there is a generic name that could be used here
instead of pruss? It seems like there should be one for remote
processors that aren't DSPs or other specialized processors.

^ permalink raw reply

* Re: [PATCH 2/3] devfreq: exynos-bus: convert to use dev_pm_opp_set_rate()
From: Krzysztof Kozlowski @ 2019-07-10 17:04 UTC (permalink / raw)
  To: k.konieczny
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Chanwoo Choi,
	Kukjin Kim, Kyungmin Park, Mark Rutland, MyungJoo Ham,
	Nishanth Menon, Rob Herring, Stephen Boyd, Viresh Kumar,
	devicetree, linux-arm-kernel, linux-kernel, linux-pm,
	linux-samsung-soc@vger.kernel.org
In-Reply-To: <20190708141140.24379-3-k.konieczny@partner.samsung.com>

On Mon, 8 Jul 2019 at 16:12, <k.konieczny@partner.samsung.com> wrote:
>
> From: Kamil Konieczny <k.konieczny@partner.samsung.com>
>
> Reuse opp core code for setting bus clock and voltage. As a side
> effect this allow useage of coupled regulators feature (required
> for boards using Exynos5422/5800 SoCs) because dev_pm_opp_set_rate()
> uses regulator_set_voltage_triplet() for setting regulator voltage
> while the old code used regulator_set_voltage_tol() with fixed
> tolerance. This patch also removes no longer needed parsing of DT
> property "exynos,voltage-tolerance" (no Exynos devfreq DT node uses

Please also update the bindings in such case. Both with removal of
unused property and with example/recommended regulator couplings.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH V13 12/12] PCI: tegra: Add Tegra194 PCIe support
From: Lorenzo Pieralisi @ 2019-07-10 17:02 UTC (permalink / raw)
  To: Vidya Sagar
  Cc: bhelgaas, robh+dt, mark.rutland, thierry.reding, jonathanh,
	kishon, catalin.marinas, will.deacon, jingoohan1,
	gustavo.pimentel, digetx, mperttunen, linux-pci, devicetree,
	linux-tegra, linux-kernel, linux-arm-kernel, kthota, mmaddireddy,
	sagar.tv
In-Reply-To: <20190710062212.1745-13-vidyas@nvidia.com>

On Wed, Jul 10, 2019 at 11:52:12AM +0530, Vidya Sagar wrote:

[...]

> +#if defined(CONFIG_PCIEASPM)
> +static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
> +{
> +	u32 val;
> +
> +	val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
> +	val &= ~PCI_L1SS_CAP_ASPM_L1_1;
> +	dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
> +}
> +
> +static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
> +{
> +	u32 val;
> +
> +	val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub);
> +	val &= ~PCI_L1SS_CAP_ASPM_L1_2;
> +	dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val);
> +}
> +
> +static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
> +{
> +	u32 val;
> +
> +	val = dw_pcie_readl_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid]);
> +	val &= ~(EVENT_COUNTER_EVENT_SEL_MASK << EVENT_COUNTER_EVENT_SEL_SHIFT);
> +	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
> +	val |= event << EVENT_COUNTER_EVENT_SEL_SHIFT;
> +	val |= EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
> +	dw_pcie_writel_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid], val);
> +	val = dw_pcie_readl_dbi(&pcie->pci, event_cntr_data_offset[pcie->cid]);
> +	return val;
> +}
> +
> +static int aspm_state_cnt(struct seq_file *s, void *data)
> +{
> +	struct tegra_pcie_dw *pcie = (struct tegra_pcie_dw *)
> +				     dev_get_drvdata(s->private);
> +	u32 val;
> +
> +	seq_printf(s, "Tx L0s entry count : %u\n",
> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_Tx_L0S));
> +
> +	seq_printf(s, "Rx L0s entry count : %u\n",
> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_Rx_L0S));
> +
> +	seq_printf(s, "Link L1 entry count : %u\n",
> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1));
> +
> +	seq_printf(s, "Link L1.1 entry count : %u\n",
> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1_1));
> +
> +	seq_printf(s, "Link L1.2 entry count : %u\n",
> +		   event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1_2));
> +
> +	/* Clear all counters */
> +	dw_pcie_writel_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid],
> +			   EVENT_COUNTER_ALL_CLEAR);
> +
> +	/* Re-enable counting */
> +	val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
> +	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
> +	dw_pcie_writel_dbi(&pcie->pci, event_cntr_ctrl_offset[pcie->cid], val);
> +
> +	return 0;
> +}
> +#endif
> +
> +static int init_debugfs(struct tegra_pcie_dw *pcie)
> +{
> +#if defined(CONFIG_PCIEASPM)
> +	struct dentry *d;
> +
> +	d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt",
> +					pcie->debugfs, aspm_state_cnt);
> +	if (IS_ERR_OR_NULL(d))
> +		dev_err(pcie->dev,
> +			"Failed to create debugfs file \"aspm_state_cnt\"\n");
> +#endif
> +	return 0;
> +}

I prefer writing it:

#if defined(CONFIG_PCIEASPM)
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
{
...
}

static void disable_aspm_l12(struct tegra_pcie_dw *pcie)
{
...
}

static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
{
...
}

static int aspm_state_cnt(struct seq_file *s, void *data)
{
...
}

static int init_debugfs(struct tegra_pcie_dw *pcie)
{
	struct dentry *d;

	d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt",
					pcie->debugfs, aspm_state_cnt);
	if (IS_ERR_OR_NULL(d))
		dev_err(pcie->dev,
			"Failed to create debugfs file \"aspm_state_cnt\"\n");
	return 0;
}
#else
static inline int init_debugfs(struct tegra_pcie_dw *pcie) { return 0; }
#endif

> +
> +static void tegra_pcie_enable_system_interrupts(struct pcie_port *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> +	u32 val;
> +	u16 val_w;
> +
> +	val = appl_readl(pcie, APPL_INTR_EN_L0_0);
> +	val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN;
> +	appl_writel(pcie, val, APPL_INTR_EN_L0_0);
> +
> +	val = appl_readl(pcie, APPL_INTR_EN_L1_0_0);
> +	val |= APPL_INTR_EN_L1_0_0_LINK_REQ_RST_NOT_INT_EN;
> +	appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
> +
> +	if (pcie->enable_cdm_check) {
> +		val = appl_readl(pcie, APPL_INTR_EN_L0_0);
> +		val |= APPL_INTR_EN_L0_0_CDM_REG_CHK_INT_EN;
> +		appl_writel(pcie, val, APPL_INTR_EN_L0_0);
> +
> +		val = appl_readl(pcie, APPL_INTR_EN_L1_18);
> +		val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_CMP_ERR;
> +		val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_LOGIC_ERR;
> +		appl_writel(pcie, val, APPL_INTR_EN_L1_18);
> +	}
> +
> +	val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
> +				  PCI_EXP_LNKSTA);
> +	pcie->init_link_width = (val_w & PCI_EXP_LNKSTA_NLW) >>
> +				PCI_EXP_LNKSTA_NLW_SHIFT;
> +
> +	val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
> +				  PCI_EXP_LNKCTL);
> +	val_w |= PCI_EXP_LNKCTL_LBMIE;
> +	dw_pcie_writew_dbi(&pcie->pci, pcie->pcie_cap_base + PCI_EXP_LNKCTL,
> +			   val_w);
> +}
> +
> +static void tegra_pcie_enable_legacy_interrupts(struct pcie_port *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> +	u32 val;
> +
> +	/* Enable legacy interrupt generation */
> +	val = appl_readl(pcie, APPL_INTR_EN_L0_0);
> +	val |= APPL_INTR_EN_L0_0_SYS_INTR_EN;
> +	val |= APPL_INTR_EN_L0_0_INT_INT_EN;
> +	appl_writel(pcie, val, APPL_INTR_EN_L0_0);
> +
> +	val = appl_readl(pcie, APPL_INTR_EN_L1_8_0);
> +	val |= APPL_INTR_EN_L1_8_INTX_EN;
> +	val |= APPL_INTR_EN_L1_8_AUTO_BW_INT_EN;
> +	val |= APPL_INTR_EN_L1_8_BW_MGT_INT_EN;
> +	if (IS_ENABLED(CONFIG_PCIEAER))
> +		val |= APPL_INTR_EN_L1_8_AER_INT_EN;
> +	appl_writel(pcie, val, APPL_INTR_EN_L1_8_0);
> +}
> +
> +static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> +	u32 val;
> +
> +	dw_pcie_msi_init(pp);
> +
> +	/* Enable MSI interrupt generation */
> +	val = appl_readl(pcie, APPL_INTR_EN_L0_0);
> +	val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
> +	val |= APPL_INTR_EN_L0_0_MSI_RCV_INT_EN;
> +	appl_writel(pcie, val, APPL_INTR_EN_L0_0);
> +}
> +
> +static void tegra_pcie_enable_interrupts(struct pcie_port *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> +
> +	/* Clear interrupt statuses before enabling interrupts */
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15);
> +	appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17);
> +
> +	tegra_pcie_enable_system_interrupts(pp);
> +	tegra_pcie_enable_legacy_interrupts(pp);
> +	if (IS_ENABLED(CONFIG_PCI_MSI))
> +		tegra_pcie_enable_msi_interrupts(pp);
> +}
> +
> +static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
> +{
> +	struct dw_pcie *pci = &pcie->pci;
> +	u32 val, offset, i;
> +
> +	/* Program init preset */
> +	for (i = 0; i < pcie->num_lanes; i++) {
> +		dw_pcie_read(pci->dbi_base + CAP_SPCIE_CAP_OFF
> +				 + (i * 2), 2, &val);
> +		val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK;
> +		val |= GEN3_GEN4_EQ_PRESET_INIT;
> +		val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK;
> +		val |= (GEN3_GEN4_EQ_PRESET_INIT <<
> +			   CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT);
> +		dw_pcie_write(pci->dbi_base + CAP_SPCIE_CAP_OFF
> +				 + (i * 2), 2, val);
> +
> +		offset = dw_pcie_find_ext_capability(pci,
> +						     PCI_EXT_CAP_ID_PL_16GT) +
> +				PCI_PL_16GT_LE_CTRL;
> +		dw_pcie_read(pci->dbi_base + offset + i, 1, &val);
> +		val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK;
> +		val |= GEN3_GEN4_EQ_PRESET_INIT;
> +		val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK;
> +		val |= (GEN3_GEN4_EQ_PRESET_INIT <<
> +			PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT);
> +		dw_pcie_write(pci->dbi_base + offset + i, 1, val);
> +	}
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> +	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> +	val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK;
> +	val |= (0x3ff << GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT);
> +	val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE_MASK;
> +	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> +	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
> +	val |= (0x1 << GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT);
> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> +	val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK;
> +	val |= (0x360 << GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT);
> +	val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE_MASK;
> +	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> +	val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK;
> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> +}
> +
> +static int tegra_pcie_dw_host_init(struct pcie_port *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> +	u32 val, tmp, offset, speed;
> +	unsigned int count;
> +	u16 val_w;
> +
> +core_init:

Why should we restart from here ? What's the effect of the reset
on following registers set-up ?

> +	count = 200;
> +#if defined(CONFIG_PCIEASPM)
> +	offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
> +	pcie->cfg_link_cap_l1sub = offset + PCI_L1SS_CAP;
> +#endif

Can we group it in the #ifdef above ?

> +	val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
> +	val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
> +	dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
> +
> +	val = dw_pcie_readl_dbi(pci, PCI_PREF_MEMORY_BASE);
> +	val |= CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE;
> +	val |= CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE;
> +	dw_pcie_writel_dbi(pci, PCI_PREF_MEMORY_BASE, val);
> +
> +	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
> +
> +	/* Configure FTS */
> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
> +	val &= ~(N_FTS_MASK << N_FTS_SHIFT);
> +	val |= N_FTS_VAL << N_FTS_SHIFT;
> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
> +
> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
> +	val &= ~FTS_MASK;
> +	val |= FTS_VAL;
> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
> +
> +	/* Enable as 0xFFFF0001 response for CRS */
> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
> +	val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT);
> +	val |= (AMBA_ERROR_RESPONSE_CRS_OKAY_FFFF0001 <<
> +		AMBA_ERROR_RESPONSE_CRS_SHIFT);
> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
> +
> +	/* Configure Max Speed from DT */
> +	if (pcie->max_speed && pcie->max_speed != -EINVAL) {
> +		val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
> +					PCI_EXP_LNKCAP);
> +		val &= ~PCI_EXP_LNKCAP_SLS;
> +		val |= pcie->max_speed;
> +		dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
> +				   val);
> +	}
> +
> +	/* Configure Max lane width from DT */
> +	val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
> +	val &= ~PCI_EXP_LNKCAP_MLW;
> +	val |= (pcie->num_lanes << PCI_EXP_LNKSTA_NLW_SHIFT);
> +	dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, val);
> +
> +	config_gen3_gen4_eq_presets(pcie);
> +
> +#if defined(CONFIG_PCIEASPM)
> +	/* Enable ASPM counters */
> +	val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT;
> +	val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT;
> +	dw_pcie_writel_dbi(pci, event_cntr_ctrl_offset[pcie->cid], val);
> +
> +	/* Program T_cmrt and T_pwr_on values */
> +	val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
> +	val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE);
> +	val |= (pcie->aspm_cmrt << 8);
> +	val |= (pcie->aspm_pwr_on_t << 19);
> +	dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
> +
> +	/* Program L0s and L1 entrance latencies */
> +	val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
> +	val &= ~L0S_ENTRANCE_LAT_MASK;
> +	val |= (pcie->aspm_l0s_enter_lat << L0S_ENTRANCE_LAT_SHIFT);
> +	val |= ENTER_ASPM;
> +	dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
> +#endif

It would be good to group all init guarded in CONFIG_PCIEASPM in
one function and related ifdef guard.

> +	val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> +	val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
> +	dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> +
> +	if (pcie->update_fc_fixup) {
> +		val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
> +		val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
> +		dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
> +	}
> +
> +	dw_pcie_setup_rc(pp);
> +
> +	clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
> +
> +	/* Assert RST */
> +	val = appl_readl(pcie, APPL_PINMUX);
> +	val &= ~APPL_PINMUX_PEX_RST;
> +	appl_writel(pcie, val, APPL_PINMUX);

What's the effect of this RST on the registers programmed above ?

> +	usleep_range(100, 200);
> +
> +	/* Enable LTSSM */
> +	val = appl_readl(pcie, APPL_CTRL);
> +	val |= APPL_CTRL_LTSSM_EN;
> +	appl_writel(pcie, val, APPL_CTRL);
> +
> +	/* De-assert RST */
> +	val = appl_readl(pcie, APPL_PINMUX);
> +	val |= APPL_PINMUX_PEX_RST;
> +	appl_writel(pcie, val, APPL_PINMUX);
> +
> +	msleep(100);
> +
> +	val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
> +	while (!(val_w & PCI_EXP_LNKSTA_DLLLA)) {
> +		if (count) {
> +			dev_dbg(pci->dev, "Waiting for link up\n");
> +			usleep_range(1000, 2000);
> +			val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
> +						  PCI_EXP_LNKSTA);
> +			count--;
> +			continue;
> +		}
> +
> +		val = appl_readl(pcie, APPL_DEBUG);
> +		val &= APPL_DEBUG_LTSSM_STATE_MASK;
> +		val >>= APPL_DEBUG_LTSSM_STATE_SHIFT;
> +		tmp = appl_readl(pcie, APPL_LINK_STATUS);
> +		tmp &= APPL_LINK_STATUS_RDLH_LINK_UP;
> +		if (!(val == 0x11 && !tmp)) {
> +			dev_info(pci->dev, "Link is down\n");
> +			return 0;
> +		}
> +
> +		dev_info(pci->dev, "Link is down in DLL");
> +		dev_info(pci->dev, "Trying again with DLFE disabled\n");
> +		/* Disable LTSSM */
> +		val = appl_readl(pcie, APPL_CTRL);
> +		val &= ~APPL_CTRL_LTSSM_EN;
> +		appl_writel(pcie, val, APPL_CTRL);
> +
> +		reset_control_assert(pcie->core_rst);
> +		reset_control_deassert(pcie->core_rst);
> +
> +		offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_DLF);
> +		val = dw_pcie_readl_dbi(pci, offset + PCI_DLF_CAP);
> +		val &= ~PCI_DLF_EXCHANGE_ENABLE;
> +		dw_pcie_writel_dbi(pci, offset, val);
> +
> +		/* Retry now with DLF Exchange disabled */
> +		goto core_init;

See above.

> +	}
> +	dev_dbg(pci->dev, "Link is up\n");
> +
> +	speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
> +		PCI_EXP_LNKSTA_CLS;
> +	clk_set_rate(pcie->core_clk, pcie_gen_freq[speed - 1]);
> +
> +	tegra_pcie_enable_interrupts(pp);
> +
> +	return 0;
> +}
> +
> +static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
> +{
> +	struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> +	u32 val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
> +
> +	return !!(val & PCI_EXP_LNKSTA_DLLLA);
> +}
> +
> +static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
> +{
> +	pp->num_vectors = MAX_MSI_IRQS;
> +}
> +
> +static const struct dw_pcie_ops tegra_dw_pcie_ops = {
> +	.link_up = tegra_pcie_dw_link_up,
> +};
> +
> +static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
> +	.rd_own_conf = tegra_pcie_dw_rd_own_conf,
> +	.wr_own_conf = tegra_pcie_dw_wr_own_conf,
> +	.host_init = tegra_pcie_dw_host_init,
> +	.set_num_vectors = tegra_pcie_set_msi_vec_num,
> +};
> +
> +static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
> +{
> +	unsigned int phy_count = pcie->phy_count;
> +
> +	while (phy_count--) {
> +		phy_power_off(pcie->phys[phy_count]);
> +		phy_exit(pcie->phys[phy_count]);
> +	}
> +}
> +
> +static int tegra_pcie_enable_phy(struct tegra_pcie_dw *pcie)
> +{
> +	unsigned int i;
> +	int ret;
> +
> +	for (i = 0; i < pcie->phy_count; i++) {
> +		ret = phy_init(pcie->phys[i]);
> +		if (ret < 0)
> +			goto phy_power_off;
> +
> +		ret = phy_power_on(pcie->phys[i]);
> +		if (ret < 0)
> +			goto phy_exit;
> +	}
> +
> +	return 0;
> +
> +phy_power_off:
> +	while (i--) {
> +		phy_power_off(pcie->phys[i]);
> +phy_exit:
> +		phy_exit(pcie->phys[i]);
> +	}
> +
> +	return ret;
> +}
> +
> +static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
> +{
> +	struct device_node *np = pcie->dev->of_node;
> +	int ret;
> +
> +	ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt);
> +	if (ret < 0) {
> +		dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32(np, "nvidia,aspm-pwr-on-t-us",
> +				   &pcie->aspm_pwr_on_t);
> +	if (ret < 0)
> +		dev_info(pcie->dev, "Failed to read ASPM Power On time: %d\n",
> +			 ret);
> +
> +	ret = of_property_read_u32(np, "nvidia,aspm-l0s-entrance-latency-us",
> +				   &pcie->aspm_l0s_enter_lat);
> +	if (ret < 0)
> +		dev_info(pcie->dev,
> +			 "Failed to read ASPM L0s Entrance latency: %d\n", ret);
> +
> +	ret = of_property_read_u32(np, "num-lanes", &pcie->num_lanes);
> +	if (ret < 0) {
> +		dev_err(pcie->dev, "Failed to read num-lanes: %d\n", ret);
> +		return ret;
> +	}
> +
> +	pcie->max_speed = of_pci_get_max_link_speed(np);
> +
> +	ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret);
> +		return ret;
> +	}
> +
> +	pcie->phy_count = of_property_count_strings(np, "phy-names");
> +	if (pcie->phy_count < 0) {
> +		dev_err(pcie->dev, "Failed to find PHY entries: %d\n",
> +			pcie->phy_count);
> +		return pcie->phy_count;
> +	}
> +
> +	if (of_property_read_bool(np, "nvidia,update-fc-fixup"))
> +		pcie->update_fc_fixup = true;
> +
> +	pcie->supports_clkreq =
> +		of_property_read_bool(pcie->dev->of_node, "supports-clkreq");
> +
> +	pcie->enable_cdm_check =
> +		of_property_read_bool(np, "snps,enable-cdm-check");
> +
> +	return 0;
> +}
> +
> +static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
> +					  bool enable)
> +{
> +	struct mrq_uphy_response resp;
> +	struct tegra_bpmp_message msg;
> +	struct mrq_uphy_request req;
> +	int err;
> +
> +	if (pcie->cid == 5)
> +		return 0;
> +
> +	memset(&req, 0, sizeof(req));
> +	memset(&resp, 0, sizeof(resp));
> +
> +	req.cmd = CMD_UPHY_PCIE_CONTROLLER_STATE;
> +	req.controller_state.pcie_controller = pcie->cid;
> +	req.controller_state.enable = enable;
> +
> +	memset(&msg, 0, sizeof(msg));
> +	msg.mrq = MRQ_UPHY;
> +	msg.tx.data = &req;
> +	msg.tx.size = sizeof(req);
> +	msg.rx.data = &resp;
> +	msg.rx.size = sizeof(resp);
> +
> +	if (irqs_disabled())
> +		err = tegra_bpmp_transfer_atomic(pcie->bpmp, &msg);
> +	else
> +		err = tegra_bpmp_transfer(pcie->bpmp, &msg);
> +
> +	return err;
> +}
> +
> +static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
> +{
> +	struct pcie_port *pp = &pcie->pci.pp;
> +	struct pci_dev *pdev;
> +	struct pci_bus *child;
> +
> +	list_for_each_entry(child, &pp->root_bus->children, node) {
> +		/* Bring downstream devices to D0 if they are not already in */
> +		if (child->parent == pp->root_bus)
> +			break;
> +	}
> +	list_for_each_entry(pdev, &child->devices, bus_list) {
> +		if (PCI_SLOT(pdev->devfn) == 0) {
> +			if (pci_set_power_state(pdev, PCI_D0))
> +				dev_err(pcie->dev,
> +					"Failed to transition %s to D0 state\n",
> +					dev_name(&pdev->dev));
> +		}
> +	}
> +}
> +
> +static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
> +					bool en_hw_hot_rst)
> +{
> +	int ret;
> +	u32 val;
> +
> +	ret = tegra_pcie_bpmp_set_ctrl_state(pcie, true);
> +	if (ret) {
> +		dev_err(pcie->dev,
> +			"Failed to enable controller %u: %d\n", pcie->cid, ret);
> +		return ret;
> +	}
> +
> +	ret = regulator_enable(pcie->pex_ctl_supply);
> +	if (ret < 0) {
> +		dev_err(pcie->dev, "Failed to enable regulator: %d\n", ret);
> +		goto fail_reg_en;
> +	}
> +
> +	ret = clk_prepare_enable(pcie->core_clk);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to enable core clock: %d\n", ret);
> +		goto fail_core_clk;
> +	}
> +
> +	ret = reset_control_deassert(pcie->core_apb_rst);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to deassert core APB reset: %d\n",
> +			ret);
> +		goto fail_core_apb_rst;
> +	}
> +
> +	if (en_hw_hot_rst) {
> +		/* Enable HW_HOT_RST mode */
> +		val = appl_readl(pcie, APPL_CTRL);
> +		val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK <<
> +			 APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
> +		val |= APPL_CTRL_HW_HOT_RST_EN;
> +		appl_writel(pcie, val, APPL_CTRL);
> +	}
> +
> +	ret = tegra_pcie_enable_phy(pcie);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to enable PHY: %d\n", ret);
> +		goto fail_phy;
> +	}
> +
> +	/* Update CFG base address */
> +	appl_writel(pcie, pcie->dbi_res->start & APPL_CFG_BASE_ADDR_MASK,
> +		    APPL_CFG_BASE_ADDR);
> +
> +	/* Configure this core for RP mode operation */
> +	appl_writel(pcie, APPL_DM_TYPE_RP, APPL_DM_TYPE);
> +
> +	appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE);
> +
> +	val = appl_readl(pcie, APPL_CTRL);
> +	appl_writel(pcie, val | APPL_CTRL_SYS_PRE_DET_STATE, APPL_CTRL);
> +
> +	val = appl_readl(pcie, APPL_CFG_MISC);
> +	val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT);
> +	appl_writel(pcie, val, APPL_CFG_MISC);
> +
> +	if (!pcie->supports_clkreq) {
> +		val = appl_readl(pcie, APPL_PINMUX);
> +		val |= APPL_PINMUX_CLKREQ_OUT_OVRD_EN;
> +		val |= APPL_PINMUX_CLKREQ_OUT_OVRD;
> +		appl_writel(pcie, val, APPL_PINMUX);
> +	}
> +
> +	/* Update iATU_DMA base address */
> +	appl_writel(pcie,
> +		    pcie->atu_dma_res->start & APPL_CFG_IATU_DMA_BASE_ADDR_MASK,
> +		    APPL_CFG_IATU_DMA_BASE_ADDR);
> +
> +	reset_control_deassert(pcie->core_rst);
> +
> +	pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
> +						      PCI_CAP_ID_EXP);
> +
> +#if defined(CONFIG_PCIEASPM)
> +	/* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
> +	if (!pcie->supports_clkreq) {
> +		disable_aspm_l11(pcie);
> +		disable_aspm_l12(pcie);
> +	}
> +#endif
> +	return ret;
> +
> +fail_phy:
> +	reset_control_assert(pcie->core_apb_rst);
> +fail_core_apb_rst:
> +	clk_disable_unprepare(pcie->core_clk);
> +fail_core_clk:
> +	regulator_disable(pcie->pex_ctl_supply);
> +fail_reg_en:
> +	tegra_pcie_bpmp_set_ctrl_state(pcie, false);
> +
> +	return ret;
> +}
> +
> +static int __deinit_controller(struct tegra_pcie_dw *pcie)
> +{
> +	int ret;
> +
> +	ret = reset_control_assert(pcie->core_rst);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
> +			ret);
> +		return ret;
> +	}
> +	tegra_pcie_disable_phy(pcie);
> +	ret = reset_control_assert(pcie->core_apb_rst);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
> +		return ret;
> +	}
> +	clk_disable_unprepare(pcie->core_clk);
> +	ret = regulator_disable(pcie->pex_ctl_supply);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
> +		return ret;
> +	}
> +	ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
> +	if (ret) {
> +		dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
> +			pcie->cid, ret);
> +		return ret;
> +	}
> +	return ret;
> +}
> +
> +static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
> +{
> +	struct dw_pcie *pci = &pcie->pci;
> +	struct pcie_port *pp = &pci->pp;
> +	int ret;
> +
> +	ret = tegra_pcie_config_controller(pcie, false);
> +	if (ret < 0)
> +		return ret;
> +
> +	pp->root_bus_nr = -1;

Useless, drop it, it is initialized in dw_pcie_host_init().

> +	pp->ops = &tegra_pcie_dw_host_ops;
> +
> +	ret = dw_pcie_host_init(pp);
> +	if (ret < 0) {
> +		dev_err(pcie->dev, "Failed to add PCIe port: %d\n", ret);
> +		goto fail_host_init;
> +	}
> +
> +	return 0;
> +
> +fail_host_init:
> +	return __deinit_controller(pcie);
> +}
> +
> +static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
> +{
> +	u32 val;
> +
> +	if (!tegra_pcie_dw_link_up(&pcie->pci))
> +		return 0;
> +
> +	val = appl_readl(pcie, APPL_RADM_STATUS);
> +	val |= APPL_PM_XMT_TURNOFF_STATE;
> +	appl_writel(pcie, val, APPL_RADM_STATUS);
> +
> +	return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val,
> +				 val & APPL_DEBUG_PM_LINKST_IN_L2_LAT,
> +				 1, PME_ACK_TIMEOUT);
> +}
> +
> +static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
> +{
> +	u32 data;
> +	int err;
> +
> +	if (!tegra_pcie_dw_link_up(&pcie->pci)) {
> +		dev_dbg(pcie->dev, "PCIe link is not up...!\n");
> +		return;
> +	}
> +
> +	if (tegra_pcie_try_link_l2(pcie)) {
> +		dev_info(pcie->dev, "Link didn't transition to L2 state\n");
> +		/*
> +		 * TX lane clock freq will reset to Gen1 only if link is in L2
> +		 * or detect state.
> +		 * So apply pex_rst to end point to force RP to go into detect
> +		 * state
> +		 */
> +		data = appl_readl(pcie, APPL_PINMUX);
> +		data &= ~APPL_PINMUX_PEX_RST;
> +		appl_writel(pcie, data, APPL_PINMUX);
> +
> +		err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
> +						data,
> +						((data &
> +						APPL_DEBUG_LTSSM_STATE_MASK) >>
> +						APPL_DEBUG_LTSSM_STATE_SHIFT) ==
> +						LTSSM_STATE_PRE_DETECT,
> +						1, LTSSM_TIMEOUT);
> +		if (err) {
> +			dev_info(pcie->dev, "Link didn't go to detect state\n");
> +		} else {
> +			/* Disable LTSSM after link is in detect state */
> +			data = appl_readl(pcie, APPL_CTRL);
> +			data &= ~APPL_CTRL_LTSSM_EN;
> +			appl_writel(pcie, data, APPL_CTRL);
> +		}
> +	}
> +	/*
> +	 * DBI registers may not be accessible after this as PLL-E would be
> +	 * down depending on how CLKREQ is pulled by end point
> +	 */
> +	data = appl_readl(pcie, APPL_PINMUX);
> +	data |= (APPL_PINMUX_CLKREQ_OVERRIDE_EN | APPL_PINMUX_CLKREQ_OVERRIDE);
> +	/* Cut REFCLK to slot */
> +	data |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN;
> +	data &= ~APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE;
> +	appl_writel(pcie, data, APPL_PINMUX);
> +}
> +
> +static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
> +{
> +	/*
> +	 * link doesn't go into L2 state with some of the endpoints with Tegra
> +	 * if they are not in D0 state. So, need to make sure that immediate
> +	 * downstream devices are in D0 state before sending PME_TurnOff to put
> +	 * link into L2 state
> +	 */
> +	tegra_pcie_downstream_dev_to_D0(pcie);
> +	dw_pcie_host_deinit(&pcie->pci.pp);
> +	tegra_pcie_dw_pme_turnoff(pcie);
> +	return __deinit_controller(pcie);
> +}
> +
> +static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
> +{
> +	struct pcie_port *pp = &pcie->pci.pp;
> +	struct device *dev = pcie->dev;
> +	char *name;
> +	int ret;
> +
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
> +		if (!pp->msi_irq) {
> +			dev_err(dev, "Failed to get MSI interrupt\n");
> +			return -ENODEV;
> +		}
> +	}
> +
> +	pm_runtime_enable(dev);
> +	ret = pm_runtime_get_sync(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to get runtime sync for PCIe dev: %d\n",
> +			ret);
> +		pm_runtime_disable(dev);
> +		return ret;
> +	}
> +
> +	tegra_pcie_init_controller(pcie);
> +
> +	pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
> +
> +	if (!pcie->link_state) {
> +		ret = -ENOMEDIUM;
> +		goto fail_host_init;
> +	}
> +
> +	name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node);
> +	if (!name) {
> +		ret = -ENOMEM;
> +		goto fail_host_init;
> +	}
> +
> +	pcie->debugfs = debugfs_create_dir(name, NULL);
> +	if (!pcie->debugfs)
> +		dev_err(dev, "Failed to create debugfs\n");
> +	else
> +		init_debugfs(pcie);
> +
> +	return ret;
> +
> +fail_host_init:
> +	tegra_pcie_deinit_controller(pcie);
> +	pm_runtime_put_sync(dev);
> +	pm_runtime_disable(dev);
> +	return ret;
> +}
> +
> +static const struct tegra_pcie_soc tegra_pcie_rc_of_data = {
> +	.mode = DW_PCIE_RC_TYPE,
> +};
> +
> +static const struct of_device_id tegra_pcie_dw_of_match[] = {
> +	{
> +		.compatible = "nvidia,tegra194-pcie",
> +		.data = &tegra_pcie_rc_of_data,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match);

Move it closer to end of file where MODULE_DESCRIPTION() et al are.

> +
> +static int tegra_pcie_dw_probe(struct platform_device *pdev)
> +{
> +	const struct tegra_pcie_soc *data;
> +	struct device *dev = &pdev->dev;
> +	struct resource *atu_dma_res;
> +	struct tegra_pcie_dw *pcie;
> +	struct resource *dbi_res;
> +	struct pcie_port *pp;
> +	struct dw_pcie *pci;
> +	struct phy **phys;
> +	char *name;
> +	int ret;
> +	u32 i;
> +
> +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> +	if (!pcie)
> +		return -ENOMEM;
> +
> +	pci = &pcie->pci;
> +	pci->dev = &pdev->dev;
> +	pci->ops = &tegra_dw_pcie_ops;
> +	pp = &pci->pp;
> +	pcie->dev = &pdev->dev;
> +
> +	data = (struct tegra_pcie_soc *)of_device_get_match_data(dev);
> +	if (!data)
> +		return -EINVAL;
> +	pcie->mode = (enum dw_pcie_device_mode)data->mode;
> +
> +	ret = tegra_pcie_dw_parse_dt(pcie);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to parse device tree: %d\n", ret);
> +		return ret;
> +	}
> +
> +	pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl");
> +	if (IS_ERR(pcie->pex_ctl_supply)) {
> +		dev_err(dev, "Failed to get regulator: %ld\n",
> +			PTR_ERR(pcie->pex_ctl_supply));
> +		return PTR_ERR(pcie->pex_ctl_supply);
> +	}
> +
> +	pcie->core_clk = devm_clk_get(dev, "core");
> +	if (IS_ERR(pcie->core_clk)) {
> +		dev_err(dev, "Failed to get core clock: %ld\n",
> +			PTR_ERR(pcie->core_clk));
> +		return PTR_ERR(pcie->core_clk);
> +	}
> +
> +	pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> +						      "appl");
> +	if (!pcie->appl_res) {
> +		dev_err(dev, "Failed to find \"appl\" region\n");
> +		return PTR_ERR(pcie->appl_res);
> +	}

Add an empty line.

> +	pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res);
> +	if (IS_ERR(pcie->appl_base))
> +		return PTR_ERR(pcie->appl_base);
> +
> +	pcie->core_apb_rst = devm_reset_control_get(dev, "apb");
> +	if (IS_ERR(pcie->core_apb_rst)) {
> +		dev_err(dev, "Failed to get APB reset: %ld\n",
> +			PTR_ERR(pcie->core_apb_rst));
> +		return PTR_ERR(pcie->core_apb_rst);
> +	}
> +
> +	phys = devm_kcalloc(dev, pcie->phy_count, sizeof(*phys), GFP_KERNEL);
> +	if (!phys)
> +		return PTR_ERR(phys);
> +
> +	for (i = 0; i < pcie->phy_count; i++) {
> +		name = kasprintf(GFP_KERNEL, "p2u-%u", i);
> +		if (!name) {
> +			dev_err(dev, "Failed to create P2U string\n");
> +			return -ENOMEM;
> +		}
> +		phys[i] = devm_phy_get(dev, name);
> +		kfree(name);
> +		if (IS_ERR(phys[i])) {
> +			ret = PTR_ERR(phys[i]);
> +			dev_err(dev, "Failed to get PHY: %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	pcie->phys = phys;
> +
> +	dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
> +	if (!dbi_res) {
> +		dev_err(dev, "Failed to find \"dbi\" region\n");
> +		return PTR_ERR(dbi_res);
> +	}
> +	pcie->dbi_res = dbi_res;
> +
> +	pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
> +	if (IS_ERR(pci->dbi_base))
> +		return PTR_ERR(pci->dbi_base);
> +
> +	/* Tegra HW locates DBI2 at a fixed offset from DBI */
> +	pci->dbi_base2 = pci->dbi_base + 0x1000;
> +
> +	atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> +						   "atu_dma");
> +	if (!atu_dma_res) {
> +		dev_err(dev, "Failed to find \"atu_dma\" region\n");
> +		return PTR_ERR(atu_dma_res);
> +	}
> +	pcie->atu_dma_res = atu_dma_res;

Add an empty line.

I have just skimmed over it, I need more time to review the driver more
thoroughly, I will try to go over it tomorrow and we can see if we can
hit v5.3 but I can't guarantee anything, sorry but there was a
significant backlog on the PCI patch queue.

The rest of the series is fine but it is useless to merge it
without this patch so let's see how it goes.

Lorenzo

> +	pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
> +	if (IS_ERR(pci->atu_base))
> +		return PTR_ERR(pci->atu_base);
> +
> +	pcie->core_rst = devm_reset_control_get(dev, "core");
> +	if (IS_ERR(pcie->core_rst)) {
> +		dev_err(dev, "Failed to get core reset: %ld\n",
> +			PTR_ERR(pcie->core_rst));
> +		return PTR_ERR(pcie->core_rst);
> +	}
> +
> +	pp->irq = platform_get_irq_byname(pdev, "intr");
> +	if (!pp->irq) {
> +		dev_err(dev, "Failed to get \"intr\" interrupt\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = devm_request_irq(dev, pp->irq, tegra_pcie_irq_handler,
> +			       IRQF_SHARED, "tegra-pcie-intr", pcie);
> +	if (ret) {
> +		dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, ret);
> +		return ret;
> +	}
> +
> +	pcie->bpmp = tegra_bpmp_get(dev);
> +	if (IS_ERR(pcie->bpmp))
> +		return PTR_ERR(pcie->bpmp);
> +
> +	platform_set_drvdata(pdev, pcie);
> +
> +	if (pcie->mode == DW_PCIE_RC_TYPE) {
> +		ret = tegra_pcie_config_rp(pcie);
> +		if (ret && ret != -ENOMEDIUM)
> +			goto fail;
> +		else
> +			return 0;
> +	}
> +
> +fail:
> +	tegra_bpmp_put(pcie->bpmp);
> +	return ret;
> +}
> +
> +static int tegra_pcie_dw_remove(struct platform_device *pdev)
> +{
> +	struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev);
> +
> +	if (pcie->mode != DW_PCIE_RC_TYPE)
> +		return 0;
> +
> +	if (!pcie->link_state)
> +		return 0;
> +
> +	debugfs_remove_recursive(pcie->debugfs);
> +	tegra_pcie_deinit_controller(pcie);
> +	pm_runtime_put_sync(pcie->dev);
> +	pm_runtime_disable(pcie->dev);
> +	tegra_bpmp_put(pcie->bpmp);
> +
> +	return 0;
> +}
> +
> +static int tegra_pcie_dw_suspend_late(struct device *dev)
> +{
> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> +	u32 val;
> +
> +	if (!pcie->link_state)
> +		return 0;
> +
> +	/* Enable HW_HOT_RST mode */
> +	val = appl_readl(pcie, APPL_CTRL);
> +	val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK <<
> +		 APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
> +	val |= APPL_CTRL_HW_HOT_RST_EN;
> +	appl_writel(pcie, val, APPL_CTRL);
> +
> +	return 0;
> +}
> +
> +static int tegra_pcie_dw_suspend_noirq(struct device *dev)
> +{
> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> +
> +	if (!pcie->link_state)
> +		return 0;
> +
> +	/* Save MSI interrupt vector */
> +	pcie->msi_ctrl_int = dw_pcie_readl_dbi(&pcie->pci,
> +					       PORT_LOGIC_MSI_CTRL_INT_0_EN);
> +	tegra_pcie_downstream_dev_to_D0(pcie);
> +	tegra_pcie_dw_pme_turnoff(pcie);
> +	return __deinit_controller(pcie);
> +}
> +
> +static int tegra_pcie_dw_resume_noirq(struct device *dev)
> +{
> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> +	int ret;
> +
> +	if (!pcie->link_state)
> +		return 0;
> +
> +	ret = tegra_pcie_config_controller(pcie, true);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = tegra_pcie_dw_host_init(&pcie->pci.pp);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to init host: %d\n", ret);
> +		goto fail_host_init;
> +	}
> +
> +	/* Restore MSI interrupt vector */
> +	dw_pcie_writel_dbi(&pcie->pci, PORT_LOGIC_MSI_CTRL_INT_0_EN,
> +			   pcie->msi_ctrl_int);
> +
> +	return 0;
> +fail_host_init:
> +	return __deinit_controller(pcie);
> +}
> +
> +static int tegra_pcie_dw_resume_early(struct device *dev)
> +{
> +	struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> +	u32 val;
> +
> +	if (!pcie->link_state)
> +		return 0;
> +
> +	/* Disable HW_HOT_RST mode */
> +	val = appl_readl(pcie, APPL_CTRL);
> +	val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK <<
> +		 APPL_CTRL_HW_HOT_RST_MODE_SHIFT);
> +	val |= APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST <<
> +	       APPL_CTRL_HW_HOT_RST_MODE_SHIFT;
> +	val &= ~APPL_CTRL_HW_HOT_RST_EN;
> +	appl_writel(pcie, val, APPL_CTRL);
> +
> +	return 0;
> +}
> +
> +static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
> +{
> +	struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev);
> +
> +	if (pcie->mode != DW_PCIE_RC_TYPE)
> +		return;
> +
> +	if (!pcie->link_state)
> +		return;
> +
> +	debugfs_remove_recursive(pcie->debugfs);
> +	tegra_pcie_downstream_dev_to_D0(pcie);
> +
> +	disable_irq(pcie->pci.pp.irq);
> +	if (IS_ENABLED(CONFIG_PCI_MSI))
> +		disable_irq(pcie->pci.pp.msi_irq);
> +
> +	tegra_pcie_dw_pme_turnoff(pcie);
> +	__deinit_controller(pcie);
> +}
> +
> +static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
> +	.suspend_late = tegra_pcie_dw_suspend_late,
> +	.suspend_noirq = tegra_pcie_dw_suspend_noirq,
> +	.resume_noirq = tegra_pcie_dw_resume_noirq,
> +	.resume_early = tegra_pcie_dw_resume_early,
> +};
> +
> +static struct platform_driver tegra_pcie_dw_driver = {
> +	.probe = tegra_pcie_dw_probe,
> +	.remove = tegra_pcie_dw_remove,
> +	.shutdown = tegra_pcie_dw_shutdown,
> +	.driver = {
> +		.name	= "tegra194-pcie",
> +		.pm = &tegra_pcie_dw_pm_ops,
> +		.of_match_table = tegra_pcie_dw_of_match,
> +	},
> +};
> +module_platform_driver(tegra_pcie_dw_driver);
> +
> +MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
> +MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.17.1
> 

^ permalink raw reply

* Re: [PATCH 1/3] opp: core: add regulators enable and disable
From: Krzysztof Kozlowski @ 2019-07-10 17:01 UTC (permalink / raw)
  To: k.konieczny
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Chanwoo Choi,
	Kukjin Kim, Kyungmin Park, Mark Rutland, MyungJoo Ham,
	Nishanth Menon, Rob Herring, Stephen Boyd, Viresh Kumar,
	devicetree, linux-arm-kernel, linux-kernel, linux-pm,
	linux-samsung-soc@vger.kernel.org
In-Reply-To: <20190708141140.24379-2-k.konieczny@partner.samsung.com>

On Mon, 8 Jul 2019 at 16:12, <k.konieczny@partner.samsung.com> wrote:
>
> From: Kamil Konieczny <k.konieczny@partner.samsung.com>
>
> Add enable regulators to dev_pm_opp_set_regulators() and disable
> regulators to dev_pm_opp_put_regulators(). This prepares for
> converting exynos-bus devfreq driver to use dev_pm_opp_set_rate().
>
> Signed-off-by: Kamil Konieczny <k.konieczny@partner.samsung.com>
> ---
>  drivers/opp/core.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)

Acked-by: Krzysztof Kozlowski <krzk@kernel.org>

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 0/3] add coupled regulators for Exynos5422/5800
From: Krzysztof Kozlowski @ 2019-07-10 17:01 UTC (permalink / raw)
  To: Kamil Konieczny
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Chanwoo Choi,
	Kukjin Kim, Kyungmin Park, Mark Rutland, MyungJoo Ham,
	Nishanth Menon, Rob Herring, Stephen Boyd, Viresh Kumar,
	devicetree, linux-arm-kernel, linux-kernel, linux-pm,
	linux-samsung-soc@vger.kernel.org
In-Reply-To: <631ffd68-7aab-2483-8799-2019bf3bb444@partner.samsung.com>

On Wed, 10 Jul 2019 at 15:51, Kamil Konieczny
<k.konieczny@partner.samsung.com> wrote:
>
> On 10.07.2019 12:14, Krzysztof Kozlowski wrote:
> > On Wed, 10 Jul 2019 at 12:03, Kamil Konieczny
> > <k.konieczny@partner.samsung.com> wrote:
> >>
> >> On 10.07.2019 11:00, Krzysztof Kozlowski wrote:
> >>> On Mon, 8 Jul 2019 at 16:12, <k.konieczny@partner.samsung.com> wrote:
> >>>>
> >>>> From: Kamil Konieczny <k.konieczny@partner.samsung.com>
> >>>>
> >>>> Hi,
> >>>>
> >>>> The main purpose of this patch series is to add coupled regulators for
> >>>> Exynos5422/5800 to keep constrain on voltage difference between vdd_arm
> >>>> and vdd_int to be at most 300mV. In exynos-bus instead of using
> >>>> regulator_set_voltage_tol() with default voltage tolerance it should be
> >>>> used regulator_set_voltage_triplet() with volatege range, and this is
> >>>> already present in opp/core.c code, so it can be reused. While at this,
> >>>> move setting regulators into opp/core.
> >>>>
> >>>> This patchset was tested on Odroid XU3.
> >>>>
> >>>> The last patch depends on two previous.
> >>>
> >>> So you break the ABI... I assume that patchset maintains
> >>> bisectability. However there is no explanation why ABI break is needed
> >>> so this does not look good...
> >>
> >> Patchset is bisectable, first one is simple and do not depends on others,
> >> second depends on first, last depends on first and second.
> >>
> >> What do you mean by breaking ABI ?
> >
> > I mean, that Linux kernel stops working with existing DTBs... or am I
> > mistaken and there is no problem? Maybe I confused the order...
>
> It is not ABI break, it should work with existing DTBs

Ah, thanks. My misunderstanding then. Looks good.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH v2 6/7] dt-bindings: net: realtek: Add property to configure LED mode
From: Florian Fainelli @ 2019-07-10 16:28 UTC (permalink / raw)
  To: Rob Herring, Matthias Kaehlcke, Andrew Lunn, Heiner Kallweit
  Cc: David S . Miller, Mark Rutland, netdev, devicetree,
	linux-kernel@vger.kernel.org, Douglas Anderson
In-Reply-To: <CAL_JsqL_AU+JV0c2mNbXiPh2pvfYbPbLV-2PHHX0hC3vUH4QWg@mail.gmail.com>

On 7/10/19 8:55 AM, Rob Herring wrote:
> On Wed, Jul 3, 2019 at 5:23 PM Matthias Kaehlcke <mka@chromium.org> wrote:
>>
>> Hi Florian,
>>
>> On Wed, Jul 03, 2019 at 02:37:47PM -0700, Florian Fainelli wrote:
>>> On 7/3/19 12:37 PM, Matthias Kaehlcke wrote:
>>>> The LED behavior of some Realtek PHYs is configurable. Add the
>>>> property 'realtek,led-modes' to specify the configuration of the
>>>> LEDs.
>>>>
>>>> Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>> Changes in v2:
>>>> - patch added to the series
>>>> ---
>>>>  .../devicetree/bindings/net/realtek.txt         |  9 +++++++++
>>>>  include/dt-bindings/net/realtek.h               | 17 +++++++++++++++++
>>>>  2 files changed, 26 insertions(+)
>>>>  create mode 100644 include/dt-bindings/net/realtek.h
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/net/realtek.txt b/Documentation/devicetree/bindings/net/realtek.txt
>>>> index 71d386c78269..40b0d6f9ee21 100644
>>>> --- a/Documentation/devicetree/bindings/net/realtek.txt
>>>> +++ b/Documentation/devicetree/bindings/net/realtek.txt
>>>> @@ -9,6 +9,12 @@ Optional properties:
>>>>
>>>>     SSC is only available on some Realtek PHYs (e.g. RTL8211E).
>>>>
>>>> +- realtek,led-modes: LED mode configuration.
>>>> +
>>>> +   A 0..3 element vector, with each element configuring the operating
>>>> +   mode of an LED. Omitted LEDs are turned off. Allowed values are
>>>> +   defined in "include/dt-bindings/net/realtek.h".
>>>
>>> This should probably be made more general and we should define LED modes
>>> that makes sense regardless of the PHY device, introduce a set of
>>> generic functions for validating and then add new function pointer for
>>> setting the LED configuration to the PHY driver. This would allow to be
>>> more future proof where each PHY driver could expose standard LEDs class
>>> devices to user-space, and it would also allow facilities like: ethtool
>>> -p to plug into that.
>>>
>>> Right now, each driver invents its own way of configuring LEDs, that
>>> does not scale, and there is not really a good reason for that other
>>> than reviewing drivers in isolation and therefore making it harder to
>>> extract the commonality. Yes, I realize that since you are the latest
>>> person submitting something in that area, you are being selected :)
> 
> I agree.
> 
>> I see the merit of your proposal to come up with a generic mechanism
>> to configure Ethernet LEDs, however I can't justify spending much of
>> my work time on this. If it is deemed useful I'm happy to send another
>> version of the current patchset that addresses the reviewer's comments,
>> but if the implementation of a generic LED configuration interface is
>> a requirement I will have to abandon at least the LED configuration
>> part of this series.
> 
> Can you at least define a common binding for this. Maybe that's just
> removing 'realtek'. While the kernel side can evolve to a common
> infrastructure, the DT bindings can't.

That would be a great start, and that is actually what I had in mind
(should have been more specific), I was not going to have you Matthias
do the grand slam and convert all this LED configuration into the LEDs
class etc. that would not be fair.

It seems to be that we can fairly easily agree on a common binding for
LED configuration, I would define something along those lines to be
flexible:

phy-led-configuration = <LED_NUM_MASK LED_CFG_MASK>;

where LED_NUM_MASK is one of:

0 -> link
1 -> activity
2 -> speed

that way you can define single/dual/triple LED configurations by
updating the bitmask.

LED_CFG_MASK is one of:

0 -> LED_CFG_10
1 -> LED_CFG_100
2 -> LED_CFG_1000

(let's assume 1Gbps or less for now)

or this can be combined in a single cell with a left shift.

Andrew, Heiner, do you see that approach working correctly and scaling
appropriately?
-- 
Florian

^ permalink raw reply

* Re: [patch 5/5] Documentation: DT bindings AST2500 DMA UART driver
From: Rob Herring @ 2019-07-10 15:55 UTC (permalink / raw)
  To: sudheer.v
  Cc: Greg Kroah-Hartman, Jiri Slaby, Joel Stanley, Andrew Jeffery,
	Benjamin Herrenschmidt, Mark Rutland,
	ShivahShankar Shakarnarayan rao, shivahshankar, Sudheer V,
	sudheer veliseti, linux-kernel@vger.kernel.org,
	open list:SERIAL DRIVERS, devicetree, linux-aspeed
In-Reply-To: <1561115855-4186-6-git-send-email-open.sudheer@gmail.com>


On Fri, Jun 21, 2019 at 5:16 AM sudheer.v <open.sudheer@gmail.com> wrote:
>
> From: sudheer veliseti <sudheer.open@gmail.com>
>
> Signed-off-by: sudheer veliseti <sudheer.open@gmail.com>
> ---
>  .../bindings/serial/ast2500-dma-uart.txt      | 40 +++++++++++++++++++
>  1 file changed, 40 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt
>
> diff --git a/Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt b/Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt
> new file mode 100644
> index 000000000000..6f01ddecba56
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt
> @@ -0,0 +1,40 @@
> +
> +node for DMA controller:
> +                       ast_uart_sdma: uart_sdma@1e79e000 {
> +                               compatible = "aspeed,ast-uart-sdma";
> +                               reg = <0x1e79e000 0x400>;
> +                               interrupts = <50>;
> +                               status = "disabled";
> +                       };
> +this node  doesn't binds with any driver.
> +DMA controller is handled as a separate SW layer,and is included in the same driver.
> +This DMA controller node is included in DT just for Register base and interrupt details
> +
> +
> +
> +node for DMA-UART :
> +
> +
> +Required properties:
> +
> +- compatible: "aspeed,ast-sdma-uart"
> +- reg: The base address of the UART register bank
> +- interrupts: should contain interrupt specifier.
> +- clocks: Clock driving the hardware;
> +- pinctrl-0 : list of pinconfigurations
> +- dma-channel: channel of DMA-controller which is used
> +
> +Example:
> +
> +                 dma_uart1: dma_uart1@1e783000{
> +                          compatible = "aspeed,ast-sdma-uart";
> +                          reg = <0x1e783000 0x1000>;
> +                          reg-shift = <2>;
> +                          interrupts = <9>;
> +                          clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>;
> +                          dma-channel = <0>;
> +                          no-loopback-test;
> +                          pinctrl-names = "default";
> +                          pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>;
> +                          status = "disabled";
> +                       };
> --
> 2.17.1
>

^ permalink raw reply

* Re: [PATCH v2 6/7] dt-bindings: net: realtek: Add property to configure LED mode
From: Rob Herring @ 2019-07-10 15:55 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Florian Fainelli, David S . Miller, Mark Rutland, Andrew Lunn,
	Heiner Kallweit, netdev, devicetree, linux-kernel@vger.kernel.org,
	Douglas Anderson
In-Reply-To: <20190703232331.GL250418@google.com>

On Wed, Jul 3, 2019 at 5:23 PM Matthias Kaehlcke <mka@chromium.org> wrote:
>
> Hi Florian,
>
> On Wed, Jul 03, 2019 at 02:37:47PM -0700, Florian Fainelli wrote:
> > On 7/3/19 12:37 PM, Matthias Kaehlcke wrote:
> > > The LED behavior of some Realtek PHYs is configurable. Add the
> > > property 'realtek,led-modes' to specify the configuration of the
> > > LEDs.
> > >
> > > Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
> > > ---
> > > Changes in v2:
> > > - patch added to the series
> > > ---
> > >  .../devicetree/bindings/net/realtek.txt         |  9 +++++++++
> > >  include/dt-bindings/net/realtek.h               | 17 +++++++++++++++++
> > >  2 files changed, 26 insertions(+)
> > >  create mode 100644 include/dt-bindings/net/realtek.h
> > >
> > > diff --git a/Documentation/devicetree/bindings/net/realtek.txt b/Documentation/devicetree/bindings/net/realtek.txt
> > > index 71d386c78269..40b0d6f9ee21 100644
> > > --- a/Documentation/devicetree/bindings/net/realtek.txt
> > > +++ b/Documentation/devicetree/bindings/net/realtek.txt
> > > @@ -9,6 +9,12 @@ Optional properties:
> > >
> > >     SSC is only available on some Realtek PHYs (e.g. RTL8211E).
> > >
> > > +- realtek,led-modes: LED mode configuration.
> > > +
> > > +   A 0..3 element vector, with each element configuring the operating
> > > +   mode of an LED. Omitted LEDs are turned off. Allowed values are
> > > +   defined in "include/dt-bindings/net/realtek.h".
> >
> > This should probably be made more general and we should define LED modes
> > that makes sense regardless of the PHY device, introduce a set of
> > generic functions for validating and then add new function pointer for
> > setting the LED configuration to the PHY driver. This would allow to be
> > more future proof where each PHY driver could expose standard LEDs class
> > devices to user-space, and it would also allow facilities like: ethtool
> > -p to plug into that.
> >
> > Right now, each driver invents its own way of configuring LEDs, that
> > does not scale, and there is not really a good reason for that other
> > than reviewing drivers in isolation and therefore making it harder to
> > extract the commonality. Yes, I realize that since you are the latest
> > person submitting something in that area, you are being selected :)

I agree.

> I see the merit of your proposal to come up with a generic mechanism
> to configure Ethernet LEDs, however I can't justify spending much of
> my work time on this. If it is deemed useful I'm happy to send another
> version of the current patchset that addresses the reviewer's comments,
> but if the implementation of a generic LED configuration interface is
> a requirement I will have to abandon at least the LED configuration
> part of this series.

Can you at least define a common binding for this. Maybe that's just
removing 'realtek'. While the kernel side can evolve to a common
infrastructure, the DT bindings can't.

Rob

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: mmc: Document Aspeed SD controller
From: Rob Herring @ 2019-07-10 15:49 UTC (permalink / raw)
  To: Andrew Jeffery
  Cc: linux-mmc, Ulf Hansson, Mark Rutland, Joel Stanley, Adrian Hunter,
	devicetree,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	linux-aspeed, linux-kernel@vger.kernel.org, ryanchen.aspeed
In-Reply-To: <20190710141611.21159-2-andrew@aj.id.au>

On Wed, Jul 10, 2019 at 8:16 AM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the
> SDIO Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit
> data bus if only a single slot is enabled.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> ---
>  .../bindings/mmc/sdhci-of-aspeed.yaml         | 91 +++++++++++++++++++

aspeed,sdhci.yaml

>  1 file changed, 91 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml
>
> diff --git a/Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml b/Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml
> new file mode 100644
> index 000000000000..e98a2ac4d46d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml
> @@ -0,0 +1,91 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later

The preferred license is (GPL-2.0 OR BSD-2-Clause) if that is okay with you.

> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mmc/sdhci-of-aspeed.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ASPEED SD/SDIO/eMMC Controller
> +
> +maintainers:
> +  - Andrew Jeffery <andrew@aj.id.au>
> +  - Ryan Chen <ryanchen.aspeed@gmail.com>
> +
> +description: |+
> +  The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the SDIO
> +  Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if
> +  only a single slot is enabled.
> +
> +  The two slots are supported by a common configuration area. As the SDHCIs for
> +  the slots are dependent on the common configuration area, they are described
> +  as child nodes.
> +
> +properties:
> +  compatible:
> +    enum: [ aspeed,ast2400-sdc, aspeed,ast2500-sdc ]
> +  reg:
> +    description: Common configuration registers

This should have a 'maxItems: 1'. Same for the child reg.

> +  ranges: true
> +  clocks:
> +    maxItems: 1
> +    description: The SD/SDIO controller clock gate
> +  sdhci:

This needs to be a pattern (under patternProperties) as these have
unit-addresses.

> +    type: object
> +    properties:
> +      compatible:
> +        allOf:
> +          - enum: [ aspeed,ast2400-sdhci, aspeed,ast2500-sdhci ]
> +          - const: sdhci

This condition can never be true. What you need is s/allOf/items/.
However, 'sdhci' is not really a useful compatible because every
implementation has quirks, so I'd drop it.

> +      reg:
> +        description: The SDHCI registers
> +      clocks:
> +        maxItems: 1
> +        description: The SD bus clock
> +      slot:
> +        allOf:
> +          - $ref: /schemas/types.yaml#/definitions/uint32
> +          - enum: [0, 1]

Is this really needed? Offset 0x100 is slot 0 and offset 0x200 is slot
1. Does that ever change?

> +      interrupts:
> +        maxItems: 1
> +        description: The SD interrupt shared between both slots
> +    required:
> +      - compatible
> +      - reg
> +      - clocks
> +      - slot
> +      - interrupts
> +
> +required:
> +  - compatible
> +  - reg
> +  - ranges
> +  - clocks

#address-cells and #size-cells are required too.

You should also add 'additionalProperties: false' here so other random
properties can't be present.

> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/aspeed-clock.h>
> +    sdc@1e740000 {
> +            compatible = "aspeed,ast2500-sdc";
> +            reg = <0x1e740000 0x100>;
> +            #address-cells = <1>;
> +            #size-cells = <1>;
> +            ranges;

It's preferred to limit the range here and then the child addresses
are 0x100 and 0x200.

> +            clocks = <&syscon ASPEED_CLK_GATE_SDCLK>;
> +
> +            sdhci0: sdhci@1e740100 {
> +                    compatible = "aspeed,ast2500-sdhci", "sdhci";
> +                    reg = <0x1e740100 0x100>;
> +                    slot = <0>;
> +                    interrupts = <26>;
> +                    sdhci,auto-cmd12;
> +                    clocks = <&syscon ASPEED_CLK_SDIO>;
> +            };
> +
> +            sdhci1: sdhci@1e740200 {
> +                    compatible = "aspeed,ast2500-sdhci", "sdhci";
> +                    reg = <0x1e740200 0x100>;
> +                    slot = <1>;
> +                    interrupts = <26>;
> +                    sdhci,auto-cmd12;
> +                    clocks = <&syscon ASPEED_CLK_SDIO>;
> +            };
> +    };
> --
> 2.20.1
>

^ permalink raw reply

* Applied "spi: dt-bindings: spi-controller: remove unnecessary 'maxItems: 1' from reg" to the spi tree
From: Mark Brown @ 2019-07-10 15:34 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, linux-kernel, linux-spi, Mark Brown, Maxime Ripard
In-Reply-To: <20190709192631.16394-1-robh@kernel.org>

The patch

   spi: dt-bindings: spi-controller: remove unnecessary 'maxItems: 1' from reg

has been applied to the spi tree at

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-5.3

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 43167bb1f6bb7efa73adc40d2dd700bb6546cc2c Mon Sep 17 00:00:00 2001
From: Rob Herring <robh@kernel.org>
Date: Tue, 9 Jul 2019 13:26:31 -0600
Subject: [PATCH] spi: dt-bindings: spi-controller: remove unnecessary
 'maxItems: 1' from reg

Mixing array constraints like 'maxItems' and string or integer value
constraints like 'minimum' don't make sense. Also, with only value
constraints, it is implied we have a single value. So lets remove
'maxItems: 1'.

Cc: Mark Brown <broonie@kernel.org>
Cc: linux-spi@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20190709192631.16394-1-robh@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/devicetree/bindings/spi/spi-controller.yaml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml
index 876c0623f322..a02e2fe2bfb2 100644
--- a/Documentation/devicetree/bindings/spi/spi-controller.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml
@@ -73,7 +73,6 @@ patternProperties:
           Compatible of the SPI device.
 
       reg:
-        maxItems: 1
         minimum: 0
         maximum: 256
         description:
-- 
2.20.1

^ permalink raw reply related

* Re: [PATCH V13 08/12] dt-bindings: Add PCIe supports-clkreq property
From: Lorenzo Pieralisi @ 2019-07-10 15:28 UTC (permalink / raw)
  To: Vidya Sagar
  Cc: bhelgaas, robh+dt, mark.rutland, thierry.reding, jonathanh,
	kishon, catalin.marinas, will.deacon, jingoohan1,
	gustavo.pimentel, digetx, mperttunen, linux-pci, devicetree,
	linux-tegra, linux-kernel, linux-arm-kernel, kthota, mmaddireddy,
	sagar.tv
In-Reply-To: <20190710062212.1745-9-vidyas@nvidia.com>

On Wed, Jul 10, 2019 at 11:52:08AM +0530, Vidya Sagar wrote:
> Some host controllers need to know the existence of clkreq signal routing to
> downstream devices to be able to advertise low power features like ASPM L1
> substates. Without clkreq signal routing being present, enabling ASPM L1 sub
> states might lead to downstream devices falling off the bus. Hence a new device

You mean "being disconnected from the bus" right ? I will update it.

Lorenzo

> tree property 'supports-clkreq' is added to make such host controllers
> aware of clkreq signal routing to downstream devices.
> 
> Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Reviewed-by: Thierry Reding <treding@nvidia.com>
> ---
> V13:
> * None
> 
> V12:
> * Rebased on top of linux-next top of the tree
> 
> V11:
> * None
> 
> V10:
> * None
> 
> V9:
> * None
> 
> V8:
> * None
> 
> V7:
> * None
> 
> V6:
> * s/Documentation\/devicetree/dt-bindings/ in the subject
> 
> V5:
> * None
> 
> V4:
> * Rebased on top of linux-next top of the tree
> 
> V3:
> * None
> 
> V2:
> * This is a new patch in v2 series
> 
>  Documentation/devicetree/bindings/pci/pci.txt | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
> index 2a5d91024059..29bcbd88f457 100644
> --- a/Documentation/devicetree/bindings/pci/pci.txt
> +++ b/Documentation/devicetree/bindings/pci/pci.txt
> @@ -27,6 +27,11 @@ driver implementation may support the following properties:
>  - reset-gpios:
>     If present this property specifies PERST# GPIO. Host drivers can parse the
>     GPIO and apply fundamental reset to endpoints.
> +- supports-clkreq:
> +   If present this property specifies that CLKREQ signal routing exists from
> +   root port to downstream device and host bridge drivers can do programming
> +   which depends on CLKREQ signal existence. For example, programming root port
> +   not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal.
>  
>  PCI-PCI Bridge properties
>  -------------------------
> -- 
> 2.17.1
> 

^ permalink raw reply

* Re: [PATCH v8 07/21] iommu/io-pgtable-arm-v7s: Extend MediaTek 4GB Mode
From: Will Deacon @ 2019-07-10 14:36 UTC (permalink / raw)
  To: Yong Wu
  Cc: Joerg Roedel, Matthias Brugger, Robin Murphy, Rob Herring,
	Evan Green, Tomasz Figa, Will Deacon, linux-mediatek,
	srv_heupstream, devicetree, linux-kernel, linux-arm-kernel, iommu,
	yingjoe.chen, youlin.pei, Nicolas Boichat, anan.sun,
	Matthias Kaehlcke
In-Reply-To: <1561774167-24141-8-git-send-email-yong.wu@mediatek.com>

On Sat, Jun 29, 2019 at 10:09:13AM +0800, Yong Wu wrote:
> MediaTek extend the arm v7s descriptor to support the dram over 4GB.
> 
> In the mt2712 and mt8173, it's called "4GB mode", the physical address
> is from 0x4000_0000 to 0x1_3fff_ffff, but from EMI point of view, it
> is remapped to high address from 0x1_0000_0000 to 0x1_ffff_ffff, the
> bit32 is always enabled. thus, in the M4U, we always enable the bit9
> for all PTEs which means to enable bit32 of physical address.
> 
> but in mt8183, M4U support the dram from 0x4000_0000 to 0x3_ffff_ffff
> which isn't remaped. We extend the PTEs: the bit9 represent bit32 of
> PA and the bit4 represent bit33 of PA. Meanwhile the iova still is
> 32bits.

What happens if bit4 is set in the pte for mt2712 or mt8173? Perhaps the
io-pgtable backend should be allowing oas > 32 when
IO_PGTABLE_QUIRK_ARM_MTK_4GB is set, and then enforcing that itself.

> In order to unify code, in the "4GB mode", we add the bit32 for the
> physical address manually in our driver.
> 
> Correspondingly, Adding bit32 and bit33 for the PA in the iova_to_phys
> has to been moved into v7s.
> 
> Regarding whether the pagetable address could be over 4GB, the mt8183
> support it while the previous mt8173 don't. thus keep it as is.
> 
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Reviewed-by: Evan Green <evgreen@chromium.org>
> ---
> Comparing with the previous one:
> 1). Add a new patch "iommu/mediatek: Fix iova_to_phys PA start for 4GB
> mode" before this one. Thus rebase it.
> A little difference: in the 4gb mode, we add bit32 for PA. and the PA got
> from iova_to_phys always have bit32 here, thus we should adjust it to locate
> the valid pa.
> 2). Add this code suggested from Evan.
>  if (!data->plat_data->has_4gb_mode)
> 	       data->enable_4GB = false;
> ---
>  drivers/iommu/io-pgtable-arm-v7s.c | 31 ++++++++++++++++++++++++-------
>  drivers/iommu/mtk_iommu.c          | 29 ++++++++++++++++++-----------
>  drivers/iommu/mtk_iommu.h          |  1 +
>  3 files changed, 43 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c
> index 94c38db..4077822 100644
> --- a/drivers/iommu/io-pgtable-arm-v7s.c
> +++ b/drivers/iommu/io-pgtable-arm-v7s.c
> @@ -123,7 +123,9 @@
>  #define ARM_V7S_TEX_MASK		0x7
>  #define ARM_V7S_ATTR_TEX(val)		(((val) & ARM_V7S_TEX_MASK) << ARM_V7S_TEX_SHIFT)
>  
> -#define ARM_V7S_ATTR_MTK_4GB		BIT(9) /* MTK extend it for 4GB mode */
> +/* MediaTek extend the two bits below for over 4GB mode */
> +#define ARM_V7S_ATTR_MTK_PA_BIT32	BIT(9)
> +#define ARM_V7S_ATTR_MTK_PA_BIT33	BIT(4)
>  
>  /* *well, except for TEX on level 2 large pages, of course :( */
>  #define ARM_V7S_CONT_PAGE_TEX_SHIFT	6
> @@ -190,13 +192,22 @@ static dma_addr_t __arm_v7s_dma_addr(void *pages)
>  static arm_v7s_iopte paddr_to_iopte(phys_addr_t paddr, int lvl,
>  				    struct io_pgtable_cfg *cfg)
>  {
> -	return paddr & ARM_V7S_LVL_MASK(lvl);
> +	arm_v7s_iopte pte = paddr & ARM_V7S_LVL_MASK(lvl);
> +
> +	if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) {
> +		if (paddr & BIT_ULL(32))
> +			pte |= ARM_V7S_ATTR_MTK_PA_BIT32;
> +		if (paddr & BIT_ULL(33))
> +			pte |= ARM_V7S_ATTR_MTK_PA_BIT33;
> +	}
> +	return pte;
>  }
>  
>  static phys_addr_t iopte_to_paddr(arm_v7s_iopte pte, int lvl,
>  				  struct io_pgtable_cfg *cfg)
>  {
>  	arm_v7s_iopte mask;
> +	phys_addr_t paddr;
>  
>  	if (ARM_V7S_PTE_IS_TABLE(pte, lvl))
>  		mask = ARM_V7S_TABLE_MASK;
> @@ -205,7 +216,14 @@ static phys_addr_t iopte_to_paddr(arm_v7s_iopte pte, int lvl,
>  	else
>  		mask = ARM_V7S_LVL_MASK(lvl);
>  
> -	return pte & mask;
> +	paddr = pte & mask;
> +	if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB) {
> +		if (pte & ARM_V7S_ATTR_MTK_PA_BIT32)
> +			paddr |= BIT_ULL(32);
> +		if (pte & ARM_V7S_ATTR_MTK_PA_BIT33)
> +			paddr |= BIT_ULL(33);
> +	}
> +	return paddr;

I think this relies on CONFIG_PHYS_ADDR_T_64BIT, which isn't always set on
32-bit ARM.

Will

^ permalink raw reply

* RE: [v4 2/6] media: platform: dwc: Add MIPI CSI-2 controller driver
From: Luis de Oliveira @ 2019-07-10 14:21 UTC (permalink / raw)
  To: Eugen.Hristev@microchip.com, Luis.Oliveira@synopsys.com,
	mchehab@kernel.org, davem@davemloft.net,
	gregkh@linuxfoundation.org, Jonathan.Cameron@huawei.com,
	robh@kernel.org, Nicolas.Ferre@microchip.com,
	paulmck@linux.ibm.com, mark.rutland@arm.com, kishon@ti.com,
	devicetree@vger.kernel.org, linux-media@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Joao.Pinto@synopsys.com
In-Reply-To: <95b85099-aff1-8b4d-44ef-549f9a1a9d9c@microchip.com>

Hi Eugen,

My answers,

From: Eugen.Hristev@microchip.com <Eugen.Hristev@microchip.com>
Date: Wed, Jul 10, 2019 at 09:59:13

> Hello Luis,
> 
> A few questions inline:
> 
> On 11.06.2019 22:20, Luis Oliveira wrote:
> > Add the Synopsys MIPI CSI-2 controller driver. This
> > controller driver is divided in platform functions and core functions.
> > This way it serves as platform for future DesignWare drivers.
> > 
> > Signed-off-by: Luis Oliveira <luis.oliveira@synopsys.com>
> > ---
> > Changelog
> > v3-v4
> > - fix v4l2_fwnode_endpoint bad initialization @eugen
> > - removed extra lines and fixed coding style issues
> > 
> >   MAINTAINERS                               |   8 +
> >   drivers/media/platform/Kconfig            |   1 +
> >   drivers/media/platform/Makefile           |   2 +
> >   drivers/media/platform/dwc/Kconfig        |  19 +
> >   drivers/media/platform/dwc/Makefile       |   9 +
> >   drivers/media/platform/dwc/dw-csi-plat.c  | 475 +++++++++++++++++++++++
> >   drivers/media/platform/dwc/dw-csi-plat.h  |  97 +++++
> >   drivers/media/platform/dwc/dw-csi-sysfs.c | 624 ++++++++++++++++++++++++++++++
> >   drivers/media/platform/dwc/dw-mipi-csi.c  | 569 +++++++++++++++++++++++++++
> >   drivers/media/platform/dwc/dw-mipi-csi.h  | 287 ++++++++++++++
> >   include/media/dwc/dw-mipi-csi-pltfrm.h    | 104 +++++
> >   11 files changed, 2195 insertions(+)
> >   create mode 100644 drivers/media/platform/dwc/Kconfig
> >   create mode 100644 drivers/media/platform/dwc/Makefile
> >   create mode 100644 drivers/media/platform/dwc/dw-csi-plat.c
> >   create mode 100644 drivers/media/platform/dwc/dw-csi-plat.h
> >   create mode 100644 drivers/media/platform/dwc/dw-csi-sysfs.c
> >   create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.c
> >   create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.h
> >   create mode 100644 include/media/dwc/dw-mipi-csi-pltfrm.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 16a97ba..6ffe4fd 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -15187,6 +15187,14 @@ S:	Maintained
> >   F:	drivers/dma/dwi-axi-dmac/
> >   F:	Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt
> >   
> > +SYNOPSYS DESIGNWARE MIPI DPHY CSI-2 HOST DRIVER
> > +M:	Luis Oliveira <luis.oliveira@synopsys.com>
> > +L:	linux-media@vger.kernel.org
> > +T:	git git://linuxtv.org/media_tree.git
> > +S:	Maintained
> > +F:	drivers/media/platform/dwc
> > +F:	Documentation/devicetree/bindings/media/snps,dw-csi.txt
> > +
> >   SYNOPSYS DESIGNWARE DMAC DRIVER
> >   M:	Viresh Kumar <vireshk@kernel.org>
> >   R:	Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> > index 8a19654..b6fb139 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -147,6 +147,7 @@ source "drivers/media/platform/xilinx/Kconfig"
> >   source "drivers/media/platform/rcar-vin/Kconfig"
> >   source "drivers/media/platform/atmel/Kconfig"
> >   source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
> > +source "drivers/media/platform/dwc/Kconfig"
> >   
> >   config VIDEO_TI_CAL
> >   	tristate "TI CAL (Camera Adaptation Layer) driver"
> > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > index 7cbbd92..4807caf 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -101,3 +101,5 @@ obj-y					+= meson/
> >   obj-y					+= cros-ec-cec/
> >   
> >   obj-$(CONFIG_VIDEO_SUN6I_CSI)		+= sunxi/sun6i-csi/
> > +
> > +obj-y					+= dwc/
> > diff --git a/drivers/media/platform/dwc/Kconfig b/drivers/media/platform/dwc/Kconfig
> > new file mode 100644
> > index 0000000..508ac21
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/Kconfig
> > @@ -0,0 +1,19 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +#  Synopsys DWC Platform drivers
> > +#	Drivers here are currently for MIPI CSI-2 support
> > +
> > +config DWC_MIPI_CSI2_HOST
> > +	tristate "Synopsys DesignWare CSI-2 Host Controller support"
> > +	select VIDEO_DEV
> > +	select VIDEO_V4L2
> > +	select VIDEO_V4L2_SUBDEV_API
> > +	select V4L2_FWNODE
> > +	help
> > +	  This selects the DesignWare MIPI CSI-2 host controller support. This
> > +	  controller gives access to control a CSI-2 receiver acting as a V4L2
> > +	  subdevice.
> > +
> > +	  If you have a controller with this interface, say Y.
> > +
> > +	   If unsure, say N.
> > diff --git a/drivers/media/platform/dwc/Makefile b/drivers/media/platform/dwc/Makefile
> > new file mode 100644
> > index 0000000..057f137
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/Makefile
> > @@ -0,0 +1,9 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Makefile for Synopsys DWC Platform drivers
> > +#
> > +dw-csi-objs := dw-csi-plat.o dw-mipi-csi.o
> > +ifeq ($(CONFIG_DWC_MIPI_TC_DPHY_GEN3),y)
> > +	dw-csi-objs += dw-csi-sysfs.o
> > +endif
> > +obj-$(CONFIG_DWC_MIPI_CSI2_HOST) += dw-csi.o
> > diff --git a/drivers/media/platform/dwc/dw-csi-plat.c b/drivers/media/platform/dwc/dw-csi-plat.c
> > new file mode 100644
> > index 0000000..9828d55
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/dw-csi-plat.c
> > @@ -0,0 +1,475 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
> > + *
> > + * Synopsys DesignWare MIPI CSI-2 Host controller driver.
> > + * Platform driver
> > + *
> > + * Author: Luis Oliveira <luis.oliveira@synopsys.com>
> > + */
> > +
> > +#include <media/dwc/dw-dphy-data.h>
> > +
> > +#include "dw-csi-plat.h"
> > +
> > +const struct mipi_dt csi_dt[] = {
> > +	{
> > +		.hex = CSI_2_YUV420_8,
> > +		.name = "YUV420_8bits",
> > +	}, {
> > +		.hex = CSI_2_YUV420_10,
> > +		.name = "YUV420_10bits",
> > +	}, {
> > +		.hex = CSI_2_YUV420_8_LEG,
> > +		.name = "YUV420_8bits_LEGACY",
> > +	}, {
> > +		.hex = CSI_2_YUV420_8_SHIFT,
> > +		.name = "YUV420_8bits_SHIFT",
> > +	}, {
> > +		.hex = CSI_2_YUV420_10_SHIFT,
> > +		.name = "YUV420_10bits_SHIFT",
> > +	}, {
> > +		.hex = CSI_2_YUV422_8,
> > +		.name = "YUV442_8bits",
> > +	}, {
> > +		.hex = CSI_2_YUV422_10,
> > +		.name = "YUV442_10bits",
> > +	}, {
> > +		.hex = CSI_2_RGB444,
> > +		.name = "RGB444",
> > +	}, {
> > +		.hex = CSI_2_RGB555,
> > +		.name = "RGB555",
> > +	}, {
> > +		.hex = CSI_2_RGB565,
> > +		.name = "RGB565",
> > +	}, {
> > +		.hex = CSI_2_RGB666,
> > +		.name = "RGB666",
> > +	}, {
> > +		.hex = CSI_2_RGB888,
> > +		.name = "RGB888",
> > +	}, {
> > +		.hex = CSI_2_RAW6,
> > +		.name = "RAW6",
> > +	}, {
> > +		.hex = CSI_2_RAW7,
> > +		.name = "RAW7",
> > +	}, {
> > +		.hex = CSI_2_RAW8,
> > +		.name = "RAW8",
> > +	}, {
> > +		.hex = CSI_2_RAW10,
> > +		.name = "RAW10",
> > +	}, {
> > +		.hex = CSI_2_RAW12,
> > +		.name = "RAW12",
> > +	}, {
> > +		.hex = CSI_2_RAW14,
> > +		.name = "RAW14",
> > +	}, {
> > +		.hex = CSI_2_RAW16,
> > +		.name = "RAW16",
> > +	},
> > +};
> > +
> > +static struct mipi_fmt *
> > +find_dw_mipi_csi_format(struct v4l2_mbus_framefmt *mf)
> > +{
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(dw_mipi_csi_formats); i++)
> > +		if (mf->code == dw_mipi_csi_formats[i].mbus_code)
> > +			return &dw_mipi_csi_formats[i];
> > +
> > +	return NULL;
> > +}
> > +
> > +static int dw_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd,
> > +				      struct v4l2_subdev_pad_config *cfg,
> > +				      struct v4l2_subdev_mbus_code_enum *code)
> > +{
> > +	if (code->index >= ARRAY_SIZE(dw_mipi_csi_formats))
> > +		return -EINVAL;
> > +
> > +	if (code->index != 0)
> > +		return -EINVAL;
> 
> What is the purpose of checking if index >= array_size, if any value 
> different from 0 will return an error anyway ?
> 

You are right, I added this !=0 later and forgot to remove the >= 
array_size. 


> > +
> > +	code->code = dw_mipi_csi_formats[code->index].mbus_code;
> > +	return 0;
> > +}
> > +
> > +static struct mipi_fmt *
> > +dw_mipi_csi_try_format(struct v4l2_mbus_framefmt *mf)
> > +{
> > +	struct mipi_fmt *fmt;
> > +
> > +	fmt = find_dw_mipi_csi_format(mf);
> > +	if (!fmt)
> > +		fmt = &dw_mipi_csi_formats[0];
> > +
> > +	mf->code = fmt->mbus_code;
> > +
> > +	return fmt;
> > +}
> > +
> > +static struct v4l2_mbus_framefmt *
> > +dw_mipi_csi_get_format(struct dw_csi *dev, struct v4l2_subdev_pad_config *cfg,
> > +		       enum v4l2_subdev_format_whence which)
> > +{
> > +	if (which == V4L2_SUBDEV_FORMAT_TRY)
> > +		return cfg ? v4l2_subdev_get_try_format(&dev->sd,
> > +							cfg,
> > +							0) : NULL;
> > +	dev_dbg(dev->dev,
> > +		"%s got v4l2_mbus_pixelcode. 0x%x\n", __func__,
> > +		dev->format.code);
> > +	dev_dbg(dev->dev,
> > +		"%s got width. 0x%x\n", __func__,
> > +		dev->format.width);
> > +	dev_dbg(dev->dev,
> > +		"%s got height. 0x%x\n", __func__,
> > +		dev->format.height);
> > +	return &dev->format;
> > +}
> > +
> > +static int
> > +dw_mipi_csi_set_fmt(struct v4l2_subdev *sd,
> > +		    struct v4l2_subdev_pad_config *cfg,
> > +		    struct v4l2_subdev_format *fmt)
> > +{
> > +	struct dw_csi *dev = sd_to_mipi_csi_dev(sd);
> > +	struct mipi_fmt *dev_fmt;
> > +	struct v4l2_mbus_framefmt *mf = dw_mipi_csi_get_format(dev, cfg,
> > +							       fmt->which);
> > +	int i;
> > +
> > +	dev_fmt = dw_mipi_csi_try_format(&fmt->format);
> > +
> > +	if (dev_fmt) {
> > +		*mf = fmt->format;
> > +		if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> > +			dev->fmt = dev_fmt;
> > +		dev->fmt->mbus_code = mf->code;
> > +		dw_mipi_csi_set_ipi_fmt(dev);
> > +	}
> > +
> > +	if (fmt->format.width > 0 && fmt->format.height > 0) {
> > +		dw_mipi_csi_fill_timings(dev, fmt);
> > +	} else {
> > +		dev_vdbg(dev->dev, "%s unacceptable values 0x%x.\n",
> > +			 __func__, fmt->format.width);
> > +		dev_vdbg(dev->dev, "%s unacceptable values 0x%x.\n",
> > +			 __func__, fmt->format.height);
> > +		return -EINVAL;
> > +	}
> > +
> > +	for (i = 0; i < ARRAY_SIZE(csi_dt); i++)
> > +		if (csi_dt[i].hex == dev->ipi_dt) {
> > +			dev_vdbg(dev->dev, "Using data type %s\n",
> > +				 csi_dt[i].name);
> > +		}
> > +	return 0;
> > +}
> > +
> > +static int
> > +dw_mipi_csi_get_fmt(struct v4l2_subdev *sd,
> > +		    struct v4l2_subdev_pad_config *cfg,
> > +		    struct v4l2_subdev_format *fmt)
> > +{
> > +	struct dw_csi *dev = sd_to_mipi_csi_dev(sd);
> > +	struct v4l2_mbus_framefmt *mf;
> > +
> > +	mf = dw_mipi_csi_get_format(dev, cfg, fmt->which);
> > +	if (!mf)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&dev->lock);
> > +	fmt->format = *mf;
> > +	mutex_unlock(&dev->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +dw_mipi_csi_s_power(struct v4l2_subdev *sd, int on)
> > +{
> > +	struct dw_csi *dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	dev_vdbg(dev->dev, "%s: on=%d\n", __func__, on);
> > +
> > +	if (on) {
> > +		dw_mipi_csi_hw_stdby(dev);
> > +		dw_mipi_csi_start(dev);
> > +	} else {
> > +		phy_power_off(dev->phy);
> > +		dw_mipi_csi_mask_irq_power_off(dev);
> > +		/* reset data type */
> > +		dev->ipi_dt = 0x0;
> > +	}
> > +	return 0;
> > +}
> > +
> > +static int
> > +dw_mipi_csi_log_status(struct v4l2_subdev *sd)
> > +{
> > +	struct dw_csi *dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	dw_mipi_csi_dump(dev);
> > +
> > +	return 0;
> > +}
> > +
> > +#if IS_ENABLED(CONFIG_VIDEO_ADV_DEBUG)
> > +static int
> > +dw_mipi_csi_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
> > +{
> > +	struct dw_csi *dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	dev_vdbg(dev->dev, "%s: reg=%llu\n", __func__, reg->reg);
> > +	reg->val = dw_mipi_csi_read(dev, reg->reg);
> > +
> > +	return 0;
> > +}
> > +#endif
> > +static int dw_mipi_csi_init_cfg(struct v4l2_subdev *sd,
> > +				struct v4l2_subdev_pad_config *cfg)
> > +{
> > +	struct v4l2_mbus_framefmt *format =
> > +	    v4l2_subdev_get_try_format(sd, cfg, 0);
> > +
> > +	format->colorspace = V4L2_COLORSPACE_SRGB;
> > +	format->code = MEDIA_BUS_FMT_RGB888_1X24;
> > +	format->field = V4L2_FIELD_NONE;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct v4l2_subdev_core_ops dw_mipi_csi_core_ops = {
> > +	.s_power = dw_mipi_csi_s_power,
> > +	.log_status = dw_mipi_csi_log_status,
> > +#if IS_ENABLED(CONFIG_VIDEO_ADV_DEBUG)
> > +	.g_register = dw_mipi_csi_g_register,
> > +#endif
> > +};
> > +
> > +static struct v4l2_subdev_pad_ops dw_mipi_csi_pad_ops = {
> > +	.init_cfg = dw_mipi_csi_init_cfg,
> > +	.enum_mbus_code = dw_mipi_csi_enum_mbus_code,
> > +	.get_fmt = dw_mipi_csi_get_fmt,
> > +	.set_fmt = dw_mipi_csi_set_fmt,
> > +};
> > +
> > +static struct v4l2_subdev_ops dw_mipi_csi_subdev_ops = {
> > +	.core = &dw_mipi_csi_core_ops,
> > +	.pad = &dw_mipi_csi_pad_ops,
> > +};
> > +
> > +static irqreturn_t dw_mipi_csi_irq1(int irq, void *dev_id)
> 
> This naming 'irq1' is pretty unfortunate, do you agree ?
> 
Yep, I will remove the 1. 

> > +{
> > +	struct dw_csi *csi_dev = dev_id;
> > +
> > +	dw_mipi_csi_irq_handler(csi_dev);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static int
> > +dw_mipi_csi_parse_dt(struct platform_device *pdev, struct dw_csi *dev)
> > +{
> > +	struct device_node *node = pdev->dev.of_node;
> > +	struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
> > +	int ret = 0;
> > +
> > +	if (of_property_read_u32(node, "snps,output-type",
> > +				 &dev->hw.output))
> > +		dev->hw.output = 2;
> > +
> > +	node = of_graph_get_next_endpoint(node, NULL);
> > +	if (!node) {
> > +		dev_err(&pdev->dev, "No port node at %pOF\n",
> > +			pdev->dev.of_node);
> > +		return -EINVAL;
> > +	}
> > +	/* Get port node and validate MIPI-CSI channel id. */
> > +	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &ep);
> > +	if (ret)
> > +		goto err;
> > +
> > +	dev->index = ep.base.port - 1;
> > +	if (dev->index >= CSI_MAX_ENTITIES) {
> > +		ret = -ENXIO;
> > +		goto err;
> > +	}
> > +	dev->hw.num_lanes = ep.bus.mipi_csi2.num_data_lanes;
> > +err:
> > +	of_node_put(node);
> > +	return ret;
> > +}
> > +
> > +static const struct of_device_id dw_mipi_csi_of_match[];
> > +
> > +static int dw_csi_probe(struct platform_device *pdev)
> > +{
> > +	const struct of_device_id *of_id = NULL;
> > +	struct device *dev = &pdev->dev;
> > +	struct resource *res = NULL;
> > +	struct dw_csi *csi;
> > +	struct v4l2_subdev *sd;
> > +	int ret;
> > +
> > +	dev_vdbg(dev, "Probing started\n");
> > +
> > +	/* Resource allocation */
> > +	csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
> > +	if (!csi)
> > +		return -ENOMEM;
> > +
> > +	mutex_init(&csi->lock);
> > +	spin_lock_init(&csi->slock);
> > +	csi->dev = dev;
> > +
> > +	of_id = of_match_node(dw_mipi_csi_of_match, dev->of_node);
> > +	if (!of_id)
> > +		return -EINVAL;
> > +
> > +	ret = dw_mipi_csi_parse_dt(pdev, csi);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	csi->phy = devm_of_phy_get(dev, dev->of_node, NULL);
> > +	if (IS_ERR(csi->phy)) {
> > +		dev_err(dev, "No DPHY available\n");
> > +		return PTR_ERR(csi->phy);
> > +	}
> > +	/* Registers mapping */
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!res)
> > +		return -ENXIO;
> > +
> > +	csi->base_address = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(csi->base_address)) {
> > +		dev_err(dev, "Base address not set.\n");
> > +		return PTR_ERR(csi->base_address);
> > +	}
> > +
> > +	csi->ctrl_irq_number = platform_get_irq(pdev, 0);
> > +	if (csi->ctrl_irq_number < 0) {
> > +		dev_err(dev, "irq number %d not set.\n", csi->ctrl_irq_number);
> > +		ret = csi->ctrl_irq_number;
> > +		goto end;
> > +	}
> > +
> > +	csi->rst = devm_reset_control_get_optional_shared(dev, NULL);
> > +	if (IS_ERR(csi->rst)) {
> > +		dev_err(dev, "error getting reset control %d\n", ret);
> 
> this is optional ? in case it does not exist, there is no error ?
> 

Let me see if I understand. Should I do like this?
	ret = PTR_ERR(csi->rst);
	goto error_label;

> > +		return PTR_ERR(csi->rst);
> > +	}
> > +
> > +	ret = devm_request_irq(dev, csi->ctrl_irq_number,
> > +			       dw_mipi_csi_irq1, IRQF_SHARED,
> > +			       dev_name(dev), csi);
> > +	if (ret) {
> > +		dev_err(dev, "irq csi %s failed\n", of_id->name);
> > +
> > +		goto end;
> 
> if this fails and you go to end, media entity cleanup is called, but it 
> was never initialized ? does it matter ?

I think maybe I can use another label that just returns.

> 
> > +	}
> > +
> > +	sd = &csi->sd;
> > +	v4l2_subdev_init(sd, &dw_mipi_csi_subdev_ops);
> > +	csi->sd.owner = THIS_MODULE;
> > +
> > +	snprintf(sd->name, sizeof(sd->name), "%s.%d",
> > +		 "dw-csi", csi->index);
> > +
> > +	csi->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > +	csi->fmt = &dw_mipi_csi_formats[0];
> > +	csi->format.code = dw_mipi_csi_formats[0].mbus_code;
> > +
> > +	sd->entity.function = MEDIA_ENT_F_IO_V4L;
> > +	csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> > +	csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
> > +	ret = media_entity_pads_init(&csi->sd.entity,
> > +				     CSI_PADS_NUM, csi->pads);
> > +
> > +	dev_vdbg(dev, "v4l2.name: %s\n", csi->v4l2_dev.name);
> > +
> > +	if (ret < 0) {
> > +		dev_err(dev, "media entity init failed\n");
> > +		goto end;
> > +	}
> > +
> > +	v4l2_set_subdevdata(&csi->sd, pdev);
> > +	platform_set_drvdata(pdev, &csi->sd);
> > +	dev_set_drvdata(dev, sd);
> > +
> > +	if (csi->rst)
> > +		reset_control_deassert(csi->rst);
> > +#if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3)
> > +	dw_csi_create_capabilities_sysfs(pdev);
> > +#endif
> > +	dw_mipi_csi_get_version(csi);
> > +	dw_mipi_csi_specific_mappings(csi);
> > +	dw_mipi_csi_mask_irq_power_off(csi);
> > +
> > +	dev_info(dev, "DW MIPI CSI-2 Host registered successfully HW v%u.%u\n",
> > +		 csi->hw_version_major, csi->hw_version_minor);
> > +
> > +	phy_init(csi->phy);
> > +
> > +	return 0;
> > +
> > +end:
> > +	media_entity_cleanup(&csi->sd.entity);
> > +	v4l2_device_unregister(csi->vdev.v4l2_dev);
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * @short Exit routine - Exit point of the driver
> > + * @param[in] pdev pointer to the platform device structure
> > + * @return 0 on success
> > + */
> > +static int dw_csi_remove(struct platform_device *pdev)
> > +{
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *mipi_csi = sd_to_mipi_csi_dev(sd);
> > +
> > +	dev_dbg(&pdev->dev, "Removing MIPI CSI-2 module\n");
> > +
> > +	if (mipi_csi->rst)
> > +		reset_control_assert(mipi_csi->rst);
> > +	media_entity_cleanup(&mipi_csi->sd.entity);
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * @short of_device_id structure
> > + */
> > +static const struct of_device_id dw_mipi_csi_of_match[] = {
> > +	{ .compatible = "snps,dw-csi" },
> > +	{},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, dw_mipi_csi_of_match);
> > +
> > +/**
> > + * @short Platform driver structure
> > + */
> > +static struct platform_driver dw_mipi_csi_driver = {
> > +	.remove = dw_csi_remove,
> > +	.probe = dw_csi_probe,
> > +	.driver = {
> > +		.name = "dw-csi",
> > +		.owner = THIS_MODULE,
> > +		.of_match_table = of_match_ptr(dw_mipi_csi_of_match),
> > +	},
> > +};
> > +
> > +module_platform_driver(dw_mipi_csi_driver);
> > +
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_AUTHOR("Luis Oliveira <luis.oliveira@synopsys.com>");
> > +MODULE_DESCRIPTION("Synopsys DesignWare MIPI CSI-2 Host Platform driver");
> > diff --git a/drivers/media/platform/dwc/dw-csi-plat.h b/drivers/media/platform/dwc/dw-csi-plat.h
> > new file mode 100644
> > index 0000000..e322592
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/dw-csi-plat.h
> > @@ -0,0 +1,97 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (c) 2018 Synopsys, Inc.
> > + *
> > + * Synopsys DesignWare MIPI CSI-2 Host controller driver.
> > + * Supported bus formats
> > + *
> > + * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
> > + */
> > +
> > +#ifndef _DW_CSI_PLAT_H__
> > +#define _DW_CSI_PLAT_H__
> > +
> > +#include "dw-mipi-csi.h"
> > +
> > +/* Video formats supported by the MIPI CSI-2 */
> > +struct mipi_fmt dw_mipi_csi_formats[] = {
> > +	{
> > +		/* RAW 8 */
> > +		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
> > +		.depth = 8,
> > +	}, {
> > +		/* RAW 10 */
> > +		.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
> > +		.depth = 10,
> > +	}, {
> > +		/* RAW 12 */
> > +		.mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
> > +		.depth = 12,
> > +	}, {
> > +		/* RAW 14 */
> > +		.mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14,
> > +		.depth = 14,
> > +	}, {
> > +		/* RAW 16 */
> > +		.mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16,
> > +		.depth = 16,
> > +	}, {
> > +		/* RGB 666 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB666_1X18,
> > +		.depth = 18,
> > +	}, {
> > +		/* RGB 565 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE,
> > +		.depth = 16,
> > +	}, {
> > +		/* BGR 565 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
> > +		.depth = 16,
> > +	}, {
> > +		/* RGB 555 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
> > +		.depth = 16,
> > +	}, {
> > +		/* BGR 555 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
> > +		.depth = 16,
> > +	}, {
> > +		/* RGB 444 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE,
> > +		.depth = 16,
> > +	}, {
> > +		/* RGB 444 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
> > +		.depth = 16,
> > +	}, {
> > +		/* RGB 888 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB888_2X12_LE,
> > +		.depth = 24,
> > +	}, {
> > +		/* BGR 888 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB888_2X12_BE,
> > +		.depth = 24,
> > +	}, {
> > +		/* BGR 888 */
> > +		.mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
> > +		.depth = 24,
> > +	}, {
> > +		/* YUV 422 8-bit */
> > +		.mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
> > +		.depth = 16,
> > +	}, {
> > +		/* YUV 422 10-bit */
> > +		.mbus_code = MEDIA_BUS_FMT_VYUY10_2X10,
> > +		.depth = 20,
> > +	}, {
> > +		/* YUV 420 8-bit LEGACY */
> > +		.mbus_code = MEDIA_BUS_FMT_Y8_1X8,
> > +		.depth = 8,
> > +	}, {
> > +		/* YUV 420 10-bit */
> > +		.mbus_code = MEDIA_BUS_FMT_Y10_1X10,
> > +		.depth = 10,
> > +	},
> > +};
> > +
> > +#endif	/* _DW_CSI_PLAT_H__ */
> > diff --git a/drivers/media/platform/dwc/dw-csi-sysfs.c b/drivers/media/platform/dwc/dw-csi-sysfs.c
> > new file mode 100644
> > index 0000000..e8d2bb9
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/dw-csi-sysfs.c
> > @@ -0,0 +1,624 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
> > + *
> > + * Synopsys DesignWare MIPI CSI-2 Host controller driver.
> > + * SysFS components for the platform driver
> > + *
> > + * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
> > + */
> > +
> > +#include "dw-mipi-csi.h"
> > +
> > +static ssize_t core_version_show(struct device *dev,
> > +				 struct device_attribute *attr,
> > +				 char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "v.%d.%d*\n", csi_dev->hw_version_major,
> > +		 csi_dev->hw_version_minor);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t n_lanes_store(struct device *dev, struct device_attribute *attr,
> > +			     const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long lanes;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 10, &lanes);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (lanes > 8) {
> > +		dev_err(dev, "Invalid number of lanes %lu\n", lanes);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "Lanes %lu\n", lanes);
> > +	csi_dev->hw.num_lanes = lanes;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t n_lanes_show(struct device *dev,
> > +			    struct device_attribute *attr,
> > +			    char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%d\n", csi_dev->hw.num_lanes);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t core_reset_show(struct device *dev,
> > +			       struct device_attribute *attr,
> > +			       char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	/* Reset Controller and DPHY */
> > +	phy_reset(csi_dev->phy);
> > +	dw_mipi_csi_reset(csi_dev);
> > +
> > +	snprintf(buffer, 10, "Reset\n");
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t data_type_store(struct device *dev,
> > +			       struct device_attribute *attr,
> > +			       const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long dt;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &dt);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (dt < 0x18 || dt > 0x2F) {
> 
> These aren't some top/start defines in your list ?
> 

Yes, good point.

> > +		dev_err(dev, "Invalid data type %lx\n", dt);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "Data type 0x%lx\n", dt);
> > +	csi_dev->ipi_dt = dt;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t data_type_show(struct device *dev,
> > +			      struct device_attribute *attr,
> > +			      char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->ipi_dt);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t hsa_store(struct device *dev,
> > +			 struct device_attribute *attr,
> > +			 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long hsa;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &hsa);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (hsa > 0xFFF) {
> > +		dev_err(dev, "Invalid HSA time %lx\n", hsa);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "HSA time 0x%lx\n", hsa);
> > +	csi_dev->hw.hsa = hsa;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t hsa_show(struct device *dev,
> > +			struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->hw.hsa);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t hbp_store(struct device *dev,
> > +			 struct device_attribute *attr,
> > +			 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long hbp;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &hbp);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (hbp > 0xFFF) {
> > +		dev_err(dev, "Invalid HBP time %lx\n", hbp);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "HBP time 0x%lx\n", hbp);
> > +	csi_dev->hw.hbp = hbp;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t hbp_show(struct device *dev,
> > +			struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->hw.hbp);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t hsd_store(struct device *dev,
> > +			 struct device_attribute *attr,
> > +			 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long hsd;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &hsd);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (hsd > 0xFF) {
> > +		dev_err(dev, "Invalid HSD time %lx\n", hsd);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "HSD time 0x%lx\n", hsd);
> > +	csi_dev->hw.hsd = hsd;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t hsd_show(struct device *dev,
> > +			struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->hw.hsd);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t vsa_store(struct device *dev,
> > +			 struct device_attribute *attr,
> > +			 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long vsa;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &vsa);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (vsa > 0x3FF) {
> > +		dev_err(dev, "Invalid VSA period %lx\n", vsa);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "VSA period 0x%lx\n", vsa);
> > +	csi_dev->hw.vsa = vsa;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t vsa_show(struct device *dev,
> > +			struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->hw.vsa);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t vbp_store(struct device *dev,
> > +			 struct device_attribute *attr,
> > +			 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long vbp;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &vbp);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (vbp > 0x2FF) {
> > +		dev_err(dev, "Invalid VBP period %lx\n", vbp);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "VBP period 0x%lx\n", vbp);
> > +	csi_dev->hw.vbp = vbp;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t vbp_show(struct device *dev,
> > +			struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->hw.vbp);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t vfp_store(struct device *dev,
> > +			 struct device_attribute *attr,
> > +			 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long vfp;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 16, &vfp);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (vfp > 0x3ff) {
> > +		dev_err(dev, "Invalid VFP period %lx\n", vfp);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "VFP period 0x%lx\n", vfp);
> > +	csi_dev->hw.vfp = vfp;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t vfp_show(struct device *dev,
> > +			struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%x\n", csi_dev->hw.vfp);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t virtual_channel_store(struct device *dev,
> > +				     struct device_attribute *attr,
> > +				     const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long virtual_ch;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 10, &virtual_ch);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if ((signed int)virtual_ch < 0 || (signed int)virtual_ch > 8) {
> > +		dev_err(dev, "Invalid Virtual Channel %lu\n", virtual_ch);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "Virtual Channel %lu\n", virtual_ch);
> > +	csi_dev->hw.virtual_ch = virtual_ch;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t virtual_channel_show(struct device *dev,
> > +				    struct device_attribute *attr,
> > +				    char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%d\n", csi_dev->hw.virtual_ch);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t ipi_color_mode_store(struct device *dev,
> > +				    struct device_attribute *attr,
> > +				    const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long ipi_color_mode;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 10, &ipi_color_mode);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if ((signed int)ipi_color_mode < 0 || (signed int)ipi_color_mode > 1) {
> > +		dev_err(dev,
> > +			"Wrong Color Mode %lu, (48 bits -> 0 or 16 bits -> 1\n",
> > +			ipi_color_mode);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "IPI Color mode %lu\n", ipi_color_mode);
> > +	csi_dev->hw.ipi_color_mode = ipi_color_mode;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t ipi_color_mode_show(struct device *dev,
> > +				   struct device_attribute *attr,
> > +				   char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%d\n", csi_dev->hw.ipi_color_mode);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t ipi_auto_flush_store(struct device *dev,
> > +				    struct device_attribute *attr,
> > +				    const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long ipi_auto_flush;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 10, &ipi_auto_flush);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if ((signed int)ipi_auto_flush < 0 || (signed int)ipi_auto_flush > 1) {
> > +		dev_err(dev,
> > +			"Invalid Auto Flush Mode %lu, (No -> 0 or Yes -> 1\n",
> > +			ipi_auto_flush);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "IPI Auto Flush %lu\n", ipi_auto_flush);
> > +	csi_dev->hw.ipi_auto_flush = ipi_auto_flush;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t ipi_auto_flush_show(struct device *dev,
> > +				   struct device_attribute *attr,
> > +				   char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%d\n", csi_dev->hw.ipi_auto_flush);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t ipi_timings_mode_store(struct device *dev,
> > +				      struct device_attribute *attr,
> > +				      const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long ipi_mode;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 10, &ipi_mode);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if ((signed int)ipi_mode < 0 || (signed int)ipi_mode > 1) {
> > +		dev_err(dev,
> > +			"Invalid Timing Source %lu (Camera:0|Controller:1)\n",
> > +			ipi_mode);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "IPI Color mode %lu\n", ipi_mode);
> > +	csi_dev->hw.ipi_mode = ipi_mode;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t ipi_timings_mode_show(struct device *dev,
> > +				     struct device_attribute *attr,
> > +				     char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%d\n", csi_dev->hw.ipi_mode);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static ssize_t output_type_store(struct device *dev,
> > +				 struct device_attribute *attr,
> > +				 const char *buf, size_t count)
> > +{
> > +	int ret;
> > +	unsigned long output;
> > +
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	ret = kstrtoul(buf, 10, &output);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if ((signed int)output < 0 || (signed int)output > 1) {
> > +		dev_err(dev,
> > +			"Invalid Core output %lu to be used \
> > +			(IPI-> 0 or IDI->1 or BOTH- 2\n",
> > +			output);
> > +		return count;
> > +	}
> > +
> > +	dev_info(dev, "IPI Color mode %lu\n", output);
> > +	csi_dev->hw.output = output;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t output_type_show(struct device *dev,
> > +				struct device_attribute *attr,
> > +				char *buf)
> > +{
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
> > +	struct dw_csi *csi_dev = sd_to_mipi_csi_dev(sd);
> > +
> > +	char buffer[10];
> > +
> > +	snprintf(buffer, 10, "%d\n", csi_dev->hw.output);
> > +
> > +	return strlcpy(buf, buffer, PAGE_SIZE);
> > +}
> > +
> > +static DEVICE_ATTR_RO(core_version);
> > +static DEVICE_ATTR_RO(core_reset);
> > +static DEVICE_ATTR_RW(n_lanes);
> > +static DEVICE_ATTR_RW(data_type);
> > +static DEVICE_ATTR_RW(hsa);
> > +static DEVICE_ATTR_RW(hbp);
> > +static DEVICE_ATTR_RW(hsd);
> > +static DEVICE_ATTR_RW(vsa);
> > +static DEVICE_ATTR_RW(vbp);
> > +static DEVICE_ATTR_RW(vfp);
> > +static DEVICE_ATTR_RW(virtual_channel);
> > +static DEVICE_ATTR_RW(ipi_color_mode);
> > +static DEVICE_ATTR_RW(ipi_auto_flush);
> > +static DEVICE_ATTR_RW(ipi_timings_mode);
> > +static DEVICE_ATTR_RW(output_type);
> > +
> > +int dw_csi_create_capabilities_sysfs(struct platform_device *pdev)
> > +{
> > +	device_create_file(&pdev->dev, &dev_attr_core_version);
> > +	device_create_file(&pdev->dev, &dev_attr_core_reset);
> > +	device_create_file(&pdev->dev, &dev_attr_n_lanes);
> > +	device_create_file(&pdev->dev, &dev_attr_data_type);
> > +	device_create_file(&pdev->dev, &dev_attr_hsa);
> > +	device_create_file(&pdev->dev, &dev_attr_hbp);
> > +	device_create_file(&pdev->dev, &dev_attr_hsd);
> > +	device_create_file(&pdev->dev, &dev_attr_vsa);
> > +	device_create_file(&pdev->dev, &dev_attr_vbp);
> > +	device_create_file(&pdev->dev, &dev_attr_vfp);
> > +	device_create_file(&pdev->dev, &dev_attr_virtual_channel);
> > +	device_create_file(&pdev->dev, &dev_attr_ipi_color_mode);
> > +	device_create_file(&pdev->dev, &dev_attr_ipi_auto_flush);
> > +	device_create_file(&pdev->dev, &dev_attr_ipi_timings_mode);
> > +	device_create_file(&pdev->dev, &dev_attr_output_type);
> > +
> > +	return 0;
> > +}
> > diff --git a/drivers/media/platform/dwc/dw-mipi-csi.c b/drivers/media/platform/dwc/dw-mipi-csi.c
> > new file mode 100644
> > index 0000000..d01418d
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/dw-mipi-csi.c
> > @@ -0,0 +1,569 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
> > + *
> > + * Synopsys DesignWare MIPI CSI-2 Host controller driver
> > + * Core MIPI CSI-2 functions
> > + *
> > + * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
> > + */
> > +
> > +#include "dw-mipi-csi.h"
> > +
> > +static struct R_CSI2 reg = {
> > +	.VERSION = 0x00,
> > +	.N_LANES = 0x04,
> > +	.CTRL_RESETN = 0x08,
> > +	.INTERRUPT = 0x0C,
> > +	.DATA_IDS_1 = 0x10,
> > +	.DATA_IDS_2 = 0x14,
> > +	.IPI_MODE = 0x80,
> > +	.IPI_VCID = 0x84,
> > +	.IPI_DATA_TYPE = 0x88,
> > +	.IPI_MEM_FLUSH = 0x8C,
> > +	.IPI_HSA_TIME = 0x90,
> > +	.IPI_HBP_TIME = 0x94,
> > +	.IPI_HSD_TIME = 0x98,
> > +	.IPI_HLINE_TIME = 0x9C,
> > +	.IPI_SOFTRSTN = 0xA0,
> > +	.IPI_ADV_FEATURES = 0xAC,
> > +	.IPI_VSA_LINES = 0xB0,
> > +	.IPI_VBP_LINES = 0xB4,
> > +	.IPI_VFP_LINES = 0xB8,
> > +	.IPI_VACTIVE_LINES = 0xBC,
> > +	.INT_PHY_FATAL = 0xe0,
> > +	.MASK_INT_PHY_FATAL = 0xe4,
> > +	.FORCE_INT_PHY_FATAL = 0xe8,
> > +	.INT_PKT_FATAL = 0xf0,
> > +	.MASK_INT_PKT_FATAL = 0xf4,
> > +	.FORCE_INT_PKT_FATAL = 0xf8,
> > +	.INT_PHY = 0x110,
> > +	.MASK_INT_PHY = 0x114,
> > +	.FORCE_INT_PHY = 0x118,
> > +	.INT_LINE = 0x130,
> > +	.MASK_INT_LINE = 0x134,
> > +	.FORCE_INT_LINE = 0x138,
> > +	.INT_IPI = 0x140,
> > +	.MASK_INT_IPI = 0x144,
> > +	.FORCE_INT_IPI = 0x148,
> > +};
> > +
> > +struct interrupt_type csi_int = {
> > +	.PHY_FATAL = BIT(0),
> > +	.PKT_FATAL = BIT(1),
> > +	.PHY = BIT(16),
> > +};
> > +
> > +#define dw_print(VAR) \
> > +	dev_info(csi_dev->dev, "%s: 0x%x: %X\n", "#VAR#",\
> > +	VAR, dw_mipi_csi_read(csi_dev, VAR))
> > +
> > +void dw_mipi_csi_write_part(struct dw_csi *dev, u32 address, u32 data,
> > +			    u8 shift, u8 width)
> > +{
> > +	u32 mask = (1 << width) - 1;
> > +	u32 temp = dw_mipi_csi_read(dev, address);
> > +
> > +	temp &= ~(mask << shift);
> > +	temp |= (data & mask) << shift;
> > +	dw_mipi_csi_write(dev, address, temp);
> > +}
> > +
> > +void dw_mipi_csi_reset(struct dw_csi *csi_dev)
> > +{
> > +	dw_mipi_csi_write(csi_dev, reg.CTRL_RESETN, 0);
> > +	usleep_range(100, 200);
> > +	dw_mipi_csi_write(csi_dev, reg.CTRL_RESETN, 1);
> > +}
> > +
> > +int dw_mipi_csi_mask_irq_power_off(struct dw_csi *csi_dev)
> > +{
> > +	if (csi_dev->hw_version_major == 1) {
> > +		/* set only one lane (lane 0) as active (ON) */
> > +		dw_mipi_csi_write(csi_dev, reg.N_LANES, 0);
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY_FATAL, 0);
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PKT_FATAL, 0);
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY, 0);
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_LINE, 0);
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_IPI, 0);
> > +
> > +		/* only for version 1.30 */
> > +		if (csi_dev->hw_version_minor == 30)
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MASK_INT_FRAME_FATAL, 0);
> > +
> > +		dw_mipi_csi_write(csi_dev, reg.CTRL_RESETN, 0);
> > +
> > +		/* only for version 1.40 */
> > +		if (csi_dev->hw_version_minor == 40) {
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_BNDRY_FRAME_FATAL, 0);
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_SEQ_FRAME_FATAL, 0);
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_CRC_FRAME_FATAL, 0);
> > +			dw_mipi_csi_write(csi_dev, reg.MSK_PLD_CRC_FATAL, 0);
> > +			dw_mipi_csi_write(csi_dev, reg.MSK_DATA_ID, 0);
> > +			dw_mipi_csi_write(csi_dev, reg.MSK_ECC_CORRECT, 0);
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int dw_mipi_csi_hw_stdby(struct dw_csi *csi_dev)
> > +{
> > +	if (csi_dev->hw_version_major == 1) {
> > +		/* set only one lane (lane 0) as active (ON) */
> > +		dw_mipi_csi_reset(csi_dev);
> > +		dw_mipi_csi_write(csi_dev, reg.N_LANES, 0);
> > +		phy_init(csi_dev->phy);
> > +
> > +		/* only for version 1.30 */
> > +		if (csi_dev->hw_version_minor == 30)
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MASK_INT_FRAME_FATAL,
> > +					  GENMASK(31, 0));
> > +
> > +		/* common */
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY_FATAL,
> > +				  GENMASK(8, 0));
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PKT_FATAL,
> > +				  GENMASK(1, 0));
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_PHY, GENMASK(23, 0));
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_LINE, GENMASK(23, 0));
> > +		dw_mipi_csi_write(csi_dev, reg.MASK_INT_IPI, GENMASK(5, 0));
> > +
> > +		/* only for version 1.40 */
> > +		if (csi_dev->hw_version_minor == 40) {
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_BNDRY_FRAME_FATAL,
> > +					  GENMASK(31, 0));
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_SEQ_FRAME_FATAL,
> > +					  GENMASK(31, 0));
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_CRC_FRAME_FATAL,
> > +					  GENMASK(31, 0));
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_PLD_CRC_FATAL,
> > +					  GENMASK(31, 0));
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_DATA_ID, GENMASK(31, 0));
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.MSK_ECC_CORRECT, GENMASK(31, 0));
> > +		}
> > +	}
> > +	return 0;
> > +}
> > +
> > +void dw_mipi_csi_set_ipi_fmt(struct dw_csi *csi_dev)
> > +{
> > +	struct device *dev = csi_dev->dev;
> > +
> > +	if (csi_dev->ipi_dt) {
> > +		dw_mipi_csi_write(csi_dev, reg.IPI_DATA_TYPE, csi_dev->ipi_dt);
> > +		switch (csi_dev->ipi_dt) {
> > +		case CSI_2_YUV420_8:
> > +		case CSI_2_YUV420_8_LEG:
> > +		case CSI_2_YUV420_8_SHIFT:
> > +		break;
> > +		case CSI_2_YUV420_10:
> > +		case CSI_2_YUV420_10_SHIFT:
> > +		break;
> > +		}
> 
> any reason for this switch instruction? does basically nothing.
> 

Oversight. I had prints here that were removed, now it is just silly.

> > +	} else {
> > +		switch (csi_dev->fmt->mbus_code) {
> > +		/* RGB 666 */
> > +		case MEDIA_BUS_FMT_RGB666_1X18:
> > +		csi_dev->ipi_dt =  CSI_2_RGB666;
> > +		break;
> > +		/* RGB 565 */
> > +		case MEDIA_BUS_FMT_RGB565_2X8_BE:
> > +		case MEDIA_BUS_FMT_RGB565_2X8_LE:
> > +		csi_dev->ipi_dt = CSI_2_RGB565;
> > +		break;
> > +		/* RGB 555 */
> > +		case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
> > +		case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
> > +		csi_dev->ipi_dt = CSI_2_RGB555;
> > +		break;
> > +		/* RGB 444 */
> > +		case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
> > +		case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
> > +		csi_dev->ipi_dt = CSI_2_RGB444;
> > +		break;
> > +		/* RGB 888 */
> > +		break;
> > +		case MEDIA_BUS_FMT_RGB888_2X12_LE:
> > +		case MEDIA_BUS_FMT_RGB888_2X12_BE:
> > +		csi_dev->ipi_dt = CSI_2_RGB888;
> > +		break;
> > +		/* RAW 10 */
> > +		case MEDIA_BUS_FMT_SBGGR10_1X10:
> > +		case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
> > +		csi_dev->ipi_dt = CSI_2_RAW10;
> > +		break;
> > +		/* RAW 12 */
> > +		case MEDIA_BUS_FMT_SBGGR12_1X12:
> > +		csi_dev->ipi_dt = CSI_2_RAW12;
> > +		break;
> > +		/* RAW 14 */
> > +		case MEDIA_BUS_FMT_SBGGR14_1X14:
> > +		csi_dev->ipi_dt = CSI_2_RAW14;
> > +		break;
> > +		/* RAW 16 */
> > +		case MEDIA_BUS_FMT_SBGGR16_1X16:
> > +		csi_dev->ipi_dt = CSI_2_RAW16;
> > +		break;
> > +		/* RAW 8 */
> > +		case MEDIA_BUS_FMT_SBGGR8_1X8:
> > +		csi_dev->ipi_dt = CSI_2_RAW8;
> > +		break;
> > +		/* YUV 422 8-bit */
> > +		case MEDIA_BUS_FMT_YVYU8_2X8:
> > +		csi_dev->ipi_dt = CSI_2_RAW8;
> > +		break;
> > +		/* YUV 422 10-bit */
> > +		case MEDIA_BUS_FMT_VYUY8_1X16:
> > +		csi_dev->ipi_dt = CSI_2_YUV422_8;
> > +		break;
> > +		/* YUV 420 8-bit LEGACY */
> > +		case MEDIA_BUS_FMT_Y8_1X8:
> > +		csi_dev->ipi_dt = CSI_2_RAW8;
> > +		break;
> > +		/* YUV 420 10-bit */
> > +		case MEDIA_BUS_FMT_Y10_1X10:
> > +		csi_dev->ipi_dt = CSI_2_RAW8;
> > +		break;
> > +		default:
> > +		break;
> > +		}
> > +		dw_mipi_csi_write(csi_dev, reg.IPI_DATA_TYPE, csi_dev->ipi_dt);
> > +	}
> > +	dev_info(dev, "Selected IPI Data Type 0x%X\n", csi_dev->ipi_dt);
> > +}
> > +
> > +void dw_mipi_csi_fill_timings(struct dw_csi *dev,
> > +			      struct v4l2_subdev_format *fmt)
> > +{
> > +	/* expected values */
> > +	dev->hw.virtual_ch = 0;
> > +	dev->hw.ipi_color_mode = COLOR48;
> > +	dev->hw.ipi_auto_flush = 1;
> > +	dev->hw.ipi_mode = CAMERA_TIMING;
> > +	dev->hw.ipi_cut_through = CTINACTIVE;
> > +	dev->hw.ipi_adv_features = LINE_EVENT_SELECTION(EVSELAUTO);
> > +	dev->hw.htotal = fmt->format.width + dev->hw.hsa +
> > +			 dev->hw.hbp + dev->hw.hsd;
> > +	dev->hw.vactive = fmt->format.height;
> > +	dev->hw.output = 2;
> > +
> > +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > +		dev_dbg(dev->dev, "*********** timings *********\n");
> > +		dev_dbg(dev->dev, "Horizontal Sync Active: %d\n", dev->hw.hsa);
> > +		dev_dbg(dev->dev, "Horizontal Back Porch: %d\n", dev->hw.hbp);
> > +		dev_dbg(dev->dev, "Horizontal Width: %d\n", fmt->format.width);
> > +		dev_dbg(dev->dev, "Horizontal Total: %d\n", dev->hw.htotal);
> > +		dev_dbg(dev->dev, "Vertical Sync Active: %d\n", dev->hw.vsa);
> > +		dev_dbg(dev->dev, "Vertical Back Porch: %d\n", dev->hw.vbp);
> > +		dev_dbg(dev->dev, "Vertical Front Porch: %d\n", dev->hw.vfp);
> > +		dev_dbg(dev->dev, "Vertical Active: %d\n", dev->hw.vactive);
> > +	}
> > +}
> > +
> > +void dw_mipi_csi_start(struct dw_csi *csi_dev)
> > +{
> > +	struct device *dev = csi_dev->dev;
> > +
> > +	dw_mipi_csi_write(csi_dev, reg.N_LANES, (csi_dev->hw.num_lanes - 1));
> > +	dev_info(dev, "number of lanes: %d\n", csi_dev->hw.num_lanes);
> > +
> > +	/* IPI Related Configuration */
> > +	if (csi_dev->hw.output == IPI_OUT || csi_dev->hw.output == BOTH_OUT) {
> > +		if (csi_dev->hw_version_major >= 1) {
> > +			if (csi_dev->hw_version_minor >= 20)
> > +				dw_mipi_csi_write(csi_dev,
> > +						  reg.IPI_ADV_FEATURES,
> > +						  csi_dev->hw.ipi_adv_features);
> > +			if (csi_dev->hw_version_minor >= 30)
> > +				dw_mipi_csi_write(csi_dev,
> > +						  reg.IPI_SOFTRSTN, 0x1);
> > +		}
> > +		/*  address | data, | shift | width */
> > +		dw_mipi_csi_write_part(csi_dev, reg.IPI_MODE, 1, 24, 1);
> > +		dw_mipi_csi_write_part(csi_dev,
> > +				       reg.IPI_MODE,
> > +				       csi_dev->hw.ipi_mode,
> > +				       0, 1);
> > +		if (csi_dev->hw.ipi_mode == CAMERA_TIMING) {
> > +			dw_mipi_csi_write(csi_dev,
> > +					  reg.IPI_ADV_FEATURES,
> > +					  LINE_EVENT_SELECTION(EVSELPROG) |
> > +					  EN_VIDEO |
> > +					  EN_LINE_START |
> > +					  EN_NULL |
> > +					  EN_BLANKING |
> > +					  EN_EMBEDDED);
> > +		}
> > +		dw_mipi_csi_write_part(csi_dev,
> > +				       reg.IPI_MODE,
> > +				       csi_dev->hw.ipi_color_mode,
> > +				       8, 1);
> > +		dw_mipi_csi_write_part(csi_dev,
> > +				       reg.IPI_MODE,
> > +				       csi_dev->hw.ipi_cut_through,
> > +				       16, 1);
> > +		dw_mipi_csi_write_part(csi_dev,
> > +				       reg.IPI_VCID,
> > +				       csi_dev->hw.virtual_ch,
> > +				       0, 2);
> > +		dw_mipi_csi_write_part(csi_dev,
> > +				       reg.IPI_MEM_FLUSH,
> > +				       csi_dev->hw.ipi_auto_flush,
> > +				       8, 1);
> > +
> > +		dev_vdbg(dev, "*********** config *********\n");
> > +		dev_vdbg(dev, "IPI enable: %s\n",
> > +			 csi_dev->hw.output ? "YES" : "NO");
> > +		dev_vdbg(dev, "video mode transmission type: %s timming\n",
> > +			 csi_dev->hw.ipi_mode ? "controller" : "camera");
> > +		dev_vdbg(dev, "Color Mode: %s\n",
> > +			 csi_dev->hw.ipi_color_mode ? "16 bits" : "48 bits");
> > +		dev_vdbg(dev, "Cut Through Mode: %s\n",
> > +			 csi_dev->hw.ipi_cut_through ? "enable" : "disable");
> > +		dev_vdbg(dev, "Virtual Channel: %d\n",
> > +			 csi_dev->hw.virtual_ch);
> > +		dev_vdbg(dev, "Auto-flush: %d\n",
> > +			 csi_dev->hw.ipi_auto_flush);
> > +		dw_mipi_csi_write(csi_dev, reg.IPI_SOFTRSTN, 1);
> > +
> > +		if (csi_dev->hw.ipi_mode == AUTO_TIMING)
> > +			phy_power_on(csi_dev->phy);
> > +
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_HSA_TIME, csi_dev->hw.hsa);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_HBP_TIME, csi_dev->hw.hbp);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_HSD_TIME, csi_dev->hw.hsd);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_HLINE_TIME, csi_dev->hw.htotal);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_VSA_LINES, csi_dev->hw.vsa);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_VBP_LINES, csi_dev->hw.vbp);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_VFP_LINES, csi_dev->hw.vfp);
> > +		dw_mipi_csi_write(csi_dev,
> > +				  reg.IPI_VACTIVE_LINES, csi_dev->hw.vactive);
> > +	}
> > +	phy_power_on(csi_dev->phy);
> > +}
> > +
> > +int dw_mipi_csi_irq_handler(struct dw_csi *csi_dev)
> > +{
> > +	struct device *dev = csi_dev->dev;
> > +	u32 global_int_status, i_sts;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&csi_dev->slock, flags);
> > +	global_int_status = dw_mipi_csi_read(csi_dev, reg.INTERRUPT);
> > +
> > +	if (global_int_status & csi_int.PHY_FATAL) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PHY_FATAL);
> > +		dev_err_ratelimited(dev, "int %08X: PHY FATAL: %08X\n",
> > +				    reg.INT_PHY_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.PKT_FATAL) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PKT_FATAL);
> > +		dev_err_ratelimited(dev, "int %08X: PKT FATAL: %08X\n",
> > +				    reg.INT_PKT_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.FRAME_FATAL &&
> > +	    csi_dev->hw_version_major == 1 &&
> > +	    csi_dev->hw_version_minor == 30) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_FRAME_FATAL);
> > +		dev_err_ratelimited(dev, "int %08X: FRAME FATAL: %08X\n",
> > +				    reg.INT_FRAME_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.PHY) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PHY);
> > +		dev_err_ratelimited(dev, "int %08X: PHY: %08X\n",
> > +				    reg.INT_PHY, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.PKT &&
> > +	    csi_dev->hw_version_major == 1 &&
> > +	    csi_dev->hw_version_minor <= 30) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_PKT);
> > +		dev_err_ratelimited(dev, "int %08X: PKT: %08X\n",
> > +				    reg.INT_PKT, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.LINE) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_LINE);
> > +		dev_err_ratelimited(dev, "int %08X: LINE: %08X\n",
> > +				    reg.INT_LINE, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.IPI) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.INT_IPI);
> > +		dev_err_ratelimited(dev, "int %08X: IPI: %08X\n",
> > +				    reg.INT_IPI, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.BNDRY_FRAME_FATAL) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_BNDRY_FRAME_FATAL);
> > +		dev_err_ratelimited(dev,
> > +				    "int %08X: ST_BNDRY_FRAME_FATAL: %08X\n",
> > +				    reg.ST_BNDRY_FRAME_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.SEQ_FRAME_FATAL) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_SEQ_FRAME_FATAL);
> > +		dev_err_ratelimited(dev,
> > +				    "int %08X: ST_SEQ_FRAME_FATAL: %08X\n",
> > +				    reg.ST_SEQ_FRAME_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.CRC_FRAME_FATAL) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_CRC_FRAME_FATAL);
> > +		dev_err_ratelimited(dev,
> > +				    "int %08X: ST_CRC_FRAME_FATAL: %08X\n",
> > +				    reg.ST_CRC_FRAME_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.PLD_CRC_FATAL) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_PLD_CRC_FATAL);
> > +		dev_err_ratelimited(dev,
> > +				    "int %08X: ST_PLD_CRC_FATAL: %08X\n",
> > +				    reg.ST_PLD_CRC_FATAL, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.DATA_ID) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_DATA_ID);
> > +		dev_err_ratelimited(dev, "int %08X: ST_DATA_ID: %08X\n",
> > +				    reg.ST_DATA_ID, i_sts);
> > +	}
> > +
> > +	if (global_int_status & csi_int.ECC_CORRECTED) {
> > +		i_sts = dw_mipi_csi_read(csi_dev, reg.ST_ECC_CORRECT);
> > +		dev_err_ratelimited(dev, "int %08X: ST_ECC_CORRECT: %08X\n",
> > +				    reg.ST_ECC_CORRECT, i_sts);
> > +	}
> > +
> > +	spin_unlock_irqrestore(&csi_dev->slock, flags);
> > +
> > +	return 1;
> 
> any reason for this return 1 ?
> 
> I see the code does not use this return value and it looks hardcoded.

Another oversight. I used to check the return value of this handler but I 
don’t anymore. Will be returning 0.

> 
> > +}
> > +
> > +void dw_mipi_csi_get_version(struct dw_csi *csi_dev)
> > +{
> > +	u32 hw_version;
> > +
> > +	hw_version = dw_mipi_csi_read(csi_dev, reg.VERSION);
> > +	csi_dev->hw_version_major = (u8)((hw_version >> 24) - '0');
> > +	csi_dev->hw_version_minor = (u8)((hw_version >> 16) - '0');
> > +	csi_dev->hw_version_minor = csi_dev->hw_version_minor * 10;
> > +	csi_dev->hw_version_minor += (u8)((hw_version >> 8) - '0');
> > +}
> > +
> > +int dw_mipi_csi_specific_mappings(struct dw_csi *csi_dev)
> > +{
> > +	struct device *dev = csi_dev->dev;
> > +
> > +	if (csi_dev->hw_version_major == 1) {
> > +		if (csi_dev->hw_version_minor == 30) {
> > +			/*
> > +			 * Hardware registers that were
> > +			 * exclusive to version < 1.40
> > +			 */
> > +			reg.INT_FRAME_FATAL = 0x100;
> > +			reg.MASK_INT_FRAME_FATAL = 0x104;
> > +			reg.FORCE_INT_FRAME_FATAL = 0x108;
> > +			reg.INT_PKT = 0x120;
> > +			reg.MASK_INT_PKT = 0x124;
> > +			reg.FORCE_INT_PKT = 0x128;
> > +
> > +			/* interrupt source present until this release */
> > +			csi_int.PKT = BIT(17);
> > +			csi_int.LINE = BIT(18);
> > +			csi_int.IPI = BIT(19);
> > +			csi_int.FRAME_FATAL = BIT(2);
> > +
> > +		} else if (csi_dev->hw_version_minor == 40) {
> > +			/*
> > +			 * HW registers that were added
> > +			 * to version 1.40
> > +			 */
> > +			reg.ST_BNDRY_FRAME_FATAL = 0x280;
> > +			reg.MSK_BNDRY_FRAME_FATAL = 0x284;
> > +			reg.FORCE_BNDRY_FRAME_FATAL = 0x288;
> > +			reg.ST_SEQ_FRAME_FATAL = 0x290;
> > +			reg.MSK_SEQ_FRAME_FATAL	= 0x294;
> > +			reg.FORCE_SEQ_FRAME_FATAL = 0x298;
> > +			reg.ST_CRC_FRAME_FATAL = 0x2a0;
> > +			reg.MSK_CRC_FRAME_FATAL	= 0x2a4;
> > +			reg.FORCE_CRC_FRAME_FATAL = 0x2a8;
> > +			reg.ST_PLD_CRC_FATAL = 0x2b0;
> > +			reg.MSK_PLD_CRC_FATAL = 0x2b4;
> > +			reg.FORCE_PLD_CRC_FATAL = 0x2b8;
> > +			reg.ST_DATA_ID = 0x2c0;
> > +			reg.MSK_DATA_ID = 0x2c4;
> > +			reg.FORCE_DATA_ID = 0x2c8;
> > +			reg.ST_ECC_CORRECT = 0x2d0;
> > +			reg.MSK_ECC_CORRECT = 0x2d4;
> > +			reg.FORCE_ECC_CORRECT = 0x2d8;
> > +			reg.DATA_IDS_VC_1 = 0x0;
> > +			reg.DATA_IDS_VC_2 = 0x0;
> > +			reg.VC_EXTENSION = 0x0;
> > +
> > +			/* interrupts map were changed */
> > +			csi_int.LINE = BIT(17);
> > +			csi_int.IPI = BIT(18);
> > +			csi_int.BNDRY_FRAME_FATAL = BIT(2);
> > +			csi_int.SEQ_FRAME_FATAL	= BIT(3);
> > +			csi_int.CRC_FRAME_FATAL = BIT(4);
> > +			csi_int.PLD_CRC_FATAL = BIT(5);
> > +			csi_int.DATA_ID = BIT(6);
> > +			csi_int.ECC_CORRECTED = BIT(7);
> > +
> > +		} else {
> > +			dev_info(dev, "Version minor not supported.");
> > +		}
> > +	} else {
> > +		dev_info(dev, "Version major not supported.");
> > +	}
> > +	return 0;
> 
> any reason why this function returns anything ? unused and only 0 is the 
> possible return value


No reason. Will be removed.
> 
> > +}
> > +
> > +void dw_mipi_csi_dump(struct dw_csi *csi_dev)
> > +{
> > +	dw_print(reg.VERSION);
> > +	dw_print(reg.N_LANES);
> > +	dw_print(reg.CTRL_RESETN);
> > +	dw_print(reg.INTERRUPT);
> > +	dw_print(reg.DATA_IDS_1);
> > +	dw_print(reg.DATA_IDS_2);
> > +	dw_print(reg.IPI_MODE);
> > +	dw_print(reg.IPI_VCID);
> > +	dw_print(reg.IPI_DATA_TYPE);
> > +	dw_print(reg.IPI_MEM_FLUSH);
> > +	dw_print(reg.IPI_HSA_TIME);
> > +	dw_print(reg.IPI_HBP_TIME);
> > +	dw_print(reg.IPI_HSD_TIME);
> > +	dw_print(reg.IPI_HLINE_TIME);
> > +	dw_print(reg.IPI_SOFTRSTN);
> > +	dw_print(reg.IPI_ADV_FEATURES);
> > +	dw_print(reg.IPI_VSA_LINES);
> > +	dw_print(reg.IPI_VBP_LINES);
> > +	dw_print(reg.IPI_VFP_LINES);
> > +	dw_print(reg.IPI_VACTIVE_LINES);
> > +	dw_print(reg.IPI_DATA_TYPE);
> > +	dw_print(reg.VERSION);
> > +	dw_print(reg.IPI_ADV_FEATURES);
> > +}
> > diff --git a/drivers/media/platform/dwc/dw-mipi-csi.h b/drivers/media/platform/dwc/dw-mipi-csi.h
> > new file mode 100644
> > index 0000000..6df3688
> > --- /dev/null
> > +++ b/drivers/media/platform/dwc/dw-mipi-csi.h
> > @@ -0,0 +1,287 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
> > + *
> > + * Synopsys DesignWare MIPI CSI-2 Host controller driver
> > + *
> > + * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
> > + */
> > +
> > +#ifndef _DW_MIPI_CSI_H__
> > +#define _DW_MIPI_CSI_H__
> > +
> > +#include <linux/delay.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/io.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/delay.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/of.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/ratelimit.h>
> > +#include <linux/reset.h>
> > +#include <linux/videodev2.h>
> > +#include <linux/wait.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-fwnode.h>
> > +#include <media/dwc/dw-mipi-csi-pltfrm.h>
> > +
> > +/* Advanced features */
> > +#define IPI_DT_OVERWRITE BIT(0)
> > +#define DATA_TYPE_OVERWRITE(dt) (((dt) & GENMASK(5, 0)) << 8)
> > +#define LINE_EVENT_SELECTION(n) ((n) << 16)
> > +
> > +enum line_event {
> > +	EVSELAUTO = 0,
> > +	EVSELPROG = 1,
> > +};
> > +
> > +#define EN_VIDEO BIT(17)
> > +#define EN_LINE_START BIT(18)
> > +#define EN_NULL BIT(19)
> > +#define EN_BLANKING BIT(20)
> > +#define EN_EMBEDDED BIT(21)
> > +#define IPI_SYNC_EVENT_MODE(n) ((n) << 24)
> > +
> > +enum sync_event {
> > +	SYNCEVFSN = 0,
> > +	SYNCEVFS = 1,
> > +};
> > +
> > +/* DW MIPI CSI-2 register addresses*/
> > +
> > +struct R_CSI2 {
> > +	u16 VERSION;
> > +	u16 N_LANES;
> > +	u16 CTRL_RESETN;
> > +	u16 INTERRUPT;
> > +	u16 DATA_IDS_1;
> > +	u16 DATA_IDS_2;
> > +	u16 DATA_IDS_VC_1;
> > +	u16 DATA_IDS_VC_2;
> > +	u16 IPI_MODE;
> > +	u16 IPI_VCID;
> > +	u16 IPI_DATA_TYPE;
> > +	u16 IPI_MEM_FLUSH;
> > +	u16 IPI_HSA_TIME;
> > +	u16 IPI_HBP_TIME;
> > +	u16 IPI_HSD_TIME;
> > +	u16 IPI_HLINE_TIME;
> > +	u16 IPI_SOFTRSTN;
> > +	u16 IPI_ADV_FEATURES;
> > +	u16 IPI_VSA_LINES;
> > +	u16 IPI_VBP_LINES;
> > +	u16 IPI_VFP_LINES;
> > +	u16 IPI_VACTIVE_LINES;
> > +	u16 VC_EXTENSION;
> > +	u16 INT_PHY_FATAL;
> > +	u16 MASK_INT_PHY_FATAL;
> > +	u16 FORCE_INT_PHY_FATAL;
> > +	u16 INT_PKT_FATAL;
> > +	u16 MASK_INT_PKT_FATAL;
> > +	u16 FORCE_INT_PKT_FATAL;
> > +	u16 INT_FRAME_FATAL;
> > +	u16 MASK_INT_FRAME_FATAL;
> > +	u16 FORCE_INT_FRAME_FATAL;
> > +	u16 INT_PHY;
> > +	u16 MASK_INT_PHY;
> > +	u16 FORCE_INT_PHY;
> > +	u16 INT_PKT;
> > +	u16 MASK_INT_PKT;
> > +	u16 FORCE_INT_PKT;
> > +	u16 INT_LINE;
> > +	u16 MASK_INT_LINE;
> > +	u16 FORCE_INT_LINE;
> > +	u16 INT_IPI;
> > +	u16 MASK_INT_IPI;
> > +	u16 FORCE_INT_IPI;
> > +	u16 ST_BNDRY_FRAME_FATAL;
> > +	u16 MSK_BNDRY_FRAME_FATAL;
> > +	u16 FORCE_BNDRY_FRAME_FATAL;
> > +	u16 ST_SEQ_FRAME_FATAL;
> > +	u16 MSK_SEQ_FRAME_FATAL;
> > +	u16 FORCE_SEQ_FRAME_FATAL;
> > +	u16 ST_CRC_FRAME_FATAL;
> > +	u16 MSK_CRC_FRAME_FATAL;
> > +	u16 FORCE_CRC_FRAME_FATAL;
> > +	u16 ST_PLD_CRC_FATAL;
> > +	u16 MSK_PLD_CRC_FATAL;
> > +	u16 FORCE_PLD_CRC_FATAL;
> > +	u16 ST_DATA_ID;
> > +	u16 MSK_DATA_ID;
> > +	u16 FORCE_DATA_ID;
> > +	u16 ST_ECC_CORRECT;
> > +	u16 MSK_ECC_CORRECT;
> > +	u16 FORCE_ECC_CORRECT;
> > +};
> > +
> > +/* Interrupt Masks */
> > +struct interrupt_type {
> > +	u32 PHY_FATAL;
> > +	u32 PKT_FATAL;
> > +	u32 FRAME_FATAL;
> > +	u32 PHY;
> > +	u32 PKT;
> > +	u32 LINE;
> > +	u32 IPI;
> > +	u32 BNDRY_FRAME_FATAL;
> > +	u32 SEQ_FRAME_FATAL;
> > +	u32 CRC_FRAME_FATAL;
> > +	u32 PLD_CRC_FATAL;
> > +	u32 DATA_ID;
> > +	u32 ECC_CORRECTED;
> > +};
> > +
> > +/* IPI Data Types */
> > +enum data_type {
> > +	CSI_2_YUV420_8 = 0x18,
> > +	CSI_2_YUV420_10 = 0x19,
> > +	CSI_2_YUV420_8_LEG = 0x1A,
> > +	CSI_2_YUV420_8_SHIFT = 0x1C,
> > +	CSI_2_YUV420_10_SHIFT = 0x1D,
> > +	CSI_2_YUV422_8 = 0x1E,
> > +	CSI_2_YUV422_10 = 0x1F,
> > +	CSI_2_RGB444 = 0x20,
> > +	CSI_2_RGB555 = 0x21,
> > +	CSI_2_RGB565 = 0x22,
> > +	CSI_2_RGB666 = 0x23,
> > +	CSI_2_RGB888 = 0x24,
> > +	CSI_2_RAW6 = 0x28,
> > +	CSI_2_RAW7 = 0x29,
> > +	CSI_2_RAW8 = 0x2A,
> > +	CSI_2_RAW10 = 0x2B,
> > +	CSI_2_RAW12 = 0x2C,
> > +	CSI_2_RAW14 = 0x2D,
> > +	CSI_2_RAW16 = 0x2E,
> > +	CSI_2_RAW20 = 0x2F,
> > +	USER_DEFINED_1 = 0x30,
> > +	USER_DEFINED_2 = 0x31,
> > +	USER_DEFINED_3 = 0x32,
> > +	USER_DEFINED_4 = 0x33,
> > +	USER_DEFINED_5 = 0x34,
> > +	USER_DEFINED_6 = 0x35,
> > +	USER_DEFINED_7 = 0x36,
> > +	USER_DEFINED_8 = 0x37,
> > +};
> 
> These are csi2 standard defines... would be good to have them available 
> in a more generic header to not redefine them if they are needed elsewhere ?
> 

Suggesting somewhere in ./include/media/...? Please elaborate on that.

> > +
> > +/* DWC MIPI CSI-2 output types */
> > +enum output {
> > +	IPI_OUT = 0,
> > +	IDI_OUT = 1,
> > +	BOTH_OUT = 2
> > +};
> > +
> > +/* IPI color components */
> > +enum color_mode {
> > +	COLOR48 = 0,
> > +	COLOR16 = 1
> > +};
> > +
> > +/* IPI cut through */
> > +enum cut_through {
> > +	CTINACTIVE = 0,
> > +	CTACTIVE = 1
> > +};
> > +
> > +/* IPI output types */
> > +enum ipi_output {
> > +	CAMERA_TIMING = 0,
> > +	AUTO_TIMING = 1
> > +};
> > +
> > +/* Format template */
> > +struct mipi_fmt {
> > +	u32 mbus_code;
> > +	u8 depth;
> > +};
> > +
> > +struct mipi_dt {
> > +	u32 hex;
> > +	char *name;
> > +};
> > +
> > +/* CSI specific configuration */
> > +struct csi_data {
> > +	u32 num_lanes;
> > +	u32 dphy_freq;
> > +	u32 pclk;
> > +	u32 fps;
> > +	u32 bpp;
> > +	u32 output;
> > +	u32 ipi_mode;
> > +	u32 ipi_adv_features;
> > +	u32 ipi_cut_through;
> > +	u32 ipi_color_mode;
> > +	u32 ipi_auto_flush;
> > +	u32 virtual_ch;
> > +	u32 hsa;
> > +	u32 hbp;
> > +	u32 hsd;
> > +	u32 htotal;
> > +	u32 vsa;
> > +	u32 vbp;
> > +	u32 vfp;
> > +	u32 vactive;
> > +};
> > +
> > +/* Structure to embed device driver information */
> > +struct dw_csi {
> > +	struct v4l2_subdev sd;
> > +	struct video_device vdev;
> > +	struct v4l2_device v4l2_dev;
> > +	struct device *dev;
> > +	struct media_pad pads[CSI_PADS_NUM];
> > +	struct mipi_fmt *fmt;
> > +	struct v4l2_mbus_framefmt format;
> > +	void __iomem *base_address;
> > +	void __iomem *demo;
> > +	void __iomem *csc;
> > +	int ctrl_irq_number;
> > +	int demosaic_irq;
> > +	struct csi_data hw;
> > +	struct reset_control *rst;
> > +	struct phy *phy;
> > +	struct dw_csih_pdata *config;
> > +	struct mutex lock; /* protect resources sharing */
> > +	spinlock_t slock; /* interrupt handling lock */
> > +	u8 ipi_dt;
> > +	u8 index;
> > +	u8 hw_version_major;
> > +	u16 hw_version_minor;
> > +};
> > +
> > +static inline struct dw_csi *sd_to_mipi_csi_dev(struct v4l2_subdev *sdev)
> > +{
> > +	return container_of(sdev, struct dw_csi, sd);
> > +}
> > +
> > +void dw_mipi_csi_reset(struct dw_csi *csi_dev);
> > +int dw_mipi_csi_mask_irq_power_off(struct dw_csi *csi_dev);
> > +int dw_mipi_csi_hw_stdby(struct dw_csi *csi_dev);
> > +void dw_mipi_csi_set_ipi_fmt(struct dw_csi *csi_dev);
> > +void dw_mipi_csi_start(struct dw_csi *csi_dev);
> > +int dw_mipi_csi_irq_handler(struct dw_csi *csi_dev);
> > +void dw_mipi_csi_get_version(struct dw_csi *csi_dev);
> > +int dw_mipi_csi_specific_mappings(struct dw_csi *csi_dev);
> > +void dw_mipi_csi_fill_timings(struct dw_csi *dev,
> > +			      struct v4l2_subdev_format *fmt);
> > +void dw_mipi_csi_dump(struct dw_csi *csi_dev);
> > +
> > +#if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3)
> > +int dw_csi_create_capabilities_sysfs(struct platform_device *pdev);
> > +#endif
> > +
> > +static inline void dw_mipi_csi_write(struct dw_csi *dev,
> > +				     u32 address, u32 data)
> > +{
> > +	writel(data, dev->base_address + address);
> > +}
> > +
> > +static inline u32 dw_mipi_csi_read(struct dw_csi *dev, u32 address)
> > +{
> > +	return readl(dev->base_address + address);
> > +}
> > +
> > +#endif /*_DW_MIPI_CSI_H__ */
> > diff --git a/include/media/dwc/dw-mipi-csi-pltfrm.h b/include/media/dwc/dw-mipi-csi-pltfrm.h
> > new file mode 100644
> > index 0000000..948db4e
> > --- /dev/null
> > +++ b/include/media/dwc/dw-mipi-csi-pltfrm.h
> > @@ -0,0 +1,104 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
> > + *
> > + * Synopsys DesignWare MIPI CSI-2 Host media entities
> > + *
> > + * Author: Luis Oliveira <Luis.Oliveira@synopsys.com>
> > + */
> > +
> > +#ifndef __DW_MIPI_CSI_PLTFRM_INCLUDES_H_
> > +#define __DW_MIPI_CSI_PLTFRM_INCLUDES_H_
> > +
> > +#include <media/media-entity.h>
> > +#include <media/v4l2-dev.h>
> > +#include <media/v4l2-mediabus.h>
> > +#include <media/v4l2-subdev.h>
> > +
> > +#define MAX_WIDTH	3280
> > +#define MAX_HEIGHT	1852
> > +
> > +/* The subdevices' group IDs. */
> > +#define GRP_ID_SENSOR		(10)
> > +#define GRP_ID_CSI		(20)
> > +#define GRP_ID_VIF		(30)
> > +#define GRP_ID_VIDEODEV		(40)
> > +
> > +#define CSI_MAX_ENTITIES	(2)
> > +#define VIF_MAX_ENTITIES	(2)
> > +#define PLAT_MAX_SENSORS	(2)
> > +
> > +struct pdata_names {
> > +	char *name;
> > +};
> > +
> > +enum video_dev_pads {
> > +	VIDEO_DEV_SD_PAD_SINK_VIF1,
> > +	VIDEO_DEV_SD_PAD_SINK_VIF2,
> > +	VIDEO_DEV_SD_PAD_SOURCE_DMA,
> > +	VIDEO_DEV_SD_PADS_NUM,
> > +};
> > +
> > +enum vif_pads {
> > +	VIF_PAD_SINK_CSI,
> > +	VIF_PAD_SOURCE_DMA,
> > +	VIF_PADS_NUM,
> > +};
> > +
> > +enum mipi_csi_pads {
> > +	CSI_PAD_SINK,
> > +	CSI_PAD_SOURCE,
> > +	CSI_PADS_NUM,
> > +};
> > +
> > +struct plat_csi_source_info {
> > +	u16 flags;
> > +	u16 mux_id;
> > +};
> > +
> > +struct plat_csi_fmt {
> > +	char *name;
> > +	u32 mbus_code;
> > +	u32 fourcc;
> > +	u8 depth;
> > +};
> > +
> > +struct plat_csi_media_pipeline;
> > +
> > +/*
> > + * Media pipeline operations to be called from within a video node,  i.e. the
> > + * last entity within the pipeline. Implemented by related media device driver.
> > + */
> > +struct plat_csi_media_pipeline_ops {
> > +	int (*prepare)(struct plat_csi_media_pipeline *p,
> > +		       struct media_entity *me);
> > +	int (*unprepare)(struct plat_csi_media_pipeline *p);
> > +	int (*open)(struct plat_csi_media_pipeline *p, struct media_entity *me,
> > +		    bool resume);
> > +	int (*close)(struct plat_csi_media_pipeline *p);
> > +	int (*set_stream)(struct plat_csi_media_pipeline *p, bool state);
> > +	int (*set_format)(struct plat_csi_media_pipeline *p,
> > +			  struct v4l2_subdev_format *fmt);
> > +};
> > +
> > +struct plat_csi_video_entity {
> > +	struct video_device vdev;
> > +	struct plat_csi_media_pipeline *pipe;
> > +};
> > +
> > +struct plat_csi_media_pipeline {
> > +	struct media_pipeline mp;
> > +	const struct plat_csi_media_pipeline_ops *ops;
> > +};
> > +
> > +static inline struct plat_csi_video_entity
> > +*vdev_to_plat_csi_video_entity(struct video_device *vdev)
> > +{
> > +	return container_of(vdev, struct plat_csi_video_entity, vdev);
> > +}
> > +
> > +#define plat_csi_pipeline_call(ent, op, args...)			  \
> > +	(!(ent) ? -ENOENT : (((ent)->pipe->ops && (ent)->pipe->ops->op) ? \
> > +	(ent)->pipe->ops->op(((ent)->pipe), ##args) : -ENOIOCTLCMD))	  \
> > +
> > +#endif /* __DW_MIPI_CSI_PLTFRM_INCLUDES_H_ */
> 
> Would be useful to prefix these with 'dw_' to be sure they do not step 
> over some other symbols when included ?
> > 

I will fix this also.

Thank you Eugen,
Luis



^ permalink raw reply

* Re: [PATCH V13 05/12] PCI: dwc: Add ext config space capability search API
From: Lorenzo Pieralisi @ 2019-07-10 14:19 UTC (permalink / raw)
  To: Vidya Sagar
  Cc: bhelgaas, robh+dt, mark.rutland, thierry.reding, jonathanh,
	kishon, catalin.marinas, will.deacon, jingoohan1,
	gustavo.pimentel, digetx, mperttunen, linux-pci, devicetree,
	linux-tegra, linux-kernel, linux-arm-kernel, kthota, mmaddireddy,
	sagar.tv
In-Reply-To: <fd1fc10e-47d0-aaac-158d-1c19363ec8d3@nvidia.com>

On Wed, Jul 10, 2019 at 04:57:23PM +0530, Vidya Sagar wrote:
> On 7/10/2019 4:07 PM, Lorenzo Pieralisi wrote:
> > On Wed, Jul 10, 2019 at 11:52:05AM +0530, Vidya Sagar wrote:
> > > Add extended configuration space capability search API using struct dw_pcie *
> > > pointer
> > 
> > Sentences are terminated with a period and this is v13 not v1, which
> > proves that you do not read the commit logs you write.
> > 
> > I need you guys to understand that I can't rewrite commit logs all
> > the time, I do not want to go as far as not accepting your patches
> > anymore so please do pay attention to commit log details they
> > are as important as the code itself.
> > 
> > https://lore.kernel.org/linux-pci/20171026223701.GA25649@bhelgaas-glaptop.roam.corp.google.com/
> My sincere apologies.
> Since I didn't touch this patch much all through this series, I missed it.
> I'll make a point to not make such mistakes again.
> Do you want me to send a new version fixing it?

I will update it, I just wanted to get the point across, no
problems.

Lorenzo

> Thanks,
> Vidya Sagar
> 
> > 
> > Thanks,
> > Lorenzo
> > 
> > > Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
> > > Acked-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> > > Acked-by: Thierry Reding <treding@nvidia.com>
> > > ---
> > > V13:
> > > * None
> > > 
> > > V12:
> > > * None
> > > 
> > > V11:
> > > * None
> > > 
> > > V10:
> > > * None
> > > 
> > > V9:
> > > * Added Acked-by from Thierry
> > > 
> > > V8:
> > > * Changed data types of return and arguments to be inline with data being returned
> > >    and passed.
> > > 
> > > V7:
> > > * None
> > > 
> > > V6:
> > > * None
> > > 
> > > V5:
> > > * None
> > > 
> > > V4:
> > > * None
> > > 
> > > V3:
> > > * None
> > > 
> > > V2:
> > > * This is a new patch in v2 series
> > > 
> > >   drivers/pci/controller/dwc/pcie-designware.c | 41 ++++++++++++++++++++
> > >   drivers/pci/controller/dwc/pcie-designware.h |  1 +
> > >   2 files changed, 42 insertions(+)
> > > 
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > index 7818b4febb08..181449e342f1 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > @@ -53,6 +53,47 @@ u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
> > >   }
> > >   EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
> > > +static u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
> > > +					    u8 cap)
> > > +{
> > > +	u32 header;
> > > +	int ttl;
> > > +	int pos = PCI_CFG_SPACE_SIZE;
> > > +
> > > +	/* minimum 8 bytes per capability */
> > > +	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
> > > +
> > > +	if (start)
> > > +		pos = start;
> > > +
> > > +	header = dw_pcie_readl_dbi(pci, pos);
> > > +	/*
> > > +	 * If we have no capabilities, this is indicated by cap ID,
> > > +	 * cap version and next pointer all being 0.
> > > +	 */
> > > +	if (header == 0)
> > > +		return 0;
> > > +
> > > +	while (ttl-- > 0) {
> > > +		if (PCI_EXT_CAP_ID(header) == cap && pos != start)
> > > +			return pos;
> > > +
> > > +		pos = PCI_EXT_CAP_NEXT(header);
> > > +		if (pos < PCI_CFG_SPACE_SIZE)
> > > +			break;
> > > +
> > > +		header = dw_pcie_readl_dbi(pci, pos);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
> > > +{
> > > +	return dw_pcie_find_next_ext_capability(pci, 0, cap);
> > > +}
> > > +EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
> > > +
> > >   int dw_pcie_read(void __iomem *addr, int size, u32 *val)
> > >   {
> > >   	if (!IS_ALIGNED((uintptr_t)addr, size)) {
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > > index d8c66a6827dc..11c223471416 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > > @@ -252,6 +252,7 @@ struct dw_pcie {
> > >   		container_of((endpoint), struct dw_pcie, ep)
> > >   u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap);
> > > +u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap);
> > >   int dw_pcie_read(void __iomem *addr, int size, u32 *val);
> > >   int dw_pcie_write(void __iomem *addr, int size, u32 val);
> > > -- 
> > > 2.17.1
> > > 
> 

^ permalink raw reply

* [PATCH 2/2] mmc: Add support for the ASPEED SD controller
From: Andrew Jeffery @ 2019-07-10 14:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: Andrew Jeffery, ulf.hansson, robh+dt, mark.rutland, joel,
	adrian.hunter, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, ryanchen.aspeed
In-Reply-To: <20190710141611.21159-1-andrew@aj.id.au>

Add a minimal driver for ASPEED's SD controller, which exposes two
SDHCIs.

The ASPEED design implements a common register set for the SDHCIs, and
moves some of the standard configuration elements out to this common
area (e.g. 8-bit mode, and card detect configuration which is not
currently supported).

The SD controller has a dedicated hardware interrupt that is shared
between the slots. The common register set exposes information on which
slot triggered the interrupt; early revisions of the patch introduced an
irqchip for the register, but reality is it doesn't behave as an
irqchip, and the result fits awkwardly into the irqchip APIs. Instead
I've taken the simple approach of using the IRQ as a shared IRQ with
some minor performance impact for the second slot.

Ryan was the original author of the patch - I've taken his work and
massaged it to drop the irqchip support and rework the devicetree
integration. The driver has been smoke tested under qemu against a
minimal SD controller model and lightly tested on an ast2500-evb.

Signed-off-by: Ryan Chen <ryanchen.aspeed@gmail.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
 drivers/mmc/host/Kconfig           |  12 ++
 drivers/mmc/host/Makefile          |   1 +
 drivers/mmc/host/sdhci-of-aspeed.c | 307 +++++++++++++++++++++++++++++
 3 files changed, 320 insertions(+)
 create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..2bb5e1264b3d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -154,6 +154,18 @@ config MMC_SDHCI_OF_ARASAN
 
 	  If unsure, say N.
 
+config MMC_SDHCI_OF_ASPEED
+	tristate "SDHCI OF support for the ASPEED SDHCI controller"
+	depends on MMC_SDHCI_PLTFM
+	depends on OF
+	help
+	  This selects the ASPEED Secure Digital Host Controller Interface.
+
+	  If you have a controller with this interface, say Y or M here. You
+	  also need to enable an appropriate bus interface.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_OF_AT91
 	tristate "SDHCI OF support for the Atmel SDMMC controller"
 	depends on MMC_SDHCI_PLTFM
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..390ee162fe71 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
 obj-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ARASAN)	+= sdhci-of-arasan.o
+obj-$(CONFIG_MMC_SDHCI_OF_ASPEED)	+= sdhci-of-aspeed.o
 obj-$(CONFIG_MMC_SDHCI_OF_AT91)		+= sdhci-of-at91.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
new file mode 100644
index 000000000000..23fad19787db
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2019 ASPEED Technology Inc. */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include "sdhci-pltfm.h"
+
+#define ASPEED_SDC_INFO		0x00
+#define   ASPEED_SDC_S1MMC8	BIT(25)
+#define   ASPEED_SDC_S0MMC8	BIT(24)
+
+struct aspeed_sdc {
+	struct clk *clk;
+
+	spinlock_t lock;
+	void __iomem *regs;
+};
+
+struct aspeed_sdhci {
+	struct aspeed_sdc *parent;
+	u32 width_mask;
+};
+
+static void aspeed_sdc_bus_width(struct aspeed_sdc *sdc,
+				 struct aspeed_sdhci *sdhci, bool bus8)
+{
+	u32 info;
+
+	/* Set/clear 8 bit mode */
+	spin_lock(&sdc->lock);
+	info = readl(sdc->regs + ASPEED_SDC_INFO);
+	if (bus8)
+		info |= sdhci->width_mask;
+	else
+		info &= ~sdhci->width_mask;
+	writel(info, sdc->regs + ASPEED_SDC_INFO);
+	spin_unlock(&sdc->lock);
+}
+
+static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	unsigned long timeout;
+	int div;
+	u16 clk;
+
+	if (clock == host->clock)
+		return;
+
+	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+	if (clock == 0)
+		goto out;
+
+	for (div = 1; div < 256; div *= 2) {
+		if ((host->max_clk / div) <= clock)
+			break;
+	}
+	div >>= 1;
+
+	clk = div << SDHCI_DIVIDER_SHIFT;
+	clk |= SDHCI_CLOCK_INT_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	/* Wait max 20 ms */
+	timeout = 20;
+	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+		 & SDHCI_CLOCK_INT_STABLE)) {
+		if (timeout == 0) {
+			pr_err("%s: Internal clock never stabilised.\n",
+			       mmc_hostname(host->mmc));
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+out:
+	host->clock = clock;
+}
+
+static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+	struct sdhci_pltfm_host *pltfm_priv;
+	struct aspeed_sdhci *aspeed_sdhci;
+	struct aspeed_sdc *aspeed_sdc;
+	u8 ctrl;
+
+	pltfm_priv = sdhci_priv(host);
+	aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv);
+	aspeed_sdc = aspeed_sdhci->parent;
+
+	/* Set/clear 8-bit mode */
+	aspeed_sdc_bus_width(aspeed_sdc, aspeed_sdhci,
+			     width == MMC_BUS_WIDTH_8);
+
+	/* Set/clear 1 or 4 bit mode */
+	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+	if (width == MMC_BUS_WIDTH_4)
+		ctrl |= SDHCI_CTRL_4BITBUS;
+	else
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+static const struct sdhci_ops aspeed_sdhci_ops = {
+	.set_clock = aspeed_sdhci_set_clock,
+	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
+	.set_bus_width = aspeed_sdhci_set_bus_width,
+	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+	.reset = sdhci_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data aspeed_sdc_pdata = {
+	.ops = &aspeed_sdhci_ops,
+	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+	.quirks2 = SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
+};
+
+static int aspeed_sdhci_probe(struct platform_device *pdev)
+{
+	struct sdhci_pltfm_host *pltfm_host;
+	struct aspeed_sdhci *dev;
+	struct sdhci_host *host;
+	u32 slot;
+	int ret;
+
+	host = sdhci_pltfm_init(pdev, &aspeed_sdc_pdata, sizeof(*dev));
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	pltfm_host = sdhci_priv(host);
+	dev = sdhci_pltfm_priv(pltfm_host);
+	dev->parent = dev_get_drvdata(pdev->dev.parent);
+
+	ret = of_property_read_u32(pdev->dev.of_node, "slot", &slot);
+	if (ret < 0)
+		return ret;
+	else if (slot > 2)
+		return -EINVAL;
+
+	dev->width_mask = !slot ? ASPEED_SDC_S0MMC8 : ASPEED_SDC_S1MMC8;
+
+	sdhci_get_of_property(pdev);
+
+	pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pltfm_host->clk))
+		return PTR_ERR(pltfm_host->clk);
+
+	ret = clk_prepare_enable(pltfm_host->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to enable SDIO clock\n");
+		goto err_pltfm_free;
+	}
+
+	ret = mmc_of_parse(host->mmc);
+	if (ret)
+		goto err_sdhci_add;
+
+	ret = sdhci_add_host(host);
+	if (ret)
+		goto err_sdhci_add;
+
+	return 0;
+
+err_sdhci_add:
+	clk_disable_unprepare(pltfm_host->clk);
+err_pltfm_free:
+	sdhci_pltfm_free(pdev);
+	return ret;
+}
+
+static int aspeed_sdhci_remove(struct platform_device *pdev)
+{
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_host *host;
+	int dead;
+
+	host = platform_get_drvdata(pdev);
+	pltfm_host = sdhci_priv(host);
+
+	dead = readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff;
+
+	sdhci_remove_host(host, dead);
+
+	clk_disable_unprepare(pltfm_host->clk);
+
+	sdhci_pltfm_free(pdev);
+
+	return 0;
+}
+
+static const struct of_device_id aspeed_sdhci_of_match[] = {
+	{ .compatible = "aspeed,ast2400-sdhci", },
+	{ .compatible = "aspeed,ast2500-sdhci", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, aspeed_sdhci_of_match);
+
+static struct platform_driver aspeed_sdhci_driver = {
+	.driver		= {
+		.name	= "sdhci-aspeed",
+		.of_match_table = aspeed_sdhci_of_match,
+	},
+	.probe		= aspeed_sdhci_probe,
+	.remove		= aspeed_sdhci_remove,
+};
+
+module_platform_driver(aspeed_sdhci_driver);
+
+static int aspeed_sdc_probe(struct platform_device *pdev)
+
+{
+	struct device_node *parent, *child;
+	struct aspeed_sdc *sdc;
+	int ret;
+
+	sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
+	if (!sdc)
+		return -ENOMEM;
+
+	spin_lock_init(&sdc->lock);
+
+	sdc->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(sdc->clk))
+		return PTR_ERR(sdc->clk);
+
+	ret = clk_prepare_enable(sdc->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to enable SDCLK\n");
+		return ret;
+	}
+
+	sdc->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(sdc->regs)) {
+		ret = PTR_ERR(sdc->regs);
+		goto err_clk;
+	}
+
+	dev_set_drvdata(&pdev->dev, sdc);
+
+	parent = pdev->dev.of_node;
+	for_each_available_child_of_node(parent, child) {
+		struct platform_device *cpdev;
+
+		cpdev = of_platform_device_create(child, NULL, &pdev->dev);
+		if (IS_ERR(cpdev)) {
+			of_node_put(child);
+			ret = PTR_ERR(pdev);
+			goto err_clk;
+		}
+	}
+
+	return 0;
+
+err_clk:
+	clk_disable_unprepare(sdc->clk);
+	return ret;
+}
+
+static int aspeed_sdc_remove(struct platform_device *pdev)
+{
+	struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
+
+	clk_disable_unprepare(sdc->clk);
+
+	return 0;
+}
+
+static const struct of_device_id aspeed_sdc_of_match[] = {
+	{ .compatible = "aspeed,ast2400-sdc", .data = &aspeed_sdc_pdata },
+	{ .compatible = "aspeed,ast2500-sdc", .data = &aspeed_sdc_pdata },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match);
+
+static struct platform_driver aspeed_sdc_driver = {
+	.driver		= {
+		.name	= "sdc-aspeed",
+		.pm	= &sdhci_pltfm_pmops,
+		.of_match_table = aspeed_sdc_of_match,
+	},
+	.probe		= aspeed_sdc_probe,
+	.remove		= aspeed_sdc_remove,
+};
+
+module_platform_driver(aspeed_sdc_driver);
+
+MODULE_DESCRIPTION("Driver for the ASPEED SD/SDIO/SDHCI Controllers");
+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1

^ permalink raw reply related

* [PATCH 1/2] dt-bindings: mmc: Document Aspeed SD controller
From: Andrew Jeffery @ 2019-07-10 14:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: Andrew Jeffery, ulf.hansson, robh+dt, mark.rutland, joel,
	adrian.hunter, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, ryanchen.aspeed
In-Reply-To: <20190710141611.21159-1-andrew@aj.id.au>

The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the
SDIO Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit
data bus if only a single slot is enabled.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
---
 .../bindings/mmc/sdhci-of-aspeed.yaml         | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml b/Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml
new file mode 100644
index 000000000000..e98a2ac4d46d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/sdhci-of-aspeed.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED SD/SDIO/eMMC Controller
+
+maintainers:
+  - Andrew Jeffery <andrew@aj.id.au>
+  - Ryan Chen <ryanchen.aspeed@gmail.com>
+
+description: |+
+  The ASPEED SD/SDIO/eMMC controller exposes two slots implementing the SDIO
+  Host Specification v2.00, with 1 or 4 bit data buses, or an 8 bit data bus if
+  only a single slot is enabled.
+
+  The two slots are supported by a common configuration area. As the SDHCIs for
+  the slots are dependent on the common configuration area, they are described
+  as child nodes.
+
+properties:
+  compatible:
+    enum: [ aspeed,ast2400-sdc, aspeed,ast2500-sdc ]
+  reg:
+    description: Common configuration registers
+  ranges: true
+  clocks:
+    maxItems: 1
+    description: The SD/SDIO controller clock gate
+  sdhci:
+    type: object
+    properties:
+      compatible:
+        allOf:
+          - enum: [ aspeed,ast2400-sdhci, aspeed,ast2500-sdhci ]
+          - const: sdhci
+      reg:
+        description: The SDHCI registers
+      clocks:
+        maxItems: 1
+        description: The SD bus clock
+      slot:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [0, 1]
+      interrupts:
+        maxItems: 1
+        description: The SD interrupt shared between both slots
+    required:
+      - compatible
+      - reg
+      - clocks
+      - slot
+      - interrupts
+
+required:
+  - compatible
+  - reg
+  - ranges
+  - clocks
+
+examples:
+  - |
+    #include <dt-bindings/clock/aspeed-clock.h>
+    sdc@1e740000 {
+            compatible = "aspeed,ast2500-sdc";
+            reg = <0x1e740000 0x100>;
+            #address-cells = <1>;
+            #size-cells = <1>;
+            ranges;
+            clocks = <&syscon ASPEED_CLK_GATE_SDCLK>;
+
+            sdhci0: sdhci@1e740100 {
+                    compatible = "aspeed,ast2500-sdhci", "sdhci";
+                    reg = <0x1e740100 0x100>;
+                    slot = <0>;
+                    interrupts = <26>;
+                    sdhci,auto-cmd12;
+                    clocks = <&syscon ASPEED_CLK_SDIO>;
+            };
+
+            sdhci1: sdhci@1e740200 {
+                    compatible = "aspeed,ast2500-sdhci", "sdhci";
+                    reg = <0x1e740200 0x100>;
+                    slot = <1>;
+                    interrupts = <26>;
+                    sdhci,auto-cmd12;
+                    clocks = <&syscon ASPEED_CLK_SDIO>;
+            };
+    };
-- 
2.20.1

^ permalink raw reply related

* [PATCH 0/2] mmc: Add support for the ASPEED SD controller
From: Andrew Jeffery @ 2019-07-10 14:16 UTC (permalink / raw)
  To: linux-mmc
  Cc: Andrew Jeffery, ulf.hansson, robh+dt, mark.rutland, joel,
	adrian.hunter, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, ryanchen.aspeed

Hello,

This short series introduce devicetree bindings and a driver for the ASPEED SD
controller. Please review!

Andrew

Andrew Jeffery (2):
  dt-bindings: mmc: Document Aspeed SD controller
  mmc: Add support for the ASPEED SD controller

 .../bindings/mmc/sdhci-of-aspeed.yaml         |  91 ++++++
 drivers/mmc/host/Kconfig                      |  12 +
 drivers/mmc/host/Makefile                     |   1 +
 drivers/mmc/host/sdhci-of-aspeed.c            | 307 ++++++++++++++++++
 4 files changed, 411 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-of-aspeed.yaml
 create mode 100644 drivers/mmc/host/sdhci-of-aspeed.c

-- 
2.20.1

^ permalink raw reply

* Re: [PATCH RFC 0/4] DDR/L3 Scaling support on SDM845 SoCs
From: Sibi Sankar @ 2019-07-10 14:14 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: nm, sboyd, georgi.djakov, agross, david.brown, robh+dt,
	mark.rutland, rjw, linux-arm-msm, devicetree, linux-kernel,
	linux-pm, saravanak, linux-kernel-owner, adharmap
In-Reply-To: <20190701092949.afenn2et2qexostt@vireshk-i7>

Hey Viresh,

On 2019-07-01 14:59, Viresh Kumar wrote:
> On 27-06-19, 19:04, Sibi Sankar wrote:
>> This RFC series aims to extend cpu based scaling support to L3/DDR on
>> SDM845 SoCs. The patch series depends on "Introduce OPP bandwidth 
>> bindings"
>> series (https://patchwork.kernel.org/cover/10912993/). A part of the
>> series will still be applicable if we decide to go ahead with the 
>> proposal
>> from Saravana as well so I decided to post this out.
>> 
>> v2:
>> * Incorporated Viresh's comments from:
>> [1]https://lore.kernel.org/lkml/20190410102429.r6j6brm5kspmqxc3@vireshk-i7/
>> [2]https://lore.kernel.org/lkml/20190410112516.gnh77jcwawvld6et@vireshk-i7/
> 
> Did you get a chance to look at this ?
> 
> lore.kernel.org/lkml/20190622003449.33707-1-saravanak@google.com

Yes, I have v2 of cpufreq passive governor
patch in the works based on Saravana's
series. I plan on posting it out end of
week. I had sent this series out
since a portion (specifically update_
voltage helper and adding opp_tables
to cpufreq-hw driver) would remain
constant irrespective of the path
we choose.

FWIW, on SDM845 SoCs we cannot use a
rpmh_write_batch based icc_set on
cpufreq fast switch pathw since it
uses the "wait_for_completion" api.


-- 
-- Sibi Sankar --
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply

* Re: [PATCH v2 3/5] memremap: Add support for read-only memory mappings
From: Will Deacon @ 2019-07-10 14:14 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Dan Williams, linux-kernel, linux-arm-msm, linux-arm-kernel,
	devicetree, Evan Green, Rob Herring, Bjorn Andersson, Andy Gross,
	Will Deacon, Catalin Marinas
In-Reply-To: <20190614203717.75479-4-swboyd@chromium.org>

On Fri, Jun 14, 2019 at 01:37:15PM -0700, Stephen Boyd wrote:
> Sometimes we have memories that are supposed to be read-only, but when
> we map these regions the best we can do is map them as write-back with
> MEMREMAP_WB. Introduce a read-only memory mapping (MEMREMAP_RO) that
> allows us to map reserved memory regions as read-only. This way, we're
> less likely to see these special memory regions become corrupted by
> stray writes to them.
> 
> Cc: Evan Green <evgreen@chromium.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
> Cc: Andy Gross <agross@kernel.org>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> Signed-off-by: Stephen Boyd <swboyd@chromium.org>
> ---
>  include/linux/io.h |  1 +
>  kernel/iomem.c     | 15 +++++++++++++--
>  2 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/io.h b/include/linux/io.h
> index 32e30e8fb9db..16c7f4498869 100644
> --- a/include/linux/io.h
> +++ b/include/linux/io.h
> @@ -159,6 +159,7 @@ enum {
>  	MEMREMAP_WC = 1 << 2,
>  	MEMREMAP_ENC = 1 << 3,
>  	MEMREMAP_DEC = 1 << 4,
> +	MEMREMAP_RO = 1 << 5,
>  };
>  
>  void *memremap(resource_size_t offset, size_t size, unsigned long flags);
> diff --git a/kernel/iomem.c b/kernel/iomem.c
> index 93c264444510..10d5ef0ff09e 100644
> --- a/kernel/iomem.c
> +++ b/kernel/iomem.c
> @@ -19,6 +19,13 @@ static void *arch_memremap_wb(resource_size_t offset, unsigned long size)
>  }
>  #endif
>  
> +#ifndef arch_memremap_ro
> +static void *arch_memremap_ro(resource_size_t offset, unsigned long size)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  #ifndef arch_memremap_can_ram_remap
>  static bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
>  					unsigned long flags)
> @@ -84,7 +91,10 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags)
>  	}
>  
>  	/* Try all mapping types requested until one returns non-NULL */
> -	if (flags & MEMREMAP_WB) {
> +	if ((flags & MEMREMAP_RO) && is_ram != REGION_INTERSECTS)
> +		addr = arch_memremap_ro(offset, size);
> +
> +	if (!addr && (flags & MEMREMAP_WB)) {
>  		/*
>  		 * MEMREMAP_WB is special in that it can be satisfied
>  		 * from the direct map.  Some archs depend on the
> @@ -103,7 +113,8 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags)
>  	 * address mapping.  Enforce that this mapping is not aliasing
>  	 * System RAM.
>  	 */
> -	if (!addr && is_ram == REGION_INTERSECTS && flags != MEMREMAP_WB) {
> +	if (!addr && is_ram == REGION_INTERSECTS &&
> +	    (flags != MEMREMAP_WB || flags != MEMREMAP_RO)) {
>  		WARN_ONCE(1, "memremap attempted on ram %pa size: %#lx\n",
>  				&offset, (unsigned long) size);
>  		return NULL;

This function seems a little confused about whether 'flags' is really a
bitmap of flags, or whether it is equal to exactly one entry in the enum.
Given that I think it's sensible for somebody to specify 'MEMREMAP_RO |
MEMREMAP_WT', then we probably need to start checking these things a bit
more thoroughly so we can reject unsupported combinations at the very least.

Will

^ permalink raw reply

* Re: [PATCH 2/4] dt-bindings: iio/adc: Add AUX2 channel idx for JZ4770 SoC ADC
From: Rob Herring @ 2019-07-10 13:53 UTC (permalink / raw)
  Cc: Jonathan Cameron, Mark Rutland, linux-iio, devicetree,
	linux-kernel, Maarten ter Huurne, Paul Cercueil, Artur Rojek
In-Reply-To: <20190623184732.5492-2-contact@artur-rojek.eu>

On Sun, 23 Jun 2019 20:47:30 +0200, Artur Rojek wrote:
> Introduce support for AUX2 channel found in ADC hardware present on
> Ingenic JZ4770 SoC.
> 
> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
> ---
>  include/dt-bindings/iio/adc/ingenic,adc.h | 1 +
>  1 file changed, 1 insertion(+)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply

* Re: [PATCH 1/4] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC
From: Rob Herring @ 2019-07-10 13:52 UTC (permalink / raw)
  Cc: Jonathan Cameron, Mark Rutland, linux-iio, devicetree,
	linux-kernel, Maarten ter Huurne, Paul Cercueil, Artur Rojek
In-Reply-To: <20190623184732.5492-1-contact@artur-rojek.eu>

On Sun, 23 Jun 2019 20:47:29 +0200, Artur Rojek wrote:
> Add a compatible string for the ADC controller present on
> Ingenic JZ4770 SoC.
> 
> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
> ---
>  Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt | 1 +
>  1 file changed, 1 insertion(+)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox