* Re: [PATCH v6 7/7] misc: pci_endpoint_test: Document a policy about adding pci_device_id
From: Manivannan Sadhasivam @ 2024-04-10 17:54 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, marek.vasut+renesas, linux-pci, devicetree,
linux-renesas-soc, Frank Li
In-Reply-To: <20240410004832.3726922-8-yoshihiro.shimoda.uh@renesas.com>
On Wed, Apr 10, 2024 at 09:48:32AM +0900, Yoshihiro Shimoda wrote:
> To avoid becoming struct pci_device_id pci_endpoint_test_tbl longer
> and longer, document a policy. For example, if PCIe endpoint controller
> can configure vendor id and/or product id, you can reuse one of
> existing entries to test.
>
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
One comment below. With that addressed,
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> ---
> Cc: Frank Li <Frank.li@nxp.com>
> ---
> drivers/misc/pci_endpoint_test.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index c38a6083f0a7..3c8a0afad91d 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -980,6 +980,7 @@ static const struct pci_endpoint_test_data j721e_data = {
> .irq_type = IRQ_TYPE_MSI,
> };
>
> +/* Don't need to add a new entry if you can use existing entry to test */
'Do not add a new entry if the controller can use existing VID:PID combinations'
- Mani
> static const struct pci_device_id pci_endpoint_test_tbl[] = {
> { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
> .driver_data = (kernel_ulong_t)&default_data,
> --
> 2.25.1
>
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v6 6/7] PCI: rcar-gen4: Add support for r8a779g0
From: Manivannan Sadhasivam @ 2024-04-10 17:51 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, marek.vasut+renesas, linux-pci, devicetree,
linux-renesas-soc
In-Reply-To: <20240410004832.3726922-7-yoshihiro.shimoda.uh@renesas.com>
On Wed, Apr 10, 2024 at 09:48:31AM +0900, Yoshihiro Shimoda wrote:
> This driver previously supported r8a779f0 (R-Car S4-8). Add support
> for r8a779g0 (R-Car V4H).
>
> To support r8a779g0, it requires specific firmware.
>
Add more information about the new SoC. Like features, why firmware is needed,
how it is downloaded/verified etc...
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
> drivers/pci/controller/dwc/pcie-rcar-gen4.c | 201 +++++++++++++++++++-
> 1 file changed, 200 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index 47ec394885f5..a62804674f4e 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> @@ -5,8 +5,10 @@
> */
>
> #include <linux/delay.h>
> +#include <linux/firmware.h>
> #include <linux/interrupt.h>
> #include <linux/io.h>
> +#include <linux/iopoll.h>
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/pci.h>
> @@ -20,9 +22,10 @@
> /* Renesas-specific */
> /* PCIe Mode Setting Register 0 */
> #define PCIEMSR0 0x0000
> -#define BIFUR_MOD_SET_ON BIT(0)
> +#define APP_SRIS_MODE BIT(6)
> #define DEVICE_TYPE_EP 0
> #define DEVICE_TYPE_RC BIT(4)
> +#define BIFUR_MOD_SET_ON BIT(0)
>
> /* PCIe Interrupt Status 0 */
> #define PCIEINTSTS0 0x0084
> @@ -37,19 +40,47 @@
> #define PCIEDMAINTSTSEN 0x0314
> #define PCIEDMAINTSTSEN_INIT GENMASK(15, 0)
>
> +/* Port Logic Registers 89 */
> +#define PRTLGC89 0x0b70
> +
> +/* Port Logic Registers 90 */
> +#define PRTLGC90 0x0b74
> +
> /* PCIe Reset Control Register 1 */
> #define PCIERSTCTRL1 0x0014
> #define APP_HOLD_PHY_RST BIT(16)
> #define APP_LTSSM_ENABLE BIT(0)
>
> +/* PCIe Power Management Control */
> +#define PCIEPWRMNGCTRL 0x0070
> +#define APP_CLK_REQ_N BIT(11)
> +#define APP_CLK_PM_EN BIT(10)
> +
> +/*
> + * The R-Car Gen4 documents don't describe the PHY registers' name.
> + * But, the initialization procedure describes these offsets. So,
> + * this driver makes up own #defines for the offsets.
> + */
This provides no information at all. So better hardcode them.
> +#define RCAR_GEN4_PCIE_PHY_0f8 0x0f8
> +#define RCAR_GEN4_PCIE_PHY_148 0x148
> +#define RCAR_GEN4_PCIE_PHY_1d4 0x1d4
> +#define RCAR_GEN4_PCIE_PHY_514 0x514
> +#define RCAR_GEN4_PCIE_PHY_700 0x700
> +
> #define RCAR_NUM_SPEED_CHANGE_RETRIES 10
> #define RCAR_MAX_LINK_SPEED 4
>
> #define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
> #define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
>
> +#define RCAR_GEN4_PCIE_FIRMWARE_NAME "rcar_gen4_pcie.bin"
> +#define RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR 0xc000
> +
> +MODULE_FIRMWARE(RCAR_GEN4_PCIE_FIRMWARE_NAME);
> +
> struct rcar_gen4_pcie;
> struct rcar_gen4_pcie_platdata {
> + void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
> int (*ltssm_enable)(struct rcar_gen4_pcie *rcar);
> enum dw_pcie_device_mode mode;
> };
> @@ -57,12 +88,144 @@ struct rcar_gen4_pcie_platdata {
> struct rcar_gen4_pcie {
> struct dw_pcie dw;
> void __iomem *base;
> + void __iomem *phy_base;
> struct platform_device *pdev;
> const struct rcar_gen4_pcie_platdata *platdata;
> };
> #define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
>
> /* Common */
> +static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
> + u32 offset, u32 mask, u32 val)
> +{
> + u32 tmp;
> +
> + tmp = readl(rcar->phy_base + offset);
> + tmp &= ~mask;
> + tmp |= val;
> + writel(tmp, rcar->phy_base + offset);
If you use FIELD_* macros, then the values can be passed sensibly ie., just 0
and 1.
> +}
> +
> +static int rcar_gen4_pcie_reg_check_bit(struct rcar_gen4_pcie *rcar,
rcar_gen4_pcie_reg_check()?
> + u32 offset, u32 mask)
> +{
> + struct dw_pcie *dw = &rcar->dw;
> +
> + if (dw_pcie_readl_dbi(dw, offset) & mask)
> + return -EAGAIN;
> +
> + return 0;
> +}
> +
> +static int rcar_gen4_pcie_update_phy_firmware(struct rcar_gen4_pcie *rcar)
> +{
> + const u32 check_addr[] = { 0x00101018, 0x00101118, 0x00101021, 0x00101121};
What are these addresses?
> + struct dw_pcie *dw = &rcar->dw;
> + const struct firmware *fw;
> + unsigned int i, timeout;
> + u32 data;
> + int ret;
> +
> + ret = request_firmware(&fw, RCAR_GEN4_PCIE_FIRMWARE_NAME, dw->dev);
Is this the PHY firmware or PCIe?
> + if (ret) {
> + dev_err(dw->dev, "%s: Requesting firmware failed\n", __func__);
Please, do not print function names in error log.
> + return ret;
> + }
> +
> + for (i = 0; i < (fw->size / 2); i++) {
> + data = fw->data[i * 2] | fw->data[(i * 2) + 1] << 8;
Well, the usual concat order is:
data << 8 | data
> + timeout = 100;
> + do {
> + dw_pcie_writel_dbi(dw, PRTLGC89, RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR + i);
> + dw_pcie_writel_dbi(dw, PRTLGC90, data);
> + if (rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30)) >= 0)
What is going on here? Please add a comment to make it clear.
> + break;
> + if (!(--timeout)) {
> + ret = -ETIMEDOUT;
> + goto exit;
> + }
> + usleep_range(100, 200);
> + } while (1);
> + }
> +
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(17), BIT(17));
> +
> + for (i = 0; i < ARRAY_SIZE(check_addr); i++) {
> + timeout = 100;
> + do {
> + dw_pcie_writel_dbi(dw, PRTLGC89, check_addr[i]);
> + ret = rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30));
> + ret |= rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC90, BIT(0));
> + if (ret >= 0)
> + break;
> + if (!(--timeout)) {
> + ret = -ETIMEDOUT;
> + goto exit;
> + }
> + usleep_range(100, 200);
> + } while (1);
> + }
> +
> + ret = 0;
return 0
> +exit:
> + release_firmware(fw);
> +
> + return ret;
> +}
> +
> +static int rcar_gen4_pcie_enable_phy(struct rcar_gen4_pcie *rcar)
> +{
> + struct dw_pcie *dw = &rcar->dw;
> + u32 val;
> + int ret;
> +
> + val = dw_pcie_readl_dbi(dw, PCIE_PORT_FORCE);
> + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> + dw_pcie_writel_dbi(dw, PCIE_PORT_FORCE, val);
> +
> + val = readl(rcar->base + PCIEMSR0);
> + val |= APP_SRIS_MODE;
> + writel(val, rcar->base + PCIEMSR0);
> +
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(28), 0);
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(20), 0);
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(12), 0);
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(4), 0);
> +
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
> + GENMASK(23, 22), BIT(22));
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
> + GENMASK(18, 16), GENMASK(17, 16));
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
> + GENMASK(7, 6), BIT(6));
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
> + GENMASK(2, 0), GENMASK(11, 0));
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_1d4,
> + GENMASK(16, 15), GENMASK(16, 15));
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_514, BIT(26), BIT(26));
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(16), 0);
> + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(19), BIT(19));
> +
> + val = readl(rcar->base + PCIERSTCTRL1);
> + val &= ~APP_HOLD_PHY_RST;
> + writel(val, rcar->base + PCIERSTCTRL1);
> +
> + ret = readl_poll_timeout(rcar->phy_base + RCAR_GEN4_PCIE_PHY_0f8, val,
> + !(val & BIT(18)), 100, 10000);
> + if (ret < 0)
> + return ret;
> +
> + ret = rcar_gen4_pcie_update_phy_firmware(rcar);
Updating or downloading the PHY firmware?
> + if (ret)
> + return ret;
> +
> + val = readl(rcar->base + PCIERSTCTRL1);
> + val |= APP_LTSSM_ENABLE;
> + writel(val, rcar->base + PCIERSTCTRL1);
> +
> + return 0;
> +}
> +
> static void rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar,
> bool enable)
> {
> @@ -200,6 +363,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
> if (ret)
> goto err_unprepare;
>
> + if (rcar->platdata->additional_common_init)
> + rcar->platdata->additional_common_init(rcar);
> +
> return 0;
>
> err_unprepare:
> @@ -241,6 +407,10 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
>
> static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
> {
> + rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
> + if (IS_ERR(rcar->phy_base))
> + return PTR_ERR(rcar->base);
rcar->phy_base?
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH 2/3] dt-bindings: PCI: mediatek,mt7621: add missing child node reg
From: Rob Herring @ 2024-04-10 17:48 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Mark Kettenis, Jianjun Wang, Broadcom internal kernel review list,
Ahmad Zainie, Kishon Vijay Abraham I, Scott Branden,
linux-mediatek, Lorenzo Pieralisi, Nicolas Saenz Julienne,
Sven Peter, Daire McNamara, Geert Uytterhoeven, linux-kernel,
linux-renesas-soc, Ryder Lee, Krzysztof Wilczyński,
Manivannan Sadhasivam, Srikanth Thokala, Jim Quinlan,
Bjorn Andersson, Thippeswamy Havalige, Yoshihiro Shimoda,
Neil Armstrong, Gustavo Pimentel, Jiaxun Yang, devicetree,
AngeloGioacchino Del Regno, Matthias Brugger, Krzysztof Kozlowski,
Tom Joseph, Will Deacon, Bjorn Helgaas, linux-rpi-kernel,
linux-rockchip, Alyssa Rosenzweig, linux-arm-msm,
Florian Fainelli, Michal Simek, Sergio Paracuellos, Jingoo Han,
Magnus Damm, Conor Dooley, Linus Walleij, Marek Vasut, Ray Jui,
Bharat Kumar Gogada, Hector Martin, Konrad Dybcio, Heiko Stuebner,
linux-arm-kernel, linux-pci, Shawn Lin, asahi
In-Reply-To: <20240407102000.37213-2-krzysztof.kozlowski@linaro.org>
On Sun, 07 Apr 2024 12:19:59 +0200, Krzysztof Kozlowski wrote:
> MT7621 PCI host bridge has children which apparently are also PCI host
> bridges, at least that's what the binding suggest. The children have
> "reg" property, but do not explicitly define it. Instead they rely on
> pci-bus.yaml schema, but that one has "reg" without any constraints.
>
> Define the "reg" for the children, so the binding will be more specific
> and later will allow dropping reference to deprecated pci-bus.yaml
> schema.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> ---
> .../devicetree/bindings/pci/mediatek,mt7621-pcie.yaml | 3 +++
> 1 file changed, 3 insertions(+)
>
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 3/3] dt-bindings: PCI: host-bridges: switch from deprecated pci-bus.yaml
From: Rob Herring @ 2024-04-10 17:48 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Krzysztof Kozlowski, Conor Dooley, Hector Martin, Sven Peter,
Alyssa Rosenzweig, Ray Jui, Scott Branden,
Broadcom internal kernel review list, Jim Quinlan,
Nicolas Saenz Julienne, Florian Fainelli, Will Deacon,
Linus Walleij, Srikanth Thokala, Ryder Lee, Jianjun Wang,
Sergio Paracuellos, Matthias Brugger, AngeloGioacchino Del Regno,
Daire McNamara, Bjorn Andersson, Konrad Dybcio, Marek Vasut,
Yoshihiro Shimoda, Shawn Lin, Heiko Stuebner, Jingoo Han,
Gustavo Pimentel, Manivannan Sadhasivam, Bharat Kumar Gogada,
Michal Simek, Geert Uytterhoeven, Magnus Damm, Neil Armstrong,
Mark Kettenis, Tom Joseph, Ahmad Zainie, Jiaxun Yang,
Kishon Vijay Abraham I, Thippeswamy Havalige, linux-pci,
devicetree, linux-kernel, asahi, linux-arm-kernel,
linux-rpi-kernel, linux-mediatek, linux-arm-msm,
linux-renesas-soc, linux-rockchip
In-Reply-To: <20240407102000.37213-3-krzysztof.kozlowski@linaro.org>
On Sun, Apr 07, 2024 at 12:20:00PM +0200, Krzysztof Kozlowski wrote:
> dtschema package with core schemas deprecated pci-bus.yaml schema in
> favor of pci-host-bridge.yaml. Update all bindings to use the latter
> one.
>
> The difference between pci-bus.yaml and pci-host-bridge.yaml is only in
> lack of "reg" property defined by the latter, which should not have any
> effect here, because all these bindings define the "reg".
>
> The change is therefore quite trivial, except mediatek,mt7621-pcie.yaml
> binding which have children nodes being also host bridges, apparently.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> ---
> Documentation/devicetree/bindings/pci/amlogic,axg-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/apple,pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/brcm,iproc-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/cdns-pcie-host.yaml | 2 +-
> Documentation/devicetree/bindings/pci/faraday,ftpci100.yaml | 2 +-
> Documentation/devicetree/bindings/pci/host-generic-pci.yaml | 2 +-
> Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml | 2 +-
> Documentation/devicetree/bindings/pci/intel,keembay-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/loongson.yaml | 2 +-
> .../devicetree/bindings/pci/mediatek,mt7621-pcie.yaml | 4 ++--
> Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml | 2 +-
> .../devicetree/bindings/pci/microchip,pcie-host.yaml | 2 +-
> Documentation/devicetree/bindings/pci/qcom,pcie-common.yaml | 2 +-
> Documentation/devicetree/bindings/pci/qcom,pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/rcar-pci-host.yaml | 2 +-
> .../devicetree/bindings/pci/renesas,pci-rcar-gen2.yaml | 2 +-
> .../devicetree/bindings/pci/rockchip,rk3399-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/ti,am65-pci-host.yaml | 2 +-
> Documentation/devicetree/bindings/pci/versatile.yaml | 2 +-
> Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml | 2 +-
> Documentation/devicetree/bindings/pci/xlnx,axi-pcie-host.yaml | 2 +-
> Documentation/devicetree/bindings/pci/xlnx,nwl-pcie.yaml | 2 +-
> Documentation/devicetree/bindings/pci/xlnx,xdma-host.yaml | 2 +-
> 25 files changed, 26 insertions(+), 26 deletions(-)
> diff --git a/Documentation/devicetree/bindings/pci/mediatek,mt7621-pcie.yaml b/Documentation/devicetree/bindings/pci/mediatek,mt7621-pcie.yaml
> index 61d027239910..5bbb4a3f3dbd 100644
> --- a/Documentation/devicetree/bindings/pci/mediatek,mt7621-pcie.yaml
> +++ b/Documentation/devicetree/bindings/pci/mediatek,mt7621-pcie.yaml
> @@ -14,7 +14,7 @@ description: |+
> with 3 Root Ports. Each Root Port supports a Gen1 1-lane Link
>
> allOf:
> - - $ref: /schemas/pci/pci-bus.yaml#
> + - $ref: /schemas/pci/pci-host-bridge.yaml#
>
> properties:
> compatible:
> @@ -33,7 +33,7 @@ properties:
> patternProperties:
> '^pcie@[0-2],0$':
> type: object
> - $ref: /schemas/pci/pci-bus.yaml#
> + $ref: /schemas/pci/pci-host-bridge.yaml#
I think this one should be pci-pci-bridge.yaml instead since it says
these are root ports and based on the unit-address here.
Rob
^ permalink raw reply
* Re: [PATCH v3 0/9] spi: cadence-qspi: add Mobileye EyeQ5 support
From: Mark Brown @ 2024-04-10 17:47 UTC (permalink / raw)
To: Théo Lebrun
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vaishnav Achath,
Thomas Bogendoerfer, Rob Herring, linux-spi, devicetree,
linux-kernel, linux-mips, Vladimir Kondratiev, Gregory CLEMENT,
Thomas Petazzoni, Tawfik Bayouk, Krzysztof Kozlowski
In-Reply-To: <20240410-cdns-qspi-mbly-v3-0-7b7053449cf7@bootlin.com>
[-- Attachment #1: Type: text/plain, Size: 284 bytes --]
On Wed, Apr 10, 2024 at 11:29:03AM +0200, Théo Lebrun wrote:
> V1 cover letter [5] contains a brief summary of what gets added.
Please make your cover letters stand alone things, things like a basic
description of the contents of the series should just be included
directly.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: PCI: cdns,cdns-pcie-host: drop redundant msi-parent and pci-bus.yaml
From: Rob Herring @ 2024-04-10 17:35 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Linus Walleij, Jiaxun Yang, Tom Joseph, Magnus Damm,
linux-arm-msm, Ray Jui, Marek Vasut, Geert Uytterhoeven,
linux-rpi-kernel, linux-mediatek, Krzysztof Wilczyński,
Shawn Lin, Bjorn Andersson, Mark Kettenis, Sven Peter,
Alyssa Rosenzweig, linux-pci, linux-renesas-soc, Michal Simek,
Manivannan Sadhasivam, Jingoo Han, Nicolas Saenz Julienne,
Jianjun Wang, Heiko Stuebner, Thippeswamy Havalige, Conor Dooley,
Srikanth Thokala, Sergio Paracuellos, Konrad Dybcio, asahi,
AngeloGioacchino Del Regno, Daire McNamara, Jim Quinlan,
Krzysztof Kozlowski, devicetree, Ryder Lee, linux-rockchip,
Broadcom internal kernel review list, Lorenzo Pieralisi,
Gustavo Pimentel, Bharat Kumar Gogada, Scott Branden, Will Deacon,
linux-arm-kernel, Florian Fainelli, Hector Martin, Ahmad Zainie,
Neil Armstrong, Bjorn Helgaas, Kishon Vijay Abraham I,
Yoshihiro Shimoda, linux-kernel, Matthias Brugger
In-Reply-To: <20240407102000.37213-1-krzysztof.kozlowski@linaro.org>
On Sun, 07 Apr 2024 12:19:58 +0200, Krzysztof Kozlowski wrote:
> The binding reference common cdns-pcie-host.yaml, which already defines
> msi-parent and has a reference to pci-bus.yaml schema. Drop redundant
> pieces here to make it a bit smaller.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> ---
> Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml | 3 ---
> 1 file changed, 3 deletions(-)
>
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH] dt-bindings: usb: hx3: Remove unneeded dr_mode
From: Rob Herring @ 2024-04-10 17:34 UTC (permalink / raw)
To: Fabio Estevam
Cc: krzk+dt, Fabio Estevam, conor+dt, linux-usb, devicetree, gregkh
In-Reply-To: <20240405195051.945474-1-festevam@gmail.com>
On Fri, 05 Apr 2024 16:50:51 -0300, Fabio Estevam wrote:
> From: Fabio Estevam <festevam@denx.de>
>
> It is expected that the USB controller works in host mode
> to have the USB hub operational.
>
> Remove such unneeded property from the devicetree example.
>
> Signed-off-by: Fabio Estevam <festevam@denx.de>
> ---
> Documentation/devicetree/bindings/usb/cypress,hx3.yaml | 1 -
> 1 file changed, 1 deletion(-)
>
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 07/11] dt-bindings: iio: dac: add docs for AD9739A
From: Rob Herring @ 2024-04-10 17:33 UTC (permalink / raw)
To: Nuno Sa
Cc: Jonathan Cameron, Olivier Moysan, Lars-Peter Clausen,
Conor Dooley, linux-iio, Krzysztof Kozlowski, Michael Hennerich,
Dragos Bogdan, devicetree
In-Reply-To: <20240405-iio-backend-axi-dac-v2-7-293bab7d5552@analog.com>
On Fri, 05 Apr 2024 17:00:05 +0200, Nuno Sa wrote:
> This adds the bindings documentation for the 14 bit
> RF Digital-to-Analog converter.
>
> Signed-off-by: Nuno Sa <nuno.sa@analog.com>
> ---
> .../devicetree/bindings/iio/dac/adi,ad9739a.yaml | 94 ++++++++++++++++++++++
> MAINTAINERS | 8 ++
> 2 files changed, 102 insertions(+)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: Re: [PATCH] arm64: dts: rockchip: remove startup-delay-us from vcc3v3_pcie2x1l0 on rock-5b
From: Jianfeng Liu @ 2024-04-10 17:33 UTC (permalink / raw)
To: shawn.lin
Cc: conor+dt, devicetree, heiko, krzysztof.kozlowski+dt,
linux-arm-kernel, linux-kernel, linux-rockchip, liujianfeng1994,
robh, sfr
In-Reply-To: <432000a6-1de9-4452-beb7-6954677e34c8@rock-chips.com>
Hi Shawn,
Wed, 10 Apr 2024 14:30:16 +0800, Shawn Lin wrote:
>Could you help try this patch to checkout if it works for you?
This patch works for me. Thank you for pointing me to the right path!
Looking forward to your fix.
Jianfeng
^ permalink raw reply
* Re: [PATCH v2 06/11] dt-bindings: iio: dac: add docs for AXI DAC IP
From: Rob Herring @ 2024-04-10 17:33 UTC (permalink / raw)
To: Nuno Sa
Cc: Krzysztof Kozlowski, Dragos Bogdan, Conor Dooley, Olivier Moysan,
Jonathan Cameron, devicetree, Michael Hennerich,
Lars-Peter Clausen, linux-iio
In-Reply-To: <20240405-iio-backend-axi-dac-v2-6-293bab7d5552@analog.com>
On Fri, 05 Apr 2024 17:00:04 +0200, Nuno Sa wrote:
> This adds the bindings documentation for the Analog Devices AXI DAC IP
> core.
>
> Signed-off-by: Nuno Sa <nuno.sa@analog.com>
> ---
> .../devicetree/bindings/iio/dac/adi,axi-dac.yaml | 62 ++++++++++++++++++++++
> MAINTAINERS | 7 +++
> 2 files changed, 69 insertions(+)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: PCI: altera: Convert to YAML
From: Rob Herring @ 2024-04-10 17:31 UTC (permalink / raw)
To: matthew.gerlach
Cc: bhelgaas, lpieralisi, kw, krzysztof.kozlowski+dt, conor+dt,
linux-pci, devicetree, linux-kernel
In-Reply-To: <20240405145322.3805828-1-matthew.gerlach@linux.intel.com>
On Fri, Apr 05, 2024 at 09:53:22AM -0500, matthew.gerlach@linux.intel.com wrote:
> From: Matthew Gerlach <matthew.gerlach@linux.intel.com>
>
> Convert the device tree bindings for the Altera Root Port PCIe controller
> from text to YAML.
>
> Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
> ---
> v2:
> - Move allOf: to bottom of file, just like example-schema is showing
> - add constraint for reg and reg-names
> - remove unneeded device_type
> - drop #address-cells and #size-cells
> - change minItems to maxItems for interrupts:
> - change msi-parent to just "msi-parent: true"
> - cleaned up required:
> - make subject consistent with other commits coverting to YAML
> - s/overt/onvert/g
> ---
> .../devicetree/bindings/pci/altera-pcie.txt | 50 ---------
> .../bindings/pci/altr,pcie-root-port.yaml | 106 ++++++++++++++++++
> 2 files changed, 106 insertions(+), 50 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/pci/altera-pcie.txt
> create mode 100644 Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
>
> diff --git a/Documentation/devicetree/bindings/pci/altera-pcie.txt b/Documentation/devicetree/bindings/pci/altera-pcie.txt
> deleted file mode 100644
> index 816b244a221e..000000000000
> --- a/Documentation/devicetree/bindings/pci/altera-pcie.txt
> +++ /dev/null
> @@ -1,50 +0,0 @@
> -* Altera PCIe controller
> -
> -Required properties:
> -- compatible : should contain "altr,pcie-root-port-1.0" or "altr,pcie-root-port-2.0"
> -- reg: a list of physical base address and length for TXS and CRA.
> - For "altr,pcie-root-port-2.0", additional HIP base address and length.
> -- reg-names: must include the following entries:
> - "Txs": TX slave port region
> - "Cra": Control register access region
> - "Hip": Hard IP region (if "altr,pcie-root-port-2.0")
> -- interrupts: specifies the interrupt source of the parent interrupt
> - controller. The format of the interrupt specifier depends
> - on the parent interrupt controller.
> -- device_type: must be "pci"
> -- #address-cells: set to <3>
> -- #size-cells: set to <2>
> -- #interrupt-cells: set to <1>
> -- ranges: describes the translation of addresses for root ports and
> - standard PCI regions.
> -- interrupt-map-mask and interrupt-map: standard PCI properties to define the
> - mapping of the PCIe interface to interrupt numbers.
> -
> -Optional properties:
> -- msi-parent: Link to the hardware entity that serves as the MSI controller
> - for this PCIe controller.
> -- bus-range: PCI bus numbers covered
> -
> -Example
> - pcie_0: pcie@c00000000 {
> - compatible = "altr,pcie-root-port-1.0";
> - reg = <0xc0000000 0x20000000>,
> - <0xff220000 0x00004000>;
> - reg-names = "Txs", "Cra";
> - interrupt-parent = <&hps_0_arm_gic_0>;
> - interrupts = <0 40 4>;
> - interrupt-controller;
> - #interrupt-cells = <1>;
> - bus-range = <0x0 0xFF>;
> - device_type = "pci";
> - msi-parent = <&msi_to_gic_gen_0>;
> - #address-cells = <3>;
> - #size-cells = <2>;
> - interrupt-map-mask = <0 0 0 7>;
> - interrupt-map = <0 0 0 1 &pcie_0 1>,
> - <0 0 0 2 &pcie_0 2>,
> - <0 0 0 3 &pcie_0 3>,
> - <0 0 0 4 &pcie_0 4>;
> - ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
> - 0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
> - };
> diff --git a/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
> new file mode 100644
> index 000000000000..999dcda05f55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
> @@ -0,0 +1,106 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +# Copyright (C) 2024, Intel Corporation
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/altr,pcie-root-port.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Altera PCIe Root Port
> +
> +maintainers:
> + - Matthew Gerlach <matthew.gerlach@linux.intel.com>
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - altr,pcie-root-port-1.0
> + - altr,pcie-root-port-2.0
> +
> + interrupts:
> + maxItems: 1
> +
> + interrupt-map-mask:
> + items:
> + - const: 0
> + - const: 0
> + - const: 0
> + - const: 7
> +
> + interrupt-map:
> + maxItems: 4
> +
> + "#interrupt-cells":
> + const: 1
Already defined in the common schema, drop.
> +
> + msi-parent: true
> +
> +required:
> + - compatible
> + - reg
> + - reg-names
> + - device_type
Drop.
> + - interrupts
> + - interrupt-map
> + - interrupt-map-mask
> +
> +unevaluatedProperties: false
> +
> +allOf:
> + - $ref: /schemas/pci/pci-bus.yaml#
> + - if:
> + properties:
> + compatible:
> + enum:
> + - altr,pcie-root-port-1.0
> + then:
> + properties:
> + reg:
> + items:
> + - description: TX slave port region
> + - description: Control register access region
> +
> + reg-names:
> + items:
> + - const: Txs
> + - const: Cra
> +
> + else:
> + properties:
> + reg:
> + items:
> + - description: Hard IP region
> + - description: TX slave port region
> + - description: Control register access region
> +
> + reg-names:
> + items:
> + - const: Hip
> + - const: Txs
> + - const: Cra
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> + pcie_0: pcie@c00000000 {
> + compatible = "altr,pcie-root-port-1.0";
> + reg = <0xc0000000 0x20000000>,
> + <0xff220000 0x00004000>;
> + reg-names = "Txs", "Cra";
> + interrupt-parent = <&hps_0_arm_gic_0>;
> + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
> + #interrupt-cells = <1>;
> + bus-range = <0x0 0xff>;
> + device_type = "pci";
> + msi-parent = <&msi_to_gic_gen_0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + interrupt-map-mask = <0 0 0 7>;
> + interrupt-map = <0 0 0 1 &pcie_intc 1>,
> + <0 0 0 2 &pcie_intc 2>,
> + <0 0 0 3 &pcie_intc 3>,
> + <0 0 0 4 &pcie_intc 4>;
> + ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
> + 0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
> + };
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: PCI: altera: Convert to YAML
From: Rob Herring @ 2024-04-10 17:29 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: matthew.gerlach, bhelgaas, lpieralisi, kw, krzysztof.kozlowski+dt,
conor+dt, linux-pci, devicetree, linux-kernel
In-Reply-To: <d079bf4d-ebfe-4d98-b718-0c545aabbd30@linaro.org>
On Tue, Apr 09, 2024 at 08:29:07AM +0200, Krzysztof Kozlowski wrote:
> On 08/04/2024 22:34, matthew.gerlach@linux.intel.com wrote:
> >>> diff --git a/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
> >>> new file mode 100644
> >>> index 000000000000..999dcda05f55
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
> >>> @@ -0,0 +1,106 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> >>> +# Copyright (C) 2024, Intel Corporation
> >>
> >> This is derivative of previous work, which is easily visible by doing
> >> the same mistakes in DTS as they were before.
> >
> > This is definitely derivative of previous work, and I want to fix the
> > DTS mistakes too.
> >
> >>
> >> You now added fresh copyrights ignoring all previous work, even though
> >> you copied it. I don't agree.
> >>
> >> If you want to ignore previous copyrights, then at least don't copy
> >> existing code... although even that would not be sufficient.
> >
> > Ignoring previous copyrights was not my intent. There is no copyright
> > statement in the original text version of the device tree bindings. Should
> > that lack of copyright statement carry forward?
>
> All the authors are copyright holders automatically, at least in some or
> maybe most jurisdictions. You do not need to add copyright label for
> material to be copyrighted. That's why you are not allowed to relicense
> the work for example, without other authors' agreement.
The only thing I see as missing is some years. All the authors were
Altera which is now Intel, so Intel is the sole copyright holder.
Whether is says 2015 contributions were Altera or Intel is probably
immaterial. There were also contributions by Google (Bjorn), but those
were purely editorial.
Rob
^ permalink raw reply
* Re: DT Query on "New Compatible vs New Property"
From: Nikunj Kela @ 2024-04-10 17:24 UTC (permalink / raw)
To: Krzysztof Kozlowski, Sudeep Holla, Srinivas Kandagatla
Cc: Trilok Soni, Ulf Hansson, Manivannan Sadhasivam,
krzysztof.kozlowski+dt, Vincent Guittot, robh+dt, conor+dt,
devicetree, Prasad Sodagudi (QUIC)
In-Reply-To: <afc07c5d-640b-4eaf-94a2-086a6d43d712@linaro.org>
On 4/10/2024 10:13 AM, Krzysztof Kozlowski wrote:
> On 10/04/2024 18:55, Nikunj Kela wrote:
>> If there are no more questions on this and everyone is on the same page,
>> I would like to conclude this thread in favor of using a new DT property
>> 'qcom,firmware-managed-resources'.
> Just to recap my earlier statement, because I am not sure if I got the
> answer (if answer was provided, then I don't forgot... sorry):
>
> This is a new hardware, so you have a new compatible, therefore any
> additional property is not needed.
This is not a new HW, this is the same HW with different FW and
interface to FW is different too. As you can see earlier discussion on
this thread, new compatible was ruled out since it is the same HW IP.
>
> In other cases, just use existing properties, don't bring a third one. :/
Not sure which existing property you are referring to. There is no
property to the best of my knowledge to deal with our scenario. Are you
suggesting we reuse "qcom,controlled-remotely" property that is used in
Qualcomm BAM DMA Controller for our case too?
>
> Best regards,
> Krzysztof
>
^ permalink raw reply
* Re: [PATCH v6 5/7] PCI: rcar-gen4: Add .ltssm_enable() for other SoC support
From: Manivannan Sadhasivam @ 2024-04-10 17:23 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, marek.vasut+renesas, linux-pci, devicetree,
linux-renesas-soc
In-Reply-To: <20240410004832.3726922-6-yoshihiro.shimoda.uh@renesas.com>
On Wed, Apr 10, 2024 at 09:48:30AM +0900, Yoshihiro Shimoda wrote:
> This driver can reuse other R-Car Gen4 SoCs support like r8a779g0 and
> r8a779h0. However, r8a779g0 and r8a779h0 require other initializing
> settings that differ than r8a779f0. So, add a new function pointer
> .ltssm_enable() for it. No behavior changes.
>
> After applied this patch, probing SoCs by rcar_gen4_pcie_of_match[]
> will be changed like below:
>
> - r8a779f0 as "renesas,r8a779f0-pcie" and "renesas,r8a779f0-pcie-ep"
>
If r8a779f0 SoC can work with the existing 'renesas,rcar-gen4-pcie' and
'renesas,rcar-gen4-pcie-ep' compatibles, then you should just leave it as it is
and add a new compatible with dedicated callbacks for only r8a779g0 and
r8a779h0.
- Mani
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
> drivers/pci/controller/dwc/pcie-rcar-gen4.c | 41 ++++++++++++++++++---
> 1 file changed, 36 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index da2821d6efce..47ec394885f5 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> @@ -48,7 +48,9 @@
> #define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
> #define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
>
> +struct rcar_gen4_pcie;
> struct rcar_gen4_pcie_platdata {
> + int (*ltssm_enable)(struct rcar_gen4_pcie *rcar);
> enum dw_pcie_device_mode mode;
> };
>
> @@ -61,8 +63,8 @@ struct rcar_gen4_pcie {
> #define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
>
> /* Common */
> -static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
> - bool enable)
> +static void rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar,
> + bool enable)
> {
> u32 val;
>
> @@ -127,9 +129,13 @@ static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
> static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
> {
> struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
> - int i, changes;
> + int i, changes, ret;
>
> - rcar_gen4_pcie_ltssm_enable(rcar, true);
> + if (rcar->platdata->ltssm_enable) {
> + ret = rcar->platdata->ltssm_enable(rcar);
> + if (ret)
> + return ret;
> + }
>
> /*
> * Require direct speed change with retrying here if the link_gen is
> @@ -157,7 +163,7 @@ static void rcar_gen4_pcie_stop_link(struct dw_pcie *dw)
> {
> struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
>
> - rcar_gen4_pcie_ltssm_enable(rcar, false);
> + rcar_gen4_pcie_ltssm_control(rcar, false);
> }
>
> static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
> @@ -504,6 +510,23 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
> rcar_gen4_pcie_unprepare(rcar);
> }
>
> +static int r8a779f0_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar)
> +{
> + rcar_gen4_pcie_ltssm_control(rcar, true);
> +
> + return 0;
> +}
> +
> +static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
> + .ltssm_enable = r8a779f0_pcie_ltssm_enable,
> + .mode = DW_PCIE_RC_TYPE,
> +};
> +
> +static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
> + .ltssm_enable = r8a779f0_pcie_ltssm_enable,
> + .mode = DW_PCIE_EP_TYPE,
> +};
> +
> static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
> .mode = DW_PCIE_RC_TYPE,
> };
> @@ -513,6 +536,14 @@ static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
> };
>
> static const struct of_device_id rcar_gen4_pcie_of_match[] = {
> + {
> + .compatible = "renesas,r8a779f0-pcie",
> + .data = &platdata_r8a779f0_pcie,
> + },
> + {
> + .compatible = "renesas,r8a779f0-pcie-ep",
> + .data = &platdata_r8a779f0_pcie_ep,
> + },
> {
> .compatible = "renesas,rcar-gen4-pcie",
> .data = &platdata_rcar_gen4_pcie,
> --
> 2.25.1
>
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v2 2/6] dt-bindings: firmware: add i.MX SCMI Extension protocol
From: Rob Herring @ 2024-04-10 17:19 UTC (permalink / raw)
To: Peng Fan (OSS)
Cc: Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Sudeep Holla,
Cristian Marussi, Peng Fan, devicetree, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <20240405-imx95-bbm-misc-v2-v2-2-9fc9186856c2@nxp.com>
On Fri, Apr 05, 2024 at 08:39:24PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> Add i.MX SCMI Extension protocols bindings for:
> - Battery Backed Secure Module(BBSM)
> - MISC settings such as General Purpose Registers settings.
>
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
> .../devicetree/bindings/firmware/imx,scmi.yaml | 80 ++++++++++++++++++++++
> 1 file changed, 80 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/firmware/imx,scmi.yaml b/Documentation/devicetree/bindings/firmware/imx,scmi.yaml
> new file mode 100644
> index 000000000000..7ee19a661d83
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/firmware/imx,scmi.yaml
> @@ -0,0 +1,80 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +# Copyright 2024 NXP
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/firmware/imx,scmi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: i.MX System Control and Management Interface(SCMI) Vendor Protocols Extension
> +
> +maintainers:
> + - Peng Fan <peng.fan@nxp.com>
> +
> +allOf:
> + - $ref: arm,scmi.yaml#
This needs to be the other way around. Add a ref to this file in
arm,scmi.yaml under an 'anyOf' entry.
> +
> +properties:
> + protocol@81:
> + $ref: 'arm,scmi.yaml#/$defs/protocol-node'
> + unevaluatedProperties: false
> + description:
> + The BBM Protocol is for managing Battery Backed Secure Module (BBSM) RTC
> + and the ON/OFF Key
> +
> + properties:
> + reg:
> + const: 0x81
> +
> + required:
> + - reg
> +
> + protocol@84:
> + $ref: 'arm,scmi.yaml#/$defs/protocol-node'
> + unevaluatedProperties: false
> + description:
> + The MISC Protocol is for managing SoC Misc settings, such as GPR settings
> +
> + properties:
> + reg:
> + const: 0x84
> +
> + wakeup-sources:
> + description:
> + Each entry consists of 2 integers, represents the source and electric signal edge
> + items:
> + items:
> + - description: the wakeup source
> + - description: the wakeup electric signal edge
No constraints on the entry values?
> + $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +
> + required:
> + - reg
> +
> +additionalProperties: false
And then this can be true.
Rob
^ permalink raw reply
* Re: [PATCH v6 4/7] PCI: rcar-gen4: Add rcar_gen4_pcie_platdata
From: Manivannan Sadhasivam @ 2024-04-10 17:17 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, marek.vasut+renesas, linux-pci, devicetree,
linux-renesas-soc
In-Reply-To: <20240410004832.3726922-5-yoshihiro.shimoda.uh@renesas.com>
On Wed, Apr 10, 2024 at 09:48:29AM +0900, Yoshihiro Shimoda wrote:
> This driver supports r8a779f0 now. In the future, add support for
> r8a779g0 and r8a779h0. To support these new SoCs, need other
> initializing settings. So, at first, add rcar_gen4_pcie_platdata
> and have a member with mode. No behavior changes.
>
How about,
"In order to support future SoCs such as r8a779g0 and r8a779h0 that require
different initialization settings, let's introduce SoC specific driver data with
the initial member being the device mode. No functional change."
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
> drivers/pci/controller/dwc/pcie-rcar-gen4.c | 30 ++++++++++++++-------
> 1 file changed, 21 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index 0be760ed420b..da2821d6efce 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> @@ -48,11 +48,15 @@
> #define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
> #define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
>
> +struct rcar_gen4_pcie_platdata {
Common naming convention is 'drvdata'.
> + enum dw_pcie_device_mode mode;
> +};
> +
> struct rcar_gen4_pcie {
> struct dw_pcie dw;
> void __iomem *base;
> struct platform_device *pdev;
> - enum dw_pcie_device_mode mode;
> + const struct rcar_gen4_pcie_platdata *platdata;
> };
> #define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
>
> @@ -137,7 +141,7 @@ static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
> * Since dw_pcie_setup_rc() sets it once, PCIe Gen2 will be trained.
> * So, this needs remaining times for up to PCIe Gen4 if RC mode.
> */
> - if (changes && rcar->mode == DW_PCIE_RC_TYPE)
> + if (changes && rcar->platdata->mode == DW_PCIE_RC_TYPE)
I'd recommend checking for the existence of the drvdata first. But if you are
sure that it will be present for all SoCs, then it can be left.
- Mani
> changes--;
>
> for (i = 0; i < changes; i++) {
> @@ -172,9 +176,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
> reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
>
> val = readl(rcar->base + PCIEMSR0);
> - if (rcar->mode == DW_PCIE_RC_TYPE) {
> + if (rcar->platdata->mode == DW_PCIE_RC_TYPE) {
> val |= DEVICE_TYPE_RC;
> - } else if (rcar->mode == DW_PCIE_EP_TYPE) {
> + } else if (rcar->platdata->mode == DW_PCIE_EP_TYPE) {
> val |= DEVICE_TYPE_EP;
> } else {
> ret = -EINVAL;
> @@ -437,9 +441,9 @@ static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
> /* Common */
> static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
> {
> - rcar->mode = (uintptr_t)of_device_get_match_data(&rcar->pdev->dev);
> + rcar->platdata = of_device_get_match_data(&rcar->pdev->dev);
>
> - switch (rcar->mode) {
> + switch (rcar->platdata->mode) {
> case DW_PCIE_RC_TYPE:
> return rcar_gen4_add_dw_pcie_rp(rcar);
> case DW_PCIE_EP_TYPE:
> @@ -480,7 +484,7 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
>
> static void rcar_gen4_remove_dw_pcie(struct rcar_gen4_pcie *rcar)
> {
> - switch (rcar->mode) {
> + switch (rcar->platdata->mode) {
> case DW_PCIE_RC_TYPE:
> rcar_gen4_remove_dw_pcie_rp(rcar);
> break;
> @@ -500,14 +504,22 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
> rcar_gen4_pcie_unprepare(rcar);
> }
>
> +static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
> + .mode = DW_PCIE_RC_TYPE,
> +};
> +
> +static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
> + .mode = DW_PCIE_EP_TYPE,
> +};
> +
> static const struct of_device_id rcar_gen4_pcie_of_match[] = {
> {
> .compatible = "renesas,rcar-gen4-pcie",
> - .data = (void *)DW_PCIE_RC_TYPE,
> + .data = &platdata_rcar_gen4_pcie,
> },
> {
> .compatible = "renesas,rcar-gen4-pcie-ep",
> - .data = (void *)DW_PCIE_EP_TYPE,
> + .data = &platdata_rcar_gen4_pcie_ep,
> },
> {},
> };
> --
> 2.25.1
>
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: DT Query on "New Compatible vs New Property"
From: Krzysztof Kozlowski @ 2024-04-10 17:13 UTC (permalink / raw)
To: Nikunj Kela, Sudeep Holla, Srinivas Kandagatla
Cc: Trilok Soni, Ulf Hansson, Manivannan Sadhasivam,
krzysztof.kozlowski+dt, Vincent Guittot, robh+dt, conor+dt,
devicetree, Prasad Sodagudi (QUIC)
In-Reply-To: <c66f280b-aa29-4b18-98f1-701f60cbc63d@quicinc.com>
On 10/04/2024 18:55, Nikunj Kela wrote:
> If there are no more questions on this and everyone is on the same page,
> I would like to conclude this thread in favor of using a new DT property
> 'qcom,firmware-managed-resources'.
Just to recap my earlier statement, because I am not sure if I got the
answer (if answer was provided, then I don't forgot... sorry):
This is a new hardware, so you have a new compatible, therefore any
additional property is not needed.
In other cases, just use existing properties, don't bring a third one. :/
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH 11/11] MIPS: mobileye: eyeq5: add pinctrl node & pinmux function nodes
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
Pins on this platform have two functions: GPIO or something-else. We
create function nodes for each something-else based on functions.
UART nodes are present in the platform devicetree. Add pinctrl to them
now that the pin controller is supported.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi | 125 ++++++++++++++++++++++++++++
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 13 +++
2 files changed, 138 insertions(+)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi
new file mode 100644
index 000000000000..42acda13e57a
--- /dev/null
+++ b/arch/mips/boot/dts/mobileye/eyeq5-pins.dtsi
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+/*
+ * Default pin configuration for Mobileye EyeQ5 boards. We mostly create one
+ * pin configuration node per function.
+ */
+
+&pinctrl {
+ timer0_pins: timer0-pins {
+ function = "timer0";
+ pins = "PA0", "PA1";
+ };
+ timer1_pins: timer1-pins {
+ function = "timer1";
+ pins = "PA2", "PA3";
+ };
+ timer2_pins: timer2-pins {
+ function = "timer2";
+ pins = "PA4", "PA5";
+ };
+ pps0_pins: pps0-pin {
+ function = "timer2";
+ pins = "PA4";
+ };
+ pps1_pins: pps1-pin {
+ function = "timer2";
+ pins = "PA5";
+ };
+ timer5_ext_pins: timer5-ext-pins {
+ function = "timer5";
+ pins = "PA6", "PA7", "PA8", "PA9";
+ };
+ timer5_ext_input_pins: timer5-ext-input-pins {
+ function = "timer5";
+ pins = "PA6", "PA7";
+ };
+ timer5_ext_incap_a_pins: timer5-ext-incap-a-pin {
+ function = "timer5";
+ pins = "PA6";
+ };
+ timer5_ext_incap_b_pins: timer5-ext-incap-b-pin {
+ function = "timer5";
+ pins = "PA7";
+ };
+ can0_pins: can0-pins {
+ function = "can0";
+ pins = "PA14", "PA15";
+ };
+ can1_pins: can1-pins {
+ function = "can1";
+ pins = "PA16", "PA17";
+ };
+ uart0_pins: uart0-pins {
+ function = "uart0";
+ pins = "PA10", "PA11";
+ };
+ uart1_pins: uart1-pins {
+ function = "uart1";
+ pins = "PA12", "PA13";
+ };
+ spi0_pins: spi0-pins {
+ function = "spi0";
+ pins = "PA18", "PA19", "PA20", "PA21", "PA22";
+ };
+ spi1_pins: spi1-pins {
+ function = "spi1";
+ pins = "PA23", "PA24", "PA25", "PA26", "PA27";
+ };
+ spi1_slave_pins: spi1-slave-pins {
+ function = "spi1";
+ pins = "PA24", "PA25", "PA26";
+ };
+ refclk0_pins: refclk0-pin {
+ function = "refclk0";
+ pins = "PA28";
+ };
+ timer3_pins: timer3-pins {
+ function = "timer3";
+ pins = "PB0", "PB1";
+ };
+ timer4_pins: timer4-pins {
+ function = "timer4";
+ pins = "PB2", "PB3";
+ };
+ timer6_ext_pins: timer6-ext-pins {
+ function = "timer6";
+ pins = "PB4", "PB5", "PB6", "PB7";
+ };
+ timer6_ext_input_pins: timer6-ext-input-pins {
+ function = "timer6";
+ pins = "PB4", "PB5";
+ };
+ timer6_ext_incap_a_pins: timer6-ext-incap-a-pin {
+ function = "timer6";
+ pins = "PB4";
+ };
+ timer6_ext_incap_b_pins: timer6-ext-incap-b-pin {
+ function = "timer6";
+ pins = "PB5";
+ };
+ can2_pins: can2-pins {
+ function = "can2";
+ pins = "PB10", "PB11";
+ };
+ uart2_pins: uart2-pins {
+ function = "uart2";
+ pins = "PB8", "PB9";
+ };
+ spi2_pins: spi2-pins {
+ function = "spi2";
+ pins = "PB12", "PB13", "PB14", "PB15", "PB16";
+ };
+ spi3_pins: spi3-pins {
+ function = "spi3";
+ pins = "PB17", "PB18", "PB19", "PB20", "PB21";
+ };
+ spi3_slave_pins: spi3-slave-pins {
+ function = "spi3";
+ pins = "PB18", "PB19", "PB20";
+ };
+ mclk0_pins: mclk0-pin {
+ function = "mclk0";
+ pins = "PB22";
+ };
+};
diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
index 76935f237ab5..8d4f65ec912d 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
@@ -79,6 +79,8 @@ uart0: serial@800000 {
clocks = <&uart_clk>, <&occ_periph>;
clock-names = "uartclk", "apb_pclk";
resets = <&reset 0 10>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
};
uart1: serial@900000 {
@@ -90,6 +92,8 @@ uart1: serial@900000 {
clocks = <&uart_clk>, <&occ_periph>;
clock-names = "uartclk", "apb_pclk";
resets = <&reset 0 11>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
};
uart2: serial@a00000 {
@@ -101,6 +105,8 @@ uart2: serial@a00000 {
clocks = <&uart_clk>, <&occ_periph>;
clock-names = "uartclk", "apb_pclk";
resets = <&reset 0 12>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
};
olb: system-controller@e00000 {
@@ -125,6 +131,11 @@ clocks: clock-controller@e0002c {
clocks = <&xtal>;
clock-names = "ref";
};
+
+ pinctrl: pinctrl@e000b0 {
+ compatible = "mobileye,eyeq5-pinctrl";
+ reg = <0x0b0 0x30>;
+ };
};
gic: interrupt-controller@140000 {
@@ -149,3 +160,5 @@ timer {
};
};
};
+
+#include "eyeq5-pins.dtsi"
--
2.44.0
^ permalink raw reply related
* [PATCH 10/11] MIPS: mobileye: eyeq5: add OLB reset controller node
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
Add devicetree node for the reset controller on Mobileye EyeQ5.
It appears as a subnode to the OLB syscon as its registers are located
in this shared register region.
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
index 1a65b43e13b1..76935f237ab5 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
@@ -78,6 +78,7 @@ uart0: serial@800000 {
interrupts = <GIC_SHARED 6 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_clk>, <&occ_periph>;
clock-names = "uartclk", "apb_pclk";
+ resets = <&reset 0 10>;
};
uart1: serial@900000 {
@@ -88,6 +89,7 @@ uart1: serial@900000 {
interrupts = <GIC_SHARED 6 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_clk>, <&occ_periph>;
clock-names = "uartclk", "apb_pclk";
+ resets = <&reset 0 11>;
};
uart2: serial@a00000 {
@@ -98,6 +100,7 @@ uart2: serial@a00000 {
interrupts = <GIC_SHARED 6 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&uart_clk>, <&occ_periph>;
clock-names = "uartclk", "apb_pclk";
+ resets = <&reset 0 12>;
};
olb: system-controller@e00000 {
@@ -107,6 +110,13 @@ olb: system-controller@e00000 {
#address-cells = <1>;
#size-cells = <1>;
+ reset: reset-controller@e00000 {
+ compatible = "mobileye,eyeq5-reset";
+ reg = <0x000 0x0c>, <0x200 0x34>, <0x120 0x04>;
+ reg-names = "d0", "d1", "d2";
+ #reset-cells = <2>;
+ };
+
clocks: clock-controller@e0002c {
compatible = "mobileye,eyeq5-clk";
reg = <0x02c 0x50>, <0x11c 0x04>;
--
2.44.0
^ permalink raw reply related
* [PATCH 09/11] MIPS: mobileye: eyeq5: use OLB clocks controller node
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
We add the clock controller inside the OLB syscon region and remove
previous fixed devicetree nodes representing PLLs exposed by the clock
controller.
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
.../{eyeq5-fixed-clocks.dtsi => eyeq5-clocks.dtsi} | 54 +++++++---------------
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 11 ++++-
2 files changed, 26 insertions(+), 39 deletions(-)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi
similarity index 88%
rename from arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi
rename to arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi
index 78f5533a95c6..aa6db704a786 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5-fixed-clocks.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi
@@ -3,42 +3,20 @@
* Copyright 2023 Mobileye Vision Technologies Ltd.
*/
+#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
+
/ {
/* Fixed clock */
- pll_cpu: pll-cpu {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <1500000000>;
- };
-
- pll_vdi: pll-vdi {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <1280000000>;
- };
-
- pll_per: pll-per {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <2000000000>;
- };
-
- pll_ddr0: pll-ddr0 {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <1857210000>;
- };
-
- pll_ddr1: pll-ddr1 {
+ xtal: xtal {
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <1857210000>;
+ clock-frequency = <30000000>;
};
/* PLL_CPU derivatives */
occ_cpu: occ-cpu {
compatible = "fixed-factor-clock";
- clocks = <&pll_cpu>;
+ clocks = <&clocks EQ5C_PLL_CPU>;
#clock-cells = <0>;
clock-div = <1>;
clock-mult = <1>;
@@ -101,7 +79,7 @@ mem_clk: mem-clk {
};
occ_isram: occ-isram {
compatible = "fixed-factor-clock";
- clocks = <&pll_cpu>;
+ clocks = <&clocks EQ5C_PLL_CPU>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
@@ -115,7 +93,7 @@ isram_clk: isram-clk { /* gate ClkRstGen_isram */
};
occ_dbu: occ-dbu {
compatible = "fixed-factor-clock";
- clocks = <&pll_cpu>;
+ clocks = <&clocks EQ5C_PLL_CPU>;
#clock-cells = <0>;
clock-div = <10>;
clock-mult = <1>;
@@ -130,7 +108,7 @@ si_dbu_tp_pclk: si-dbu-tp-pclk { /* gate ClkRstGen_dbu */
/* PLL_VDI derivatives */
occ_vdi: occ-vdi {
compatible = "fixed-factor-clock";
- clocks = <&pll_vdi>;
+ clocks = <&clocks EQ5C_PLL_VDI>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
@@ -144,7 +122,7 @@ vdi_clk: vdi-clk { /* gate ClkRstGen_vdi */
};
occ_can_ser: occ-can-ser {
compatible = "fixed-factor-clock";
- clocks = <&pll_vdi>;
+ clocks = <&clocks EQ5C_PLL_VDI>;
#clock-cells = <0>;
clock-div = <16>;
clock-mult = <1>;
@@ -158,7 +136,7 @@ can_ser_clk: can-ser-clk { /* gate ClkRstGen_can_ser */
};
i2c_ser_clk: i2c-ser-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_vdi>;
+ clocks = <&clocks EQ5C_PLL_VDI>;
#clock-cells = <0>;
clock-div = <20>;
clock-mult = <1>;
@@ -166,7 +144,7 @@ i2c_ser_clk: i2c-ser-clk {
/* PLL_PER derivatives */
occ_periph: occ-periph {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <16>;
clock-mult = <1>;
@@ -225,7 +203,7 @@ gpio_clk: gpio-clk {
};
emmc_sys_clk: emmc-sys-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <10>;
clock-mult = <1>;
@@ -233,7 +211,7 @@ emmc_sys_clk: emmc-sys-clk {
};
ccf_ctrl_clk: ccf-ctrl-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <4>;
clock-mult = <1>;
@@ -241,7 +219,7 @@ ccf_ctrl_clk: ccf-ctrl-clk {
};
occ_mjpeg_core: occ-mjpeg-core {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
@@ -265,7 +243,7 @@ mjpeg_core_clk: mjpeg-core-clk { /* gate ClkRstGen_mjpeg_gen */
};
fcmu_a_clk: fcmu-a-clk {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <20>;
clock-mult = <1>;
@@ -273,7 +251,7 @@ fcmu_a_clk: fcmu-a-clk {
};
occ_pci_sys: occ-pci-sys {
compatible = "fixed-factor-clock";
- clocks = <&pll_per>;
+ clocks = <&clocks EQ5C_PLL_PER>;
#clock-cells = <0>;
clock-div = <8>;
clock-mult = <1>;
diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
index e82d2a57f6da..1a65b43e13b1 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
@@ -5,7 +5,7 @@
#include <dt-bindings/interrupt-controller/mips-gic.h>
-#include "eyeq5-fixed-clocks.dtsi"
+#include "eyeq5-clocks.dtsi"
/ {
#address-cells = <2>;
@@ -106,6 +106,15 @@ olb: system-controller@e00000 {
ranges = <0x0 0x0 0xe00000 0x400>;
#address-cells = <1>;
#size-cells = <1>;
+
+ clocks: clock-controller@e0002c {
+ compatible = "mobileye,eyeq5-clk";
+ reg = <0x02c 0x50>, <0x11c 0x04>;
+ reg-names = "plls", "ospi";
+ #clock-cells = <1>;
+ clocks = <&xtal>;
+ clock-names = "ref";
+ };
};
gic: interrupt-controller@140000 {
--
2.44.0
^ permalink raw reply related
* [PATCH 08/11] MIPS: mobileye: eyeq5: add OLB syscon node
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
The OLB ("Other Logic Block") is a syscon region hosting clock, reset
and pin controllers. It contains registers such as I2C speed mode that
need to be accessible by other nodes.
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
arch/mips/boot/dts/mobileye/eyeq5.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
index 6cc5980e2fa1..e82d2a57f6da 100644
--- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi
+++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi
@@ -100,6 +100,14 @@ uart2: serial@a00000 {
clock-names = "uartclk", "apb_pclk";
};
+ olb: system-controller@e00000 {
+ compatible = "mobileye,eyeq5-olb", "syscon", "simple-mfd";
+ reg = <0 0xe00000 0x0 0x400>;
+ ranges = <0x0 0x0 0xe00000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
gic: interrupt-controller@140000 {
compatible = "mti,gic";
reg = <0x0 0x140000 0x0 0x20000>;
--
2.44.0
^ permalink raw reply related
* [PATCH 07/11] pinctrl: eyeq5: add platform driver
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
Add the Mobileye EyeQ5 pin controller driver. It belongs to a syscon
region called OLB.
Existing pins and their function live statically in the driver code
rather than in the devicetree, see compatible match data.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
MAINTAINERS | 2 +
drivers/pinctrl/Kconfig | 14 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-eyeq5.c | 579 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 596 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 724f20ea0411..5cede8039c1b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14927,12 +14927,14 @@ L: linux-mips@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml
F: Documentation/devicetree/bindings/mips/mobileye.yaml
+F: Documentation/devicetree/bindings/pinctrl/mobileye,eyeq5-pinctrl.yaml
F: Documentation/devicetree/bindings/reset/mobileye,eyeq5-reset.yaml
F: Documentation/devicetree/bindings/soc/mobileye/
F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/eyeq5_defconfig
F: arch/mips/mobileye/board-epm5.its.S
F: drivers/clk/clk-eyeq5.c
+F: drivers/pinctrl/pinctrl-eyeq5.c
F: drivers/reset/reset-eyeq5.c
F: include/dt-bindings/clock/mobileye,eyeq5-clk.h
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d45657aa986a..b266326372e2 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -213,6 +213,20 @@ config PINCTRL_EQUILIBRIUM
desired pin functions, configure GPIO attributes for LGM SoC pins.
Pin muxing and pin config settings are retrieved from device tree.
+config PINCTRL_EYEQ5
+ bool "Mobileye EyeQ5 pinctrl driver"
+ depends on MACH_EYEQ5 || COMPILE_TEST
+ select PINMUX
+ select GENERIC_PINCONF
+ select MFD_SYSCON
+ default MACH_EYEQ5
+ help
+ Pin controller driver for the Mobileye EyeQ5 platform. It does both
+ pin config & pin muxing. It does not handle GPIO.
+
+ Pin muxing supports two functions for each pin: first is GPIO, second
+ is pin-dependent. Pin config is about bias & drive strength.
+
config PINCTRL_GEMINI
bool
depends on ARCH_GEMINI
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 2152539b53d5..6113e980cdb2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o
obj-$(CONFIG_PINCTRL_DA9062) += pinctrl-da9062.o
obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o
obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o
+obj-$(CONFIG_PINCTRL_EYEQ5) += pinctrl-eyeq5.o
obj-$(CONFIG_PINCTRL_GEMINI) += pinctrl-gemini.o
obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o
obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o
diff --git a/drivers/pinctrl/pinctrl-eyeq5.c b/drivers/pinctrl/pinctrl-eyeq5.c
new file mode 100644
index 000000000000..3228fc2a026e
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-eyeq5.c
@@ -0,0 +1,579 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Pinctrl driver for the Mobileye EyeQ5 platform.
+ *
+ * The registers are located in a syscon region called OLB. There are two pin
+ * banks, each being controlled by 5 registers (see enum eq5p_regs) for
+ * pull-down, pull-up, drive strength and muxing.
+ *
+ * For each pin, muxing is between two functions: (0) GPIO or (1) another one
+ * that is pin-dependent. Functions are declared statically in this driver.
+ *
+ * We create pinctrl groups that are 1:1 equivalent to pins: each group has a
+ * single pin, and its index/selector is the pin number.
+ *
+ * We use eq5p_ as prefix, as-in "EyeQ5 Pinctrl", but way shorter.
+ *
+ * Copyright (C) 2024 Mobileye Vision Technologies Ltd.
+ */
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+struct eq5p_pinctrl {
+ struct pinctrl_desc desc;
+ void __iomem *base;
+};
+
+enum eq5p_bank {
+ EQ5P_BANK_A,
+ EQ5P_BANK_B,
+
+ EQ5P_BANK_COUNT,
+};
+
+enum eq5p_regs {
+ EQ5P_PD,
+ EQ5P_PU,
+ EQ5P_DS_LOW,
+ EQ5P_DS_HIGH,
+ EQ5P_IOCR,
+
+ EQ5P_REG_COUNT,
+};
+
+static const unsigned int eq5p_regs[EQ5P_BANK_COUNT][EQ5P_REG_COUNT] = {
+ [EQ5P_BANK_A] = {0x010, 0x014, 0x020, 0x024, 0x000},
+ [EQ5P_BANK_B] = {0x018, 0x01C, 0x028, 0x02C, 0x004},
+};
+
+/*
+ * Drive strength; two bits per pin.
+ */
+#define EQ5P_DS_MASK GENMASK(1, 0)
+
+/*
+ * Comments to the right of each pin are the "signal name" in the datasheet.
+ */
+static const struct pinctrl_pin_desc eq5p_pins[] = {
+ /* Bank A */
+ PINCTRL_PIN(0, "PA0"), /* A0_TIMER0_CK */
+ PINCTRL_PIN(1, "PA1"), /* A1_TIMER0_EOC */
+ PINCTRL_PIN(2, "PA2"), /* A2_TIMER1_CK */
+ PINCTRL_PIN(3, "PA3"), /* A3_TIMER1_EOC */
+ PINCTRL_PIN(4, "PA4"), /* A4_TIMER2_CK */
+ PINCTRL_PIN(5, "PA5"), /* A5_TIMER2_EOC */
+ PINCTRL_PIN(6, "PA6"), /* A6_TIMER5_EXT_INCAP1 */
+ PINCTRL_PIN(7, "PA7"), /* A7_TIMER5_EXT_INCAP2 */
+ PINCTRL_PIN(8, "PA8"), /* A8_TIMER5_EXT_OUTCMP1 */
+ PINCTRL_PIN(9, "PA9"), /* A9_TIMER5_EXT_OUTCMP2 */
+ PINCTRL_PIN(10, "PA10"), /* A10_UART_0_TX */
+ PINCTRL_PIN(11, "PA11"), /* A11_UART_0_RX */
+ PINCTRL_PIN(12, "PA12"), /* A12_UART_1_TX */
+ PINCTRL_PIN(13, "PA13"), /* A13_UART_1_RX */
+ PINCTRL_PIN(14, "PA14"), /* A14_CAN_0_TX */
+ PINCTRL_PIN(15, "PA15"), /* A15_CAN_0_RX */
+ PINCTRL_PIN(16, "PA16"), /* A16_CAN_1_TX */
+ PINCTRL_PIN(17, "PA17"), /* A17_CAN_1_RX */
+ PINCTRL_PIN(18, "PA18"), /* A18_SPI_0_DO */
+ PINCTRL_PIN(19, "PA19"), /* A19_SPI_0_DI */
+ PINCTRL_PIN(20, "PA20"), /* A20_SPI_0_CK */
+ PINCTRL_PIN(21, "PA21"), /* A21_SPI_0_CS0 */
+ PINCTRL_PIN(22, "PA22"), /* A22_SPI_0_CS1 */
+ PINCTRL_PIN(23, "PA23"), /* A23_SPI_1_DO */
+ PINCTRL_PIN(24, "PA24"), /* A24_SPI_1_DI */
+ PINCTRL_PIN(25, "PA25"), /* A25_SPI_1_CK */
+ PINCTRL_PIN(26, "PA26"), /* A26_SPI_1_CS0 */
+ PINCTRL_PIN(27, "PA27"), /* A27_SPI_1_CS1 */
+ PINCTRL_PIN(28, "PA28"), /* A28_REF_CLK0 */
+
+#define EQ5P_PIN_OFFSET_BANK_B 29
+
+ /* Bank B */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 0, "PB0"), /* B0_TIMER3_CK */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 1, "PB1"), /* B1_TIMER3_EOC */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 2, "PB2"), /* B2_TIMER4_CK */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 3, "PB3"), /* B3_TIMER4_EOC */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 4, "PB4"), /* B4_TIMER6_EXT_INCAP1 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 5, "PB5"), /* B5_TIMER6_EXT_INCAP2 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 6, "PB6"), /* B6_TIMER6_EXT_OUTCMP1 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 7, "PB7"), /* B7_TIMER6_EXT_OUTCMP2 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 8, "PB8"), /* B8_UART_2_TX */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 9, "PB9"), /* B9_UART_2_RX */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 10, "PB10"), /* B10_CAN_2_TX */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 11, "PB11"), /* B11_CAN_2_RX */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 12, "PB12"), /* B12_SPI_2_DO */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 13, "PB13"), /* B13_SPI_2_DI */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 14, "PB14"), /* B14_SPI_2_CK */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 15, "PB15"), /* B15_SPI_2_CS0 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 16, "PB16"), /* B16_SPI_2_CS1 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 17, "PB17"), /* B17_SPI_3_DO */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 18, "PB18"), /* B18_SPI_3_DI */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 19, "PB19"), /* B19_SPI_3_CK */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 20, "PB20"), /* B20_SPI_3_CS0 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 21, "PB21"), /* B21_SPI_3_CS1 */
+ PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 22, "PB22"), /* B22_MCLK0 */
+};
+
+static const char * const gpio_groups[] = {
+ /* Bank A */
+ "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7",
+ "PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15",
+ "PA16", "PA17", "PA18", "PA19", "PA20", "PA21", "PA22", "PA23",
+ "PA24", "PA25", "PA26", "PA27", "PA28",
+
+ /* Bank B */
+ "PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7",
+ "PB8", "PB9", "PB10", "PB11", "PB12", "PB13", "PB14", "PB15",
+ "PB16", "PB17", "PB18", "PB19", "PB20", "PB21", "PB22",
+};
+
+/* Groups of functions on bank A */
+static const char * const timer0_groups[] = { "PA0", "PA1" };
+static const char * const timer1_groups[] = { "PA2", "PA3" };
+static const char * const timer2_groups[] = { "PA4", "PA5" };
+static const char * const timer5_groups[] = { "PA6", "PA7", "PA8", "PA9" };
+static const char * const uart0_groups[] = { "PA10", "PA11" };
+static const char * const uart1_groups[] = { "PA12", "PA13" };
+static const char * const can0_groups[] = { "PA14", "PA15" };
+static const char * const can1_groups[] = { "PA16", "PA17" };
+static const char * const spi0_groups[] = { "PA18", "PA19", "PA20", "PA21", "PA22" };
+static const char * const spi1_groups[] = { "PA23", "PA24", "PA25", "PA26", "PA27" };
+static const char * const refclk0_groups[] = { "PA28" };
+
+/* Groups of functions on bank B */
+static const char * const timer3_groups[] = { "PB0", "PB1" };
+static const char * const timer4_groups[] = { "PB2", "PB3" };
+static const char * const timer6_groups[] = { "PB4", "PB5", "PB6", "PB7" };
+static const char * const uart2_groups[] = { "PB8", "PB9" };
+static const char * const can2_groups[] = { "PB10", "PB11" };
+static const char * const spi2_groups[] = { "PB12", "PB13", "PB14", "PB15", "PB16" };
+static const char * const spi3_groups[] = { "PB17", "PB18", "PB19", "PB20", "PB21" };
+static const char * const mclk0_groups[] = { "PB22" };
+
+static const struct pinfunction eq5p_functions[] = {
+ /* GPIO having a fixed index is depended upon, see GPIO_FUNC_SELECTOR. */
+ PINCTRL_PINFUNCTION("gpio", gpio_groups, ARRAY_SIZE(gpio_groups)),
+#define GPIO_FUNC_SELECTOR 0
+
+ /* Bank A functions */
+ PINCTRL_PINFUNCTION("timer0", timer0_groups, ARRAY_SIZE(timer0_groups)),
+ PINCTRL_PINFUNCTION("timer1", timer1_groups, ARRAY_SIZE(timer1_groups)),
+ PINCTRL_PINFUNCTION("timer2", timer2_groups, ARRAY_SIZE(timer2_groups)),
+ PINCTRL_PINFUNCTION("timer5", timer5_groups, ARRAY_SIZE(timer5_groups)),
+ PINCTRL_PINFUNCTION("uart0", uart0_groups, ARRAY_SIZE(uart0_groups)),
+ PINCTRL_PINFUNCTION("uart1", uart1_groups, ARRAY_SIZE(uart1_groups)),
+ PINCTRL_PINFUNCTION("can0", can0_groups, ARRAY_SIZE(can0_groups)),
+ PINCTRL_PINFUNCTION("can1", can1_groups, ARRAY_SIZE(can1_groups)),
+ PINCTRL_PINFUNCTION("spi0", spi0_groups, ARRAY_SIZE(spi0_groups)),
+ PINCTRL_PINFUNCTION("spi1", spi1_groups, ARRAY_SIZE(spi1_groups)),
+ PINCTRL_PINFUNCTION("refclk0", refclk0_groups, ARRAY_SIZE(refclk0_groups)),
+
+ /* Bank B functions */
+ PINCTRL_PINFUNCTION("timer3", timer3_groups, ARRAY_SIZE(timer3_groups)),
+ PINCTRL_PINFUNCTION("timer4", timer4_groups, ARRAY_SIZE(timer4_groups)),
+ PINCTRL_PINFUNCTION("timer6", timer6_groups, ARRAY_SIZE(timer6_groups)),
+ PINCTRL_PINFUNCTION("uart2", uart2_groups, ARRAY_SIZE(uart2_groups)),
+ PINCTRL_PINFUNCTION("can2", can2_groups, ARRAY_SIZE(can2_groups)),
+ PINCTRL_PINFUNCTION("spi2", spi2_groups, ARRAY_SIZE(spi2_groups)),
+ PINCTRL_PINFUNCTION("spi3", spi3_groups, ARRAY_SIZE(spi3_groups)),
+ PINCTRL_PINFUNCTION("mclk0", mclk0_groups, ARRAY_SIZE(mclk0_groups)),
+};
+
+static void eq5p_update_bits(const struct eq5p_pinctrl *pctrl,
+ enum eq5p_bank bank, enum eq5p_regs reg,
+ u32 mask, u32 val)
+{
+ void __iomem *ptr = pctrl->base + eq5p_regs[bank][reg];
+
+ writel((readl(ptr) & ~mask) | (val & mask), ptr);
+}
+
+static bool eq5p_test_bit(const struct eq5p_pinctrl *pctrl,
+ enum eq5p_bank bank, enum eq5p_regs reg, int offset)
+{
+ u32 val = readl(pctrl->base + eq5p_regs[bank][reg]);
+
+ if (WARN_ON(offset > 31))
+ return false;
+
+ return (val & BIT(offset)) != 0;
+}
+
+static enum eq5p_bank eq5p_pin_to_bank(unsigned int pin)
+{
+ if (pin < EQ5P_PIN_OFFSET_BANK_B)
+ return EQ5P_BANK_A;
+ else
+ return EQ5P_BANK_B;
+}
+
+static unsigned int eq5p_pin_to_offset(unsigned int pin)
+{
+ if (pin < EQ5P_PIN_OFFSET_BANK_B)
+ return pin;
+ else
+ return pin - EQ5P_PIN_OFFSET_BANK_B;
+}
+
+static int eq5p_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(eq5p_pins);
+}
+
+static const char *eq5p_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ return pctldev->desc->pins[selector].name;
+}
+
+static int eq5p_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ *pins = &pctldev->desc->pins[selector].number;
+ *num_pins = 1;
+ return 0;
+}
+
+static int eq5p_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *config)
+{
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int offset = eq5p_pin_to_offset(pin);
+ enum eq5p_bank bank = eq5p_pin_to_bank(pin);
+ u32 val_ds, arg;
+ bool pd, pu;
+
+ pd = eq5p_test_bit(pctrl, bank, EQ5P_PD, offset);
+ pu = eq5p_test_bit(pctrl, bank, EQ5P_PU, offset);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ arg = !(pd || pu);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ arg = pd;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ arg = pu;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ offset *= 2; /* two bits per pin */
+ if (offset >= 32) {
+ val_ds = readl(pctrl->base + eq5p_regs[bank][EQ5P_DS_HIGH]);
+ offset -= 32;
+ } else {
+ val_ds = readl(pctrl->base + eq5p_regs[bank][EQ5P_DS_LOW]);
+ }
+ arg = (val_ds >> offset) & EQ5P_DS_MASK;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static void eq5p_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+ unsigned int pin)
+{
+ struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const char *pin_name = pctrl->desc.pins[pin].name;
+ unsigned int offset = eq5p_pin_to_offset(pin);
+ enum eq5p_bank bank = eq5p_pin_to_bank(pin);
+ const char *func_name, *bias;
+ unsigned long ds_config;
+ u32 drive_strength;
+ bool pd, pu;
+ int i, j;
+
+ /*
+ * First, let's get the function name. All pins have only two functions:
+ * GPIO (IOCR == 0) and something else (IOCR == 1).
+ */
+ if (eq5p_test_bit(pctrl, bank, EQ5P_IOCR, offset)) {
+ func_name = NULL;
+ for (i = 0; i < ARRAY_SIZE(eq5p_functions); i++) {
+ if (i == GPIO_FUNC_SELECTOR)
+ continue;
+
+ for (j = 0; j < eq5p_functions[i].ngroups; j++) {
+ /* Groups and pins are the same thing for us. */
+ const char *x = eq5p_functions[i].groups[j];
+
+ if (strcmp(x, pin_name) == 0) {
+ func_name = eq5p_functions[i].name;
+ break;
+ }
+ }
+
+ if (func_name)
+ break;
+ }
+
+ /*
+ * We have not found the function attached to this pin, this
+ * should never occur as all pins have exactly two functions.
+ */
+ if (!func_name)
+ func_name = "unknown";
+ } else {
+ func_name = eq5p_functions[GPIO_FUNC_SELECTOR].name;
+ }
+
+ /* Second, we retrieve the bias. */
+ pd = eq5p_test_bit(pctrl, bank, EQ5P_PD, offset);
+ pu = eq5p_test_bit(pctrl, bank, EQ5P_PU, offset);
+ if (pd && pu)
+ bias = "both";
+ else if (pd && !pu)
+ bias = "pulldown";
+ else if (!pd && pu)
+ bias = "pullup";
+ else
+ bias = "none";
+
+ /* Third, we get the drive strength. */
+ ds_config = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, 0);
+ eq5p_pinconf_get(pctldev, pin, &ds_config);
+ drive_strength = pinconf_to_config_argument(ds_config);
+
+ seq_printf(s, "function=%s bias=%s drive_strength=%d",
+ func_name, bias, drive_strength);
+}
+
+static const struct pinctrl_ops eq5p_pinctrl_ops = {
+ .get_groups_count = eq5p_pinctrl_get_groups_count,
+ .get_group_name = eq5p_pinctrl_get_group_name,
+ .get_group_pins = eq5p_pinctrl_get_group_pins,
+ .pin_dbg_show = eq5p_pinctrl_pin_dbg_show,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int eq5p_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(eq5p_functions);
+}
+
+static const char *eq5p_pinmux_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ return eq5p_functions[selector].name;
+}
+
+static int eq5p_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int *num_groups)
+{
+ *groups = eq5p_functions[selector].groups;
+ *num_groups = eq5p_functions[selector].ngroups;
+ return 0;
+}
+
+static int eq5p_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int func_selector, unsigned int pin)
+{
+ struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const char *func_name = eq5p_functions[func_selector].name;
+ const char *group_name = pctldev->desc->pins[pin].name;
+ bool is_gpio = func_selector == GPIO_FUNC_SELECTOR;
+ unsigned int offset = eq5p_pin_to_offset(pin);
+ enum eq5p_bank bank = eq5p_pin_to_bank(pin);
+ u32 mask, val;
+
+ dev_dbg(pctldev->dev, "func=%s group=%s\n", func_name, group_name);
+
+ mask = BIT(offset);
+ val = is_gpio ? 0 : mask;
+ eq5p_update_bits(pctrl, bank, EQ5P_IOCR, mask, val);
+ return 0;
+}
+
+static int eq5p_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin)
+{
+ /* Pin numbers and group selectors are the same thing in our case. */
+ return eq5p_pinmux_set_mux(pctldev, GPIO_FUNC_SELECTOR, pin);
+}
+
+static const struct pinmux_ops eq5p_pinmux_ops = {
+ .get_functions_count = eq5p_pinmux_get_functions_count,
+ .get_function_name = eq5p_pinmux_get_function_name,
+ .get_function_groups = eq5p_pinmux_get_function_groups,
+ .set_mux = eq5p_pinmux_set_mux,
+ .gpio_request_enable = eq5p_pinmux_gpio_request_enable,
+ .strict = true,
+};
+
+static int eq5p_pinconf_set_drive_strength(struct pinctrl_dev *pctldev,
+ unsigned int pin, u32 arg)
+{
+ struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int offset = eq5p_pin_to_offset(pin);
+ enum eq5p_bank bank = eq5p_pin_to_bank(pin);
+ unsigned int reg;
+ u32 mask, val;
+
+ if (arg & ~EQ5P_DS_MASK) {
+ dev_err(pctldev->dev, "Unsupported drive strength: %u\n", arg);
+ return -EINVAL;
+ }
+
+ offset *= 2; /* two bits per pin */
+
+ if (offset >= 32) {
+ reg = EQ5P_DS_HIGH;
+ offset -= 32;
+ } else {
+ reg = EQ5P_DS_LOW;
+ }
+
+ mask = EQ5P_DS_MASK << offset;
+ val = arg << offset;
+ eq5p_update_bits(pctrl, bank, reg, mask, val);
+ return 0;
+}
+
+static int eq5p_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const char *pin_name = pctldev->desc->pins[pin].name;
+ unsigned int offset = eq5p_pin_to_offset(pin);
+ enum eq5p_bank bank = eq5p_pin_to_bank(pin);
+ struct device *dev = pctldev->dev;
+ u32 val = BIT(offset);
+ unsigned int i;
+
+ for (i = 0; i < num_configs; i++) {
+ enum pin_config_param param = pinconf_to_config_param(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ dev_dbg(dev, "pin=%s bias_disable\n", pin_name);
+
+ eq5p_update_bits(pctrl, bank, EQ5P_PD, val, 0);
+ eq5p_update_bits(pctrl, bank, EQ5P_PU, val, 0);
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ dev_dbg(dev, "pin=%s bias_pull_down arg=%u\n",
+ pin_name, arg);
+
+ if (arg == 0) /* cannot connect to GND */
+ return -ENOTSUPP;
+
+ eq5p_update_bits(pctrl, bank, EQ5P_PD, val, val);
+ eq5p_update_bits(pctrl, bank, EQ5P_PU, val, 0);
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ dev_dbg(dev, "pin=%s bias_pull_up arg=%u\n",
+ pin_name, arg);
+
+ if (arg == 0) /* cannot connect to VDD */
+ return -ENOTSUPP;
+
+ eq5p_update_bits(pctrl, bank, EQ5P_PD, val, 0);
+ eq5p_update_bits(pctrl, bank, EQ5P_PU, val, val);
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ dev_dbg(dev, "pin=%s drive_strength arg=%u\n",
+ pin_name, arg);
+
+ eq5p_pinconf_set_drive_strength(pctldev, pin, arg);
+ break;
+
+ default:
+ dev_err(dev, "Unsupported pinconf %u\n", param);
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops eq5p_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = eq5p_pinconf_get,
+ .pin_config_set = eq5p_pinconf_set,
+ /* Pins and groups are equivalent in this driver. */
+ .pin_config_group_get = eq5p_pinconf_get,
+ .pin_config_group_set = eq5p_pinconf_set,
+};
+
+static int eq5p_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pinctrl_dev *pctldev;
+ struct eq5p_pinctrl *pctrl;
+ int ret;
+
+ pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ pctrl->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pctrl->base))
+ return PTR_ERR(pctrl->base);
+
+ pctrl->desc.name = dev_name(dev);
+ pctrl->desc.pins = eq5p_pins;
+ pctrl->desc.npins = ARRAY_SIZE(eq5p_pins);
+ pctrl->desc.pctlops = &eq5p_pinctrl_ops;
+ pctrl->desc.pmxops = &eq5p_pinmux_ops;
+ pctrl->desc.confops = &eq5p_pinconf_ops;
+ pctrl->desc.owner = THIS_MODULE;
+
+ ret = devm_pinctrl_register_and_init(dev, &pctrl->desc, pctrl, &pctldev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed registering pinctrl device\n");
+
+ ret = pinctrl_enable(pctldev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed enabling pinctrl device\n");
+
+ return 0;
+}
+
+static const struct of_device_id eq5p_match[] = {
+ { .compatible = "mobileye,eyeq5-pinctrl" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, eq5p_match);
+
+static struct platform_driver eq5p_driver = {
+ .driver = {
+ .name = "eyeq5-pinctrl",
+ .of_match_table = eq5p_match,
+ },
+ .probe = eq5p_probe,
+};
+builtin_platform_driver(eq5p_driver);
--
2.44.0
^ permalink raw reply related
* [PATCH 06/11] reset: eyeq: add platform driver
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
Add Mobileye EyeQ reset controller driver, for EyeQ5, EyeQ6L and EyeQ6H
SoCs. Instances belong to a shared register region called OLB.
There is one OLB instance for EyeQ5 and EyeQ6L. There are seven OLB
instances on EyeQ6H; three have a reset controller embedded:
- West and east get handled by the same compatible.
- Acc is another one.
Each instance vary in the number and types of reset domains.
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
MAINTAINERS | 1 +
drivers/reset/Kconfig | 13 ++
drivers/reset/Makefile | 1 +
drivers/reset/reset-eyeq.c | 543 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 558 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 33168ebf3cc5..724f20ea0411 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14933,6 +14933,7 @@ F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/eyeq5_defconfig
F: arch/mips/mobileye/board-epm5.its.S
F: drivers/clk/clk-eyeq5.c
+F: drivers/reset/reset-eyeq5.c
F: include/dt-bindings/clock/mobileye,eyeq5-clk.h
MODULE SUPPORT
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 85b27c42cf65..18ee99ed8ecc 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -66,6 +66,19 @@ config RESET_BRCMSTB_RESCAL
This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on
BCM7216.
+config RESET_EYEQ
+ bool "Mobileye EyeQ reset controller"
+ depends on MFD_SYSCON
+ depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST
+ default MACH_EYEQ5 || MACH_EYEQ6H
+ help
+ This enables the Mobileye EyeQ reset controller, used in EyeQ5, EyeQ6L
+ and EyeQ6H SoCs.
+
+ It has one or more domains, with a varying number of resets in each.
+ Registers are located in a shared register region called OLB. EyeQ6H
+ has multiple reset instances.
+
config RESET_GPIO
tristate "GPIO reset controller"
help
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index fd8b49fa46fc..a4e6fea29800 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o
obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
+obj-$(CONFIG_RESET_EYEQ) += reset-eyeq.o
obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
diff --git a/drivers/reset/reset-eyeq.c b/drivers/reset/reset-eyeq.c
new file mode 100644
index 000000000000..b86930145256
--- /dev/null
+++ b/drivers/reset/reset-eyeq.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Reset driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms.
+ *
+ * Controllers live in a shared register region called OLB. EyeQ5 and EyeQ6L
+ * have a single OLB instance for a single reset controller. EyeQ6H has seven
+ * OLB instances; three host reset controllers.
+ *
+ * Each reset controller has one or more domain. Domains are of a given type
+ * (see enum eqr_domain_type), with a valid offset mask (up to 32 resets per
+ * domain).
+ *
+ * Domain types define expected behavior: one-register-per-reset,
+ * one-bit-per-reset, status detection method, busywait duration, etc.
+ *
+ * We use eqr_ as prefix, as-in "EyeQ Reset", but way shorter.
+ *
+ * Known resets in EyeQ5 domain 0 (type EQR_EYEQ5_SARCR):
+ * 3. CAN0 4. CAN1 5. CAN2 6. SPI0
+ * 7. SPI1 8. SPI2 9. SPI3 10. UART0
+ * 11. UART1 12. UART2 13. I2C0 14. I2C1
+ * 15. I2C2 16. I2C3 17. I2C4 18. TIMER0
+ * 19. TIMER1 20. TIMER2 21. TIMER3 22. TIMER4
+ * 23. WD0 24. EXT0 25. EXT1 26. GPIO
+ * 27. WD1
+ *
+ * Known resets in EyeQ5 domain 1 (type EQR_EYEQ5_ACRP):
+ * 0. VMP0 1. VMP1 2. VMP2 3. VMP3
+ * 4. PMA0 5. PMA1 6. PMAC0 7. PMAC1
+ * 8. MPC0 9. MPC1 10. MPC2 11. MPC3
+ * 12. MPC4
+ *
+ * Known resets in EyeQ5 domain 2 (type EQR_EYEQ5_PCIE):
+ * 0. PCIE0_CORE 1. PCIE0_APB 2. PCIE0_LINK_AXI 3. PCIE0_LINK_MGMT
+ * 4. PCIE0_LINK_HOT 5. PCIE0_LINK_PIPE 6. PCIE1_CORE 7. PCIE1_APB
+ * 8. PCIE1_LINK_AXI 9. PCIE1_LINK_MGMT 10. PCIE1_LINK_HOT 11. PCIE1_LINK_PIPE
+ * 12. MULTIPHY 13. MULTIPHY_APB 15. PCIE0_LINK_MGMT 16. PCIE1_LINK_MGMT
+ * 17. PCIE0_LINK_PM 18. PCIE1_LINK_PM
+ *
+ * Known resets in EyeQ6L domain 0 (type EQR_EYEQ5_SARCR):
+ * 0. SPI0 1. SPI1 2. UART0 3. I2C0
+ * 4. I2C1 5. TIMER0 6. TIMER1 7. TIMER2
+ * 8. TIMER3 9. WD0 10. WD1 11. EXT0
+ * 12. EXT1 13. GPIO
+ *
+ * Known resets in EyeQ6L domain 1 (type EQR_EYEQ5_ACRP):
+ * 0. VMP0 1. VMP1 2. VMP2 3. VMP3
+ * 4. PMA0 5. PMA1 6. PMAC0 7. PMAC1
+ * 8. MPC0 9. MPC1 10. MPC2 11. MPC3
+ * 12. MPC4
+ *
+ * Known resets in EyeQ6H west/east (type EQR_EYEQ6H_SARCR):
+ * 0. CAN 1. SPI0 2. SPI1 3. UART0
+ * 4. UART1 5. I2C0 6. I2C1 7. -hole-
+ * 8. TIMER0 9. TIMER1 10. WD 11. EXT TIMER
+ * 12. GPIO
+ *
+ * Known resets in EyeQ6H acc (type EQR_EYEQ5_ACRP):
+ * 1. XNN0 2. XNN1 3. XNN2 4. XNN3
+ * 5. VMP0 6. VMP1 7. VMP2 8. VMP3
+ * 9. PMA0 10. PMA1 11. MPC0 12. MPC1
+ * 13. MPC2 14. MPC3 15. PERIPH
+ *
+ * Abbreviations:
+ * - PMA: Programmable Macro Array
+ * - MPC: Multi-threaded Processing Clusters
+ * - VMP: Vector Microcode Processors
+ *
+ * Copyright (C) 2024 Mobileye Vision Technologies Ltd.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/cleanup.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/lockdep.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/*
+ * A reset ID, as returned by eqr_of_xlate, is a (domain, offset) pair.
+ * Low byte is domain, rest is offset.
+ */
+#define ID_DOMAIN_MASK GENMASK(7, 0)
+#define ID_OFFSET_MASK GENMASK(31, 8)
+
+enum eqr_domain_type {
+ EQR_EYEQ5_SARCR,
+ EQR_EYEQ5_ACRP,
+ EQR_EYEQ5_PCIE,
+ EQR_EYEQ6H_SARCR,
+};
+
+/*
+ * Domain type EQR_EYEQ5_SARCR register offsets.
+ */
+#define EQR_EYEQ5_SARCR_REQUEST (0x004)
+#define EQR_EYEQ5_SARCR_STATUS (0x008)
+
+/*
+ * Domain type EQR_EYEQ5_ACRP register masks.
+ * Registers are: base + 4 * offset.
+ */
+#define EQR_EYEQ5_ACRP_PD_REQ BIT(0)
+#define EQR_EYEQ5_ACRP_ST_POWER_DOWN BIT(27)
+#define EQR_EYEQ5_ACRP_ST_ACTIVE BIT(29)
+
+/*
+ * Domain type EQR_EYEQ6H_SARCR register offsets.
+ */
+#define EQR_EYEQ6H_SARCR_RST_REQUEST (0x004)
+#define EQR_EYEQ6H_SARCR_CLK_STATUS (0x008)
+#define EQR_EYEQ6H_SARCR_RST_STATUS (0x00C)
+#define EQR_EYEQ6H_SARCR_CLK_REQUEST (0x010)
+
+struct eqr_busy_wait_timings {
+ unsigned long sleep_us;
+ unsigned long timeout_us;
+};
+
+static const struct eqr_busy_wait_timings eqr_timings[] = {
+ [EQR_EYEQ5_SARCR] = {1, 10},
+ [EQR_EYEQ5_ACRP] = {1, 40 * USEC_PER_MSEC}, /* LBIST implies long timeout. */
+ /* EQR_EYEQ5_PCIE does no busy waiting. */
+ [EQR_EYEQ6H_SARCR] = {1, 400},
+};
+
+#define EQR_MAX_DOMAIN_COUNT 3
+
+struct eqr_domain_descriptor {
+ const char *resource_name;
+ enum eqr_domain_type type;
+ u32 valid_mask;
+};
+
+struct eqr_match_data {
+ unsigned int domain_count;
+ const struct eqr_domain_descriptor *domains;
+};
+
+struct eqr_private {
+ struct mutex mutexes[EQR_MAX_DOMAIN_COUNT];
+ void __iomem *bases[EQR_MAX_DOMAIN_COUNT];
+ const struct eqr_match_data *data;
+ struct reset_controller_dev rcdev;
+};
+
+#define rcdev_to_priv(rcdev) container_of(rcdev, struct eqr_private, rcdev)
+
+static u32 eqr_double_readl(void __iomem *addr_a, void __iomem *addr_b,
+ u32 *dest_a, u32 *dest_b)
+{
+ *dest_a = readl(addr_a);
+ *dest_b = readl(addr_b);
+ return 0; /* read_poll_timeout() op argument must return something. */
+}
+
+static int eqr_busy_wait_locked(struct eqr_private *priv, struct device *dev,
+ u32 domain, u32 offset, bool assert)
+{
+ enum eqr_domain_type domain_type = priv->data->domains[domain].type;
+ unsigned long sleep_us, timeout_us;
+ u32 val, mask, val0, val1;
+ void __iomem *base, *reg;
+ int ret;
+
+ lockdep_assert_held(&priv->mutexes[domain]);
+
+ base = priv->bases[domain];
+ sleep_us = eqr_timings[domain_type].sleep_us;
+ timeout_us = eqr_timings[domain_type].timeout_us;
+
+ switch (domain_type) {
+ case EQR_EYEQ5_SARCR:
+ reg = base + EQR_EYEQ5_SARCR_STATUS;
+ mask = BIT(offset);
+
+ ret = readl_poll_timeout(reg, val, !(val & mask) == assert,
+ sleep_us, timeout_us);
+ break;
+
+ case EQR_EYEQ5_ACRP:
+ reg = base + 4 * offset;
+ if (assert)
+ mask = EQR_EYEQ5_ACRP_ST_POWER_DOWN;
+ else
+ mask = EQR_EYEQ5_ACRP_ST_ACTIVE;
+
+ ret = readl_poll_timeout(reg, val, !!(val & mask),
+ sleep_us, timeout_us);
+ break;
+
+ case EQR_EYEQ5_PCIE:
+ ret = 0; /* No busy waiting. */
+ break;
+
+ case EQR_EYEQ6H_SARCR:
+ /*
+ * Wait until both bits change:
+ * readl(base + EQR_EYEQ6H_SARCR_RST_STATUS) & BIT(offset)
+ * readl(base + EQR_EYEQ6H_SARCR_CLK_STATUS) & BIT(offset)
+ */
+ mask = BIT(offset);
+ ret = read_poll_timeout(eqr_double_readl, val,
+ (!(val0 & mask) == assert) &&
+ (!(val1 & mask) == assert),
+ sleep_us, timeout_us, false,
+ base + EQR_EYEQ6H_SARCR_RST_STATUS,
+ base + EQR_EYEQ6H_SARCR_CLK_STATUS,
+ &val0, &val1);
+ break;
+
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == -ETIMEDOUT)
+ dev_dbg(dev, "%u-%u: timeout\n", domain, offset);
+ return ret;
+}
+
+static void eqr_assert_locked(struct eqr_private *priv, u32 domain,
+ u32 offset)
+{
+ enum eqr_domain_type domain_type = priv->data->domains[domain].type;
+ void __iomem *base, *reg;
+ u32 val;
+
+ lockdep_assert_held(&priv->mutexes[domain]);
+
+ base = priv->bases[domain];
+
+ switch (domain_type) {
+ case EQR_EYEQ5_SARCR:
+ reg = base + EQR_EYEQ5_SARCR_REQUEST;
+ writel(readl(reg) & ~BIT(offset), reg);
+ break;
+
+ case EQR_EYEQ5_ACRP:
+ reg = base + 4 * offset;
+ writel(readl(reg) | EQR_EYEQ5_ACRP_PD_REQ, reg);
+ break;
+
+ case EQR_EYEQ5_PCIE:
+ writel(readl(base) & ~BIT(offset), base);
+ break;
+
+ case EQR_EYEQ6H_SARCR:
+ val = readl(base + EQR_EYEQ6H_SARCR_RST_REQUEST);
+ val &= ~BIT(offset);
+ writel(val, base + EQR_EYEQ6H_SARCR_RST_REQUEST);
+ writel(val, base + EQR_EYEQ6H_SARCR_CLK_REQUEST);
+ break;
+
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static int eqr_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct eqr_private *priv = rcdev_to_priv(rcdev);
+ u32 domain = FIELD_GET(ID_DOMAIN_MASK, id);
+ u32 offset = FIELD_GET(ID_OFFSET_MASK, id);
+
+ dev_dbg(rcdev->dev, "%u-%u: assert request\n", domain, offset);
+
+ guard(mutex)(&priv->mutexes[domain]);
+ eqr_assert_locked(priv, domain, offset);
+ return eqr_busy_wait_locked(priv, rcdev->dev, domain, offset, true);
+}
+
+static void eqr_deassert_locked(struct eqr_private *priv, u32 domain,
+ u32 offset)
+{
+ enum eqr_domain_type domain_type = priv->data->domains[domain].type;
+ void __iomem *base, *reg;
+ u32 val;
+
+ lockdep_assert_held(&priv->mutexes[domain]);
+
+ base = priv->bases[domain];
+
+ switch (domain_type) {
+ case EQR_EYEQ5_SARCR:
+ reg = base + EQR_EYEQ5_SARCR_REQUEST;
+ writel(readl(reg) | BIT(offset), reg);
+ break;
+
+ case EQR_EYEQ5_ACRP:
+ reg = base + 4 * offset;
+ writel(readl(reg) & ~EQR_EYEQ5_ACRP_PD_REQ, reg);
+ break;
+
+ case EQR_EYEQ5_PCIE:
+ writel(readl(base) | BIT(offset), base);
+ break;
+
+ case EQR_EYEQ6H_SARCR:
+ val = readl(base + EQR_EYEQ6H_SARCR_RST_REQUEST);
+ val |= BIT(offset);
+ writel(val, base + EQR_EYEQ6H_SARCR_RST_REQUEST);
+ writel(val, base + EQR_EYEQ6H_SARCR_CLK_REQUEST);
+ break;
+
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static int eqr_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct eqr_private *priv = rcdev_to_priv(rcdev);
+ u32 domain = FIELD_GET(ID_DOMAIN_MASK, id);
+ u32 offset = FIELD_GET(ID_OFFSET_MASK, id);
+
+ dev_dbg(rcdev->dev, "%u-%u: deassert request\n", domain, offset);
+
+ guard(mutex)(&priv->mutexes[domain]);
+ eqr_deassert_locked(priv, domain, offset);
+ return eqr_busy_wait_locked(priv, rcdev->dev, domain, offset, false);
+}
+
+static int eqr_status(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 domain = FIELD_GET(ID_DOMAIN_MASK, id);
+ struct eqr_private *priv = rcdev_to_priv(rcdev);
+ enum eqr_domain_type domain_type = priv->data->domains[domain].type;
+ u32 offset = FIELD_GET(ID_OFFSET_MASK, id);
+ void __iomem *base, *reg;
+
+ dev_dbg(rcdev->dev, "%u-%u: status request\n", domain, offset);
+
+ guard(mutex)(&priv->mutexes[domain]);
+
+ base = priv->bases[domain];
+
+ switch (domain_type) {
+ case EQR_EYEQ5_SARCR:
+ reg = base + EQR_EYEQ5_SARCR_STATUS;
+ return !(readl(reg) & BIT(offset));
+ case EQR_EYEQ5_ACRP:
+ reg = base + 4 * offset;
+ return !(readl(reg) & EQR_EYEQ5_ACRP_ST_ACTIVE);
+ case EQR_EYEQ5_PCIE:
+ return !(readl(base) & BIT(offset));
+ case EQR_EYEQ6H_SARCR:
+ reg = base + EQR_EYEQ6H_SARCR_RST_STATUS;
+ return !(readl(reg) & BIT(offset));
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct reset_control_ops eqr_ops = {
+ .assert = eqr_assert,
+ .deassert = eqr_deassert,
+ .status = eqr_status,
+};
+
+static int eqr_of_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ struct eqr_private *priv = rcdev_to_priv(rcdev);
+ u32 domain, offset;
+
+ /* Args count is expected to be 1 iff domain count is 1. */
+ if (reset_spec->args_count == 1) {
+ WARN_ON(priv->data->domain_count > 1);
+ domain = 0;
+ offset = reset_spec->args[0];
+ } else if (reset_spec->args_count == 2) {
+ WARN_ON(priv->data->domain_count < 2);
+ domain = reset_spec->args[0];
+ offset = reset_spec->args[1];
+ } else {
+ return -EINVAL;
+ }
+
+ if (domain >= priv->data->domain_count || offset > 31 ||
+ !(priv->data->domains[domain].valid_mask & BIT(offset))) {
+ dev_err(rcdev->dev, "%u-%u: invalid reset\n", domain, offset);
+ return -EINVAL;
+ }
+
+ return FIELD_PREP(ID_DOMAIN_MASK, domain) | FIELD_PREP(ID_OFFSET_MASK, offset);
+}
+
+static int eqr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct eqr_private *priv;
+ unsigned int i;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->data = device_get_match_data(dev);
+ if (!priv->data)
+ return -ENODEV;
+
+ priv->rcdev.ops = &eqr_ops;
+ priv->rcdev.owner = THIS_MODULE;
+ priv->rcdev.dev = dev;
+ priv->rcdev.of_node = np;
+ priv->rcdev.of_xlate = eqr_of_xlate;
+
+ if (priv->data->domain_count == 1) {
+ priv->rcdev.of_reset_n_cells = 1;
+
+ /* Single domain means single unnamed resource. Ignore resource name. */
+ priv->bases[0] = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->bases[0]))
+ return PTR_ERR(priv->bases[0]);
+ } else {
+ priv->rcdev.of_reset_n_cells = 2;
+
+ /* Multiple domains means named resources. */
+ for (i = 0; i < priv->data->domain_count; i++) {
+ const char *res_name = priv->data->domains[i].resource_name;
+
+ priv->bases[i] = devm_platform_ioremap_resource_byname(pdev, res_name);
+ if (IS_ERR(priv->bases[i]))
+ return PTR_ERR(priv->bases[i]);
+ }
+ }
+
+ for (i = 0; i < priv->data->domain_count; i++)
+ mutex_init(&priv->mutexes[i]);
+
+ priv->rcdev.nr_resets = 0;
+ for (i = 0; i < priv->data->domain_count; i++)
+ priv->rcdev.nr_resets += hweight32(priv->data->domains[i].valid_mask);
+
+ ret = devm_reset_controller_register(dev, &priv->rcdev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed registering reset controller\n");
+
+ return 0;
+}
+
+static const struct eqr_domain_descriptor eqr_eyeq5_domains[] = {
+ {
+ .resource_name = "d0",
+ .type = EQR_EYEQ5_SARCR,
+ .valid_mask = 0xFFFFFF8,
+ },
+ {
+ .resource_name = "d1",
+ .type = EQR_EYEQ5_ACRP,
+ .valid_mask = 0x0001FFF,
+ },
+ {
+ .resource_name = "d2",
+ .type = EQR_EYEQ5_PCIE,
+ .valid_mask = 0x007BFFF,
+ },
+};
+
+static const struct eqr_match_data eqr_eyeq5_data = {
+ .domain_count = ARRAY_SIZE(eqr_eyeq5_domains),
+ .domains = eqr_eyeq5_domains,
+};
+
+static const struct eqr_domain_descriptor eqr_eyeq6l_domains[] = {
+ {
+ .resource_name = "d0",
+ .type = EQR_EYEQ5_SARCR,
+ .valid_mask = 0x3FFF,
+ },
+ {
+ .resource_name = "d1",
+ .type = EQR_EYEQ5_ACRP,
+ .valid_mask = 0x00FF,
+ },
+};
+
+static const struct eqr_match_data eqr_eyeq6l_data = {
+ .domain_count = ARRAY_SIZE(eqr_eyeq6l_domains),
+ .domains = eqr_eyeq6l_domains,
+};
+
+/* West and east OLBs each have an instance. */
+static const struct eqr_domain_descriptor eqr_eyeq6h_we_domains[] = {
+ {
+ .type = EQR_EYEQ6H_SARCR,
+ .valid_mask = 0x1F7F,
+ },
+};
+
+static const struct eqr_match_data eqr_eyeq6h_we_data = {
+ .domain_count = ARRAY_SIZE(eqr_eyeq6h_we_domains),
+ .domains = eqr_eyeq6h_we_domains,
+};
+
+static const struct eqr_domain_descriptor eqr_eyeq6h_acc_domains[] = {
+ {
+ .type = EQR_EYEQ5_ACRP,
+ .valid_mask = 0x7FFF,
+ },
+};
+
+static const struct eqr_match_data eqr_eyeq6h_acc_data = {
+ .domain_count = ARRAY_SIZE(eqr_eyeq6h_acc_domains),
+ .domains = eqr_eyeq6h_acc_domains,
+};
+
+static const struct of_device_id eqr_match_table[] = {
+ { .compatible = "mobileye,eyeq5-reset", .data = &eqr_eyeq5_data },
+ { .compatible = "mobileye,eyeq6l-reset", .data = &eqr_eyeq6l_data },
+ { .compatible = "mobileye,eyeq6h-we-reset", .data = &eqr_eyeq6h_we_data },
+ { .compatible = "mobileye,eyeq6h-acc-reset", .data = &eqr_eyeq6h_acc_data },
+ {}
+};
+
+static struct platform_driver eqr_driver = {
+ .probe = eqr_probe,
+ .driver = {
+ .name = "eyeq5-reset",
+ .of_match_table = eqr_match_table,
+ },
+};
+builtin_platform_driver(eqr_driver);
--
2.44.0
^ permalink raw reply related
* [PATCH 05/11] clk: eyeq: add driver
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
Add Mobileye EyeQ5, EyeQ6L and EyeQ6H clock controller driver. It is
both a platform driver and a hook onto of_clk_init() used for clocks
required early (GIC timer, UARTs).
For some compatible, it is both at the same time. eqc_init() initialises
early PLLs and stores clock array in a static linked list. It marks
other clocks as deferred. eqc_probe() retrieves the clock array and
adds all remaining clocks.
It exposes read-only PLLs derived from the main crystal on board. It
also exposes another type of clocks: divider clocks. They always have
even divisors and have one PLL as parent.
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
MAINTAINERS | 1 +
drivers/clk/Kconfig | 11 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-eyeq.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 657 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 42553da10be9..33168ebf3cc5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14932,6 +14932,7 @@ F: Documentation/devicetree/bindings/soc/mobileye/
F: arch/mips/boot/dts/mobileye/
F: arch/mips/configs/eyeq5_defconfig
F: arch/mips/mobileye/board-epm5.its.S
+F: drivers/clk/clk-eyeq5.c
F: include/dt-bindings/clock/mobileye,eyeq5-clk.h
MODULE SUPPORT
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 50af5fc7f570..1eb6e70977a3 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -218,6 +218,17 @@ config COMMON_CLK_EN7523
This driver provides the fixed clocks and gates present on Airoha
ARM silicon.
+config COMMON_CLK_EYEQ
+ bool "Clock driver for the Mobileye EyeQ platform"
+ depends on OF || COMPILE_TEST
+ depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST
+ default MACH_EYEQ5 || MACH_EYEQ6H
+ help
+ This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H
+ SoCs. Controllers live in shared register regions called OLB. Driver
+ provides read-only PLLs, derived from the main crystal clock (which
+ must be constant). It also exposes some divider clocks.
+
config COMMON_CLK_FSL_FLEXSPI
tristate "Clock driver for FlexSPI on Layerscape SoCs"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 14fa8d4ecc1f..52de92309aa8 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
+obj-$(CONFIG_COMMON_CLK_EYEQ) += clk-eyeq.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c
new file mode 100644
index 000000000000..bb2535010ae6
--- /dev/null
+++ b/drivers/clk/clk-eyeq.c
@@ -0,0 +1,644 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms.
+ *
+ * This controller handles read-only PLLs, all derived from the same main
+ * crystal clock. It also exposes divider clocks, those are children to PLLs.
+ * Parent clock is expected to be constant. This driver's registers live in
+ * a shared region called OLB. Some PLLs are initialised early by of_clk_init().
+ *
+ * We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter.
+ *
+ * Copyright (C) 2024 Mobileye Vision Technologies Ltd.
+ */
+
+#define pr_fmt(fmt) "clk-eyeq: " fmt
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
+
+#define EQC_MAX_DIV_COUNT 4
+
+/* In frac mode, it enables fractional noise canceling DAC. Else, no function. */
+#define PCSR0_DAC_EN BIT(0)
+/* Fractional or integer mode */
+#define PCSR0_DSM_EN BIT(1)
+#define PCSR0_PLL_EN BIT(2)
+/* All clocks output held at 0 */
+#define PCSR0_FOUTPOSTDIV_EN BIT(3)
+#define PCSR0_POST_DIV1 GENMASK(6, 4)
+#define PCSR0_POST_DIV2 GENMASK(9, 7)
+#define PCSR0_REF_DIV GENMASK(15, 10)
+#define PCSR0_INTIN GENMASK(27, 16)
+#define PCSR0_BYPASS BIT(28)
+/* Bits 30..29 are reserved */
+#define PCSR0_PLL_LOCKED BIT(31)
+
+#define PCSR1_RESET BIT(0)
+#define PCSR1_SSGC_DIV GENMASK(4, 1)
+/* Spread amplitude (% = 0.1 * SPREAD[4:0]) */
+#define PCSR1_SPREAD GENMASK(9, 5)
+#define PCSR1_DIS_SSCG BIT(10)
+/* Down-spread or center-spread */
+#define PCSR1_DOWN_SPREAD BIT(11)
+#define PCSR1_FRAC_IN GENMASK(31, 12)
+
+/*
+ * Driver might register clock provider from eqc_init() if PLLs are required
+ * early (before platform bus is ready). Store struct eqc_priv inside linked
+ * list to pass clock provider from eqc_init() to eqc_probe() and register
+ * remaining clocks from platform device probe.
+ *
+ * Clock provider is NOT created by eqc_init() if no early clock is required.
+ * Store as linked list because EyeQ6H has multiple clock controller instances.
+ * Matching is done based on devicetree node pointer.
+ */
+static DEFINE_SPINLOCK(eqc_list_slock);
+static LIST_HEAD(eqc_list);
+
+struct eqc_pll {
+ unsigned int index;
+ const char *name;
+ u32 reg64;
+};
+
+/*
+ * Divider clock. Divider is 2*(v+1), with v the register value.
+ * Min divider is 2, max is 2*(2^width).
+ */
+struct eqc_div {
+ unsigned int index;
+ const char *name;
+ unsigned int parent;
+ const char *resource_name;
+ u8 shift;
+ u8 width;
+};
+
+struct eqc_match_data {
+ unsigned int early_pll_count;
+ const struct eqc_pll *early_plls;
+
+ unsigned int pll_count;
+ const struct eqc_pll *plls;
+
+ unsigned int div_count;
+ const struct eqc_div *divs;
+};
+
+struct eqc_priv {
+ struct clk_hw_onecell_data *cells;
+ const struct eqc_match_data *data;
+ void __iomem *base_plls;
+ struct device_node *np;
+ struct list_head list;
+};
+
+static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult,
+ unsigned long *div, unsigned long *acc)
+{
+ if (r0 & PCSR0_BYPASS) {
+ *mult = 1;
+ *div = 1;
+ *acc = 0;
+ return 0;
+ }
+
+ if (!(r0 & PCSR0_PLL_LOCKED))
+ return -EINVAL;
+
+ *mult = FIELD_GET(PCSR0_INTIN, r0);
+ *div = FIELD_GET(PCSR0_REF_DIV, r0);
+ if (r0 & PCSR0_FOUTPOSTDIV_EN)
+ *div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0);
+
+ /* Fractional mode, in 2^20 (0x100000) parts. */
+ if (r0 & PCSR0_DSM_EN) {
+ *div *= 0x100000;
+ *mult = *mult * 0x100000 + FIELD_GET(PCSR1_FRAC_IN, r1);
+ }
+
+ if (!*mult || !*div)
+ return -EINVAL;
+
+ /* Spread spectrum. */
+ if (!(r1 & (PCSR1_RESET | PCSR1_DIS_SSCG))) {
+ /*
+ * Spread is 1/1000 parts of frequency, accuracy is half of
+ * that. To get accuracy, convert to ppb (parts per billion).
+ */
+ u32 spread = FIELD_GET(PCSR1_SPREAD, r1);
+
+ *acc = spread * 500000;
+ if (r1 & PCSR1_DOWN_SPREAD) {
+ /*
+ * Downspreading: the central frequency is half a
+ * spread lower.
+ */
+ *mult *= 2000 - spread;
+ *div *= 2000;
+ }
+ } else {
+ *acc = 0;
+ }
+
+ return 0;
+}
+
+static unsigned int eqc_compute_clock_count(const struct eqc_match_data *data)
+{
+ unsigned int i, nb_clks = 0;
+
+ for (i = 0; i < data->early_pll_count; i++)
+ if (data->early_plls[i].index >= nb_clks)
+ nb_clks = data->early_plls[i].index + 1;
+ for (i = 0; i < data->pll_count; i++)
+ if (data->plls[i].index >= nb_clks)
+ nb_clks = data->plls[i].index + 1;
+ for (i = 0; i < data->div_count; i++)
+ if (data->divs[i].index >= nb_clks)
+ nb_clks = data->divs[i].index + 1;
+
+ /* We expect the biggest clock index to be 1 below the clock count. */
+ WARN_ON(nb_clks != data->early_pll_count + data->pll_count + data->div_count);
+
+ return nb_clks;
+}
+
+static int eqc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ void __iomem *div_resources[EQC_MAX_DIV_COUNT];
+ struct device_node *np = dev->of_node;
+ const struct eqc_match_data *data;
+ struct eqc_priv *priv = NULL;
+ struct clk_hw *hw;
+ unsigned int i;
+
+ data = device_get_match_data(dev);
+ if (!data)
+ return -ENODEV;
+
+ if (data->early_pll_count) {
+ /* Device got inited early. Retrieve clock provider from list. */
+ struct eqc_priv *entry;
+
+ spin_lock(&eqc_list_slock);
+ list_for_each_entry(entry, &eqc_list, list) {
+ if (entry->np == np) {
+ priv = entry;
+ break;
+ }
+ }
+ spin_unlock(&eqc_list_slock);
+
+ if (!priv)
+ return -ENODEV;
+ } else {
+ /* Device did NOT get init early. Do it now. */
+ unsigned int nb_clks;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->np = np;
+ priv->data = data;
+
+ nb_clks = eqc_compute_clock_count(data);
+ priv->cells = devm_kzalloc(dev, struct_size(priv->cells, hws, nb_clks),
+ GFP_KERNEL);
+ if (!priv->cells)
+ return -ENOMEM;
+
+ priv->cells->num = nb_clks;
+
+ /*
+ * We expect named resources if divider clocks are present.
+ * Else, we only expect one resource.
+ */
+ if (data->div_count)
+ priv->base_plls = devm_platform_ioremap_resource_byname(pdev, "plls");
+ else
+ priv->base_plls = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base_plls))
+ return PTR_ERR(priv->base_plls);
+ }
+
+ for (i = 0; i < data->pll_count; i++) {
+ const struct eqc_pll *pll = &data->plls[i];
+ unsigned long mult, div, acc;
+ u32 r0, r1;
+ u64 val;
+ int ret;
+
+ val = readq(priv->base_plls + pll->reg64);
+ r0 = val;
+ r1 = val >> 32;
+
+ ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
+ if (ret) {
+ dev_warn(dev, "failed parsing state of %s\n", pll->name);
+ priv->cells->hws[pll->index] = ERR_PTR(ret);
+ continue;
+ }
+
+ hw = clk_hw_register_fixed_factor_with_accuracy_fwname(dev,
+ dev->of_node, pll->name, "ref", 0, mult, div, acc);
+ priv->cells->hws[pll->index] = hw;
+ if (IS_ERR(hw))
+ dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw);
+ }
+
+ BUG_ON(ARRAY_SIZE(div_resources) < data->div_count);
+
+ for (i = 0; i < data->div_count; i++) {
+ const struct eqc_div *div = &data->divs[i];
+ void __iomem *base = NULL;
+ struct clk_hw *parent;
+ unsigned int j;
+
+ /*
+ * Multiple divider clocks can request the same resource. Store
+ * resource pointers during probe(). For each divider clock,
+ * check if previous clocks referenced the same resource name.
+ *
+ * See EQ6HC_SOUTH_DIV_OSPI_REF and EQ6HC_SOUTH_DIV_OSPI_SYS.
+ */
+ for (j = 0; j < i; j++) {
+ if (strcmp(data->divs[j].resource_name, div->resource_name) == 0) {
+ base = div_resources[j];
+ break;
+ }
+ }
+
+ /* Resource is first encountered. */
+ if (!base) {
+ base = devm_platform_ioremap_resource_byname(pdev, div->resource_name);
+ if (IS_ERR(base)) {
+ dev_warn(dev, "failed to iomap resource for %s\n", div->name);
+ priv->cells->hws[div->index] = base;
+ continue;
+ }
+ }
+
+ div_resources[i] = base;
+
+ parent = priv->cells->hws[div->parent];
+ hw = clk_hw_register_divider_table_parent_hw(dev, div->name,
+ parent, 0, base, div->shift, div->width,
+ CLK_DIVIDER_EVEN_INTEGERS, NULL, NULL);
+ priv->cells->hws[div->index] = hw;
+ if (IS_ERR(hw))
+ dev_warn(dev, "failed registering %s: %pe\n",
+ div->name, hw);
+ }
+
+ /* Clock provider has not been registered by eqc_init(). Do it now. */
+ if (data->early_pll_count == 0) {
+ /* When providing a single clock, require no cell. */
+ if (priv->cells->num == 1)
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ priv->cells->hws);
+ else
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ priv->cells);
+ }
+
+ return 0;
+}
+
+/* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */
+static const struct eqc_pll eqc_eyeq5_early_plls[] = {
+ { .index = EQ5C_PLL_CPU, .name = "pll-cpu", .reg64 = 0x00, },
+ { .index = EQ5C_PLL_PER, .name = "pll-per", .reg64 = 0x30, },
+};
+
+static const struct eqc_pll eqc_eyeq5_plls[] = {
+ { .index = EQ5C_PLL_VMP, .name = "pll-vmp", .reg64 = 0x08, },
+ { .index = EQ5C_PLL_PMA, .name = "pll-pma", .reg64 = 0x10, },
+ { .index = EQ5C_PLL_VDI, .name = "pll-vdi", .reg64 = 0x18, },
+ { .index = EQ5C_PLL_DDR0, .name = "pll-ddr0", .reg64 = 0x20, },
+ { .index = EQ5C_PLL_PCI, .name = "pll-pci", .reg64 = 0x28, },
+ { .index = EQ5C_PLL_PMAC, .name = "pll-pmac", .reg64 = 0x38, },
+ { .index = EQ5C_PLL_MPC, .name = "pll-mpc", .reg64 = 0x40, },
+ { .index = EQ5C_PLL_DDR1, .name = "pll-ddr1", .reg64 = 0x48, },
+};
+
+static const struct eqc_div eqc_eyeq5_divs[] = {
+ {
+ .index = EQ5C_DIV_OSPI,
+ .name = "div-ospi",
+ .parent = EQ5C_PLL_PER,
+ .resource_name = "ospi",
+ .shift = 0,
+ .width = 4,
+ },
+};
+
+static const struct eqc_match_data eqc_eyeq5_match_data = {
+ .early_pll_count = ARRAY_SIZE(eqc_eyeq5_early_plls),
+ .early_plls = eqc_eyeq5_early_plls,
+
+ .pll_count = ARRAY_SIZE(eqc_eyeq5_plls),
+ .plls = eqc_eyeq5_plls,
+
+ .div_count = ARRAY_SIZE(eqc_eyeq5_divs),
+ .divs = eqc_eyeq5_divs,
+};
+
+static const struct eqc_pll eqc_eyeq6l_plls[] = {
+ { .index = EQ6LC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x2C },
+ { .index = EQ6LC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x34 }, /* also acc */
+ { .index = EQ6LC_PLL_PER, .name = "pll-per", .reg64 = 0x3C },
+ { .index = EQ6LC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x44 },
+};
+
+static const struct eqc_match_data eqc_eyeq6l_match_data = {
+ .pll_count = ARRAY_SIZE(eqc_eyeq6l_plls),
+ .plls = eqc_eyeq6l_plls,
+};
+
+/* Required early for GIC timer. */
+static const struct eqc_pll eqc_eyeq6h_central_early_plls[] = {
+ { .index = 0, .name = "pll-cpu", .reg64 = 0x00 },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_central_match_data = {
+ .early_pll_count = ARRAY_SIZE(eqc_eyeq6h_central_early_plls),
+ .early_plls = eqc_eyeq6h_central_early_plls,
+};
+
+/* Required early for UART. */
+static const struct eqc_pll eqc_eyeq6h_west_early_plls[] = {
+ { .index = 0, .name = "pll-west", .reg64 = 0x00 },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_west_match_data = {
+ .early_pll_count = ARRAY_SIZE(eqc_eyeq6h_west_early_plls),
+ .early_plls = eqc_eyeq6h_west_early_plls,
+};
+
+static const struct eqc_pll eqc_eyeq6h_east_plls[] = {
+ { .index = 0, .name = "pll-east", .reg64 = 0x00 },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_east_match_data = {
+ .pll_count = ARRAY_SIZE(eqc_eyeq6h_east_plls),
+ .plls = eqc_eyeq6h_east_plls,
+};
+
+static const struct eqc_pll eqc_eyeq6h_south_plls[] = {
+ { .index = EQ6HC_SOUTH_PLL_VDI, .name = "pll-vdi", .reg64 = 0x00 },
+ { .index = EQ6HC_SOUTH_PLL_PCIE, .name = "pll-pcie", .reg64 = 0x08 },
+ { .index = EQ6HC_SOUTH_PLL_PER, .name = "pll-per", .reg64 = 0x10 },
+ { .index = EQ6HC_SOUTH_PLL_ISP, .name = "pll-isp", .reg64 = 0x18 },
+};
+
+static const struct eqc_div eqc_eyeq6h_south_divs[] = {
+ {
+ .index = EQ6HC_SOUTH_DIV_EMMC,
+ .name = "div-emmc",
+ .parent = EQ6HC_SOUTH_PLL_PER,
+ .resource_name = "emmc",
+ .shift = 4,
+ .width = 4,
+ },
+ {
+ .index = EQ6HC_SOUTH_DIV_OSPI_REF,
+ .name = "div-ospi-ref",
+ .parent = EQ6HC_SOUTH_PLL_PER,
+ .resource_name = "ospi",
+ .shift = 4,
+ .width = 4,
+ },
+ {
+ .index = EQ6HC_SOUTH_DIV_OSPI_SYS,
+ .name = "div-ospi-sys",
+ .parent = EQ6HC_SOUTH_PLL_PER,
+ .resource_name = "ospi",
+ .shift = 8,
+ .width = 1,
+ },
+ {
+ .index = EQ6HC_SOUTH_DIV_TSU,
+ .name = "div-tsu",
+ .parent = EQ6HC_SOUTH_PLL_PCIE,
+ .resource_name = "tsu",
+ .shift = 4,
+ .width = 8,
+ },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_south_match_data = {
+ .pll_count = ARRAY_SIZE(eqc_eyeq6h_south_plls),
+ .plls = eqc_eyeq6h_south_plls,
+
+ .div_count = ARRAY_SIZE(eqc_eyeq6h_south_divs),
+ .divs = eqc_eyeq6h_south_divs,
+};
+
+static const struct eqc_pll eqc_eyeq6h_ddr0_plls[] = {
+ { .index = 0, .name = "pll-ddr0", .reg64 = 0x00 },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_ddr0_match_data = {
+ .pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr0_plls),
+ .plls = eqc_eyeq6h_ddr0_plls,
+};
+
+static const struct eqc_pll eqc_eyeq6h_ddr1_plls[] = {
+ { .index = 0, .name = "pll-ddr1", .reg64 = 0x00 },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_ddr1_match_data = {
+ .pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr1_plls),
+ .plls = eqc_eyeq6h_ddr1_plls,
+};
+
+static const struct eqc_pll eqc_eyeq6h_acc_plls[] = {
+ { .index = EQ6HC_ACC_PLL_XNN, .name = "pll-xnn", .reg64 = 0x00 },
+ { .index = EQ6HC_ACC_PLL_VMP, .name = "pll-vmp", .reg64 = 0x10 },
+ { .index = EQ6HC_ACC_PLL_PMA, .name = "pll-pma", .reg64 = 0x1C },
+ { .index = EQ6HC_ACC_PLL_MPC, .name = "pll-mpc", .reg64 = 0x28 },
+ { .index = EQ6HC_ACC_PLL_NOC, .name = "pll-noc", .reg64 = 0x30 },
+};
+
+static const struct eqc_match_data eqc_eyeq6h_acc_match_data = {
+ .pll_count = ARRAY_SIZE(eqc_eyeq6h_acc_plls),
+ .plls = eqc_eyeq6h_acc_plls,
+};
+
+static const struct of_device_id eqc_match_table[] = {
+ { .compatible = "mobileye,eyeq5-clk", .data = &eqc_eyeq5_match_data },
+ { .compatible = "mobileye,eyeq6l-clk", .data = &eqc_eyeq6l_match_data },
+ { .compatible = "mobileye,eyeq6h-central-clk", .data = &eqc_eyeq6h_central_match_data },
+ { .compatible = "mobileye,eyeq6h-west-clk", .data = &eqc_eyeq6h_west_match_data },
+ { .compatible = "mobileye,eyeq6h-east-clk", .data = &eqc_eyeq6h_east_match_data },
+ { .compatible = "mobileye,eyeq6h-south-clk", .data = &eqc_eyeq6h_south_match_data },
+ { .compatible = "mobileye,eyeq6h-ddr0-clk", .data = &eqc_eyeq6h_ddr0_match_data },
+ { .compatible = "mobileye,eyeq6h-ddr1-clk", .data = &eqc_eyeq6h_ddr1_match_data },
+ { .compatible = "mobileye,eyeq6h-acc-clk", .data = &eqc_eyeq6h_acc_match_data },
+ {}
+};
+MODULE_DEVICE_TABLE(of, eqc_match_table);
+
+static struct platform_driver eqc_driver = {
+ .probe = eqc_probe,
+ .driver = {
+ .name = "clk-eyeq",
+ .of_match_table = eqc_match_table,
+ },
+};
+builtin_platform_driver(eqc_driver);
+
+static void __init eqc_init(struct device_node *np)
+{
+ const struct eqc_match_data *data;
+ unsigned int nb_clks = 0;
+ struct eqc_priv *priv;
+ unsigned int i;
+ int ret;
+
+ data = of_match_node(eqc_match_table, np)->data;
+
+ /* No reason to early init this clock provider. Do it at probe. */
+ if (data->early_pll_count == 0)
+ return;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ priv->np = np;
+ priv->data = data;
+
+ nb_clks = eqc_compute_clock_count(data);
+ priv->cells = kzalloc(struct_size(priv->cells, hws, nb_clks), GFP_KERNEL);
+ if (!priv->cells) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ priv->cells->num = nb_clks;
+
+ /*
+ * Mark non-early clocks as deferred; they'll be registered at platform
+ * device probe.
+ */
+ for (i = 0; i < data->pll_count; i++)
+ priv->cells->hws[data->plls[i].index] = ERR_PTR(-EPROBE_DEFER);
+ for (i = 0; i < data->div_count; i++)
+ priv->cells->hws[data->divs[i].index] = ERR_PTR(-EPROBE_DEFER);
+
+ /*
+ * We expect named resources if divider clocks are present.
+ * Else, we only expect one resource.
+ */
+ if (data->div_count)
+ ret = of_property_match_string(np, "reg-names", "plls");
+ else
+ ret = 0;
+ if (ret < 0)
+ goto err;
+
+ priv->base_plls = of_iomap(np, ret);
+ if (!priv->base_plls) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ for (i = 0; i < data->early_pll_count; i++) {
+ const struct eqc_pll *pll = &data->early_plls[i];
+ unsigned long mult, div, acc;
+ struct clk_hw *hw;
+ u32 r0, r1;
+ u64 val;
+
+ val = readq(priv->base_plls + pll->reg64);
+ r0 = val;
+ r1 = val >> 32;
+
+ ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
+ if (ret) {
+ pr_err("failed parsing state of %s\n", pll->name);
+ goto err;
+ }
+
+ hw = clk_hw_register_fixed_factor_with_accuracy_fwname(NULL,
+ np, pll->name, "ref", 0, mult, div, acc);
+ priv->cells->hws[pll->index] = hw;
+ if (IS_ERR(hw)) {
+ pr_err("failed registering %s: %pe\n", pll->name, hw);
+ ret = PTR_ERR(hw);
+ goto err;
+ }
+ }
+
+ /* When providing a single clock, require no cell. */
+ if (nb_clks == 1)
+ ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, priv->cells->hws);
+ else
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, priv->cells);
+ if (ret) {
+ pr_err("failed registering clk provider: %d\n", ret);
+ goto err;
+ }
+
+ spin_lock(&eqc_list_slock);
+ list_add_tail(&priv->list, &eqc_list);
+ spin_unlock(&eqc_list_slock);
+
+ return;
+
+err:
+ /*
+ * We are doomed. The system will not be able to boot.
+ *
+ * Let's still try to be good citizens by freeing resources and print
+ * a last error message that might help debugging.
+ */
+
+ if (priv && priv->cells) {
+ of_clk_del_provider(np);
+
+ for (i = 0; i < data->early_pll_count; i++) {
+ const struct eqc_pll *pll = &data->early_plls[i];
+ struct clk_hw *hw = priv->cells->hws[pll->index];
+
+ if (!IS_ERR_OR_NULL(hw))
+ clk_hw_unregister_fixed_factor(hw);
+ }
+
+ kfree(priv->cells);
+ }
+
+ kfree(priv);
+
+ pr_err("failed clk init: %d\n", ret);
+}
+
+CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-clk", eqc_init);
+CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-clk", eqc_init);
+CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-clk", eqc_init);
--
2.44.0
^ permalink raw reply related
* [PATCH 04/11] clk: divider: Introduce CLK_DIVIDER_EVEN_INTEGERS flag
From: Théo Lebrun @ 2024-04-10 17:12 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Philipp Zabel, Linus Walleij
Cc: linux-mips, devicetree, linux-kernel, linux-clk, linux-gpio,
Vladimir Kondratiev, Gregory CLEMENT, Thomas Petazzoni,
Tawfik Bayouk, Théo Lebrun
In-Reply-To: <20240410-mbly-olb-v1-0-335e496d7be3@bootlin.com>
Add CLK_DIVIDER_EVEN_INTEGERS flag to support divisor of 2, 4, 6, etc.
The same divisor can be done using a table, which would be big and
wasteful for a clock dividor of width 8 (256 entries).
Require increasing flags size from u8 to u16 because
CLK_DIVIDER_EVEN_INTEGERS is the eighth flag.
Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
---
drivers/clk/clk-divider.c | 12 +++++++++---
include/linux/clk-provider.h | 11 +++++++----
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index a2c2b5203b0a..b6654c5c36d2 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
return clk_div_mask(width);
if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << clk_div_mask(width);
+ if (flags & CLK_DIVIDER_EVEN_INTEGERS)
+ return 2 * (clk_div_mask(width) + 1);
if (table)
return _get_table_maxdiv(table, width);
return clk_div_mask(width) + 1;
@@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *table,
return 1 << val;
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
return val ? val : clk_div_mask(width) + 1;
+ if (flags & CLK_DIVIDER_EVEN_INTEGERS)
+ return 2 * (val + 1);
if (table)
return _get_table_div(table, val);
return val + 1;
@@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table *table,
return __ffs(div);
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
return (div == clk_div_mask(width) + 1) ? 0 : div;
+ if (flags & CLK_DIVIDER_EVEN_INTEGERS)
+ return (div >> 1) - 1;
if (table)
return _get_table_val(table, div);
return div - 1;
@@ -538,7 +544,7 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+ void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{
struct clk_divider *div;
@@ -610,7 +616,7 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
- u8 clk_divider_flags, const struct clk_div_table *table,
+ u16 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{
struct clk_hw *hw;
@@ -664,7 +670,7 @@ struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+ void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{
struct clk_hw **ptr, *hw;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 4a537260f655..cb348e502e41 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -675,13 +675,15 @@ struct clk_div_table {
* CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used
* for the divider register. Setting this flag makes the register accesses
* big endian.
+ * CLK_DIVIDER_EVEN_INTEGERS - clock divisor is 2, 4, 6, 8, 10, etc.
+ * Formula is 2 * (value read from hardware + 1).
*/
struct clk_divider {
struct clk_hw hw;
void __iomem *reg;
u8 shift;
u8 width;
- u8 flags;
+ u16 flags;
const struct clk_div_table *table;
spinlock_t *lock;
};
@@ -697,6 +699,7 @@ struct clk_divider {
#define CLK_DIVIDER_READ_ONLY BIT(5)
#define CLK_DIVIDER_MAX_AT_ZERO BIT(6)
#define CLK_DIVIDER_BIG_ENDIAN BIT(7)
+#define CLK_DIVIDER_EVEN_INTEGERS BIT(8)
extern const struct clk_ops clk_divider_ops;
extern const struct clk_ops clk_divider_ro_ops;
@@ -726,18 +729,18 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+ void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock);
struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+ void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock);
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
- u8 clk_divider_flags, const struct clk_div_table *table,
+ u16 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
/**
* clk_register_divider - register a divider clock with the clock framework
--
2.44.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox