summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/blkmap.c82
-rw-r--r--drivers/block/blkmap_helper.c2
-rw-r--r--drivers/bootcount/Kconfig3
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/airoha/Makefile3
-rw-r--r--drivers/clk/airoha/clk-airoha.c454
-rw-r--r--drivers/clk/altera/clk-agilex5.c53
-rw-r--r--drivers/clk/clk-composite.c4
-rw-r--r--drivers/clk/clk-divider.c7
-rw-r--r--drivers/clk/clk-fixed-factor.c6
-rw-r--r--drivers/clk/clk-gate.c5
-rw-r--r--drivers/clk/clk-mux.c47
-rw-r--r--drivers/clk/clk-stub.c1
-rw-r--r--drivers/clk/clk-uclass.c18
-rw-r--r--drivers/clk/imx/Kconfig1
-rw-r--r--drivers/clk/imx/clk-composite-8m.c4
-rw-r--r--drivers/clk/imx/clk-gate2.c5
-rw-r--r--drivers/clk/imx/clk-imx6q.c92
-rw-r--r--drivers/clk/imx/clk-imx8mm.c268
-rw-r--r--drivers/clk/imx/clk-imx8mn.c262
-rw-r--r--drivers/clk/imx/clk-imx8mp.c348
-rw-r--r--drivers/clk/imx/clk-imx8mq.c226
-rw-r--r--drivers/clk/imx/clk-imx93.c8
-rw-r--r--drivers/clk/imx/clk-imxrt1020.c42
-rw-r--r--drivers/clk/imx/clk-imxrt1050.c78
-rw-r--r--drivers/clk/imx/clk-imxrt1170.c30
-rw-r--r--drivers/clk/imx/clk-pllv3.c9
-rw-r--r--drivers/clk/imx/clk.h116
-rw-r--r--drivers/clk/mediatek/Makefile2
-rw-r--r--drivers/clk/qcom/Kconfig8
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clock-apq8016.c12
-rw-r--r--drivers/clk/qcom/clock-ipq9574.c94
-rw-r--r--drivers/clk/qcom/clock-qcm2290.c4
-rw-r--r--drivers/clk/qcom/clock-qcom.h13
-rw-r--r--drivers/clk/qcom/clock-sa8775p.c4
-rw-r--r--drivers/clk/qcom/clock-sc7280.c124
-rw-r--r--drivers/clk/qcom/clock-sdm845.c4
-rw-r--r--drivers/clk/qcom/clock-sm6115.c4
-rw-r--r--drivers/clk/qcom/clock-sm8150.c4
-rw-r--r--drivers/clk/qcom/clock-sm8250.c4
-rw-r--r--drivers/clk/qcom/clock-sm8550.c4
-rw-r--r--drivers/clk/qcom/clock-sm8650.c4
-rw-r--r--drivers/clk/qcom/clock-x1e80100.c4
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.c17
-rw-r--r--drivers/clk/sunxi/Kconfig7
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk_a100.c102
-rw-r--r--drivers/clk/sunxi/clk_sunxi.c5
-rw-r--r--drivers/clk/ti/clk-k3.c6
-rw-r--r--drivers/core/Makefile2
-rw-r--r--drivers/core/ofnode_graph.c217
-rw-r--r--drivers/cpu/imx8_cpu.c54
-rw-r--r--drivers/ddr/altera/Makefile3
-rw-r--r--drivers/ddr/altera/iossm_mailbox.c748
-rw-r--r--drivers/ddr/altera/iossm_mailbox.h136
-rw-r--r--drivers/ddr/altera/sdram_agilex5.c420
-rw-r--r--drivers/ddr/altera/sdram_soc64.c78
-rw-r--r--drivers/ddr/altera/sdram_soc64.h10
-rw-r--r--drivers/dma/Kconfig7
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/adi_dma.c253
-rw-r--r--drivers/dma/ti/Makefile1
-rw-r--r--drivers/dma/ti/k3-psil.c2
-rw-r--r--drivers/dma/ti/k3-udma.c20
-rw-r--r--drivers/firmware/ti_sci_static_data.h2
-rw-r--r--drivers/gpio/Kconfig17
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/adp5588_gpio.c208
-rw-r--r--drivers/gpio/gpio-adi-adsp.c179
-rw-r--r--drivers/gpio/pca953x_gpio.c2
-rw-r--r--drivers/i2c/Kconfig7
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/adi_i2c.c386
-rw-r--r--drivers/mailbox/Kconfig7
-rw-r--r--drivers/mailbox/Makefile1
-rw-r--r--drivers/mailbox/imx-mailbox.c443
-rw-r--r--drivers/mailbox/zynqmp-ipi.c1
-rw-r--r--drivers/memory/ti-gpmc.c1
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/k3_fuse.c78
-rw-r--r--drivers/misc/qfw_acpi.c32
-rw-r--r--drivers/mmc/Kconfig15
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/adi_sdhci.c148
-rw-r--r--drivers/mmc/fsl_esdhc_imx.c8
-rw-r--r--drivers/mmc/msm_sdhci.c10
-rw-r--r--drivers/mmc/sunxi_mmc.c35
-rw-r--r--drivers/mmc/sunxi_mmc.h18
-rw-r--r--drivers/mtd/mtdpart.c5
-rw-r--r--drivers/mtd/nand/raw/Kconfig24
-rw-r--r--drivers/mtd/nand/raw/Makefile2
-rw-r--r--drivers/mtd/nand/raw/atmel/nand-controller.c13
-rw-r--r--drivers/mtd/nand/raw/cadence_nand.c2423
-rw-r--r--drivers/mtd/nand/raw/cadence_spl.c59
-rw-r--r--drivers/mtd/nand/raw/meson_nand.c4
-rw-r--r--drivers/mtd/nand/raw/nand_base.c69
-rw-r--r--drivers/mux/Kconfig10
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/designware.c294
-rw-r--r--drivers/net/dwc_eth_qos.c6
-rw-r--r--drivers/net/dwc_eth_qos.h2
-rw-r--r--drivers/net/dwc_eth_qos_adi.c103
-rw-r--r--drivers/net/phy/micrel_ksz90x1.c169
-rw-r--r--drivers/net/phy/miiphybb.c216
-rw-r--r--drivers/net/ravb.c194
-rw-r--r--drivers/net/sh_eth.c189
-rw-r--r--drivers/net/ti/am65-cpsw-nuss.c2
-rw-r--r--drivers/pci/pci_auto.c3
-rw-r--r--drivers/phy/Kconfig5
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-rcar-gen3.c79
-rw-r--r--drivers/phy/starfive/Kconfig21
-rw-r--r--drivers/phy/starfive/Makefile7
-rw-r--r--drivers/phy/starfive/phy-jh7110-pcie.c239
-rw-r--r--drivers/phy/starfive/phy-jh7110-usb-syscon.h9
-rw-r--r--drivers/phy/starfive/phy-jh7110-usb2.c162
-rw-r--r--drivers/pinctrl/Kconfig8
-rw-r--r--drivers/pinctrl/Makefile2
-rw-r--r--drivers/pinctrl/intel/Kconfig3
-rw-r--r--drivers/pinctrl/pinctrl-adi-adsp.c161
-rw-r--r--drivers/pinctrl/pinctrl-at91.c52
-rw-r--r--drivers/pinctrl/qcom/Kconfig38
-rw-r--r--drivers/pinctrl/qcom/Makefile2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-apq8016.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-apq8096.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ipq4019.c3
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ipq9574.c226
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcm2290.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.c5
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.h3
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcs404.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc7280.c106
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm845.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm6115.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8150.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8250.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8550.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8650.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-x1e80100.c4
-rw-r--r--drivers/pinctrl/sunxi/Kconfig10
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c47
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.c90
-rw-r--r--drivers/power/Kconfig25
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/axp_spl.c17
-rw-r--r--drivers/power/domain/ti-power-domain.c6
-rw-r--r--drivers/power/regulator/Kconfig8
-rw-r--r--drivers/power/regulator/Makefile1
-rw-r--r--drivers/power/regulator/rzg2l-usbphy-regulator.c42
-rw-r--r--drivers/pwm/Kconfig8
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-mtk.c16
-rw-r--r--drivers/pwm/pwm-stm32.c205
-rw-r--r--drivers/ram/Kconfig2
-rw-r--r--drivers/ram/renesas/dbsc5/dram.c92
-rw-r--r--drivers/remoteproc/Kconfig22
-rw-r--r--drivers/remoteproc/Makefile2
-rw-r--r--drivers/remoteproc/adi_sc5xx_rproc.c277
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c36
-rw-r--r--drivers/remoteproc/ti_k3_m4_rproc.c371
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c2
-rw-r--r--drivers/reset/Kconfig23
-rw-r--r--drivers/reset/Makefile3
-rw-r--r--drivers/reset/reset-airoha.c173
-rw-r--r--drivers/reset/reset-rzg2l-usbphy-ctrl.c142
-rw-r--r--drivers/reset/reset-spacemit-k1.c548
-rw-r--r--drivers/rng/msm_rng.c13
-rw-r--r--drivers/serial/Kconfig6
-rw-r--r--drivers/serial/Makefile3
-rw-r--r--drivers/serial/ns16550.c16
-rw-r--r--drivers/serial/sandbox.c10
-rw-r--r--drivers/serial/serial_mxc.c11
-rw-r--r--drivers/serial/serial_stm32.c18
-rw-r--r--drivers/serial/usbtty.c983
-rw-r--r--drivers/serial/usbtty.h49
-rw-r--r--drivers/soc/soc_ti_k3.c16
-rw-r--r--drivers/spi/Kconfig11
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/adi_spi3.c679
-rw-r--r--drivers/spi/atmel-quadspi.c294
-rw-r--r--drivers/spi/soft_spi.c19
-rw-r--r--drivers/sysinfo/Kconfig7
-rw-r--r--drivers/sysinfo/Makefile1
-rw-r--r--drivers/sysinfo/iot2050.c202
-rw-r--r--drivers/sysinfo/iot2050.h14
-rw-r--r--drivers/sysinfo/sysinfo-uclass.c29
-rw-r--r--drivers/sysreset/Kconfig1
-rw-r--r--drivers/timer/sandbox_timer.c5
-rw-r--r--drivers/ufs/ufs.c44
-rw-r--r--drivers/ufs/ufs.h335
-rw-r--r--drivers/ufs/ufshci.h469
-rw-r--r--drivers/ufs/unipro.h128
-rw-r--r--drivers/usb/cdns3/Kconfig7
-rw-r--r--drivers/usb/cdns3/Makefile1
-rw-r--r--drivers/usb/cdns3/cdns3-starfive.c182
-rw-r--r--drivers/usb/cdns3/core.c3
-rw-r--r--drivers/usb/cdns3/drd.c14
-rw-r--r--drivers/usb/emul/sandbox_keyb.c8
-rw-r--r--drivers/usb/gadget/Makefile4
-rw-r--r--drivers/usb/gadget/core.c621
-rw-r--r--drivers/usb/gadget/ep0.c619
-rw-r--r--drivers/usb/musb-new/Kconfig7
-rw-r--r--drivers/usb/musb-new/Makefile1
-rw-r--r--drivers/usb/musb-new/sc5xx.c202
-rw-r--r--drivers/video/Kconfig46
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/bridge/Kconfig15
-rw-r--r--drivers/video/bridge/Makefile1
-rw-r--r--drivers/video/bridge/dp501.c27
-rw-r--r--drivers/video/bridge/lvds-codec.c128
-rw-r--r--drivers/video/bridge/ssd2825.c159
-rw-r--r--drivers/video/bridge/tc358768.c101
-rw-r--r--drivers/video/bridge/video-bridge-uclass.c11
-rw-r--r--drivers/video/endeavoru-panel.c21
-rw-r--r--drivers/video/lg-ld070wx3.c2
-rw-r--r--drivers/video/lm3533_backlight.c142
-rw-r--r--drivers/video/lp855x_backlight.c302
-rw-r--r--drivers/video/renesas-r61307.c13
-rw-r--r--drivers/video/renesas-r69328.c37
-rw-r--r--drivers/video/samsung-ltl106hl02.c2
-rw-r--r--drivers/video/sharp-lq079l1sx01.c288
-rw-r--r--drivers/video/sharp-lq101r1sx01.c1
-rw-r--r--drivers/video/tegra20/Kconfig16
-rw-r--r--drivers/video/tegra20/Makefile2
-rw-r--r--drivers/video/tegra20/tegra-dc.c326
-rw-r--r--drivers/video/tegra20/tegra-dc.h3
-rw-r--r--drivers/video/tegra20/tegra-dsi.c243
-rw-r--r--drivers/video/tegra20/tegra-hdmi.c623
-rw-r--r--drivers/video/tegra20/tegra-hdmi.h648
-rw-r--r--drivers/video/tegra20/tegra-host1x.c86
-rw-r--r--drivers/video/tegra20/tegra-mipi.c134
-rw-r--r--drivers/video/tegra20/tegra-pwm-backlight.c12
-rw-r--r--drivers/video/ti/tilcdc.c4
-rw-r--r--drivers/watchdog/Kconfig9
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/adi_wdt.c143
-rw-r--r--drivers/watchdog/da9063-wdt.c1
240 files changed, 17223 insertions, 4660 deletions
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
index 34eed1380dc..473c65b5911 100644
--- a/drivers/block/blkmap.c
+++ b/drivers/block/blkmap.c
@@ -17,6 +17,30 @@
struct blkmap;
/**
+ * define BLKMAP_SLICE_LINEAR - Linear mapping to another block device
+ *
+ * This blkmap slice type is used for mapping to other existing block
+ * devices.
+ */
+#define BLKMAP_SLICE_LINEAR BIT(0)
+
+/**
+ * define BLKMAP_SLICE_MEM - Linear mapping to memory based block device
+ *
+ * This blkmap slice type is used for mapping to memory based block
+ * devices, like ramdisks.
+ */
+#define BLKMAP_SLICE_MEM BIT(1)
+
+/**
+ * define BLKMAP_SLICE_PRESERVE - Preserved blkmap slice
+ *
+ * This blkmap slice is intended to be preserved, and it's
+ * information passed on to a later stage, like OS.
+ */
+#define BLKMAP_SLICE_PRESERVE BIT(2)
+
+/**
* struct blkmap_slice - Region mapped to a blkmap
*
* Common data for a region mapped to a blkmap, specialized by each
@@ -25,12 +49,14 @@ struct blkmap;
* @node: List node used to associate this slice with a blkmap
* @blknr: Start block number of the mapping
* @blkcnt: Number of blocks covered by this mapping
+ * @attr: Attributes of blkmap slice
*/
struct blkmap_slice {
struct list_head node;
lbaint_t blknr;
lbaint_t blkcnt;
+ uint attr;
/**
* @read: - Read from slice
@@ -169,6 +195,7 @@ int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
.slice = {
.blknr = blknr,
.blkcnt = blkcnt,
+ .attr = BLKMAP_SLICE_LINEAR,
.read = blkmap_linear_read,
.write = blkmap_linear_write,
@@ -234,7 +261,7 @@ static void blkmap_mem_destroy(struct blkmap *bm, struct blkmap_slice *bms)
}
int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
- void *addr, bool remapped)
+ void *addr, bool remapped, bool preserve)
{
struct blkmap *bm = dev_get_plat(dev);
struct blkmap_mem *bmm;
@@ -248,6 +275,7 @@ int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
.slice = {
.blknr = blknr,
.blkcnt = blkcnt,
+ .attr = BLKMAP_SLICE_MEM,
.read = blkmap_mem_read,
.write = blkmap_mem_write,
@@ -258,6 +286,9 @@ int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
.remapped = remapped,
};
+ if (preserve)
+ bmm->slice.attr |= BLKMAP_SLICE_PRESERVE;
+
err = blkmap_slice_add(bm, &bmm->slice);
if (err)
free(bmm);
@@ -268,11 +299,11 @@ int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *addr)
{
- return __blkmap_map_mem(dev, blknr, blkcnt, addr, false);
+ return __blkmap_map_mem(dev, blknr, blkcnt, addr, false, false);
}
int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
- phys_addr_t paddr)
+ phys_addr_t paddr, bool preserve)
{
struct blkmap *bm = dev_get_plat(dev);
struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
@@ -283,7 +314,7 @@ int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
if (!addr)
return -ENOMEM;
- err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true);
+ err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true, preserve);
if (err)
unmap_sysmem(addr);
@@ -486,6 +517,49 @@ err:
return err;
}
+static bool blkmap_mem_preserve_slice(struct blkmap_slice *bms)
+{
+ return (bms->attr & (BLKMAP_SLICE_MEM | BLKMAP_SLICE_PRESERVE)) ==
+ (BLKMAP_SLICE_MEM | BLKMAP_SLICE_PRESERVE);
+}
+
+int blkmap_get_preserved_pmem_slices(int (*cb)(void *ctx, u64 addr,
+ u64 size), void *ctx)
+{
+ int ret;
+ u64 addr, size;
+ struct udevice *dev;
+ struct uclass *uc;
+ struct blkmap *bm;
+ struct blkmap_mem *bmm;
+ struct blkmap_slice *bms;
+ struct blk_desc *bd;
+
+ if (!cb) {
+ log_debug("%s: No callback passed to the function\n", __func__);
+ return 0;
+ }
+
+ uclass_id_foreach_dev(UCLASS_BLKMAP, dev, uc) {
+ bm = dev_get_plat(dev);
+ bd = dev_get_uclass_plat(bm->blk);
+
+ list_for_each_entry(bms, &bm->slices, node) {
+ if (!blkmap_mem_preserve_slice(bms))
+ continue;
+
+ bmm = container_of(bms, struct blkmap_mem, slice);
+ addr = (u64)(uintptr_t)bmm->addr;
+ size = (u64)bms->blkcnt << bd->log2blksz;
+ ret = cb(ctx, addr, size);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int blkmap_destroy(struct udevice *dev)
{
int err;
diff --git a/drivers/block/blkmap_helper.c b/drivers/block/blkmap_helper.c
index bfba14110d2..2f1bc28ee5d 100644
--- a/drivers/block/blkmap_helper.c
+++ b/drivers/block/blkmap_helper.c
@@ -28,7 +28,7 @@ int blkmap_create_ramdisk(const char *label, ulong image_addr, ulong image_size,
bm = dev_get_plat(bm_dev);
desc = dev_get_uclass_plat(bm->blk);
blknum = image_size >> desc->log2blksz;
- ret = blkmap_map_pmem(bm_dev, 0, blknum, image_addr);
+ ret = blkmap_map_pmem(bm_dev, 0, blknum, image_addr, true);
if (ret) {
log_err("Unable to map %#llx at block %d : %d\n",
(unsigned long long)image_addr, 0, ret);
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 0080d2a165c..99b6c7534fd 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -183,6 +183,9 @@ config BOOTCOUNT_BOOTLIMIT
counter being cleared.
If set to 0, do not set a boot limit in the environment.
+config BOOTCOUNT_ALTBOOTCMD
+ string "Alternative boot command when BOOTLIMIT is reached"
+
config SYS_BOOTCOUNT_SINGLEWORD
bool "Use single word to pack boot count and magic value"
depends on BOOTCOUNT_GENERIC
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index fe0e49f6112..8411205ee04 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_$(PHASE_)CLK_GPIO) += clk-gpio.o
obj-$(CONFIG_$(PHASE_)CLK_STUB) += clk-stub.o
obj-y += adi/
+obj-y += airoha/
obj-y += analogbits/
obj-y += imx/
obj-$(CONFIG_CLK_JH7110) += starfive/
diff --git a/drivers/clk/airoha/Makefile b/drivers/clk/airoha/Makefile
new file mode 100644
index 00000000000..1744c5f7236
--- /dev/null
+++ b/drivers/clk/airoha/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+# Core
+obj-$(CONFIG_ARCH_AIROHA) += clk-airoha.o
diff --git a/drivers/clk/airoha/clk-airoha.c b/drivers/clk/airoha/clk-airoha.c
new file mode 100644
index 00000000000..1b2c4c98de5
--- /dev/null
+++ b/drivers/clk/airoha/clk-airoha.c
@@ -0,0 +1,454 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on the Linux clk-en7523.c but majorly reworked
+ * for U-Boot that doesn't require CCF subsystem.
+ *
+ * Major modification, support for set_rate, realtime
+ * get_rate and split for reset part to a different driver.
+ *
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org> (original driver)
+ * Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include <dt-bindings/clock/en7523-clk.h>
+
+#define REG_GSW_CLK_DIV_SEL 0x1b4
+#define REG_EMI_CLK_DIV_SEL 0x1b8
+#define REG_BUS_CLK_DIV_SEL 0x1bc
+#define REG_SPI_CLK_DIV_SEL 0x1c4
+#define REG_SPI_CLK_FREQ_SEL 0x1c8
+#define REG_NPU_CLK_DIV_SEL 0x1fc
+
+#define REG_NP_SCU_PCIC 0x88
+#define REG_NP_SCU_SSTR 0x9c
+#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
+#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
+#define REG_CRYPTO_CLKSRC2 0x20c
+
+#define EN7581_MAX_CLKS 9
+
+struct airoha_clk_desc {
+ int id;
+ const char *name;
+ u32 base_reg;
+ u8 base_bits;
+ u8 base_shift;
+ union {
+ const unsigned int *base_values;
+ unsigned int base_value;
+ };
+ size_t n_base_values;
+
+ u16 div_reg;
+ u8 div_bits;
+ u8 div_shift;
+ u16 div_val0;
+ u8 div_step;
+ u8 div_offset;
+};
+
+struct airoha_clk_priv {
+ struct regmap *chip_scu_map;
+ struct airoha_clk_soc_data *data;
+};
+
+struct airoha_clk_soc_data {
+ u32 num_clocks;
+ const struct airoha_clk_desc *descs;
+};
+
+static const u32 gsw_base[] = { 400000000, 500000000 };
+static const u32 slic_base[] = { 100000000, 3125000 };
+
+static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
+static const u32 bus7581_base[] = { 600000000, 540000000 };
+static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
+static const u32 crypto_base[] = { 540000000, 480000000 };
+static const u32 emmc7581_base[] = { 200000000, 150000000 };
+
+static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = {
+ [EN7523_CLK_GSW] = {
+ .id = EN7523_CLK_GSW,
+ .name = "gsw",
+
+ .base_reg = REG_GSW_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = gsw_base,
+ .n_base_values = ARRAY_SIZE(gsw_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_EMI] = {
+ .id = EN7523_CLK_EMI,
+ .name = "emi",
+
+ .base_reg = REG_EMI_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = emi7581_base,
+ .n_base_values = ARRAY_SIZE(emi7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_BUS] = {
+ .id = EN7523_CLK_BUS,
+ .name = "bus",
+
+ .base_reg = REG_BUS_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = bus7581_base,
+ .n_base_values = ARRAY_SIZE(bus7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_SLIC] = {
+ .id = EN7523_CLK_SLIC,
+ .name = "slic",
+
+ .base_reg = REG_SPI_CLK_FREQ_SEL,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = slic_base,
+ .n_base_values = ARRAY_SIZE(slic_base),
+
+ .div_reg = REG_SPI_CLK_DIV_SEL,
+ .div_bits = 5,
+ .div_shift = 24,
+ .div_val0 = 20,
+ .div_step = 2,
+ },
+ [EN7523_CLK_SPI] = {
+ .id = EN7523_CLK_SPI,
+ .name = "spi",
+
+ .base_reg = REG_SPI_CLK_DIV_SEL,
+
+ .base_value = 400000000,
+
+ .div_bits = 5,
+ .div_shift = 8,
+ .div_val0 = 40,
+ .div_step = 2,
+ },
+ [EN7523_CLK_NPU] = {
+ .id = EN7523_CLK_NPU,
+ .name = "npu",
+
+ .base_reg = REG_NPU_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = npu7581_base,
+ .n_base_values = ARRAY_SIZE(npu7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_CRYPTO] = {
+ .id = EN7523_CLK_CRYPTO,
+ .name = "crypto",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = crypto_base,
+ .n_base_values = ARRAY_SIZE(crypto_base),
+ },
+ [EN7581_CLK_EMMC] = {
+ .id = EN7581_CLK_EMMC,
+ .name = "emmc",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 12,
+ .base_values = emmc7581_base,
+ .n_base_values = ARRAY_SIZE(emmc7581_base),
+ }
+};
+
+static u32 airoha_clk_get_base_rate(const struct airoha_clk_desc *desc, u32 val)
+{
+ if (!desc->base_bits)
+ return desc->base_value;
+
+ val >>= desc->base_shift;
+ val &= (1 << desc->base_bits) - 1;
+
+ if (val >= desc->n_base_values)
+ return 0;
+
+ return desc->base_values[val];
+}
+
+static u32 airoha_clk_get_div(const struct airoha_clk_desc *desc, u32 val)
+{
+ if (!desc->div_bits)
+ return 1;
+
+ val >>= desc->div_shift;
+ val &= (1 << desc->div_bits) - 1;
+
+ if (!val && desc->div_val0)
+ return desc->div_val0;
+
+ return (val + desc->div_offset) * desc->div_step;
+}
+
+static int airoha_clk_enable(struct clk *clk)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
+ struct airoha_clk_soc_data *data = priv->data;
+ int id = clk->id;
+
+ if (id > data->num_clocks)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int airoha_clk_disable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong airoha_clk_get_rate(struct clk *clk)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
+ struct airoha_clk_soc_data *data = priv->data;
+ const struct airoha_clk_desc *desc;
+ struct regmap *map = priv->chip_scu_map;
+ int id = clk->id;
+ u32 reg, val;
+ ulong rate;
+ int ret;
+
+ if (id > data->num_clocks) {
+ dev_err(clk->dev, "Invalid clk ID %d\n", id);
+ return 0;
+ }
+
+ desc = &data->descs[id];
+
+ ret = regmap_read(map, desc->base_reg, &val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to read reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+
+ rate = airoha_clk_get_base_rate(desc, val);
+
+ reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+ ret = regmap_read(map, reg, &val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to read reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+
+ rate /= airoha_clk_get_div(desc, val);
+
+ return rate;
+}
+
+static int airoha_clk_search_rate(const struct airoha_clk_desc *desc, int div,
+ ulong rate)
+{
+ int i;
+
+ /* Single base rate */
+ if (!desc->base_bits) {
+ if (rate != desc->base_value / div)
+ goto err;
+
+ return 0;
+ }
+
+ /* Check every base rate with provided divisor */
+ for (i = 0; i < desc->n_base_values; i++)
+ if (rate == desc->base_values[i] / div)
+ return i;
+
+err:
+ return -EINVAL;
+}
+
+static ulong airoha_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
+ struct airoha_clk_soc_data *data = priv->data;
+ const struct airoha_clk_desc *desc;
+ struct regmap *map = priv->chip_scu_map;
+ int div_val, base_val;
+ u32 reg, val, mask;
+ int id = clk->id;
+ int div;
+ int ret;
+
+ if (id > data->num_clocks) {
+ dev_err(clk->dev, "Invalid clk ID %d\n", id);
+ return 0;
+ }
+
+ desc = &data->descs[id];
+
+ if (!desc->base_bits && !desc->div_bits) {
+ dev_err(clk->dev, "Can't set rate for fixed clock %s\n",
+ desc->name);
+ return 0;
+ }
+
+ if (!desc->div_bits) {
+ /* Divisor not supported, just search in base rate */
+ div_val = 0;
+ base_val = airoha_clk_search_rate(desc, 1, rate);
+ if (base_val < 0) {
+ dev_err(clk->dev, "Invalid rate for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ } else {
+ div_val = 0;
+
+ /* Check if div0 satisfy the request */
+ if (desc->div_val0) {
+ base_val = airoha_clk_search_rate(desc, desc->div_val0,
+ rate);
+ if (base_val >= 0) {
+ div_val = 0;
+ goto apply;
+ }
+
+ /* Skip checking first divisor val */
+ div_val = 1;
+ }
+
+ /* Simulate rate with every divisor supported */
+ for (div_val = div_val + desc->div_offset;
+ div_val < BIT(desc->div_bits) - 1; div_val++) {
+ div = div_val * desc->div_step;
+
+ base_val = airoha_clk_search_rate(desc, div, rate);
+ if (base_val >= 0)
+ break;
+ }
+
+ if (div_val == BIT(desc->div_bits) - 1) {
+ dev_err(clk->dev, "Invalid rate for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ }
+
+apply:
+ if (desc->div_bits) {
+ reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+
+ mask = (BIT(desc->div_bits) - 1) << desc->div_shift;
+ val = div_val << desc->div_shift;
+
+ ret = regmap_update_bits(map, reg, mask, val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to update div reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ }
+
+ if (desc->base_bits) {
+ mask = (BIT(desc->base_bits) - 1) << desc->base_shift;
+ val = base_val << desc->base_shift;
+
+ ret = regmap_update_bits(map, desc->base_reg, mask, val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to update reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ }
+
+ return rate;
+}
+
+const struct clk_ops airoha_clk_ops = {
+ .enable = airoha_clk_enable,
+ .disable = airoha_clk_disable,
+ .get_rate = airoha_clk_get_rate,
+ .set_rate = airoha_clk_set_rate,
+};
+
+static int airoha_clk_probe(struct udevice *dev)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(dev);
+ ofnode chip_scu_node;
+
+ chip_scu_node = ofnode_by_compatible(ofnode_null(),
+ "airoha,en7581-chip-scu");
+ if (!ofnode_valid(chip_scu_node))
+ return -EINVAL;
+
+ priv->chip_scu_map = syscon_node_to_regmap(chip_scu_node);
+ if (IS_ERR(priv->chip_scu_map))
+ return PTR_ERR(priv->chip_scu_map);
+
+ priv->data = (void *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static int airoha_clk_bind(struct udevice *dev)
+{
+ struct udevice *rst_dev;
+ int ret = 0;
+
+ if (CONFIG_IS_ENABLED(RESET_AIROHA)) {
+ ret = device_bind_driver_to_node(dev, "airoha-reset", "reset",
+ dev_ofnode(dev), &rst_dev);
+ if (ret)
+ debug("Warning: failed to bind reset controller\n");
+ }
+
+ return ret;
+}
+
+static const struct airoha_clk_soc_data en7581_data = {
+ .num_clocks = ARRAY_SIZE(en7581_base_clks),
+ .descs = en7581_base_clks,
+};
+
+static const struct udevice_id airoha_clk_ids[] = {
+ { .compatible = "airoha,en7581-scu",
+ .data = (ulong)&en7581_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(airoha_clk) = {
+ .name = "clk-airoha",
+ .id = UCLASS_CLK,
+ .of_match = airoha_clk_ids,
+ .probe = airoha_clk_probe,
+ .bind = airoha_clk_bind,
+ .priv_auto = sizeof(struct airoha_clk_priv),
+ .ops = &airoha_clk_ops,
+};
diff --git a/drivers/clk/altera/clk-agilex5.c b/drivers/clk/altera/clk-agilex5.c
index 716c71598bc..fb1e72ffc5c 100644
--- a/drivers/clk/altera/clk-agilex5.c
+++ b/drivers/clk/altera/clk-agilex5.c
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2024 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
*/
-#include <clk-uclass.h>
#include <config.h>
-#include <errno.h>
-#include <dm.h>
#include <log.h>
+#include <dm.h>
+#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
@@ -23,9 +23,14 @@
#include <linux/types.h>
#include <asm/arch/clock_manager.h>
#include <dt-bindings/clock/agilex5-clock.h>
+#include <wait_bit.h>
+#include <clk-uclass.h>
DECLARE_GLOBAL_DATA_PTR;
+#define CLKMGR_CTRL_SWCTRLBTCLKEN_MASK BIT(8)
+#define CLKMGR_CTRL_SWCTRLBTCLKSEL_MASK BIT(9)
+
struct socfpga_clk_plat {
void __iomem *regs;
};
@@ -36,21 +41,30 @@ struct socfpga_clk_plat {
*/
static void clk_write_bypass_mainpll(struct socfpga_clk_plat *plat, u32 val)
{
+ uintptr_t base_addr = (uintptr_t)plat->regs;
+
CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_BYPASS);
- cm_wait_for_fsm();
+ wait_for_bit_le32((const void *)(base_addr + CLKMGR_STAT), CLKMGR_STAT_BUSY,
+ false, 20000, false);
}
static void clk_write_bypass_perpll(struct socfpga_clk_plat *plat, u32 val)
{
+ uintptr_t base_addr = (uintptr_t)plat->regs;
+
CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_BYPASS);
- cm_wait_for_fsm();
+ wait_for_bit_le32((const void *)(base_addr + CLKMGR_STAT), CLKMGR_STAT_BUSY,
+ false, 20000, false);
}
/* function to write the ctrl register which requires a poll of the busy bit */
static void clk_write_ctrl(struct socfpga_clk_plat *plat, u32 val)
{
+ uintptr_t base_addr = (uintptr_t)plat->regs;
+
CM_REG_WRITEL(plat, val, CLKMGR_CTRL);
- cm_wait_for_fsm();
+ wait_for_bit_le32((const void *)(base_addr + CLKMGR_STAT), CLKMGR_STAT_BUSY,
+ false, 20000, false);
}
static const struct {
@@ -59,15 +73,6 @@ static const struct {
u32 mask;
} membus_pll[] = {
{
- MEMBUS_CLKSLICE_REG,
- /*
- * BIT[7:7]
- * Enable source synchronous mode
- */
- BIT(7),
- BIT(7)
- },
- {
MEMBUS_SYNTHCALFOSC_INIT_CENTERFREQ_REG,
/*
* BIT[0:0]
@@ -238,6 +243,7 @@ static void clk_basic_init(struct udevice *dev,
{
struct socfpga_clk_plat *plat = dev_get_plat(dev);
u32 vcocalib;
+ uintptr_t base_addr = (uintptr_t)plat->regs;
if (!cfg)
return;
@@ -249,7 +255,8 @@ static void clk_basic_init(struct udevice *dev,
CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLGLOB,
CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
- cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK);
+ wait_for_bit_le32((const void *)(base_addr + CLKMGR_STAT),
+ CLKMGR_STAT_ALLPLL_LOCKED_MASK, true, 20000, false);
/* Put both PLLs in bypass */
clk_write_bypass_mainpll(plat, CLKMGR_BYPASS_MAINPLL_ALL);
@@ -264,9 +271,14 @@ static void clk_basic_init(struct udevice *dev,
CM_REG_READL(plat, CLKMGR_CTRL) & ~CLKMGR_CTRL_BOOTMODE);
} else {
#ifdef CONFIG_XPL_BUILD
- /* Always force clock manager into boot mode before any configuration */
- clk_write_ctrl(plat,
- CM_REG_READL(plat, CLKMGR_CTRL) | CLKMGR_CTRL_BOOTMODE);
+ /*
+ * Configure HPS Internal Oscillator as default boot_clk source,
+ * always force clock manager into boot mode before any configuration
+ */
+ clk_write_ctrl(plat, CM_REG_READL(plat, CLKMGR_CTRL) |
+ CLKMGR_CTRL_BOOTMODE |
+ CLKMGR_CTRL_SWCTRLBTCLKEN_MASK |
+ CLKMGR_CTRL_SWCTRLBTCLKSEL_MASK);
#else
/* Skip clock configuration in SSBL if it's not in boot mode */
if (!(CM_REG_READL(plat, CLKMGR_CTRL) & CLKMGR_CTRL_BOOTMODE))
@@ -365,7 +377,8 @@ static void clk_basic_init(struct udevice *dev,
CLKMGR_PLLCX_EN_SET_MSK,
CLKMGR_PERPLL_PLLC3);
- cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK);
+ wait_for_bit_le32((const void *)(base_addr + CLKMGR_STAT),
+ CLKMGR_STAT_ALLPLL_LOCKED_MASK, true, 20000, false);
CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_MAINPLL_LOSTLOCK);
CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_PERPLL_LOSTLOCK);
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 199ca6eaa37..9e3b5191767 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -97,7 +97,7 @@ static int clk_composite_disable(struct clk *clk)
return 0;
}
-struct clk *clk_register_composite(struct device *dev, const char *name,
+struct clk *clk_register_composite(struct udevice *dev, const char *name,
const char * const *parent_names,
int num_parents, struct clk *mux,
const struct clk_ops *mux_ops,
@@ -149,7 +149,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
clk = &composite->clk;
clk->flags = flags;
ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
- parent_names[clk_composite_get_parent(clk)]);
+ clk_resolve_parent_clk(dev, parent_names[clk_composite_get_parent(clk)]));
if (ret) {
clk = ERR_PTR(ret);
goto err;
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index aa210e3d15f..e692b9c2167 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -183,7 +183,7 @@ const struct clk_ops clk_divider_ops = {
.set_rate = clk_divider_set_rate,
};
-static struct clk *_register_divider(struct device *dev, const char *name,
+static struct clk *_register_divider(struct udevice *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)
@@ -218,7 +218,8 @@ static struct clk *_register_divider(struct device *dev, const char *name,
clk = &div->clk;
clk->flags = flags;
- ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name);
+ ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name,
+ clk_resolve_parent_clk(dev, parent_name));
if (ret) {
kfree(div);
return ERR_PTR(ret);
@@ -227,7 +228,7 @@ static struct clk *_register_divider(struct device *dev, const char *name,
return clk;
}
-struct clk *clk_register_divider(struct device *dev, const char *name,
+struct clk *clk_register_divider(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags)
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index 068798cf9b0..4eb8be728e6 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -37,7 +37,7 @@ const struct clk_ops ccf_clk_fixed_factor_ops = {
.get_rate = clk_factor_recalc_rate,
};
-struct clk *clk_hw_register_fixed_factor(struct device *dev,
+struct clk *clk_hw_register_fixed_factor(struct udevice *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
{
@@ -56,7 +56,7 @@ struct clk *clk_hw_register_fixed_factor(struct device *dev,
clk->flags = flags;
ret = clk_register(clk, UBOOT_DM_CLK_IMX_FIXED_FACTOR, name,
- parent_name);
+ clk_resolve_parent_clk(dev, parent_name));
if (ret) {
kfree(fix);
return ERR_PTR(ret);
@@ -65,7 +65,7 @@ struct clk *clk_hw_register_fixed_factor(struct device *dev,
return clk;
}
-struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
+struct clk *clk_register_fixed_factor(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
{
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index bf1c6a93b46..256ff108991 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -117,7 +117,7 @@ const struct clk_ops clk_gate_ops = {
.get_rate = clk_generic_get_rate,
};
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *clk_register_gate(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock)
@@ -149,7 +149,8 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
clk = &gate->clk;
clk->flags = flags;
- ret = clk_register(clk, UBOOT_DM_CLK_GATE, name, parent_name);
+ ret = clk_register(clk, UBOOT_DM_CLK_GATE, name,
+ clk_resolve_parent_clk(dev, parent_name));
if (ret) {
kfree(gate);
return ERR_PTR(ret);
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 62477e15d27..d7411f8f282 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -113,6 +113,11 @@ int clk_mux_fetch_parent_index(struct clk *clk, struct clk *parent)
for (i = 0; i < mux->num_parents; i++) {
if (!strcmp(parent->dev->name, mux->parent_names[i]))
return i;
+ if (!strcmp(parent->dev->name,
+ clk_resolve_parent_clk(clk->dev,
+ mux->parent_names[i])))
+ return i;
+
}
return -EINVAL;
@@ -159,15 +164,15 @@ const struct clk_ops clk_mux_ops = {
.set_parent = clk_mux_set_parent,
};
-struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
+struct clk *clk_register_mux(struct udevice *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
- void __iomem *reg, u8 shift, u32 mask,
- u8 clk_mux_flags, u32 *table)
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags)
{
+ u32 mask = BIT(width) - 1;
struct clk_mux *mux;
struct clk *clk;
- u8 width = 0;
int ret;
if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
@@ -192,7 +197,7 @@ struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
mux->shift = shift;
mux->mask = mask;
mux->flags = clk_mux_flags;
- mux->table = table;
+ mux->table = NULL;
#if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
mux->io_mux_val = *(u32 *)reg;
#endif
@@ -207,7 +212,8 @@ struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
* for the corresponding clock (to do that define .set_parent() method).
*/
ret = clk_register(clk, UBOOT_DM_CLK_CCF_MUX, name,
- parent_names[clk_mux_get_parent(clk)]);
+ clk_resolve_parent_clk(dev,
+ parent_names[clk_mux_get_parent(clk)]));
if (ret) {
kfree(mux);
return ERR_PTR(ret);
@@ -216,35 +222,6 @@ struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
return clk;
}
-struct clk *clk_register_mux_table(struct device *dev, const char *name,
- const char * const *parent_names, u8 num_parents,
- unsigned long flags,
- void __iomem *reg, u8 shift, u32 mask,
- u8 clk_mux_flags, u32 *table)
-{
- struct clk *clk;
-
- clk = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
- flags, reg, shift, mask, clk_mux_flags,
- table);
- if (IS_ERR(clk))
- return ERR_CAST(clk);
- return clk;
-}
-
-struct clk *clk_register_mux(struct device *dev, const char *name,
- const char * const *parent_names, u8 num_parents,
- unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
- u8 clk_mux_flags)
-{
- u32 mask = BIT(width) - 1;
-
- return clk_register_mux_table(dev, name, parent_names, num_parents,
- flags, reg, shift, mask, clk_mux_flags,
- NULL);
-}
-
U_BOOT_DRIVER(ccf_clk_mux) = {
.name = UBOOT_DM_CLK_CCF_MUX,
.id = UCLASS_CLK,
diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c
index 5fbbb07b7f7..343fa5cd3fe 100644
--- a/drivers/clk/clk-stub.c
+++ b/drivers/clk/clk-stub.c
@@ -50,6 +50,7 @@ static struct clk_ops stub_clk_ops = {
static const struct udevice_id stub_clk_ids[] = {
{ .compatible = "qcom,rpmcc" },
+ { .compatible = "qcom,sc7280-rpmh-clk" },
{ .compatible = "qcom,sm8150-rpmh-clk" },
{ .compatible = "qcom,sm8250-rpmh-clk" },
{ .compatible = "qcom,sm8550-rpmh-clk" },
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 353ae476068..90b70529a47 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -420,6 +420,24 @@ int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
return clk_get_by_index_nodev(node, index, clk);
}
+const char *
+clk_resolve_parent_clk(struct udevice *dev, const char *name)
+{
+ struct udevice *parent;
+ struct clk clk;
+ int ret;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, name, &parent);
+ if (!ret)
+ return name;
+
+ ret = clk_get_by_name(dev, name, &clk);
+ if (!clk.dev)
+ return name;
+
+ return clk.dev->name;
+}
+
int clk_release_all(struct clk *clk, unsigned int count)
{
unsigned int i;
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index 56d893e0579..d17a54fb9b3 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -60,6 +60,7 @@ config SPL_CLK_IMX8MP
depends on ARCH_IMX8M && SPL
select SPL_CLK
select SPL_CLK_CCF
+ select SPL_CLK_COMPOSITE_CCF
help
This enables SPL DM/DTS support for clock driver in i.MX8MP
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
index 64bffa3b181..14c5b92939c 100644
--- a/drivers/clk/imx/clk-composite-8m.c
+++ b/drivers/clk/imx/clk-composite-8m.c
@@ -151,7 +151,7 @@ const struct clk_ops imx8m_clk_mux_ops = {
.set_parent = imx8m_clk_mux_set_parent,
};
-struct clk *imx8m_clk_composite_flags(const char *name,
+struct clk *imx8m_clk_composite_flags(struct udevice *dev, const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg,
unsigned long flags)
@@ -187,7 +187,7 @@ struct clk *imx8m_clk_composite_flags(const char *name,
gate->reg = reg;
gate->bit_idx = PCG_CGC_SHIFT;
- clk = clk_register_composite(NULL, name,
+ clk = clk_register_composite(dev, name,
parent_names, num_parents,
&mux->clk, &imx8m_clk_mux_ops, &div->clk,
&imx8m_clk_composite_divider_ops,
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index 65fa6b5b139..fa07b13249b 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -90,7 +90,7 @@ static const struct clk_ops clk_gate2_ops = {
.get_rate = clk_generic_get_rate,
};
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk *clk_register_gate2(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, u8 cgr_val,
u8 clk_gate2_flags, unsigned int *share_count)
@@ -111,7 +111,8 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
clk = &gate->clk;
- ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE2, name, parent_name);
+ ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE2, name,
+ clk_resolve_parent_clk(dev, parent_name));
if (ret) {
kfree(gate);
return ERR_PTR(ret);
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index df9f0285e1e..13239f2f64d 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -35,6 +35,8 @@ static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
static const char *const periph_sels[] = { "periph_pre", "periph_clk2", };
static const char *const periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m",
"pll2_pfd0_352m", "pll2_198m", };
+static const char *const uart_sels[] = { "pll3_80m", "osc", };
+static const char *const ecspi_sels[] = { "pll3_60m", "osc", };
static int imx6q_clk_probe(struct udevice *dev)
{
@@ -44,21 +46,21 @@ static int imx6q_clk_probe(struct udevice *dev)
base = (void *)ANATOP_BASE_ADDR;
clk_dm(IMX6QDL_CLK_PLL2,
- imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc",
base + 0x30, 0x1));
clk_dm(IMX6QDL_CLK_PLL3_USB_OTG,
- imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg", "osc",
base + 0x10, 0x3));
clk_dm(IMX6QDL_CLK_PLL3_60M,
- imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8));
+ imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8));
clk_dm(IMX6QDL_CLK_PLL2_PFD0_352M,
imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0));
clk_dm(IMX6QDL_CLK_PLL2_PFD2_396M,
imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2));
clk_dm(IMX6QDL_CLK_PLL6,
- imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3));
+ imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3));
clk_dm(IMX6QDL_CLK_PLL6_ENET,
- imx_clk_gate("pll6_enet", "pll6", base + 0xe0, 13));
+ imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13));
/* CCM clocks */
base = dev_read_addr_ptr(dev);
@@ -66,76 +68,98 @@ static int imx6q_clk_probe(struct udevice *dev)
return -EINVAL;
clk_dm(IMX6QDL_CLK_USDHC1_SEL,
- imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
+ imx_clk_mux(dev, "usdhc1_sel", base + 0x1c, 16, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMX6QDL_CLK_USDHC2_SEL,
- imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
+ imx_clk_mux(dev, "usdhc2_sel", base + 0x1c, 17, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMX6QDL_CLK_USDHC3_SEL,
- imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1,
+ imx_clk_mux(dev, "usdhc3_sel", base + 0x1c, 18, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMX6QDL_CLK_USDHC4_SEL,
- imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1,
+ imx_clk_mux(dev, "usdhc4_sel", base + 0x1c, 19, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+ if (of_machine_is_compatible("fsl,imx6qp")) {
+ clk_dm(IMX6QDL_CLK_UART_SEL,
+ imx_clk_mux(dev, "uart_sel", base + 0x24, 6, 1, uart_sels,
+ ARRAY_SIZE(uart_sels)));
+ clk_dm(IMX6QDL_CLK_ECSPI_SEL,
+ imx_clk_mux(dev, "ecspi_sel", base + 0x38, 18, 1, ecspi_sels,
+ ARRAY_SIZE(ecspi_sels)));
+ }
+
clk_dm(IMX6QDL_CLK_USDHC1_PODF,
- imx_clk_divider("usdhc1_podf", "usdhc1_sel",
+ imx_clk_divider(dev, "usdhc1_podf", "usdhc1_sel",
base + 0x24, 11, 3));
clk_dm(IMX6QDL_CLK_USDHC2_PODF,
- imx_clk_divider("usdhc2_podf", "usdhc2_sel",
+ imx_clk_divider(dev, "usdhc2_podf", "usdhc2_sel",
base + 0x24, 16, 3));
clk_dm(IMX6QDL_CLK_USDHC3_PODF,
- imx_clk_divider("usdhc3_podf", "usdhc3_sel",
+ imx_clk_divider(dev, "usdhc3_podf", "usdhc3_sel",
base + 0x24, 19, 3));
clk_dm(IMX6QDL_CLK_USDHC4_PODF,
- imx_clk_divider("usdhc4_podf", "usdhc4_sel",
+ imx_clk_divider(dev, "usdhc4_podf", "usdhc4_sel",
base + 0x24, 22, 3));
- clk_dm(IMX6QDL_CLK_ECSPI_ROOT,
- imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6));
+ if (of_machine_is_compatible("fsl,imx6qp")) {
+ clk_dm(IMX6QDL_CLK_UART_SERIAL_PODF,
+ imx_clk_divider(dev, "uart_serial_podf", "uart_sel", base + 0x24, 0, 6));
+ clk_dm(IMX6QDL_CLK_ECSPI_ROOT,
+ imx_clk_divider(dev, "ecspi_root", "ecspi_sel", base + 0x38, 19, 6));
+ } else {
+ clk_dm(IMX6QDL_CLK_UART_SERIAL_PODF,
+ imx_clk_divider(dev, "uart_serial_podf", "pll3_80m", base + 0x24, 0, 6));
+ clk_dm(IMX6QDL_CLK_ECSPI_ROOT,
+ imx_clk_divider(dev, "ecspi_root", "pll3_60m", base + 0x38, 19, 6));
+ }
clk_dm(IMX6QDL_CLK_ECSPI1,
- imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
+ imx_clk_gate2(dev, "ecspi1", "ecspi_root", base + 0x6c, 0));
clk_dm(IMX6QDL_CLK_ECSPI2,
- imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2));
+ imx_clk_gate2(dev, "ecspi2", "ecspi_root", base + 0x6c, 2));
clk_dm(IMX6QDL_CLK_ECSPI3,
- imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4));
+ imx_clk_gate2(dev, "ecspi3", "ecspi_root", base + 0x6c, 4));
clk_dm(IMX6QDL_CLK_ECSPI4,
- imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6));
+ imx_clk_gate2(dev, "ecspi4", "ecspi_root", base + 0x6c, 6));
+ clk_dm(IMX6QDL_CLK_UART_IPG,
+ imx_clk_gate2(dev, "uart_ipg", "ipg", base + 0x7c, 24));
+ clk_dm(IMX6QDL_CLK_UART_SERIAL,
+ imx_clk_gate2(dev, "uart_serial", "uart_serial_podf", base + 0x7c, 26));
clk_dm(IMX6QDL_CLK_USDHC1,
- imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
+ imx_clk_gate2(dev, "usdhc1", "usdhc1_podf", base + 0x80, 2));
clk_dm(IMX6QDL_CLK_USDHC2,
- imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
+ imx_clk_gate2(dev, "usdhc2", "usdhc2_podf", base + 0x80, 4));
clk_dm(IMX6QDL_CLK_USDHC3,
- imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6));
+ imx_clk_gate2(dev, "usdhc3", "usdhc3_podf", base + 0x80, 6));
clk_dm(IMX6QDL_CLK_USDHC4,
- imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8));
+ imx_clk_gate2(dev, "usdhc4", "usdhc4_podf", base + 0x80, 8));
clk_dm(IMX6QDL_CLK_PERIPH_PRE,
- imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels,
+ imx_clk_mux(dev, "periph_pre", base + 0x18, 18, 2, periph_pre_sels,
ARRAY_SIZE(periph_pre_sels)));
clk_dm(IMX6QDL_CLK_PERIPH,
- imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48,
+ imx_clk_busy_mux(dev, "periph", base + 0x14, 25, 1, base + 0x48,
5, periph_sels, ARRAY_SIZE(periph_sels)));
clk_dm(IMX6QDL_CLK_AHB,
- imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3,
+ imx_clk_busy_divider(dev, "ahb", "periph", base + 0x14, 10, 3,
base + 0x48, 1));
clk_dm(IMX6QDL_CLK_IPG,
- imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2));
+ imx_clk_divider(dev, "ipg", "ahb", base + 0x14, 8, 2));
clk_dm(IMX6QDL_CLK_IPG_PER,
- imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6));
+ imx_clk_divider(dev, "ipg_per", "ipg", base + 0x1c, 0, 6));
clk_dm(IMX6QDL_CLK_I2C1,
- imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6));
+ imx_clk_gate2(dev, "i2c1", "ipg_per", base + 0x70, 6));
clk_dm(IMX6QDL_CLK_I2C2,
- imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8));
+ imx_clk_gate2(dev, "i2c2", "ipg_per", base + 0x70, 8));
clk_dm(IMX6QDL_CLK_I2C3,
- imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10));
+ imx_clk_gate2(dev, "i2c3", "ipg_per", base + 0x70, 10));
clk_dm(IMX6QDL_CLK_PWM1,
- imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16));
+ imx_clk_gate2(dev, "pwm1", "ipg_per", base + 0x78, 16));
- clk_dm(IMX6QDL_CLK_ENET, imx_clk_gate2("enet", "ipg", base + 0x6c, 10));
+ clk_dm(IMX6QDL_CLK_ENET, imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10));
clk_dm(IMX6QDL_CLK_ENET_REF,
- imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1));
+ imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1));
return 0;
}
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index bb6958f0ec2..b81db516a69 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -14,7 +14,7 @@
#include "clk.h"
-static const char * const pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", };
+static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
@@ -23,128 +23,144 @@ static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_se
static const char * const imx8mm_arm_core_sels[] = {"arm_a53_src", "arm_pll_out", };
-static const char * const imx8mm_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m",
+static const char * const imx8mm_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m",
"sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
"audio_pll1_out", "sys_pll3_out", };
-static const char * const imx8mm_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_800m",
+static const char * const imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m",
"sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out",
"audio_pll1_out", "video_pll1_out", };
#ifndef CONFIG_XPL_BUILD
-static const char * const imx8mm_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+static const char * const imx8mm_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out",
"video_pll1_out", "sys_pll3_out", };
-static const char * const imx8mm_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m",
+static const char * const imx8mm_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
"sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
"video_pll1_out", "clk_ext4", };
-static const char * const imx8mm_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out",
+static const char * const imx8mm_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
"clk_ext1", "clk_ext2", "clk_ext3",
"clk_ext4", "video_pll1_out", };
-static const char * const imx8mm_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m",
+static const char * const imx8mm_enet_phy_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m",
"sys_pll2_200m", "sys_pll2_500m", "video_pll1_out",
"audio_pll2_out", };
#endif
-static const char * const imx8mm_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+static const char * const imx8mm_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll1_out", };
-static const char * const imx8mm_usb_bus_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m",
+static const char * const imx8mm_usb_bus_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
-static const char * const imx8mm_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mm_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
-static const char * const imx8mm_usdhc2_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mm_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
-static const char * const imx8mm_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mm_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mm_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mm_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mm_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mm_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mm_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mm_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
+static const char * const imx8mm_uart1_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2", "clk_ext4",
+ "audio_pll2_out", };
+
+static const char * const imx8mm_uart2_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2", "clk_ext3",
+ "audio_pll2_out", };
+
+static const char * const imx8mm_uart3_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2", "clk_ext4",
+ "audio_pll2_out", };
+
+static const char * const imx8mm_uart4_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2", "clk_ext3",
+ "audio_pll2_out", };
+
#if CONFIG_IS_ENABLED(PCIE_DW_IMX)
-static const char * const imx8mm_pcie1_ctrl_sels[] = {"clock-osc-24m", "sys_pll2_250m", "sys_pll2_200m",
+static const char * const imx8mm_pcie1_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m",
"sys_pll1_266m", "sys_pll1_800m", "sys_pll2_500m",
"sys_pll2_333m", "sys_pll3_out", };
-static const char * const imx8mm_pcie1_phy_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll2_500m",
+static const char * const imx8mm_pcie1_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m",
"clk_ext1", "clk_ext2", "clk_ext3",
"clk_ext4", "sys_pll1_400m", };
-static const char * const imx8mm_pcie1_aux_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll2_50m",
+static const char * const imx8mm_pcie1_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m",
"sys_pll3_out", "sys_pll2_100m", "sys_pll1_80m",
"sys_pll1_160m", "sys_pll1_200m", };
#endif
#ifndef CONFIG_XPL_BUILD
-static const char * const imx8mm_pwm1_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mm_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mm_pwm2_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mm_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mm_pwm3_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mm_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mm_pwm4_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mm_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
"sys_pll1_80m", "video_pll1_out", };
#endif
-static const char * const imx8mm_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m",
+static const char * const imx8mm_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m",
"vpu_pll_out", "sys_pll2_125m", "sys_pll3_out",
"sys_pll1_80m", "sys_pll2_166m", };
-static const char * const imx8mm_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mm_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_clk", "sys_pll1_100m", };
#if CONFIG_IS_ENABLED(NXP_FSPI)
-static const char * const imx8mm_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m",
+static const char * const imx8mm_qspi_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll2_333m",
"sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m",
"sys_pll3_out", "sys_pll1_100m", };
#endif
-static const char * const imx8mm_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+static const char * const imx8mm_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
-static const char * const imx8mm_usb_phy_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+static const char * const imx8mm_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
#if CONFIG_IS_ENABLED(DM_SPI)
-static const char * const imx8mm_ecspi1_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mm_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mm_ecspi2_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mm_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mm_ecspi3_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mm_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
#endif
@@ -156,19 +172,19 @@ static int imx8mm_clk_probe(struct udevice *dev)
base = (void *)ANATOP_BASE_ADDR;
clk_dm(IMX8MM_DRAM_PLL_REF_SEL,
- imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2,
+ imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x50, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MM_ARM_PLL_REF_SEL,
- imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2,
+ imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x84, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MM_SYS_PLL1_REF_SEL,
- imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2,
+ imx_clk_mux(dev, "sys_pll1_ref_sel", base + 0x94, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MM_SYS_PLL2_REF_SEL,
- imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2,
+ imx_clk_mux(dev, "sys_pll2_ref_sel", base + 0x104, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MM_SYS_PLL3_REF_SEL,
- imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2,
+ imx_clk_mux(dev, "sys_pll3_ref_sel", base + 0x114, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MM_DRAM_PLL,
@@ -189,238 +205,254 @@ static int imx8mm_clk_probe(struct udevice *dev)
/* PLL bypass out */
clk_dm(IMX8MM_DRAM_PLL_BYPASS,
- imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1,
+ imx_clk_mux_flags(dev, "dram_pll_bypass", base + 0x50, 4, 1,
dram_pll_bypass_sels,
ARRAY_SIZE(dram_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MM_ARM_PLL_BYPASS,
- imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1,
+ imx_clk_mux_flags(dev, "arm_pll_bypass", base + 0x84, 4, 1,
arm_pll_bypass_sels,
ARRAY_SIZE(arm_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MM_SYS_PLL1_BYPASS,
- imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1,
+ imx_clk_mux_flags(dev, "sys_pll1_bypass", base + 0x94, 4, 1,
sys_pll1_bypass_sels,
ARRAY_SIZE(sys_pll1_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MM_SYS_PLL2_BYPASS,
- imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1,
+ imx_clk_mux_flags(dev, "sys_pll2_bypass", base + 0x104, 4, 1,
sys_pll2_bypass_sels,
ARRAY_SIZE(sys_pll2_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MM_SYS_PLL3_BYPASS,
- imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1,
+ imx_clk_mux_flags(dev, "sys_pll3_bypass", base + 0x114, 4, 1,
sys_pll3_bypass_sels,
ARRAY_SIZE(sys_pll3_bypass_sels),
CLK_SET_RATE_PARENT));
/* PLL out gate */
clk_dm(IMX8MM_DRAM_PLL_OUT,
- imx_clk_gate("dram_pll_out", "dram_pll_bypass",
+ imx_clk_gate(dev, "dram_pll_out", "dram_pll_bypass",
base + 0x50, 13));
clk_dm(IMX8MM_ARM_PLL_OUT,
- imx_clk_gate("arm_pll_out", "arm_pll_bypass",
+ imx_clk_gate(dev, "arm_pll_out", "arm_pll_bypass",
base + 0x84, 11));
clk_dm(IMX8MM_SYS_PLL1_OUT,
- imx_clk_gate("sys_pll1_out", "sys_pll1_bypass",
+ imx_clk_gate(dev, "sys_pll1_out", "sys_pll1_bypass",
base + 0x94, 11));
clk_dm(IMX8MM_SYS_PLL2_OUT,
- imx_clk_gate("sys_pll2_out", "sys_pll2_bypass",
+ imx_clk_gate(dev, "sys_pll2_out", "sys_pll2_bypass",
base + 0x104, 11));
clk_dm(IMX8MM_SYS_PLL3_OUT,
- imx_clk_gate("sys_pll3_out", "sys_pll3_bypass",
+ imx_clk_gate(dev, "sys_pll3_out", "sys_pll3_bypass",
base + 0x114, 11));
/* SYS PLL fixed output */
clk_dm(IMX8MM_SYS_PLL1_40M,
- imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20));
+ imx_clk_fixed_factor(dev, "sys_pll1_40m", "sys_pll1_out", 1, 20));
clk_dm(IMX8MM_SYS_PLL1_80M,
- imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10));
+ imx_clk_fixed_factor(dev, "sys_pll1_80m", "sys_pll1_out", 1, 10));
clk_dm(IMX8MM_SYS_PLL1_100M,
- imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8));
+ imx_clk_fixed_factor(dev, "sys_pll1_100m", "sys_pll1_out", 1, 8));
clk_dm(IMX8MM_SYS_PLL1_133M,
- imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6));
+ imx_clk_fixed_factor(dev, "sys_pll1_133m", "sys_pll1_out", 1, 6));
clk_dm(IMX8MM_SYS_PLL1_160M,
- imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5));
+ imx_clk_fixed_factor(dev, "sys_pll1_160m", "sys_pll1_out", 1, 5));
clk_dm(IMX8MM_SYS_PLL1_200M,
- imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4));
+ imx_clk_fixed_factor(dev, "sys_pll1_200m", "sys_pll1_out", 1, 4));
clk_dm(IMX8MM_SYS_PLL1_266M,
- imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3));
+ imx_clk_fixed_factor(dev, "sys_pll1_266m", "sys_pll1_out", 1, 3));
clk_dm(IMX8MM_SYS_PLL1_400M,
- imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll1_400m", "sys_pll1_out", 1, 2));
clk_dm(IMX8MM_SYS_PLL1_800M,
- imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1));
+ imx_clk_fixed_factor(dev, "sys_pll1_800m", "sys_pll1_out", 1, 1));
clk_dm(IMX8MM_SYS_PLL2_50M,
- imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20));
+ imx_clk_fixed_factor(dev, "sys_pll2_50m", "sys_pll2_out", 1, 20));
clk_dm(IMX8MM_SYS_PLL2_100M,
- imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10));
+ imx_clk_fixed_factor(dev, "sys_pll2_100m", "sys_pll2_out", 1, 10));
clk_dm(IMX8MM_SYS_PLL2_125M,
- imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8));
+ imx_clk_fixed_factor(dev, "sys_pll2_125m", "sys_pll2_out", 1, 8));
clk_dm(IMX8MM_SYS_PLL2_166M,
- imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6));
+ imx_clk_fixed_factor(dev, "sys_pll2_166m", "sys_pll2_out", 1, 6));
clk_dm(IMX8MM_SYS_PLL2_200M,
- imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5));
+ imx_clk_fixed_factor(dev, "sys_pll2_200m", "sys_pll2_out", 1, 5));
clk_dm(IMX8MM_SYS_PLL2_250M,
- imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4));
+ imx_clk_fixed_factor(dev, "sys_pll2_250m", "sys_pll2_out", 1, 4));
clk_dm(IMX8MM_SYS_PLL2_333M,
- imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3));
+ imx_clk_fixed_factor(dev, "sys_pll2_333m", "sys_pll2_out", 1, 3));
clk_dm(IMX8MM_SYS_PLL2_500M,
- imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll2_500m", "sys_pll2_out", 1, 2));
clk_dm(IMX8MM_SYS_PLL2_1000M,
- imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1));
+ imx_clk_fixed_factor(dev, "sys_pll2_1000m", "sys_pll2_out", 1, 1));
base = dev_read_addr_ptr(dev);
if (!base)
return -EINVAL;
clk_dm(IMX8MM_CLK_A53_SRC,
- imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3,
+ imx_clk_mux2(dev, "arm_a53_src", base + 0x8000, 24, 3,
imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels)));
clk_dm(IMX8MM_CLK_A53_CG,
- imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
+ imx_clk_gate3(dev, "arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
clk_dm(IMX8MM_CLK_A53_DIV,
- imx_clk_divider2("arm_a53_div", "arm_a53_cg",
+ imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg",
base + 0x8000, 0, 3));
clk_dm(IMX8MM_CLK_AHB,
- imx8m_clk_composite_critical("ahb", imx8mm_ahb_sels,
+ imx8m_clk_composite_critical(dev, "ahb", imx8mm_ahb_sels,
base + 0x9000));
clk_dm(IMX8MM_CLK_IPG_ROOT,
- imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1));
+ imx_clk_divider2(dev, "ipg_root", "ahb", base + 0x9080, 0, 1));
clk_dm(IMX8MM_CLK_NAND_USDHC_BUS,
- imx8m_clk_composite_critical("nand_usdhc_bus",
+ imx8m_clk_composite_critical(dev, "nand_usdhc_bus",
imx8mm_nand_usdhc_sels,
base + 0x8900));
clk_dm(IMX8MM_CLK_USB_BUS,
- imx8m_clk_composite("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80));
+ imx8m_clk_composite(dev, "usb_bus", imx8mm_usb_bus_sels, base + 0x8b80));
/* IP */
#if CONFIG_IS_ENABLED(PCIE_DW_IMX)
clk_dm(IMX8MM_CLK_PCIE1_CTRL,
- imx8m_clk_composite("pcie1_ctrl", imx8mm_pcie1_ctrl_sels,
+ imx8m_clk_composite(dev, "pcie1_ctrl", imx8mm_pcie1_ctrl_sels,
base + 0xa300));
clk_dm(IMX8MM_CLK_PCIE1_PHY,
- imx8m_clk_composite("pcie1_phy", imx8mm_pcie1_phy_sels,
+ imx8m_clk_composite(dev, "pcie1_phy", imx8mm_pcie1_phy_sels,
base + 0xa380));
clk_dm(IMX8MM_CLK_PCIE1_AUX,
- imx8m_clk_composite("pcie1_aux", imx8mm_pcie1_aux_sels,
+ imx8m_clk_composite(dev, "pcie1_aux", imx8mm_pcie1_aux_sels,
base + 0xa400));
#endif
clk_dm(IMX8MM_CLK_USDHC1,
- imx8m_clk_composite("usdhc1", imx8mm_usdhc1_sels,
+ imx8m_clk_composite(dev, "usdhc1", imx8mm_usdhc1_sels,
base + 0xac00));
clk_dm(IMX8MM_CLK_USDHC2,
- imx8m_clk_composite("usdhc2", imx8mm_usdhc2_sels,
+ imx8m_clk_composite(dev, "usdhc2", imx8mm_usdhc2_sels,
base + 0xac80));
clk_dm(IMX8MM_CLK_I2C1,
- imx8m_clk_composite("i2c1", imx8mm_i2c1_sels, base + 0xad00));
+ imx8m_clk_composite(dev, "i2c1", imx8mm_i2c1_sels, base + 0xad00));
clk_dm(IMX8MM_CLK_I2C2,
- imx8m_clk_composite("i2c2", imx8mm_i2c2_sels, base + 0xad80));
+ imx8m_clk_composite(dev, "i2c2", imx8mm_i2c2_sels, base + 0xad80));
clk_dm(IMX8MM_CLK_I2C3,
- imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00));
+ imx8m_clk_composite(dev, "i2c3", imx8mm_i2c3_sels, base + 0xae00));
clk_dm(IMX8MM_CLK_I2C4,
- imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80));
+ imx8m_clk_composite(dev, "i2c4", imx8mm_i2c4_sels, base + 0xae80));
+ clk_dm(IMX8MM_CLK_UART1,
+ imx8m_clk_composite(dev, "uart1", imx8mm_uart1_sels, base + 0xaf00));
+ clk_dm(IMX8MM_CLK_UART2,
+ imx8m_clk_composite(dev, "uart2", imx8mm_uart2_sels, base + 0xaf80));
+ clk_dm(IMX8MM_CLK_UART3,
+ imx8m_clk_composite(dev, "uart3", imx8mm_uart3_sels, base + 0xb000));
+ clk_dm(IMX8MM_CLK_UART4,
+ imx8m_clk_composite(dev, "uart4", imx8mm_uart4_sels, base + 0xb080));
+ clk_dm(IMX8MM_CLK_UART1_ROOT,
+ imx_clk_gate4(dev, "uart1_root_clk", "uart1", base + 0x4490, 0));
+ clk_dm(IMX8MM_CLK_UART2_ROOT,
+ imx_clk_gate4(dev, "uart2_root_clk", "uart2", base + 0x44a0, 0));
+ clk_dm(IMX8MM_CLK_UART3_ROOT,
+ imx_clk_gate4(dev, "uart3_root_clk", "uart3", base + 0x44b0, 0));
+ clk_dm(IMX8MM_CLK_UART4_ROOT,
+ imx_clk_gate4(dev, "uart4_root_clk", "uart4", base + 0x44c0, 0));
clk_dm(IMX8MM_CLK_WDOG,
- imx8m_clk_composite("wdog", imx8mm_wdog_sels, base + 0xb900));
+ imx8m_clk_composite(dev, "wdog", imx8mm_wdog_sels, base + 0xb900));
clk_dm(IMX8MM_CLK_USDHC3,
- imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels,
+ imx8m_clk_composite(dev, "usdhc3", imx8mm_usdhc3_sels,
base + 0xbc80));
clk_dm(IMX8MM_CLK_USB_CORE_REF,
- imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100));
+ imx8m_clk_composite(dev, "usb_core_ref", imx8mm_usb_core_sels, base + 0xb100));
clk_dm(IMX8MM_CLK_USB_PHY_REF,
- imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180));
+ imx8m_clk_composite(dev, "usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180));
clk_dm(IMX8MM_CLK_I2C1_ROOT,
- imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
+ imx_clk_gate4(dev, "i2c1_root_clk", "i2c1", base + 0x4170, 0));
clk_dm(IMX8MM_CLK_I2C2_ROOT,
- imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0));
+ imx_clk_gate4(dev, "i2c2_root_clk", "i2c2", base + 0x4180, 0));
clk_dm(IMX8MM_CLK_I2C3_ROOT,
- imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0));
+ imx_clk_gate4(dev, "i2c3_root_clk", "i2c3", base + 0x4190, 0));
clk_dm(IMX8MM_CLK_I2C4_ROOT,
- imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0));
+ imx_clk_gate4(dev, "i2c4_root_clk", "i2c4", base + 0x41a0, 0));
clk_dm(IMX8MM_CLK_OCOTP_ROOT,
- imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0));
+ imx_clk_gate4(dev, "ocotp_root_clk", "ipg_root", base + 0x4220, 0));
clk_dm(IMX8MM_CLK_USDHC1_ROOT,
- imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
+ imx_clk_gate4(dev, "usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
clk_dm(IMX8MM_CLK_USDHC2_ROOT,
- imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
+ imx_clk_gate4(dev, "usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
clk_dm(IMX8MM_CLK_WDOG1_ROOT,
- imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0));
+ imx_clk_gate4(dev, "wdog1_root_clk", "wdog", base + 0x4530, 0));
clk_dm(IMX8MM_CLK_WDOG2_ROOT,
- imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0));
+ imx_clk_gate4(dev, "wdog2_root_clk", "wdog", base + 0x4540, 0));
clk_dm(IMX8MM_CLK_WDOG3_ROOT,
- imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
+ imx_clk_gate4(dev, "wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MM_CLK_USDHC3_ROOT,
- imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
+ imx_clk_gate4(dev, "usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
clk_dm(IMX8MM_CLK_USB1_CTRL_ROOT,
- imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
+ imx_clk_gate4(dev, "usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
/* clks not needed in SPL stage */
#ifndef CONFIG_XPL_BUILD
clk_dm(IMX8MM_CLK_ENET_AXI,
- imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels,
+ imx8m_clk_composite(dev, "enet_axi", imx8mm_enet_axi_sels,
base + 0x8880));
clk_dm(IMX8MM_CLK_ENET_REF,
- imx8m_clk_composite("enet_ref", imx8mm_enet_ref_sels,
+ imx8m_clk_composite(dev, "enet_ref", imx8mm_enet_ref_sels,
base + 0xa980));
clk_dm(IMX8MM_CLK_ENET_TIMER,
- imx8m_clk_composite("enet_timer", imx8mm_enet_timer_sels,
+ imx8m_clk_composite(dev, "enet_timer", imx8mm_enet_timer_sels,
base + 0xaa00));
clk_dm(IMX8MM_CLK_ENET_PHY_REF,
- imx8m_clk_composite("enet_phy", imx8mm_enet_phy_sels,
+ imx8m_clk_composite(dev, "enet_phy", imx8mm_enet_phy_sels,
base + 0xaa80));
clk_dm(IMX8MM_CLK_ENET1_ROOT,
- imx_clk_gate4("enet1_root_clk", "enet_axi",
+ imx_clk_gate4(dev, "enet1_root_clk", "enet_axi",
base + 0x40a0, 0));
clk_dm(IMX8MM_CLK_PWM1,
- imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380));
+ imx8m_clk_composite(dev, "pwm1", imx8mm_pwm1_sels, base + 0xb380));
clk_dm(IMX8MM_CLK_PWM2,
- imx8m_clk_composite("pwm2", imx8mm_pwm2_sels, base + 0xb400));
+ imx8m_clk_composite(dev, "pwm2", imx8mm_pwm2_sels, base + 0xb400));
clk_dm(IMX8MM_CLK_PWM3,
- imx8m_clk_composite("pwm3", imx8mm_pwm3_sels, base + 0xb480));
+ imx8m_clk_composite(dev, "pwm3", imx8mm_pwm3_sels, base + 0xb480));
clk_dm(IMX8MM_CLK_PWM4,
- imx8m_clk_composite("pwm4", imx8mm_pwm4_sels, base + 0xb500));
+ imx8m_clk_composite(dev, "pwm4", imx8mm_pwm4_sels, base + 0xb500));
clk_dm(IMX8MM_CLK_PWM1_ROOT,
- imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0));
+ imx_clk_gate4(dev, "pwm1_root_clk", "pwm1", base + 0x4280, 0));
clk_dm(IMX8MM_CLK_PWM2_ROOT,
- imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0));
+ imx_clk_gate4(dev, "pwm2_root_clk", "pwm2", base + 0x4290, 0));
clk_dm(IMX8MM_CLK_PWM3_ROOT,
- imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0));
+ imx_clk_gate4(dev, "pwm3_root_clk", "pwm3", base + 0x42a0, 0));
clk_dm(IMX8MM_CLK_PWM4_ROOT,
- imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0));
+ imx_clk_gate4(dev, "pwm4_root_clk", "pwm4", base + 0x42b0, 0));
#endif
#if CONFIG_IS_ENABLED(PCIE_DW_IMX)
clk_dm(IMX8MM_CLK_PCIE1_ROOT,
- imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0));
+ imx_clk_gate4(dev, "pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0));
#endif
#if CONFIG_IS_ENABLED(DM_SPI)
clk_dm(IMX8MM_CLK_ECSPI1,
- imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280));
+ imx8m_clk_composite(dev, "ecspi1", imx8mm_ecspi1_sels, base + 0xb280));
clk_dm(IMX8MM_CLK_ECSPI2,
- imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300));
+ imx8m_clk_composite(dev, "ecspi2", imx8mm_ecspi2_sels, base + 0xb300));
clk_dm(IMX8MM_CLK_ECSPI3,
- imx8m_clk_composite("ecspi3", imx8mm_ecspi3_sels, base + 0xc180));
+ imx8m_clk_composite(dev, "ecspi3", imx8mm_ecspi3_sels, base + 0xc180));
clk_dm(IMX8MM_CLK_ECSPI1_ROOT,
- imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
+ imx_clk_gate4(dev, "ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
clk_dm(IMX8MM_CLK_ECSPI2_ROOT,
- imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
+ imx_clk_gate4(dev, "ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
clk_dm(IMX8MM_CLK_ECSPI3_ROOT,
- imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
+ imx_clk_gate4(dev, "ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
#endif
#if CONFIG_IS_ENABLED(NXP_FSPI)
clk_dm(IMX8MM_CLK_QSPI,
- imx8m_clk_composite("qspi", imx8mm_qspi_sels, base + 0xab80));
+ imx8m_clk_composite(dev, "qspi", imx8mm_qspi_sels, base + 0xab80));
clk_dm(IMX8MM_CLK_QSPI_ROOT,
- imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
+ imx_clk_gate4(dev, "qspi_root_clk", "qspi", base + 0x42f0, 0));
#endif
clk_dm(IMX8MM_CLK_ARM,
- imx_clk_mux2_flags("arm_core", base + 0x9880, 24, 1,
+ imx_clk_mux2_flags(dev, "arm_core", base + 0x9880, 24, 1,
imx8mm_arm_core_sels,
ARRAY_SIZE(imx8mm_arm_core_sels),
CLK_IS_CRITICAL));
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index be15ebd0e25..be5b7933a8d 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -16,7 +16,7 @@
static u32 share_count_nand;
-static const char * const pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", };
+static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
@@ -25,117 +25,133 @@ static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_se
static const char * const imx8mn_arm_core_sels[] = {"arm_a53_src", "arm_pll_out", };
-static const char * const imx8mn_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m",
+static const char * const imx8mn_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m",
"sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
"audio_pll1_out", "sys_pll3_out", };
-static const char * const imx8mn_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_800m",
+static const char * const imx8mn_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m",
"sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out",
"audio_pll1_out", "video_pll_out", };
-static const char * const imx8mn_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+static const char * const imx8mn_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out",
"video_pll_out", "sys_pll3_out", };
#ifndef CONFIG_XPL_BUILD
-static const char * const imx8mn_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m",
+static const char * const imx8mn_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
"sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
"video_pll_out", "clk_ext4", };
-static const char * const imx8mn_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out",
+static const char * const imx8mn_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
"clk_ext1", "clk_ext2", "clk_ext3",
"clk_ext4", "video_pll_out", };
-static const char * const imx8mn_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m",
+static const char * const imx8mn_enet_phy_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m",
"sys_pll2_200m", "sys_pll2_500m", "audio_pll1_out",
"video_pll_out", "audio_pll2_out", };
#endif
-static const char * const imx8mn_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+static const char * const imx8mn_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll1_out", };
-static const char * const imx8mn_usb_bus_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m",
+static const char * const imx8mn_usb_bus_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
-static const char * const imx8mn_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mn_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
-static const char * const imx8mn_usdhc2_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mn_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
#if CONFIG_IS_ENABLED(DM_SPI)
-static const char * const imx8mn_ecspi1_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mn_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mn_ecspi2_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mn_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mn_ecspi3_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mn_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
#endif
-static const char * const imx8mn_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mn_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mn_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mn_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mn_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mn_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mn_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mn_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll_out",
"audio_pll2_out", "sys_pll1_133m", };
+static const char * const imx8mn_uart1_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mn_uart2_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_uart3_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext4", "audio_pll2_out", };
+
+static const char * const imx8mn_uart4_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+ "sys_pll2_100m", "sys_pll3_out", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
#ifndef CONFIG_XPL_BUILD
-static const char * const imx8mn_pwm1_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mn_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
"sys_pll1_80m", "video_pll_out", };
-static const char * const imx8mn_pwm2_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mn_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
"sys_pll1_80m", "video_pll_out", };
-static const char * const imx8mn_pwm3_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mn_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
"sys_pll1_80m", "video_pll_out", };
-static const char * const imx8mn_pwm4_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mn_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
"sys_pll1_80m", "video_pll_out", };
#endif
-static const char * const imx8mn_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m",
+static const char * const imx8mn_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m",
"m7_alt_pll", "sys_pll2_125m", "sys_pll3_out",
"sys_pll1_80m", "sys_pll2_166m", };
-static const char * const imx8mn_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mn_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_clk", "sys_pll1_100m", };
-static const char * const imx8mn_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m",
+static const char * const imx8mn_qspi_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll2_333m",
"sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m",
"sys_pll3_out", "sys_pll1_100m", };
-static const char * const imx8mn_nand_sels[] = {"clock-osc-24m", "sys_pll2_500m", "audio_pll1_out",
+static const char * const imx8mn_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out",
"sys_pll1_400m", "audio_pll2_out", "sys_pll3_out",
"sys_pll2_250m", "video_pll_out", };
-static const char * const imx8mn_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+static const char * const imx8mn_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
-static const char * const imx8mn_usb_phy_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+static const char * const imx8mn_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
@@ -148,19 +164,19 @@ static int imx8mn_clk_probe(struct udevice *dev)
base = (void *)ANATOP_BASE_ADDR;
clk_dm(IMX8MN_DRAM_PLL_REF_SEL,
- imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2,
+ imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x50, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MN_ARM_PLL_REF_SEL,
- imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2,
+ imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x84, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MN_SYS_PLL1_REF_SEL,
- imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2,
+ imx_clk_mux(dev, "sys_pll1_ref_sel", base + 0x94, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MN_SYS_PLL2_REF_SEL,
- imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2,
+ imx_clk_mux(dev, "sys_pll2_ref_sel", base + 0x104, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MN_SYS_PLL3_REF_SEL,
- imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2,
+ imx_clk_mux(dev, "sys_pll3_ref_sel", base + 0x114, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MN_DRAM_PLL,
@@ -181,86 +197,86 @@ static int imx8mn_clk_probe(struct udevice *dev)
/* PLL bypass out */
clk_dm(IMX8MN_DRAM_PLL_BYPASS,
- imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1,
+ imx_clk_mux_flags(dev, "dram_pll_bypass", base + 0x50, 4, 1,
dram_pll_bypass_sels,
ARRAY_SIZE(dram_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MN_ARM_PLL_BYPASS,
- imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1,
+ imx_clk_mux_flags(dev, "arm_pll_bypass", base + 0x84, 4, 1,
arm_pll_bypass_sels,
ARRAY_SIZE(arm_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MN_SYS_PLL1_BYPASS,
- imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1,
+ imx_clk_mux_flags(dev, "sys_pll1_bypass", base + 0x94, 4, 1,
sys_pll1_bypass_sels,
ARRAY_SIZE(sys_pll1_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MN_SYS_PLL2_BYPASS,
- imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1,
+ imx_clk_mux_flags(dev, "sys_pll2_bypass", base + 0x104, 4, 1,
sys_pll2_bypass_sels,
ARRAY_SIZE(sys_pll2_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MN_SYS_PLL3_BYPASS,
- imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1,
+ imx_clk_mux_flags(dev, "sys_pll3_bypass", base + 0x114, 4, 1,
sys_pll3_bypass_sels,
ARRAY_SIZE(sys_pll3_bypass_sels),
CLK_SET_RATE_PARENT));
/* PLL out gate */
clk_dm(IMX8MN_DRAM_PLL_OUT,
- imx_clk_gate("dram_pll_out", "dram_pll_bypass",
+ imx_clk_gate(dev, "dram_pll_out", "dram_pll_bypass",
base + 0x50, 13));
clk_dm(IMX8MN_ARM_PLL_OUT,
- imx_clk_gate("arm_pll_out", "arm_pll_bypass",
+ imx_clk_gate(dev, "arm_pll_out", "arm_pll_bypass",
base + 0x84, 11));
clk_dm(IMX8MN_SYS_PLL1_OUT,
- imx_clk_gate("sys_pll1_out", "sys_pll1_bypass",
+ imx_clk_gate(dev, "sys_pll1_out", "sys_pll1_bypass",
base + 0x94, 11));
clk_dm(IMX8MN_SYS_PLL2_OUT,
- imx_clk_gate("sys_pll2_out", "sys_pll2_bypass",
+ imx_clk_gate(dev, "sys_pll2_out", "sys_pll2_bypass",
base + 0x104, 11));
clk_dm(IMX8MN_SYS_PLL3_OUT,
- imx_clk_gate("sys_pll3_out", "sys_pll3_bypass",
+ imx_clk_gate(dev, "sys_pll3_out", "sys_pll3_bypass",
base + 0x114, 11));
/* SYS PLL fixed output */
clk_dm(IMX8MN_SYS_PLL1_40M,
- imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20));
+ imx_clk_fixed_factor(dev, "sys_pll1_40m", "sys_pll1_out", 1, 20));
clk_dm(IMX8MN_SYS_PLL1_80M,
- imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10));
+ imx_clk_fixed_factor(dev, "sys_pll1_80m", "sys_pll1_out", 1, 10));
clk_dm(IMX8MN_SYS_PLL1_100M,
- imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8));
+ imx_clk_fixed_factor(dev, "sys_pll1_100m", "sys_pll1_out", 1, 8));
clk_dm(IMX8MN_SYS_PLL1_133M,
- imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6));
+ imx_clk_fixed_factor(dev, "sys_pll1_133m", "sys_pll1_out", 1, 6));
clk_dm(IMX8MN_SYS_PLL1_160M,
- imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5));
+ imx_clk_fixed_factor(dev, "sys_pll1_160m", "sys_pll1_out", 1, 5));
clk_dm(IMX8MN_SYS_PLL1_200M,
- imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4));
+ imx_clk_fixed_factor(dev, "sys_pll1_200m", "sys_pll1_out", 1, 4));
clk_dm(IMX8MN_SYS_PLL1_266M,
- imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3));
+ imx_clk_fixed_factor(dev, "sys_pll1_266m", "sys_pll1_out", 1, 3));
clk_dm(IMX8MN_SYS_PLL1_400M,
- imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll1_400m", "sys_pll1_out", 1, 2));
clk_dm(IMX8MN_SYS_PLL1_800M,
- imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1));
+ imx_clk_fixed_factor(dev, "sys_pll1_800m", "sys_pll1_out", 1, 1));
clk_dm(IMX8MN_SYS_PLL2_50M,
- imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20));
+ imx_clk_fixed_factor(dev, "sys_pll2_50m", "sys_pll2_out", 1, 20));
clk_dm(IMX8MN_SYS_PLL2_100M,
- imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10));
+ imx_clk_fixed_factor(dev, "sys_pll2_100m", "sys_pll2_out", 1, 10));
clk_dm(IMX8MN_SYS_PLL2_125M,
- imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8));
+ imx_clk_fixed_factor(dev, "sys_pll2_125m", "sys_pll2_out", 1, 8));
clk_dm(IMX8MN_SYS_PLL2_166M,
- imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6));
+ imx_clk_fixed_factor(dev, "sys_pll2_166m", "sys_pll2_out", 1, 6));
clk_dm(IMX8MN_SYS_PLL2_200M,
- imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5));
+ imx_clk_fixed_factor(dev, "sys_pll2_200m", "sys_pll2_out", 1, 5));
clk_dm(IMX8MN_SYS_PLL2_250M,
- imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4));
+ imx_clk_fixed_factor(dev, "sys_pll2_250m", "sys_pll2_out", 1, 4));
clk_dm(IMX8MN_SYS_PLL2_333M,
- imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3));
+ imx_clk_fixed_factor(dev, "sys_pll2_333m", "sys_pll2_out", 1, 3));
clk_dm(IMX8MN_SYS_PLL2_500M,
- imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll2_500m", "sys_pll2_out", 1, 2));
clk_dm(IMX8MN_SYS_PLL2_1000M,
- imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1));
+ imx_clk_fixed_factor(dev, "sys_pll2_1000m", "sys_pll2_out", 1, 1));
ret = clk_get_by_name(dev, "osc_24m", &osc_24m_clk);
if (ret)
@@ -272,141 +288,157 @@ static int imx8mn_clk_probe(struct udevice *dev)
return -EINVAL;
clk_dm(IMX8MN_CLK_A53_SRC,
- imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3,
+ imx_clk_mux2(dev, "arm_a53_src", base + 0x8000, 24, 3,
imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels)));
clk_dm(IMX8MN_CLK_A53_CG,
- imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
+ imx_clk_gate3(dev, "arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
clk_dm(IMX8MN_CLK_A53_DIV,
- imx_clk_divider2("arm_a53_div", "arm_a53_cg",
+ imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg",
base + 0x8000, 0, 3));
clk_dm(IMX8MN_CLK_AHB,
- imx8m_clk_composite_critical("ahb", imx8mn_ahb_sels,
+ imx8m_clk_composite_critical(dev, "ahb", imx8mn_ahb_sels,
base + 0x9000));
clk_dm(IMX8MN_CLK_IPG_ROOT,
- imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1));
+ imx_clk_divider2(dev, "ipg_root", "ahb", base + 0x9080, 0, 1));
clk_dm(IMX8MN_CLK_ENET_AXI,
- imx8m_clk_composite("enet_axi", imx8mn_enet_axi_sels,
+ imx8m_clk_composite(dev, "enet_axi", imx8mn_enet_axi_sels,
base + 0x8880));
clk_dm(IMX8MN_CLK_NAND_USDHC_BUS,
- imx8m_clk_composite_critical("nand_usdhc_bus",
+ imx8m_clk_composite_critical(dev, "nand_usdhc_bus",
imx8mn_nand_usdhc_sels,
base + 0x8900));
clk_dm(IMX8MN_CLK_USB_BUS,
- imx8m_clk_composite("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80));
+ imx8m_clk_composite(dev, "usb_bus", imx8mn_usb_bus_sels, base + 0x8b80));
/* IP */
clk_dm(IMX8MN_CLK_USDHC1,
- imx8m_clk_composite("usdhc1", imx8mn_usdhc1_sels,
+ imx8m_clk_composite(dev, "usdhc1", imx8mn_usdhc1_sels,
base + 0xac00));
clk_dm(IMX8MN_CLK_USDHC2,
- imx8m_clk_composite("usdhc2", imx8mn_usdhc2_sels,
+ imx8m_clk_composite(dev, "usdhc2", imx8mn_usdhc2_sels,
base + 0xac80));
clk_dm(IMX8MN_CLK_I2C1,
- imx8m_clk_composite("i2c1", imx8mn_i2c1_sels, base + 0xad00));
+ imx8m_clk_composite(dev, "i2c1", imx8mn_i2c1_sels, base + 0xad00));
clk_dm(IMX8MN_CLK_I2C2,
- imx8m_clk_composite("i2c2", imx8mn_i2c2_sels, base + 0xad80));
+ imx8m_clk_composite(dev, "i2c2", imx8mn_i2c2_sels, base + 0xad80));
clk_dm(IMX8MN_CLK_I2C3,
- imx8m_clk_composite("i2c3", imx8mn_i2c3_sels, base + 0xae00));
+ imx8m_clk_composite(dev, "i2c3", imx8mn_i2c3_sels, base + 0xae00));
clk_dm(IMX8MN_CLK_I2C4,
- imx8m_clk_composite("i2c4", imx8mn_i2c4_sels, base + 0xae80));
+ imx8m_clk_composite(dev, "i2c4", imx8mn_i2c4_sels, base + 0xae80));
+ clk_dm(IMX8MN_CLK_UART1,
+ imx8m_clk_composite(dev, "uart1", imx8mn_uart1_sels, base + 0xaf00));
+ clk_dm(IMX8MN_CLK_UART2,
+ imx8m_clk_composite(dev, "uart2", imx8mn_uart2_sels, base + 0xaf80));
+ clk_dm(IMX8MN_CLK_UART3,
+ imx8m_clk_composite(dev, "uart3", imx8mn_uart3_sels, base + 0xb000));
+ clk_dm(IMX8MN_CLK_UART4,
+ imx8m_clk_composite(dev, "uart4", imx8mn_uart4_sels, base + 0xb080));
clk_dm(IMX8MN_CLK_WDOG,
- imx8m_clk_composite("wdog", imx8mn_wdog_sels, base + 0xb900));
+ imx8m_clk_composite(dev, "wdog", imx8mn_wdog_sels, base + 0xb900));
clk_dm(IMX8MN_CLK_USDHC3,
- imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels,
+ imx8m_clk_composite(dev, "usdhc3", imx8mn_usdhc3_sels,
base + 0xbc80));
clk_dm(IMX8MN_CLK_NAND,
- imx8m_clk_composite("nand", imx8mn_nand_sels, base + 0xab00));
+ imx8m_clk_composite(dev, "nand", imx8mn_nand_sels, base + 0xab00));
clk_dm(IMX8MN_CLK_QSPI,
- imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80));
+ imx8m_clk_composite(dev, "qspi", imx8mn_qspi_sels, base + 0xab80));
clk_dm(IMX8MN_CLK_USB_CORE_REF,
- imx8m_clk_composite("usb_core_ref", imx8mn_usb_core_sels, base + 0xb100));
+ imx8m_clk_composite(dev, "usb_core_ref", imx8mn_usb_core_sels, base + 0xb100));
clk_dm(IMX8MN_CLK_USB_PHY_REF,
- imx8m_clk_composite("usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180));
+ imx8m_clk_composite(dev, "usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180));
clk_dm(IMX8MN_CLK_I2C1_ROOT,
- imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
+ imx_clk_gate4(dev, "i2c1_root_clk", "i2c1", base + 0x4170, 0));
clk_dm(IMX8MN_CLK_I2C2_ROOT,
- imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0));
+ imx_clk_gate4(dev, "i2c2_root_clk", "i2c2", base + 0x4180, 0));
clk_dm(IMX8MN_CLK_I2C3_ROOT,
- imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0));
+ imx_clk_gate4(dev, "i2c3_root_clk", "i2c3", base + 0x4190, 0));
clk_dm(IMX8MN_CLK_I2C4_ROOT,
- imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0));
+ imx_clk_gate4(dev, "i2c4_root_clk", "i2c4", base + 0x41a0, 0));
clk_dm(IMX8MN_CLK_OCOTP_ROOT,
- imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0));
+ imx_clk_gate4(dev, "ocotp_root_clk", "ipg_root", base + 0x4220, 0));
clk_dm(IMX8MN_CLK_USDHC1_ROOT,
- imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
+ imx_clk_gate4(dev, "usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
clk_dm(IMX8MN_CLK_USDHC2_ROOT,
- imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
+ imx_clk_gate4(dev, "usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
clk_dm(IMX8MN_CLK_WDOG1_ROOT,
- imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0));
+ imx_clk_gate4(dev, "wdog1_root_clk", "wdog", base + 0x4530, 0));
clk_dm(IMX8MN_CLK_WDOG2_ROOT,
- imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0));
+ imx_clk_gate4(dev, "wdog2_root_clk", "wdog", base + 0x4540, 0));
clk_dm(IMX8MN_CLK_WDOG3_ROOT,
- imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
+ imx_clk_gate4(dev, "wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MN_CLK_USDHC3_ROOT,
- imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
+ imx_clk_gate4(dev, "usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
clk_dm(IMX8MN_CLK_QSPI_ROOT,
- imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
+ imx_clk_gate4(dev, "qspi_root_clk", "qspi", base + 0x42f0, 0));
clk_dm(IMX8MN_CLK_NAND_ROOT,
- imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand));
+ imx_clk_gate2_shared2(dev, "nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand));
clk_dm(IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK,
- imx_clk_gate2_shared2("nand_usdhc_rawnand_clk",
+ imx_clk_gate2_shared2(dev, "nand_usdhc_rawnand_clk",
"nand_usdhc_bus", base + 0x4300, 0,
&share_count_nand));
+ clk_dm(IMX8MN_CLK_UART1_ROOT,
+ imx_clk_gate4(dev, "uart1_root_clk", "uart1", base + 0x4490, 0));
+ clk_dm(IMX8MN_CLK_UART2_ROOT,
+ imx_clk_gate4(dev, "uart2_root_clk", "uart2", base + 0x44a0, 0));
+ clk_dm(IMX8MN_CLK_UART3_ROOT,
+ imx_clk_gate4(dev, "uart3_root_clk", "uart3", base + 0x44b0, 0));
+ clk_dm(IMX8MN_CLK_UART4_ROOT,
+ imx_clk_gate4(dev, "uart4_root_clk", "uart4", base + 0x44c0, 0));
clk_dm(IMX8MN_CLK_USB1_CTRL_ROOT,
- imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
+ imx_clk_gate4(dev, "usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
/* clks not needed in SPL stage */
#ifndef CONFIG_XPL_BUILD
clk_dm(IMX8MN_CLK_ENET_REF,
- imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels,
+ imx8m_clk_composite(dev, "enet_ref", imx8mn_enet_ref_sels,
base + 0xa980));
clk_dm(IMX8MN_CLK_ENET_TIMER,
- imx8m_clk_composite("enet_timer", imx8mn_enet_timer_sels,
+ imx8m_clk_composite(dev, "enet_timer", imx8mn_enet_timer_sels,
base + 0xaa00));
clk_dm(IMX8MN_CLK_ENET_PHY_REF,
- imx8m_clk_composite("enet_phy", imx8mn_enet_phy_sels,
+ imx8m_clk_composite(dev, "enet_phy", imx8mn_enet_phy_sels,
base + 0xaa80));
clk_dm(IMX8MN_CLK_ENET1_ROOT,
- imx_clk_gate4("enet1_root_clk", "enet_axi",
+ imx_clk_gate4(dev, "enet1_root_clk", "enet_axi",
base + 0x40a0, 0));
clk_dm(IMX8MN_CLK_PWM1,
- imx8m_clk_composite("pwm1", imx8mn_pwm1_sels, base + 0xb380));
+ imx8m_clk_composite(dev, "pwm1", imx8mn_pwm1_sels, base + 0xb380));
clk_dm(IMX8MN_CLK_PWM2,
- imx8m_clk_composite("pwm2", imx8mn_pwm2_sels, base + 0xb400));
+ imx8m_clk_composite(dev, "pwm2", imx8mn_pwm2_sels, base + 0xb400));
clk_dm(IMX8MN_CLK_PWM3,
- imx8m_clk_composite("pwm3", imx8mn_pwm3_sels, base + 0xb480));
+ imx8m_clk_composite(dev, "pwm3", imx8mn_pwm3_sels, base + 0xb480));
clk_dm(IMX8MN_CLK_PWM4,
- imx8m_clk_composite("pwm4", imx8mn_pwm4_sels, base + 0xb500));
+ imx8m_clk_composite(dev, "pwm4", imx8mn_pwm4_sels, base + 0xb500));
clk_dm(IMX8MN_CLK_PWM1_ROOT,
- imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0));
+ imx_clk_gate4(dev, "pwm1_root_clk", "pwm1", base + 0x4280, 0));
clk_dm(IMX8MN_CLK_PWM2_ROOT,
- imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0));
+ imx_clk_gate4(dev, "pwm2_root_clk", "pwm2", base + 0x4290, 0));
clk_dm(IMX8MN_CLK_PWM3_ROOT,
- imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0));
+ imx_clk_gate4(dev, "pwm3_root_clk", "pwm3", base + 0x42a0, 0));
clk_dm(IMX8MN_CLK_PWM4_ROOT,
- imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0));
+ imx_clk_gate4(dev, "pwm4_root_clk", "pwm4", base + 0x42b0, 0));
#endif
#if CONFIG_IS_ENABLED(DM_SPI)
clk_dm(IMX8MN_CLK_ECSPI1,
- imx8m_clk_composite("ecspi1", imx8mn_ecspi1_sels, base + 0xb280));
+ imx8m_clk_composite(dev, "ecspi1", imx8mn_ecspi1_sels, base + 0xb280));
clk_dm(IMX8MN_CLK_ECSPI2,
- imx8m_clk_composite("ecspi2", imx8mn_ecspi2_sels, base + 0xb300));
+ imx8m_clk_composite(dev, "ecspi2", imx8mn_ecspi2_sels, base + 0xb300));
clk_dm(IMX8MN_CLK_ECSPI3,
- imx8m_clk_composite("ecspi3", imx8mn_ecspi3_sels, base + 0xc180));
+ imx8m_clk_composite(dev, "ecspi3", imx8mn_ecspi3_sels, base + 0xc180));
clk_dm(IMX8MN_CLK_ECSPI1_ROOT,
- imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
+ imx_clk_gate4(dev, "ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
clk_dm(IMX8MN_CLK_ECSPI2_ROOT,
- imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
+ imx_clk_gate4(dev, "ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
clk_dm(IMX8MN_CLK_ECSPI3_ROOT,
- imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
+ imx_clk_gate4(dev, "ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
#endif
clk_dm(IMX8MN_CLK_ARM,
- imx_clk_mux2_flags("arm_core", base + 0x9880, 24, 1,
+ imx_clk_mux2_flags(dev, "arm_core", base + 0x9880, 24, 1,
imx8mn_arm_core_sels,
ARRAY_SIZE(imx8mn_arm_core_sels),
CLK_IS_CRITICAL));
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index 1d04090ca00..bad579f8d5e 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -14,7 +14,7 @@
#include "clk.h"
-static const char * const pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", };
+static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
@@ -23,167 +23,167 @@ static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_se
static const char * const imx8mp_arm_core_sels[] = {"arm_a53_src", "arm_pll_out", };
-static const char * const imx8mp_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m",
+static const char * const imx8mp_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m",
"sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
"audio_pll1_out", "sys_pll3_out", };
-static const char * const imx8mp_hsio_axi_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m",
+static const char * const imx8mp_hsio_axi_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
-static const char * const imx8mp_main_axi_sels[] = {"clock-osc-24m", "sys_pll2_333m", "sys_pll1_800m",
+static const char * const imx8mp_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m",
"sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out",
"video_pll1_out", "sys_pll1_100m",};
-static const char * const imx8mp_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+static const char * const imx8mp_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out",
"video_pll1_out", "sys_pll3_out", };
-static const char * const imx8mp_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+static const char * const imx8mp_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll1_out", };
-static const char * const imx8mp_noc_sels[] = {"clock-osc-24m", "sys_pll1_800m", "sys_pll3_out",
+static const char * const imx8mp_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", };
-static const char * const imx8mp_noc_io_sels[] = {"clock-osc-24m", "sys_pll1_800m", "sys_pll3_out",
+static const char * const imx8mp_noc_io_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", };
-static const char * const imx8mp_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_800m",
+static const char * const imx8mp_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m",
"sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out",
"audio_pll1_out", "video_pll1_out", };
-static const char * const imx8mp_dram_alt_sels[] = {"clock-osc-24m", "sys_pll1_800m", "sys_pll1_100m",
+static const char * const imx8mp_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m",
"sys_pll2_500m", "sys_pll2_1000m", "sys_pll3_out",
"audio_pll1_out", "sys_pll1_266m", };
-static const char * const imx8mp_dram_apb_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mp_dram_apb_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mp_pcie_aux_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll2_50m",
+static const char * const imx8mp_pcie_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m",
"sys_pll3_out", "sys_pll2_100m", "sys_pll1_80m",
"sys_pll1_160m", "sys_pll1_200m", };
-static const char * const imx8mp_i2c5_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mp_i2c5_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mp_i2c6_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mp_i2c6_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mp_enet_qos_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m",
+static const char * const imx8mp_enet_qos_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
"sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
"video_pll1_out", "clk_ext4", };
-static const char * const imx8mp_enet_qos_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out",
+static const char * const imx8mp_enet_qos_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
"clk_ext1", "clk_ext2", "clk_ext3",
"clk_ext4", "video_pll1_out", };
-static const char * const imx8mp_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mp_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
-static const char * const imx8mp_usdhc2_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mp_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
-static const char * const imx8mp_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mp_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mp_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mp_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mp_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mp_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mp_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m",
+static const char * const imx8mp_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m",
"sys_pll3_out", "audio_pll1_out", "video_pll1_out",
"audio_pll2_out", "sys_pll1_133m", };
-static const char * const imx8mp_uart1_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+static const char * const imx8mp_uart1_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
"sys_pll2_100m", "sys_pll3_out", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
-static const char * const imx8mp_uart2_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+static const char * const imx8mp_uart2_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
"sys_pll2_100m", "sys_pll3_out", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
-static const char * const imx8mp_uart3_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+static const char * const imx8mp_uart3_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
"sys_pll2_100m", "sys_pll3_out", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
-static const char * const imx8mp_uart4_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m",
+static const char * const imx8mp_uart4_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m",
"sys_pll2_100m", "sys_pll3_out", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
-static const char * const imx8mp_usb_core_ref_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+static const char * const imx8mp_usb_core_ref_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
-static const char * const imx8mp_usb_phy_ref_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+static const char * const imx8mp_usb_phy_ref_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext3", "audio_pll2_out", };
-static const char * const imx8mp_gic_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mp_gic_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll2_100m", "sys_pll1_800m",
"sys_pll2_500m", "clk_ext4", "audio_pll2_out" };
-static const char * const imx8mp_pwm1_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mp_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mp_pwm2_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mp_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext1",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mp_pwm3_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mp_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mp_pwm4_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m",
+static const char * const imx8mp_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m",
"sys_pll1_40m", "sys_pll3_out", "clk_ext2",
"sys_pll1_80m", "video_pll1_out", };
-static const char * const imx8mp_ecspi1_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mp_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mp_ecspi2_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mp_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mp_ecspi3_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m",
+static const char * const imx8mp_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m",
"sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll2_out", };
-static const char * const imx8mp_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m",
+static const char * const imx8mp_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m",
"vpu_pll_out", "sys_pll2_125m", "sys_pll3_out",
"sys_pll1_80m", "sys_pll2_166m" };
-static const char * const imx8mp_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m",
+static const char * const imx8mp_qspi_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll2_333m",
"sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m",
"sys_pll3_out", "sys_pll1_100m", };
-static const char * const imx8mp_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
+static const char * const imx8mp_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
-static const char * const imx8mp_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m",
+static const char * const imx8mp_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
"sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
"video_pll1_out", "clk_ext4", };
-static const char * const imx8mp_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out",
+static const char * const imx8mp_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out",
"clk_ext1", "clk_ext2", "clk_ext3",
"clk_ext4", "video_pll1_out", };
-static const char * const imx8mp_enet_phy_ref_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m",
+static const char * const imx8mp_enet_phy_ref_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m",
"sys_pll2_200m", "sys_pll2_500m", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", };
@@ -199,11 +199,11 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0));
- clk_dm(IMX8MP_DRAM_PLL_REF_SEL, imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
- clk_dm(IMX8MP_ARM_PLL_REF_SEL, imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
- clk_dm(IMX8MP_SYS_PLL1_REF_SEL, imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
- clk_dm(IMX8MP_SYS_PLL2_REF_SEL, imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
- clk_dm(IMX8MP_SYS_PLL3_REF_SEL, imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+ clk_dm(IMX8MP_DRAM_PLL_REF_SEL, imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+ clk_dm(IMX8MP_ARM_PLL_REF_SEL, imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+ clk_dm(IMX8MP_SYS_PLL1_REF_SEL, imx_clk_mux(dev, "sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+ clk_dm(IMX8MP_SYS_PLL2_REF_SEL, imx_clk_mux(dev, "sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+ clk_dm(IMX8MP_SYS_PLL3_REF_SEL, imx_clk_mux(dev, "sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50,
&imx_1443x_dram_pll));
@@ -216,37 +216,37 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114,
&imx_1416x_pll));
- clk_dm(IMX8MP_DRAM_PLL_BYPASS, imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT));
- clk_dm(IMX8MP_ARM_PLL_BYPASS, imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT));
- clk_dm(IMX8MP_SYS_PLL1_BYPASS, imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT));
- clk_dm(IMX8MP_SYS_PLL2_BYPASS, imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT));
- clk_dm(IMX8MP_SYS_PLL3_BYPASS, imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT));
-
- clk_dm(IMX8MP_DRAM_PLL_OUT, imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13));
- clk_dm(IMX8MP_ARM_PLL_OUT, imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 11));
- clk_dm(IMX8MP_SYS_PLL1_OUT, imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11));
- clk_dm(IMX8MP_SYS_PLL2_OUT, imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 11));
- clk_dm(IMX8MP_SYS_PLL3_OUT, imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11));
-
- clk_dm(IMX8MP_SYS_PLL1_40M, imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20));
- clk_dm(IMX8MP_SYS_PLL1_80M, imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10));
- clk_dm(IMX8MP_SYS_PLL1_100M, imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8));
- clk_dm(IMX8MP_SYS_PLL1_133M, imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6));
- clk_dm(IMX8MP_SYS_PLL1_160M, imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5));
- clk_dm(IMX8MP_SYS_PLL1_200M, imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4));
- clk_dm(IMX8MP_SYS_PLL1_266M, imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3));
- clk_dm(IMX8MP_SYS_PLL1_400M, imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2));
- clk_dm(IMX8MP_SYS_PLL1_800M, imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1));
-
- clk_dm(IMX8MP_SYS_PLL2_50M, imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20));
- clk_dm(IMX8MP_SYS_PLL2_100M, imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10));
- clk_dm(IMX8MP_SYS_PLL2_125M, imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8));
- clk_dm(IMX8MP_SYS_PLL2_166M, imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6));
- clk_dm(IMX8MP_SYS_PLL2_200M, imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5));
- clk_dm(IMX8MP_SYS_PLL2_250M, imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4));
- clk_dm(IMX8MP_SYS_PLL2_333M, imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3));
- clk_dm(IMX8MP_SYS_PLL2_500M, imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2));
- clk_dm(IMX8MP_SYS_PLL2_1000M, imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1));
+ clk_dm(IMX8MP_DRAM_PLL_BYPASS, imx_clk_mux_flags(dev, "dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT));
+ clk_dm(IMX8MP_ARM_PLL_BYPASS, imx_clk_mux_flags(dev, "arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT));
+ clk_dm(IMX8MP_SYS_PLL1_BYPASS, imx_clk_mux_flags(dev, "sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT));
+ clk_dm(IMX8MP_SYS_PLL2_BYPASS, imx_clk_mux_flags(dev, "sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT));
+ clk_dm(IMX8MP_SYS_PLL3_BYPASS, imx_clk_mux_flags(dev, "sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT));
+
+ clk_dm(IMX8MP_DRAM_PLL_OUT, imx_clk_gate(dev, "dram_pll_out", "dram_pll_bypass", base + 0x50, 13));
+ clk_dm(IMX8MP_ARM_PLL_OUT, imx_clk_gate(dev, "arm_pll_out", "arm_pll_bypass", base + 0x84, 11));
+ clk_dm(IMX8MP_SYS_PLL1_OUT, imx_clk_gate(dev, "sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11));
+ clk_dm(IMX8MP_SYS_PLL2_OUT, imx_clk_gate(dev, "sys_pll2_out", "sys_pll2_bypass", base + 0x104, 11));
+ clk_dm(IMX8MP_SYS_PLL3_OUT, imx_clk_gate(dev, "sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11));
+
+ clk_dm(IMX8MP_SYS_PLL1_40M, imx_clk_fixed_factor(dev, "sys_pll1_40m", "sys_pll1_out", 1, 20));
+ clk_dm(IMX8MP_SYS_PLL1_80M, imx_clk_fixed_factor(dev, "sys_pll1_80m", "sys_pll1_out", 1, 10));
+ clk_dm(IMX8MP_SYS_PLL1_100M, imx_clk_fixed_factor(dev, "sys_pll1_100m", "sys_pll1_out", 1, 8));
+ clk_dm(IMX8MP_SYS_PLL1_133M, imx_clk_fixed_factor(dev, "sys_pll1_133m", "sys_pll1_out", 1, 6));
+ clk_dm(IMX8MP_SYS_PLL1_160M, imx_clk_fixed_factor(dev, "sys_pll1_160m", "sys_pll1_out", 1, 5));
+ clk_dm(IMX8MP_SYS_PLL1_200M, imx_clk_fixed_factor(dev, "sys_pll1_200m", "sys_pll1_out", 1, 4));
+ clk_dm(IMX8MP_SYS_PLL1_266M, imx_clk_fixed_factor(dev, "sys_pll1_266m", "sys_pll1_out", 1, 3));
+ clk_dm(IMX8MP_SYS_PLL1_400M, imx_clk_fixed_factor(dev, "sys_pll1_400m", "sys_pll1_out", 1, 2));
+ clk_dm(IMX8MP_SYS_PLL1_800M, imx_clk_fixed_factor(dev, "sys_pll1_800m", "sys_pll1_out", 1, 1));
+
+ clk_dm(IMX8MP_SYS_PLL2_50M, imx_clk_fixed_factor(dev, "sys_pll2_50m", "sys_pll2_out", 1, 20));
+ clk_dm(IMX8MP_SYS_PLL2_100M, imx_clk_fixed_factor(dev, "sys_pll2_100m", "sys_pll2_out", 1, 10));
+ clk_dm(IMX8MP_SYS_PLL2_125M, imx_clk_fixed_factor(dev, "sys_pll2_125m", "sys_pll2_out", 1, 8));
+ clk_dm(IMX8MP_SYS_PLL2_166M, imx_clk_fixed_factor(dev, "sys_pll2_166m", "sys_pll2_out", 1, 6));
+ clk_dm(IMX8MP_SYS_PLL2_200M, imx_clk_fixed_factor(dev, "sys_pll2_200m", "sys_pll2_out", 1, 5));
+ clk_dm(IMX8MP_SYS_PLL2_250M, imx_clk_fixed_factor(dev, "sys_pll2_250m", "sys_pll2_out", 1, 4));
+ clk_dm(IMX8MP_SYS_PLL2_333M, imx_clk_fixed_factor(dev, "sys_pll2_333m", "sys_pll2_out", 1, 3));
+ clk_dm(IMX8MP_SYS_PLL2_500M, imx_clk_fixed_factor(dev, "sys_pll2_500m", "sys_pll2_out", 1, 2));
+ clk_dm(IMX8MP_SYS_PLL2_1000M, imx_clk_fixed_factor(dev, "sys_pll2_1000m", "sys_pll2_out", 1, 1));
ret = clk_get_by_name(dev, "osc_24m", &osc_24m_clk);
if (ret)
@@ -262,104 +262,104 @@ static int imx8mp_clk_probe(struct udevice *dev)
if (!base)
return -EINVAL;
- clk_dm(IMX8MP_CLK_A53_SRC, imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mp_a53_sels, ARRAY_SIZE(imx8mp_a53_sels)));
- clk_dm(IMX8MP_CLK_A53_CG, imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
- clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3));
-
- clk_dm(IMX8MP_CLK_HSIO_AXI, imx8m_clk_composite("hsio_axi", imx8mp_hsio_axi_sels, base + 0x8380));
- clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical("main_axi", imx8mp_main_axi_sels, base + 0x8800));
- clk_dm(IMX8MP_CLK_ENET_AXI, imx8m_clk_composite_critical("enet_axi", imx8mp_enet_axi_sels, base + 0x8880));
- clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900));
- clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical("noc", imx8mp_noc_sels, base + 0x8d00));
- clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical("noc_io", imx8mp_noc_io_sels, base + 0x8d80));
-
- clk_dm(IMX8MP_CLK_AHB, imx8m_clk_composite_critical("ahb_root", imx8mp_ahb_sels, base + 0x9000));
-
- clk_dm(IMX8MP_CLK_IPG_ROOT, imx_clk_divider2("ipg_root", "ahb_root", base + 0x9080, 0, 1));
-
- clk_dm(IMX8MP_CLK_DRAM_ALT, imx8m_clk_composite("dram_alt", imx8mp_dram_alt_sels, base + 0xa000));
- clk_dm(IMX8MP_CLK_DRAM_APB, imx8m_clk_composite_critical("dram_apb", imx8mp_dram_apb_sels, base + 0xa080));
- clk_dm(IMX8MP_CLK_PCIE_AUX, imx8m_clk_composite("pcie_aux", imx8mp_pcie_aux_sels, base + 0xa400));
- clk_dm(IMX8MP_CLK_I2C5, imx8m_clk_composite("i2c5", imx8mp_i2c5_sels, base + 0xa480));
- clk_dm(IMX8MP_CLK_I2C6, imx8m_clk_composite("i2c6", imx8mp_i2c6_sels, base + 0xa500));
- clk_dm(IMX8MP_CLK_ENET_QOS, imx8m_clk_composite("enet_qos", imx8mp_enet_qos_sels, base + 0xa880));
- clk_dm(IMX8MP_CLK_ENET_QOS_TIMER, imx8m_clk_composite("enet_qos_timer", imx8mp_enet_qos_timer_sels, base + 0xa900));
- clk_dm(IMX8MP_CLK_ENET_REF, imx8m_clk_composite("enet_ref", imx8mp_enet_ref_sels, base + 0xa980));
- clk_dm(IMX8MP_CLK_ENET_TIMER, imx8m_clk_composite("enet_timer", imx8mp_enet_timer_sels, base + 0xaa00));
- clk_dm(IMX8MP_CLK_ENET_PHY_REF, imx8m_clk_composite("enet_phy_ref", imx8mp_enet_phy_ref_sels, base + 0xaa80));
- clk_dm(IMX8MP_CLK_QSPI, imx8m_clk_composite("qspi", imx8mp_qspi_sels, base + 0xab80));
- clk_dm(IMX8MP_CLK_USDHC1, imx8m_clk_composite("usdhc1", imx8mp_usdhc1_sels, base + 0xac00));
- clk_dm(IMX8MP_CLK_USDHC2, imx8m_clk_composite("usdhc2", imx8mp_usdhc2_sels, base + 0xac80));
- clk_dm(IMX8MP_CLK_I2C1, imx8m_clk_composite("i2c1", imx8mp_i2c1_sels, base + 0xad00));
- clk_dm(IMX8MP_CLK_I2C2, imx8m_clk_composite("i2c2", imx8mp_i2c2_sels, base + 0xad80));
- clk_dm(IMX8MP_CLK_I2C3, imx8m_clk_composite("i2c3", imx8mp_i2c3_sels, base + 0xae00));
- clk_dm(IMX8MP_CLK_I2C4, imx8m_clk_composite("i2c4", imx8mp_i2c4_sels, base + 0xae80));
-
- clk_dm(IMX8MP_CLK_UART1, imx8m_clk_composite("uart1", imx8mp_uart1_sels, base + 0xaf00));
- clk_dm(IMX8MP_CLK_UART2, imx8m_clk_composite("uart2", imx8mp_uart2_sels, base + 0xaf80));
- clk_dm(IMX8MP_CLK_UART3, imx8m_clk_composite("uart3", imx8mp_uart3_sels, base + 0xb000));
- clk_dm(IMX8MP_CLK_UART4, imx8m_clk_composite("uart4", imx8mp_uart4_sels, base + 0xb080));
- clk_dm(IMX8MP_CLK_USB_CORE_REF, imx8m_clk_composite("usb_core_ref", imx8mp_usb_core_ref_sels, base + 0xb100));
- clk_dm(IMX8MP_CLK_USB_PHY_REF, imx8m_clk_composite("usb_phy_ref", imx8mp_usb_phy_ref_sels, base + 0xb180));
- clk_dm(IMX8MP_CLK_GIC, imx8m_clk_composite_critical("gic", imx8mp_gic_sels, base + 0xb200));
- clk_dm(IMX8MP_CLK_ECSPI1, imx8m_clk_composite("ecspi1", imx8mp_ecspi1_sels, base + 0xb280));
- clk_dm(IMX8MP_CLK_ECSPI2, imx8m_clk_composite("ecspi2", imx8mp_ecspi2_sels, base + 0xb300));
- clk_dm(IMX8MP_CLK_PWM1, imx8m_clk_composite_critical("pwm1", imx8mp_pwm1_sels, base + 0xb380));
- clk_dm(IMX8MP_CLK_PWM2, imx8m_clk_composite_critical("pwm2", imx8mp_pwm2_sels, base + 0xb400));
- clk_dm(IMX8MP_CLK_PWM3, imx8m_clk_composite_critical("pwm3", imx8mp_pwm3_sels, base + 0xb480));
- clk_dm(IMX8MP_CLK_PWM4, imx8m_clk_composite_critical("pwm4", imx8mp_pwm4_sels, base + 0xb500));
- clk_dm(IMX8MP_CLK_ECSPI3, imx8m_clk_composite("ecspi3", imx8mp_ecspi3_sels, base + 0xc180));
-
- clk_dm(IMX8MP_CLK_WDOG, imx8m_clk_composite("wdog", imx8mp_wdog_sels, base + 0xb900));
- clk_dm(IMX8MP_CLK_USDHC3, imx8m_clk_composite("usdhc3", imx8mp_usdhc3_sels, base + 0xbc80));
-
- clk_dm(IMX8MP_CLK_DRAM_ALT_ROOT, imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4));
- clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL));
-
- clk_dm(IMX8MP_CLK_DRAM1_ROOT, imx_clk_gate4_flags("dram1_root_clk", "dram_core_clk", base + 0x4050, 0, CLK_IS_CRITICAL));
- clk_dm(IMX8MP_CLK_ECSPI1_ROOT, imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
- clk_dm(IMX8MP_CLK_ECSPI2_ROOT, imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
- clk_dm(IMX8MP_CLK_ECSPI3_ROOT, imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
- clk_dm(IMX8MP_CLK_ENET1_ROOT, imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0));
- clk_dm(IMX8MP_CLK_GPIO1_ROOT, imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0));
- clk_dm(IMX8MP_CLK_GPIO2_ROOT, imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0));
- clk_dm(IMX8MP_CLK_GPIO3_ROOT, imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0));
- clk_dm(IMX8MP_CLK_GPIO4_ROOT, imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0));
- clk_dm(IMX8MP_CLK_GPIO5_ROOT, imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0));
- clk_dm(IMX8MP_CLK_I2C1_ROOT, imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
- clk_dm(IMX8MP_CLK_I2C2_ROOT, imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0));
- clk_dm(IMX8MP_CLK_I2C3_ROOT, imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0));
- clk_dm(IMX8MP_CLK_I2C4_ROOT, imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0));
- clk_dm(IMX8MP_CLK_PCIE_ROOT, imx_clk_gate4("pcie_root_clk", "pcie_aux", base + 0x4250, 0));
- clk_dm(IMX8MP_CLK_PWM1_ROOT, imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0));
- clk_dm(IMX8MP_CLK_PWM2_ROOT, imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0));
- clk_dm(IMX8MP_CLK_PWM3_ROOT, imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0));
- clk_dm(IMX8MP_CLK_PWM4_ROOT, imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0));
- clk_dm(IMX8MP_CLK_QOS_ROOT, imx_clk_gate4("qos_root_clk", "ipg_root", base + 0x42c0, 0));
- clk_dm(IMX8MP_CLK_QOS_ENET_ROOT, imx_clk_gate4("qos_enet_root_clk", "ipg_root", base + 0x42e0, 0));
- clk_dm(IMX8MP_CLK_QSPI_ROOT, imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
- clk_dm(IMX8MP_CLK_I2C5_ROOT, imx_clk_gate2("i2c5_root_clk", "i2c5", base + 0x4330, 0));
- clk_dm(IMX8MP_CLK_I2C6_ROOT, imx_clk_gate2("i2c6_root_clk", "i2c6", base + 0x4340, 0));
- clk_dm(IMX8MP_CLK_SIM_ENET_ROOT, imx_clk_gate4("sim_enet_root_clk", "enet_axi", base + 0x4400, 0));
- clk_dm(IMX8MP_CLK_ENET_QOS_ROOT, imx_clk_gate4("enet_qos_root_clk", "sim_enet_root_clk", base + 0x43b0, 0));
- clk_dm(IMX8MP_CLK_UART1_ROOT, imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0));
- clk_dm(IMX8MP_CLK_UART2_ROOT, imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0));
- clk_dm(IMX8MP_CLK_UART3_ROOT, imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0));
- clk_dm(IMX8MP_CLK_UART4_ROOT, imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0));
- clk_dm(IMX8MP_CLK_USB_ROOT, imx_clk_gate2("usb_root_clk", "hsio_axi", base + 0x44d0, 0));
- clk_dm(IMX8MP_CLK_USB_SUSP, imx_clk_gate2("usb_suspend_clk", "clock-osc-24m", base + 0x44d0, 0));
- clk_dm(IMX8MP_CLK_USB_PHY_ROOT, imx_clk_gate4("usb_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0));
- clk_dm(IMX8MP_CLK_USDHC1_ROOT, imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
- clk_dm(IMX8MP_CLK_USDHC2_ROOT, imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
- clk_dm(IMX8MP_CLK_WDOG1_ROOT, imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0));
- clk_dm(IMX8MP_CLK_WDOG2_ROOT, imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0));
- clk_dm(IMX8MP_CLK_WDOG3_ROOT, imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
- clk_dm(IMX8MP_CLK_HSIO_ROOT, imx_clk_gate4("hsio_root_clk", "ipg_root", base + 0x45c0, 0));
-
- clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
+ clk_dm(IMX8MP_CLK_A53_SRC, imx_clk_mux2(dev, "arm_a53_src", base + 0x8000, 24, 3, imx8mp_a53_sels, ARRAY_SIZE(imx8mp_a53_sels)));
+ clk_dm(IMX8MP_CLK_A53_CG, imx_clk_gate3(dev, "arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
+ clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3));
+
+ clk_dm(IMX8MP_CLK_HSIO_AXI, imx8m_clk_composite(dev, "hsio_axi", imx8mp_hsio_axi_sels, base + 0x8380));
+ clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical(dev, "main_axi", imx8mp_main_axi_sels, base + 0x8800));
+ clk_dm(IMX8MP_CLK_ENET_AXI, imx8m_clk_composite_critical(dev, "enet_axi", imx8mp_enet_axi_sels, base + 0x8880));
+ clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical(dev, "nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900));
+ clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical(dev, "noc", imx8mp_noc_sels, base + 0x8d00));
+ clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical(dev, "noc_io", imx8mp_noc_io_sels, base + 0x8d80));
+
+ clk_dm(IMX8MP_CLK_AHB, imx8m_clk_composite_critical(dev, "ahb_root", imx8mp_ahb_sels, base + 0x9000));
+
+ clk_dm(IMX8MP_CLK_IPG_ROOT, imx_clk_divider2(dev, "ipg_root", "ahb_root", base + 0x9080, 0, 1));
+
+ clk_dm(IMX8MP_CLK_DRAM_ALT, imx8m_clk_composite(dev, "dram_alt", imx8mp_dram_alt_sels, base + 0xa000));
+ clk_dm(IMX8MP_CLK_DRAM_APB, imx8m_clk_composite_critical(dev, "dram_apb", imx8mp_dram_apb_sels, base + 0xa080));
+ clk_dm(IMX8MP_CLK_PCIE_AUX, imx8m_clk_composite(dev, "pcie_aux", imx8mp_pcie_aux_sels, base + 0xa400));
+ clk_dm(IMX8MP_CLK_I2C5, imx8m_clk_composite(dev, "i2c5", imx8mp_i2c5_sels, base + 0xa480));
+ clk_dm(IMX8MP_CLK_I2C6, imx8m_clk_composite(dev, "i2c6", imx8mp_i2c6_sels, base + 0xa500));
+ clk_dm(IMX8MP_CLK_ENET_QOS, imx8m_clk_composite(dev, "enet_qos", imx8mp_enet_qos_sels, base + 0xa880));
+ clk_dm(IMX8MP_CLK_ENET_QOS_TIMER, imx8m_clk_composite(dev, "enet_qos_timer", imx8mp_enet_qos_timer_sels, base + 0xa900));
+ clk_dm(IMX8MP_CLK_ENET_REF, imx8m_clk_composite(dev, "enet_ref", imx8mp_enet_ref_sels, base + 0xa980));
+ clk_dm(IMX8MP_CLK_ENET_TIMER, imx8m_clk_composite(dev, "enet_timer", imx8mp_enet_timer_sels, base + 0xaa00));
+ clk_dm(IMX8MP_CLK_ENET_PHY_REF, imx8m_clk_composite(dev, "enet_phy_ref", imx8mp_enet_phy_ref_sels, base + 0xaa80));
+ clk_dm(IMX8MP_CLK_QSPI, imx8m_clk_composite(dev, "qspi", imx8mp_qspi_sels, base + 0xab80));
+ clk_dm(IMX8MP_CLK_USDHC1, imx8m_clk_composite(dev, "usdhc1", imx8mp_usdhc1_sels, base + 0xac00));
+ clk_dm(IMX8MP_CLK_USDHC2, imx8m_clk_composite(dev, "usdhc2", imx8mp_usdhc2_sels, base + 0xac80));
+ clk_dm(IMX8MP_CLK_I2C1, imx8m_clk_composite(dev, "i2c1", imx8mp_i2c1_sels, base + 0xad00));
+ clk_dm(IMX8MP_CLK_I2C2, imx8m_clk_composite(dev, "i2c2", imx8mp_i2c2_sels, base + 0xad80));
+ clk_dm(IMX8MP_CLK_I2C3, imx8m_clk_composite(dev, "i2c3", imx8mp_i2c3_sels, base + 0xae00));
+ clk_dm(IMX8MP_CLK_I2C4, imx8m_clk_composite(dev, "i2c4", imx8mp_i2c4_sels, base + 0xae80));
+
+ clk_dm(IMX8MP_CLK_UART1, imx8m_clk_composite(dev, "uart1", imx8mp_uart1_sels, base + 0xaf00));
+ clk_dm(IMX8MP_CLK_UART2, imx8m_clk_composite(dev, "uart2", imx8mp_uart2_sels, base + 0xaf80));
+ clk_dm(IMX8MP_CLK_UART3, imx8m_clk_composite(dev, "uart3", imx8mp_uart3_sels, base + 0xb000));
+ clk_dm(IMX8MP_CLK_UART4, imx8m_clk_composite(dev, "uart4", imx8mp_uart4_sels, base + 0xb080));
+ clk_dm(IMX8MP_CLK_USB_CORE_REF, imx8m_clk_composite(dev, "usb_core_ref", imx8mp_usb_core_ref_sels, base + 0xb100));
+ clk_dm(IMX8MP_CLK_USB_PHY_REF, imx8m_clk_composite(dev, "usb_phy_ref", imx8mp_usb_phy_ref_sels, base + 0xb180));
+ clk_dm(IMX8MP_CLK_GIC, imx8m_clk_composite_critical(dev, "gic", imx8mp_gic_sels, base + 0xb200));
+ clk_dm(IMX8MP_CLK_ECSPI1, imx8m_clk_composite(dev, "ecspi1", imx8mp_ecspi1_sels, base + 0xb280));
+ clk_dm(IMX8MP_CLK_ECSPI2, imx8m_clk_composite(dev, "ecspi2", imx8mp_ecspi2_sels, base + 0xb300));
+ clk_dm(IMX8MP_CLK_PWM1, imx8m_clk_composite_critical(dev, "pwm1", imx8mp_pwm1_sels, base + 0xb380));
+ clk_dm(IMX8MP_CLK_PWM2, imx8m_clk_composite_critical(dev, "pwm2", imx8mp_pwm2_sels, base + 0xb400));
+ clk_dm(IMX8MP_CLK_PWM3, imx8m_clk_composite_critical(dev, "pwm3", imx8mp_pwm3_sels, base + 0xb480));
+ clk_dm(IMX8MP_CLK_PWM4, imx8m_clk_composite_critical(dev, "pwm4", imx8mp_pwm4_sels, base + 0xb500));
+ clk_dm(IMX8MP_CLK_ECSPI3, imx8m_clk_composite(dev, "ecspi3", imx8mp_ecspi3_sels, base + 0xc180));
+
+ clk_dm(IMX8MP_CLK_WDOG, imx8m_clk_composite(dev, "wdog", imx8mp_wdog_sels, base + 0xb900));
+ clk_dm(IMX8MP_CLK_USDHC3, imx8m_clk_composite(dev, "usdhc3", imx8mp_usdhc3_sels, base + 0xbc80));
+
+ clk_dm(IMX8MP_CLK_DRAM_ALT_ROOT, imx_clk_fixed_factor(dev, "dram_alt_root", "dram_alt", 1, 4));
+ clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags(dev, "dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL));
+
+ clk_dm(IMX8MP_CLK_DRAM1_ROOT, imx_clk_gate4_flags(dev, "dram1_root_clk", "dram_core_clk", base + 0x4050, 0, CLK_IS_CRITICAL));
+ clk_dm(IMX8MP_CLK_ECSPI1_ROOT, imx_clk_gate4(dev, "ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
+ clk_dm(IMX8MP_CLK_ECSPI2_ROOT, imx_clk_gate4(dev, "ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
+ clk_dm(IMX8MP_CLK_ECSPI3_ROOT, imx_clk_gate4(dev, "ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
+ clk_dm(IMX8MP_CLK_ENET1_ROOT, imx_clk_gate4(dev, "enet1_root_clk", "enet_axi", base + 0x40a0, 0));
+ clk_dm(IMX8MP_CLK_GPIO1_ROOT, imx_clk_gate4(dev, "gpio1_root_clk", "ipg_root", base + 0x40b0, 0));
+ clk_dm(IMX8MP_CLK_GPIO2_ROOT, imx_clk_gate4(dev, "gpio2_root_clk", "ipg_root", base + 0x40c0, 0));
+ clk_dm(IMX8MP_CLK_GPIO3_ROOT, imx_clk_gate4(dev, "gpio3_root_clk", "ipg_root", base + 0x40d0, 0));
+ clk_dm(IMX8MP_CLK_GPIO4_ROOT, imx_clk_gate4(dev, "gpio4_root_clk", "ipg_root", base + 0x40e0, 0));
+ clk_dm(IMX8MP_CLK_GPIO5_ROOT, imx_clk_gate4(dev, "gpio5_root_clk", "ipg_root", base + 0x40f0, 0));
+ clk_dm(IMX8MP_CLK_I2C1_ROOT, imx_clk_gate4(dev, "i2c1_root_clk", "i2c1", base + 0x4170, 0));
+ clk_dm(IMX8MP_CLK_I2C2_ROOT, imx_clk_gate4(dev, "i2c2_root_clk", "i2c2", base + 0x4180, 0));
+ clk_dm(IMX8MP_CLK_I2C3_ROOT, imx_clk_gate4(dev, "i2c3_root_clk", "i2c3", base + 0x4190, 0));
+ clk_dm(IMX8MP_CLK_I2C4_ROOT, imx_clk_gate4(dev, "i2c4_root_clk", "i2c4", base + 0x41a0, 0));
+ clk_dm(IMX8MP_CLK_PCIE_ROOT, imx_clk_gate4(dev, "pcie_root_clk", "pcie_aux", base + 0x4250, 0));
+ clk_dm(IMX8MP_CLK_PWM1_ROOT, imx_clk_gate4(dev, "pwm1_root_clk", "pwm1", base + 0x4280, 0));
+ clk_dm(IMX8MP_CLK_PWM2_ROOT, imx_clk_gate4(dev, "pwm2_root_clk", "pwm2", base + 0x4290, 0));
+ clk_dm(IMX8MP_CLK_PWM3_ROOT, imx_clk_gate4(dev, "pwm3_root_clk", "pwm3", base + 0x42a0, 0));
+ clk_dm(IMX8MP_CLK_PWM4_ROOT, imx_clk_gate4(dev, "pwm4_root_clk", "pwm4", base + 0x42b0, 0));
+ clk_dm(IMX8MP_CLK_QOS_ROOT, imx_clk_gate4(dev, "qos_root_clk", "ipg_root", base + 0x42c0, 0));
+ clk_dm(IMX8MP_CLK_QOS_ENET_ROOT, imx_clk_gate4(dev, "qos_enet_root_clk", "ipg_root", base + 0x42e0, 0));
+ clk_dm(IMX8MP_CLK_QSPI_ROOT, imx_clk_gate4(dev, "qspi_root_clk", "qspi", base + 0x42f0, 0));
+ clk_dm(IMX8MP_CLK_I2C5_ROOT, imx_clk_gate2(dev, "i2c5_root_clk", "i2c5", base + 0x4330, 0));
+ clk_dm(IMX8MP_CLK_I2C6_ROOT, imx_clk_gate2(dev, "i2c6_root_clk", "i2c6", base + 0x4340, 0));
+ clk_dm(IMX8MP_CLK_SIM_ENET_ROOT, imx_clk_gate4(dev, "sim_enet_root_clk", "enet_axi", base + 0x4400, 0));
+ clk_dm(IMX8MP_CLK_ENET_QOS_ROOT, imx_clk_gate4(dev, "enet_qos_root_clk", "sim_enet_root_clk", base + 0x43b0, 0));
+ clk_dm(IMX8MP_CLK_UART1_ROOT, imx_clk_gate4(dev, "uart1_root_clk", "uart1", base + 0x4490, 0));
+ clk_dm(IMX8MP_CLK_UART2_ROOT, imx_clk_gate4(dev, "uart2_root_clk", "uart2", base + 0x44a0, 0));
+ clk_dm(IMX8MP_CLK_UART3_ROOT, imx_clk_gate4(dev, "uart3_root_clk", "uart3", base + 0x44b0, 0));
+ clk_dm(IMX8MP_CLK_UART4_ROOT, imx_clk_gate4(dev, "uart4_root_clk", "uart4", base + 0x44c0, 0));
+ clk_dm(IMX8MP_CLK_USB_ROOT, imx_clk_gate2(dev, "usb_root_clk", "hsio_axi", base + 0x44d0, 0));
+ clk_dm(IMX8MP_CLK_USB_SUSP, imx_clk_gate2(dev, "usb_suspend_clk", "osc_24m", base + 0x44d0, 0));
+ clk_dm(IMX8MP_CLK_USB_PHY_ROOT, imx_clk_gate4(dev, "usb_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0));
+ clk_dm(IMX8MP_CLK_USDHC1_ROOT, imx_clk_gate4(dev, "usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
+ clk_dm(IMX8MP_CLK_USDHC2_ROOT, imx_clk_gate4(dev, "usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
+ clk_dm(IMX8MP_CLK_WDOG1_ROOT, imx_clk_gate4(dev, "wdog1_root_clk", "wdog", base + 0x4530, 0));
+ clk_dm(IMX8MP_CLK_WDOG2_ROOT, imx_clk_gate4(dev, "wdog2_root_clk", "wdog", base + 0x4540, 0));
+ clk_dm(IMX8MP_CLK_WDOG3_ROOT, imx_clk_gate4(dev, "wdog3_root_clk", "wdog", base + 0x4550, 0));
+ clk_dm(IMX8MP_CLK_HSIO_ROOT, imx_clk_gate4(dev, "hsio_root_clk", "ipg_root", base + 0x45c0, 0));
+
+ clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4(dev, "usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
clk_dm(IMX8MP_CLK_ARM,
- imx_clk_mux2_flags("arm_core", base + 0x9880, 24, 1,
+ imx_clk_mux2_flags(dev, "arm_core", base + 0x9880, 24, 1,
imx8mp_arm_core_sels,
ARRAY_SIZE(imx8mp_arm_core_sels),
CLK_IS_CRITICAL));
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index ed4acd79ef7..fe6cba19758 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -152,31 +152,31 @@ static int imx8mq_clk_probe(struct udevice *dev)
clk_dm(IMX8MQ_CLK_27M, clk_register_fixed_rate(NULL, "clock-osc-27m", 27000000));
clk_dm(IMX8MQ_DRAM_PLL1_REF_SEL,
- imx_clk_mux("dram_pll_ref_sel", base + 0x60, 0, 2,
+ imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x60, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_ARM_PLL_REF_SEL,
- imx_clk_mux("arm_pll_ref_sel", base + 0x28, 0, 2,
+ imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x28, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_GPU_PLL_REF_SEL,
- imx_clk_mux("gpu_pll_ref_sel", base + 0x18, 0, 2,
+ imx_clk_mux(dev, "gpu_pll_ref_sel", base + 0x18, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_VPU_PLL_REF_SEL,
- imx_clk_mux("vpu_pll_ref_sel", base + 0x20, 0, 2,
+ imx_clk_mux(dev, "vpu_pll_ref_sel", base + 0x20, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_SYS3_PLL1_REF_SEL,
- imx_clk_mux("sys3_pll_ref_sel", base + 0x48, 0, 2,
+ imx_clk_mux(dev, "sys3_pll_ref_sel", base + 0x48, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_AUDIO_PLL1_REF_SEL,
- imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2,
+ imx_clk_mux(dev, "audio_pll1_ref_sel", base + 0x0, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_AUDIO_PLL2_REF_SEL,
- imx_clk_mux("audio_pll2_ref_sel", base + 0x8, 0, 2,
+ imx_clk_mux(dev, "audio_pll2_ref_sel", base + 0x8, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_VIDEO_PLL1_REF_SEL,
- imx_clk_mux("video_pll1_ref_sel", base + 0x10, 0, 2,
+ imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x10, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_VIDEO2_PLL1_REF_SEL,
- imx_clk_mux("video_pll2_ref_sel", base + 0x54, 0, 2,
+ imx_clk_mux(dev, "video_pll2_ref_sel", base + 0x54, 0, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MQ_ARM_PLL,
@@ -207,140 +207,140 @@ static int imx8mq_clk_probe(struct udevice *dev)
/* PLL bypass out */
clk_dm(IMX8MQ_ARM_PLL_BYPASS,
- imx_clk_mux_flags("arm_pll_bypass", base + 0x28, 4, 1,
+ imx_clk_mux_flags(dev, "arm_pll_bypass", base + 0x28, 4, 1,
arm_pll_bypass_sels,
ARRAY_SIZE(arm_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MQ_GPU_PLL_BYPASS,
- imx_clk_mux_flags("gpu_pll_bypass", base + 0x18, 4, 1,
+ imx_clk_mux_flags(dev, "gpu_pll_bypass", base + 0x18, 4, 1,
gpu_pll_bypass_sels,
ARRAY_SIZE(gpu_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MQ_VPU_PLL_BYPASS,
- imx_clk_mux_flags("vpu_pll_bypass", base + 0x20, 4, 1,
+ imx_clk_mux_flags(dev, "vpu_pll_bypass", base + 0x20, 4, 1,
vpu_pll_bypass_sels,
ARRAY_SIZE(vpu_pll_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MQ_AUDIO_PLL1_BYPASS,
- imx_clk_mux_flags("audio_pll1_bypass", base + 0x0, 4, 1,
+ imx_clk_mux_flags(dev, "audio_pll1_bypass", base + 0x0, 4, 1,
audio_pll1_bypass_sels,
ARRAY_SIZE(audio_pll1_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MQ_AUDIO_PLL2_BYPASS,
- imx_clk_mux_flags("audio_pll2_bypass", base + 0x8, 4, 1,
+ imx_clk_mux_flags(dev, "audio_pll2_bypass", base + 0x8, 4, 1,
audio_pll2_bypass_sels,
ARRAY_SIZE(audio_pll2_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MQ_VIDEO_PLL1_BYPASS,
- imx_clk_mux_flags("video_pll1_bypass", base + 0x10, 4, 1,
+ imx_clk_mux_flags(dev, "video_pll1_bypass", base + 0x10, 4, 1,
video_pll1_bypass_sels,
ARRAY_SIZE(video_pll1_bypass_sels),
CLK_SET_RATE_PARENT));
/* PLL out gate */
clk_dm(IMX8MQ_DRAM_PLL_OUT,
- imx_clk_gate("dram_pll_out", "dram_pll_ref_sel",
+ imx_clk_gate(dev, "dram_pll_out", "dram_pll_ref_sel",
base + 0x60, 13));
clk_dm(IMX8MQ_ARM_PLL_OUT,
- imx_clk_gate("arm_pll_out", "arm_pll_bypass",
+ imx_clk_gate(dev, "arm_pll_out", "arm_pll_bypass",
base + 0x28, 11));
clk_dm(IMX8MQ_GPU_PLL_OUT,
- imx_clk_gate("gpu_pll_out", "gpu_pll_bypass",
+ imx_clk_gate(dev, "gpu_pll_out", "gpu_pll_bypass",
base + 0x18, 11));
clk_dm(IMX8MQ_VPU_PLL_OUT,
- imx_clk_gate("vpu_pll_out", "vpu_pll_bypass",
+ imx_clk_gate(dev, "vpu_pll_out", "vpu_pll_bypass",
base + 0x20, 11));
clk_dm(IMX8MQ_AUDIO_PLL1_OUT,
- imx_clk_gate("audio_pll1_out", "audio_pll1_bypass",
+ imx_clk_gate(dev, "audio_pll1_out", "audio_pll1_bypass",
base + 0x0, 11));
clk_dm(IMX8MQ_AUDIO_PLL2_OUT,
- imx_clk_gate("audio_pll2_out", "audio_pll2_bypass",
+ imx_clk_gate(dev, "audio_pll2_out", "audio_pll2_bypass",
base + 0x8, 11));
clk_dm(IMX8MQ_VIDEO_PLL1_OUT,
- imx_clk_gate("video_pll1_out", "video_pll1_bypass",
+ imx_clk_gate(dev, "video_pll1_out", "video_pll1_bypass",
base + 0x10, 11));
clk_dm(IMX8MQ_SYS1_PLL_OUT,
- imx_clk_gate("sys_pll1_out", "sys1_pll",
+ imx_clk_gate(dev, "sys_pll1_out", "sys1_pll",
base + 0x30, 11));
clk_dm(IMX8MQ_SYS2_PLL_OUT,
- imx_clk_gate("sys_pll2_out", "sys2_pll",
+ imx_clk_gate(dev, "sys_pll2_out", "sys2_pll",
base + 0x3c, 11));
clk_dm(IMX8MQ_SYS3_PLL_OUT,
- imx_clk_gate("sys_pll3_out", "sys3_pll",
+ imx_clk_gate(dev, "sys_pll3_out", "sys3_pll",
base + 0x48, 11));
clk_dm(IMX8MQ_VIDEO2_PLL_OUT,
- imx_clk_gate("video_pll2_out", "video_pll2_ref_sel",
+ imx_clk_gate(dev, "video_pll2_out", "video_pll2_ref_sel",
base + 0x54, 11));
/* SYS PLL fixed output */
clk_dm(IMX8MQ_SYS1_PLL_40M,
- imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20));
+ imx_clk_fixed_factor(dev, "sys_pll1_40m", "sys_pll1_out", 1, 20));
clk_dm(IMX8MQ_SYS1_PLL_80M,
- imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10));
+ imx_clk_fixed_factor(dev, "sys_pll1_80m", "sys_pll1_out", 1, 10));
clk_dm(IMX8MQ_SYS1_PLL_100M,
- imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8));
+ imx_clk_fixed_factor(dev, "sys_pll1_100m", "sys_pll1_out", 1, 8));
clk_dm(IMX8MQ_SYS1_PLL_133M,
- imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6));
+ imx_clk_fixed_factor(dev, "sys_pll1_133m", "sys_pll1_out", 1, 6));
clk_dm(IMX8MQ_SYS1_PLL_160M,
- imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5));
+ imx_clk_fixed_factor(dev, "sys_pll1_160m", "sys_pll1_out", 1, 5));
clk_dm(IMX8MQ_SYS1_PLL_200M,
- imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4));
+ imx_clk_fixed_factor(dev, "sys_pll1_200m", "sys_pll1_out", 1, 4));
clk_dm(IMX8MQ_SYS1_PLL_266M,
- imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3));
+ imx_clk_fixed_factor(dev, "sys_pll1_266m", "sys_pll1_out", 1, 3));
clk_dm(IMX8MQ_SYS1_PLL_400M,
- imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll1_400m", "sys_pll1_out", 1, 2));
clk_dm(IMX8MQ_SYS1_PLL_800M,
- imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1));
+ imx_clk_fixed_factor(dev, "sys_pll1_800m", "sys_pll1_out", 1, 1));
clk_dm(IMX8MQ_SYS2_PLL_50M,
- imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20));
+ imx_clk_fixed_factor(dev, "sys_pll2_50m", "sys_pll2_out", 1, 20));
clk_dm(IMX8MQ_SYS2_PLL_100M,
- imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10));
+ imx_clk_fixed_factor(dev, "sys_pll2_100m", "sys_pll2_out", 1, 10));
clk_dm(IMX8MQ_SYS2_PLL_125M,
- imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8));
+ imx_clk_fixed_factor(dev, "sys_pll2_125m", "sys_pll2_out", 1, 8));
clk_dm(IMX8MQ_SYS2_PLL_166M,
- imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6));
+ imx_clk_fixed_factor(dev, "sys_pll2_166m", "sys_pll2_out", 1, 6));
clk_dm(IMX8MQ_SYS2_PLL_200M,
- imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5));
+ imx_clk_fixed_factor(dev, "sys_pll2_200m", "sys_pll2_out", 1, 5));
clk_dm(IMX8MQ_SYS2_PLL_250M,
- imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4));
+ imx_clk_fixed_factor(dev, "sys_pll2_250m", "sys_pll2_out", 1, 4));
clk_dm(IMX8MQ_SYS2_PLL_333M,
- imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3));
+ imx_clk_fixed_factor(dev, "sys_pll2_333m", "sys_pll2_out", 1, 3));
clk_dm(IMX8MQ_SYS2_PLL_500M,
- imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll2_500m", "sys_pll2_out", 1, 2));
clk_dm(IMX8MQ_SYS2_PLL_1000M,
- imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1));
+ imx_clk_fixed_factor(dev, "sys_pll2_1000m", "sys_pll2_out", 1, 1));
clk_dm(IMX8MQ_CLK_MON_AUDIO_PLL1_DIV,
- imx_clk_divider("audio_pll1_out_monitor", "audio_pll1_bypass", base + 0x78, 0, 3));
+ imx_clk_divider(dev, "audio_pll1_out_monitor", "audio_pll1_bypass", base + 0x78, 0, 3));
clk_dm(IMX8MQ_CLK_MON_AUDIO_PLL2_DIV,
- imx_clk_divider("audio_pll2_out_monitor", "audio_pll2_bypass", base + 0x78, 4, 3));
+ imx_clk_divider(dev, "audio_pll2_out_monitor", "audio_pll2_bypass", base + 0x78, 4, 3));
clk_dm(IMX8MQ_CLK_MON_VIDEO_PLL1_DIV,
- imx_clk_divider("video_pll1_out_monitor", "video_pll1_bypass", base + 0x78, 8, 3));
+ imx_clk_divider(dev, "video_pll1_out_monitor", "video_pll1_bypass", base + 0x78, 8, 3));
clk_dm(IMX8MQ_CLK_MON_GPU_PLL_DIV,
- imx_clk_divider("gpu_pll_out_monitor", "gpu_pll_bypass", base + 0x78, 12, 3));
+ imx_clk_divider(dev, "gpu_pll_out_monitor", "gpu_pll_bypass", base + 0x78, 12, 3));
clk_dm(IMX8MQ_CLK_MON_VPU_PLL_DIV,
- imx_clk_divider("vpu_pll_out_monitor", "vpu_pll_bypass", base + 0x78, 16, 3));
+ imx_clk_divider(dev, "vpu_pll_out_monitor", "vpu_pll_bypass", base + 0x78, 16, 3));
clk_dm(IMX8MQ_CLK_MON_ARM_PLL_DIV,
- imx_clk_divider("arm_pll_out_monitor", "arm_pll_bypass", base + 0x78, 20, 3));
+ imx_clk_divider(dev, "arm_pll_out_monitor", "arm_pll_bypass", base + 0x78, 20, 3));
clk_dm(IMX8MQ_CLK_MON_SYS_PLL1_DIV,
- imx_clk_divider("sys_pll1_out_monitor", "sys_pll1_out", base + 0x7c, 0, 3));
+ imx_clk_divider(dev, "sys_pll1_out_monitor", "sys_pll1_out", base + 0x7c, 0, 3));
clk_dm(IMX8MQ_CLK_MON_SYS_PLL2_DIV,
- imx_clk_divider("sys_pll2_out_monitor", "sys_pll2_out", base + 0x7c, 4, 3));
+ imx_clk_divider(dev, "sys_pll2_out_monitor", "sys_pll2_out", base + 0x7c, 4, 3));
clk_dm(IMX8MQ_CLK_MON_SYS_PLL3_DIV,
- imx_clk_divider("sys_pll3_out_monitor", "sys_pll3_out", base + 0x7c, 8, 3));
+ imx_clk_divider(dev, "sys_pll3_out_monitor", "sys_pll3_out", base + 0x7c, 8, 3));
clk_dm(IMX8MQ_CLK_MON_DRAM_PLL_DIV,
- imx_clk_divider("dram_pll_out_monitor", "dram_pll_out", base + 0x7c, 12, 3));
+ imx_clk_divider(dev, "dram_pll_out_monitor", "dram_pll_out", base + 0x7c, 12, 3));
clk_dm(IMX8MQ_CLK_MON_VIDEO_PLL2_DIV,
- imx_clk_divider("video_pll2_out_monitor", "video_pll2_out", base + 0x7c, 16, 3));
+ imx_clk_divider(dev, "video_pll2_out_monitor", "video_pll2_out", base + 0x7c, 16, 3));
clk_dm(IMX8MQ_CLK_MON_SEL,
- imx_clk_mux_flags("pllout_monitor_sel", base + 0x74, 0, 4,
+ imx_clk_mux_flags(dev, "pllout_monitor_sel", base + 0x74, 0, 4,
pllout_monitor_sels,
ARRAY_SIZE(pllout_monitor_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMX8MQ_CLK_MON_CLK2_OUT,
- imx_clk_gate4("pllout_monitor_clk2", "pllout_monitor_sel", base + 0x74, 4));
+ imx_clk_gate4(dev, "pllout_monitor_clk2", "pllout_monitor_sel", base + 0x74, 4));
base = dev_read_addr_ptr(dev);
if (!base) {
@@ -349,140 +349,140 @@ static int imx8mq_clk_probe(struct udevice *dev)
}
clk_dm(IMX8MQ_CLK_A53_SRC,
- imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3,
+ imx_clk_mux2(dev, "arm_a53_src", base + 0x8000, 24, 3,
imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels)));
clk_dm(IMX8MQ_CLK_A53_CG,
- imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
+ imx_clk_gate3(dev, "arm_a53_cg", "arm_a53_src", base + 0x8000, 28));
clk_dm(IMX8MQ_CLK_A53_DIV,
- imx_clk_divider2("arm_a53_div", "arm_a53_cg",
+ imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg",
base + 0x8000, 0, 3));
clk_dm(IMX8MQ_CLK_A53_CORE,
- imx_clk_mux2("arm_a53_src", base + 0x9880, 24, 1,
+ imx_clk_mux2(dev, "arm_a53_src", base + 0x9880, 24, 1,
imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels)));
clk_dm(IMX8MQ_CLK_AHB,
- imx8m_clk_composite_critical("ahb", imx8mq_ahb_sels,
+ imx8m_clk_composite_critical(dev, "ahb", imx8mq_ahb_sels,
base + 0x9000));
clk_dm(IMX8MQ_CLK_IPG_ROOT,
- imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1));
+ imx_clk_divider2(dev, "ipg_root", "ahb", base + 0x9080, 0, 1));
clk_dm(IMX8MQ_CLK_ENET_AXI,
- imx8m_clk_composite("enet_axi", imx8mq_enet_axi_sels,
+ imx8m_clk_composite(dev, "enet_axi", imx8mq_enet_axi_sels,
base + 0x8880));
clk_dm(IMX8MQ_CLK_NAND_USDHC_BUS,
- imx8m_clk_composite_critical("nand_usdhc_bus",
+ imx8m_clk_composite_critical(dev, "nand_usdhc_bus",
imx8mq_nand_usdhc_sels,
base + 0x8900));
clk_dm(IMX8MQ_CLK_USB_BUS,
- imx8m_clk_composite("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80));
+ imx8m_clk_composite(dev, "usb_bus", imx8mq_usb_bus_sels, base + 0x8b80));
/* DRAM */
clk_dm(IMX8MQ_CLK_DRAM_CORE,
- imx_clk_mux2("dram_core_clk", base + 0x9800, 24, 1,
+ imx_clk_mux2(dev, "dram_core_clk", base + 0x9800, 24, 1,
imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels)));
clk_dm(IMX8MQ_CLK_DRAM_ALT,
- imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000));
+ imx8m_clk_composite(dev, "dram_alt", imx8mq_dram_alt_sels, base + 0xa000));
clk_dm(IMX8MQ_CLK_DRAM_APB,
- imx8m_clk_composite_critical("dram_apb", imx8mq_dram_apb_sels, base + 0xa080));
+ imx8m_clk_composite_critical(dev, "dram_apb", imx8mq_dram_apb_sels, base + 0xa080));
/* IP */
clk_dm(IMX8MQ_CLK_USDHC1,
- imx8m_clk_composite("usdhc1", imx8mq_usdhc1_sels,
+ imx8m_clk_composite(dev, "usdhc1", imx8mq_usdhc1_sels,
base + 0xac00));
clk_dm(IMX8MQ_CLK_USDHC2,
- imx8m_clk_composite("usdhc2", imx8mq_usdhc2_sels,
+ imx8m_clk_composite(dev, "usdhc2", imx8mq_usdhc2_sels,
base + 0xac80));
clk_dm(IMX8MQ_CLK_I2C1,
- imx8m_clk_composite("i2c1", imx8mq_i2c1_sels, base + 0xad00));
+ imx8m_clk_composite(dev, "i2c1", imx8mq_i2c1_sels, base + 0xad00));
clk_dm(IMX8MQ_CLK_I2C2,
- imx8m_clk_composite("i2c2", imx8mq_i2c2_sels, base + 0xad80));
+ imx8m_clk_composite(dev, "i2c2", imx8mq_i2c2_sels, base + 0xad80));
clk_dm(IMX8MQ_CLK_I2C3,
- imx8m_clk_composite("i2c3", imx8mq_i2c3_sels, base + 0xae00));
+ imx8m_clk_composite(dev, "i2c3", imx8mq_i2c3_sels, base + 0xae00));
clk_dm(IMX8MQ_CLK_I2C4,
- imx8m_clk_composite("i2c4", imx8mq_i2c4_sels, base + 0xae80));
+ imx8m_clk_composite(dev, "i2c4", imx8mq_i2c4_sels, base + 0xae80));
clk_dm(IMX8MQ_CLK_WDOG,
- imx8m_clk_composite("wdog", imx8mq_wdog_sels, base + 0xb900));
+ imx8m_clk_composite(dev, "wdog", imx8mq_wdog_sels, base + 0xb900));
clk_dm(IMX8MQ_CLK_UART1,
- imx8m_clk_composite("uart1", imx8mq_uart1_sels, base + 0xaf00));
+ imx8m_clk_composite(dev, "uart1", imx8mq_uart1_sels, base + 0xaf00));
clk_dm(IMX8MQ_CLK_UART2,
- imx8m_clk_composite("uart2", imx8mq_uart2_sels, base + 0xaf80));
+ imx8m_clk_composite(dev, "uart2", imx8mq_uart2_sels, base + 0xaf80));
clk_dm(IMX8MQ_CLK_UART3,
- imx8m_clk_composite("uart3", imx8mq_uart3_sels, base + 0xb000));
+ imx8m_clk_composite(dev, "uart3", imx8mq_uart3_sels, base + 0xb000));
clk_dm(IMX8MQ_CLK_UART4,
- imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080));
+ imx8m_clk_composite(dev, "uart4", imx8mq_uart4_sels, base + 0xb080));
clk_dm(IMX8MQ_CLK_QSPI,
- imx8m_clk_composite("qspi", imx8mq_qspi_sels, base + 0xab80));
+ imx8m_clk_composite(dev, "qspi", imx8mq_qspi_sels, base + 0xab80));
clk_dm(IMX8MQ_CLK_USB_CORE_REF,
- imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100));
+ imx8m_clk_composite(dev, "usb_core_ref", imx8mq_usb_core_sels, base + 0xb100));
clk_dm(IMX8MQ_CLK_USB_PHY_REF,
- imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180));
+ imx8m_clk_composite(dev, "usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180));
clk_dm(IMX8MQ_CLK_ECSPI1,
- imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280));
+ imx8m_clk_composite(dev, "ecspi1", imx8mq_ecspi1_sels, base + 0xb280));
clk_dm(IMX8MQ_CLK_ECSPI2,
- imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300));
+ imx8m_clk_composite(dev, "ecspi2", imx8mq_ecspi2_sels, base + 0xb300));
clk_dm(IMX8MQ_CLK_ECSPI3,
- imx8m_clk_composite("ecspi3", imx8mq_ecspi3_sels, base + 0xc180));
+ imx8m_clk_composite(dev, "ecspi3", imx8mq_ecspi3_sels, base + 0xc180));
clk_dm(IMX8MQ_CLK_ECSPI1_ROOT,
- imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
+ imx_clk_gate4(dev, "ecspi1_root_clk", "ecspi1", base + 0x4070, 0));
clk_dm(IMX8MQ_CLK_ECSPI2_ROOT,
- imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
+ imx_clk_gate4(dev, "ecspi2_root_clk", "ecspi2", base + 0x4080, 0));
clk_dm(IMX8MQ_CLK_ECSPI3_ROOT,
- imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
+ imx_clk_gate4(dev, "ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
clk_dm(IMX8MQ_CLK_I2C1_ROOT,
- imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
+ imx_clk_gate4(dev, "i2c1_root_clk", "i2c1", base + 0x4170, 0));
clk_dm(IMX8MQ_CLK_I2C2_ROOT,
- imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0));
+ imx_clk_gate4(dev, "i2c2_root_clk", "i2c2", base + 0x4180, 0));
clk_dm(IMX8MQ_CLK_I2C3_ROOT,
- imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0));
+ imx_clk_gate4(dev, "i2c3_root_clk", "i2c3", base + 0x4190, 0));
clk_dm(IMX8MQ_CLK_I2C4_ROOT,
- imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0));
+ imx_clk_gate4(dev, "i2c4_root_clk", "i2c4", base + 0x41a0, 0));
clk_dm(IMX8MQ_CLK_UART1_ROOT,
- imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0));
+ imx_clk_gate4(dev, "uart1_root_clk", "uart1", base + 0x4490, 0));
clk_dm(IMX8MQ_CLK_UART2_ROOT,
- imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0));
+ imx_clk_gate4(dev, "uart2_root_clk", "uart2", base + 0x44a0, 0));
clk_dm(IMX8MQ_CLK_UART3_ROOT,
- imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0));
+ imx_clk_gate4(dev, "uart3_root_clk", "uart3", base + 0x44b0, 0));
clk_dm(IMX8MQ_CLK_UART4_ROOT,
- imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0));
+ imx_clk_gate4(dev, "uart4_root_clk", "uart4", base + 0x44c0, 0));
clk_dm(IMX8MQ_CLK_OCOTP_ROOT,
- imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0));
+ imx_clk_gate4(dev, "ocotp_root_clk", "ipg_root", base + 0x4220, 0));
clk_dm(IMX8MQ_CLK_USDHC1_ROOT,
- imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
+ imx_clk_gate4(dev, "usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
clk_dm(IMX8MQ_CLK_USDHC2_ROOT,
- imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
+ imx_clk_gate4(dev, "usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
clk_dm(IMX8MQ_CLK_WDOG1_ROOT,
- imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0));
+ imx_clk_gate4(dev, "wdog1_root_clk", "wdog", base + 0x4530, 0));
clk_dm(IMX8MQ_CLK_WDOG2_ROOT,
- imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0));
+ imx_clk_gate4(dev, "wdog2_root_clk", "wdog", base + 0x4540, 0));
clk_dm(IMX8MQ_CLK_WDOG3_ROOT,
- imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
+ imx_clk_gate4(dev, "wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MQ_CLK_QSPI_ROOT,
- imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
+ imx_clk_gate4(dev, "qspi_root_clk", "qspi", base + 0x42f0, 0));
clk_dm(IMX8MQ_CLK_USB1_CTRL_ROOT,
- imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
+ imx_clk_gate4(dev, "usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
clk_dm(IMX8MQ_CLK_USB2_CTRL_ROOT,
- imx_clk_gate4("usb2_ctrl_root_clk", "usb_bus", base + 0x44e0, 0));
+ imx_clk_gate4(dev, "usb2_ctrl_root_clk", "usb_bus", base + 0x44e0, 0));
clk_dm(IMX8MQ_CLK_USB1_PHY_ROOT,
- imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0));
+ imx_clk_gate4(dev, "usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0));
clk_dm(IMX8MQ_CLK_USB2_PHY_ROOT,
- imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0));
+ imx_clk_gate4(dev, "usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0));
clk_dm(IMX8MQ_CLK_ENET_REF,
- imx8m_clk_composite("enet_ref", imx8mq_enet_ref_sels,
+ imx8m_clk_composite(dev, "enet_ref", imx8mq_enet_ref_sels,
base + 0xa980));
clk_dm(IMX8MQ_CLK_ENET_TIMER,
- imx8m_clk_composite("enet_timer", imx8mq_enet_timer_sels,
+ imx8m_clk_composite(dev, "enet_timer", imx8mq_enet_timer_sels,
base + 0xaa00));
clk_dm(IMX8MQ_CLK_ENET_PHY_REF,
- imx8m_clk_composite("enet_phy", imx8mq_enet_phy_sels,
+ imx8m_clk_composite(dev, "enet_phy", imx8mq_enet_phy_sels,
base + 0xaa80));
clk_dm(IMX8MQ_CLK_ENET1_ROOT,
- imx_clk_gate4("enet1_root_clk", "enet_axi",
+ imx_clk_gate4(dev, "enet1_root_clk", "enet_axi",
base + 0x40a0, 0));
clk_dm(IMX8MQ_CLK_DRAM_ALT_ROOT,
- imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4));
+ imx_clk_fixed_factor(dev, "dram_alt_root", "dram_alt", 1, 4));
return 0;
}
diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
index b31e57a4a01..c3112968c17 100644
--- a/drivers/clk/imx/clk-imx93.c
+++ b/drivers/clk/imx/clk-imx93.c
@@ -291,15 +291,15 @@ static int imx93_clk_probe(struct udevice *dev)
clk_dm(IMX93_CLK_SYS_PLL_PFD0,
clk_register_fixed_rate(NULL, "sys_pll_pfd0", 1000000000));
clk_dm(IMX93_CLK_SYS_PLL_PFD0_DIV2,
- imx_clk_fixed_factor("sys_pll_pfd0_div2", "sys_pll_pfd0", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll_pfd0_div2", "sys_pll_pfd0", 1, 2));
clk_dm(IMX93_CLK_SYS_PLL_PFD1,
clk_register_fixed_rate(NULL, "sys_pll_pfd1", 800000000));
clk_dm(IMX93_CLK_SYS_PLL_PFD1_DIV2,
- imx_clk_fixed_factor("sys_pll_pfd1_div2", "sys_pll_pfd1", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll_pfd1_div2", "sys_pll_pfd1", 1, 2));
clk_dm(IMX93_CLK_SYS_PLL_PFD2,
clk_register_fixed_rate(NULL, "sys_pll_pfd2", 625000000));
clk_dm(IMX93_CLK_SYS_PLL_PFD2_DIV2,
- imx_clk_fixed_factor("sys_pll_pfd2_div2", "sys_pll_pfd2", 1, 2));
+ imx_clk_fixed_factor(dev, "sys_pll_pfd2_div2", "sys_pll_pfd2", 1, 2));
anatop_base = (void *)ANATOP_BASE_ADDR;
@@ -338,7 +338,7 @@ static int imx93_clk_probe(struct udevice *dev)
}
clk_dm(IMX93_CLK_A55_SEL,
- imx_clk_mux2("a55_sel", base + 0x4820, 0, 1,
+ imx_clk_mux2(dev, "a55_sel", base + 0x4820, 0, 1,
a55_core_sels, ARRAY_SIZE(a55_core_sels)));
return 0;
diff --git a/drivers/clk/imx/clk-imxrt1020.c b/drivers/clk/imx/clk-imxrt1020.c
index 752434cb0ad..c14afdaf236 100644
--- a/drivers/clk/imx/clk-imxrt1020.c
+++ b/drivers/clk/imx/clk-imxrt1020.c
@@ -38,26 +38,26 @@ static int imxrt1020_clk_probe(struct udevice *dev)
base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop"));
clk_dm(IMXRT1020_CLK_PLL2_SYS,
- imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_sys", "osc",
base + 0x30, 0x1));
clk_dm(IMXRT1020_CLK_PLL3_USB_OTG,
- imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg", "osc",
base + 0x10, 0x1));
/* PLL bypass out */
clk_dm(IMXRT1020_CLK_PLL2_BYPASS,
- imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1,
+ imx_clk_mux_flags(dev, "pll2_bypass", base + 0x30, 16, 1,
pll2_bypass_sels,
ARRAY_SIZE(pll2_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMXRT1020_CLK_PLL3_BYPASS,
- imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1,
+ imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1,
pll3_bypass_sels,
ARRAY_SIZE(pll3_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMXRT1020_CLK_PLL3_80M,
- imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6));
+ imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6));
clk_dm(IMXRT1020_CLK_PLL2_PFD0_352M,
imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + 0x100, 0));
@@ -78,51 +78,51 @@ static int imxrt1020_clk_probe(struct udevice *dev)
return -EINVAL;
clk_dm(IMXRT1020_CLK_PRE_PERIPH_SEL,
- imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2,
+ imx_clk_mux(dev, "pre_periph_sel", base + 0x18, 18, 2,
pre_periph_sels, ARRAY_SIZE(pre_periph_sels)));
clk_dm(IMXRT1020_CLK_PERIPH_SEL,
- imx_clk_mux("periph_sel", base + 0x14, 25, 1,
+ imx_clk_mux(dev, "periph_sel", base + 0x14, 25, 1,
periph_sels, ARRAY_SIZE(periph_sels)));
clk_dm(IMXRT1020_CLK_USDHC1_SEL,
- imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
+ imx_clk_mux(dev, "usdhc1_sel", base + 0x1c, 16, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMXRT1020_CLK_USDHC2_SEL,
- imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
+ imx_clk_mux(dev, "usdhc2_sel", base + 0x1c, 17, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMXRT1020_CLK_LPUART_SEL,
- imx_clk_mux("lpuart_sel", base + 0x24, 6, 1,
+ imx_clk_mux(dev, "lpuart_sel", base + 0x24, 6, 1,
lpuart_sels, ARRAY_SIZE(lpuart_sels)));
clk_dm(IMXRT1020_CLK_SEMC_ALT_SEL,
- imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1,
+ imx_clk_mux(dev, "semc_alt_sel", base + 0x14, 7, 1,
semc_alt_sels, ARRAY_SIZE(semc_alt_sels)));
clk_dm(IMXRT1020_CLK_SEMC_SEL,
- imx_clk_mux("semc_sel", base + 0x14, 6, 1,
+ imx_clk_mux(dev, "semc_sel", base + 0x14, 6, 1,
semc_sels, ARRAY_SIZE(semc_sels)));
clk_dm(IMXRT1020_CLK_AHB_PODF,
- imx_clk_divider("ahb_podf", "periph_sel",
+ imx_clk_divider(dev, "ahb_podf", "periph_sel",
base + 0x14, 10, 3));
clk_dm(IMXRT1020_CLK_USDHC1_PODF,
- imx_clk_divider("usdhc1_podf", "usdhc1_sel",
+ imx_clk_divider(dev, "usdhc1_podf", "usdhc1_sel",
base + 0x24, 11, 3));
clk_dm(IMXRT1020_CLK_USDHC2_PODF,
- imx_clk_divider("usdhc2_podf", "usdhc2_sel",
+ imx_clk_divider(dev, "usdhc2_podf", "usdhc2_sel",
base + 0x24, 16, 3));
clk_dm(IMXRT1020_CLK_LPUART_PODF,
- imx_clk_divider("lpuart_podf", "lpuart_sel",
+ imx_clk_divider(dev, "lpuart_podf", "lpuart_sel",
base + 0x24, 0, 6));
clk_dm(IMXRT1020_CLK_SEMC_PODF,
- imx_clk_divider("semc_podf", "semc_sel",
+ imx_clk_divider(dev, "semc_podf", "semc_sel",
base + 0x14, 16, 3));
clk_dm(IMXRT1020_CLK_USDHC1,
- imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
+ imx_clk_gate2(dev, "usdhc1", "usdhc1_podf", base + 0x80, 2));
clk_dm(IMXRT1020_CLK_USDHC2,
- imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
+ imx_clk_gate2(dev, "usdhc2", "usdhc2_podf", base + 0x80, 4));
clk_dm(IMXRT1020_CLK_LPUART1,
- imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, 24));
+ imx_clk_gate2(dev, "lpuart1", "lpuart_podf", base + 0x7c, 24));
clk_dm(IMXRT1020_CLK_SEMC,
- imx_clk_gate2("semc", "semc_podf", base + 0x74, 4));
+ imx_clk_gate2(dev, "semc", "semc_podf", base + 0x74, 4));
#ifdef CONFIG_XPL_BUILD
struct clk *clk, *clk1;
diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c
index 2c029ec5a6e..ba5b48748ef 100644
--- a/drivers/clk/imx/clk-imxrt1050.c
+++ b/drivers/clk/imx/clk-imxrt1050.c
@@ -36,63 +36,63 @@ static int imxrt1050_clk_probe(struct udevice *dev)
base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop"));
clk_dm(IMXRT1050_CLK_PLL1_REF_SEL,
- imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2,
+ imx_clk_mux(dev, "pll1_arm_ref_sel", base + 0x0, 14, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMXRT1050_CLK_PLL2_REF_SEL,
- imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2,
+ imx_clk_mux(dev, "pll2_sys_ref_sel", base + 0x30, 14, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMXRT1050_CLK_PLL3_REF_SEL,
- imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, 2,
+ imx_clk_mux(dev, "pll3_usb_otg_ref_sel", base + 0x10, 14, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMXRT1050_CLK_PLL5_REF_SEL,
- imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2,
+ imx_clk_mux(dev, "pll5_video_ref_sel", base + 0xa0, 14, 2,
pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMXRT1050_CLK_PLL1_ARM,
- imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", "pll1_arm_ref_sel",
+ imx_clk_pllv3(dev, IMX_PLLV3_SYS, "pll1_arm", "pll1_arm_ref_sel",
base + 0x0, 0x7f));
clk_dm(IMXRT1050_CLK_PLL2_SYS,
- imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "pll2_sys_ref_sel",
+ imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_sys", "pll2_sys_ref_sel",
base + 0x30, 0x1));
clk_dm(IMXRT1050_CLK_PLL3_USB_OTG,
- imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg",
+ imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg",
"pll3_usb_otg_ref_sel",
base + 0x10, 0x1));
clk_dm(IMXRT1050_CLK_PLL5_VIDEO,
- imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "pll5_video_ref_sel",
+ imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5_video", "pll5_video_ref_sel",
base + 0xa0, 0x7f));
/* PLL bypass out */
clk_dm(IMXRT1050_CLK_PLL1_BYPASS,
- imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1,
+ imx_clk_mux_flags(dev, "pll1_bypass", base + 0x0, 16, 1,
pll1_bypass_sels,
ARRAY_SIZE(pll1_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMXRT1050_CLK_PLL2_BYPASS,
- imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1,
+ imx_clk_mux_flags(dev, "pll2_bypass", base + 0x30, 16, 1,
pll2_bypass_sels,
ARRAY_SIZE(pll2_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMXRT1050_CLK_PLL3_BYPASS,
- imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1,
+ imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1,
pll3_bypass_sels,
ARRAY_SIZE(pll3_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMXRT1050_CLK_PLL5_BYPASS,
- imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1,
+ imx_clk_mux_flags(dev, "pll5_bypass", base + 0xa0, 16, 1,
pll5_bypass_sels,
ARRAY_SIZE(pll5_bypass_sels),
CLK_SET_RATE_PARENT));
clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL,
- imx_clk_divider("video_post_div_sel", "pll5_video",
+ imx_clk_divider(dev, "video_post_div_sel", "pll5_video",
base + 0xa0, 19, 2));
clk_dm(IMXRT1050_CLK_VIDEO_DIV,
- imx_clk_divider("video_div", "video_post_div_sel",
+ imx_clk_divider(dev, "video_div", "video_post_div_sel",
base + 0x170, 30, 2));
clk_dm(IMXRT1050_CLK_PLL3_80M,
- imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6));
+ imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6));
clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M,
imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + 0x100, 0));
@@ -113,73 +113,73 @@ static int imxrt1050_clk_probe(struct udevice *dev)
return -EINVAL;
clk_dm(IMXRT1050_CLK_ARM_PODF,
- imx_clk_divider("arm_podf", "pll1_arm",
+ imx_clk_divider(dev, "arm_podf", "pll1_arm",
base + 0x10, 0, 3));
clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL,
- imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2,
+ imx_clk_mux(dev, "pre_periph_sel", base + 0x18, 18, 2,
pre_periph_sels, ARRAY_SIZE(pre_periph_sels)));
clk_dm(IMXRT1050_CLK_PERIPH_SEL,
- imx_clk_mux("periph_sel", base + 0x14, 25, 1,
+ imx_clk_mux(dev, "periph_sel", base + 0x14, 25, 1,
periph_sels, ARRAY_SIZE(periph_sels)));
clk_dm(IMXRT1050_CLK_USDHC1_SEL,
- imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
+ imx_clk_mux(dev, "usdhc1_sel", base + 0x1c, 16, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMXRT1050_CLK_USDHC2_SEL,
- imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
+ imx_clk_mux(dev, "usdhc2_sel", base + 0x1c, 17, 1,
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
clk_dm(IMXRT1050_CLK_LPUART_SEL,
- imx_clk_mux("lpuart_sel", base + 0x24, 6, 1,
+ imx_clk_mux(dev, "lpuart_sel", base + 0x24, 6, 1,
lpuart_sels, ARRAY_SIZE(lpuart_sels)));
clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL,
- imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1,
+ imx_clk_mux(dev, "semc_alt_sel", base + 0x14, 7, 1,
semc_alt_sels, ARRAY_SIZE(semc_alt_sels)));
clk_dm(IMXRT1050_CLK_SEMC_SEL,
- imx_clk_mux("semc_sel", base + 0x14, 6, 1,
+ imx_clk_mux(dev, "semc_sel", base + 0x14, 6, 1,
semc_sels, ARRAY_SIZE(semc_sels)));
clk_dm(IMXRT1050_CLK_LCDIF_SEL,
- imx_clk_mux("lcdif_sel", base + 0x38, 15, 3,
+ imx_clk_mux(dev, "lcdif_sel", base + 0x38, 15, 3,
lcdif_sels, ARRAY_SIZE(lcdif_sels)));
clk_dm(IMXRT1050_CLK_AHB_PODF,
- imx_clk_divider("ahb_podf", "periph_sel",
+ imx_clk_divider(dev, "ahb_podf", "periph_sel",
base + 0x14, 10, 3));
clk_dm(IMXRT1050_CLK_IPG_PDOF,
- imx_clk_divider("ipg_podf", "ahb_podf",
+ imx_clk_divider(dev, "ipg_podf", "ahb_podf",
base + 0x14, 8, 2));
clk_dm(IMXRT1050_CLK_USDHC1_PODF,
- imx_clk_divider("usdhc1_podf", "usdhc1_sel",
+ imx_clk_divider(dev, "usdhc1_podf", "usdhc1_sel",
base + 0x24, 11, 3));
clk_dm(IMXRT1050_CLK_USDHC2_PODF,
- imx_clk_divider("usdhc2_podf", "usdhc2_sel",
+ imx_clk_divider(dev, "usdhc2_podf", "usdhc2_sel",
base + 0x24, 16, 3));
clk_dm(IMXRT1050_CLK_LPUART_PODF,
- imx_clk_divider("lpuart_podf", "lpuart_sel",
+ imx_clk_divider(dev, "lpuart_podf", "lpuart_sel",
base + 0x24, 0, 6));
clk_dm(IMXRT1050_CLK_SEMC_PODF,
- imx_clk_divider("semc_podf", "semc_sel",
+ imx_clk_divider(dev, "semc_podf", "semc_sel",
base + 0x14, 16, 3));
clk_dm(IMXRT1050_CLK_LCDIF_PRED,
- imx_clk_divider("lcdif_pred", "lcdif_sel",
+ imx_clk_divider(dev, "lcdif_pred", "lcdif_sel",
base + 0x38, 12, 3));
clk_dm(IMXRT1050_CLK_LCDIF_PODF,
- imx_clk_divider("lcdif_podf", "lcdif_pred",
+ imx_clk_divider(dev, "lcdif_podf", "lcdif_pred",
base + 0x18, 23, 3));
clk_dm(IMXRT1050_CLK_USDHC1,
- imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
+ imx_clk_gate2(dev, "usdhc1", "usdhc1_podf", base + 0x80, 2));
clk_dm(IMXRT1050_CLK_USDHC2,
- imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
+ imx_clk_gate2(dev, "usdhc2", "usdhc2_podf", base + 0x80, 4));
clk_dm(IMXRT1050_CLK_LPUART1,
- imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, 24));
+ imx_clk_gate2(dev, "lpuart1", "lpuart_podf", base + 0x7c, 24));
clk_dm(IMXRT1050_CLK_SEMC,
- imx_clk_gate2("semc", "semc_podf", base + 0x74, 4));
+ imx_clk_gate2(dev, "semc", "semc_podf", base + 0x74, 4));
clk_dm(IMXRT1050_CLK_LCDIF_APB,
- imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, 28));
+ imx_clk_gate2(dev, "lcdif", "lcdif_podf", base + 0x70, 28));
clk_dm(IMXRT1050_CLK_LCDIF_PIX,
- imx_clk_gate2("lcdif_pix", "lcdif", base + 0x74, 10));
+ imx_clk_gate2(dev, "lcdif_pix", "lcdif", base + 0x74, 10));
clk_dm(IMXRT1050_CLK_USBOH3,
- imx_clk_gate2("usboh3", "pll3_usb_otg", base + 0x80, 0));
+ imx_clk_gate2(dev, "usboh3", "pll3_usb_otg", base + 0x80, 0));
struct clk *clk, *clk1;
diff --git a/drivers/clk/imx/clk-imxrt1170.c b/drivers/clk/imx/clk-imxrt1170.c
index 88a294f4165..3f55d0d0127 100644
--- a/drivers/clk/imx/clk-imxrt1170.c
+++ b/drivers/clk/imx/clk-imxrt1170.c
@@ -114,20 +114,20 @@ static int imxrt1170_clk_probe(struct udevice *dev)
base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop"));
clk_dm(IMXRT1170_CLK_RCOSC_48M,
- imx_clk_fixed_factor("rcosc48M", "rcosc16M", 3, 1));
+ imx_clk_fixed_factor(dev, "rcosc48M", "rcosc16M", 3, 1));
clk_dm(IMXRT1170_CLK_RCOSC_400M,
- imx_clk_fixed_factor("rcosc400M", "rcosc16M", 25, 1));
+ imx_clk_fixed_factor(dev, "rcosc400M", "rcosc16M", 25, 1));
clk_dm(IMXRT1170_CLK_RCOSC_48M_DIV2,
- imx_clk_fixed_factor("rcosc48M_div2", "rcosc48M", 1, 2));
+ imx_clk_fixed_factor(dev, "rcosc48M_div2", "rcosc48M", 1, 2));
clk_dm(IMXRT1170_CLK_PLL_ARM,
- imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_SYS, "pll_arm", "osc",
base + 0x200, 0xff));
clk_dm(IMXRT1170_CLK_PLL3,
- imx_clk_pllv3(IMX_PLLV3_GENERICV2, "pll3_sys", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_GENERICV2, "pll3_sys", "osc",
base + 0x210, 1));
clk_dm(IMXRT1170_CLK_PLL2,
- imx_clk_pllv3(IMX_PLLV3_GENERICV2, "pll2_sys", "osc",
+ imx_clk_pllv3(dev, IMX_PLLV3_GENERICV2, "pll2_sys", "osc",
base + 0x240, 1));
clk_dm(IMXRT1170_CLK_PLL3_PFD0,
@@ -149,7 +149,7 @@ static int imxrt1170_clk_probe(struct udevice *dev)
imx_clk_pfd("pll2_pfd3", "pll2_sys", base + 0x270, 3));
clk_dm(IMXRT1170_CLK_PLL3_DIV2,
- imx_clk_fixed_factor("pll3_div2", "pll3_sys", 1, 2));
+ imx_clk_fixed_factor(dev, "pll3_div2", "pll3_sys", 1, 2));
/* CCM clocks */
base = dev_read_addr_ptr(dev);
@@ -157,31 +157,31 @@ static int imxrt1170_clk_probe(struct udevice *dev)
return -EINVAL;
clk_dm(IMXRT1170_CLK_LPUART1_SEL,
- imx_clk_mux("lpuart1_sel", base + (25 * 0x80), 8, 3,
+ imx_clk_mux(dev, "lpuart1_sel", base + (25 * 0x80), 8, 3,
lpuart1_sels, ARRAY_SIZE(lpuart1_sels)));
clk_dm(IMXRT1170_CLK_LPUART1,
- imx_clk_divider("lpuart1", "lpuart1_sel",
+ imx_clk_divider(dev, "lpuart1", "lpuart1_sel",
base + (25 * 0x80), 0, 8));
clk_dm(IMXRT1170_CLK_USDHC1_SEL,
- imx_clk_mux("usdhc1_sel", base + (58 * 0x80), 8, 3,
+ imx_clk_mux(dev, "usdhc1_sel", base + (58 * 0x80), 8, 3,
usdhc1_sels, ARRAY_SIZE(usdhc1_sels)));
clk_dm(IMXRT1170_CLK_USDHC1,
- imx_clk_divider("usdhc1", "usdhc1_sel",
+ imx_clk_divider(dev, "usdhc1", "usdhc1_sel",
base + (58 * 0x80), 0, 8));
clk_dm(IMXRT1170_CLK_GPT1_SEL,
- imx_clk_mux("gpt1_sel", base + (14 * 0x80), 8, 3,
+ imx_clk_mux(dev, "gpt1_sel", base + (14 * 0x80), 8, 3,
gpt1_sels, ARRAY_SIZE(gpt1_sels)));
clk_dm(IMXRT1170_CLK_GPT1,
- imx_clk_divider("gpt1", "gpt1_sel",
+ imx_clk_divider(dev, "gpt1", "gpt1_sel",
base + (14 * 0x80), 0, 8));
clk_dm(IMXRT1170_CLK_SEMC_SEL,
- imx_clk_mux("semc_sel", base + (4 * 0x80), 8, 3,
+ imx_clk_mux(dev, "semc_sel", base + (4 * 0x80), 8, 3,
semc_sels, ARRAY_SIZE(semc_sels)));
clk_dm(IMXRT1170_CLK_SEMC,
- imx_clk_divider("semc", "semc_sel",
+ imx_clk_divider(dev, "semc", "semc_sel",
base + (4 * 0x80), 0, 8));
struct clk *clk, *clk1;
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index c6692f2f9f5..85b6a9809e8 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -281,9 +281,9 @@ static const struct clk_ops clk_pllv3_enet_ops = {
.get_rate = clk_pllv3_enet_get_rate,
};
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
- const char *parent_name, void __iomem *base,
- u32 div_mask)
+struct clk *imx_clk_pllv3(struct udevice *dev, enum imx_pllv3_type type,
+ const char *name, const char *parent_name,
+ void __iomem *base, u32 div_mask)
{
struct clk_pllv3 *pll;
struct clk *clk;
@@ -339,7 +339,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
pll->div_mask = div_mask;
clk = &pll->clk;
- ret = clk_register(clk, drv_name, name, parent_name);
+ ret = clk_register(clk, drv_name, name,
+ clk_resolve_parent_clk(dev, parent_name));
if (ret) {
kfree(pll);
return ERR_PTR(ret);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 27a53ae5583..7d14dbc395f 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -78,84 +78,89 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk);
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk *clk_register_gate2(struct udevice *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, u8 cgr_val,
u8 clk_gate_flags, unsigned int *share_count);
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
- const char *parent_name, void __iomem *base,
- u32 div_mask);
+struct clk *imx_clk_pllv3(struct udevice *dev, enum imx_pllv3_type type,
+ const char *name, const char *parent_name,
+ void __iomem *base, u32 div_mask);
-static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
- void __iomem *reg, u8 shift)
+static inline struct clk *imx_clk_gate2(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg,
+ u8 shift)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_register_gate2(dev, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, NULL);
}
-static inline struct clk *imx_clk_gate2_shared(const char *name,
+static inline struct clk *imx_clk_gate2_shared(struct udevice *dev, const char *name,
const char *parent,
void __iomem *reg, u8 shift,
unsigned int *share_count)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_register_gate2(dev, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, share_count);
}
-static inline struct clk *imx_clk_gate2_shared2(const char *name,
+static inline struct clk *imx_clk_gate2_shared2(struct udevice *dev, const char *name,
const char *parent,
void __iomem *reg, u8 shift,
unsigned int *share_count)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+ return clk_register_gate2(dev, name, parent, CLK_SET_RATE_PARENT |
CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
share_count);
}
-static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
+static inline struct clk *imx_clk_gate4(struct udevice *dev, const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate2(NULL, name, parent,
+ return clk_register_gate2(dev, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0x3, 0, NULL);
}
-static inline struct clk *imx_clk_gate4_flags(const char *name,
+static inline struct clk *imx_clk_gate4_flags(struct udevice *dev, const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned long flags)
{
- return clk_register_gate2(NULL, name, parent,
+ return clk_register_gate2(dev, name, parent,
flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0x3, 0, NULL);
}
-static inline struct clk *imx_clk_fixed_factor(const char *name,
- const char *parent, unsigned int mult, unsigned int div)
+static inline struct clk *
+imx_clk_fixed_factor(struct udevice *dev, const char *name, const char *parent,
+ unsigned int mult, unsigned int div)
{
- return clk_register_fixed_factor(NULL, name, parent,
+ return clk_register_fixed_factor(dev, name, parent,
CLK_SET_RATE_PARENT, mult, div);
}
-static inline struct clk *imx_clk_divider(const char *name, const char *parent,
- void __iomem *reg, u8 shift, u8 width)
+static inline struct clk *imx_clk_divider(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg,
+ u8 shift, u8 width)
{
- return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+ return clk_register_divider(dev, name, parent, CLK_SET_RATE_PARENT,
reg, shift, width, 0);
}
static inline struct clk *
-imx_clk_busy_divider(const char *name, const char *parent, void __iomem *reg,
- u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift)
+imx_clk_busy_divider(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg, u8 shift, u8 width,
+ void __iomem *busy_reg, u8 busy_shift)
{
- return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+ return clk_register_divider(dev, name, parent, CLK_SET_RATE_PARENT,
reg, shift, width, 0);
}
-static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
- void __iomem *reg, u8 shift, u8 width)
+static inline struct clk *imx_clk_divider2(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg,
+ u8 shift, u8 width)
{
- return clk_register_divider(NULL, name, parent,
+ return clk_register_divider(dev, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0);
}
@@ -167,90 +172,93 @@ struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents, void (*fixup)(u32 *val));
-static inline struct clk *imx_clk_mux_flags(const char *name,
+static inline struct clk *imx_clk_mux_flags(struct udevice *dev, const char *name,
void __iomem *reg, u8 shift, u8 width,
const char * const *parents, int num_parents,
unsigned long flags)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_register_mux(dev, name, parents, num_parents,
flags | CLK_SET_RATE_NO_REPARENT, reg, shift,
width, 0);
}
-static inline struct clk *imx_clk_mux2_flags(const char *name,
+static inline struct clk *imx_clk_mux2_flags(struct udevice *dev, const char *name,
void __iomem *reg, u8 shift, u8 width,
const char * const *parents,
int num_parents, unsigned long flags)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_register_mux(dev, name, parents, num_parents,
flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0);
}
-static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
- u8 shift, u8 width, const char * const *parents,
+static inline struct clk *imx_clk_mux(struct udevice *dev, const char *name,
+ void __iomem *reg, u8 shift, u8 width, const char * const *parents,
int num_parents)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_register_mux(dev, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT, reg, shift,
width, 0);
}
static inline struct clk *
-imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width,
+imx_clk_busy_mux(struct udevice *dev, const char *name, void __iomem *reg, u8 shift, u8 width,
void __iomem *busy_reg, u8 busy_shift,
const char * const *parents, int num_parents)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_register_mux(dev, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT, reg, shift,
width, 0);
}
-static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
+static inline struct clk *imx_clk_mux2(struct udevice *dev, const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_register_mux(dev, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0);
}
-static inline struct clk *imx_clk_gate(const char *name, const char *parent,
- void __iomem *reg, u8 shift)
+static inline struct clk *imx_clk_gate(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg,
+ u8 shift)
{
- return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_register_gate(dev, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0, NULL);
}
-static inline struct clk *imx_clk_gate_flags(const char *name, const char *parent,
- void __iomem *reg, u8 shift, unsigned long flags)
+static inline struct clk *imx_clk_gate_flags(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg,
+ u8 shift, unsigned long flags)
{
- return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+ return clk_register_gate(dev, name, parent, flags | CLK_SET_RATE_PARENT, reg,
shift, 0, NULL);
}
-static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
- void __iomem *reg, u8 shift)
+static inline struct clk *imx_clk_gate3(struct udevice *dev, const char *name,
+ const char *parent, void __iomem *reg,
+ u8 shift)
{
- return clk_register_gate(NULL, name, parent,
+ return clk_register_gate(dev, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, NULL);
}
-struct clk *imx8m_clk_composite_flags(const char *name,
+struct clk *imx8m_clk_composite_flags(struct udevice *dev, const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg, unsigned long flags);
-#define __imx8m_clk_composite(name, parent_names, reg, flags) \
- imx8m_clk_composite_flags(name, parent_names, \
+#define __imx8m_clk_composite(dev, name, parent_names, reg, flags) \
+ imx8m_clk_composite_flags(dev, name, parent_names, \
ARRAY_SIZE(parent_names), reg, \
flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
-#define imx8m_clk_composite(name, parent_names, reg) \
- __imx8m_clk_composite(name, parent_names, reg, 0)
+#define imx8m_clk_composite(dev, name, parent_names, reg) \
+ __imx8m_clk_composite(dev, name, parent_names, reg, 0)
-#define imx8m_clk_composite_critical(name, parent_names, reg) \
- __imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
+#define imx8m_clk_composite_critical(dev, name, parent_names, reg) \
+ __imx8m_clk_composite(dev, name, parent_names, reg, CLK_IS_CRITICAL)
struct clk *imx93_clk_composite_flags(const char *name,
const char * const *parent_names,
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index e412c92cafc..12893687b68 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -3,7 +3,6 @@
obj-$(CONFIG_ARCH_MEDIATEK) += clk-mtk.o
# SoC Drivers
-obj-$(CONFIG_MT8512) += clk-mt8512.o
obj-$(CONFIG_TARGET_MT7623) += clk-mt7623.o
obj-$(CONFIG_TARGET_MT7622) += clk-mt7622.o
obj-$(CONFIG_TARGET_MT7629) += clk-mt7629.o
@@ -13,5 +12,6 @@ obj-$(CONFIG_TARGET_MT7988) += clk-mt7988.o
obj-$(CONFIG_TARGET_MT7987) += clk-mt7987.o
obj-$(CONFIG_TARGET_MT8183) += clk-mt8183.o
obj-$(CONFIG_TARGET_MT8365) += clk-mt8365.o
+obj-$(CONFIG_TARGET_MT8512) += clk-mt8512.o
obj-$(CONFIG_TARGET_MT8516) += clk-mt8516.o
obj-$(CONFIG_TARGET_MT8518) += clk-mt8518.o
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index cb867acc48c..3ea01f3c969 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -31,6 +31,14 @@ config CLK_QCOM_IPQ4019
on the Snapdragon IPQ4019 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
+config CLK_QCOM_IPQ9574
+ bool "Qualcomm IPQ9574 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon IPQ9574 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
config CLK_QCOM_QCM2290
bool "Qualcomm QCM2290 GCC"
select CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 1bc0f15005b..e13fc8c1071 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o
obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o
obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o
obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o
+obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o
obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o
obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o
obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
index b5def55dbc2..6a53f900a9e 100644
--- a/drivers/clk/qcom/clock-apq8016.c
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -54,8 +54,9 @@ static struct vote_clk gcc_blsp1_ahb_clk = {
};
static const struct gate_clk apq8016_clks[] = {
- GATE_CLK(GCC_USB_HS_AHB_CLK, 0x41008, 0x00000001),
- GATE_CLK(GCC_USB_HS_SYSTEM_CLK, 0x41004, 0x00000001),
+ GATE_CLK(GCC_PRNG_AHB_CLK, 0x45004, BIT(8)),
+ GATE_CLK(GCC_USB_HS_AHB_CLK, 0x41008, BIT(0)),
+ GATE_CLK(GCC_USB_HS_SYSTEM_CLK, 0x41004, BIT(0)),
};
/* SDHCI */
@@ -139,15 +140,14 @@ static int apq8016_clk_enable(struct clk *clk)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
- if (priv->data->num_clks < clk->id) {
+ if (priv->data->num_clks < clk->id || !apq8016_clks[clk->id].reg) {
log_warning("%s: unknown clk id %lu\n", __func__, clk->id);
return 0;
}
- debug("%s: clk %s\n", __func__, apq8016_clks[clk->id].name);
- qcom_gate_clk_en(priv, clk->id);
+ debug("%s: enabling clock %s\n", __func__, apq8016_clks[clk->id].name);
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static struct msm_clk_data apq8016_clk_data = {
diff --git a/drivers/clk/qcom/clock-ipq9574.c b/drivers/clk/qcom/clock-ipq9574.c
new file mode 100644
index 00000000000..b0af4036059
--- /dev/null
+++ b/drivers/clk/qcom/clock-ipq9574.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock drivers for Qualcomm ipq9574
+ *
+ * (C) Copyright 2025 Linaro Ltd.
+ */
+
+#include <linux/types.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,ipq9574-gcc.h>
+#include <dt-bindings/reset/qcom,ipq9574-gcc.h>
+
+#include "clock-qcom.h"
+
+#define GCC_BLSP1_AHB_CBCR 0x1004
+#define GCC_BLSP1_UART3_APPS_CMD_RCGR 0x402C
+#define GCC_BLSP1_UART3_APPS_CBCR 0x4054
+
+#define GCC_SDCC1_APPS_CBCR 0x3302C
+#define GCC_SDCC1_AHB_CBCR 0x33034
+#define GCC_SDCC1_APPS_CMD_RCGR 0x33004
+#define GCC_SDCC1_ICE_CORE_CBCR 0x33030
+
+static ulong ipq9574_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case GCC_BLSP1_UART3_APPS_CLK:
+ clk_rcg_set_rate_mnd(priv->base, GCC_BLSP1_UART3_APPS_CMD_RCGR,
+ 0, 144, 15625, CFG_CLK_SRC_GPLL0, 16);
+ return rate;
+ case GCC_SDCC1_APPS_CLK:
+ clk_rcg_set_rate_mnd(priv->base, GCC_SDCC1_APPS_CMD_RCGR,
+ 11, 0, 0, CFG_CLK_SRC_GPLL2, 16);
+ return rate;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct gate_clk ipq9574_clks[] = {
+ GATE_CLK(GCC_BLSP1_UART3_APPS_CLK, 0x4054, 0x00000001),
+ GATE_CLK(GCC_BLSP1_AHB_CLK, 0x1004, 0x00000001),
+ GATE_CLK(GCC_SDCC1_AHB_CLK, 0x33034, 0x00000001),
+ GATE_CLK(GCC_SDCC1_APPS_CLK, 0x3302C, 0x00000001),
+ GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x33030, 0x00000001),
+};
+
+static int ipq9574_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ debug("%s: clk %s\n", __func__, ipq9574_clks[clk->id].name);
+
+ if (!ipq9574_clks[clk->id].reg)
+ return -EINVAL;
+
+ qcom_gate_clk_en(priv, clk->id);
+
+ return 0;
+}
+
+static const struct qcom_reset_map ipq9574_gcc_resets[] = {
+ [GCC_SDCC_BCR] = { 0x33000 },
+};
+
+static struct msm_clk_data ipq9574_gcc_data = {
+ .resets = ipq9574_gcc_resets,
+ .num_resets = ARRAY_SIZE(ipq9574_gcc_resets),
+ .enable = ipq9574_enable,
+ .set_rate = ipq9574_set_rate,
+};
+
+static const struct udevice_id gcc_ipq9574_of_match[] = {
+ {
+ .compatible = "qcom,ipq9574-gcc",
+ .data = (ulong)&ipq9574_gcc_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_ipq9574) = {
+ .name = "gcc_ipq9574",
+ .id = UCLASS_NOP,
+ .of_match = gcc_ipq9574_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/clk/qcom/clock-qcm2290.c b/drivers/clk/qcom/clock-qcm2290.c
index c78705cb8cf..1326b770c3e 100644
--- a/drivers/clk/qcom/clock-qcm2290.c
+++ b/drivers/clk/qcom/clock-qcm2290.c
@@ -134,9 +134,7 @@ static int qcm2290_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map qcm2290_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
index ff336dea39c..f43edea2525 100644
--- a/drivers/clk/qcom/clock-qcom.h
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -7,10 +7,12 @@
#include <asm/io.h>
#include <linux/bitfield.h>
+#include <errno.h>
#define CFG_CLK_SRC_CXO (0 << 8)
#define CFG_CLK_SRC_GPLL0 (1 << 8)
#define CFG_CLK_SRC_GPLL0_AUX2 (2 << 8)
+#define CFG_CLK_SRC_GPLL2 (2 << 8)
#define CFG_CLK_SRC_GPLL9 (2 << 8)
#define CFG_CLK_SRC_GPLL0_ODD (3 << 8)
#define CFG_CLK_SRC_GPLL6 (4 << 8)
@@ -105,14 +107,19 @@ void clk_rcg_set_rate(phys_addr_t base, uint32_t cmd_rcgr, int div,
int source);
void clk_phy_mux_enable(phys_addr_t base, uint32_t cmd_rcgr, bool enabled);
-static inline void qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id)
+static inline int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id)
{
u32 val;
- if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0)
- return;
+ if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) {
+ log_err("gcc@%#08llx: unknown clock ID %lu!\n",
+ priv->base, id);
+ return -ENOENT;
+ }
val = readl(priv->base + priv->data->clks[id].reg);
writel(val | priv->data->clks[id].en_val, priv->base + priv->data->clks[id].reg);
+
+ return 0;
}
#endif
diff --git a/drivers/clk/qcom/clock-sa8775p.c b/drivers/clk/qcom/clock-sa8775p.c
index e31f24ed4f0..527cecf5c82 100644
--- a/drivers/clk/qcom/clock-sa8775p.c
+++ b/drivers/clk/qcom/clock-sa8775p.c
@@ -73,9 +73,7 @@ static int sa8775p_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sa8775p_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index 5d343f12051..8691f08109b 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -16,29 +16,64 @@
#include "clock-qcom.h"
-#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038
#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020
+#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038
+#define USB30_SEC_MASTER_CLK_CMD_RCGR 0x9e020
+#define USB30_SEC_MOCK_UTMI_CLK_CMD_RCGR 0x9e038
+#define PCIE_1_AUX_CLK_CMD_RCGR 0x8d058
+#define PCIE1_PHY_RCHNG_CMD_RCGR 0x8d03c
+#define PCIE_1_PIPE_CLK_PHY_MUX 0x8d054
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0),
+ F(133333333, CFG_CLK_SRC_GPLL0, 4.5, 0, 0),
+ F(200000000, CFG_CLK_SRC_GPLL0_ODD, 1, 0, 0),
+ F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_sec_master_clk_src[] = {
+ F(60000000, CFG_CLK_SRC_GPLL0_EVEN, 5, 0, 0),
+ F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0),
+ { }
+};
static ulong sc7280_set_rate(struct clk *clk, ulong rate)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct freq_tbl *freq;
if (clk->id < priv->data->num_clks)
debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate);
switch (clk->id) {
- case GCC_USB30_PRIM_MOCK_UTMI_CLK:
- WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate);
- clk_rcg_set_rate(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO);
- return rate;
case GCC_USB30_PRIM_MASTER_CLK:
- WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate);
+ freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate);
clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
- 1, 0, 0, CFG_CLK_SRC_GPLL0_ODD, 8);
- clk_rcg_set_rate(priv->base, 0xf064, 0, 0);
- return rate;
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ case GCC_USB30_PRIM_MOCK_UTMI_CLK:
+ clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 1, 0);
+ return 19200000;
+ case GCC_USB3_PRIM_PHY_AUX_CLK_SRC:
+ clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 1, 0);
+ return 19200000;
+ case GCC_USB30_SEC_MASTER_CLK:
+ freq = qcom_find_freq(ftbl_gcc_usb30_sec_master_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, USB30_SEC_MASTER_CLK_CMD_RCGR,
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ case GCC_USB30_SEC_MOCK_UTMI_CLK:
+ clk_rcg_set_rate(priv->base, USB30_SEC_MOCK_UTMI_CLK_CMD_RCGR, 1, 0);
+ return 19200000;
+ case GCC_USB3_SEC_PHY_AUX_CLK_SRC:
+ clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 1, 0);
+ return 19200000;
+ case GCC_PCIE1_PHY_RCHNG_CLK:
+ clk_rcg_set_rate(priv->base, PCIE1_PHY_RCHNG_CMD_RCGR, 5, CFG_CLK_SRC_GPLL0_EVEN);
+ return 100000000;
default:
- return 0;
+ return rate;
}
}
@@ -50,13 +85,35 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf01c, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf054, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf058, 1),
+ GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x9e07c, 1),
+ GATE_CLK(GCC_USB30_SEC_MASTER_CLK, 0x9e010, 1),
+ GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x9e080, 1),
+ GATE_CLK(GCC_USB30_SEC_SLEEP_CLK, 0x9e018, 1),
+ GATE_CLK(GCC_USB30_SEC_MOCK_UTMI_CLK, 0x9e01c, 1),
+ GATE_CLK(GCC_USB3_SEC_PHY_AUX_CLK, 0x9e054, 1),
+ GATE_CLK(GCC_USB3_SEC_PHY_COM_AUX_CLK, 0x9e058, 1),
+ GATE_CLK(GCC_PCIE_CLKREF_EN, 0x8c004, 1),
+ GATE_CLK(GCC_PCIE_1_PIPE_CLK, 0x52000, BIT(30)),
+ GATE_CLK(GCC_PCIE_1_AUX_CLK, 0x52000, BIT(29)),
+ GATE_CLK(GCC_PCIE_1_CFG_AHB_CLK, 0x52000, BIT(28)),
+ GATE_CLK(GCC_PCIE_1_MSTR_AXI_CLK, 0x52000, BIT(27)),
+ GATE_CLK(GCC_PCIE_1_SLV_AXI_CLK, 0x52000, BIT(26)),
+ GATE_CLK(GCC_PCIE_1_SLV_Q2A_AXI_CLK, 0x52000, BIT(25)),
+ GATE_CLK(GCC_PCIE1_PHY_RCHNG_CLK, 0x52000, BIT(23)),
+ GATE_CLK(GCC_DDRSS_PCIE_SF_CLK, 0x52000, BIT(19)),
+ GATE_CLK(GCC_AGGRE_NOC_PCIE_TBU_CLK, 0x52000, BIT(18)),
+ GATE_CLK(GCC_AGGRE_NOC_PCIE_1_AXI_CLK, 0x52000, BIT(11)),
+ GATE_CLK(GCC_AGGRE_NOC_PCIE_CENTER_SF_AXI_CLK, 0x52008, BIT(28)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)),
};
static int sc7280_enable(struct clk *clk)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
- if (priv->data->num_clks < clk->id) {
+ if (priv->data->num_clks <= clk->id) {
debug("%s: unknown clk id %lu\n", __func__, clk->id);
return 0;
}
@@ -71,11 +128,32 @@ static int sc7280_enable(struct clk *clk)
qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
break;
+ case GCC_AGGRE_USB3_SEC_AXI_CLK:
+ qcom_gate_clk_en(priv, GCC_USB30_SEC_MASTER_CLK);
+ fallthrough;
+ case GCC_USB30_SEC_MASTER_CLK:
+ qcom_gate_clk_en(priv, GCC_USB3_SEC_PHY_AUX_CLK);
+ qcom_gate_clk_en(priv, GCC_USB3_SEC_PHY_COM_AUX_CLK);
+ break;
+ case GCC_PCIE_1_PIPE_CLK:
+ clk_phy_mux_enable(priv->base, PCIE_1_PIPE_CLK_PHY_MUX, true);
+ break;
+ case GCC_PCIE_1_AUX_CLK:
+ clk_rcg_set_rate_mnd(priv->base, PCIE_1_AUX_CLK_CMD_RCGR, 1, 0, 0,
+ CFG_CLK_SRC_CXO, 16);
+ break;
+ case GCC_QUPV3_WRAP0_S0_CLK:
+ clk_rcg_set_rate_mnd(priv->base, 0x17010, 1, 0, 0, CFG_CLK_SRC_CXO, 16);
+ break;
+ case GCC_QUPV3_WRAP0_S1_CLK:
+ clk_rcg_set_rate_mnd(priv->base, 0x17140, 1, 0, 0, CFG_CLK_SRC_CXO, 16);
+ break;
+ case GCC_QUPV3_WRAP0_S3_CLK:
+ clk_rcg_set_rate_mnd(priv->base, 0x173a0, 1, 0, 0, CFG_CLK_SRC_CXO, 16);
+ break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sc7280_gcc_resets[] = {
@@ -100,6 +178,20 @@ static const struct qcom_reset_map sc7280_gcc_resets[] = {
static const struct qcom_power_map sc7280_gdscs[] = {
[GCC_UFS_PHY_GDSC] = { 0x77004 },
[GCC_USB30_PRIM_GDSC] = { 0xf004 },
+ [GCC_USB30_SEC_GDSC] = { 0x9e004 },
+ [GCC_PCIE_1_GDSC] = { 0x8d004 },
+};
+
+static const phys_addr_t sc7280_rcg_addrs[] = {
+ 0x10f020, // USB30_PRIM_MASTER_CLK_CMD_RCGR
+ 0x10f038, // USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR
+ 0x18d058, // PCIE_1_AUX_CLK_CMD_RCGR
+};
+
+static const char *const sc7280_rcg_names[] = {
+ "USB30_PRIM_MASTER_CLK_SRC",
+ "USB30_PRIM_MOCK_UTMI_CLK_SRC",
+ "GCC_PCIE_1_AUX_CLK_SRC",
};
static struct msm_clk_data qcs404_gcc_data = {
@@ -113,6 +205,10 @@ static struct msm_clk_data qcs404_gcc_data = {
.enable = sc7280_enable,
.set_rate = sc7280_set_rate,
+
+ .dbg_rcg_addrs = sc7280_rcg_addrs,
+ .num_rcgs = ARRAY_SIZE(sc7280_rcg_addrs),
+ .dbg_rcg_names = sc7280_rcg_names,
};
static const struct udevice_id gcc_sc7280_of_match[] = {
diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c
index adffb0cb240..6a0bf16ba2d 100644
--- a/drivers/clk/qcom/clock-sdm845.c
+++ b/drivers/clk/qcom/clock-sdm845.c
@@ -162,9 +162,7 @@ static int sdm845_clk_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sdm845_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-sm6115.c b/drivers/clk/qcom/clock-sm6115.c
index 9057dfe0bb1..17c2e561758 100644
--- a/drivers/clk/qcom/clock-sm6115.c
+++ b/drivers/clk/qcom/clock-sm6115.c
@@ -146,9 +146,7 @@ static int sm6115_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sm6115_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-sm8150.c b/drivers/clk/qcom/clock-sm8150.c
index 88f2e678f43..7dd0d56eb43 100644
--- a/drivers/clk/qcom/clock-sm8150.c
+++ b/drivers/clk/qcom/clock-sm8150.c
@@ -243,9 +243,7 @@ static int sm8150_clk_enable(struct clk *clk)
break;
};
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sm8150_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c
index e322a923a5c..26396847d85 100644
--- a/drivers/clk/qcom/clock-sm8250.c
+++ b/drivers/clk/qcom/clock-sm8250.c
@@ -195,9 +195,7 @@ static int sm8250_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sm8250_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-sm8550.c b/drivers/clk/qcom/clock-sm8550.c
index 62b5a409e8e..7c06489b9c4 100644
--- a/drivers/clk/qcom/clock-sm8550.c
+++ b/drivers/clk/qcom/clock-sm8550.c
@@ -220,9 +220,7 @@ static int sm8550_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sm8550_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-sm8650.c b/drivers/clk/qcom/clock-sm8650.c
index 9baaecb571f..364454644a6 100644
--- a/drivers/clk/qcom/clock-sm8650.c
+++ b/drivers/clk/qcom/clock-sm8650.c
@@ -217,9 +217,7 @@ static int sm8650_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map sm8650_gcc_resets[] = {
diff --git a/drivers/clk/qcom/clock-x1e80100.c b/drivers/clk/qcom/clock-x1e80100.c
index bd9c6ed1c8a..542d6248d65 100644
--- a/drivers/clk/qcom/clock-x1e80100.c
+++ b/drivers/clk/qcom/clock-x1e80100.c
@@ -174,9 +174,7 @@ static int x1e80100_enable(struct clk *clk)
break;
}
- qcom_gate_clk_en(priv, clk->id);
-
- return 0;
+ return qcom_gate_clk_en(priv, clk->id);
}
static const struct qcom_reset_map x1e80100_gcc_resets[] = {
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
index 3c5340df8ee..7fce1f70d13 100644
--- a/drivers/clk/renesas/rzg2l-cpg.c
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -70,17 +70,12 @@ static int rzg2l_cpg_clk_set(struct clk *clk, bool enable)
dev_dbg(clk->dev, "%s %s clock %u\n", enable ? "enable" : "disable",
is_mod_clk(clk->id) ? "module" : "core", cpg_clk_id);
- if (!is_mod_clk(clk->id)) {
- /*
- * Non-module clocks are always on. Ignore attempts to enable
- * them and reject attempts to disable them.
- */
- if (enable)
- return 0;
-
- dev_err(clk->dev, "ID %lu is not a module clock\n", clk->id);
- return -EINVAL;
- }
+ /*
+ * Non-module clocks are always on. Ignore attempts to enable or disable
+ * them.
+ */
+ if (!is_mod_clk(clk->id))
+ return 0;
for (i = 0; i < data->info->num_mod_clks; i++) {
if (data->info->mod_clks[i].id == cpg_clk_id) {
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
index 8bdc0944896..f44db76c182 100644
--- a/drivers/clk/sunxi/Kconfig
+++ b/drivers/clk/sunxi/Kconfig
@@ -122,4 +122,11 @@ config CLK_SUN50I_A64
This enables common clock driver support for platforms based
on Allwinner A64 SoC.
+config CLK_SUN50I_A100
+ bool "Clock driver for Allwinner A100/A133"
+ default MACH_SUN50I_A133
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner A100/A133 SoCs.
+
endif # CLK_SUNXI
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 90a277489dc..7ff71c756e0 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o
obj-$(CONFIG_CLK_SUN50I_H6_R) += clk_h6_r.o
obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o
obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o
+obj-$(CONFIG_CLK_SUN50I_A100) += clk_a100.o
diff --git a/drivers/clk/sunxi/clk_a100.c b/drivers/clk/sunxi/clk_a100.c
new file mode 100644
index 00000000000..b641feb8612
--- /dev/null
+++ b/drivers/clk/sunxi/clk_a100.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2023-2024 Arm Ltd.
+ */
+
+#include <clk/sunxi.h>
+#include <dt-bindings/clock/sun50i-a100-ccu.h>
+#include <dt-bindings/reset/sun50i-a100-ccu.h>
+#include <linux/bitops.h>
+
+static struct ccu_clk_gate a100_gates[] = {
+ [CLK_PLL_PERIPH0] = GATE(0x020, BIT(31) | BIT(27)),
+
+ [CLK_APB1] = GATE_DUMMY,
+
+ [CLK_DE] = GATE(0x600, BIT(31)),
+ [CLK_BUS_DE] = GATE(0x60c, BIT(0)),
+
+ [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)),
+ [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)),
+ [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)),
+
+ [CLK_BUS_UART0] = GATE(0x90c, BIT(0)),
+ [CLK_BUS_UART1] = GATE(0x90c, BIT(1)),
+ [CLK_BUS_UART2] = GATE(0x90c, BIT(2)),
+ [CLK_BUS_UART3] = GATE(0x90c, BIT(3)),
+ [CLK_BUS_UART4] = GATE(0x90c, BIT(4)),
+
+ [CLK_BUS_I2C0] = GATE(0x91c, BIT(0)),
+ [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)),
+ [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)),
+ [CLK_BUS_I2C3] = GATE(0x91c, BIT(3)),
+
+ [CLK_SPI0] = GATE(0x940, BIT(31)),
+ [CLK_SPI1] = GATE(0x944, BIT(31)),
+ [CLK_SPI2] = GATE(0x948, BIT(31)),
+
+ [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)),
+ [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)),
+ [CLK_BUS_SPI2] = GATE(0x96c, BIT(2)),
+
+ [CLK_BUS_EMAC] = GATE(0x97c, BIT(0)),
+
+ [CLK_USB_PHY0] = GATE(0xa70, BIT(29)),
+ [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)),
+
+ [CLK_USB_PHY1] = GATE(0xa74, BIT(29)),
+ [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)),
+
+ [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
+ [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)),
+ [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
+ [CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)),
+ [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
+
+ [CLK_TCON_LCD] = GATE(0xb60, BIT(31)),
+ [CLK_BUS_TCON_LCD] = GATE(0xb7c, BIT(0)),
+};
+
+static struct ccu_reset a100_resets[] = {
+ [RST_BUS_DE] = RESET(0x60c, BIT(16)),
+
+ [RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
+ [RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
+ [RST_BUS_MMC2] = RESET(0x84c, BIT(18)),
+
+ [RST_BUS_UART0] = RESET(0x90c, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x90c, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x90c, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x90c, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x90c, BIT(20)),
+
+ [RST_BUS_I2C0] = RESET(0x91c, BIT(16)),
+ [RST_BUS_I2C1] = RESET(0x91c, BIT(17)),
+ [RST_BUS_I2C2] = RESET(0x91c, BIT(18)),
+ [RST_BUS_I2C3] = RESET(0x91c, BIT(19)),
+
+ [RST_BUS_SPI0] = RESET(0x96c, BIT(16)),
+ [RST_BUS_SPI1] = RESET(0x96c, BIT(17)),
+ [RST_BUS_SPI2] = RESET(0x96c, BIT(18)),
+
+ [RST_BUS_EMAC] = RESET(0x97c, BIT(16)),
+
+ [RST_USB_PHY0] = RESET(0xa70, BIT(30)),
+
+ [RST_USB_PHY1] = RESET(0xa74, BIT(30)),
+
+ [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
+ [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)),
+ [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
+ [RST_BUS_EHCI1] = RESET(0xa8c, BIT(21)),
+ [RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
+
+ [RST_BUS_TCON_LCD] = RESET(0xb7c, BIT(16)),
+};
+
+const struct ccu_desc a100_ccu_desc = {
+ .gates = a100_gates,
+ .resets = a100_resets,
+ .num_gates = ARRAY_SIZE(a100_gates),
+ .num_resets = ARRAY_SIZE(a100_resets),
+};
diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c
index 2ef4f45dacf..e0765cbc6dc 100644
--- a/drivers/clk/sunxi/clk_sunxi.c
+++ b/drivers/clk/sunxi/clk_sunxi.c
@@ -122,6 +122,7 @@ extern const struct ccu_desc f1c100s_ccu_desc;
extern const struct ccu_desc h3_ccu_desc;
extern const struct ccu_desc h6_ccu_desc;
extern const struct ccu_desc h616_ccu_desc;
+extern const struct ccu_desc a100_ccu_desc;
extern const struct ccu_desc h6_r_ccu_desc;
extern const struct ccu_desc r40_ccu_desc;
extern const struct ccu_desc v3s_ccu_desc;
@@ -215,6 +216,10 @@ static const struct udevice_id sunxi_clk_ids[] = {
{ .compatible = "allwinner,sun50i-h616-r-ccu",
.data = (ulong)&h6_r_ccu_desc },
#endif
+#ifdef CONFIG_CLK_SUN50I_A100
+ { .compatible = "allwinner,sun50i-a100-ccu",
+ .data = (ulong)&a100_ccu_desc },
+#endif
#ifdef CONFIG_CLK_SUNIV_F1C100S
{ .compatible = "allwinner,suniv-f1c100s-ccu",
.data = (ulong)&f1c100s_ccu_desc },
diff --git a/drivers/clk/ti/clk-k3.c b/drivers/clk/ti/clk-k3.c
index bf65f573cb8..b38e559e45a 100644
--- a/drivers/clk/ti/clk-k3.c
+++ b/drivers/clk/ti/clk-k3.c
@@ -82,6 +82,8 @@ static const struct soc_attr ti_k3_soc_clk_data[] = {
.family = "J721E",
.data = &j721e_clk_platdata,
},
+#endif
+#if IS_ENABLED(CONFIG_SOC_K3_J7200)
{
.family = "J7200",
.data = &j7200_clk_platdata,
@@ -104,6 +106,10 @@ static const struct soc_attr ti_k3_soc_clk_data[] = {
.family = "J784S4",
.data = &j784s4_clk_platdata,
},
+ {
+ .family = "J742S2",
+ .data = &j784s4_clk_platdata,
+ },
#endif
{ /* sentinel */ }
};
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 9ea57911f89..657e589c286 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -16,6 +16,6 @@ ifndef CONFIG_DM_DEV_READ_INLINE
obj-$(CONFIG_OF_CONTROL) += read.o
endif
obj-$(CONFIG_$(XPL_)OF_PLATDATA) += read.o
-obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o
+obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o ofnode_graph.o
ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG
diff --git a/drivers/core/ofnode_graph.c b/drivers/core/ofnode_graph.c
new file mode 100644
index 00000000000..90c92af3258
--- /dev/null
+++ b/drivers/core/ofnode_graph.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY LOGC_DT
+
+#include <dm.h>
+#include <log.h>
+#include <dm/ofnode.h>
+#include <linux/err.h>
+
+/**
+ * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device ofnode
+ * @parent: ofnode to the device containing ports and endpoints
+ *
+ * Return: count of endpoint of this device ofnode
+ */
+unsigned int ofnode_graph_get_endpoint_count(ofnode parent)
+{
+ ofnode ports, port, endpoint;
+ unsigned int num = 0;
+
+ /* Check if ports node exists */
+ ports = ofnode_find_subnode(parent, "ports");
+ if (ofnode_valid(ports))
+ parent = ports;
+
+ ofnode_for_each_subnode(port, parent) {
+ if (!strncmp(ofnode_get_name(port), "port", 4)) {
+ /* Port node can only contain endpoints */
+ ofnode_for_each_subnode(endpoint, port)
+ num++;
+ }
+ };
+
+ log_debug("%s: detected %d endpoints\n", __func__, num);
+
+ return num++;
+}
+
+/**
+ * ofnode_graph_get_port_count() - get the number of port in a device or ports ofnode
+ * @parent: ofnode to the device or ports node
+ *
+ * Return: count of port of this device or ports node
+ */
+unsigned int ofnode_graph_get_port_count(ofnode parent)
+{
+ ofnode ports, port;
+ unsigned int num = 0;
+
+ /* Check if ports node exists */
+ ports = ofnode_find_subnode(parent, "ports");
+ if (ofnode_valid(ports))
+ parent = ports;
+
+ ofnode_for_each_subnode(port, parent)
+ if (!strncmp(ofnode_get_name(port), "port", 4))
+ num++;
+
+ log_debug("%s: detected %d ports\n", __func__, num);
+
+ return num++;
+}
+
+/**
+ * ofnode_graph_get_port_by_id() - get the port matching a given id
+ * @parent: parent ofnode
+ * @id: id of the port
+ *
+ * Return: ofnode in given port.
+ */
+ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id)
+{
+ ofnode ports, port;
+ u32 port_id;
+
+ ports = ofnode_find_subnode(parent, "ports");
+ if (!ofnode_valid(ports))
+ return ofnode_null();
+
+ /* Check ports for node with desired id */
+ ofnode_for_each_subnode(port, ports) {
+ ofnode_read_u32(port, "reg", &port_id);
+ log_debug("%s: detected port %d\n", __func__, port_id);
+ if (port_id == id)
+ return port;
+ }
+
+ return ofnode_null();
+}
+
+/**
+ * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id
+ * @parent: parent ofnode
+ * @reg_id: id of the port
+ * @id: id for the endpoint
+ *
+ * Return: ofnode in given endpoint or ofnode_null() if not found.
+ * reg and port_reg are ignored when they are -1.
+ */
+ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id)
+{
+ ofnode port, endpoint;
+ u32 ep_id;
+
+ /* get the port to work with */
+ if (reg_id < 0)
+ port = ofnode_find_subnode(parent, "port");
+ else
+ port = ofnode_graph_get_port_by_id(parent, reg_id);
+
+ if (!ofnode_valid(port)) {
+ log_debug("%s: port node is not found\n", __func__);
+ return ofnode_null();
+ }
+
+ if (id < 0)
+ return ofnode_find_subnode(port, "endpoint");
+
+ /* Check endpoints for node with desired id */
+ ofnode_for_each_subnode(endpoint, port) {
+ ofnode_read_u32(endpoint, "reg", &ep_id);
+ log_debug("%s: detected endpoint %d\n", __func__, ep_id);
+ if (ep_id == id)
+ return endpoint;
+ }
+
+ return ofnode_null();
+}
+
+/**
+ * ofnode_graph_get_remote_endpoint() - get remote endpoint node
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: Remote endpoint ofnode linked with local endpoint.
+ */
+ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint)
+{
+ /* Get remote endpoint node. */
+ return ofnode_parse_phandle(endpoint, "remote-endpoint", 0);
+}
+
+/**
+ * ofnode_graph_get_port_parent() - get port's parent node
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: device ofnode associated with endpoint
+ */
+ofnode ofnode_graph_get_port_parent(ofnode endpoint)
+{
+ ofnode port = ofnode_get_parent(endpoint);
+ ofnode parent = ofnode_get_parent(port);
+
+ /* check if we are on top level or in ports node */
+ if (!strcmp(ofnode_get_name(parent), "ports"))
+ parent = ofnode_get_parent(parent);
+
+ return parent;
+}
+
+/**
+ * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: device ofnode associated with endpoint linked to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint)
+{
+ ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint);
+ if (!ofnode_valid(remote_endpoint)) {
+ log_debug("%s: remote endpoint is not found\n", __func__);
+ return ofnode_null();
+ }
+
+ return ofnode_graph_get_port_parent(remote_endpoint);
+}
+
+/**
+ * ofnode_graph_get_remote_port() - get remote port ofnode
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: port ofnode associated with remote endpoint node linked
+ * to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_port(ofnode endpoint)
+{
+ ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint);
+ if (!ofnode_valid(remote_endpoint)) {
+ log_debug("%s: remote endpoint is not found\n", __func__);
+ return ofnode_null();
+ }
+
+ return ofnode_get_parent(remote_endpoint);
+}
+
+/**
+ * ofnode_graph_get_remote_node() - get remote parent ofnode for given port/endpoint
+ * @parent: parent ofnode containing graph port/endpoint
+ * @port: identifier (value of reg property) of the parent port ofnode
+ * @endpoint: identifier (value of reg property) of the endpoint ofnode
+ *
+ * Return: device ofnode associated with endpoint linked to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_node(ofnode parent, int port, int endpoint)
+{
+ ofnode endpoint_ofnode;
+
+ endpoint_ofnode = ofnode_graph_get_endpoint_by_regs(parent, port, endpoint);
+ if (!ofnode_valid(endpoint_ofnode)) {
+ log_debug("%s: endpoint is not found\n", __func__);
+ return ofnode_null();
+ }
+
+ return ofnode_graph_get_remote_port_parent(endpoint_ofnode);
+}
diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c
index 53d31b3c0bf..4e1eccaa5b0 100644
--- a/drivers/cpu/imx8_cpu.c
+++ b/drivers/cpu/imx8_cpu.c
@@ -35,11 +35,49 @@ static const char *get_imx_type_str(u32 imxtype)
{
switch (imxtype) {
case MXC_CPU_IMX8MM:
- return "8MM";
+ return "8MMQ"; /* Quad-core version of the imx8mm */
+ case MXC_CPU_IMX8MML:
+ return "8MMQL"; /* Quad-core Lite version of the imx8mm */
+ case MXC_CPU_IMX8MMD:
+ return "8MMD"; /* Dual-core version of the imx8mm */
+ case MXC_CPU_IMX8MMDL:
+ return "8MMDL"; /* Dual-core Lite version of the imx8mm */
+ case MXC_CPU_IMX8MMS:
+ return "8MMS"; /* Single-core version of the imx8mm */
+ case MXC_CPU_IMX8MMSL:
+ return "8MMSL"; /* Single-core Lite version of the imx8mm */
case MXC_CPU_IMX8MN:
- return "8MN";
+ return "8MNano Quad"; /* Quad-core version */
+ case MXC_CPU_IMX8MND:
+ return "8MNano Dual"; /* Dual-core version */
+ case MXC_CPU_IMX8MNS:
+ return "8MNano Solo"; /* Single-core version */
+ case MXC_CPU_IMX8MNL:
+ return "8MNano QuadLite"; /* Quad-core Lite version */
+ case MXC_CPU_IMX8MNDL:
+ return "8MNano DualLite"; /* Dual-core Lite version */
+ case MXC_CPU_IMX8MNSL:
+ return "8MNano SoloLite";/* Single-core Lite version of the imx8mn */
+ case MXC_CPU_IMX8MNUQ:
+ return "8MNano UltraLite Quad";/* Quad-core UltraLite version of the imx8mn */
+ case MXC_CPU_IMX8MNUD:
+ return "8MNano UltraLite Dual";/* Dual-core UltraLite version of the imx8mn */
+ case MXC_CPU_IMX8MNUS:
+ return "8MNano UltraLite Solo";/* Single-core UltraLite version of the imx8mn */
case MXC_CPU_IMX8MP:
- return "8MP";
+ return "8MP[8]"; /* Quad-core version of the imx8mp */
+ case MXC_CPU_IMX8MPD:
+ return "8MP Dual[3]"; /* Dual-core version of the imx8mp */
+ case MXC_CPU_IMX8MPL:
+ return "8MP Lite[4]"; /* Quad-core Lite version of the imx8mp */
+ case MXC_CPU_IMX8MP6:
+ return "8MP[6]"; /* Quad-core version of the imx8mp, NPU fused */
+ case MXC_CPU_IMX8MQ:
+ return "8MQ"; /* Quad-core version of the imx8mq */
+ case MXC_CPU_IMX8MQL:
+ return "8MQLite"; /* Quad-core Lite version of the imx8mq */
+ case MXC_CPU_IMX8MD:
+ return "8MD"; /* Dual-core version of the imx8mq */
case MXC_CPU_IMX8QXP:
case MXC_CPU_IMX8QXP_A0:
return "8QXP";
@@ -177,19 +215,19 @@ static int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size)
ret = snprintf(buf, size, "NXP i.MX%s Rev%s %s at %u MHz",
plat->type, plat->rev, plat->name, plat->freq_mhz);
- if (IS_ENABLED(CONFIG_IMX9)) {
+ if (IS_ENABLED(CONFIG_IMX_TMU)) {
switch (get_cpu_temp_grade(&minc, &maxc)) {
case TEMP_AUTOMOTIVE:
- grade = "Automotive temperature grade ";
+ grade = "Automotive temperature grade";
break;
case TEMP_INDUSTRIAL:
- grade = "Industrial temperature grade ";
+ grade = "Industrial temperature grade";
break;
case TEMP_EXTCOMMERCIAL:
- grade = "Extended Consumer temperature grade ";
+ grade = "Extended Consumer temperature grade";
break;
default:
- grade = "Consumer temperature grade ";
+ grade = "Consumer temperature grade";
break;
}
diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
index c1d6a6b6c59..b19f3601813 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -4,7 +4,7 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
-# Copyright (C) 2014-2021 Altera Corporation <www.altera.com>
+# Copyright (C) 2014-2025 Altera Corporation <www.altera.com>
ifdef CONFIG_$(XPL_)ALTERA_SDRAM
obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o
@@ -12,4 +12,5 @@ obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o
obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o
obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += sdram_soc64.o sdram_agilex.o
obj-$(CONFIG_TARGET_SOCFPGA_N5X) += sdram_soc64.o sdram_n5x.o
+obj-$(CONFIG_TARGET_SOCFPGA_AGILEX5) += sdram_soc64.o sdram_agilex5.o iossm_mailbox.o
endif
diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c
new file mode 100644
index 00000000000..db9435db657
--- /dev/null
+++ b/drivers/ddr/altera/iossm_mailbox.c
@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ *
+ */
+
+#include <hang.h>
+#include <string.h>
+#include <wait_bit.h>
+#include <asm/arch/base_addr_soc64.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include "iossm_mailbox.h"
+
+#define TIMEOUT_120000MS 120000
+#define TIMEOUT_60000MS 60000
+#define TIMEOUT TIMEOUT_120000MS
+#define IOSSM_STATUS_CAL_SUCCESS BIT(0)
+#define IOSSM_STATUS_CAL_FAIL BIT(1)
+#define IOSSM_STATUS_CAL_BUSY BIT(2)
+#define IOSSM_STATUS_COMMAND_RESPONSE_READY BIT(0)
+#define IOSSM_CMD_RESPONSE_STATUS_OFFSET 0x45C
+#define IOSSM_CMD_RESPONSE_DATA_0_OFFSET 0x458
+#define IOSSM_CMD_RESPONSE_DATA_1_OFFSET 0x454
+#define IOSSM_CMD_RESPONSE_DATA_2_OFFSET 0x450
+#define IOSSM_CMD_REQ_OFFSET 0x43C
+#define IOSSM_CMD_PARAM_0_OFFSET 0x438
+#define IOSSM_CMD_PARAM_1_OFFSET 0x434
+#define IOSSM_CMD_PARAM_2_OFFSET 0x430
+#define IOSSM_CMD_PARAM_3_OFFSET 0x42C
+#define IOSSM_CMD_PARAM_4_OFFSET 0x428
+#define IOSSM_CMD_PARAM_5_OFFSET 0x424
+#define IOSSM_CMD_PARAM_6_OFFSET 0x420
+#define IOSSM_CMD_RESPONSE_DATA_SHORT_MASK GENMASK(31, 16)
+#define IOSSM_CMD_RESPONSE_DATA_SHORT(n) FIELD_GET(IOSSM_CMD_RESPONSE_DATA_SHORT_MASK, n)
+#define IOSSM_STATUS_CMD_RESPONSE_ERROR_MASK GENMASK(7, 5)
+#define IOSSM_STATUS_CMD_RESPONSE_ERROR(n) FIELD_GET(IOSSM_STATUS_CMD_RESPONSE_ERROR_MASK, n)
+#define IOSSM_STATUS_GENERAL_ERROR_MASK GENMASK(4, 1)
+#define IOSSM_STATUS_GENERAL_ERROR(n) FIELD_GET(IOSSM_STATUS_GENERAL_ERROR_MASK, n)
+
+/* Offset of Mailbox Read-only Registers */
+#define IOSSM_MAILBOX_HEADER_OFFSET 0x0
+#define IOSSM_MEM_INTF_INFO_0_OFFSET 0X200
+#define IOSSM_MEM_INTF_INFO_1_OFFSET 0x280
+#define IOSSM_MEM_TECHNOLOGY_INTF0_OFFSET 0x210
+#define IOSSM_MEM_TECHNOLOGY_INTF1_OFFSET 0x290
+#define IOSSM_MEM_WIDTH_INFO_INTF0_OFFSET 0x230
+#define IOSSM_MEM_WIDTH_INFO_INTF1_OFFSET 0x2B0
+#define IOSSM_MEM_TOTAL_CAPACITY_INTF0_OFFSET 0x234
+#define IOSSM_MEM_TOTAL_CAPACITY_INTF1_OFFSET 0x2B4
+#define IOSSM_ECC_ENABLE_INTF0_OFFSET 0x240
+#define IOSSM_ECC_ENABLE_INTF1_OFFSET 0x2C0
+#define IOSSM_ECC_SCRUB_STATUS_INTF0_OFFSET 0x244
+#define IOSSM_ECC_SCRUB_STATUS_INTF1_OFFSET 0x2C4
+#define IOSSM_LP_MODE_INTF0_OFFSET 0x250
+#define IOSSM_LP_MODE_INTF1_OFFSET 0x2D0
+#define IOSSM_MEM_INIT_STATUS_INTF0_OFFSET 0x260
+#define IOSSM_MEM_INIT_STATUS_INTF1_OFFSET 0x2E0
+#define IOSSM_BIST_STATUS_INTF0_OFFSET 0x264
+#define IOSSM_BIST_STATUS_INTF1_OFFSET 0x2E4
+#define IOSSM_ECC_ERR_STATUS_OFFSET 0x300
+#define IOSSM_ECC_ERR_DATA_START_OFFSET 0x310
+#define IOSSM_STATUS_OFFSET 0x400
+#define IOSSM_STATUS_CAL_INTF0_OFFSET 0x404
+#define IOSSM_STATUS_CAL_INTF1_OFFSET 0x408
+
+#define ECC_INTSTATUS_SERR SOCFPGA_SYSMGR_ADDRESS + 0x9C
+#define ECC_INISTATUS_DERR SOCFPGA_SYSMGR_ADDRESS + 0xA0
+#define DDR_CSR_CLKGEN_LOCKED_IO96B0_MASK BIT(16)
+#define DDR_CSR_CLKGEN_LOCKED_IO96B1_MASK BIT(17)
+
+/* offset info of GET_MEM_INTF_INFO */
+#define INTF_IP_TYPE_MASK GENMASK(31, 29)
+#define INTF_INSTANCE_ID_MASK GENMASK(28, 24)
+
+/* offset info of GET_MEM_CAL_STATUS */
+#define INTF_UNUSED 0x0
+#define INTF_MEM_CAL_STATUS_SUCCESS 0x1
+#define INTF_MEM_CAL_STATUS_FAIL 0x2
+#define INTF_MEM_CAL_STATUS_ONGOING 0x4
+
+/* offset info of MEM_TECHNOLOGY_INTF */
+#define INTF_DDR_TYPE_MASK GENMASK(2, 0)
+
+/* offset info of MEM_TOTAL_CAPACITY_INTF */
+#define INTF_CAPACITY_GBITS_MASK GENMASK(7, 0)
+
+/* offset info of ECC_ENABLE_INTF */
+#define INTF_ECC_ENABLE_TYPE_MASK GENMASK(1, 0)
+
+/* cmd opcode BIST_MEM_INIT_START, BIST performed on full memory address range */
+#define BIST_FULL_MEM BIT(6)
+
+/* offset info of ECC_ENABLE_INTF */
+#define INTF_BIST_STATUS_MASK BIT(0)
+
+/* offset info of ECC_ERR_STATUS */
+#define ECC_ERR_COUNTER_MASK GENMASK(15, 0)
+
+/* offset info of ECC_ERR_DATA */
+#define ECC_ERR_IP_TYPE_MASK GENMASK(24, 22)
+#define ECC_ERR_INSTANCE_ID_MASK GENMASK(21, 17)
+#define ECC_ERR_SOURCE_ID_MASK GENMASK(16, 10)
+#define ECC_ERR_TYPE_MASK GENMASK(9, 6)
+#define ECC_ERR_ADDR_UPPER_MASK GENMASK(5, 0)
+#define ECC_ERR_ADDR_LOWER_MASK GENMASK(31, 0)
+
+#define MAX_ECC_ERR_INFO_COUNT 16
+
+#define IO96B_MB_REQ_SETUP(v, w, x, y, z) \
+ usr_req.ip_type = v; \
+ usr_req.ip_id = w; \
+ usr_req.usr_cmd_type = x; \
+ usr_req.usr_cmd_opcode = y; \
+ usr_req.cmd_param[0] = z; \
+ for (n = 1; n < NUM_CMD_PARAM; n++) \
+ usr_req.cmd_param[n] = 0
+#define MAX_RETRY_COUNT 3
+#define NUM_CMD_RESPONSE_DATA 3
+
+#define IO96B0_PLL_A_MASK BIT(0)
+#define IO96B0_PLL_B_MASK BIT(1)
+#define IO96B1_PLL_A_MASK BIT(2)
+#define IO96B1_PLL_B_MASK BIT(3)
+
+/* supported DDR type list */
+static const char *ddr_type_list[7] = {
+ "DDR4", "DDR5", "DDR5_RDIMM", "LPDDR4", "LPDDR5", "QDRIV", "UNKNOWN"
+};
+
+/* Define an enumeration for ECC error types */
+enum ecc_error_type {
+ SINGLE_BIT_ERROR = 0, /* 0b0000 */
+ MULTIPLE_SINGLE_BIT_ERRORS = 1, /* 0b0001 */
+ DOUBLE_BIT_ERROR = 2, /* 0b0010 */
+ MULTIPLE_DOUBLE_BIT_ERRORS = 3, /* 0b0011 */
+ SINGLE_BIT_ERROR_SCRUBBING = 8, /* 0b1000 */
+ WRITE_LINK_SINGLE_BIT_ERROR = 9, /* 0b1001 */
+ WRITE_LINK_DOUBLE_BIT_ERROR = 10, /* 0b1010 */
+ READ_LINK_SINGLE_BIT_ERROR = 11, /* 0b1011 */
+ READ_LINK_DOUBLE_BIT_ERROR = 12, /* 0b1100 */
+ READ_MODIFY_WRITE_DOUBLE_BIT_ERROR = 13 /* 0b1101 */
+};
+
+/*
+ * ecc error info
+ *
+ * @ip_type: The IP type of the interface that produced the ECC interrupt.
+ * @instance_id: The instance ID of the interface that produced the ECC interrupt.
+ * @ecc_err_source_id: The source ID associated with the ECC event.
+ * @ecc_err_type: The ECC error type of the ECC event.
+ * @ecc_err_addr_upper: Upper 6 bits of the address of the read data that caused the ECC event.
+ * @ecc_err_addr_lower: Lower 32 bits of the address of the read data that caused the ECC event.
+ */
+struct ecc_err_info {
+ u32 ip_type;
+ u32 instance_id;
+ u32 source_id;
+ enum ecc_error_type err_type;
+ u32 addr_upper;
+ u32 addr_lower;
+};
+
+static int is_ddr_csr_clkgen_locked(u8 io96b_pll)
+{
+ int ret = 0;
+ const char *pll_names[MAX_IO96B_SUPPORTED][2] = {
+ {"io96b_0 clkgenA", "io96b_0 clkgenB"},
+ {"io96b_1 clkgenA", "io96b_1 clkgenB"}
+ };
+ u32 masks[MAX_IO96B_SUPPORTED][2] = {
+ {IO96B0_PLL_A_MASK, IO96B0_PLL_B_MASK},
+ {IO96B1_PLL_A_MASK, IO96B1_PLL_B_MASK}
+ };
+ u32 lock_masks[MAX_IO96B_SUPPORTED] = {
+ DDR_CSR_CLKGEN_LOCKED_IO96B0_MASK,
+ DDR_CSR_CLKGEN_LOCKED_IO96B1_MASK
+ };
+
+ for (int i = 0; i < MAX_IO96B_SUPPORTED ; i++) {
+ /* Check for PLL_A */
+ if (io96b_pll & masks[i][0]) {
+ ret = wait_for_bit_le32((const void *)(ECC_INTSTATUS_SERR), lock_masks[i],
+ true, TIMEOUT, false);
+
+ if (ret) {
+ debug("%s: ddr csr %s locked is timeout\n",
+ __func__, pll_names[i][0]);
+ goto err;
+ } else {
+ debug("%s: ddr csr %s is successfully locked\n",
+ __func__, pll_names[i][0]);
+ }
+ }
+
+ /* Check for PLL_B */
+ if (io96b_pll & masks[i][1]) {
+ ret = wait_for_bit_le32((const void *)(ECC_INISTATUS_DERR), lock_masks[i],
+ true, TIMEOUT, false);
+
+ if (ret) {
+ debug("%s: ddr csr %s locked is timeout\n",
+ __func__, pll_names[i][1]);
+ goto err;
+ } else {
+ debug("%s: ddr csr %s is successfully locked\n",
+ __func__, pll_names[i][1]);
+ }
+ }
+ }
+
+err:
+ return ret;
+}
+
+/*
+ * Mailbox request function
+ * This function will send the request to IOSSM mailbox and wait for response return
+ *
+ * @io96b_csr_addr: CSR address for the target IO96B
+ * @req: Structure contain command request for IOSSM mailbox command
+ * @resp_data_len: User desire extra response data fields other than
+ * CMD_RESPONSE_DATA_SHORT field on CMD_RESPONSE_STATUS
+ * @resp: Structure contain responses returned from the requested IOSSM
+ * mailbox command
+ */
+int io96b_mb_req(phys_addr_t io96b_csr_addr, struct io96b_mb_req req,
+ u32 resp_data_len, struct io96b_mb_resp *resp)
+{
+ int i, ret;
+ u32 cmd_req;
+
+ if (!resp) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Zero initialization for responses */
+ resp->cmd_resp_status = 0;
+
+ /* Ensure CMD_REQ is cleared before write any command request */
+ ret = wait_for_bit_le32((const void *)(io96b_csr_addr + IOSSM_CMD_REQ_OFFSET),
+ GENMASK(31, 0), false, TIMEOUT, false);
+ if (ret) {
+ printf("%s: Timeout of waiting DDR mailbox ready to be functioned!\n",
+ __func__);
+ goto err;
+ }
+
+ /* Write CMD_PARAM_* */
+ for (i = 0; i < NUM_CMD_PARAM ; i++) {
+ switch (i) {
+ case 0:
+ if (req.cmd_param[0])
+ writel(req.cmd_param[0], io96b_csr_addr + IOSSM_CMD_PARAM_0_OFFSET);
+ break;
+ case 1:
+ if (req.cmd_param[1])
+ writel(req.cmd_param[1], io96b_csr_addr + IOSSM_CMD_PARAM_1_OFFSET);
+ break;
+ case 2:
+ if (req.cmd_param[2])
+ writel(req.cmd_param[2], io96b_csr_addr + IOSSM_CMD_PARAM_2_OFFSET);
+ break;
+ case 3:
+ if (req.cmd_param[3])
+ writel(req.cmd_param[3], io96b_csr_addr + IOSSM_CMD_PARAM_3_OFFSET);
+ break;
+ case 4:
+ if (req.cmd_param[4])
+ writel(req.cmd_param[4], io96b_csr_addr + IOSSM_CMD_PARAM_4_OFFSET);
+ break;
+ case 5:
+ if (req.cmd_param[5])
+ writel(req.cmd_param[5], io96b_csr_addr + IOSSM_CMD_PARAM_5_OFFSET);
+ break;
+ case 6:
+ if (req.cmd_param[6])
+ writel(req.cmd_param[6], io96b_csr_addr + IOSSM_CMD_PARAM_6_OFFSET);
+ break;
+ }
+ }
+
+ /* Write CMD_REQ (IP_TYPE, IP_INSTANCE_ID, CMD_TYPE and CMD_OPCODE) */
+ cmd_req = FIELD_PREP(CMD_TARGET_IP_TYPE_MASK, req.ip_type) |
+ FIELD_PREP(CMD_TARGET_IP_INSTANCE_ID_MASK, req.ip_id) |
+ FIELD_PREP(CMD_TYPE_MASK, req.usr_cmd_type) |
+ FIELD_PREP(CMD_OPCODE_MASK, req.usr_cmd_opcode);
+ writel(cmd_req, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+
+ debug("%s: Write 0x%x to IOSSM_CMD_REQ_OFFSET 0x%llx\n", __func__, cmd_req,
+ io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+
+ /* Read CMD_RESPONSE_READY in CMD_RESPONSE_STATUS */
+ ret = wait_for_bit_le32((const void *)(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET),
+ IOSSM_STATUS_COMMAND_RESPONSE_READY, true, TIMEOUT, false);
+
+ /* read CMD_RESPONSE_STATUS */
+ resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+
+ debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__, io96b_csr_addr +
+ IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+ if (ret) {
+ printf("%s: CMD_RESPONSE ERROR:\n", __func__);
+
+ printf("%s: STATUS_GENERAL_ERROR: 0x%lx\n", __func__,
+ IOSSM_STATUS_GENERAL_ERROR(resp->cmd_resp_status));
+ printf("%s: STATUS_CMD_RESPONSE_ERROR: 0x%lx\n", __func__,
+ IOSSM_STATUS_CMD_RESPONSE_ERROR(resp->cmd_resp_status));
+ goto err;
+ }
+
+ /* read CMD_RESPONSE_DATA_* */
+ for (i = 0; i < resp_data_len; i++) {
+ switch (i) {
+ case 0:
+ resp->cmd_resp_data[i] =
+ readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET);
+
+ debug("%s: IOSSM_CMD_RESPONSE_DATA_0_OFFSET 0x%llx: 0x%x\n", __func__,
+ io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET,
+ resp->cmd_resp_data[i]);
+ break;
+ case 1:
+ resp->cmd_resp_data[i] =
+ readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET);
+
+ debug("%s: IOSSM_CMD_RESPONSE_DATA_1_OFFSET 0x%llx: 0x%x\n", __func__,
+ io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET,
+ resp->cmd_resp_data[i]);
+ break;
+ case 2:
+ resp->cmd_resp_data[i] =
+ readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET);
+
+ debug("%s: IOSSM_CMD_RESPONSE_DATA_2_OFFSET 0x%llx: 0x%x\n", __func__,
+ io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET,
+ resp->cmd_resp_data[i]);
+ break;
+ default:
+ resp->cmd_resp_data[i] = 0;
+ printf("%s: Invalid response data\n", __func__);
+ }
+ }
+
+ /* write CMD_RESPONSE_READY = 0 */
+ clrbits_le32((u32 *)(uintptr_t)(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET),
+ IOSSM_STATUS_COMMAND_RESPONSE_READY);
+
+ debug("%s: After clear CMD_RESPONSE_READY bit: 0x%llx: 0x%x\n", __func__,
+ io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET,
+ readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET));
+
+err:
+ return ret;
+}
+
+/*
+ * Initial function to be called to set memory interface IP type and instance ID
+ * IP type and instance ID need to be determined before sending mailbox command
+ */
+void io96b_mb_init(struct io96b_info *io96b_ctrl)
+{
+ int i, j;
+ u32 mem_intf_info_0, mem_intf_info_1;
+
+ debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance);
+
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ debug("%s: get memory interface IO96B %d\n", __func__, i);
+ io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface = 0;
+
+ mem_intf_info_0 = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ IOSSM_MEM_INTF_INFO_0_OFFSET);
+ mem_intf_info_1 = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ IOSSM_MEM_INTF_INFO_1_OFFSET);
+
+ io96b_ctrl->io96b[i].mb_ctrl.ip_type[0] = FIELD_GET(INTF_IP_TYPE_MASK,
+ mem_intf_info_0);
+ io96b_ctrl->io96b[i].mb_ctrl.ip_id[0] = FIELD_GET(INTF_INSTANCE_ID_MASK,
+ mem_intf_info_0);
+ io96b_ctrl->io96b[i].mb_ctrl.ip_type[1] = FIELD_GET(INTF_IP_TYPE_MASK,
+ mem_intf_info_1);
+ io96b_ctrl->io96b[i].mb_ctrl.ip_id[1] = FIELD_GET(INTF_INSTANCE_ID_MASK,
+ mem_intf_info_1);
+
+ for (j = 0; j < MAX_MEM_INTERFACE_SUPPORTED; j++) {
+ if (io96b_ctrl->io96b[i].mb_ctrl.ip_type[j]) {
+ io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface++;
+
+ debug("%s: IO96B %d mem_interface %d: ip_type_ret: 0x%x\n",
+ __func__, i, j, io96b_ctrl->io96b[i].mb_ctrl.ip_type[j]);
+ debug("%s: IO96B %d mem_interface %d: instance_id_ret: 0x%x\n",
+ __func__, i, j, io96b_ctrl->io96b[i].mb_ctrl.ip_id[j]);
+ }
+ }
+
+ debug("%s: IO96B %d: num_mem_interface: 0x%x\n", __func__, i,
+ io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface);
+ }
+}
+
+int io96b_cal_status(phys_addr_t addr)
+{
+ u32 cal_success, cal_fail;
+ phys_addr_t status_addr = addr + IOSSM_STATUS_OFFSET;
+ u32 start = get_timer(0);
+
+ do {
+ if (get_timer(start) > TIMEOUT_60000MS) {
+ printf("%s: SDRAM calibration for IO96B instance 0x%llx timeout!\n",
+ __func__, status_addr);
+ hang();
+ }
+
+ udelay(1);
+ schedule();
+
+ /* Polling until getting any calibration result */
+ cal_success = readl(status_addr) & IOSSM_STATUS_CAL_SUCCESS;
+ cal_fail = readl(status_addr) & IOSSM_STATUS_CAL_FAIL;
+ } while (!cal_success && !cal_fail);
+
+ debug("%s: Calibration for IO96B instance 0x%llx done at %ld msec!\n",
+ __func__, status_addr, get_timer(start));
+
+ if (cal_success && !cal_fail)
+ return 0;
+ else
+ return -EPERM;
+}
+
+void init_mem_cal(struct io96b_info *io96b_ctrl)
+{
+ int count, i, ret;
+
+ /* Initialize overall calibration status */
+ io96b_ctrl->overall_cal_status = false;
+
+ if (io96b_ctrl->ckgen_lock) {
+ ret = is_ddr_csr_clkgen_locked(io96b_ctrl->io96b_pll);
+ if (ret) {
+ printf("%s: iossm IO96B ckgena_lock is not locked\n", __func__);
+ hang();
+ }
+ }
+
+ /* Check initial calibration status for the assigned IO96B */
+ count = 0;
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ ret = io96b_cal_status(io96b_ctrl->io96b[i].io96b_csr_addr);
+ if (ret) {
+ io96b_ctrl->io96b[i].cal_status = false;
+
+ printf("%s: Initial DDR calibration IO96B_%d failed %d\n", __func__,
+ i, ret);
+
+ hang();
+ }
+
+ io96b_ctrl->io96b[i].cal_status = true;
+
+ printf("%s: Initial DDR calibration IO96B_%d succeed\n", __func__, i);
+
+ count++;
+ }
+
+ if (count == io96b_ctrl->num_instance)
+ io96b_ctrl->overall_cal_status = true;
+}
+
+int get_mem_technology(struct io96b_info *io96b_ctrl)
+{
+ int i, j, ret = 0;
+ u32 mem_technology_intf;
+ u8 ddr_type_ret;
+
+ u32 mem_technology_intf_offset[MAX_MEM_INTERFACE_SUPPORTED] = {
+ IOSSM_MEM_TECHNOLOGY_INTF0_OFFSET,
+ IOSSM_MEM_TECHNOLOGY_INTF1_OFFSET
+ };
+
+ /* Initialize ddr type */
+ io96b_ctrl->ddr_type = ddr_type_list[6];
+
+ /* Get and ensure all memory interface(s) same DDR type */
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+ mem_technology_intf = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ mem_technology_intf_offset[j]);
+
+ ddr_type_ret = FIELD_GET(INTF_DDR_TYPE_MASK, mem_technology_intf);
+
+ if (!strcmp(io96b_ctrl->ddr_type, "UNKNOWN"))
+ io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret];
+
+ if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) {
+ printf("%s: Mismatch DDR type on IO96B_%d\n", __func__, i);
+
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+ }
+
+err:
+ return ret;
+}
+
+int get_mem_width_info(struct io96b_info *io96b_ctrl)
+{
+ int i, j, ret = 0;
+ u32 mem_width_info;
+ u16 memory_size, total_memory_size = 0;
+
+ u32 mem_total_capacity_intf_offset[MAX_MEM_INTERFACE_SUPPORTED] = {
+ IOSSM_MEM_TOTAL_CAPACITY_INTF0_OFFSET,
+ IOSSM_MEM_TOTAL_CAPACITY_INTF1_OFFSET
+ };
+
+ /* Get all memory interface(s) total memory size on all instance(s) */
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ memory_size = 0;
+ for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+ mem_width_info = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ mem_total_capacity_intf_offset[j]);
+
+ memory_size = memory_size +
+ FIELD_GET(INTF_CAPACITY_GBITS_MASK, mem_width_info);
+ }
+
+ if (!memory_size) {
+ printf("%s: Failed to get valid memory size\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ io96b_ctrl->io96b[i].size = memory_size;
+
+ total_memory_size = total_memory_size + memory_size;
+ }
+
+ if (!total_memory_size) {
+ printf("%s: Failed to get valid memory size\n", __func__);
+ ret = -EINVAL;
+ }
+
+ io96b_ctrl->overall_size = total_memory_size;
+
+err:
+ return ret;
+}
+
+int ecc_enable_status(struct io96b_info *io96b_ctrl)
+{
+ int i, j, ret = 0;
+ u32 ecc_enable_intf;
+ bool ecc_stat, ecc_stat_set = false;
+
+ u32 ecc_enable_intf_offset[MAX_MEM_INTERFACE_SUPPORTED] = {
+ IOSSM_ECC_ENABLE_INTF0_OFFSET,
+ IOSSM_ECC_ENABLE_INTF1_OFFSET
+ };
+
+ /* Initialize ECC status */
+ io96b_ctrl->ecc_status = false;
+
+ /* Get and ensure all memory interface(s) same ECC status */
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+ ecc_enable_intf = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ ecc_enable_intf_offset[j]);
+
+ ecc_stat = (FIELD_GET(INTF_ECC_ENABLE_TYPE_MASK, ecc_enable_intf)
+ == 0) ? false : true;
+
+ if (!ecc_stat_set) {
+ io96b_ctrl->ecc_status = ecc_stat;
+ ecc_stat_set = true;
+ }
+
+ if (ecc_stat != io96b_ctrl->ecc_status) {
+ printf("%s: Mismatch DDR ECC status on IO96B_%d\n", __func__, i);
+
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+ }
+
+ debug("%s: ECC enable status: %d\n", __func__, io96b_ctrl->ecc_status);
+
+err:
+ return ret;
+}
+
+bool is_double_bit_error(enum ecc_error_type err_type)
+{
+ switch (err_type) {
+ case DOUBLE_BIT_ERROR:
+ case MULTIPLE_DOUBLE_BIT_ERRORS:
+ case WRITE_LINK_DOUBLE_BIT_ERROR:
+ case READ_LINK_DOUBLE_BIT_ERROR:
+ case READ_MODIFY_WRITE_DOUBLE_BIT_ERROR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool ecc_interrupt_status(struct io96b_info *io96b_ctrl)
+{
+ int i, j;
+ u32 ecc_err_status;
+ u16 ecc_err_counter;
+ bool ecc_error_flag = false;
+
+ /* Get ECC double-bit error status */
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ ecc_err_status = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ IOSSM_ECC_ERR_STATUS_OFFSET);
+ ecc_err_counter = FIELD_GET(ECC_ERR_COUNTER_MASK, ecc_err_status);
+ debug("%s: ECC error number detected on IO96B_%d: %d\n",
+ __func__, i, ecc_err_counter);
+
+ if (ecc_err_counter != 0) {
+ phys_addr_t address;
+ u32 ecc_err_data;
+ struct ecc_err_info err_info;
+
+ address = io96b_ctrl->io96b[i].io96b_csr_addr +
+ IOSSM_ECC_ERR_DATA_START_OFFSET;
+
+ for (j = 0; j < ecc_err_counter && j < MAX_ECC_ERR_INFO_COUNT; j++) {
+ ecc_err_data = readl(address);
+ err_info.err_type = FIELD_GET(ECC_ERR_TYPE_MASK,
+ ecc_err_data);
+ err_info.ip_type = FIELD_GET(ECC_ERR_IP_TYPE_MASK,
+ ecc_err_data);
+ err_info.instance_id = FIELD_GET(ECC_ERR_INSTANCE_ID_MASK,
+ ecc_err_data);
+ err_info.source_id = FIELD_GET(ECC_ERR_SOURCE_ID_MASK,
+ ecc_err_data);
+ err_info.addr_upper = FIELD_GET(ECC_ERR_ADDR_UPPER_MASK,
+ ecc_err_data);
+ err_info.addr_lower = readl(address + sizeof(u32));
+
+ debug("%s: ECC double-bit error detected on IO96B_%d:\n",
+ __func__, i);
+ debug("- error info address :0x%llx\n", address);
+ debug("- error ip type: %d\n", err_info.ip_type);
+ debug("- error instance id: %d\n", err_info.instance_id);
+ debug("- error source id: %d\n", err_info.source_id);
+ debug("- error type: %d\n", err_info.err_type);
+ debug("- error address upper: 0x%x\n", err_info.addr_upper);
+ debug("- error address lower: 0x%x\n", err_info.addr_lower);
+
+ if (is_double_bit_error(err_info.err_type)) {
+ if (!ecc_error_flag)
+ ecc_error_flag = true;
+ }
+
+ address += sizeof(u32) * 2;
+ }
+ }
+ }
+
+ if (ecc_error_flag)
+ printf("\n%s: ECC double-bit error detected!\n", __func__);
+
+ return ecc_error_flag;
+}
+
+int bist_mem_init_start(struct io96b_info *io96b_ctrl)
+{
+ struct io96b_mb_req usr_req;
+ struct io96b_mb_resp usr_resp;
+ int i, j, n, ret = 0;
+ bool bist_start, bist_success;
+ u32 mem_init_status_intf, start;
+
+ u32 mem_init_status_offset[MAX_MEM_INTERFACE_SUPPORTED] = {
+ IOSSM_MEM_INIT_STATUS_INTF0_OFFSET,
+ IOSSM_MEM_INIT_STATUS_INTF1_OFFSET
+ };
+
+ /* Full memory initialization BIST performed on all memory interface(s) */
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+ bist_start = false;
+ bist_success = false;
+
+ /* Start memory initialization BIST on full memory address */
+ IO96B_MB_REQ_SETUP(io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+ io96b_ctrl->io96b[i].mb_ctrl.ip_id[j],
+ CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START,
+ BIST_FULL_MEM);
+
+ ret = io96b_mb_req(io96b_ctrl->io96b[i].io96b_csr_addr,
+ usr_req, 0, &usr_resp);
+ if (ret)
+ goto err;
+
+ bist_start = IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+ & BIT(0);
+
+ if (!bist_start) {
+ printf("%s: Failed to initialize memory on IO96B_%d\n", __func__,
+ i);
+ printf("%s: BIST_MEM_INIT_START Error code 0x%lx\n", __func__,
+ IOSSM_STATUS_CMD_RESPONSE_ERROR(usr_resp.cmd_resp_status));
+
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Polling for the initiated memory initialization BIST status */
+ start = get_timer(0);
+ while (!bist_success) {
+ udelay(1);
+
+ mem_init_status_intf = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+ mem_init_status_offset[j]);
+
+ bist_success = FIELD_GET(INTF_BIST_STATUS_MASK,
+ mem_init_status_intf);
+
+ if (!bist_success && (get_timer(start) > TIMEOUT)) {
+ printf("%s: Timeout initialize memory on IO96B_%d\n",
+ __func__, i);
+ printf("%s: BIST_MEM_INIT_STATUS Error code 0x%lx\n",
+ __func__,
+ IOSSM_STATUS_CMD_RESPONSE_ERROR(usr_resp.cmd_resp_status));
+
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+ }
+ }
+
+ debug("%s: Memory initialized successfully on IO96B_%d\n", __func__, i);
+ }
+
+err:
+ return ret;
+}
diff --git a/drivers/ddr/altera/iossm_mailbox.h b/drivers/ddr/altera/iossm_mailbox.h
new file mode 100644
index 00000000000..6f794781d30
--- /dev/null
+++ b/drivers/ddr/altera/iossm_mailbox.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ *
+ */
+
+#define MAX_IO96B_SUPPORTED 2
+#define MAX_MEM_INTERFACE_SUPPORTED 2
+#define NUM_CMD_RESPONSE_DATA 3
+#define NUM_CMD_PARAM 7
+
+/* supported mailbox command type */
+enum iossm_mailbox_cmd_type {
+ CMD_NOP,
+ CMD_GET_SYS_INFO,
+ CMD_GET_MEM_INFO,
+ CMD_GET_MEM_CAL_INFO,
+ CMD_TRIG_CONTROLLER_OP,
+ CMD_TRIG_MEM_CAL_OP
+};
+
+/* supported mailbox command opcode */
+enum iossm_mailbox_cmd_opcode {
+ ECC_ENABLE_SET = 0x0101,
+ ECC_INTERRUPT_MASK = 0x0105,
+ ECC_WRITEBACK_ENABLE = 0x0106,
+ ECC_INJECT_ERROR = 0x0109,
+ ECC_SCRUB_MODE_0_START = 0x0202,
+ ECC_SCRUB_MODE_1_START = 0x0203,
+ BIST_STANDARD_MODE_START = 0x0301,
+ BIST_MEM_INIT_START = 0x0303,
+ BIST_SET_DATA_PATTERN_UPPER = 0x0305,
+ BIST_SET_DATA_PATTERN_LOWER = 0x0306,
+ TRIG_MEM_CAL = 0x000a
+};
+
+/*
+ * IOSSM mailbox required information
+ *
+ * @num_mem_interface: Number of memory interfaces instantiated
+ * @ip_type: IP type implemented on the IO96B
+ * @ip_instance_id: IP identifier for every IP instance implemented on the IO96B
+ */
+struct io96b_mb_ctrl {
+ u32 num_mem_interface;
+ u32 ip_type[2];
+ u32 ip_id[2];
+};
+
+/* CMD_REQ Register Definition */
+#define CMD_TARGET_IP_TYPE_MASK GENMASK(31, 29)
+#define CMD_TARGET_IP_INSTANCE_ID_MASK GENMASK(28, 24)
+#define CMD_TYPE_MASK GENMASK(23, 16)
+#define CMD_OPCODE_MASK GENMASK(15, 0)
+
+/*
+ * IOSSM mailbox request
+ * @ip_type: IP type for the specified memory interface
+ * @ip_id: IP instance ID for the specified memory interface
+ * @usr_cmd_type: User desire IOSSM mailbox command type
+ * @usr_cmd_opcode: User desire IOSSM mailbox command opcode
+ * @cmd_param_*: Parameters (if applicable) for the requested IOSSM mailbox command
+ */
+struct io96b_mb_req {
+ u32 ip_type;
+ u32 ip_id;
+ u32 usr_cmd_type;
+ u32 usr_cmd_opcode;
+ u32 cmd_param[NUM_CMD_PARAM];
+};
+
+/*
+ * IOSSM mailbox response outputs
+ *
+ * @cmd_resp_status: Command Interface status
+ * @cmd_resp_data_*: More spaces for command response
+ */
+struct io96b_mb_resp {
+ u32 cmd_resp_status;
+ u32 cmd_resp_data[NUM_CMD_RESPONSE_DATA];
+};
+
+/*
+ * IO96B instance specific information
+ *
+ * @size: Memory size
+ * @io96b_csr_addr: IO96B instance CSR address
+ * @cal_status: IO96B instance calibration status
+ * @mb_ctrl: IOSSM mailbox required information
+ */
+struct io96b_instance {
+ u16 size;
+ phys_addr_t io96b_csr_addr;
+ bool cal_status;
+ struct io96b_mb_ctrl mb_ctrl;
+};
+
+/*
+ * Overall IO96B instance(s) information
+ *
+ * @num_instance: Number of instance(s) assigned to HPS
+ * @overall_cal_status: Overall calibration status for all IO96B instance(s)
+ * @ddr_type: DDR memory type
+ * @ecc_status: ECC enable status (false = disabled, true = enabled)
+ * @overall_size: Total DDR memory size
+ * @io96b[]: IO96B instance specific information
+ * @ckgen_lock: IO96B GEN PLL lock (false = not locked, true = locked)
+ * @num_port: Number of IO96B port.
+ * @io96b_pll: Selected IO96B PLL. Example bit 0: EMIF0 PLL A selected,
+ * bit 1: EMIF0 PLL B selected, bit 2 - EMIF1 PLL A selected,
+ * bit 3: EMIF1 PLL B selected
+ */
+struct io96b_info {
+ u8 num_instance;
+ bool overall_cal_status;
+ const char *ddr_type;
+ bool ecc_status;
+ u16 overall_size;
+ struct io96b_instance io96b[MAX_IO96B_SUPPORTED];
+ bool ckgen_lock;
+ u8 num_port;
+ u8 io96b_pll;
+};
+
+int io96b_mb_req(phys_addr_t io96b_csr_addr, struct io96b_mb_req req,
+ u32 resp_data_len, struct io96b_mb_resp *resp);
+
+/* Supported IOSSM mailbox function */
+void io96b_mb_init(struct io96b_info *io96b_ctrl);
+int io96b_cal_status(phys_addr_t addr);
+void init_mem_cal(struct io96b_info *io96b_ctrl);
+int get_mem_technology(struct io96b_info *io96b_ctrl);
+int get_mem_width_info(struct io96b_info *io96b_ctrl);
+int ecc_enable_status(struct io96b_info *io96b_ctrl);
+int bist_mem_init_start(struct io96b_info *io96b_ctrl);
+bool ecc_interrupt_status(struct io96b_info *io96b_ctrl);
diff --git a/drivers/ddr/altera/sdram_agilex5.c b/drivers/ddr/altera/sdram_agilex5.c
new file mode 100644
index 00000000000..801a6bbab46
--- /dev/null
+++ b/drivers/ddr/altera/sdram_agilex5.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ *
+ */
+
+#include <stdlib.h>
+#include <div64.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <hang.h>
+#include <log.h>
+#include <ram.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <wdt.h>
+#include <linux/bitfield.h>
+#include <linux/sizes.h>
+#include <asm/arch/firewall.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/system_manager.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include "iossm_mailbox.h"
+#include "sdram_soc64.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* MPFE NOC registers */
+#define F2SDRAM_SIDEBAND_FLAGOUTSET0 0x50
+#define F2SDRAM_SIDEBAND_FLAGOUTSTATUS0 0x58
+#define SIDEBANDMGR_FLAGOUTSET0_REG SOCFPGA_F2SDRAM_MGR_ADDRESS +\
+ F2SDRAM_SIDEBAND_FLAGOUTSET0
+#define SIDEBANDMGR_FLAGOUTSTATUS0_REG SOCFPGA_F2SDRAM_MGR_ADDRESS +\
+ F2SDRAM_SIDEBAND_FLAGOUTSTATUS0
+#define BOOT_SCRATCH_COLD3_REG (socfpga_get_sysmgr_addr() +\
+ SYSMGR_SOC64_BOOT_SCRATCH_COLD3)
+#define PORT_EMIF_CONFIG_OFFSET 4
+#define EMIF_PLL_MASK GENMASK(19, 16)
+
+#define IO96B0_DUAL_PORT_MASK BIT(0)
+#define IO96B0_DUAL_EMIF_MASK BIT(1)
+
+#define FIREWALL_MPFE_SCR_IO96B0_REG 0x18000d00
+#define FIREWALL_MPFE_SCR_IO96B1_REG 0x18000d04
+#define FIREWALL_MPFE_NOC_CSR_REG 0x18000d08
+
+#define MEMORY_BANK_MAX_COUNT 3
+
+/* Reset type */
+enum reset_type {
+ POR_RESET,
+ WARM_RESET,
+ COLD_RESET,
+ NCONFIG,
+ JTAG_CONFIG,
+ RSU_RECONFIG
+};
+
+phys_addr_t io96b_csr_reg_addr[] = {
+ 0x18400000, /* IO96B_0 CSR registers address */
+ 0x18800000 /* IO96B_1 CSR registers address */
+};
+
+struct dram_bank_info_s {
+ phys_addr_t start;
+ phys_size_t max_size;
+};
+
+struct dram_bank_info_s dram_bank_info[MEMORY_BANK_MAX_COUNT] = {
+ {0x80000000, 0x80000000}, /* Memory Bank 0 */
+ {0x880000000, 0x780000000}, /* Memory Bank 1 */
+ {0x8800000000, 0x7800000000} /* Memory Bank 2 */
+};
+
+static enum reset_type get_reset_type(u32 reg)
+{
+ return FIELD_GET(ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_MASK, reg);
+}
+
+static void update_io96b_assigned_to_hps(bool dual_port_flag, bool dual_emif_flag)
+{
+ clrsetbits_le32(BOOT_SCRATCH_COLD3_REG,
+ ALT_SYSMGR_SCRATCH_REG_3_DDR_PORT_EMIF_INFO_MASK,
+ FIELD_PREP(ALT_SYSMGR_SCRATCH_REG_3_DDR_PORT_INFO_MASK, dual_port_flag) |
+ FIELD_PREP(ALT_SYSMGR_SCRATCH_REG_3_DDR_EMIF_INFO_MASK, dual_emif_flag));
+
+ debug("%s: update dual port dual emif info: 0x%x\n", __func__,
+ readl(BOOT_SCRATCH_COLD3_REG));
+}
+
+static void set_mpfe_config(void)
+{
+ /* Set mpfe_lite_intfcsel */
+ setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_MPFE_CONFIG, BIT(2));
+
+ /* Set mpfe_lite_active */
+ setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_MPFE_CONFIG, BIT(8));
+
+ debug("%s: mpfe_config: 0x%x\n", __func__,
+ readl(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_MPFE_CONFIG));
+}
+
+static bool is_ddr_init_hang(void)
+{
+ u32 reg = readl(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_POR0);
+
+ debug("%s: 0x%x\n", __func__, reg);
+
+ if (reg & ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK)
+ return true;
+
+ return false;
+}
+
+static void ddr_init_inprogress(bool start)
+{
+ if (start)
+ setbits_le32(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_POR0,
+ ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK);
+ else
+ clrbits_le32(socfpga_get_sysmgr_addr() +
+ SYSMGR_SOC64_BOOT_SCRATCH_POR0,
+ ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK);
+}
+
+static void populate_ddr_handoff(struct udevice *dev, struct io96b_info *io96b_ctrl)
+{
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+ int i;
+ u32 len = SOC64_HANDOFF_SDRAM_LEN;
+ u32 handoff_table[len];
+
+ /* Read handoff for DDR configuration */
+ socfpga_handoff_read((void *)SOC64_HANDOFF_SDRAM, handoff_table, len);
+
+ /* Read handoff - dual port */
+ plat->dualport = FIELD_GET(IO96B0_DUAL_PORT_MASK, handoff_table[PORT_EMIF_CONFIG_OFFSET]);
+ debug("%s: dualport from handoff: 0x%x\n", __func__, plat->dualport);
+
+ if (plat->dualport)
+ io96b_ctrl->num_port = 2;
+ else
+ io96b_ctrl->num_port = 1;
+
+ /* Read handoff - dual EMIF */
+ plat->dualemif = FIELD_GET(IO96B0_DUAL_EMIF_MASK, handoff_table[PORT_EMIF_CONFIG_OFFSET]);
+ debug("%s: dualemif from handoff: 0x%x\n", __func__, plat->dualemif);
+
+ if (plat->dualemif)
+ io96b_ctrl->num_instance = 2;
+ else
+ io96b_ctrl->num_instance = 1;
+
+ io96b_ctrl->io96b_pll = FIELD_GET(EMIF_PLL_MASK,
+ handoff_table[PORT_EMIF_CONFIG_OFFSET]);
+ debug("%s: io96b enabled pll from handoff: 0x%x\n", __func__, io96b_ctrl->io96b_pll);
+
+ update_io96b_assigned_to_hps(plat->dualport, plat->dualemif);
+
+ /* Assign IO96B CSR base address if it is valid */
+ for (i = 0; i < io96b_ctrl->num_instance; i++) {
+ io96b_ctrl->io96b[i].io96b_csr_addr = io96b_csr_reg_addr[i];
+ debug("%s: IO96B 0x%llx CSR enabled\n", __func__,
+ io96b_ctrl->io96b[i].io96b_csr_addr);
+ }
+}
+
+static void config_mpfe_sideband_mgr(struct udevice *dev)
+{
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+
+ /* Dual port setting */
+ if (plat->dualport)
+ setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(4));
+
+ /* Dual EMIF setting */
+ if (plat->dualemif) {
+ set_mpfe_config();
+ setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(5));
+ }
+
+ debug("%s: SIDEBANDMGR_FLAGOUTSTATUS0: 0x%x\n", __func__,
+ readl(SIDEBANDMGR_FLAGOUTSTATUS0_REG));
+}
+
+static void config_ccu_mgr(struct udevice *dev)
+{
+ int ret = 0;
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+
+ if (plat->dualport || plat->dualemif) {
+ debug("%s: config interleaving on ccu reg\n", __func__);
+ ret = uclass_get_device_by_name(UCLASS_NOP,
+ "socfpga-ccu-ddr-interleaving-on", &dev);
+ } else {
+ debug("%s: config interleaving off ccu reg\n", __func__);
+ ret = uclass_get_device_by_name(UCLASS_NOP,
+ "socfpga-ccu-ddr-interleaving-off", &dev);
+ }
+
+ if (ret) {
+ printf("interleaving on/off ccu settings init failed: %d\n", ret);
+ hang();
+ }
+}
+
+static void config_firewall_mpfe_csr(struct udevice *dev)
+{
+ int ret = 0;
+
+ debug("%s: config Firewall setting for MPFE CSR\n", __func__);
+ ret = uclass_get_device_by_name(UCLASS_NOP,
+ "socfpga-noc-fw-mpfe-csr", &dev);
+
+ if (ret) {
+ printf("Firewall setting for MPFE CSR init failed: %d\n", ret);
+ hang();
+ }
+}
+
+static bool hps_ocram_dbe_status(void)
+{
+ u32 reg = readl(BOOT_SCRATCH_COLD3_REG);
+
+ if (reg & ALT_SYSMGR_SCRATCH_REG_3_OCRAM_DBE_MASK)
+ return true;
+
+ return false;
+}
+
+int sdram_mmr_init_full(struct udevice *dev)
+{
+ int i, ret = 0;
+ phys_size_t hw_size;
+ struct altera_sdram_plat *plat = dev_get_plat(dev);
+ struct altera_sdram_priv *priv = dev_get_priv(dev);
+ struct io96b_info *io96b_ctrl = malloc(sizeof(*io96b_ctrl));
+
+ u32 reg = readl(BOOT_SCRATCH_COLD3_REG);
+ enum reset_type reset_t = get_reset_type(reg);
+ bool full_mem_init = false;
+
+ /* DDR initialization progress status tracking */
+ bool is_ddr_hang_be4_rst = is_ddr_init_hang();
+
+ debug("DDR: SDRAM init in progress ...\n");
+ ddr_init_inprogress(true);
+
+ gd->bd = (struct bd_info *)malloc(sizeof(struct bd_info));
+ memset(gd->bd, '\0', sizeof(struct bd_info));
+
+ debug("DDR: Address MPFE 0x%llx\n", plat->mpfe_base_addr);
+
+ /* Populating DDR handoff data */
+ debug("DDR: Checking SDRAM configuration in progress ...\n");
+ populate_ddr_handoff(dev, io96b_ctrl);
+
+ /* Configuring MPFE sideband manager registers - dual port & dual emif */
+ config_mpfe_sideband_mgr(dev);
+
+ /* Configuring Interleave/Non-interleave ccu registers */
+ config_ccu_mgr(dev);
+
+ /* Configure if polling is needed for IO96B GEN PLL locked */
+ io96b_ctrl->ckgen_lock = true;
+
+ /* Ensure calibration status passing */
+ init_mem_cal(io96b_ctrl);
+
+ printf("DDR: Calibration success\n");
+
+ /* Initiate IOSSM mailbox */
+ io96b_mb_init(io96b_ctrl);
+
+ /* DDR type, DDR size and ECC status) */
+ ret = get_mem_technology(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to get DDR type\n");
+
+ goto err;
+ }
+
+ ret = get_mem_width_info(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to get DDR size\n");
+
+ goto err;
+ }
+
+ hw_size = (phys_size_t)io96b_ctrl->overall_size * SZ_1G / SZ_8;
+
+ /* Get bank configuration from devicetree */
+ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL,
+ (phys_size_t *)&gd->ram_size, gd->bd);
+ if (ret) {
+ puts("DDR: Failed to decode memory node\n");
+ ret = -ENXIO;
+
+ goto err;
+ }
+
+ if (gd->ram_size > hw_size) {
+ printf("DDR: Warning: DRAM size from device tree (%lld MiB) exceeds\n",
+ gd->ram_size >> 20);
+ printf(" the actual hardware capacity(%lld MiB). Memory configuration will be\n",
+ hw_size >> 20);
+ printf(" adjusted to match the detected hardware size.\n");
+ gd->ram_size = 0;
+ }
+
+ if (gd->ram_size > 0 && gd->ram_size != hw_size) {
+ printf("DDR: Warning: DRAM size from device tree (%lld MiB)\n",
+ gd->ram_size >> 20);
+ printf(" mismatch with hardware capacity(%lld MiB).\n",
+ hw_size >> 20);
+ }
+
+ if (gd->ram_size == 0 && hw_size > 0) {
+ phys_size_t remaining_size, size_counter = 0;
+ u8 config_dram_banks;
+
+ if (CONFIG_NR_DRAM_BANKS > MEMORY_BANK_MAX_COUNT) {
+ printf("DDR: Warning: CONFIG_NR_DRAM_BANKS(%d) is bigger than Max Memory Bank count(%d).\n",
+ CONFIG_NR_DRAM_BANKS, MEMORY_BANK_MAX_COUNT);
+ printf(" Max Memory Bank count is in use instead of CONFIG_NR_DRAM_BANKS.\n");
+ config_dram_banks = MEMORY_BANK_MAX_COUNT;
+ } else {
+ config_dram_banks = CONFIG_NR_DRAM_BANKS;
+ }
+
+ for (i = 0; i < config_dram_banks; i++) {
+ remaining_size = hw_size - size_counter;
+ if (remaining_size <= dram_bank_info[i].max_size) {
+ gd->bd->bi_dram[i].start = dram_bank_info[i].start;
+ gd->bd->bi_dram[i].size = remaining_size;
+ debug("Memory bank[%d] Starting address: 0x%llx size: 0x%llx\n",
+ i, gd->bd->bi_dram[i].start, gd->bd->bi_dram[i].size);
+ break;
+ }
+
+ gd->bd->bi_dram[i].start = dram_bank_info[i].start;
+ gd->bd->bi_dram[i].size = dram_bank_info[i].max_size;
+
+ debug("Memory bank[%d] Starting address: 0x%llx size: 0x%llx\n",
+ i, gd->bd->bi_dram[i].start, gd->bd->bi_dram[i].size);
+ size_counter += gd->bd->bi_dram[i].size;
+ }
+
+ gd->ram_size = hw_size;
+ }
+
+ printf("%s: %lld MiB\n", io96b_ctrl->ddr_type, gd->ram_size >> 20);
+
+ ret = ecc_enable_status(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to get ECC enabled status\n");
+
+ goto err;
+ }
+
+ /* Is HPS cold or warm reset? If yes, Skip full memory initialization if ECC
+ * enabled to preserve memory content
+ */
+ if (io96b_ctrl->ecc_status) {
+ if (ecc_interrupt_status(io96b_ctrl)) {
+ if (CONFIG_IS_ENABLED(WDT)) {
+ struct udevice *wdt;
+
+ printf("DDR: ECC error recover start now\n");
+ ret = uclass_first_device_err(UCLASS_WDT, &wdt);
+ if (ret) {
+ printf("DDR: Failed to trigger watchdog reset\n");
+ hang();
+ }
+
+ wdt_expire_now(wdt, 0);
+ }
+ hang();
+ }
+
+ full_mem_init = hps_ocram_dbe_status() | is_ddr_hang_be4_rst;
+ if (full_mem_init || !(reset_t == WARM_RESET || reset_t == COLD_RESET)) {
+ ret = bist_mem_init_start(io96b_ctrl);
+ if (ret) {
+ printf("DDR: Failed to fully initialize DDR memory\n");
+
+ goto err;
+ }
+ }
+
+ printf("SDRAM-ECC: Initialized success\n");
+ }
+
+ sdram_size_check(gd->bd);
+ printf("DDR: size check success\n");
+
+ sdram_set_firewall(gd->bd);
+
+ /* Firewall setting for MPFE CSR */
+ config_firewall_mpfe_csr(dev);
+
+ printf("DDR: firewall init success\n");
+
+ priv->info.base = gd->bd->bi_dram[0].start;
+ priv->info.size = gd->ram_size;
+
+ /* Ending DDR driver initialization success tracking */
+ ddr_init_inprogress(false);
+
+ printf("DDR: init success\n");
+
+err:
+ free(io96b_ctrl);
+
+ return ret;
+}
diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c
index 10a8e64af3d..c8c9211adce 100644
--- a/drivers/ddr/altera/sdram_soc64.c
+++ b/drivers/ddr/altera/sdram_soc64.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016-2022 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
*
*/
@@ -28,6 +29,7 @@
#define PGTABLE_OFF 0x4000
+#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg)
{
return readl(plat->iomhc + reg);
@@ -99,8 +101,9 @@ int emif_reset(struct altera_sdram_plat *plat)
debug("DDR: %s triggered successly\n", __func__);
return 0;
}
+#endif
-#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
+#if !(IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) || IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5))
int poll_hmc_clock_status(void)
{
return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() +
@@ -252,7 +255,7 @@ phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat)
return size;
}
-void sdram_set_firewall(struct bd_info *bd)
+static void sdram_set_firewall_non_f2sdram(struct bd_info *bd)
{
u32 i;
phys_size_t value;
@@ -288,7 +291,7 @@ void sdram_set_firewall(struct bd_info *bd)
FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT +
(i * 4 * sizeof(u32)));
- /* Setting non-secure MPU limit and limit extexded */
+ /* Setting non-secure MPU limit and limit extended */
value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
lower = lower_32_bits(value);
@@ -301,7 +304,7 @@ void sdram_set_firewall(struct bd_info *bd)
FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT +
(i * 4 * sizeof(u32)));
- /* Setting non-secure Non-MPU limit and limit extexded */
+ /* Setting non-secure Non-MPU limit and limit extended */
FW_MPU_DDR_SCR_WRITEL(lower,
FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT +
(i * 4 * sizeof(u32)));
@@ -314,15 +317,77 @@ void sdram_set_firewall(struct bd_info *bd)
}
}
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
+static void sdram_set_firewall_f2sdram(struct bd_info *bd)
+{
+ u32 i, lower, upper;
+ phys_size_t value;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ if (!bd->bi_dram[i].size)
+ continue;
+
+ value = bd->bi_dram[i].start;
+
+ /* Keep first 1MB of SDRAM memory region as secure region when
+ * using ATF flow, where the ATF code is located.
+ */
+ if (IS_ENABLED(CONFIG_SPL_ATF) && i == 0)
+ value += SZ_1M;
+
+ /* Setting base and base extended */
+ lower = lower_32_bits(value);
+ upper = upper_32_bits(value);
+ FW_F2SDRAM_DDR_SCR_WRITEL(lower,
+ FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE +
+ (i * 4 * sizeof(u32)));
+ FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff,
+ FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT +
+ (i * 4 * sizeof(u32)));
+
+ /* Setting limit and limit extended */
+ value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
+
+ lower = lower_32_bits(value);
+ upper = upper_32_bits(value);
+
+ FW_F2SDRAM_DDR_SCR_WRITEL(lower,
+ FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT +
+ (i * 4 * sizeof(u32)));
+ FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff,
+ FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT +
+ (i * 4 * sizeof(u32)));
+
+ FW_F2SDRAM_DDR_SCR_WRITEL(BIT(i), FW_F2SDRAM_DDR_SCR_EN_SET);
+ }
+}
+#endif
+
+void sdram_set_firewall(struct bd_info *bd)
+{
+ sdram_set_firewall_non_f2sdram(bd);
+
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
+ sdram_set_firewall_f2sdram(bd);
+#endif
+}
+
static int altera_sdram_of_to_plat(struct udevice *dev)
{
+#if !IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
struct altera_sdram_plat *plat = dev_get_plat(dev);
fdt_addr_t addr;
+#endif
/* These regs info are part of DDR handoff in bitstream */
#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X)
return 0;
-#endif
+#elif IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
+ addr = dev_read_addr_index(dev, 0);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ plat->mpfe_base_addr = addr;
+#else
addr = dev_read_addr_index(dev, 0);
if (addr == FDT_ADDR_T_NONE)
@@ -338,7 +403,7 @@ static int altera_sdram_of_to_plat(struct udevice *dev)
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
plat->hmc = (void __iomem *)addr;
-
+#endif
return 0;
}
@@ -385,6 +450,7 @@ static const struct udevice_id altera_sdram_ids[] = {
{ .compatible = "altr,sdr-ctl-s10" },
{ .compatible = "intel,sdr-ctl-agilex" },
{ .compatible = "intel,sdr-ctl-n5x" },
+ { .compatible = "intel,sdr-ctl-agilex5" },
{ /* sentinel */ }
};
diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h
index 87a70a861ba..183b1a33080 100644
--- a/drivers/ddr/altera/sdram_soc64.h
+++ b/drivers/ddr/altera/sdram_soc64.h
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2017-2019 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ *
*/
#ifndef _SDRAM_SOC64_H_
@@ -13,11 +15,19 @@ struct altera_sdram_priv {
struct reset_ctl_bulk resets;
};
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
+struct altera_sdram_plat {
+ fdt_addr_t mpfe_base_addr;
+ bool dualport;
+ bool dualemif;
+};
+#else
struct altera_sdram_plat {
void __iomem *hmc;
void __iomem *ddr_sch;
void __iomem *iomhc;
};
+#endif
/* ECC HMC registers */
#define DDRIOCTRL 0x8
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 3c64e894646..4b47be6b016 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -76,6 +76,13 @@ config XILINX_DPDMA
this file is used as placeholder for driver. The main reason is
to record compatible string and calling power domain driver.
+config ADI_DMA
+ bool "ADI DMA driver"
+ depends on DMA && DMA_CHANNELS
+ help
+ Enable DMA support for Analog Devices SOCs, such as the SC5xx.
+ Currently this is a minimalistic driver tested against OSPI use only.
+
if APBH_DMA
config APBH_DMA_BURST
bool "Enable DMA BURST"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 48811eaaeb3..00d765864cd 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -13,5 +13,6 @@ obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o
obj-$(CONFIG_XILINX_DPDMA) += xilinx_dpdma.o
+obj-$(CONFIG_ADI_DMA) += adi_dma.o
obj-y += ti/
diff --git a/drivers/dma/adi_dma.c b/drivers/dma/adi_dma.c
new file mode 100644
index 00000000000..28afe488db0
--- /dev/null
+++ b/drivers/dma/adi_dma.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Analog Devices DMA controller driver
+ *
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ * Contact: Ian Roberts <ian.roberts@timesys.com>
+ *
+ */
+#include <dm.h>
+#include <dma.h>
+#include <dma-uclass.h>
+#include <dm/device_compat.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#define HAS_MDMA BIT(0)
+
+#define REG_ADDRSTART 0x04
+#define REG_CFG 0x08
+#define REG_XCNT 0x0C
+#define REG_XMOD 0x10
+#define REG_STAT 0x30
+
+#define BITP_DMA_CFG_MSIZE 8
+#define BITP_DMA_CFG_PSIZE 4
+#define BITM_DMA_CFG_WNR 0x00000002
+#define BITM_DMA_CFG_EN 0x00000001
+#define ENUM_DMA_CFG_XCNT_INT 0x00100000
+
+#define BITP_DMA_STAT_PBWID 12
+#define BITP_DMA_STAT_ERRC 4
+#define BITM_DMA_STAT_PBWID 0x00003000
+#define BITM_DMA_STAT_ERRC 0x00000070
+#define BITM_DMA_STAT_PIRQ 0x00000004
+#define BITM_DMA_STAT_IRQERR 0x00000002
+#define BITM_DMA_STAT_IRQDONE 0x00000001
+
+#define DMA_MDMA_SRC_DEFAULT_CONFIG(psize, msize) \
+ (BITM_DMA_CFG_EN | ((psize) << BITP_DMA_CFG_PSIZE) | ((msize) << BITP_DMA_CFG_MSIZE))
+#define DMA_MDMA_DST_DEFAULT_CONFIG(psize, msize) \
+ (BITM_DMA_CFG_EN | BITM_DMA_CFG_WNR | ENUM_DMA_CFG_XCNT_INT | \
+ ((psize) << BITP_DMA_CFG_PSIZE) | ((msize) << BITP_DMA_CFG_MSIZE))
+
+struct adi_dma_channel {
+ int id;
+ struct adi_dma *dma;
+ void __iomem *iosrc;
+ void __iomem *iodest;
+};
+
+struct adi_dma {
+ struct udevice *dev;
+ struct adi_dma_channel channels[1];
+ void __iomem *ioaddr;
+ unsigned long hw_cfg;
+};
+
+static const struct udevice_id dma_dt_ids[] = {
+ { .compatible = "adi,mdma-controller", .data = HAS_MDMA },
+ { }
+};
+
+static u8 adi_dma_get_msize(u32 n_bytecount, u32 n_address)
+{
+ /* Calculate MSIZE, PSIZE, XCNT and XMOD */
+ u8 n_msize = 0;
+ u32 n_value = n_bytecount | n_address;
+ u32 n_mask = 0x1;
+
+ for (n_msize = 0; n_msize < 5; n_msize++, n_mask <<= 1) {
+ if ((n_value & n_mask) == n_mask)
+ break;
+ }
+
+ return n_msize;
+}
+
+static int adi_dma_get_ch_error(void __iomem *ch)
+{
+ u32 cause = (ioread32(ch + REG_STAT) & BITM_DMA_STAT_ERRC) >>
+ BITP_DMA_STAT_ERRC;
+ switch (cause) {
+ case 0:
+ return -EINVAL;
+ case 1:
+ return -EBUSY;
+ case 2:
+ return -EFAULT;
+ case 3:
+ fallthrough;
+ case 5:
+ fallthrough;
+ case 6:
+ fallthrough;
+ default:
+ return -EIO;
+ }
+}
+
+static int adi_mdma_transfer(struct udevice *dev, int direction,
+ dma_addr_t dst, dma_addr_t src, size_t len)
+{
+ struct adi_dma *priv = dev_get_priv(dev);
+ void __iomem *chsrc = priv->channels[0].iosrc;
+ void __iomem *chdst = priv->channels[0].iodest;
+
+ int result = 0;
+ u32 reg;
+ u32 bytecount = len;
+
+ u8 n_srcmsize;
+ u8 n_dstmsize;
+ u8 n_srcpsize;
+ u8 n_dstpsize;
+ u8 n_psize;
+ u32 srcconfig;
+ u32 dstconfig;
+ u8 srcpsizemax = (ioread32(chsrc + REG_STAT) & BITM_DMA_STAT_PBWID) >>
+ BITP_DMA_STAT_PBWID;
+ u8 dstpsizemax = (ioread32(chdst + REG_STAT) & BITM_DMA_STAT_PBWID) >>
+ BITP_DMA_STAT_PBWID;
+
+ const u32 CLRSTAT = (BITM_DMA_STAT_IRQDONE | BITM_DMA_STAT_IRQERR |
+ BITM_DMA_STAT_PIRQ);
+
+ if (len == 0)
+ return -EINVAL;
+
+ /* Clear DMA status */
+ iowrite32(CLRSTAT, chsrc + REG_STAT);
+ iowrite32(CLRSTAT, chdst + REG_STAT);
+
+ /* Calculate MSIZE, PSIZE, XCNT and XMOD */
+ n_srcmsize = adi_dma_get_msize(bytecount, src);
+ n_dstmsize = adi_dma_get_msize(bytecount, dst);
+ n_srcpsize = min(n_srcmsize, srcpsizemax);
+ n_dstpsize = min(n_dstmsize, dstpsizemax);
+ n_psize = min(n_srcpsize, n_dstpsize);
+
+ srcconfig = DMA_MDMA_SRC_DEFAULT_CONFIG(n_psize, n_srcmsize);
+ dstconfig = DMA_MDMA_DST_DEFAULT_CONFIG(n_psize, n_dstmsize);
+
+ /* Load the DMA descriptors */
+ iowrite32(src, chsrc + REG_ADDRSTART);
+ iowrite32(bytecount >> n_srcmsize, chsrc + REG_XCNT);
+ iowrite32(1 << n_srcmsize, chsrc + REG_XMOD);
+ iowrite32(dst, chdst + REG_ADDRSTART);
+ iowrite32(bytecount >> n_dstmsize, chdst + REG_XCNT);
+ iowrite32(1 << n_dstmsize, chdst + REG_XMOD);
+
+ iowrite32(dstconfig, chdst + REG_CFG);
+ iowrite32(srcconfig, chsrc + REG_CFG);
+
+ /* Wait for DMA to complete while checking for a DMA error */
+ do {
+ reg = ioread32(chsrc + REG_STAT);
+ if ((reg & BITM_DMA_STAT_IRQERR) == BITM_DMA_STAT_IRQERR) {
+ result = adi_dma_get_ch_error(chsrc);
+ break;
+ }
+ reg = ioread32(chdst + REG_STAT);
+ if ((reg & BITM_DMA_STAT_IRQERR) == BITM_DMA_STAT_IRQERR) {
+ result = adi_dma_get_ch_error(chdst);
+ break;
+ }
+ } while ((reg & BITM_DMA_STAT_IRQDONE) == 0);
+
+ clrbits_32(chsrc + REG_CFG, 1);
+ clrbits_32(chdst + REG_CFG, 1);
+
+ return result;
+}
+
+static int adi_dma_init_channel(struct adi_dma *dma,
+ struct adi_dma_channel *channel, ofnode node)
+{
+ u32 offset;
+
+ if (ofnode_read_u32(node, "adi,id", &channel->id)) {
+ dev_err(dma->dev, "Missing adi,id for channel %s\n",
+ ofnode_get_name(node));
+ return -ENOENT;
+ }
+
+ if (ofnode_read_u32(node, "adi,src-offset", &offset)) {
+ dev_err(dma->dev, "Missing adi,src-offset for channel %s\n",
+ ofnode_get_name(node));
+ return -ENOENT;
+ }
+
+ channel->iosrc = dma->ioaddr + offset;
+ channel->dma = dma;
+
+ if (dma->hw_cfg & HAS_MDMA) {
+ if (ofnode_read_u32(node, "adi,dest-offset", &offset)) {
+ dev_err(dma->dev,
+ "Missing adi,dest-offset for channel %s\n",
+ ofnode_get_name(node));
+ return -ENOENT;
+ }
+ channel->iodest = dma->ioaddr + offset;
+ }
+
+ return 0;
+}
+
+static int adi_dma_probe(struct udevice *dev)
+{
+ struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct adi_dma *priv = dev_get_priv(dev);
+ ofnode node, child;
+
+ priv->hw_cfg = dev_get_driver_data(dev);
+ if (priv->hw_cfg & HAS_MDMA)
+ uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM;
+
+ priv->ioaddr = dev_remap_addr(dev);
+ if (!priv->ioaddr)
+ return -EINVAL;
+
+ node = dev_read_first_subnode(dev);
+ if (!ofnode_valid(node)) {
+ dev_err(dev,
+ "Error: device tree DMA channel config missing!\n");
+ return -ENODEV;
+ }
+
+ node = dev_ofnode(dev);
+ ofnode_for_each_subnode(child, node) {
+ adi_dma_init_channel(priv, priv->channels, child);
+ break; //Only 1 channel supported for now
+ }
+
+ return 0;
+}
+
+static const struct dma_ops adi_dma_ops = {
+ .transfer = adi_mdma_transfer,
+};
+
+U_BOOT_DRIVER(adi_dma) = {
+ .name = "adi_dma",
+ .id = UCLASS_DMA,
+ .of_match = dma_dt_ids,
+ .ops = &adi_dma_ops,
+ .probe = adi_dma_probe,
+ .priv_auto = sizeof(struct adi_dma),
+};
diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile
index 94ec13ba7ca..90c20a6a3fa 100644
--- a/drivers/dma/ti/Makefile
+++ b/drivers/dma/ti/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_TI_K3_PSIL) += k3-psil-data.o
k3-psil-data-y += k3-psil.o
k3-psil-data-$(CONFIG_SOC_K3_AM654) += k3-psil-am654.o
k3-psil-data-$(CONFIG_SOC_K3_J721E) += k3-psil-j721e.o
+k3-psil-data-$(CONFIG_SOC_K3_J7200) += k3-psil-j721e.o
k3-psil-data-$(CONFIG_SOC_K3_J721S2) += k3-psil-j721s2.o
k3-psil-data-$(CONFIG_SOC_K3_AM642) += k3-psil-am64.o
k3-psil-data-$(CONFIG_SOC_K3_AM625) += k3-psil-am62.o
diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c
index 369e679886f..39798844a8a 100644
--- a/drivers/dma/ti/k3-psil.c
+++ b/drivers/dma/ti/k3-psil.c
@@ -20,6 +20,8 @@ struct psil_endpoint_config *psil_get_ep_config(u32 thread_id)
soc_ep_map = &am654_ep_map;
else if (IS_ENABLED(CONFIG_SOC_K3_J721E))
soc_ep_map = &j721e_ep_map;
+ else if (IS_ENABLED(CONFIG_SOC_K3_J7200))
+ soc_ep_map = &j721e_ep_map;
else if (IS_ENABLED(CONFIG_SOC_K3_J721S2))
soc_ep_map = &j721s2_ep_map;
else if (IS_ENABLED(CONFIG_SOC_K3_AM642))
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 3013c4741d0..723265ab2e5 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -36,6 +36,7 @@
#include "k3-psil-priv.h"
#define K3_UDMA_MAX_RFLOWS 1024
+#define K3_UDMA_MAX_TR 2
struct udma_chan;
@@ -74,7 +75,6 @@ struct udma_tchan {
struct k3_nav_ring *t_ring; /* Transmit ring */
struct k3_nav_ring *tc_ring; /* Transmit Completion ring */
int tflow_id; /* applicable only for PKTDMA */
-
};
#define udma_bchan udma_tchan
@@ -175,6 +175,7 @@ struct udma_dev {
struct udma_rflow *rflows;
struct udma_match_data *match_data;
+ void *bc_desc;
struct udma_chan *channels;
u32 psil_base;
@@ -1349,6 +1350,7 @@ static int udma_setup_resources(struct udma_dev *ud)
struct ti_sci_resource_desc *rm_desc;
struct ti_sci_resource *rm_res;
struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
+ size_t desc_size;
ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt),
sizeof(unsigned long), GFP_KERNEL);
@@ -1366,9 +1368,11 @@ static int udma_setup_resources(struct udma_dev *ud)
ud->rflows = devm_kcalloc(dev, ud->rflow_cnt, sizeof(*ud->rflows),
GFP_KERNEL);
+ desc_size = cppi5_trdesc_calc_size(K3_UDMA_MAX_TR, sizeof(struct cppi5_tr_type15_t));
+ ud->bc_desc = devm_kzalloc(dev, ALIGN(desc_size, ARCH_DMA_MINALIGN), GFP_KERNEL);
if (!ud->tchan_map || !ud->rchan_map || !ud->rflow_map ||
!ud->rflow_map_reserved || !ud->tchans || !ud->rchans ||
- !ud->rflows)
+ !ud->rflows || !ud->bc_desc)
return -ENOMEM;
/*
@@ -1444,6 +1448,7 @@ static int bcdma_setup_resources(struct udma_dev *ud)
struct ti_sci_resource_desc *rm_desc;
struct ti_sci_resource *rm_res;
struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
+ size_t desc_size;
ud->bchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->bchan_cnt),
sizeof(unsigned long), GFP_KERNEL);
@@ -1460,9 +1465,12 @@ static int bcdma_setup_resources(struct udma_dev *ud)
ud->rflows = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rflows),
GFP_KERNEL);
+ desc_size = cppi5_trdesc_calc_size(K3_UDMA_MAX_TR, sizeof(struct cppi5_tr_type15_t));
+ ud->bc_desc = devm_kzalloc(dev, ALIGN(desc_size, ARCH_DMA_MINALIGN), GFP_KERNEL);
+
if (!ud->bchan_map || !ud->tchan_map || !ud->rchan_map ||
!ud->bchans || !ud->tchans || !ud->rchans ||
- !ud->rflows)
+ !ud->rflows || !ud->bc_desc)
return -ENOMEM;
/* Get resource ranges from tisci */
@@ -1718,8 +1726,7 @@ static int *udma_prep_dma_memcpy(struct udma_chan *uc, dma_addr_t dest,
int num_tr;
size_t tr_size = sizeof(struct cppi5_tr_type15_t);
u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
- unsigned long dummy;
- void *tr_desc;
+ void *tr_desc = uc->ud->bc_desc;
size_t desc_size;
if (len < SZ_64K) {
@@ -1748,9 +1755,6 @@ static int *udma_prep_dma_memcpy(struct udma_chan *uc, dma_addr_t dest,
}
desc_size = cppi5_trdesc_calc_size(num_tr, tr_size);
- tr_desc = dma_alloc_coherent(desc_size, &dummy);
- if (!tr_desc)
- return NULL;
memset(tr_desc, 0, desc_size);
cppi5_trdesc_init(tr_desc, num_tr, tr_size, 0, 0);
diff --git a/drivers/firmware/ti_sci_static_data.h b/drivers/firmware/ti_sci_static_data.h
index 3370f80231d..2e61e0c7de1 100644
--- a/drivers/firmware/ti_sci_static_data.h
+++ b/drivers/firmware/ti_sci_static_data.h
@@ -16,7 +16,7 @@ struct ti_sci_resource_static_data {
#if IS_ENABLED(CONFIG_K3_DM_FW)
-#if IS_ENABLED(CONFIG_SOC_K3_J721E)
+#if IS_ENABLED(CONFIG_SOC_K3_J721E) || IS_ENABLED(CONFIG_SOC_K3_J7200)
static struct ti_sci_resource_static_data rm_static_data[] = {
/* Free rings */
{
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 21361f56e69..e11109fb56d 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -97,6 +97,15 @@ config SPL_DM_GPIO_LOOKUP_LABEL
different gpios on different hardware versions
for the same functionality in board code.
+config ADI_GPIO
+ bool "ADI GPIO driver"
+ depends on DM_GPIO && ARCH_SC5XX
+ help
+ This driver supports GPIO banks on SC5xx processors. It
+ supports inputs and outputs but does not support pin
+ interrupt functionality (PINT) or other features in the
+ Linux version of the driver.
+
config ALTERA_PIO
bool "Altera PIO driver"
depends on DM_GPIO
@@ -545,6 +554,14 @@ config DM_PCA953X
Now, max 24 bits chips and PCA953X compatible chips are
supported
+config ADP5588_GPIO
+ bool "ADP5588 GPIO expander driver"
+ depends on DM_GPIO && DM_I2C
+ help
+ Say yes here to support GPIO functionality of ADI ADP5588 chips.
+
+ The ADP5588 is an 18-port I2C GPIO expander and keypad controller.
+
config SPL_DM_PCA953X
bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports in SPL"
depends on SPL_DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 3f882c065d8..d426d3a2d7b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_$(PHASE_)DM_GPIO) += gpio-uclass.o
obj-$(CONFIG_$(XPL_)DM_PCA953X) += pca953x_gpio.o
+obj-$(CONFIG_ADI_GPIO) += gpio-adi-adsp.o
obj-$(CONFIG_ASPEED_GPIO) += gpio-aspeed.o
obj-$(CONFIG_ASPEED_G7_GPIO) += gpio-aspeed-g7.o
obj-$(CONFIG_ASPEED_SGPIO) += gpio-aspeed-sgpio.o
@@ -74,6 +75,7 @@ obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o
obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o
obj-$(CONFIG_$(XPL_)MAX77663_GPIO) += max77663_gpio.o
obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o
+obj-$(CONFIG_ADP5588_GPIO) += adp5588_gpio.o
obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o
obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
obj-$(CONFIG_FTGPIO010) += ftgpio010.o
diff --git a/drivers/gpio/adp5588_gpio.c b/drivers/gpio/adp5588_gpio.c
new file mode 100644
index 00000000000..d081e169897
--- /dev/null
+++ b/drivers/gpio/adp5588_gpio.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * GPIO Chip driver for Analog Devices
+ * ADP5588/ADP5587 I/O Expander and QWERTY Keypad Controller
+ *
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * Based on Michael Hennerich's Linux driver:
+ * Michael Hennerich <michael.hennerich@analog.com>
+ *
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <asm-generic/gpio.h>
+
+#define ADP5588_MAXGPIO 18
+#define ADP5588_BANK(offs) ((offs) >> 3)
+#define ADP5588_BIT(offs) (1u << ((offs) & 0x7))
+
+#define DEV_ID 0x00 /* Device ID */
+#define GPIO_DAT_STAT1 0x14 /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT2 0x15 /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT3 0x16 /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_OUT1 0x17 /* GPIO DATA OUT */
+#define GPIO_DAT_OUT2 0x18 /* GPIO DATA OUT */
+#define GPIO_DAT_OUT3 0x19 /* GPIO DATA OUT */
+#define GPIO_INT_EN1 0x1A /* GPIO Interrupt Enable */
+#define GPIO_INT_EN2 0x1B /* GPIO Interrupt Enable */
+#define GPIO_INT_EN3 0x1C /* GPIO Interrupt Enable */
+#define KP_GPIO1 0x1D /* Keypad or GPIO Selection */
+#define KP_GPIO2 0x1E /* Keypad or GPIO Selection */
+#define KP_GPIO3 0x1F /* Keypad or GPIO Selection */
+#define GPIO_DIR1 0x23 /* GPIO Data Direction */
+#define GPIO_DIR2 0x24 /* GPIO Data Direction */
+#define GPIO_DIR3 0x25 /* GPIO Data Direction */
+#define GPIO_PULL1 0x2C /* GPIO Pull Disable */
+#define GPIO_PULL2 0x2D /* GPIO Pull Disable */
+#define GPIO_PULL3 0x2E /* GPIO Pull Disable */
+#define ID_MASK 0x0F
+
+struct adp5588_gpio {
+ u8 dat_out[3];
+ u8 dir[3];
+};
+
+static int adp5588_gpio_read(struct udevice *dev, u8 reg)
+{
+ int ret;
+ u8 val;
+
+ ret = dm_i2c_read(dev, reg, &val, 1);
+
+ if (ret < 0) {
+ pr_err("%s: read error\n", __func__);
+ return ret;
+ }
+
+ return val;
+}
+
+static int adp5588_gpio_write(struct udevice *dev, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, &val, 1);
+ if (ret < 0) {
+ pr_err("%s: write error\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adp5588_get_value(struct udevice *dev, u32 offset)
+{
+ struct adp5588_gpio *plat = dev_get_plat(dev);
+ unsigned int bank = ADP5588_BANK(offset);
+ unsigned int bit = ADP5588_BIT(offset);
+ int val;
+
+ if (plat->dir[bank] & bit)
+ val = plat->dat_out[bank];
+ else
+ val = adp5588_gpio_read(dev, GPIO_DAT_STAT1 + bank);
+
+ return !!(val & bit);
+}
+
+static int adp5588_set_value(struct udevice *dev, u32 offset,
+ int32_t value)
+{
+ unsigned int bank, bit;
+ int ret;
+ struct adp5588_gpio *plat = dev_get_plat(dev);
+
+ bank = ADP5588_BANK(offset);
+ bit = ADP5588_BIT(offset);
+
+ if (value)
+ plat->dat_out[bank] |= bit;
+ else
+ plat->dat_out[bank] &= ~bit;
+
+ ret = adp5588_gpio_write(dev, GPIO_DAT_OUT1 + bank,
+ plat->dat_out[bank]);
+
+ return ret;
+}
+
+static int adp5588_direction_input(struct udevice *dev, u32 offset)
+{
+ int ret;
+ unsigned int bank;
+ struct adp5588_gpio *plat = dev_get_plat(dev);
+
+ bank = ADP5588_BANK(offset);
+
+ plat->dir[bank] &= ~ADP5588_BIT(offset);
+ ret = adp5588_gpio_write(dev, GPIO_DIR1 + bank, plat->dir[bank]);
+
+ return ret;
+}
+
+static int adp5588_direction_output(struct udevice *dev,
+ u32 offset, int value)
+{
+ int ret;
+ unsigned int bank, bit;
+ struct adp5588_gpio *plat = dev_get_plat(dev);
+
+ bank = ADP5588_BANK(offset);
+ bit = ADP5588_BIT(offset);
+
+ plat->dir[bank] |= bit;
+
+ if (value)
+ plat->dat_out[bank] |= bit;
+ else
+ plat->dat_out[bank] &= ~bit;
+
+ ret = adp5588_gpio_write(dev, GPIO_DAT_OUT1 + bank,
+ plat->dat_out[bank]);
+ ret |= adp5588_gpio_write(dev, GPIO_DIR1 + bank,
+ plat->dir[bank]);
+
+ return ret;
+}
+
+static int adp5588_ofdata_platdata(struct udevice *dev)
+{
+ struct adp5588_gpio *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *priv = dev_get_uclass_priv(dev);
+ int node = dev_of_offset(dev);
+ int ret, i, revid;
+
+ priv->gpio_count = ADP5588_MAXGPIO;
+ priv->bank_name = fdt_get_name(gd->fdt_blob, node, NULL);
+
+ ret = adp5588_gpio_read(dev, DEV_ID);
+ if (ret < 0)
+ return ret;
+
+ revid = ret & ID_MASK;
+
+ printf("ADP5588 Detected: Rev %x, Rev ID %x\n", ret, revid);
+
+ for (i = 0, ret = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
+ plat->dat_out[i] = adp5588_gpio_read(dev, GPIO_DAT_OUT1 + i);
+ plat->dir[i] = adp5588_gpio_read(dev, GPIO_DIR1 + i);
+ ret |= adp5588_gpio_write(dev, KP_GPIO1 + i, 0);
+ ret |= adp5588_gpio_write(dev, GPIO_PULL1 + i, 0);
+ ret |= adp5588_gpio_write(dev, GPIO_INT_EN1 + i, 0);
+ if (ret) {
+ pr_err("%s: Initialization error\n", __func__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct dm_gpio_ops adp5588_ops = {
+ .direction_input = adp5588_direction_input,
+ .direction_output = adp5588_direction_output,
+ .get_value = adp5588_get_value,
+ .set_value = adp5588_set_value,
+};
+
+static const struct udevice_id adp5588_of_match_list[] = {
+ { .compatible = "adi,adp5588"},
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(gpio_adp5588) = {
+ .name = "gpio_adp5588",
+ .id = UCLASS_GPIO,
+ .ops = &adp5588_ops,
+ .of_match = adp5588_of_match_list,
+ .of_to_plat = adp5588_ofdata_platdata,
+ .plat_auto = sizeof(struct adp5588_gpio),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/gpio/gpio-adi-adsp.c b/drivers/gpio/gpio-adi-adsp.c
new file mode 100644
index 00000000000..0ce00572e08
--- /dev/null
+++ b/drivers/gpio/gpio-adi-adsp.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Author: Greg Malysa <greg.malysa@timesys.com>
+ * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ */
+
+#include <dm.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define ADSP_PORT_MMIO_SIZE 0x80
+#define ADSP_PORT_PIN_SIZE 16
+
+#define ADSP_PORT_REG_FER 0x00
+#define ADSP_PORT_REG_FER_SET 0x04
+#define ADSP_PORT_REG_FER_CLEAR 0x08
+#define ADSP_PORT_REG_DATA 0x0c
+#define ADSP_PORT_REG_DATA_SET 0x10
+#define ADSP_PORT_REG_DATA_CLEAR 0x14
+#define ADSP_PORT_REG_DIR 0x18
+#define ADSP_PORT_REG_DIR_SET 0x1c
+#define ADSP_PORT_REG_DIR_CLEAR 0x20
+#define ADSP_PORT_REG_INEN 0x24
+#define ADSP_PORT_REG_INEN_SET 0x28
+#define ADSP_PORT_REG_INEN_CLEAR 0x2c
+#define ADSP_PORT_REG_PORT_MUX 0x30
+#define ADSP_PORT_REG_DATA_TGL 0x34
+#define ADSP_PORT_REG_POLAR 0x38
+#define ADSP_PORT_REG_POLAR_SET 0x3c
+#define ADSP_PORT_REG_POLAR_CLEAR 0x40
+#define ADSP_PORT_REG_LOCK 0x44
+#define ADSP_PORT_REG_TRIG_TGL 0x48
+
+struct adsp_gpio_priv {
+ void __iomem *base;
+ int ngpio;
+};
+
+static u32 get_port(unsigned int pin)
+{
+ return pin / ADSP_PORT_PIN_SIZE;
+}
+
+static u32 get_offset(unsigned int pin)
+{
+ return pin % ADSP_PORT_PIN_SIZE;
+}
+
+static int adsp_gpio_input(struct udevice *udev, unsigned int pin)
+{
+ struct adsp_gpio_priv *priv = dev_get_priv(udev);
+ u32 port, offset;
+ void __iomem *portbase;
+
+ if (pin < priv->ngpio) {
+ port = get_port(pin);
+ offset = get_offset(pin);
+ portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_FER_CLEAR);
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DIR_CLEAR);
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_INEN_SET);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int adsp_gpio_output(struct udevice *udev, unsigned int pin, int value)
+{
+ struct adsp_gpio_priv *priv = dev_get_priv(udev);
+ u32 port, offset;
+ void __iomem *portbase;
+
+ if (pin < priv->ngpio) {
+ port = get_port(pin);
+ offset = get_offset(pin);
+ portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_FER_CLEAR);
+
+ if (value)
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_SET);
+ else
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_CLEAR);
+
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DIR_SET);
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_INEN_CLEAR);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int adsp_gpio_get_value(struct udevice *udev, unsigned int pin)
+{
+ struct adsp_gpio_priv *priv = dev_get_priv(udev);
+ u32 port, offset;
+ u16 val;
+ void __iomem *portbase;
+
+ if (pin < priv->ngpio) {
+ port = get_port(pin);
+ offset = get_offset(pin);
+ portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+ val = ioread16(portbase + ADSP_PORT_REG_DATA);
+ return !!(val & BIT(offset));
+ }
+
+ return 0;
+}
+
+static int adsp_gpio_set_value(struct udevice *udev, unsigned int pin, int value)
+{
+ struct adsp_gpio_priv *priv = dev_get_priv(udev);
+ u32 port, offset;
+ void __iomem *portbase;
+
+ if (pin < priv->ngpio) {
+ port = get_port(pin);
+ offset = get_offset(pin);
+ portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+ if (value)
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_SET);
+ else
+ iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_CLEAR);
+ }
+
+ return 0;
+}
+
+static const struct dm_gpio_ops adsp_gpio_ops = {
+ .direction_input = adsp_gpio_input,
+ .direction_output = adsp_gpio_output,
+ .get_value = adsp_gpio_get_value,
+ .set_value = adsp_gpio_set_value,
+};
+
+static int adsp_gpio_probe(struct udevice *udev)
+{
+ struct adsp_gpio_priv *priv = dev_get_priv(udev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
+
+ uc_priv->bank_name = "adsp gpio";
+ uc_priv->gpio_count = dev_read_u32_default(udev, "adi,ngpios", 0);
+
+ if (!uc_priv->gpio_count) {
+ dev_err(udev, "Missing adi,ngpios property!\n");
+ return -ENOENT;
+ }
+
+ priv->base = dev_read_addr_ptr(udev);
+ priv->ngpio = uc_priv->gpio_count;
+
+ return 0;
+}
+
+static const struct udevice_id adsp_gpio_match[] = {
+ { .compatible = "adi,adsp-gpio" },
+ { },
+};
+
+U_BOOT_DRIVER(adi_adsp_gpio) = {
+ .name = "adi_adsp_gpio",
+ .id = UCLASS_GPIO,
+ .ops = &adsp_gpio_ops,
+ .probe = adsp_gpio_probe,
+ .priv_auto = sizeof(struct adsp_gpio_priv),
+ .of_match = adsp_gpio_match,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c
index e84038f312e..523ca8473a8 100644
--- a/drivers/gpio/pca953x_gpio.c
+++ b/drivers/gpio/pca953x_gpio.c
@@ -393,6 +393,8 @@ static const struct udevice_id pca953x_ids[] = {
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+ { .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
{ .compatible = "maxim,max7310", .data = OF_953X(8, 0), },
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index cdae6825736..46e76385961 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -154,6 +154,13 @@ config SPL_DM_I2C_GPIO
bindings are supported.
Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+config SYS_I2C_ADI
+ bool "ADI I2C driver"
+ depends on DM_I2C && ARCH_SC5XX
+ help
+ Add support for the ADI (Analog Devices) I2C driver as used
+ in SC57X, SC58X, SC59X, SC59X_64.
+
config SYS_I2C_AT91
bool "Atmel I2C driver"
depends on DM_I2C && ARCH_AT91
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index bebd728e7da..2713289f7db 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_$(XPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
obj-$(CONFIG_$(XPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_$(XPL_)SYS_I2C_LEGACY) += i2c_core.o
+obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
obj-$(CONFIG_SYS_I2C_AST2600) += ast2600_i2c.o
obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
diff --git a/drivers/i2c/adi_i2c.c b/drivers/i2c/adi_i2c.c
new file mode 100644
index 00000000000..4cddcfa6b7f
--- /dev/null
+++ b/drivers/i2c/adi_i2c.c
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Converted to driver model by Nathan Barrett-Morrison
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <mapmem.h>
+#include <linux/io.h>
+
+#define CLKLOW(x) ((x) & 0xFF) // Periods Clock Is Held Low
+#define CLKHI(y) (((y) & 0xFF) << 0x8) // Periods Clock Is High
+
+#define PRESCALE 0x007F // SCLKs Per Internal Time Reference (10MHz)
+#define TWI_ENA 0x0080 // TWI Enable
+#define SCCB 0x0200 // SCCB Compatibility Enable
+
+#define SEN 0x0001 // Slave Enable
+#define SADD_LEN 0x0002 // Slave Address Length
+#define STDVAL 0x0004 // Slave Transmit Data Valid
+#define TSC_NAK 0x0008 // NAK Generated At Conclusion Of Transfer
+#define GEN 0x0010 // General Call Adrress Matching Enabled
+
+#define SDIR 0x0001 // Slave Transfer Direction
+#define GCALL 0x0002 // General Call Indicator
+
+#define MEN 0x0001 // Master Mode Enable
+#define MADD_LEN 0x0002 // Master Address Length
+#define MDIR 0x0004 // Master Transmit Direction (RX/TX*)
+#define FAST 0x0008 // Use Fast Mode Timing Specs
+#define STOP 0x0010 // Issue Stop Condition
+#define RSTART 0x0020 // Repeat Start or Stop* At End Of Transfer
+#define DCNT 0x3FC0 // Data Bytes To Transfer
+#define SDAOVR 0x4000 // Serial Data Override
+#define SCLOVR 0x8000 // Serial Clock Override
+
+#define MPROG 0x0001 // Master Transfer In Progress
+#define LOSTARB 0x0002 // Lost Arbitration Indicator (Xfer Aborted)
+#define ANAK 0x0004 // Address Not Acknowledged
+#define DNAK 0x0008 // Data Not Acknowledged
+#define BUFRDERR 0x0010 // Buffer Read Error
+#define BUFWRERR 0x0020 // Buffer Write Error
+#define SDASEN 0x0040 // Serial Data Sense
+#define SCLSEN 0x0080 // Serial Clock Sense
+#define BUSBUSY 0x0100 // Bus Busy Indicator
+
+#define SINIT 0x0001 // Slave Transfer Initiated
+#define SCOMP 0x0002 // Slave Transfer Complete
+#define SERR 0x0004 // Slave Transfer Error
+#define SOVF 0x0008 // Slave Overflow
+#define MCOMP 0x0010 // Master Transfer Complete
+#define MERR 0x0020 // Master Transfer Error
+#define XMTSERV 0x0040 // Transmit FIFO Service
+#define RCVSERV 0x0080 // Receive FIFO Service
+
+#define XMTFLUSH 0x0001 // Transmit Buffer Flush
+#define RCVFLUSH 0x0002 // Receive Buffer Flush
+#define XMTINTLEN 0x0004 // Transmit Buffer Interrupt Length
+#define RCVINTLEN 0x0008 // Receive Buffer Interrupt Length
+
+#define XMTSTAT 0x0003 // Transmit FIFO Status
+#define XMT_EMPTY 0x0000 // Transmit FIFO Empty
+#define XMT_HALF 0x0001 // Transmit FIFO Has 1 Byte To Write
+#define XMT_FULL 0x0003 // Transmit FIFO Full (2 Bytes To Write)
+
+#define RCVSTAT 0x000C // Receive FIFO Status
+#define RCV_EMPTY 0x0000 // Receive FIFO Empty
+#define RCV_HALF 0x0004 // Receive FIFO Has 1 Byte To Read
+#define RCV_FULL 0x000C // Receive FIFO Full (2 Bytes To Read)
+
+/* Every register is 32bit aligned, but only 16bits in size */
+#define ureg(name) u16 name; u16 __pad_##name
+
+struct twi_regs {
+ ureg(clkdiv);
+ ureg(control);
+ ureg(slave_ctl);
+ ureg(slave_stat);
+ ureg(slave_addr);
+ ureg(master_ctl);
+ ureg(master_stat);
+ ureg(master_addr);
+ ureg(int_stat);
+ ureg(int_mask);
+ ureg(fifo_ctl);
+ ureg(fifo_stat);
+ u8 __pad[0x50];
+
+ ureg(xmt_data8);
+ ureg(xmt_data16);
+ ureg(rcv_data8);
+ ureg(rcv_data16);
+};
+
+#undef ureg
+
+/*
+ * The way speed is changed into duty often results in integer truncation
+ * with 50% duty, so we'll force rounding up to the next duty by adding 1
+ * to the max. In practice this will get us a speed of something like
+ * 385 KHz. The other limit is easy to handle as it is only 8 bits.
+ */
+#define I2C_SPEED_MAX 400000
+#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
+#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
+#define I2C_DUTY_MIN 0xff /* 8 bit limited */
+
+#define I2C_M_COMBO 0x4
+#define I2C_M_STOP 0x2
+#define I2C_M_READ 0x1
+
+/*
+ * All transfers are described by this data structure
+ */
+struct adi_i2c_msg {
+ u8 flags;
+ u32 len; /* msg length */
+ u8 *buf; /* pointer to msg data */
+ u32 olen; /* addr length */
+ u8 *obuf; /* addr buffer */
+};
+
+struct adi_i2c_dev {
+ struct twi_regs __iomem *base;
+ u32 i2c_clk;
+ uint speed;
+};
+
+/* Allow msec timeout per ~byte transfer */
+#define I2C_TIMEOUT 10
+
+/**
+ * wait_for_completion - manage the actual i2c transfer
+ * @msg: the i2c msg
+ */
+static int wait_for_completion(struct twi_regs *twi, struct adi_i2c_msg *msg)
+{
+ u16 int_stat;
+ ulong timebase = get_timer(0);
+
+ do {
+ int_stat = ioread16(&twi->int_stat);
+
+ if (int_stat & XMTSERV) {
+ iowrite16(XMTSERV, &twi->int_stat);
+ if (msg->olen) {
+ iowrite16(*(msg->obuf++), &twi->xmt_data8);
+ --msg->olen;
+ } else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
+ iowrite16(*(msg->buf++), &twi->xmt_data8);
+ --msg->len;
+ } else {
+ if (msg->flags & I2C_M_COMBO)
+ setbits_16(&twi->master_ctl, RSTART | MDIR);
+ else
+ setbits_16(&twi->master_ctl, STOP);
+ }
+ }
+ if (int_stat & RCVSERV) {
+ iowrite16(RCVSERV, &twi->int_stat);
+ if (msg->len) {
+ *(msg->buf++) = ioread16(&twi->rcv_data8);
+ --msg->len;
+ } else if (msg->flags & I2C_M_STOP) {
+ setbits_16(&twi->master_ctl, STOP);
+ }
+ }
+ if (int_stat & MERR) {
+ pr_err("%s: master transmit terror: %d\n", __func__,
+ ioread16(&twi->master_stat));
+ iowrite16(MERR, &twi->int_stat);
+ return -EIO;
+ }
+ if (int_stat & MCOMP) {
+ iowrite16(MCOMP, &twi->int_stat);
+ if (msg->flags & I2C_M_COMBO && msg->len) {
+ u16 mlen = min(msg->len, 0xffu) << 6;
+ clrsetbits_16(&twi->master_ctl, RSTART, mlen | MEN | MDIR);
+ } else {
+ break;
+ }
+ }
+
+ /* If we were able to do something, reset timeout */
+ if (int_stat)
+ timebase = get_timer(0);
+
+ } while (get_timer(timebase) < I2C_TIMEOUT);
+
+ return 0;
+}
+
+static int i2c_transfer(struct twi_regs *twi, u8 chip, u8 *offset,
+ int olen, u8 *buffer, int len, u8 flags)
+{
+ int ret;
+ u16 ctl;
+
+ struct adi_i2c_msg msg = {
+ .flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
+ .buf = buffer,
+ .len = len,
+ .obuf = offset,
+ .olen = olen,
+ };
+
+ /* wait for things to settle */
+ while (ioread16(&twi->master_stat) & BUSBUSY)
+ if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
+ return -EINTR;
+
+ /* Set Transmit device address */
+ iowrite16(chip, &twi->master_addr);
+
+ /* Clear the FIFO before starting things */
+ iowrite16(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl);
+ iowrite16(0, &twi->fifo_ctl);
+
+ /* Prime the pump */
+ if (msg.olen) {
+ len = (msg.flags & I2C_M_COMBO) ? msg.olen : msg.olen + len;
+ iowrite16(*(msg.obuf++), &twi->xmt_data8);
+ --msg.olen;
+ } else if (!(msg.flags & I2C_M_READ) && msg.len) {
+ iowrite16(*(msg.buf++), &twi->xmt_data8);
+ --msg.len;
+ }
+
+ /* clear int stat */
+ iowrite16(-1, &twi->master_stat);
+ iowrite16(-1, &twi->int_stat);
+ iowrite16(0, &twi->int_mask);
+
+ /* Master enable */
+ ctl = ioread16(&twi->master_ctl);
+ ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN |
+ ((msg.flags & I2C_M_READ) ? MDIR : 0);
+ iowrite16(ctl, &twi->master_ctl);
+
+ /* Process the rest */
+ ret = wait_for_completion(twi, &msg);
+
+ clrbits_16(&twi->master_ctl, MEN);
+ clrbits_16(&twi->control, TWI_ENA);
+ setbits_16(&twi->control, TWI_ENA);
+ return ret;
+}
+
+static int adi_i2c_read(struct twi_regs *twi, u8 chip,
+ u8 *offset, int olen, u8 *buffer, int len)
+{
+ return i2c_transfer(twi, chip, offset, olen, buffer,
+ len, olen ? I2C_M_COMBO : I2C_M_READ);
+}
+
+static int adi_i2c_write(struct twi_regs *twi, u8 chip,
+ u8 *offset, int olen, u8 *buffer, int len)
+{
+ return i2c_transfer(twi, chip, offset, olen, buffer, len, 0);
+}
+
+static int adi_i2c_set_bus_speed(struct udevice *bus, uint speed)
+{
+ struct adi_i2c_dev *dev = dev_get_priv(bus);
+ struct twi_regs *twi = dev->base;
+ u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
+
+ /* Set TWI interface clock */
+ if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
+ return -1;
+ clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
+ iowrite16(clkdiv, &twi->clkdiv);
+
+ /* Don't turn it on */
+ iowrite16(speed > 100000 ? FAST : 0, &twi->master_ctl);
+
+ return 0;
+}
+
+static int adi_i2c_of_to_plat(struct udevice *bus)
+{
+ struct adi_i2c_dev *dev = dev_get_priv(bus);
+ struct clk clock;
+ u32 ret;
+
+ dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct twi_regs));
+
+ if (!dev->base)
+ return -ENOMEM;
+
+ dev->speed = dev_read_u32_default(bus, "clock-frequency",
+ I2C_SPEED_FAST_RATE);
+
+ ret = clk_get_by_name(bus, "i2c", &clock);
+ if (ret < 0)
+ printf("%s: Can't get I2C clk: %d\n", __func__, ret);
+ else
+ dev->i2c_clk = clk_get_rate(&clock);
+
+ return 0;
+}
+
+static int adi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ struct adi_i2c_dev *dev = dev_get_priv(bus);
+ u8 byte;
+
+ return adi_i2c_read(dev->base, chip_addr, NULL, 0, &byte, 1);
+}
+
+static int adi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct adi_i2c_dev *dev = dev_get_priv(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /*
+ * We expect either two messages (one with an offset and one with the
+ * actual data) or one message (just data)
+ */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported.", __func__);
+ return -EINVAL;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return adi_i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
+ dmsg->buf, dmsg->len);
+ else
+ return adi_i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
+ dmsg->buf, dmsg->len);
+}
+
+int adi_i2c_probe(struct udevice *bus)
+{
+ struct adi_i2c_dev *dev = dev_get_priv(bus);
+ struct twi_regs *twi = dev->base;
+
+ u16 prescale = ((dev->i2c_clk / 1000 / 1000 + 5) / 10) & 0x7F;
+
+ /* Set TWI internal clock as 10MHz */
+ iowrite16(prescale, &twi->control);
+
+ /* Set TWI interface clock as specified */
+ adi_i2c_set_bus_speed(bus, dev->speed);
+
+ /* Enable it */
+ iowrite16(TWI_ENA | prescale, &twi->control);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops adi_i2c_ops = {
+ .xfer = adi_i2c_xfer,
+ .probe_chip = adi_i2c_probe_chip,
+ .set_bus_speed = adi_i2c_set_bus_speed,
+};
+
+static const struct udevice_id adi_i2c_ids[] = {
+ { .compatible = "adi-i2c", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_adi) = {
+ .name = "i2c_adi",
+ .id = UCLASS_I2C,
+ .of_match = adi_i2c_ids,
+ .probe = adi_i2c_probe,
+ .of_to_plat = adi_i2c_of_to_plat,
+ .priv_auto = sizeof(struct adi_i2c_dev),
+ .ops = &adi_i2c_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 67d5ac1a742..4d9f004ebad 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -21,6 +21,13 @@ config APPLE_MBOX
such as the System Management Controller (SMC) and NVMe and this
driver is required to get that functionality up and running.
+config IMX_MU_MBOX
+ bool "Enable i.MX MU MBOX support"
+ depends on DM_MAILBOX
+ help
+ Enable support for i.MX Messaging Unit for communication with other
+ processors on the SoC using mailbox interface
+
config SANDBOX_MBOX
bool "Enable the sandbox mailbox test driver"
depends on DM_MAILBOX && SANDBOX
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 6072fa1956b..574add60005 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_$(XPL_)DM_MAILBOX) += mailbox-uclass.o
obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o
+obj-$(CONFIG_IMX_MU_MBOX) += imx-mailbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
new file mode 100644
index 00000000000..b1e0465e7a8
--- /dev/null
+++ b/drivers/mailbox/imx-mailbox.c
@@ -0,0 +1,443 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <mailbox-uclass.h>
+#include <linux/bitfield.h>
+#include <linux/bug.h>
+#include <linux/iopoll.h>
+#include <linux/compat.h>
+
+/* This driver only exposes the status bits to keep with the
+ * polling methodology of u-boot.
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+#define IMX_MU_CHANS 24
+
+#define IMX_MU_V2_PAR_OFF 0x4
+#define IMX_MU_V2_TR_MASK GENMASK(7, 0)
+#define IMX_MU_V2_RR_MASK GENMASK(15, 8)
+
+enum imx_mu_chan_type {
+ IMX_MU_TYPE_TX = 0, /* Tx */
+ IMX_MU_TYPE_RX = 1, /* Rx */
+ IMX_MU_TYPE_TXDB = 2, /* Tx doorbell */
+ IMX_MU_TYPE_RXDB = 3, /* Rx doorbell */
+ IMX_MU_TYPE_RST = 4, /* Reset */
+ IMX_MU_TYPE_TXDB_V2 = 5, /* Tx doorbell with S/W ACK */
+};
+
+enum imx_mu_xcr {
+ IMX_MU_CR,
+ IMX_MU_GIER,
+ IMX_MU_GCR,
+ IMX_MU_TCR,
+ IMX_MU_RCR,
+ IMX_MU_xCR_MAX,
+};
+
+enum imx_mu_xsr {
+ IMX_MU_SR,
+ IMX_MU_GSR,
+ IMX_MU_TSR,
+ IMX_MU_RSR,
+ IMX_MU_xSR_MAX,
+};
+
+struct imx_mu_con_priv {
+ unsigned int idx;
+ enum imx_mu_chan_type type;
+ struct mbox_chan *chan;
+};
+
+enum imx_mu_type {
+ IMX_MU_V1,
+ IMX_MU_V2 = BIT(1),
+ IMX_MU_V2_S4 = BIT(15),
+ IMX_MU_V2_IRQ = BIT(16),
+};
+
+struct imx_mu {
+ void __iomem *base;
+ const struct imx_mu_dcfg *dcfg;
+ u32 num_tr;
+ u32 num_rr;
+ /* use pointers to channel as a way to reserve channels */
+ struct mbox_chan *channels[IMX_MU_CHANS];
+ struct imx_mu_con_priv con_priv[IMX_MU_CHANS];
+};
+
+struct imx_mu_dcfg {
+ int (*tx)(struct imx_mu *plat, struct imx_mu_con_priv *cp, const void *data);
+ int (*rx)(struct imx_mu *plat, struct imx_mu_con_priv *cp);
+ int (*rxdb)(struct imx_mu *plat, struct imx_mu_con_priv *cp);
+ int (*init)(struct imx_mu *plat);
+ int (*of_xlate)(struct mbox_chan *chan, struct ofnode_phandle_args *args);
+ enum imx_mu_type type;
+ u32 xTR; /* Transmit Register0 */
+ u32 xRR; /* Receive Register0 */
+ u32 xSR[IMX_MU_xSR_MAX]; /* Status Registers */
+ u32 xCR[IMX_MU_xCR_MAX]; /* Control Registers */
+};
+
+#define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
+#define IMX_MU_xSR_RFn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
+#define IMX_MU_xSR_TEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
+
+/* General Purpose Interrupt Enable */
+#define IMX_MU_xCR_GIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
+/* Receive Interrupt Enable */
+#define IMX_MU_xCR_RIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
+/* Transmit Interrupt Enable */
+#define IMX_MU_xCR_TIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
+/* General Purpose Interrupt Request */
+#define IMX_MU_xCR_GIRn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x))))
+/* MU reset */
+#define IMX_MU_xCR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(5))
+#define IMX_MU_xSR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(7))
+
+static void imx_mu_write(struct imx_mu *plat, u32 val, u32 offs)
+{
+ iowrite32(val, plat->base + offs);
+}
+
+static u32 imx_mu_read(struct imx_mu *plat, u32 offs)
+{
+ return ioread32(plat->base + offs);
+}
+
+static u32 imx_mu_xcr_rmw(struct imx_mu *plat, enum imx_mu_xcr type, u32 set, u32 clr)
+{
+ u32 val;
+
+ val = imx_mu_read(plat, plat->dcfg->xCR[type]);
+ val &= ~clr;
+ val |= set;
+ imx_mu_write(plat, val, plat->dcfg->xCR[type]);
+
+ return val;
+}
+
+/* check that the channel is open or owned by caller */
+static int imx_mu_check_channel(struct mbox_chan *chan)
+{
+ struct imx_mu *plat = dev_get_plat(chan->dev);
+
+ if (plat->channels[chan->id]) {
+ /* if reserved check that caller owns */
+ if (plat->channels[chan->id] == chan)
+ return 1; /* caller owns the channel */
+
+ return -EACCES;
+ }
+
+ return 0; /* channel empty */
+}
+
+static int imx_mu_chan_request(struct mbox_chan *chan)
+{
+ struct imx_mu *plat = dev_get_plat(chan->dev);
+ struct imx_mu_con_priv *cp;
+ enum imx_mu_chan_type type;
+ int idx;
+
+ type = chan->id / 4;
+ idx = chan->id % 4;
+
+ if (imx_mu_check_channel(chan) < 0) /* check if channel already in use */
+ return -EPERM;
+
+ plat->channels[chan->id] = chan;
+ chan->con_priv = kcalloc(1, sizeof(struct imx_mu_con_priv), 0);
+ if (!chan->con_priv)
+ return -ENOMEM;
+ cp = chan->con_priv;
+ cp->idx = idx;
+ cp->type = type;
+ cp->chan = chan;
+
+ switch (type) {
+ case IMX_MU_TYPE_RX:
+ imx_mu_xcr_rmw(plat, IMX_MU_RCR, IMX_MU_xCR_RIEn(plat->dcfg->type, idx), 0);
+ break;
+ case IMX_MU_TYPE_TXDB_V2:
+ case IMX_MU_TYPE_TXDB:
+ case IMX_MU_TYPE_RXDB:
+ imx_mu_xcr_rmw(plat, IMX_MU_GIER, IMX_MU_xCR_GIEn(plat->dcfg->type, idx), 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int imx_mu_chan_free(struct mbox_chan *chan)
+{
+ struct imx_mu *plat = dev_get_plat(chan->dev);
+ struct imx_mu_con_priv *cp = chan->con_priv;
+
+ if (imx_mu_check_channel(chan) <= 0) /* check that the channel is also not empty */
+ return -EINVAL;
+
+ /* if you own channel and channel is NOT empty */
+ plat->channels[chan->id] = NULL;
+ switch (cp->type) {
+ case IMX_MU_TYPE_TX:
+ imx_mu_xcr_rmw(plat, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(plat->dcfg->type, cp->idx));
+ break;
+ case IMX_MU_TYPE_RX:
+ imx_mu_xcr_rmw(plat, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(plat->dcfg->type, cp->idx));
+ break;
+ case IMX_MU_TYPE_TXDB_V2:
+ case IMX_MU_TYPE_TXDB:
+ case IMX_MU_TYPE_RXDB:
+ imx_mu_xcr_rmw(plat, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(plat->dcfg->type, cp->idx));
+ break;
+ default:
+ break;
+ }
+
+ kfree(cp);
+
+ return 0;
+}
+
+static int imx_mu_send(struct mbox_chan *chan, const void *data)
+{
+ struct imx_mu *plat = dev_get_plat(chan->dev);
+ struct imx_mu_con_priv *cp = chan->con_priv;
+
+ if (imx_mu_check_channel(chan) < 1) /* return if channel isn't owned */
+ return -EPERM;
+
+ return plat->dcfg->tx(plat, cp, data);
+}
+
+static int imx_mu_recv(struct mbox_chan *chan, void *data)
+{
+ struct imx_mu *plat = dev_get_plat(chan->dev);
+ struct imx_mu_con_priv *cp = chan->con_priv;
+ u32 ctrl, val;
+
+ if (imx_mu_check_channel(chan) < 1) /* return if channel isn't owned */
+ return -EPERM;
+
+ switch (cp->type) {
+ case IMX_MU_TYPE_TXDB_V2:
+ case IMX_MU_TYPE_RXDB:
+ /* check if GSR[GIRn] bit is set */
+ if (readx_poll_timeout(ioread32, plat->base + plat->dcfg->xSR[IMX_MU_GSR],
+ val, val & BIT(cp->idx), 1000000) < 0)
+ return -EBUSY;
+
+ ctrl = imx_mu_read(plat, plat->dcfg->xCR[IMX_MU_GIER]);
+ val = imx_mu_read(plat, plat->dcfg->xSR[IMX_MU_GSR]);
+ val &= IMX_MU_xSR_GIPn(plat->dcfg->type, cp->idx) &
+ (ctrl & IMX_MU_xCR_GIEn(plat->dcfg->type, cp->idx));
+ break;
+ default:
+ dev_warn(chan->dev, "Unhandled channel type %d\n", cp->type);
+ return -EOPNOTSUPP;
+ };
+
+ if (val == IMX_MU_xSR_GIPn(plat->dcfg->type, cp->idx))
+ plat->dcfg->rxdb(plat, cp);
+
+ return 0;
+}
+
+static int imx_mu_of_to_plat(struct udevice *dev)
+{
+ struct imx_mu *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ plat->base = (struct mu_type *)addr;
+
+ return 0;
+}
+
+static int imx_mu_init_generic(struct imx_mu *plat)
+{
+ unsigned int i;
+ unsigned int val;
+
+ if (plat->num_rr > 4 || plat->num_tr > 4) {
+ WARN_ONCE(true, "%s not support TR/RR larger than 4\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ /* Set default MU configuration */
+ for (i = 0; i < IMX_MU_xCR_MAX; i++)
+ imx_mu_write(plat, 0, plat->dcfg->xCR[i]);
+
+ /* Clear any pending GIP */
+ val = imx_mu_read(plat, plat->dcfg->xSR[IMX_MU_GSR]);
+ imx_mu_write(plat, val, plat->dcfg->xSR[IMX_MU_GSR]);
+
+ /* Clear any pending RSR */
+ for (i = 0; i < plat->num_rr; i++)
+ imx_mu_read(plat, plat->dcfg->xRR + i * 4);
+
+ return 0;
+}
+
+static int imx_mu_generic_of_xlate(struct mbox_chan *chan, struct ofnode_phandle_args *args)
+{
+ enum imx_mu_chan_type type;
+ int idx, cid;
+
+ if (args->args_count != 2) {
+ dev_err(chan->dev, "Invalid argument count %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ type = args->args[0]; /* channel type */
+ idx = args->args[1]; /* index */
+
+ cid = type * 4 + idx;
+ if (cid >= IMX_MU_CHANS) {
+ dev_err(chan->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n",
+ cid, type, idx);
+ return -EINVAL;
+ }
+
+ chan->id = cid;
+
+ return 0;
+}
+
+static int imx_mu_generic_tx(struct imx_mu *plat, struct imx_mu_con_priv *cp,
+ const void *data)
+{
+ switch (cp->type) {
+ case IMX_MU_TYPE_TXDB_V2:
+ imx_mu_xcr_rmw(plat, IMX_MU_GCR, IMX_MU_xCR_GIRn(plat->dcfg->type, cp->idx), 0);
+ break;
+ default:
+ dev_warn(cp->chan->dev, "Send data on wrong channel type: %d\n", cp->type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int imx_mu_generic_rxdb(struct imx_mu *plat, struct imx_mu_con_priv *cp)
+{
+ imx_mu_write(plat, IMX_MU_xSR_GIPn(plat->dcfg->type, cp->idx),
+ plat->dcfg->xSR[IMX_MU_GSR]);
+
+ return 0;
+}
+
+static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = {
+ .tx = imx_mu_generic_tx,
+ .rxdb = imx_mu_generic_rxdb,
+ .init = imx_mu_init_generic,
+ .of_xlate = imx_mu_generic_of_xlate,
+ .type = IMX_MU_V1,
+ .xTR = 0x0,
+ .xRR = 0x10,
+ .xSR = {0x20, 0x20, 0x20, 0x20},
+ .xCR = {0x24, 0x24, 0x24, 0x24, 0x24},
+};
+
+static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = {
+ .tx = imx_mu_generic_tx,
+ .rxdb = imx_mu_generic_rxdb,
+ .init = imx_mu_init_generic,
+ .of_xlate = imx_mu_generic_of_xlate,
+ .type = IMX_MU_V1,
+ .xTR = 0x20,
+ .xRR = 0x40,
+ .xSR = {0x60, 0x60, 0x60, 0x60},
+ .xCR = {0x64, 0x64, 0x64, 0x64, 0x64},
+};
+
+static const struct imx_mu_dcfg imx_mu_cfg_imx95 = {
+ .tx = imx_mu_generic_tx,
+ .rxdb = imx_mu_generic_rxdb,
+ .init = imx_mu_init_generic,
+ .of_xlate = imx_mu_generic_of_xlate,
+ .type = IMX_MU_V2,
+ .xTR = 0x200,
+ .xRR = 0x280,
+ .xSR = {0xC, 0x118, 0x124, 0x12C},
+ .xCR = {0x8, 0x110, 0x114, 0x120, 0x128},
+};
+
+static const struct udevice_id ids[] = {
+ { .compatible = "fsl,imx6sx-mu", .data = (ulong)&imx_mu_cfg_imx6sx },
+ { .compatible = "fsl,imx7ulp-mu", .data = (ulong)&imx_mu_cfg_imx7ulp },
+ { .compatible = "fsl,imx95-mu", .data = (ulong)&imx_mu_cfg_imx95 },
+ { }
+};
+
+int imx_mu_of_xlate(struct mbox_chan *chan, struct ofnode_phandle_args *args)
+{
+ struct imx_mu *plat = dev_get_plat(chan->dev);
+
+ return plat->dcfg->of_xlate(chan, args);
+}
+
+struct mbox_ops imx_mu_ops = {
+ .of_xlate = imx_mu_of_xlate,
+ .request = imx_mu_chan_request,
+ .rfree = imx_mu_chan_free,
+ .send = imx_mu_send,
+ .recv = imx_mu_recv,
+};
+
+static void imx_mu_get_tr_rr(struct imx_mu *plat)
+{
+ u32 val;
+
+ if (plat->dcfg->type & IMX_MU_V2) {
+ val = imx_mu_read(plat, IMX_MU_V2_PAR_OFF);
+ plat->num_tr = FIELD_GET(IMX_MU_V2_TR_MASK, val);
+ plat->num_rr = FIELD_GET(IMX_MU_V2_RR_MASK, val);
+ } else {
+ plat->num_tr = 4;
+ plat->num_rr = 4;
+ }
+}
+
+static int imx_mu_probe(struct udevice *dev)
+{
+ struct imx_mu *plat = dev_get_plat(dev);
+ int ret;
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ plat->dcfg = (void *)dev_get_driver_data(dev);
+
+ imx_mu_get_tr_rr(plat);
+
+ ret = plat->dcfg->init(plat);
+ if (ret) {
+ dev_err(dev, "Failed to init MU\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(imx_mu) = {
+ .name = "imx-mu",
+ .id = UCLASS_MAILBOX,
+ .of_match = ids,
+ .of_to_plat = imx_mu_of_to_plat,
+ .plat_auto = sizeof(struct imx_mu),
+ .probe = imx_mu_probe,
+ .ops = &imx_mu_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c
index 713d93a200c..851aa737c03 100644
--- a/drivers/mailbox/zynqmp-ipi.c
+++ b/drivers/mailbox/zynqmp-ipi.c
@@ -270,5 +270,4 @@ U_BOOT_DRIVER(zynqmp_ipi) = {
.id = UCLASS_NOP,
.of_match = zynqmp_ipi_ids,
.probe = zynqmp_ipi_probe,
- .flags = DM_FLAG_PROBE_AFTER_BIND,
};
diff --git a/drivers/memory/ti-gpmc.c b/drivers/memory/ti-gpmc.c
index e979c431e33..29e02f12ae0 100644
--- a/drivers/memory/ti-gpmc.c
+++ b/drivers/memory/ti-gpmc.c
@@ -1242,4 +1242,5 @@ U_BOOT_DRIVER(ti_gpmc) = {
.of_match = gpmc_dt_ids,
.probe = gpmc_probe,
.flags = DM_FLAG_ALLOC_PRIV_DMA,
+ .priv_auto = sizeof(struct ti_gpmc),
};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index da84b35e804..834e0285097 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -468,6 +468,13 @@ config STM32MP_FUSE
for STM32MP architecture.
This API is needed for CMD_FUSE.
+config K3_FUSE
+ bool "Enable TI K3 fuse wrapper providing the fuse API"
+ depends on MISC && CMD_FUSE && CMD_FUSE_WRITEBUFF
+ help
+ If you say Y here, you will get support for the fuse API (OTP)
+ for TI K3 architecture.
+
config STM32_RCC
bool "Enable RCC driver for the STM32 SoC's family"
depends on (ARCH_STM32 || ARCH_STM32MP) && MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index dac805e4cdd..0b81ba2604f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_$(XPL_)I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
obj-$(CONFIG_IMX8) += imx8/
obj-$(CONFIG_IMX_ELE) += imx_ele/
+obj-$(CONFIG_K3_FUSE) += k3_fuse.o
obj-$(CONFIG_LED_STATUS) += status_led.o
obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
diff --git a/drivers/misc/k3_fuse.c b/drivers/misc/k3_fuse.c
new file mode 100644
index 00000000000..4a8ff1f2523
--- /dev/null
+++ b/drivers/misc/k3_fuse.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Texas Instruments Incorporated, <www.ti.com>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <fuse.h>
+#include <linux/arm-smccc.h>
+#include <string.h>
+
+#define K3_SIP_OTP_WRITEBUFF 0xC2000000
+#define K3_SIP_OTP_WRITE 0xC2000001
+#define K3_SIP_OTP_READ 0xC2000002
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ struct arm_smccc_res res;
+
+ if (bank != 0U) {
+ printf("Invalid bank argument, ONLY bank 0 is supported\n");
+ return -EINVAL;
+ }
+
+ /* Make SiP SMC call and send the word in the parameter register */
+ arm_smccc_smc(K3_SIP_OTP_READ, word,
+ 0, 0, 0, 0, 0, 0, &res);
+
+ *val = res.a1;
+ if (res.a0 != 0)
+ printf("SMC call failed: Error code %lu\n", res.a0);
+
+ return res.a0;
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ return -EPERM;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ struct arm_smccc_res res;
+ u32 mask = val;
+
+ if (bank != 0U) {
+ printf("Invalid bank argument, ONLY bank 0 is supported\n");
+ return -EINVAL;
+ }
+
+ /* Make SiP SMC call and send the word, val and mask in the parameter register */
+ arm_smccc_smc(K3_SIP_OTP_WRITE, word,
+ val, mask, 0, 0, 0, 0, &res);
+
+ if (res.a0 != 0)
+ printf("SMC call failed: Error code %lu\n", res.a0);
+
+ return res.a0;
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ return -EPERM;
+}
+
+int fuse_writebuff(ulong addr)
+{
+ struct arm_smccc_res res;
+
+ /* Make SiP SMC call and send the addr in the parameter register */
+ arm_smccc_smc(K3_SIP_OTP_WRITEBUFF, (unsigned long)addr,
+ 0, 0, 0, 0, 0, 0, &res);
+
+ if (res.a0 != 0)
+ printf("SMC call failed: Error code %lu\n", res.a0);
+
+ return res.a0;
+}
diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c
index 77cebae5e3f..c6c052ac6c3 100644
--- a/drivers/misc/qfw_acpi.c
+++ b/drivers/misc/qfw_acpi.c
@@ -25,17 +25,18 @@ DECLARE_GLOBAL_DATA_PTR;
*
* @entry : BIOS linker command entry which tells where to allocate memory
* (either high memory or low memory)
- * @addr : The address that should be used for low memory allcation. If the
+ * @addr : The address that should be used for low memory allocation. If the
* memory allocation request is 'ZONE_HIGH' then this parameter will
* be ignored.
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_allocate(struct udevice *dev,
+static int bios_linker_allocate(struct acpi_ctx *ctx, struct udevice *dev,
struct bios_linker_entry *entry, ulong *addr)
{
uint32_t size, align;
struct fw_file *file;
unsigned long aligned_addr;
+ struct acpi_rsdp *rsdp;
align = le32_to_cpu(entry->alloc.align);
/* align must be power of 2 */
@@ -58,7 +59,9 @@ static int bios_linker_allocate(struct udevice *dev,
* If allocation zone is ZONE_FSEG, then we use the 'addr' passed
* in which is low memory
*/
- if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) {
+ if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) {
+ aligned_addr = ALIGN(*addr, align);
+ } else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) {
aligned_addr = (unsigned long)memalign(align, size);
if (!aligned_addr) {
printf("error: allocating resource\n");
@@ -83,8 +86,13 @@ static int bios_linker_allocate(struct udevice *dev,
(void *)aligned_addr);
file->addr = aligned_addr;
+ rsdp = (void *)aligned_addr;
+ if (!strncmp(rsdp->signature, RSDP_SIG, sizeof(rsdp->signature)))
+ ctx->rsdp = rsdp;
+
/* adjust address for low memory allocation */
- if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
+ if (IS_ENABLED(CONFIG_BLOBLIST_TABLES) ||
+ entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
*addr = (aligned_addr + size);
return 0;
@@ -209,19 +217,23 @@ ulong write_acpi_tables(ulong addr)
qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader);
for (i = 0; i < (size / sizeof(*entry)); i++) {
+ log_content("entry %d: addr %lx\n", i, addr);
entry = table_loader + i;
switch (le32_to_cpu(entry->command)) {
case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
- ret = bios_linker_allocate(dev, entry, &addr);
+ log_content(" - %s\n", entry->alloc.file);
+ ret = bios_linker_allocate(ctx, dev, entry, &addr);
if (ret)
goto out;
break;
case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
+ log_content(" - %s\n", entry->pointer.src_file);
ret = bios_linker_add_pointer(dev, entry);
if (ret)
goto out;
break;
case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
+ log_content(" - %s\n", entry->cksum.file);
ret = bios_linker_add_checksum(dev, entry);
if (ret)
goto out;
@@ -246,6 +258,16 @@ out:
free(table_loader);
+ if (!ctx->rsdp) {
+ printf("error: no RSDP found\n");
+ return addr;
+ }
+ struct acpi_rsdp *rsdp = ctx->rsdp;
+
+ rsdp->length = sizeof(*rsdp);
+ rsdp->xsdt_address = 0;
+ rsdp->ext_checksum = table_compute_checksum((u8 *)rsdp, sizeof(*rsdp));
+
gd_set_acpi_start(acpi_get_rsdp_addr());
return addr;
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4827834b4aa..6740591a653 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -292,6 +292,15 @@ config MMC_DW_ROCKCHIP
SD 3.0, SDIO 3.0 and MMC 4.5 and supports common eMMC chips as well
as removeable SD and micro-SD cards.
+config MMC_SDHCI_ADI
+ bool "ADI SD/MMC controller support"
+ depends on ARCH_SC5XX
+ depends on DM_MMC && OF_CONTROL
+ depends on MMC_SDHCI && MMC_SDHCI_ADMA
+ help
+ This enables support for the SD/MMC controller included in some Analog
+ Devices SC5XX Socs.
+
config MMC_DW_SOCFPGA
bool "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
depends on ARCH_SOCFPGA
@@ -919,6 +928,12 @@ config ESDHC_DETECT_QUIRK
bool "QIXIS-based eSDHC quirk detection"
depends on FSL_ESDHC && FSL_QIXIS
+config ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE
+ bool
+ depends on FSL_ESDHC || FSL_ESDHC_IMX
+ def_bool y if ARCH_T1024 || ARCH_T1040 || ARCH_T1042 || ARCH_T2080 \
+ || FSL_ESDHC_IMX
+
config FSL_ESDHC_IMX
bool "Freescale/NXP i.MX eSDHC controller support"
help
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 90e76f90769..94ed28ead71 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o
obj-$(CONFIG_MMC_SDHCI_NPCM) += npcm_sdhci.o
obj-$(CONFIG_MMC_SDHCI_PIC32) += pic32_sdhci.o
obj-$(CONFIG_MMC_SDHCI_ROCKCHIP) += rockchip_sdhci.o
+obj-$(CONFIG_MMC_SDHCI_ADI) += adi_sdhci.o
obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o
obj-$(CONFIG_MMC_SDHCI_SNPS) += snps_sdhci.o
obj-$(CONFIG_MMC_SDHCI_STI) += sti_sdhci.o
diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c
new file mode 100644
index 00000000000..65a22cefb71
--- /dev/null
+++ b/drivers/mmc/adi_sdhci.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * Based on Rockchip's sdhci.c file
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/cache.h>
+
+/* 400KHz is max freq for card ID etc. Use that as min */
+#define EMMC_MIN_FREQ 400000
+
+/* Check if an operation crossed a boundary of size ADMA_BOUNDARY_ALIGN */
+#define ADMA_BOUNDARY_ALGN SZ_128M
+#define BOUNDARY_OK(addr, len) \
+ (((addr) | (ADMA_BOUNDARY_ALGN - 1)) == (((addr) + (len) - 1) | \
+ (ADMA_BOUNDARY_ALGN - 1)))
+
+/* We split a descriptor for every crossing of the ADMA alignment boundary,
+ * so we need an additional descriptor for every expected crossing.
+ * As I understand it, the max expected transaction size is:
+ * CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN
+ *
+ * With the way the SDHCI-ADMA driver is implemented, if ADMA_MAX_LEN was a
+ * clean power of two, we'd only ever need +1 descriptor as the first
+ * descriptor that got split would then bring the remaining DMA
+ * destination addresses into alignment. Unfortunately, it's currently
+ * hardcoded to a non-power-of-two value.
+ *
+ * If that ever becomes parameterized, ADMA max length can be set to
+ * 0x10000, and set this to 1.
+ */
+#define ADMA_POTENTIAL_CROSSINGS \
+ DIV_ROUND_UP((CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN), \
+ ADMA_BOUNDARY_ALGN)
+/* +1 descriptor for each crossing.
+ */
+#define ADMA_TABLE_EXTRA_SZ (ADMA_POTENTIAL_CROSSINGS * ADMA_DESC_LEN)
+
+struct adi_sdhc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+void adi_dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, bool end)
+{
+ int tmplen, offset;
+
+ if (likely(!len || BOUNDARY_OK(addr, len))) {
+ sdhci_adma_write_desc(host, desc, addr, len, end);
+ return;
+ }
+
+ offset = addr & (ADMA_BOUNDARY_ALGN - 1);
+ tmplen = ADMA_BOUNDARY_ALGN - offset;
+ sdhci_adma_write_desc(host, desc, addr, tmplen, false);
+
+ addr += tmplen;
+ len -= tmplen;
+ sdhci_adma_write_desc(host, desc, addr, len, end);
+}
+
+struct sdhci_ops adi_dwcmshc_sdhci_ops = {
+ .adma_write_desc = adi_dwcmshc_adma_write_desc,
+};
+
+static int adi_dwcmshc_sdhci_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct adi_sdhc_plat *plat = dev_get_plat(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ int max_frequency, ret;
+ struct clk clk;
+
+ max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
+ ret = clk_get_by_index(dev, 0, &clk);
+
+ host->quirks = 0;
+ host->max_clk = max_frequency;
+ /*
+ * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
+ * doesn't allow us to clear MMC_MODE_4BIT. Consequently, we don't
+ * check for other bus-width values.
+ */
+ if (host->bus_width == 8)
+ host->host_caps |= MMC_MODE_8BIT;
+
+ host->mmc = &plat->mmc;
+ host->mmc->priv = host;
+ host->mmc->dev = dev;
+ upriv->mmc = host->mmc;
+
+ host->ops = &adi_dwcmshc_sdhci_ops;
+ host->adma_desc_table = memalign(ARCH_DMA_MINALIGN,
+ ADMA_TABLE_SZ + ADMA_TABLE_EXTRA_SZ);
+ host->adma_addr = virt_to_phys(host->adma_desc_table);
+
+ ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
+ if (ret)
+ return ret;
+
+ return sdhci_probe(dev);
+}
+
+static int adi_dwcmshc_sdhci_of_to_plat(struct udevice *dev)
+{
+ struct sdhci_host *host = dev_get_priv(dev);
+
+ host->name = dev->name;
+ host->ioaddr = dev_read_addr_ptr(dev);
+ host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
+
+ return 0;
+}
+
+static int adi_sdhci_bind(struct udevice *dev)
+{
+ struct adi_sdhc_plat *plat = dev_get_plat(dev);
+
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id adi_dwcmshc_sdhci_ids[] = {
+ { .compatible = "adi,dwc-sdhci" },
+ { }
+};
+
+U_BOOT_DRIVER(adi_dwcmshc_sdhci_drv) = {
+ .name = "adi_sdhci",
+ .id = UCLASS_MMC,
+ .of_match = adi_dwcmshc_sdhci_ids,
+ .of_to_plat = adi_dwcmshc_sdhci_of_to_plat,
+ .ops = &sdhci_ops,
+ .bind = adi_sdhci_bind,
+ .probe = adi_dwcmshc_sdhci_probe,
+ .priv_auto = sizeof(struct sdhci_host),
+ .plat_auto = sizeof(struct adi_sdhc_plat),
+};
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c
index d7a45ef0ad0..926113f79d3 100644
--- a/drivers/mmc/fsl_esdhc_imx.c
+++ b/drivers/mmc/fsl_esdhc_imx.c
@@ -40,12 +40,6 @@
#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
-#ifndef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE
-#ifdef CONFIG_FSL_USDHC
-#define ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE 1
-#endif
-#endif
-
DECLARE_GLOBAL_DATA_PTR;
#define SDHCI_IRQ_EN_BITS (IRQSTATEN_CC | IRQSTATEN_TC | \
@@ -376,7 +370,7 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
(timeout == 4 || timeout == 8 || timeout == 12))
timeout++;
- if (IS_ENABLED(ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE))
+ if (IS_ENABLED(CONFIG_ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE))
timeout = 0xE;
esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index 27bb7052fca..ac77fb06bf7 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -10,6 +10,7 @@
#include <clk.h>
#include <dm.h>
#include <malloc.h>
+#include <reset.h>
#include <sdhci.h>
#include <wait_bit.h>
#include <asm/global_data.h>
@@ -153,9 +154,18 @@ static int msm_sdc_probe(struct udevice *dev)
const struct msm_sdhc_variant_info *var_info;
struct sdhci_host *host = &prv->host;
u32 core_version, core_minor, core_major;
+ struct reset_ctl bcr_rst;
u32 caps;
int ret;
+ ret = reset_get_by_index(dev, 0, &bcr_rst);
+ if (!ret) {
+ reset_assert(&bcr_rst);
+ udelay(200);
+ reset_deassert(&bcr_rst);
+ udelay(200);
+ }
+
host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
host->max_clk = 0;
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 0b56d1405be..951e6acd34d 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -92,6 +92,13 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
pll = CCM_MMC_CTRL_PLL6;
pll_hz = clock_get_pll6();
#endif
+ /*
+ * On the D1/R528/T113 mux source 1 refers to PLL_PERIPH0(1x),
+ * like for the older SoCs. However we still have the hidden
+ * divider of 2x, so compensate for that here.
+ */
+ if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+ pll_hz /= 2;
}
div = pll_hz / hz;
@@ -442,6 +449,26 @@ out:
return error;
}
+static void sunxi_mmc_reset(void *regs)
+{
+ /* Reset controller */
+ writel(SUNXI_MMC_GCTRL_RESET, regs + SUNXI_MMC_GCTRL);
+ udelay(1000);
+
+ if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) {
+ /* Reset card */
+ writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST);
+ udelay(10);
+ writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST);
+ udelay(300);
+
+ /* Setup FIFO R/W threshold. Needed on H616. */
+ writel(SUNXI_MMC_THLDC_READ_THLD(512) |
+ SUNXI_MMC_THLDC_WRITE_EN |
+ SUNXI_MMC_THLDC_READ_EN, regs + SUNXI_MMC_THLDC);
+ }
+}
+
/* non-DM code here is used by the (ARM) SPL only */
#if !CONFIG_IS_ENABLED(DM_MMC)
@@ -489,9 +516,7 @@ static int sunxi_mmc_core_init(struct mmc *mmc)
{
struct sunxi_mmc_priv *priv = mmc->priv;
- /* Reset controller */
- writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
- udelay(1000);
+ sunxi_mmc_reset(priv->reg);
return 0;
}
@@ -684,9 +709,7 @@ static int sunxi_mmc_probe(struct udevice *dev)
upriv->mmc = &plat->mmc;
- /* Reset controller */
- writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
- udelay(1000);
+ sunxi_mmc_reset(priv->reg);
return 0;
}
diff --git a/drivers/mmc/sunxi_mmc.h b/drivers/mmc/sunxi_mmc.h
index f4ae5a790c8..71865160319 100644
--- a/drivers/mmc/sunxi_mmc.h
+++ b/drivers/mmc/sunxi_mmc.h
@@ -37,7 +37,9 @@ struct sunxi_mmc {
u32 res0; /* 0x54 reserved */
u32 a12a; /* 0x58 Auto command 12 argument */
u32 ntsr; /* 0x5c New timing set register */
- u32 res1[8];
+ u32 res1[6];
+ u32 hwrst; /* 0x78 Hardware Reset */
+ u32 res5;
u32 dmac; /* 0x80 internal DMA control */
u32 dlba; /* 0x84 internal DMA descr list base address */
u32 idst; /* 0x88 internal DMA status */
@@ -46,7 +48,8 @@ struct sunxi_mmc {
u32 cbda; /* 0x94 */
u32 res2[26];
#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
- u32 res3[17];
+ u32 thldc; /* 0x100 Threshold control */
+ u32 res3[16];
u32 samp_dl;
u32 res4[46];
#endif
@@ -57,6 +60,7 @@ struct sunxi_mmc {
#define SUNXI_MMC_CLK_ENABLE (0x1 << 16)
#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff)
+#define SUNXI_MMC_GCTRL 0x000
#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0)
#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1)
#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2)
@@ -123,6 +127,10 @@ struct sunxi_mmc {
#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31)
+#define SUNXI_MMC_HWRST 0x078
+#define SUNXI_MMC_HWRST_ASSERT (0x0 << 0)
+#define SUNXI_MMC_HWRST_DEASSERT (0x1 << 0)
+
#define SUNXI_MMC_IDMAC_RESET (0x1 << 0)
#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1)
#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7)
@@ -133,6 +141,12 @@ struct sunxi_mmc {
#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
#define SUNXI_MMC_COMMON_RESET (1 << 18)
+#define SUNXI_MMC_THLDC 0x100
+#define SUNXI_MMC_THLDC_READ_EN (0x1 << 0)
+#define SUNXI_MMC_THLDC_BSY_CLR_INT_EN (0x1 << 1)
+#define SUNXI_MMC_THLDC_WRITE_EN (0x1 << 2)
+#define SUNXI_MMC_THLDC_READ_THLD(x) (((x) & 0xfff) << 16)
+
#define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7)
#endif /* _SUNXI_MMC_H */
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 88094b81e7a..3f8edeb5093 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -208,7 +208,7 @@ int mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
{
struct mtd_partition partition = {}, *parts;
const char *mtdparts = *_mtdparts;
- uint64_t cur_off = 0, cur_sz = 0;
+ uint64_t cur_off = 0;
int nparts = 0;
int ret, idx;
u64 sz;
@@ -237,8 +237,7 @@ int mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
return ret;
if (parts[idx].size == MTD_SIZE_REMAINING)
- parts[idx].size = parent->size - cur_sz;
- cur_sz += parts[idx].size;
+ parts[idx].size = parent->size - parts[idx].offset;
sz = parts[idx].size;
if (sz < parent->writesize || do_div(sz, parent->writesize)) {
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 609bdffbf77..adb271dfb8f 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -190,6 +190,21 @@ config SPL_NAND_LOAD
def_bool y
depends on NAND_DAVINCI && ARCH_DAVINCI && SPL_NAND_SUPPORT
+config NAND_CADENCE
+ bool "Support Cadence NAND controller as a DT device"
+ depends on OF_CONTROL && DM_MTD
+ select SYS_NAND_SELF_INIT
+ select SPL_SYS_NAND_SELF_INIT
+ select SPL_NAND_BASE
+ select SPL_NAND_DRIVERS
+ select SPL_NAND_IDENT
+ select SPL_NAND_INIT
+ select SPL_NAND_ECC
+ imply CMD_NAND
+ help
+ Enable the driver for NAND flash on platforms using a Cadence NAND
+ controller as a DT device.
+
config NAND_DENALI
bool
select SYS_NAND_SELF_INIT
@@ -673,7 +688,7 @@ config SYS_NAND_PAGE_SIZE
SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \
MVEBU_SPL_BOOT_DEVICE_NAND || \
(NAND_ATMEL && SPL_NAND_SUPPORT) || \
- SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX
+ SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX || NAND_CADENCE
depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621
help
Number of data bytes in one page for the NAND chip on the
@@ -775,6 +790,13 @@ config SPL_NAND_AM33XX_BCH
so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling
SPL-NAND driver with software ECC correction support.
+config SPL_NAND_CADENCE
+ bool "Support Cadence NAND controller for SPL"
+ depends on SPL_NAND_SUPPORT
+ help
+ This is a small implementation of the Cadence NAND controller
+ for use on SPL.
+
config SPL_NAND_DENALI
bool "Support Denali NAND controller for SPL"
depends on SPL_NAND_SUPPORT
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index b47a3d787ce..34cba77046a 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -10,6 +10,7 @@ NORMAL_DRIVERS=y
endif
obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
+obj-$(CONFIG_SPL_NAND_CADENCE) += cadence_spl.o
obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
@@ -51,6 +52,7 @@ obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_DM_NAND_ATMEL) += atmel/
obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o
obj-$(CONFIG_NAND_BRCMNAND) += brcmnand/
+obj-$(CONFIG_NAND_CADENCE) += cadence_nand.o
obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_NAND_DENALI) += denali.o
obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index 56fbd64ef68..c90a4eab8df 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1127,7 +1127,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
const struct nand_data_interface *conf,
struct atmel_smc_cs_conf *smcconf)
{
- u32 ncycles, totalcycles, timeps, mckperiodps;
+ u32 ncycles, totalcycles, timeps, mckperiodps, pulse;
struct atmel_nand_controller *nc;
int ret;
@@ -1253,11 +1253,16 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
/*
- * Read pulse timing directly matches tRP:
+ * Read pulse timing would directly match tRP,
+ * but some NAND flash chips (S34ML01G2 and W29N02KVxxAF)
+ * do not work properly in timing mode 3.
+ * The workaround is to extend the SMC NRD pulse to meet tREA
+ * timing.
*
- * NRD_PULSE = tRP
+ * NRD_PULSE = max(tRP, tREA)
*/
- ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
+ pulse = max(conf->timings.sdr.tRP_min, conf->timings.sdr.tREA_max);
+ ncycles = DIV_ROUND_UP(pulse, mckperiodps);
totalcycles += ncycles;
ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
ncycles);
diff --git a/drivers/mtd/nand/raw/cadence_nand.c b/drivers/mtd/nand/raw/cadence_nand.c
new file mode 100644
index 00000000000..27aa7f97a45
--- /dev/null
+++ b/drivers/mtd/nand/raw/cadence_nand.c
@@ -0,0 +1,2423 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cadence NAND flash controller driver
+ *
+ * Copyright (C) 2019 Cadence
+ *
+ * Author: Piotr Sroka <piotrs@cadence.com>
+ *
+ */
+
+#include <cadence-nand.h>
+#include <clk.h>
+#include <dm.h>
+#include <hang.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <nand.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitfield.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/printk.h>
+#include <linux/sizes.h>
+
+static inline struct
+cdns_nand_chip *to_cdns_nand_chip(struct nand_chip *chip)
+{
+ return container_of(chip, struct cdns_nand_chip, chip);
+}
+
+static inline struct
+cadence_nand_info *to_cadence_nand_info(struct nand_hw_control *controller)
+{
+ return container_of(controller, struct cadence_nand_info, controller);
+}
+
+static bool
+cadence_nand_dma_buf_ok(struct cadence_nand_info *cadence, const void *buf,
+ u32 buf_len)
+{
+ u8 data_dma_width = cadence->caps2.data_dma_width;
+
+ return buf &&
+ likely(IS_ALIGNED((uintptr_t)buf, data_dma_width)) &&
+ likely(IS_ALIGNED(buf_len, DMA_DATA_SIZE_ALIGN));
+}
+
+static int cadence_nand_wait_for_value(struct cadence_nand_info *cadence,
+ u32 reg_offset, u32 timeout_us,
+ u32 mask, bool is_clear)
+{
+ u32 val;
+ int ret;
+
+ ret = readl_poll_sleep_timeout(cadence->reg + reg_offset,
+ val, !(val & mask) == is_clear,
+ 10, timeout_us);
+
+ if (ret < 0) {
+ dev_err(cadence->dev,
+ "Timeout while waiting for reg %x with mask %x is clear %d\n",
+ reg_offset, mask, is_clear);
+ }
+
+ return ret;
+}
+
+static int cadence_nand_set_ecc_enable(struct cadence_nand_info *cadence,
+ bool enable)
+{
+ u32 reg;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ reg = readl_relaxed(cadence->reg + ECC_CONFIG_0);
+
+ if (enable)
+ reg |= ECC_CONFIG_0_ECC_EN;
+ else
+ reg &= ~ECC_CONFIG_0_ECC_EN;
+
+ writel_relaxed(reg, cadence->reg + ECC_CONFIG_0);
+
+ return 0;
+}
+
+static void cadence_nand_set_ecc_strength(struct cadence_nand_info *cadence,
+ u8 corr_str_idx)
+{
+ u32 reg;
+
+ if (cadence->curr_corr_str_idx == corr_str_idx)
+ return;
+
+ reg = readl_relaxed(cadence->reg + ECC_CONFIG_0);
+ reg &= ~ECC_CONFIG_0_CORR_STR;
+ reg |= FIELD_PREP(ECC_CONFIG_0_CORR_STR, corr_str_idx);
+ writel_relaxed(reg, cadence->reg + ECC_CONFIG_0);
+
+ cadence->curr_corr_str_idx = corr_str_idx;
+}
+
+static int cadence_nand_get_ecc_strength_idx(struct cadence_nand_info *cadence,
+ u8 strength)
+{
+ int i, corr_str_idx = -1;
+
+ for (i = 0; i < BCH_MAX_NUM_CORR_CAPS; i++) {
+ if (cadence->ecc_strengths[i] == strength) {
+ corr_str_idx = i;
+ break;
+ }
+ }
+
+ return corr_str_idx;
+}
+
+static int cadence_nand_set_skip_marker_val(struct cadence_nand_info *cadence,
+ u16 marker_value)
+{
+ u32 reg;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ reg = readl_relaxed(cadence->reg + SKIP_BYTES_CONF);
+ reg &= ~SKIP_BYTES_MARKER_VALUE;
+ reg |= FIELD_PREP(SKIP_BYTES_MARKER_VALUE,
+ marker_value);
+
+ writel_relaxed(reg, cadence->reg + SKIP_BYTES_CONF);
+
+ return 0;
+}
+
+static int cadence_nand_set_skip_bytes_conf(struct cadence_nand_info *cadence,
+ u8 num_of_bytes,
+ u32 offset_value,
+ int enable)
+{
+ u32 reg, skip_bytes_offset;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ if (!enable) {
+ num_of_bytes = 0;
+ offset_value = 0;
+ }
+
+ reg = readl_relaxed(cadence->reg + SKIP_BYTES_CONF);
+ reg &= ~SKIP_BYTES_NUM_OF_BYTES;
+ reg |= FIELD_PREP(SKIP_BYTES_NUM_OF_BYTES,
+ num_of_bytes);
+ skip_bytes_offset = FIELD_PREP(SKIP_BYTES_OFFSET_VALUE,
+ offset_value);
+
+ writel_relaxed(reg, cadence->reg + SKIP_BYTES_CONF);
+ writel_relaxed(skip_bytes_offset, cadence->reg + SKIP_BYTES_OFFSET);
+
+ return 0;
+}
+
+/* Functions enables/disables hardware detection of erased data */
+static void cadence_nand_set_erase_detection(struct cadence_nand_info *cadence,
+ bool enable,
+ u8 bitflips_threshold)
+{
+ u32 reg;
+
+ reg = readl_relaxed(cadence->reg + ECC_CONFIG_0);
+
+ if (enable)
+ reg |= ECC_CONFIG_0_ERASE_DET_EN;
+ else
+ reg &= ~ECC_CONFIG_0_ERASE_DET_EN;
+
+ writel_relaxed(reg, cadence->reg + ECC_CONFIG_0);
+ writel_relaxed(bitflips_threshold, cadence->reg + ECC_CONFIG_1);
+}
+
+static int cadence_nand_set_access_width16(struct cadence_nand_info *cadence,
+ bool bit_bus16)
+{
+ u32 reg;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ reg = readl_relaxed(cadence->reg + COMMON_SET);
+ if (!bit_bus16)
+ reg &= ~COMMON_SET_DEVICE_16BIT;
+ else
+ reg |= COMMON_SET_DEVICE_16BIT;
+ writel_relaxed(reg, cadence->reg + COMMON_SET);
+
+ return 0;
+}
+
+static void
+cadence_nand_clear_interrupt(struct cadence_nand_info *cadence,
+ struct cadence_nand_irq_status *irq_status)
+{
+ writel_relaxed(irq_status->status, cadence->reg + INTR_STATUS);
+ writel_relaxed(irq_status->trd_status,
+ cadence->reg + TRD_COMP_INT_STATUS);
+ writel_relaxed(irq_status->trd_error,
+ cadence->reg + TRD_ERR_INT_STATUS);
+}
+
+static void
+cadence_nand_read_int_status(struct cadence_nand_info *cadence,
+ struct cadence_nand_irq_status *irq_status)
+{
+ irq_status->status = readl_relaxed(cadence->reg + INTR_STATUS);
+ irq_status->trd_status = readl_relaxed(cadence->reg
+ + TRD_COMP_INT_STATUS);
+ irq_status->trd_error = readl_relaxed(cadence->reg
+ + TRD_ERR_INT_STATUS);
+}
+
+static u32 irq_detected(struct cadence_nand_info *cadence,
+ struct cadence_nand_irq_status *irq_status)
+{
+ cadence_nand_read_int_status(cadence, irq_status);
+
+ return irq_status->status || irq_status->trd_status ||
+ irq_status->trd_error;
+}
+
+static void cadence_nand_reset_irq(struct cadence_nand_info *cadence)
+{
+ memset(&cadence->irq_status, 0, sizeof(cadence->irq_status));
+ memset(&cadence->irq_mask, 0, sizeof(cadence->irq_mask));
+}
+
+/*
+ * This is the interrupt service routine. It handles all interrupts
+ * sent to this device.
+ */
+static irqreturn_t cadence_nand_isr(struct cadence_nand_info *cadence)
+{
+ struct cadence_nand_irq_status irq_status;
+ irqreturn_t result = IRQ_NONE;
+
+ if (irq_detected(cadence, &irq_status)) {
+ /* Handle interrupt. */
+ /* First acknowledge it. */
+ cadence_nand_clear_interrupt(cadence, &irq_status);
+ /* Status in the device context for someone to read. */
+ cadence->irq_status.status |= irq_status.status;
+ cadence->irq_status.trd_status |= irq_status.trd_status;
+ cadence->irq_status.trd_error |= irq_status.trd_error;
+ /* Tell the OS that we've handled this. */
+ result = IRQ_HANDLED;
+ }
+ return result;
+}
+
+static void cadence_nand_set_irq_mask(struct cadence_nand_info *cadence,
+ struct cadence_nand_irq_status *irq_mask)
+{
+ writel_relaxed(INTR_ENABLE_INTR_EN | irq_mask->status,
+ cadence->reg + INTR_ENABLE);
+
+ writel_relaxed(irq_mask->trd_error,
+ cadence->reg + TRD_ERR_INT_STATUS_EN);
+}
+
+static void
+cadence_nand_wait_for_irq(struct cadence_nand_info *cadence,
+ struct cadence_nand_irq_status *irq_mask,
+ struct cadence_nand_irq_status *irq_status)
+{
+ irqreturn_t result = IRQ_NONE;
+ u32 start = get_timer(0);
+
+ while (get_timer(start) < TIMEOUT_US) {
+ result = cadence_nand_isr(cadence);
+
+ if (result == IRQ_HANDLED) {
+ *irq_status = cadence->irq_status;
+ break;
+ }
+ udelay(1);
+ }
+
+ if (!result) {
+ /* Timeout error. */
+ dev_err(cadence->dev, "timeout occurred:\n");
+ dev_err(cadence->dev, "\tstatus = 0x%x, mask = 0x%x\n",
+ irq_status->status, irq_mask->status);
+ dev_err(cadence->dev,
+ "\ttrd_status = 0x%x, trd_status mask = 0x%x\n",
+ irq_status->trd_status, irq_mask->trd_status);
+ dev_err(cadence->dev,
+ "\t trd_error = 0x%x, trd_error mask = 0x%x\n",
+ irq_status->trd_error, irq_mask->trd_error);
+ }
+}
+
+/* Execute generic command on NAND controller. */
+static int cadence_nand_generic_cmd_send(struct cadence_nand_info *cadence,
+ u8 chip_nr,
+ u64 mini_ctrl_cmd)
+{
+ u32 mini_ctrl_cmd_l, mini_ctrl_cmd_h, reg;
+
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_CS, chip_nr);
+ mini_ctrl_cmd_l = mini_ctrl_cmd & 0xFFFFFFFF;
+ mini_ctrl_cmd_h = mini_ctrl_cmd >> 32;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ cadence_nand_reset_irq(cadence);
+
+ writel_relaxed(mini_ctrl_cmd_l, cadence->reg + CMD_REG2);
+ writel_relaxed(mini_ctrl_cmd_h, cadence->reg + CMD_REG3);
+
+ /* Select generic command. */
+ reg = FIELD_PREP(CMD_REG0_CT, CMD_REG0_CT_GEN);
+ /* Thread number. */
+ reg |= FIELD_PREP(CMD_REG0_TN, 0);
+
+ /* Issue command. */
+ writel_relaxed(reg, cadence->reg + CMD_REG0);
+ cadence->buf_index = 0;
+
+ return 0;
+}
+
+/* Wait for data on slave DMA interface. */
+static int cadence_nand_wait_on_sdma(struct cadence_nand_info *cadence, u8 *out_sdma_trd,
+ u32 *out_sdma_size)
+{
+ struct cadence_nand_irq_status irq_mask, irq_status;
+
+ irq_mask.trd_status = 0;
+ irq_mask.trd_error = 0;
+ irq_mask.status = INTR_STATUS_SDMA_TRIGG
+ | INTR_STATUS_SDMA_ERR
+ | INTR_STATUS_UNSUPP_CMD;
+
+ cadence_nand_set_irq_mask(cadence, &irq_mask);
+ cadence_nand_wait_for_irq(cadence, &irq_mask, &irq_status);
+ if (irq_status.status == 0) {
+ dev_err(cadence->dev, "Timeout while waiting for SDMA\n");
+ return -ETIMEDOUT;
+ }
+
+ if (irq_status.status & INTR_STATUS_SDMA_TRIGG) {
+ *out_sdma_size = readl_relaxed(cadence->reg + SDMA_SIZE);
+ *out_sdma_trd = readl_relaxed(cadence->reg + SDMA_TRD_NUM);
+ *out_sdma_trd =
+ FIELD_GET(SDMA_TRD_NUM_SDMA_TRD, *out_sdma_trd);
+ } else {
+ dev_err(cadence->dev, "SDMA error - irq_status %x\n",
+ irq_status.status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void cadence_nand_get_caps(struct cadence_nand_info *cadence)
+{
+ u32 reg;
+
+ reg = readl_relaxed(cadence->reg + CTRL_FEATURES);
+
+ cadence->caps2.max_banks = 1 << FIELD_GET(CTRL_FEATURES_N_BANKS, reg);
+
+ if (FIELD_GET(CTRL_FEATURES_DMA_DWITH64, reg))
+ cadence->caps2.data_dma_width = 8;
+ else
+ cadence->caps2.data_dma_width = 4;
+
+ if (reg & CTRL_FEATURES_CONTROL_DATA)
+ cadence->caps2.data_control_supp = true;
+
+ if (reg & (CTRL_FEATURES_NVDDR_2_3
+ | CTRL_FEATURES_NVDDR))
+ cadence->caps2.is_phy_type_dll = true;
+}
+
+/* Prepare CDMA descriptor. */
+static void
+cadence_nand_cdma_desc_prepare(struct cadence_nand_info *cadence,
+ char nf_mem, u32 flash_ptr, dma_addr_t mem_ptr,
+ dma_addr_t ctrl_data_ptr, u16 ctype)
+{
+ struct cadence_nand_cdma_desc *cdma_desc = cadence->cdma_desc;
+
+ memset(cdma_desc, 0, sizeof(struct cadence_nand_cdma_desc));
+
+ /* Set fields for one descriptor. */
+ cdma_desc->flash_pointer = flash_ptr;
+ if (cadence->ctrl_rev >= 13)
+ cdma_desc->bank = nf_mem;
+ else
+ cdma_desc->flash_pointer |= (nf_mem << CDMA_CFPTR_MEM_SHIFT);
+
+ cdma_desc->command_flags |= CDMA_CF_DMA_MASTER;
+ cdma_desc->command_flags |= CDMA_CF_INT;
+
+ cdma_desc->memory_pointer = mem_ptr;
+ cdma_desc->status = 0;
+ cdma_desc->sync_flag_pointer = 0;
+ cdma_desc->sync_arguments = 0;
+
+ cdma_desc->command_type = ctype;
+ cdma_desc->ctrl_data_ptr = ctrl_data_ptr;
+
+ flush_cache((dma_addr_t)cadence->cdma_desc,
+ ROUND(sizeof(struct cadence_nand_cdma_desc),
+ ARCH_DMA_MINALIGN));
+}
+
+static u8 cadence_nand_check_desc_error(struct cadence_nand_info *cadence,
+ u32 desc_status)
+{
+ if (desc_status & CDMA_CS_ERP)
+ return STAT_ERASED;
+
+ if (desc_status & CDMA_CS_UNCE)
+ return STAT_ECC_UNCORR;
+
+ if (desc_status & CDMA_CS_ERR) {
+ dev_err(cadence->dev, ":CDMA desc error flag detected.\n");
+ return STAT_FAIL;
+ }
+
+ if (FIELD_GET(CDMA_CS_MAXERR, desc_status))
+ return STAT_ECC_CORR;
+
+ return STAT_FAIL;
+}
+
+static int cadence_nand_cdma_finish(struct cadence_nand_info *cadence)
+{
+ struct cadence_nand_cdma_desc *desc_ptr = cadence->cdma_desc;
+ u8 status = STAT_BUSY;
+
+ invalidate_dcache_range((dma_addr_t)cadence->cdma_desc,
+ (dma_addr_t)cadence->cdma_desc +
+ ROUND(sizeof(struct cadence_nand_cdma_desc),
+ ARCH_DMA_MINALIGN));
+
+ if (desc_ptr->status & CDMA_CS_FAIL) {
+ status = cadence_nand_check_desc_error(cadence,
+ desc_ptr->status);
+ dev_err(cadence->dev, ":CDMA error %x\n", desc_ptr->status);
+ } else if (desc_ptr->status & CDMA_CS_COMP) {
+ /* Descriptor finished with no errors. */
+ if (desc_ptr->command_flags & CDMA_CF_CONT) {
+ dev_info(cadence->dev, "DMA unsupported flag is set");
+ status = STAT_UNKNOWN;
+ } else {
+ /* Last descriptor. */
+ status = STAT_OK;
+ }
+ }
+
+ return status;
+}
+
+static int cadence_nand_cdma_send(struct cadence_nand_info *cadence,
+ u8 thread)
+{
+ u32 reg;
+ int status;
+
+ /* Wait for thread ready. */
+ status = cadence_nand_wait_for_value(cadence, TRD_STATUS,
+ TIMEOUT_US,
+ BIT(thread), true);
+ if (status)
+ return status;
+
+ cadence_nand_reset_irq(cadence);
+
+ writel_relaxed((u32)cadence->dma_cdma_desc,
+ cadence->reg + CMD_REG2);
+ writel_relaxed(0, cadence->reg + CMD_REG3);
+
+ /* Select CDMA mode. */
+ reg = FIELD_PREP(CMD_REG0_CT, CMD_REG0_CT_CDMA);
+ /* Thread number. */
+ reg |= FIELD_PREP(CMD_REG0_TN, thread);
+ /* Issue command. */
+ writel_relaxed(reg, cadence->reg + CMD_REG0);
+
+ return 0;
+}
+
+/* Send SDMA command and wait for finish. */
+static u32
+cadence_nand_cdma_send_and_wait(struct cadence_nand_info *cadence,
+ u8 thread)
+{
+ struct cadence_nand_irq_status irq_mask, irq_status = {0};
+ int status;
+ u32 val;
+
+ irq_mask.trd_status = BIT(thread);
+ irq_mask.trd_error = BIT(thread);
+ irq_mask.status = INTR_STATUS_CDMA_TERR;
+
+ cadence_nand_set_irq_mask(cadence, &irq_mask);
+
+ status = cadence_nand_cdma_send(cadence, thread);
+ if (status)
+ return status;
+
+ /* Make sure the descriptor processing is complete */
+ status = readl_poll_timeout(cadence->reg + TRD_COMP_INT_STATUS, val,
+ (val & BIT(thread)), TIMEOUT_US);
+ if (status) {
+ pr_err("cmd thread completion timeout!\n");
+ return status;
+ }
+
+ cadence_nand_wait_for_irq(cadence, &irq_mask, &irq_status);
+
+ if (irq_status.status == 0 && irq_status.trd_status == 0 &&
+ irq_status.trd_error == 0) {
+ dev_err(cadence->dev, "CDMA command timeout\n");
+ return -ETIMEDOUT;
+ }
+ if (irq_status.status & irq_mask.status) {
+ dev_err(cadence->dev, "CDMA command failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * ECC size depends on configured ECC strength and on maximum supported
+ * ECC step size.
+ */
+static int cadence_nand_calc_ecc_bytes(int max_step_size, int strength)
+{
+ int nbytes = DIV_ROUND_UP(fls(8 * max_step_size) * strength, 8);
+
+ return ALIGN(nbytes, 2);
+}
+
+#define CADENCE_NAND_CALC_ECC_BYTES(max_step_size) \
+ static int \
+ cadence_nand_calc_ecc_bytes_##max_step_size(int step_size, \
+ int strength)\
+ {\
+ return cadence_nand_calc_ecc_bytes(max_step_size, strength);\
+ }
+
+CADENCE_NAND_CALC_ECC_BYTES(256)
+CADENCE_NAND_CALC_ECC_BYTES(512)
+CADENCE_NAND_CALC_ECC_BYTES(1024)
+CADENCE_NAND_CALC_ECC_BYTES(2048)
+CADENCE_NAND_CALC_ECC_BYTES(4096)
+
+/* Function reads BCH capabilities. */
+static int cadence_nand_read_bch_caps(struct cadence_nand_info *cadence)
+{
+ struct nand_ecc_caps *ecc_caps = &cadence->ecc_caps;
+ int max_step_size = 0, nstrengths, i;
+ u32 reg;
+
+ reg = readl_relaxed(cadence->reg + BCH_CFG_3);
+ cadence->bch_metadata_size = FIELD_GET(BCH_CFG_3_METADATA_SIZE, reg);
+ if (cadence->bch_metadata_size < 4) {
+ dev_err(cadence->dev,
+ "Driver needs at least 4 bytes of BCH meta data\n");
+ return -EIO;
+ }
+
+ reg = readl_relaxed(cadence->reg + BCH_CFG_0);
+ cadence->ecc_strengths[0] = FIELD_GET(BCH_CFG_0_CORR_CAP_0, reg);
+ cadence->ecc_strengths[1] = FIELD_GET(BCH_CFG_0_CORR_CAP_1, reg);
+ cadence->ecc_strengths[2] = FIELD_GET(BCH_CFG_0_CORR_CAP_2, reg);
+ cadence->ecc_strengths[3] = FIELD_GET(BCH_CFG_0_CORR_CAP_3, reg);
+
+ reg = readl_relaxed(cadence->reg + BCH_CFG_1);
+ cadence->ecc_strengths[4] = FIELD_GET(BCH_CFG_1_CORR_CAP_4, reg);
+ cadence->ecc_strengths[5] = FIELD_GET(BCH_CFG_1_CORR_CAP_5, reg);
+ cadence->ecc_strengths[6] = FIELD_GET(BCH_CFG_1_CORR_CAP_6, reg);
+ cadence->ecc_strengths[7] = FIELD_GET(BCH_CFG_1_CORR_CAP_7, reg);
+
+ reg = readl_relaxed(cadence->reg + BCH_CFG_2);
+ cadence->ecc_stepinfos[0].stepsize =
+ FIELD_GET(BCH_CFG_2_SECT_0, reg);
+
+ cadence->ecc_stepinfos[1].stepsize =
+ FIELD_GET(BCH_CFG_2_SECT_1, reg);
+
+ nstrengths = 0;
+ for (i = 0; i < BCH_MAX_NUM_CORR_CAPS; i++) {
+ if (cadence->ecc_strengths[i] != 0)
+ nstrengths++;
+ }
+
+ ecc_caps->nstepinfos = 0;
+ for (i = 0; i < BCH_MAX_NUM_SECTOR_SIZES; i++) {
+ /* ECC strengths are common for all step infos. */
+ cadence->ecc_stepinfos[i].nstrengths = nstrengths;
+ cadence->ecc_stepinfos[i].strengths =
+ cadence->ecc_strengths;
+
+ if (cadence->ecc_stepinfos[i].stepsize != 0)
+ ecc_caps->nstepinfos++;
+
+ if (cadence->ecc_stepinfos[i].stepsize > max_step_size)
+ max_step_size = cadence->ecc_stepinfos[i].stepsize;
+ }
+ ecc_caps->stepinfos = &cadence->ecc_stepinfos[0];
+
+ switch (max_step_size) {
+ case 256:
+ ecc_caps->calc_ecc_bytes = &cadence_nand_calc_ecc_bytes_256;
+ break;
+ case 512:
+ ecc_caps->calc_ecc_bytes = &cadence_nand_calc_ecc_bytes_512;
+ break;
+ case 1024:
+ ecc_caps->calc_ecc_bytes = &cadence_nand_calc_ecc_bytes_1024;
+ break;
+ case 2048:
+ ecc_caps->calc_ecc_bytes = &cadence_nand_calc_ecc_bytes_2048;
+ break;
+ case 4096:
+ ecc_caps->calc_ecc_bytes = &cadence_nand_calc_ecc_bytes_4096;
+ break;
+ default:
+ dev_err(cadence->dev,
+ "Unsupported sector size(ecc step size) %d\n",
+ max_step_size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* Hardware initialization. */
+static int cadence_nand_hw_init(struct cadence_nand_info *cadence)
+{
+ int status;
+ u32 reg;
+
+ status = cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_INIT_COMP, false);
+ if (status)
+ return status;
+
+ reg = readl_relaxed(cadence->reg + CTRL_VERSION);
+ cadence->ctrl_rev = FIELD_GET(CTRL_VERSION_REV, reg);
+
+ dev_info(cadence->dev,
+ "%s: cadence nand controller version reg %x\n",
+ __func__, reg);
+
+ /* Disable cache and multiplane. */
+ writel_relaxed(0, cadence->reg + MULTIPLANE_CFG);
+ writel_relaxed(0, cadence->reg + CACHE_CFG);
+
+ /* Clear all interrupts. */
+ writel_relaxed(0xFFFFFFFF, cadence->reg + INTR_STATUS);
+
+ cadence_nand_get_caps(cadence);
+ if (cadence_nand_read_bch_caps(cadence))
+ return -EIO;
+
+ /*
+ * Set IO width access to 8.
+ * It is because during SW device discovering width access
+ * is expected to be 8.
+ */
+ status = cadence_nand_set_access_width16(cadence, false);
+
+ return status;
+}
+
+#define TT_MAIN_OOB_AREAS 2
+#define TT_RAW_PAGE 3
+#define TT_BBM 4
+#define TT_MAIN_OOB_AREA_EXT 5
+
+/* Prepare size of data to transfer. */
+static void
+cadence_nand_prepare_data_size(struct mtd_info *mtd,
+ int transfer_type)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ u32 sec_size = 0, offset = 0, sec_cnt = 1;
+ u32 last_sec_size = cdns_chip->sector_size;
+ u32 data_ctrl_size = 0;
+ u32 reg = 0;
+
+ if (cadence->curr_trans_type == transfer_type)
+ return;
+
+ switch (transfer_type) {
+ case TT_MAIN_OOB_AREA_EXT:
+ sec_cnt = cdns_chip->sector_count;
+ sec_size = cdns_chip->sector_size;
+ data_ctrl_size = cdns_chip->avail_oob_size;
+ break;
+ case TT_MAIN_OOB_AREAS:
+ sec_cnt = cdns_chip->sector_count;
+ last_sec_size = cdns_chip->sector_size
+ + cdns_chip->avail_oob_size;
+ sec_size = cdns_chip->sector_size;
+ break;
+ case TT_RAW_PAGE:
+ last_sec_size = mtd->writesize + mtd->oobsize;
+ break;
+ case TT_BBM:
+ offset = mtd->writesize + cdns_chip->bbm_offs;
+ last_sec_size = 8;
+ break;
+ }
+
+ reg = 0;
+ reg |= FIELD_PREP(TRAN_CFG_0_OFFSET, offset);
+ reg |= FIELD_PREP(TRAN_CFG_0_SEC_CNT, sec_cnt);
+ writel_relaxed(reg, cadence->reg + TRAN_CFG_0);
+
+ reg = 0;
+ reg |= FIELD_PREP(TRAN_CFG_1_LAST_SEC_SIZE, last_sec_size);
+ reg |= FIELD_PREP(TRAN_CFG_1_SECTOR_SIZE, sec_size);
+ writel_relaxed(reg, cadence->reg + TRAN_CFG_1);
+
+ if (cadence->caps2.data_control_supp) {
+ reg = readl_relaxed(cadence->reg + CONTROL_DATA_CTRL);
+ reg &= ~CONTROL_DATA_CTRL_SIZE;
+ reg |= FIELD_PREP(CONTROL_DATA_CTRL_SIZE, data_ctrl_size);
+ writel_relaxed(reg, cadence->reg + CONTROL_DATA_CTRL);
+ }
+
+ cadence->curr_trans_type = transfer_type;
+}
+
+static int
+cadence_nand_cdma_transfer(struct cadence_nand_info *cadence, u8 chip_nr,
+ int page, void *buf, void *ctrl_dat, u32 buf_size,
+ u32 ctrl_dat_size, enum dma_data_direction dir,
+ bool with_ecc)
+{
+ dma_addr_t dma_buf, dma_ctrl_dat = 0;
+ u8 thread_nr = chip_nr;
+ int status;
+ u16 ctype;
+
+ if (dir == DMA_FROM_DEVICE)
+ ctype = CDMA_CT_RD;
+ else
+ ctype = CDMA_CT_WR;
+
+ cadence_nand_set_ecc_enable(cadence, with_ecc);
+
+ dma_buf = dma_map_single(buf, buf_size, dir);
+ if (dma_mapping_error(cadence->dev, dma_buf)) {
+ dev_err(cadence->dev, "Failed to map DMA buffer\n");
+ return -EIO;
+ }
+
+ if (ctrl_dat && ctrl_dat_size) {
+ dma_ctrl_dat = dma_map_single(ctrl_dat,
+ ctrl_dat_size, dir);
+ if (dma_mapping_error(cadence->dev, dma_ctrl_dat)) {
+ dma_unmap_single(dma_buf,
+ buf_size, dir);
+ dev_err(cadence->dev, "Failed to map DMA buffer\n");
+ return -EIO;
+ }
+ }
+
+ cadence_nand_cdma_desc_prepare(cadence, chip_nr, page,
+ dma_buf, dma_ctrl_dat, ctype);
+
+ status = cadence_nand_cdma_send_and_wait(cadence, thread_nr);
+
+ dma_unmap_single(dma_buf,
+ buf_size, dir);
+
+ if (ctrl_dat && ctrl_dat_size)
+ dma_unmap_single(dma_ctrl_dat,
+ ctrl_dat_size, dir);
+ if (status)
+ return status;
+
+ return cadence_nand_cdma_finish(cadence);
+}
+
+static void cadence_nand_set_timings(struct cadence_nand_info *cadence,
+ struct cadence_nand_timings *t)
+{
+ writel_relaxed(t->async_toggle_timings,
+ cadence->reg + ASYNC_TOGGLE_TIMINGS);
+ writel_relaxed(t->timings0, cadence->reg + TIMINGS0);
+ writel_relaxed(t->timings1, cadence->reg + TIMINGS1);
+ writel_relaxed(t->timings2, cadence->reg + TIMINGS2);
+
+ if (cadence->caps2.is_phy_type_dll)
+ writel_relaxed(t->dll_phy_ctrl, cadence->reg + DLL_PHY_CTRL);
+
+ writel_relaxed(t->phy_ctrl, cadence->reg + PHY_CTRL);
+
+ if (cadence->caps2.is_phy_type_dll) {
+ writel_relaxed(0, cadence->reg + PHY_TSEL);
+ writel_relaxed(2, cadence->reg + PHY_DQ_TIMING);
+ writel_relaxed(t->phy_dqs_timing,
+ cadence->reg + PHY_DQS_TIMING);
+ writel_relaxed(t->phy_gate_lpbk_ctrl,
+ cadence->reg + PHY_GATE_LPBK_CTRL);
+ writel_relaxed(PHY_DLL_MASTER_CTRL_BYPASS_MODE,
+ cadence->reg + PHY_DLL_MASTER_CTRL);
+ writel_relaxed(0, cadence->reg + PHY_DLL_SLAVE_CTRL);
+ }
+}
+
+static int cadence_nand_select_target(struct nand_chip *chip)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+
+ if (chip == cadence->selected_chip)
+ return 0;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ cadence_nand_set_timings(cadence, &cdns_chip->timings);
+
+ cadence_nand_set_ecc_strength(cadence,
+ cdns_chip->corr_str_idx);
+
+ cadence_nand_set_erase_detection(cadence, true,
+ chip->ecc.strength);
+
+ cadence->curr_trans_type = -1;
+ cadence->selected_chip = chip;
+
+ return 0;
+}
+
+static int cadence_nand_erase(struct mtd_info *mtd, int page)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ int status;
+ u8 thread_nr = cdns_chip->cs[chip->cur_cs];
+
+ cadence_nand_cdma_desc_prepare(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, 0, 0,
+ CDMA_CT_ERASE);
+ status = cadence_nand_cdma_send_and_wait(cadence, thread_nr);
+ if (status) {
+ dev_err(cadence->dev, "erase operation failed\n");
+ return -EIO;
+ }
+
+ status = cadence_nand_cdma_finish(cadence);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+static int cadence_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip, int oobavail)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ int ret;
+
+ /*
+ * If .size and .strength are already set (usually by DT),
+ * check if they are supported by this controller.
+ */
+ if (chip->ecc.size && chip->ecc.strength)
+ return nand_check_ecc_caps(chip, &cadence->ecc_caps, oobavail);
+
+ /*
+ * We want .size and .strength closest to the chip's requirement
+ * unless NAND_ECC_MAXIMIZE is requested.
+ */
+ if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+ ret = nand_match_ecc_req(chip, &cadence->ecc_caps, oobavail);
+ if (!ret)
+ return 0;
+ }
+
+ /* Max ECC strength is the last thing we can do */
+ return nand_maximize_ecc(chip, &cadence->ecc_caps, oobavail);
+}
+
+static int cadence_nand_read_bbm(struct mtd_info *mtd, struct nand_chip *chip, int page, u8 *buf)
+{
+ int status;
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+
+ cadence_nand_prepare_data_size(mtd, TT_BBM);
+
+ cadence_nand_set_skip_bytes_conf(cadence, 0, 0, 0);
+
+ /*
+ * Read only bad block marker from offset
+ * defined by a memory manufacturer.
+ */
+ status = cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, cadence->buf, NULL,
+ mtd->oobsize,
+ 0, DMA_FROM_DEVICE, false);
+ if (status) {
+ dev_err(cadence->dev, "read BBM failed\n");
+ return -EIO;
+ }
+
+ memcpy(buf + cdns_chip->bbm_offs, cadence->buf, cdns_chip->bbm_len);
+
+ return 0;
+}
+
+static int cadence_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const u8 *buf, int oob_required, int page)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ int status;
+ u16 marker_val = 0xFFFF;
+
+ status = cadence_nand_select_target(chip);
+ if (status)
+ return status;
+
+ cadence_nand_set_skip_bytes_conf(cadence, cdns_chip->bbm_len,
+ mtd->writesize
+ + cdns_chip->bbm_offs,
+ 1);
+
+ if (oob_required) {
+ marker_val = *(u16 *)(chip->oob_poi
+ + cdns_chip->bbm_offs);
+ } else {
+ /* Set oob data to 0xFF. */
+ memset(cadence->buf + mtd->writesize, 0xFF,
+ cdns_chip->avail_oob_size);
+ }
+
+ cadence_nand_set_skip_marker_val(cadence, marker_val);
+
+ cadence_nand_prepare_data_size(mtd, TT_MAIN_OOB_AREA_EXT);
+
+ if (cadence_nand_dma_buf_ok(cadence, buf, mtd->writesize) &&
+ cadence->caps2.data_control_supp && !(chip->options & NAND_USE_BOUNCE_BUFFER)) {
+ u8 *oob;
+
+ if (oob_required)
+ oob = chip->oob_poi;
+ else
+ oob = cadence->buf + mtd->writesize;
+
+ status = cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, (void *)buf, oob,
+ mtd->writesize,
+ cdns_chip->avail_oob_size,
+ DMA_TO_DEVICE, true);
+ if (status) {
+ dev_err(cadence->dev, "write page failed\n");
+ return -EIO;
+ }
+
+ return 0;
+ }
+
+ if (oob_required) {
+ /* Transfer the data to the oob area. */
+ memcpy(cadence->buf + mtd->writesize, chip->oob_poi,
+ cdns_chip->avail_oob_size);
+ }
+
+ memcpy(cadence->buf, buf, mtd->writesize);
+
+ cadence_nand_prepare_data_size(mtd, TT_MAIN_OOB_AREAS);
+
+ return cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, cadence->buf, NULL,
+ mtd->writesize
+ + cdns_chip->avail_oob_size,
+ 0, DMA_TO_DEVICE, true);
+}
+
+static int cadence_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+
+ memset(cadence->buf, 0xFF, mtd->writesize);
+
+ return cadence_nand_write_page(mtd, chip, cadence->buf, 1, page);
+}
+
+static int cadence_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const u8 *buf, int oob_required, int page)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ int writesize = mtd->writesize;
+ int oobsize = mtd->oobsize;
+ int ecc_steps = chip->ecc.steps;
+ int ecc_size = chip->ecc.size;
+ int ecc_bytes = chip->ecc.bytes;
+ void *tmp_buf = cadence->buf;
+ int oob_skip = cdns_chip->bbm_len;
+ size_t size = writesize + oobsize;
+ int i, pos, len;
+ int status;
+
+ status = cadence_nand_select_target(chip);
+ if (status)
+ return status;
+
+ /*
+ * Fill the buffer with 0xff first except the full page transfer.
+ * This simplifies the logic.
+ */
+ if (!buf || !oob_required)
+ memset(tmp_buf, 0xff, size);
+
+ cadence_nand_set_skip_bytes_conf(cadence, 0, 0, 0);
+
+ /* Arrange the buffer for syndrome payload/ecc layout. */
+ if (buf) {
+ for (i = 0; i < ecc_steps; i++) {
+ pos = i * (ecc_size + ecc_bytes);
+ len = ecc_size;
+
+ if (pos >= writesize)
+ pos += oob_skip;
+ else if (pos + len > writesize)
+ len = writesize - pos;
+
+ memcpy(tmp_buf + pos, buf, len);
+ buf += len;
+ if (len < ecc_size) {
+ len = ecc_size - len;
+ memcpy(tmp_buf + writesize + oob_skip, buf,
+ len);
+ buf += len;
+ }
+ }
+ }
+
+ if (oob_required) {
+ const u8 *oob = chip->oob_poi;
+ u32 oob_data_offset = (cdns_chip->sector_count - 1) *
+ (cdns_chip->sector_size + chip->ecc.bytes)
+ + cdns_chip->sector_size + oob_skip;
+
+ /* BBM at the beginning of the OOB area. */
+ memcpy(tmp_buf + writesize, oob, oob_skip);
+
+ /* OOB free. */
+ memcpy(tmp_buf + oob_data_offset, oob,
+ cdns_chip->avail_oob_size);
+ oob += cdns_chip->avail_oob_size;
+
+ /* OOB ECC. */
+ for (i = 0; i < ecc_steps; i++) {
+ pos = ecc_size + i * (ecc_size + ecc_bytes);
+ if (i == (ecc_steps - 1))
+ pos += cdns_chip->avail_oob_size;
+
+ len = ecc_bytes;
+
+ if (pos >= writesize)
+ pos += oob_skip;
+ else if (pos + len > writesize)
+ len = writesize - pos;
+
+ memcpy(tmp_buf + pos, oob, len);
+ oob += len;
+ if (len < ecc_bytes) {
+ len = ecc_bytes - len;
+ memcpy(tmp_buf + writesize + oob_skip, oob,
+ len);
+ oob += len;
+ }
+ }
+ }
+
+ cadence_nand_prepare_data_size(mtd, TT_RAW_PAGE);
+
+ return cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, cadence->buf, NULL,
+ mtd->writesize +
+ mtd->oobsize,
+ 0, DMA_TO_DEVICE, false);
+}
+
+static int cadence_nand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ return cadence_nand_write_page_raw(mtd, chip, NULL, true, page);
+}
+
+static int cadence_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ int status;
+ int ecc_err_count = 0;
+
+ status = cadence_nand_select_target(chip);
+ if (status)
+ return status;
+
+ cadence_nand_set_skip_bytes_conf(cadence, cdns_chip->bbm_len,
+ mtd->writesize
+ + cdns_chip->bbm_offs, 1);
+
+ /*
+ * If data buffer can be accessed by DMA and data_control feature
+ * is supported then transfer data and oob directly.
+ */
+ if (cadence_nand_dma_buf_ok(cadence, buf, mtd->writesize) &&
+ cadence->caps2.data_control_supp && !(chip->options & NAND_USE_BOUNCE_BUFFER)) {
+ u8 *oob;
+
+ if (oob_required)
+ oob = chip->oob_poi;
+ else
+ oob = cadence->buf + mtd->writesize;
+
+ cadence_nand_prepare_data_size(mtd, TT_MAIN_OOB_AREA_EXT);
+ status = cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, buf, oob,
+ mtd->writesize,
+ cdns_chip->avail_oob_size,
+ DMA_FROM_DEVICE, true);
+ /* Otherwise use bounce buffer. */
+ } else {
+ cadence_nand_prepare_data_size(mtd, TT_MAIN_OOB_AREAS);
+ status = cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, cadence->buf,
+ NULL, mtd->writesize
+ + cdns_chip->avail_oob_size,
+ 0, DMA_FROM_DEVICE, true);
+
+ memcpy(buf, cadence->buf, mtd->writesize);
+ if (oob_required)
+ memcpy(chip->oob_poi,
+ cadence->buf + mtd->writesize,
+ mtd->oobsize);
+ }
+
+ switch (status) {
+ case STAT_ECC_UNCORR:
+ mtd->ecc_stats.failed++;
+ ecc_err_count++;
+ break;
+ case STAT_ECC_CORR:
+ ecc_err_count = FIELD_GET(CDMA_CS_MAXERR,
+ cadence->cdma_desc->status);
+ mtd->ecc_stats.corrected += ecc_err_count;
+ break;
+ case STAT_ERASED:
+ case STAT_OK:
+ break;
+ default:
+ dev_err(cadence->dev, "read page failed\n");
+ return -EIO;
+ }
+
+ if (oob_required)
+ if (cadence_nand_read_bbm(mtd, chip, page, chip->oob_poi))
+ return -EIO;
+
+ return ecc_err_count;
+}
+
+static int cadence_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+
+ return cadence_nand_read_page(mtd, chip, cadence->buf, 1, page);
+}
+
+static int cadence_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ int oob_skip = cdns_chip->bbm_len;
+ int writesize = mtd->writesize;
+ int ecc_steps = chip->ecc.steps;
+ int ecc_size = chip->ecc.size;
+ int ecc_bytes = chip->ecc.bytes;
+ void *tmp_buf = cadence->buf;
+ int i, pos, len;
+ int status;
+
+ status = cadence_nand_select_target(chip);
+ if (status)
+ return status;
+
+ cadence_nand_set_skip_bytes_conf(cadence, 0, 0, 0);
+
+ cadence_nand_prepare_data_size(mtd, TT_RAW_PAGE);
+ status = cadence_nand_cdma_transfer(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ page, cadence->buf, NULL,
+ mtd->writesize
+ + mtd->oobsize,
+ 0, DMA_FROM_DEVICE, false);
+
+ switch (status) {
+ case STAT_ERASED:
+ case STAT_OK:
+ break;
+ default:
+ dev_err(cadence->dev, "read raw page failed\n");
+ return -EIO;
+ }
+
+ /* Arrange the buffer for syndrome payload/ecc layout. */
+ if (buf) {
+ for (i = 0; i < ecc_steps; i++) {
+ pos = i * (ecc_size + ecc_bytes);
+ len = ecc_size;
+
+ if (pos >= writesize)
+ pos += oob_skip;
+ else if (pos + len > writesize)
+ len = writesize - pos;
+
+ memcpy(buf, tmp_buf + pos, len);
+ buf += len;
+ if (len < ecc_size) {
+ len = ecc_size - len;
+ memcpy(buf, tmp_buf + writesize + oob_skip,
+ len);
+ buf += len;
+ }
+ }
+ }
+
+ if (oob_required) {
+ u8 *oob = chip->oob_poi;
+ u32 oob_data_offset = (cdns_chip->sector_count - 1) *
+ (cdns_chip->sector_size + chip->ecc.bytes)
+ + cdns_chip->sector_size + oob_skip;
+
+ /* OOB free. */
+ memcpy(oob, tmp_buf + oob_data_offset,
+ cdns_chip->avail_oob_size);
+
+ /* BBM at the beginning of the OOB area. */
+ memcpy(oob, tmp_buf + writesize, oob_skip);
+
+ oob += cdns_chip->avail_oob_size;
+
+ /* OOB ECC */
+ for (i = 0; i < ecc_steps; i++) {
+ pos = ecc_size + i * (ecc_size + ecc_bytes);
+ len = ecc_bytes;
+
+ if (i == (ecc_steps - 1))
+ pos += cdns_chip->avail_oob_size;
+
+ if (pos >= writesize)
+ pos += oob_skip;
+ else if (pos + len > writesize)
+ len = writesize - pos;
+
+ memcpy(oob, tmp_buf + pos, len);
+ oob += len;
+ if (len < ecc_bytes) {
+ len = ecc_bytes - len;
+ memcpy(oob, tmp_buf + writesize + oob_skip,
+ len);
+ oob += len;
+ }
+ }
+ }
+ return 0;
+}
+
+static int cadence_nand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ return cadence_nand_read_page_raw(mtd, chip, NULL, true, page);
+}
+
+static void cadence_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ u8 thread_nr = 0;
+ u32 sdma_size;
+ int status;
+ int len_in_words = len >> 2;
+
+ /* Wait until slave DMA interface is ready to data transfer. */
+ status = cadence_nand_wait_on_sdma(cadence, &thread_nr, &sdma_size);
+ if (status) {
+ pr_err("Wait on sdma failed:%x\n", status);
+ hang();
+ }
+
+ if (!cadence->caps1->has_dma) {
+ readsq(cadence->io.virt, buf, len_in_words);
+
+ if (sdma_size > len) {
+ memcpy(cadence->buf, buf + (len_in_words << 2),
+ len - (len_in_words << 2));
+ readsl(cadence->io.virt, cadence->buf,
+ sdma_size / 4 - len_in_words);
+ }
+ }
+}
+
+static void cadence_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ u8 thread_nr = 0;
+ u32 sdma_size;
+ int status;
+ int len_in_words = len >> 2;
+
+ /* Wait until slave DMA interface is ready to data transfer. */
+ status = cadence_nand_wait_on_sdma(cadence, &thread_nr, &sdma_size);
+ if (status) {
+ pr_err("Wait on sdma failed:%x\n", status);
+ hang();
+ }
+
+ if (!cadence->caps1->has_dma) {
+ writesq(cadence->io.virt, buf, len_in_words);
+
+ if (sdma_size > len) {
+ memcpy(cadence->buf, buf + (len_in_words << 2),
+ len - (len_in_words << 2));
+ writesl(cadence->io.virt, cadence->buf,
+ sdma_size / 4 - len_in_words);
+ }
+ }
+}
+
+static int cadence_nand_cmd_opcode(struct nand_chip *chip, unsigned int op_id)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ u64 mini_ctrl_cmd = 0;
+ int ret;
+
+ mini_ctrl_cmd |= GCMD_LAY_TWB;
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_INSTR, GCMD_LAY_INSTR_CMD);
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_INPUT_CMD, op_id);
+
+ ret = cadence_nand_generic_cmd_send(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ mini_ctrl_cmd);
+
+ if (ret)
+ dev_err(cadence->dev, "send cmd %x failed\n",
+ op_id);
+
+ return ret;
+}
+
+static int cadence_nand_cmd_address(struct nand_chip *chip,
+ unsigned int naddrs, const u8 *addrs)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ u64 address = 0;
+ u64 mini_ctrl_cmd = 0;
+ int ret;
+ int i;
+
+ mini_ctrl_cmd |= GCMD_LAY_TWB;
+
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_INSTR,
+ GCMD_LAY_INSTR_ADDR);
+
+ for (i = 0; i < naddrs; i++)
+ address |= (u64)addrs[i] << (8 * i);
+
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_INPUT_ADDR,
+ address);
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_INPUT_ADDR_SIZE,
+ naddrs - 1);
+
+ ret = cadence_nand_generic_cmd_send(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ mini_ctrl_cmd);
+
+ if (ret)
+ pr_err("send address %llx failed\n", address);
+
+ return ret;
+}
+
+static int cadence_nand_cmd_data(struct nand_chip *chip,
+ unsigned int len, u8 mode)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ u64 mini_ctrl_cmd = 0;
+ int ret;
+
+ mini_ctrl_cmd |= GCMD_LAY_TWB;
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAY_INSTR,
+ GCMD_LAY_INSTR_DATA);
+
+ if (mode)
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_DIR, GCMD_DIR_WRITE);
+
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_SECT_CNT, 1);
+ mini_ctrl_cmd |= FIELD_PREP(GCMD_LAST_SIZE, len);
+
+ ret = cadence_nand_generic_cmd_send(cadence,
+ cdns_chip->cs[chip->cur_cs],
+ mini_ctrl_cmd);
+
+ if (ret) {
+ pr_err("send generic data cmd failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cadence_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ int status;
+
+ status = cadence_nand_wait_for_value(cadence, RBN_SETINGS,
+ TIMEOUT_US,
+ BIT(cdns_chip->cs[chip->cur_cs]),
+ false);
+ return status;
+}
+
+static int cadence_nand_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = cdns_chip->bbm_len;
+ oobregion->length = cdns_chip->avail_oob_size
+ - cdns_chip->bbm_len;
+
+ return 0;
+}
+
+static int cadence_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = cdns_chip->avail_oob_size;
+ oobregion->length = chip->ecc.total;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops cadence_nand_ooblayout_ops = {
+ .rfree = cadence_nand_ooblayout_free,
+ .ecc = cadence_nand_ooblayout_ecc,
+};
+
+static int calc_cycl(u32 timing, u32 clock)
+{
+ if (timing == 0 || clock == 0)
+ return 0;
+
+ if ((timing % clock) > 0)
+ return timing / clock;
+ else
+ return timing / clock - 1;
+}
+
+/* Calculate max data valid window. */
+static inline u32 calc_tdvw_max(u32 trp_cnt, u32 clk_period, u32 trhoh_min,
+ u32 board_delay_skew_min, u32 ext_mode)
+{
+ if (ext_mode == 0)
+ clk_period /= 2;
+
+ return (trp_cnt + 1) * clk_period + trhoh_min +
+ board_delay_skew_min;
+}
+
+/* Calculate data valid window. */
+static inline u32 calc_tdvw(u32 trp_cnt, u32 clk_period, u32 trhoh_min,
+ u32 trea_max, u32 ext_mode)
+{
+ if (ext_mode == 0)
+ clk_period /= 2;
+
+ return (trp_cnt + 1) * clk_period + trhoh_min - trea_max;
+}
+
+static inline int of_get_child_count(const ofnode node)
+{
+ return fdtdec_get_child_count(gd->fdt_blob, ofnode_to_offset(node));
+}
+
+static int cadence_setup_data_interface(struct mtd_info *mtd, int chipnr,
+ const struct nand_data_interface *conf)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(mtd_to_nand(mtd));
+ const struct nand_sdr_timings *sdr;
+ struct cadence_nand_timings *t = &cdns_chip->timings;
+ u32 reg;
+ u32 board_delay = cadence->board_delay;
+ u32 clk_period = DIV_ROUND_DOWN_ULL(1000000000000ULL,
+ cadence->nf_clk_rate);
+ u32 tceh_cnt, tcs_cnt, tadl_cnt, tccs_cnt;
+ u32 tfeat_cnt, trhz_cnt, tvdly_cnt;
+ u32 trhw_cnt, twb_cnt, twh_cnt = 0, twhr_cnt;
+ u32 twp_cnt = 0, trp_cnt = 0, trh_cnt = 0;
+ u32 if_skew = cadence->caps1->if_skew;
+ u32 board_delay_skew_min = board_delay - if_skew;
+ u32 board_delay_skew_max = board_delay + if_skew;
+ u32 dqs_sampl_res, phony_dqs_mod;
+ u32 tdvw, tdvw_min, tdvw_max;
+ u32 ext_rd_mode, ext_wr_mode;
+ u32 dll_phy_dqs_timing = 0, phony_dqs_timing = 0, rd_del_sel = 0;
+ u32 sampling_point;
+
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
+ memset(t, 0, sizeof(*t));
+ /* Sampling point calculation. */
+ if (cadence->caps2.is_phy_type_dll)
+ phony_dqs_mod = 2;
+ else
+ phony_dqs_mod = 1;
+
+ dqs_sampl_res = clk_period / phony_dqs_mod;
+
+ tdvw_min = sdr->tREA_max + board_delay_skew_max;
+ /*
+ * The idea of those calculation is to get the optimum value
+ * for tRP and tRH timings. If it is NOT possible to sample data
+ * with optimal tRP/tRH settings, the parameters will be extended.
+ * If clk_period is 50ns (the lowest value) this condition is met
+ * for SDR timing modes 1, 2, 3, 4 and 5.
+ * If clk_period is 20ns the condition is met only for SDR timing
+ * mode 5.
+ */
+ if (sdr->tRC_min <= clk_period &&
+ sdr->tRP_min <= (clk_period / 2) &&
+ sdr->tREH_min <= (clk_period / 2)) {
+ /* Performance mode. */
+ ext_rd_mode = 0;
+ tdvw = calc_tdvw(trp_cnt, clk_period, sdr->tRHOH_min,
+ sdr->tREA_max, ext_rd_mode);
+ tdvw_max = calc_tdvw_max(trp_cnt, clk_period, sdr->tRHOH_min,
+ board_delay_skew_min,
+ ext_rd_mode);
+ /*
+ * Check if data valid window and sampling point can be found
+ * and is not on the edge (ie. we have hold margin).
+ * If not extend the tRP timings.
+ */
+ if (tdvw > 0) {
+ if (tdvw_max <= tdvw_min ||
+ (tdvw_max % dqs_sampl_res) == 0) {
+ /*
+ * No valid sampling point so the RE pulse need
+ * to be widen widening by half clock cycle.
+ */
+ ext_rd_mode = 1;
+ }
+ } else {
+ /*
+ * There is no valid window
+ * to be able to sample data the tRP need to be widen.
+ * Very safe calculations are performed here.
+ */
+ trp_cnt = (sdr->tREA_max + board_delay_skew_max
+ + dqs_sampl_res) / clk_period;
+ ext_rd_mode = 1;
+ }
+
+ } else {
+ /* Extended read mode. */
+ u32 trh;
+
+ ext_rd_mode = 1;
+ trp_cnt = calc_cycl(sdr->tRP_min, clk_period);
+ trh = sdr->tRC_min - ((trp_cnt + 1) * clk_period);
+ if (sdr->tREH_min >= trh)
+ trh_cnt = calc_cycl(sdr->tREH_min, clk_period);
+ else
+ trh_cnt = calc_cycl(trh, clk_period);
+
+ tdvw = calc_tdvw(trp_cnt, clk_period, sdr->tRHOH_min,
+ sdr->tREA_max, ext_rd_mode);
+ /*
+ * Check if data valid window and sampling point can be found
+ * or if it is at the edge check if previous is valid
+ * - if not extend the tRP timings.
+ */
+ if (tdvw > 0) {
+ tdvw_max = calc_tdvw_max(trp_cnt, clk_period,
+ sdr->tRHOH_min,
+ board_delay_skew_min,
+ ext_rd_mode);
+
+ if ((((tdvw_max / dqs_sampl_res)
+ * dqs_sampl_res) <= tdvw_min) ||
+ (((tdvw_max % dqs_sampl_res) == 0) &&
+ (((tdvw_max / dqs_sampl_res - 1)
+ * dqs_sampl_res) <= tdvw_min))) {
+ /*
+ * Data valid window width is lower than
+ * sampling resolution and do not hit any
+ * sampling point to be sure the sampling point
+ * will be found the RE low pulse width will be
+ * extended by one clock cycle.
+ */
+ trp_cnt = trp_cnt + 1;
+ }
+ } else {
+ /*
+ * There is no valid window to be able to sample data.
+ * The tRP need to be widen.
+ * Very safe calculations are performed here.
+ */
+ trp_cnt = (sdr->tREA_max + board_delay_skew_max
+ + dqs_sampl_res) / clk_period;
+ }
+ }
+
+ tdvw_max = calc_tdvw_max(trp_cnt, clk_period,
+ sdr->tRHOH_min,
+ board_delay_skew_min, ext_rd_mode);
+
+ if (sdr->tWC_min <= clk_period &&
+ (sdr->tWP_min + if_skew) <= (clk_period / 2) &&
+ (sdr->tWH_min + if_skew) <= (clk_period / 2)) {
+ ext_wr_mode = 0;
+ } else {
+ u32 twh;
+
+ ext_wr_mode = 1;
+ twp_cnt = calc_cycl(sdr->tWP_min + if_skew, clk_period);
+ if ((twp_cnt + 1) * clk_period < (sdr->tALS_min + if_skew))
+ twp_cnt = calc_cycl(sdr->tALS_min + if_skew,
+ clk_period);
+
+ twh = (sdr->tWC_min - (twp_cnt + 1) * clk_period);
+ if (sdr->tWH_min >= twh)
+ twh = sdr->tWH_min;
+
+ twh_cnt = calc_cycl(twh + if_skew, clk_period);
+ }
+
+ reg = FIELD_PREP(ASYNC_TOGGLE_TIMINGS_TRH, trh_cnt);
+ reg |= FIELD_PREP(ASYNC_TOGGLE_TIMINGS_TRP, trp_cnt);
+ reg |= FIELD_PREP(ASYNC_TOGGLE_TIMINGS_TWH, twh_cnt);
+ reg |= FIELD_PREP(ASYNC_TOGGLE_TIMINGS_TWP, twp_cnt);
+ t->async_toggle_timings = reg;
+ dev_dbg(cadence->dev, "ASYNC_TOGGLE_TIMINGS_SDR\t%x\n", reg);
+
+ tadl_cnt = calc_cycl((sdr->tADL_min + if_skew), clk_period);
+ tccs_cnt = calc_cycl((sdr->tCCS_min + if_skew), clk_period);
+ twhr_cnt = calc_cycl((sdr->tWHR_min + if_skew), clk_period);
+ trhw_cnt = calc_cycl((sdr->tRHW_min + if_skew), clk_period);
+ reg = FIELD_PREP(TIMINGS0_TADL, tadl_cnt);
+
+ /*
+ * If timing exceeds delay field in timing register
+ * then use maximum value.
+ */
+ if (FIELD_FIT(TIMINGS0_TCCS, tccs_cnt))
+ reg |= FIELD_PREP(TIMINGS0_TCCS, tccs_cnt);
+ else
+ reg |= TIMINGS0_TCCS;
+
+ reg |= FIELD_PREP(TIMINGS0_TWHR, twhr_cnt);
+ reg |= FIELD_PREP(TIMINGS0_TRHW, trhw_cnt);
+ t->timings0 = reg;
+ dev_dbg(cadence->dev, "TIMINGS0_SDR\t%x\n", reg);
+
+ /* The following is related to single signal so skew is not needed. */
+ trhz_cnt = calc_cycl(sdr->tRHZ_max, clk_period);
+ trhz_cnt = trhz_cnt + 1;
+ twb_cnt = calc_cycl((sdr->tWB_max + board_delay), clk_period);
+ /*
+ * Because of the two stage syncflop the value must be increased by 3
+ * first value is related with sync, second value is related
+ * with output if delay.
+ */
+ twb_cnt = twb_cnt + 3 + 5;
+ /*
+ * The following is related to the we edge of the random data input
+ * sequence so skew is not needed.
+ */
+ tvdly_cnt = calc_cycl(500000 + if_skew, clk_period);
+ reg = FIELD_PREP(TIMINGS1_TRHZ, trhz_cnt);
+ reg |= FIELD_PREP(TIMINGS1_TWB, twb_cnt);
+ reg |= FIELD_PREP(TIMINGS1_TVDLY, tvdly_cnt);
+ t->timings1 = reg;
+ dev_dbg(cadence->dev, "TIMINGS1_SDR\t%x\n", reg);
+
+ tfeat_cnt = calc_cycl(sdr->tFEAT_max, clk_period);
+ if (tfeat_cnt < twb_cnt)
+ tfeat_cnt = twb_cnt;
+
+ tceh_cnt = calc_cycl(sdr->tCEH_min, clk_period);
+ tcs_cnt = calc_cycl((sdr->tCS_min + if_skew), clk_period);
+
+ reg = FIELD_PREP(TIMINGS2_TFEAT, tfeat_cnt);
+ reg |= FIELD_PREP(TIMINGS2_CS_HOLD_TIME, tceh_cnt);
+ reg |= FIELD_PREP(TIMINGS2_CS_SETUP_TIME, tcs_cnt);
+ t->timings2 = reg;
+ dev_dbg(cadence->dev, "TIMINGS2_SDR\t%x\n", reg);
+
+ if (cadence->caps2.is_phy_type_dll) {
+ reg = DLL_PHY_CTRL_DLL_RST_N;
+ if (ext_wr_mode)
+ reg |= DLL_PHY_CTRL_EXTENDED_WR_MODE;
+ if (ext_rd_mode)
+ reg |= DLL_PHY_CTRL_EXTENDED_RD_MODE;
+
+ reg |= FIELD_PREP(DLL_PHY_CTRL_RS_HIGH_WAIT_CNT, 7);
+ reg |= FIELD_PREP(DLL_PHY_CTRL_RS_IDLE_CNT, 7);
+ t->dll_phy_ctrl = reg;
+ dev_dbg(cadence->dev, "DLL_PHY_CTRL_SDR\t%x\n", reg);
+ }
+
+ /* Sampling point calculation. */
+ if ((tdvw_max % dqs_sampl_res) > 0)
+ sampling_point = tdvw_max / dqs_sampl_res;
+ else
+ sampling_point = (tdvw_max / dqs_sampl_res - 1);
+
+ if (sampling_point * dqs_sampl_res > tdvw_min) {
+ dll_phy_dqs_timing =
+ FIELD_PREP(PHY_DQS_TIMING_DQS_SEL_OE_END, 4);
+ dll_phy_dqs_timing |= PHY_DQS_TIMING_USE_PHONY_DQS;
+ phony_dqs_timing = sampling_point / phony_dqs_mod;
+
+ if ((sampling_point % 2) > 0) {
+ dll_phy_dqs_timing |= PHY_DQS_TIMING_PHONY_DQS_SEL;
+ if ((tdvw_max % dqs_sampl_res) == 0)
+ /*
+ * Calculation for sampling point at the edge
+ * of data and being odd number.
+ */
+ phony_dqs_timing = (tdvw_max / dqs_sampl_res)
+ / phony_dqs_mod - 1;
+
+ if (!cadence->caps2.is_phy_type_dll)
+ phony_dqs_timing--;
+
+ } else {
+ phony_dqs_timing--;
+ }
+ rd_del_sel = phony_dqs_timing + 3;
+ } else {
+ dev_warn(cadence->dev,
+ "ERROR : cannot find valid sampling point\n");
+ }
+
+ reg = FIELD_PREP(PHY_CTRL_PHONY_DQS, phony_dqs_timing);
+ if (cadence->caps2.is_phy_type_dll)
+ reg |= PHY_CTRL_SDR_DQS;
+ t->phy_ctrl = reg;
+ dev_dbg(cadence->dev, "PHY_CTRL_REG_SDR\t%x\n", reg);
+
+ if (cadence->caps2.is_phy_type_dll) {
+ dev_dbg(cadence->dev, "PHY_TSEL_REG_SDR\t%x\n", 0);
+ dev_dbg(cadence->dev, "PHY_DQ_TIMING_REG_SDR\t%x\n", 2);
+ dev_dbg(cadence->dev, "PHY_DQS_TIMING_REG_SDR\t%x\n",
+ dll_phy_dqs_timing);
+ t->phy_dqs_timing = dll_phy_dqs_timing;
+
+ reg = FIELD_PREP(PHY_GATE_LPBK_CTRL_RDS, rd_del_sel);
+ dev_dbg(cadence->dev, "PHY_GATE_LPBK_CTRL_REG_SDR\t%x\n",
+ reg);
+ t->phy_gate_lpbk_ctrl = reg;
+
+ dev_dbg(cadence->dev, "PHY_DLL_MASTER_CTRL_REG_SDR\t%lx\n",
+ PHY_DLL_MASTER_CTRL_BYPASS_MODE);
+ dev_dbg(cadence->dev, "PHY_DLL_SLAVE_CTRL_REG_SDR\t%x\n", 0);
+ }
+ return 0;
+}
+
+static int cadence_nand_attach_chip(struct nand_chip *chip)
+{
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
+ static struct nand_ecclayout nand_oob;
+ u32 ecc_size;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret;
+
+ if (chip->options & NAND_BUSWIDTH_16) {
+ ret = cadence_nand_set_access_width16(cadence, true);
+ if (ret)
+ return ret;
+ }
+
+ chip->options |= NAND_USE_BOUNCE_BUFFER;
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+ chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
+
+ cdns_chip->bbm_offs = chip->badblockpos;
+ cdns_chip->bbm_offs &= ~0x01;
+ /* this value should be even number */
+ cdns_chip->bbm_len = 2;
+
+ ret = cadence_ecc_setup(mtd, chip, mtd->oobsize - cdns_chip->bbm_len);
+ if (ret) {
+ dev_err(cadence->dev, "ECC configuration failed\n");
+ return ret;
+ }
+
+ dev_dbg(cadence->dev,
+ "chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+ chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+
+ /* Error correction configuration. */
+ cdns_chip->sector_size = chip->ecc.size;
+ cdns_chip->sector_count = mtd->writesize / cdns_chip->sector_size;
+ ecc_size = cdns_chip->sector_count * chip->ecc.bytes;
+
+ cdns_chip->avail_oob_size = mtd->oobsize - ecc_size;
+
+ if (cdns_chip->avail_oob_size > cadence->bch_metadata_size)
+ cdns_chip->avail_oob_size = cadence->bch_metadata_size;
+
+ if ((cdns_chip->avail_oob_size + cdns_chip->bbm_len + ecc_size)
+ > mtd->oobsize)
+ cdns_chip->avail_oob_size -= 4;
+
+ ret = cadence_nand_get_ecc_strength_idx(cadence, chip->ecc.strength);
+ if (ret < 0)
+ return -EINVAL;
+
+ cdns_chip->corr_str_idx = (u8)ret;
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ cadence_nand_set_ecc_strength(cadence,
+ cdns_chip->corr_str_idx);
+
+ cadence_nand_set_erase_detection(cadence, true,
+ chip->ecc.strength);
+
+ dev_dbg(cadence->dev,
+ "chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+ chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+
+ /* Override the default read operations. */
+ chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
+ chip->ecc.read_page = cadence_nand_read_page;
+ chip->ecc.read_page_raw = cadence_nand_read_page_raw;
+ chip->ecc.write_page = cadence_nand_write_page;
+ chip->ecc.write_page_raw = cadence_nand_write_page_raw;
+ chip->ecc.read_oob = cadence_nand_read_oob;
+ chip->ecc.write_oob = cadence_nand_write_oob;
+ chip->ecc.read_oob_raw = cadence_nand_read_oob_raw;
+ chip->ecc.write_oob_raw = cadence_nand_write_oob_raw;
+ chip->erase = cadence_nand_erase;
+
+ if ((mtd->writesize + mtd->oobsize) > cadence->buf_size)
+ cadence->buf_size = mtd->writesize + mtd->oobsize;
+
+ mtd_set_ooblayout(mtd, &cadence_nand_ooblayout_ops);
+
+ nand_oob.eccbytes = cdns_chip->chip.ecc.bytes;
+ cdns_chip->chip.ecc.layout = &nand_oob;
+
+ return 0;
+}
+
+/* Dummy implementation: we don't support multiple chips */
+static void cadence_nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+ switch (chipnr) {
+ case -1:
+ case 0:
+ break;
+
+ default:
+ WARN_ON(chipnr);
+ }
+}
+
+static int cadence_nand_status(struct mtd_info *mtd, unsigned int command)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+
+ ret = cadence_nand_cmd_opcode(chip, command);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_cmd_data(chip, 1, GCMD_DIR_READ);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int cadence_nand_readid(struct mtd_info *mtd, int offset_in_page, unsigned int command)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ u8 addrs = (u8)offset_in_page;
+ int ret = 0;
+
+ ret = cadence_nand_cmd_opcode(chip, command);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_cmd_address(chip, ONE_CYCLE, &addrs);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_cmd_data(chip, 8, GCMD_DIR_READ);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int cadence_nand_param(struct mtd_info *mtd, u8 offset_in_page, unsigned int command)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+
+ ret = cadence_nand_cmd_opcode(chip, command);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_cmd_address(chip, ONE_CYCLE, &offset_in_page);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_waitfunc(mtd, chip);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_cmd_data(chip, sizeof(struct nand_jedec_params), GCMD_DIR_READ);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int cadence_nand_reset(struct mtd_info *mtd, unsigned int command)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+
+ ret = cadence_nand_cmd_opcode(chip, command);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_waitfunc(mtd, chip);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int cadence_nand_features(struct mtd_info *mtd, u8 offset_in_page, u32 command)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+
+ ret = cadence_nand_cmd_opcode(chip, command);
+ if (ret)
+ return ret;
+
+ ret = cadence_nand_cmd_address(chip, ONE_CYCLE, &offset_in_page);
+ if (ret)
+ return ret;
+
+ if (command == NAND_CMD_GET_FEATURES)
+ ret = cadence_nand_cmd_data(chip, ONFI_SUBFEATURE_PARAM_LEN,
+ GCMD_DIR_READ);
+ else
+ ret = cadence_nand_cmd_data(chip, ONFI_SUBFEATURE_PARAM_LEN,
+ GCMD_DIR_WRITE);
+
+ return ret;
+}
+
+static void cadence_nand_cmdfunc(struct mtd_info *mtd, unsigned int command,
+ int offset_in_page, int page)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ int ret = 0;
+
+ cadence->cmd = command;
+ switch (command) {
+ case NAND_CMD_STATUS:
+ ret = cadence_nand_status(mtd, command);
+ break;
+
+ case NAND_CMD_READID:
+ ret = cadence_nand_readid(mtd, offset_in_page, command);
+ break;
+
+ case NAND_CMD_PARAM:
+ ret = cadence_nand_param(mtd, offset_in_page, command);
+ break;
+
+ case NAND_CMD_RESET:
+ ret = cadence_nand_reset(mtd, command);
+ break;
+
+ case NAND_CMD_SET_FEATURES:
+ case NAND_CMD_GET_FEATURES:
+ ret = cadence_nand_features(mtd, offset_in_page, command);
+ break;
+ /*
+ * ecc will override other command for read, write and erase
+ */
+ default:
+ break;
+ }
+
+ if (cadence->cmd == NAND_CMD_RESET) {
+ ret = cadence_nand_select_target(chip);
+ if (ret)
+ dev_err(cadence->dev, "Chip select failure after reset\n");
+ }
+
+ if (ret != 0)
+ printf("ERROR:%s:command:0x%x\n", __func__, cadence->cmd);
+}
+
+static int cadence_nand_dev_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+
+ if (cadence_nand_wait_for_value(cadence, CTRL_STATUS,
+ TIMEOUT_US,
+ CTRL_STATUS_CTRL_BUSY, true))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static u8 cadence_nand_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct cadence_nand_info *cadence = to_cadence_nand_info(chip->controller);
+ u32 size = 1;
+ u8 val;
+
+ if (cadence->buf_index == 0) {
+ if (cadence->cmd == NAND_CMD_READID)
+ size = 8;
+ else if (cadence->cmd == NAND_CMD_PARAM)
+ size = sizeof(struct nand_jedec_params);
+ else if (cadence->cmd == NAND_CMD_GET_FEATURES)
+ size = ONFI_SUBFEATURE_PARAM_LEN;
+
+ cadence_nand_read_buf(mtd, &cadence->buf[0], size);
+ }
+
+ val = *(&cadence->buf[0] + cadence->buf_index);
+ cadence->buf_index++;
+
+ return val;
+}
+
+static void cadence_nand_write_byte(struct mtd_info *mtd, u8 byte)
+{
+ cadence_nand_write_buf(mtd, &byte, 1);
+}
+
+static int cadence_nand_chip_init(struct cadence_nand_info *cadence, ofnode node)
+{
+ struct cdns_nand_chip *cdns_chip;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ int ret, i;
+ int nsels;
+ u32 cs;
+
+ if (!ofnode_get_property(node, "reg", &nsels))
+ return -ENODEV;
+
+ nsels /= sizeof(u32);
+ if (nsels <= 0) {
+ dev_err(cadence->dev, "invalid reg property size %d\n", nsels);
+ return -EINVAL;
+ }
+
+ cdns_chip = devm_kzalloc(cadence->dev, sizeof(*cdns_chip) +
+ (nsels * sizeof(u8)), GFP_KERNEL);
+ if (!cdns_chip)
+ return -ENODEV;
+
+ cdns_chip->nsels = nsels;
+ for (i = 0; i < nsels; i++) {
+ /* Retrieve CS id. */
+ ret = ofnode_read_u32_index(node, "reg", i, &cs);
+ if (ret) {
+ dev_err(cadence->dev,
+ "could not retrieve reg property: %d\n",
+ ret);
+ goto free_buf;
+ }
+
+ if (cs >= cadence->caps2.max_banks) {
+ dev_err(cadence->dev,
+ "invalid reg value: %u (max CS = %d)\n",
+ cs, cadence->caps2.max_banks);
+ ret = -EINVAL;
+ goto free_buf;
+ }
+
+ if (test_and_set_bit(cs, &cadence->assigned_cs)) {
+ dev_err(cadence->dev,
+ "CS %d already assigned\n", cs);
+ ret = -EINVAL;
+ goto free_buf;
+ }
+
+ cdns_chip->cs[i] = cs;
+ }
+
+ chip = &cdns_chip->chip;
+ chip->controller = &cadence->controller;
+ nand_set_flash_node(chip, node);
+ mtd = nand_to_mtd(chip);
+ mtd->dev->parent = cadence->dev;
+
+ chip->options |= NAND_BUSWIDTH_AUTO;
+ chip->select_chip = cadence_nand_select_chip;
+ chip->cmdfunc = cadence_nand_cmdfunc;
+ chip->dev_ready = cadence_nand_dev_ready;
+ chip->read_byte = cadence_nand_read_byte;
+ chip->write_byte = cadence_nand_write_byte;
+ chip->waitfunc = cadence_nand_waitfunc;
+ chip->read_buf = cadence_nand_read_buf;
+ chip->write_buf = cadence_nand_write_buf;
+ chip->setup_data_interface = cadence_setup_data_interface;
+
+ ret = nand_scan_ident(mtd, 1, NULL);
+ if (ret) {
+ dev_err(cadence->dev, "Chip identification failure\n");
+ goto free_buf;
+ }
+
+ ret = cadence_nand_attach_chip(chip);
+ if (ret) {
+ dev_err(cadence->dev, "Chip not able to attached\n");
+ goto free_buf;
+ }
+
+ ret = nand_scan_tail(mtd);
+ if (ret) {
+ dev_err(cadence->dev, "could not scan the nand chip\n");
+ goto free_buf;
+ }
+
+ ret = nand_register(0, mtd);
+ if (ret) {
+ dev_err(cadence->dev, "Failed to register MTD: %d\n", ret);
+ goto free_buf;
+ }
+
+ return 0;
+
+free_buf:
+ devm_kfree(cadence->dev, cdns_chip);
+ return ret;
+}
+
+static int cadence_nand_chips_init(struct cadence_nand_info *cadence)
+{
+ struct udevice *dev = cadence->dev;
+ ofnode node = dev_ofnode(dev);
+ ofnode nand_node;
+ int max_cs = cadence->caps2.max_banks;
+ int nchips, ret;
+
+ nchips = of_get_child_count(node);
+
+ if (nchips > max_cs) {
+ dev_err(cadence->dev,
+ "too many NAND chips: %d (max = %d CS)\n",
+ nchips, max_cs);
+ return -EINVAL;
+ }
+
+ ofnode_for_each_subnode(nand_node, node) {
+ ret = cadence_nand_chip_init(cadence, nand_node);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cadence_nand_init(struct cadence_nand_info *cadence)
+{
+ int ret;
+
+ cadence->cdma_desc = dma_alloc_coherent(sizeof(*cadence->cdma_desc),
+ (unsigned long *)&cadence->dma_cdma_desc);
+ if (!cadence->cdma_desc)
+ return -ENOMEM;
+
+ cadence->buf_size = SZ_16K;
+ cadence->buf = kmalloc(cadence->buf_size, GFP_KERNEL);
+ if (!cadence->buf) {
+ ret = -ENOMEM;
+ goto free_buf_desc;
+ }
+
+ //Hardware initialization
+ ret = cadence_nand_hw_init(cadence);
+ if (ret)
+ goto free_buf;
+
+ cadence->curr_corr_str_idx = 0xFF;
+
+ ret = cadence_nand_chips_init(cadence);
+ if (ret) {
+ dev_err(cadence->dev, "Failed to register MTD: %d\n",
+ ret);
+ goto free_buf;
+ }
+
+ kfree(cadence->buf);
+ cadence->buf = kzalloc(cadence->buf_size, GFP_KERNEL);
+ if (!cadence->buf) {
+ ret = -ENOMEM;
+ goto free_buf_desc;
+ }
+
+ return 0;
+
+free_buf:
+ kfree(cadence->buf);
+
+free_buf_desc:
+ dma_free_coherent(cadence->cdma_desc);
+
+ return ret;
+}
+
+static const struct cadence_nand_dt_devdata cadence_nand_default = {
+ .if_skew = 0,
+ .has_dma = 0,
+};
+
+static const struct udevice_id cadence_nand_dt_ids[] = {
+ {
+ .compatible = "cdns,nand",
+ .data = (unsigned long)&cadence_nand_default
+ }, {}
+};
+
+static int cadence_nand_dt_probe(struct udevice *dev)
+{
+ struct cadence_nand_info *cadence = dev_get_priv(dev);
+ const struct udevice_id *of_id;
+ const struct cadence_nand_dt_devdata *devdata;
+ struct resource res;
+ int ret;
+ u32 val;
+
+ if (!dev) {
+ dev_warn(dev, "Device ptr null\n");
+ return -EINVAL;
+ }
+
+ of_id = &cadence_nand_dt_ids[0];
+ devdata = (struct cadence_nand_dt_devdata *)of_id->data;
+
+ cadence->caps1 = devdata;
+ cadence->dev = dev;
+
+ ret = clk_get_by_index(dev, 0, &cadence->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&cadence->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOMEM) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+ cadence->nf_clk_rate = clk_get_rate(&cadence->clk);
+
+ ret = reset_get_by_index(dev, 1, &cadence->softphy_reset);
+ if (ret) {
+ if (ret != -ENOMEM)
+ dev_warn(dev, "Can't get softphy_reset: %d\n", ret);
+ } else {
+ reset_deassert(&cadence->softphy_reset);
+ }
+
+ ret = reset_get_by_index(dev, 0, &cadence->nand_reset);
+ if (ret) {
+ if (ret != -ENOMEM)
+ dev_warn(dev, "Can't get nand_reset: %d\n", ret);
+ } else {
+ reset_deassert(&cadence->nand_reset);
+ }
+
+ ret = dev_read_resource_byname(dev, "reg", &res);
+ if (ret)
+ return ret;
+ cadence->reg = devm_ioremap(dev, res.start, resource_size(&res));
+
+ ret = dev_read_resource_byname(dev, "sdma", &res);
+ if (ret)
+ return ret;
+ cadence->io.dma = res.start;
+ cadence->io.virt = devm_ioremap(dev, res.start, resource_size(&res));
+
+ ret = ofnode_read_u32(dev_ofnode(dev->parent),
+ "cdns,board-delay-ps", &val);
+ if (ret) {
+ val = 4830;
+ dev_info(cadence->dev,
+ "missing cdns,board-delay-ps property, %d was set\n",
+ val);
+ }
+ cadence->board_delay = val;
+
+ ret = cadence_nand_init(cadence);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(cadence_nand_dt) = {
+ .name = "cadence-nand-dt",
+ .id = UCLASS_MTD,
+ .of_match = cadence_nand_dt_ids,
+ .probe = cadence_nand_dt_probe,
+ .priv_auto = sizeof(struct cadence_nand_info),
+};
+
+void board_nand_init(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get_device_by_driver(UCLASS_MTD,
+ DM_DRIVER_GET(cadence_nand_dt),
+ &dev);
+ if (ret && ret != -ENODEV)
+ pr_err("Failed to initialize Cadence NAND controller. (error %d)\n",
+ ret);
+}
diff --git a/drivers/mtd/nand/raw/cadence_spl.c b/drivers/mtd/nand/raw/cadence_spl.c
new file mode 100644
index 00000000000..17058e49faa
--- /dev/null
+++ b/drivers/mtd/nand/raw/cadence_spl.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Intel Corporation <www.intel.com>
+ */
+
+#include <cadence-nand.h>
+#include <dm.h>
+#include <hang.h>
+#include <nand.h>
+#include <system-constants.h>
+
+/* Unselect after operation */
+void nand_deselect(void)
+{
+ struct mtd_info *mtd;
+ struct nand_chip *chip;
+
+ mtd = get_nand_dev_by_index(nand_curr_device);
+ if (!mtd)
+ hang();
+ chip = mtd_to_nand(mtd);
+
+ if (chip->select_chip)
+ chip->select_chip(mtd, -1);
+}
+
+static int nand_is_bad_block(int block)
+{
+ struct mtd_info *mtd;
+ struct nand_chip *chip;
+ loff_t ofs = block * CONFIG_SYS_NAND_BLOCK_SIZE;
+
+ mtd = get_nand_dev_by_index(nand_curr_device);
+ if (!mtd)
+ hang();
+ chip = mtd_to_nand(mtd);
+
+ return chip->block_bad(mtd, ofs);
+}
+
+static int nand_read_page(int block, int page, uchar *dst)
+{
+ struct mtd_info *mtd;
+ int page_addr = block * SYS_NAND_BLOCK_PAGES + page;
+ loff_t ofs = page_addr * CONFIG_SYS_NAND_PAGE_SIZE;
+ int ret;
+ size_t len = CONFIG_SYS_NAND_PAGE_SIZE;
+
+ mtd = get_nand_dev_by_index(nand_curr_device);
+ if (!mtd)
+ hang();
+
+ ret = nand_read(mtd, ofs, &len, dst);
+ if (ret)
+ printf("nand_read failed %d\n", ret);
+
+ return ret;
+}
+#include "nand_spl_loaders.c"
diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c
index 28c851f103b..7e683f49c5e 100644
--- a/drivers/mtd/nand/raw/meson_nand.c
+++ b/drivers/mtd/nand/raw/meson_nand.c
@@ -618,9 +618,7 @@ static int meson_nfc_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *ch
memcpy(meson_chip->data_buf, buf, mtd->writesize);
memset(meson_chip->info_buf, 0, chip->ecc.steps * PER_INFO_BYTE);
-
- if (oob_required)
- meson_nfc_set_user_byte(chip, chip->oob_poi);
+ meson_nfc_set_user_byte(chip, chip->oob_poi);
return meson_nfc_write_page_sub(chip, page, false);
}
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 1b65c6f6443..bb5460e0068 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -306,6 +306,35 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
}
+/*
+ * nand_bbm_get_next_page - Get the next page for bad block markers
+ * @chip: The NAND chip
+ * @page: First page to start checking for bad block marker usage
+ *
+ * Returns an integer that corresponds to the page offset within a block, for
+ * a page that is used to store bad block markers. If no more pages are
+ * available, -EINVAL is returned.
+ */
+int nand_bbm_get_next_page(struct nand_chip *chip, int page)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int last_page = ((mtd->erasesize - mtd->writesize) >>
+ chip->page_shift) & chip->pagemask;
+ unsigned int bbm_flags = NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE
+ | NAND_BBM_LASTPAGE;
+
+ if (page == 0 && !(chip->options & bbm_flags))
+ return 0;
+ if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE)
+ return 0;
+ if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
+ return 1;
+ if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
+ return last_page;
+
+ return -EINVAL;
+}
+
/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @mtd: MTD device structure
@@ -315,40 +344,32 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
*/
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{
- int page, res = 0, i = 0;
struct nand_chip *chip = mtd_to_nand(mtd);
- u16 bad;
+ int first_page, page_offset;
+ int res;
+ u8 bad;
- if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
- ofs += mtd->erasesize - mtd->writesize;
+ first_page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+ page_offset = nand_bbm_get_next_page(chip, 0);
- page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+ while (page_offset >= 0) {
+ res = chip->ecc.read_oob(mtd, chip, first_page + page_offset);
+ if (res < 0)
+ return res;
- do {
- if (chip->options & NAND_BUSWIDTH_16) {
- chip->cmdfunc(mtd, NAND_CMD_READOOB,
- chip->badblockpos & 0xFE, page);
- bad = cpu_to_le16(chip->read_word(mtd));
- if (chip->badblockpos & 0x1)
- bad >>= 8;
- else
- bad &= 0xFF;
- } else {
- chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
- page);
- bad = chip->read_byte(mtd);
- }
+ bad = chip->oob_poi[chip->badblockpos];
if (likely(chip->badblockbits == 8))
res = bad != 0xFF;
else
res = hweight8(bad) < chip->badblockbits;
- ofs += mtd->writesize;
- page = (int)(ofs >> chip->page_shift) & chip->pagemask;
- i++;
- } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+ if (res)
+ return res;
- return res;
+ page_offset = nand_bbm_get_next_page(chip, page_offset + 1);
+ }
+
+ return 0;
}
/**
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index f15ee4f833f..2b95eb02177 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -10,6 +10,16 @@ config MULTIPLEXER
if MULTIPLEXER
+config SPL_MUX_MMIO
+ bool "MMIO register bitfield-controlled Multiplexer"
+ depends on MULTIPLEXER && SYSCON
+ help
+ MMIO register bitfield-controlled Multiplexer controller.
+
+ The driver builds multiplexer controllers for bitfields in a syscon
+ register. For N bit wide bitfields, there will be 2^N possible
+ multiplexer states.
+
config MUX_MMIO
bool "MMIO register bitfield-controlled Multiplexer"
depends on MULTIPLEXER && SYSCON
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1563404ca17..3db784faedd 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -237,6 +237,13 @@ config DWC_ETH_QOS
Of Service) IP block. The IP supports many options for bus type,
clocking/reset structure, and feature list.
+config DWC_ETH_QOS_ADI
+ bool "Synopsys DWC Ethernet QOS device support for ADI SC59x-64 parts"
+ depends on DWC_ETH_QOS
+ help
+ The Synopsis Designware Ethernet QoS IP block with the specific
+ configuration used in the ADI ADSP-SC59X 64 bit SoCs
+
config DWC_ETH_QOS_IMX
bool "Synopsys DWC Ethernet QOS device support for IMX"
depends on DWC_ETH_QOS
@@ -852,6 +859,7 @@ config RENESAS_ETHER_SWITCH
config RENESAS_RAVB
bool "Renesas Ethernet AVB MAC"
depends on RCAR_64
+ select BITBANGMII
select PHYLIB
select PHY_ETHERNET_ID
help
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 80d70212971..d919d437c08 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
+obj-$(CONFIG_DWC_ETH_QOS_ADI) += dwc_eth_qos_adi.o
obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
obj-$(CONFIG_DWC_ETH_QOS_INTEL) += dwc_eth_qos_intel.o
obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 0a1fff38727..0f93c25e3fe 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -33,6 +33,9 @@
#include <linux/printk.h>
#include <power/regulator.h>
#include "designware.h"
+#if IS_ENABLED(CONFIG_ARCH_NPCM8XX)
+#include <asm/arch/gmac.h>
+#endif
static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
{
@@ -223,6 +226,136 @@ static int dw_dm_mdio_init(const char *name, void *priv)
}
#endif
+#if IS_ENABLED(CONFIG_BITBANGMII) && IS_ENABLED(CONFIG_DM_GPIO)
+static int dw_eth_bb_mdio_active(struct mii_dev *miidev)
+{
+ struct dw_eth_dev *priv = miidev->priv;
+ struct gpio_desc *desc = &priv->mdio_gpio;
+
+ desc->flags = 0;
+ dm_gpio_set_dir_flags(&priv->mdio_gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+ return 0;
+}
+
+static int dw_eth_bb_mdio_tristate(struct mii_dev *miidev)
+{
+ struct dw_eth_dev *priv = miidev->priv;
+ struct gpio_desc *desc = &priv->mdio_gpio;
+
+ desc->flags = 0;
+ dm_gpio_set_dir_flags(&priv->mdio_gpio, GPIOD_IS_IN);
+
+ return 0;
+}
+
+static int dw_eth_bb_set_mdio(struct mii_dev *miidev, int v)
+{
+ struct dw_eth_dev *priv = miidev->priv;
+
+ if (v)
+ dm_gpio_set_value(&priv->mdio_gpio, 1);
+ else
+ dm_gpio_set_value(&priv->mdio_gpio, 0);
+
+ return 0;
+}
+
+static int dw_eth_bb_get_mdio(struct mii_dev *miidev, int *v)
+{
+ struct dw_eth_dev *priv = miidev->priv;
+
+ *v = dm_gpio_get_value(&priv->mdio_gpio);
+
+ return 0;
+}
+
+static int dw_eth_bb_set_mdc(struct mii_dev *miidev, int v)
+{
+ struct dw_eth_dev *priv = miidev->priv;
+
+ if (v)
+ dm_gpio_set_value(&priv->mdc_gpio, 1);
+ else
+ dm_gpio_set_value(&priv->mdc_gpio, 0);
+
+ return 0;
+}
+
+static int dw_eth_bb_delay(struct mii_dev *miidev)
+{
+ struct dw_eth_dev *priv = miidev->priv;
+
+ udelay(priv->bb_delay);
+ return 0;
+}
+
+static const struct bb_miiphy_bus_ops dw_eth_bb_miiphy_bus_ops = {
+ .mdio_active = dw_eth_bb_mdio_active,
+ .mdio_tristate = dw_eth_bb_mdio_tristate,
+ .set_mdio = dw_eth_bb_set_mdio,
+ .get_mdio = dw_eth_bb_get_mdio,
+ .set_mdc = dw_eth_bb_set_mdc,
+ .delay = dw_eth_bb_delay,
+};
+
+static int dw_bb_miiphy_read(struct mii_dev *miidev, int addr,
+ int devad, int reg)
+{
+ return bb_miiphy_read(miidev, &dw_eth_bb_miiphy_bus_ops,
+ addr, devad, reg);
+}
+
+static int dw_bb_miiphy_write(struct mii_dev *miidev, int addr,
+ int devad, int reg, u16 value)
+{
+ return bb_miiphy_write(miidev, &dw_eth_bb_miiphy_bus_ops,
+ addr, devad, reg, value);
+}
+
+static int dw_bb_mdio_init(const char *name, struct udevice *dev)
+{
+ struct dw_eth_dev *dwpriv = dev_get_priv(dev);
+ struct mii_dev *bus = mdio_alloc();
+ int ret;
+
+ if (!bus) {
+ printf("Failed to allocate MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ debug("\n%s: use bitbang mii..\n", dev->name);
+ ret = gpio_request_by_name(dev, "snps,mdc-gpio", 0,
+ &dwpriv->mdc_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret) {
+ debug("no mdc-gpio\n");
+ return ret;
+ }
+ ret = gpio_request_by_name(dev, "snps,mdio-gpio", 0,
+ &dwpriv->mdio_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret) {
+ debug("no mdio-gpio\n");
+ return ret;
+ }
+ dwpriv->bb_delay = dev_read_u32_default(dev, "snps,bitbang-delay", 1);
+
+ dwpriv->bus = bus;
+ dwpriv->dev = dev;
+
+ snprintf(bus->name, sizeof(bus->name), "%s", name);
+ bus->read = dw_bb_miiphy_read;
+ bus->write = dw_bb_miiphy_write;
+#if CONFIG_IS_ENABLED(DM_GPIO)
+ bus->reset = dw_mdio_reset;
+#endif
+ bus->priv = dwpriv;
+
+ return mdio_register(bus);
+}
+#endif
+
static void tx_descs_init(struct dw_eth_dev *priv)
{
struct eth_dma_regs *dma_p = priv->dma_regs_p;
@@ -352,10 +485,35 @@ static int dw_adjust_link(struct dw_eth_dev *priv, struct eth_mac_regs *mac_p,
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
#ifdef CONFIG_ARCH_NPCM8XX
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ unsigned int start;
+
+ /* Indirect access to VR_MII_MMD registers */
+ writew((VR_MII_MMD >> 9), PCS_BA + PCS_IND_AC);
+ /* Set PCS_Mode to SGMII */
+ clrsetbits_le16(PCS_BA + VR_MII_MMD_AN_CTRL, BIT(1), BIT(2));
+ /* Set Auto Speed Mode Change */
+ setbits_le16(PCS_BA + VR_MII_MMD_CTRL1, BIT(9));
+ /* Indirect access to SR_MII_MMD registers */
+ writew((SR_MII_MMD >> 9), PCS_BA + PCS_IND_AC);
+ /* Restart Auto-Negotiation */
+ setbits_le16(PCS_BA + SR_MII_MMD_CTRL, BIT(9) | BIT(12));
+
+ printf("SGMII PHY Wait for link up \n");
+ /* SGMII PHY Wait for link up */
+ start = get_timer(0);
+ while (!(readw(PCS_BA + SR_MII_MMD_STS) & BIT(2))) {
+ if (get_timer(start) >= LINK_UP_TIMEOUT) {
+ printf("PHY link up timeout\n");
+ return -ETIMEDOUT;
+ }
+ mdelay(1);
+ };
+ }
/* Pass all Multicast Frames */
setbits_le32(&mac_p->framefilt, BIT(4));
-
#endif
+
return 0;
}
@@ -784,51 +942,29 @@ int designware_eth_probe(struct udevice *dev)
priv->interface = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
-#if IS_ENABLED(CONFIG_DM_MDIO)
- ret = dw_dm_mdio_init(dev->name, dev);
-#else
- ret = dw_mdio_init(dev->name, dev);
-#endif
- if (ret) {
- err = ret;
- goto mdio_err;
- }
- priv->bus = miiphy_get_dev_by_name(dev->name);
- priv->dev = dev;
-
#if IS_ENABLED(CONFIG_BITBANGMII) && IS_ENABLED(CONFIG_DM_GPIO)
if (dev_read_bool(dev, "snps,bitbang-mii")) {
- int bus_idx;
-
- debug("\n%s: use bitbang mii..\n", dev->name);
- ret = gpio_request_by_name(dev, "snps,mdc-gpio", 0,
- &priv->mdc_gpio, GPIOD_IS_OUT
- | GPIOD_IS_OUT_ACTIVE);
+ ret = dw_bb_mdio_init(dev->name, dev);
if (ret) {
- debug("no mdc-gpio\n");
- return ret;
+ err = ret;
+ goto mdio_err;
}
- ret = gpio_request_by_name(dev, "snps,mdio-gpio", 0,
- &priv->mdio_gpio, GPIOD_IS_OUT
- | GPIOD_IS_OUT_ACTIVE);
+ } else
+#endif
+ {
+#if IS_ENABLED(CONFIG_DM_MDIO)
+ ret = dw_dm_mdio_init(dev->name, dev);
+#else
+ ret = dw_mdio_init(dev->name, dev);
+#endif
if (ret) {
- debug("no mdio-gpio\n");
- return ret;
- }
- priv->bb_delay = dev_read_u32_default(dev, "snps,bitbang-delay", 1);
-
- for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; bus_idx++) {
- if (!bb_miiphy_buses[bus_idx].priv) {
- bb_miiphy_buses[bus_idx].priv = priv;
- strlcpy(bb_miiphy_buses[bus_idx].name, priv->bus->name,
- MDIO_NAME_LEN);
- priv->bus->read = bb_miiphy_read;
- priv->bus->write = bb_miiphy_write;
- break;
- }
+ err = ret;
+ goto mdio_err;
}
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+ priv->dev = dev;
}
-#endif
+
ret = dw_phy_init(priv, dev);
debug("%s, ret=%d\n", __func__, ret);
if (!ret)
@@ -939,83 +1075,3 @@ static struct pci_device_id supported[] = {
};
U_BOOT_PCI_DEVICE(eth_designware, supported);
-
-#if IS_ENABLED(CONFIG_BITBANGMII) && IS_ENABLED(CONFIG_DM_GPIO)
-static int dw_eth_bb_mdio_active(struct bb_miiphy_bus *bus)
-{
- struct dw_eth_dev *priv = bus->priv;
- struct gpio_desc *desc = &priv->mdio_gpio;
-
- desc->flags = 0;
- dm_gpio_set_dir_flags(&priv->mdio_gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
-
- return 0;
-}
-
-static int dw_eth_bb_mdio_tristate(struct bb_miiphy_bus *bus)
-{
- struct dw_eth_dev *priv = bus->priv;
- struct gpio_desc *desc = &priv->mdio_gpio;
-
- desc->flags = 0;
- dm_gpio_set_dir_flags(&priv->mdio_gpio, GPIOD_IS_IN);
-
- return 0;
-}
-
-static int dw_eth_bb_set_mdio(struct bb_miiphy_bus *bus, int v)
-{
- struct dw_eth_dev *priv = bus->priv;
-
- if (v)
- dm_gpio_set_value(&priv->mdio_gpio, 1);
- else
- dm_gpio_set_value(&priv->mdio_gpio, 0);
-
- return 0;
-}
-
-static int dw_eth_bb_get_mdio(struct bb_miiphy_bus *bus, int *v)
-{
- struct dw_eth_dev *priv = bus->priv;
-
- *v = dm_gpio_get_value(&priv->mdio_gpio);
-
- return 0;
-}
-
-static int dw_eth_bb_set_mdc(struct bb_miiphy_bus *bus, int v)
-{
- struct dw_eth_dev *priv = bus->priv;
-
- if (v)
- dm_gpio_set_value(&priv->mdc_gpio, 1);
- else
- dm_gpio_set_value(&priv->mdc_gpio, 0);
-
- return 0;
-}
-
-static int dw_eth_bb_delay(struct bb_miiphy_bus *bus)
-{
- struct dw_eth_dev *priv = bus->priv;
-
- udelay(priv->bb_delay);
- return 0;
-}
-
-struct bb_miiphy_bus bb_miiphy_buses[] = {
- {
- .name = BB_MII_DEVNAME,
- .mdio_active = dw_eth_bb_mdio_active,
- .mdio_tristate = dw_eth_bb_mdio_tristate,
- .set_mdio = dw_eth_bb_set_mdio,
- .get_mdio = dw_eth_bb_get_mdio,
- .set_mdc = dw_eth_bb_set_mdc,
- .delay = dw_eth_bb_delay,
- .priv = NULL,
- }
-};
-
-int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
-#endif
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 2279481d935..b4ec3614696 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -1632,6 +1632,12 @@ static const struct udevice_id eqos_ids[] = {
.data = (ulong)&eqos_jh7110_config
},
#endif
+#if IS_ENABLED(CONFIG_DWC_ETH_QOS_ADI)
+ {
+ .compatible = "adi,sc59x-dwmac-eqos",
+ .data = (ulong)&eqos_adi_config
+ },
+#endif
{ }
};
diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h
index 123f98d5d53..403e8203974 100644
--- a/drivers/net/dwc_eth_qos.h
+++ b/drivers/net/dwc_eth_qos.h
@@ -87,6 +87,7 @@ struct eqos_mac_regs {
#define EQOS_MAC_MDIO_ADDRESS_CR_MASK GENMASK(11, 8)
#define EQOS_MAC_MDIO_ADDRESS_CR_100_150 1
#define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2
+#define EQOS_MAC_MDIO_ADDRESS_CR_150_250 4
#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5
#define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4)
#define EQOS_MAC_MDIO_ADDRESS_GOC_MASK GENMASK(3, 2)
@@ -301,3 +302,4 @@ extern struct eqos_config eqos_qcom_config;
extern struct eqos_config eqos_stm32mp13_config;
extern struct eqos_config eqos_stm32mp15_config;
extern struct eqos_config eqos_jh7110_config;
+extern struct eqos_config eqos_adi_config;
diff --git a/drivers/net/dwc_eth_qos_adi.c b/drivers/net/dwc_eth_qos_adi.c
new file mode 100644
index 00000000000..0e6a901e303
--- /dev/null
+++ b/drivers/net/dwc_eth_qos_adi.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * (C) Copyright 2024 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Author: Greg Malysa <greg.malysa@timesys.com>
+ * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <linux/io.h>
+
+#include <asm/arch-adi/sc5xx/sc5xx.h>
+
+#include "dwc_eth_qos.h"
+
+static int eqos_start_resets_adi(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+
+ /*
+ * Settings need to latch with the DMA reset below. Currently only
+ * rgmii is supported but other phy interfaces may be supported in
+ * the future
+ */
+ sc5xx_enable_rgmii();
+ setbits_32(&eqos->dma_regs->mode, EQOS_DMA_MODE_SWR);
+
+ return 0;
+}
+
+static int eqos_probe_resources_adi(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ phy_interface_t interface;
+ int ret;
+
+ ret = eqos_get_base_addr_dt(dev);
+ if (ret) {
+ pr_err("eqos_get_base_addr_dt failed: %d\n", ret);
+ return ret;
+ }
+
+ interface = eqos->config->interface(dev);
+ if (interface == PHY_INTERFACE_MODE_NA) {
+ pr_err("Invalid PHY interface\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * rgmii tx clock rate is set to 125 MHz regardless of phy mode, and
+ * by default the internal clock is always connected to 125 MHz. According
+ * to the HRM it is invalid for this clock to have any other speed, so
+ * the hardware won't work anyway if this is wrong.
+ */
+static ulong eqos_get_tick_clk_rate_adi(struct udevice *dev)
+{
+ return 125 * 1000000;
+}
+
+static int eqos_get_enetaddr_adi(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+
+ return eth_env_get_enetaddr("ethaddr", pdata->enetaddr);
+}
+
+static struct eqos_ops eqos_adi_ops = {
+ .eqos_inval_desc = eqos_inval_desc_generic,
+ .eqos_flush_desc = eqos_flush_desc_generic,
+ .eqos_inval_buffer = eqos_inval_buffer_generic,
+ .eqos_flush_buffer = eqos_flush_buffer_generic,
+ .eqos_probe_resources = eqos_probe_resources_adi,
+ .eqos_remove_resources = eqos_null_ops,
+ .eqos_start_resets = eqos_start_resets_adi,
+ .eqos_stop_resets = eqos_null_ops,
+ .eqos_start_clks = eqos_null_ops,
+ .eqos_stop_clks = eqos_null_ops,
+ .eqos_calibrate_pads = eqos_null_ops,
+ .eqos_disable_calibration = eqos_null_ops,
+ .eqos_set_tx_clk_speed = eqos_null_ops,
+ .eqos_get_enetaddr = eqos_get_enetaddr_adi,
+ .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_adi,
+};
+
+struct eqos_config __maybe_unused eqos_adi_config = {
+ .reg_access_always_ok = true,
+ .mdio_wait = 20,
+ .swr_wait = 50,
+ .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+ .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_150_250,
+ .axi_bus_width = EQOS_AXI_WIDTH_32,
+ .interface = dev_read_phy_mode,
+ .ops = &eqos_adi_ops,
+};
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c
index c48ae6e88f3..ee8eae1efd9 100644
--- a/drivers/net/phy/micrel_ksz90x1.c
+++ b/drivers/net/phy/micrel_ksz90x1.c
@@ -389,10 +389,126 @@ U_BOOT_PHY_DRIVER(ksz9031) = {
#define KSZ9131RN_DLL_ENABLE_DELAY 0
#define KSZ9131RN_DLL_DISABLE_DELAY BIT(12)
+#define KSZ9131RN_COMMON_CTRL 0
+#define KSZ9131RN_COMMON_CTRL_INDIVIDUAL_LED_MODE BIT(4)
+
+#define KSZ9131RN_LED_ERRATA_REG 0x1e
+#define KSZ9131RN_LED_ERRATA_BIT BIT(9)
+
+#define KSZ9131RN_CONTROL_PAD_SKEW 4
+#define KSZ9131RN_RX_DATA_PAD_SKEW 5
+#define KSZ9131RN_TX_DATA_PAD_SKEW 6
+#define KSZ9131RN_CLK_PAD_SKEW 8
+
+#define KSZ9131RN_SKEW_5BIT_MAX 2400
+#define KSZ9131RN_SKEW_4BIT_MAX 800
+#define KSZ9131RN_OFFSET 700
+#define KSZ9131RN_STEP 100
+
+static int ksz9131_of_load_skew_values(struct phy_device *phydev,
+ ofnode of_node,
+ u16 reg, size_t field_sz,
+ const char *field[], u8 numfields)
+{
+ int val[4] = {-(1 + KSZ9131RN_OFFSET), -(2 + KSZ9131RN_OFFSET),
+ -(3 + KSZ9131RN_OFFSET), -(4 + KSZ9131RN_OFFSET)};
+ int skewval, skewmax = 0;
+ int matches = 0;
+ u16 maxval;
+ u16 newval;
+ u16 mask;
+ int i;
+
+ /* psec properties in dts should mean x pico seconds */
+ if (field_sz == 5)
+ skewmax = KSZ9131RN_SKEW_5BIT_MAX;
+ else
+ skewmax = KSZ9131RN_SKEW_4BIT_MAX;
+
+ for (i = 0; i < numfields; i++)
+ if (!ofnode_read_s32(of_node, field[i], &skewval)) {
+ if (skewval < -KSZ9131RN_OFFSET)
+ skewval = -KSZ9131RN_OFFSET;
+ else if (skewval > skewmax)
+ skewval = skewmax;
+
+ val[i] = skewval + KSZ9131RN_OFFSET;
+ matches++;
+ }
+
+ if (!matches)
+ return 0;
+
+ if (matches < numfields)
+ newval = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, reg);
+ else
+ newval = 0;
+
+ maxval = (field_sz == 4) ? 0xf : 0x1f;
+ for (i = 0; i < numfields; i++)
+ if (val[i] != -(i + 1 + KSZ9131RN_OFFSET)) {
+ mask = 0xffff;
+ mask ^= maxval << (field_sz * i);
+ newval = (newval & mask) |
+ (((val[i] / KSZ9131RN_STEP) & maxval)
+ << (field_sz * i));
+ }
+
+ return phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, reg, newval);
+}
+
+static int ksz9131_of_load_all_skew_values(struct phy_device *phydev)
+{
+ const char *control_skews[2] = { "txen-skew-psec", "rxdv-skew-psec" };
+ const char *clk_skews[2] = { "rxc-skew-psec", "txc-skew-psec" };
+ const char *rx_data_skews[4] = {
+ "rxd0-skew-psec", "rxd1-skew-psec",
+ "rxd2-skew-psec", "rxd3-skew-psec"
+ };
+ const char *tx_data_skews[4] = {
+ "txd0-skew-psec", "txd1-skew-psec",
+ "txd2-skew-psec", "txd3-skew-psec"
+ };
+ struct ofnode_phandle_args phandle_args;
+ int ret;
+
+ /*
+ * Silently ignore failure here as the device tree is not required to
+ * contain a phy node.
+ */
+ if (dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL, 0, 0,
+ &phandle_args))
+ return 0;
+
+ if (!ofnode_valid(phandle_args.node))
+ return 0;
+
+ ret = ksz9131_of_load_skew_values(phydev, phandle_args.node,
+ KSZ9131RN_CLK_PAD_SKEW, 5,
+ clk_skews, 2);
+ if (ret < 0)
+ return ret;
+
+ ret = ksz9131_of_load_skew_values(phydev, phandle_args.node,
+ KSZ9131RN_CONTROL_PAD_SKEW, 4,
+ control_skews, 2);
+ if (ret < 0)
+ return ret;
+
+ ret = ksz9131_of_load_skew_values(phydev, phandle_args.node,
+ KSZ9131RN_RX_DATA_PAD_SKEW, 4,
+ rx_data_skews, 4);
+ if (ret < 0)
+ return ret;
+
+ return ksz9131_of_load_skew_values(phydev, phandle_args.node,
+ KSZ9131RN_TX_DATA_PAD_SKEW, 4,
+ tx_data_skews, 4);
+}
+
static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
{
- struct phy_driver *drv = phydev->drv;
- u16 rxcdll_val, txcdll_val, val;
+ u16 rxcdll_val, txcdll_val;
int ret;
switch (phydev->interface) {
@@ -416,24 +532,37 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
return 0;
}
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
- KSZ9131RN_RXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= rxcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
- KSZ9131RN_RXC_DLL_CTRL, val);
- if (ret)
+ ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+ KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
+ rxcdll_val);
+ if (ret < 0)
return ret;
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
- KSZ9131RN_TXC_DLL_CTRL);
+ return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+ KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
+ txcdll_val);
+}
+
+/* Silicon Errata DS80000693B
+ *
+ * When LEDs are configured in Individual Mode, LED1 is ON in a no-link
+ * condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves
+ * according to the datasheet (off if there is no link).
+ */
+static int ksz9131_led_errata(struct phy_device *phydev)
+{
+ int reg;
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= txcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
- KSZ9131RN_TXC_DLL_CTRL, val);
+ reg = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+ KSZ9131RN_COMMON_CTRL);
+ if (reg < 0)
+ return reg;
- return ret;
+ if (!(reg & KSZ9131RN_COMMON_CTRL_INDIVIDUAL_LED_MODE))
+ return 0;
+
+ return phy_set_bits(phydev, MDIO_DEVAD_NONE, KSZ9131RN_LED_ERRATA_REG,
+ KSZ9131RN_LED_ERRATA_BIT);
}
static int ksz9131_config(struct phy_device *phydev)
@@ -446,6 +575,14 @@ static int ksz9131_config(struct phy_device *phydev)
return ret;
}
+ ret = ksz9131_of_load_all_skew_values(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = ksz9131_led_errata(phydev);
+ if (ret < 0)
+ return ret;
+
/* add an option to disable the gigabit feature of this PHY */
if (env_get("disable_giga")) {
unsigned features;
diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c
index 9f5f9b12c9f..76463da7299 100644
--- a/drivers/net/phy/miiphybb.c
+++ b/drivers/net/phy/miiphybb.c
@@ -17,37 +17,13 @@
#include <miiphy.h>
#include <asm/global_data.h>
-int bb_miiphy_init(void)
-{
- int i;
-
- for (i = 0; i < bb_miiphy_buses_num; i++)
- if (bb_miiphy_buses[i].init != NULL)
- bb_miiphy_buses[i].init(&bb_miiphy_buses[i]);
-
- return 0;
-}
-
-static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname)
-{
- int i;
-
- /* Search the correct bus */
- for (i = 0; i < bb_miiphy_buses_num; i++) {
- if (!strcmp(bb_miiphy_buses[i].name, devname)) {
- return &bb_miiphy_buses[i];
- }
- }
- return NULL;
-}
-
/*****************************************************************************
*
* Utility to send the preamble, address, and register (common to read
* and write).
*/
-static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
- unsigned char addr, unsigned char reg)
+static void miiphy_pre(struct mii_dev *miidev, const struct bb_miiphy_bus_ops *ops,
+ char read, unsigned char addr, unsigned char reg)
{
int j;
@@ -59,62 +35,62 @@ static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
* but it is safer and will be much more robust.
*/
- bus->mdio_active(bus);
- bus->set_mdio(bus, 1);
+ ops->mdio_active(miidev);
+ ops->set_mdio(miidev, 1);
for (j = 0; j < 32; j++) {
- bus->set_mdc(bus, 0);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
}
/* send the start bit (01) and the read opcode (10) or write (10) */
- bus->set_mdc(bus, 0);
- bus->set_mdio(bus, 0);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 0);
- bus->set_mdio(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 0);
- bus->set_mdio(bus, read);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 0);
- bus->set_mdio(bus, !read);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->set_mdio(miidev, 0);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 0);
+ ops->set_mdio(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 0);
+ ops->set_mdio(miidev, read);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 0);
+ ops->set_mdio(miidev, !read);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
/* send the PHY address */
for (j = 0; j < 5; j++) {
- bus->set_mdc(bus, 0);
+ ops->set_mdc(miidev, 0);
if ((addr & 0x10) == 0) {
- bus->set_mdio(bus, 0);
+ ops->set_mdio(miidev, 0);
} else {
- bus->set_mdio(bus, 1);
+ ops->set_mdio(miidev, 1);
}
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
addr <<= 1;
}
/* send the register address */
for (j = 0; j < 5; j++) {
- bus->set_mdc(bus, 0);
+ ops->set_mdc(miidev, 0);
if ((reg & 0x10) == 0) {
- bus->set_mdio(bus, 0);
+ ops->set_mdio(miidev, 0);
} else {
- bus->set_mdio(bus, 1);
+ ops->set_mdio(miidev, 1);
}
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
reg <<= 1;
}
}
@@ -126,62 +102,57 @@ static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
* Returns:
* 0 on success
*/
-int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg)
+int bb_miiphy_read(struct mii_dev *miidev, const struct bb_miiphy_bus_ops *ops,
+ int addr, int devad, int reg)
{
unsigned short rdreg; /* register working value */
int v;
int j; /* counter */
- struct bb_miiphy_bus *bus;
- bus = bb_miiphy_getbus(miidev->name);
- if (bus == NULL) {
- return -1;
- }
-
- miiphy_pre (bus, 1, addr, reg);
+ miiphy_pre(miidev, ops, 1, addr, reg);
/* tri-state our MDIO I/O pin so we can read */
- bus->set_mdc(bus, 0);
- bus->mdio_tristate(bus);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->mdio_tristate(miidev);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
/* check the turnaround bit: the PHY should be driving it to zero */
- bus->get_mdio(bus, &v);
+ ops->get_mdio(miidev, &v);
if (v != 0) {
/* puts ("PHY didn't drive TA low\n"); */
for (j = 0; j < 32; j++) {
- bus->set_mdc(bus, 0);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
}
/* There is no PHY, return */
return -1;
}
- bus->set_mdc(bus, 0);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->delay(miidev);
/* read 16 bits of register data, MSB first */
rdreg = 0;
for (j = 0; j < 16; j++) {
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
rdreg <<= 1;
- bus->get_mdio(bus, &v);
+ ops->get_mdio(miidev, &v);
rdreg |= (v & 0x1);
- bus->set_mdc(bus, 0);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->delay(miidev);
}
- bus->set_mdc(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 0);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 0);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
debug("%s[%s](0x%x) @ 0x%x = 0x%04x\n", __func__, miidev->name, reg, addr, rdreg);
@@ -195,54 +166,47 @@ int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg)
* Returns:
* 0 on success
*/
-int bb_miiphy_write(struct mii_dev *miidev, int addr, int devad, int reg,
- u16 value)
+int bb_miiphy_write(struct mii_dev *miidev, const struct bb_miiphy_bus_ops *ops,
+ int addr, int devad, int reg, u16 value)
{
- struct bb_miiphy_bus *bus;
int j; /* counter */
- bus = bb_miiphy_getbus(miidev->name);
- if (bus == NULL) {
- /* Bus not found! */
- return -1;
- }
-
- miiphy_pre (bus, 0, addr, reg);
+ miiphy_pre(miidev, ops, 0, addr, reg);
/* send the turnaround (10) */
- bus->set_mdc(bus, 0);
- bus->set_mdio(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
- bus->set_mdc(bus, 0);
- bus->set_mdio(bus, 0);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->set_mdc(miidev, 0);
+ ops->set_mdio(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 0);
+ ops->set_mdio(miidev, 0);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
/* write 16 bits of register data, MSB first */
for (j = 0; j < 16; j++) {
- bus->set_mdc(bus, 0);
+ ops->set_mdc(miidev, 0);
if ((value & 0x00008000) == 0) {
- bus->set_mdio(bus, 0);
+ ops->set_mdio(miidev, 0);
} else {
- bus->set_mdio(bus, 1);
+ ops->set_mdio(miidev, 1);
}
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
value <<= 1;
}
/*
* Tri-state the MDIO line.
*/
- bus->mdio_tristate(bus);
- bus->set_mdc(bus, 0);
- bus->delay(bus);
- bus->set_mdc(bus, 1);
- bus->delay(bus);
+ ops->mdio_tristate(miidev);
+ ops->set_mdc(miidev, 0);
+ ops->delay(miidev);
+ ops->set_mdc(miidev, 1);
+ ops->delay(miidev);
return 0;
}
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c
index 7286ad19598..539fd37ee59 100644
--- a/drivers/net/ravb.c
+++ b/drivers/net/ravb.c
@@ -354,8 +354,15 @@ static int ravb_mac_init(struct ravb_priv *eth)
/* Disable MAC Interrupt */
writel(0, eth->iobase + RAVB_REG_ECSIPR);
- /* Recv frame limit set register */
- writel(RFLR_RFL_MIN, eth->iobase + RAVB_REG_RFLR);
+ /*
+ * Set receive frame length
+ *
+ * The length set here describes the frame from the destination address
+ * up to and including the CRC data. However only the frame data,
+ * excluding the CRC, are transferred to memory. To allow for the
+ * largest frames add the CRC length to the maximum Rx descriptor size.
+ */
+ writel(RFLR_RFL_MIN + ETH_FCS_LEN, eth->iobase + RAVB_REG_RFLR);
return 0;
}
@@ -490,6 +497,88 @@ static void ravb_stop(struct udevice *dev)
ravb_reset(dev);
}
+/* Bitbang MDIO access */
+static int ravb_bb_mdio_active(struct mii_dev *miidev)
+{
+ struct ravb_priv *eth = miidev->priv;
+
+ setbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MMD);
+
+ return 0;
+}
+
+static int ravb_bb_mdio_tristate(struct mii_dev *miidev)
+{
+ struct ravb_priv *eth = miidev->priv;
+
+ clrbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MMD);
+
+ return 0;
+}
+
+static int ravb_bb_set_mdio(struct mii_dev *miidev, int v)
+{
+ struct ravb_priv *eth = miidev->priv;
+
+ if (v)
+ setbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDO);
+ else
+ clrbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDO);
+
+ return 0;
+}
+
+static int ravb_bb_get_mdio(struct mii_dev *miidev, int *v)
+{
+ struct ravb_priv *eth = miidev->priv;
+
+ *v = (readl(eth->iobase + RAVB_REG_PIR) & PIR_MDI) >> 3;
+
+ return 0;
+}
+
+static int ravb_bb_set_mdc(struct mii_dev *miidev, int v)
+{
+ struct ravb_priv *eth = miidev->priv;
+
+ if (v)
+ setbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDC);
+ else
+ clrbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDC);
+
+ return 0;
+}
+
+static int ravb_bb_delay(struct mii_dev *miidev)
+{
+ udelay(10);
+
+ return 0;
+}
+
+static const struct bb_miiphy_bus_ops ravb_bb_miiphy_bus_ops = {
+ .mdio_active = ravb_bb_mdio_active,
+ .mdio_tristate = ravb_bb_mdio_tristate,
+ .set_mdio = ravb_bb_set_mdio,
+ .get_mdio = ravb_bb_get_mdio,
+ .set_mdc = ravb_bb_set_mdc,
+ .delay = ravb_bb_delay,
+};
+
+static int ravb_bb_miiphy_read(struct mii_dev *miidev, int addr,
+ int devad, int reg)
+{
+ return bb_miiphy_read(miidev, &ravb_bb_miiphy_bus_ops,
+ addr, devad, reg);
+}
+
+static int ravb_bb_miiphy_write(struct mii_dev *miidev, int addr,
+ int devad, int reg, u16 value)
+{
+ return bb_miiphy_write(miidev, &ravb_bb_miiphy_bus_ops,
+ addr, devad, reg, value);
+}
+
static int ravb_probe(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
@@ -503,7 +592,7 @@ static int ravb_probe(struct udevice *dev)
ret = clk_get_bulk(dev, &eth->clks);
if (ret < 0)
- goto err_mdio_alloc;
+ goto err_clk_get;
mdiodev = mdio_alloc();
if (!mdiodev) {
@@ -511,37 +600,39 @@ static int ravb_probe(struct udevice *dev)
goto err_mdio_alloc;
}
- mdiodev->read = bb_miiphy_read;
- mdiodev->write = bb_miiphy_write;
- bb_miiphy_buses[0].priv = eth;
+ mdiodev->read = ravb_bb_miiphy_read;
+ mdiodev->write = ravb_bb_miiphy_write;
+ mdiodev->priv = eth;
snprintf(mdiodev->name, sizeof(mdiodev->name), dev->name);
ret = mdio_register(mdiodev);
if (ret < 0)
goto err_mdio_register;
- eth->bus = miiphy_get_dev_by_name(dev->name);
+ eth->bus = mdiodev;
/* Bring up PHY */
ret = clk_enable_bulk(&eth->clks);
if (ret)
- goto err_mdio_register;
+ goto err_clk_enable;
ret = ravb_reset(dev);
if (ret)
- goto err_mdio_reset;
+ goto err_clk_enable;
ret = ravb_phy_config(dev);
if (ret)
- goto err_mdio_reset;
+ goto err_clk_enable;
return 0;
-err_mdio_reset:
- clk_release_bulk(&eth->clks);
+err_clk_enable:
+ mdio_unregister(mdiodev);
err_mdio_register:
mdio_free(mdiodev);
err_mdio_alloc:
+ clk_release_bulk(&eth->clks);
+err_clk_get:
unmap_physmem(eth->iobase, MAP_NOCACHE);
return ret;
}
@@ -560,83 +651,6 @@ static int ravb_remove(struct udevice *dev)
return 0;
}
-static int ravb_bb_init(struct bb_miiphy_bus *bus)
-{
- return 0;
-}
-
-static int ravb_bb_mdio_active(struct bb_miiphy_bus *bus)
-{
- struct ravb_priv *eth = bus->priv;
-
- setbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MMD);
-
- return 0;
-}
-
-static int ravb_bb_mdio_tristate(struct bb_miiphy_bus *bus)
-{
- struct ravb_priv *eth = bus->priv;
-
- clrbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MMD);
-
- return 0;
-}
-
-static int ravb_bb_set_mdio(struct bb_miiphy_bus *bus, int v)
-{
- struct ravb_priv *eth = bus->priv;
-
- if (v)
- setbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDO);
- else
- clrbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDO);
-
- return 0;
-}
-
-static int ravb_bb_get_mdio(struct bb_miiphy_bus *bus, int *v)
-{
- struct ravb_priv *eth = bus->priv;
-
- *v = (readl(eth->iobase + RAVB_REG_PIR) & PIR_MDI) >> 3;
-
- return 0;
-}
-
-static int ravb_bb_set_mdc(struct bb_miiphy_bus *bus, int v)
-{
- struct ravb_priv *eth = bus->priv;
-
- if (v)
- setbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDC);
- else
- clrbits_le32(eth->iobase + RAVB_REG_PIR, PIR_MDC);
-
- return 0;
-}
-
-static int ravb_bb_delay(struct bb_miiphy_bus *bus)
-{
- udelay(10);
-
- return 0;
-}
-
-struct bb_miiphy_bus bb_miiphy_buses[] = {
- {
- .name = "ravb",
- .init = ravb_bb_init,
- .mdio_active = ravb_bb_mdio_active,
- .mdio_tristate = ravb_bb_mdio_tristate,
- .set_mdio = ravb_bb_set_mdio,
- .get_mdio = ravb_bb_get_mdio,
- .set_mdc = ravb_bb_set_mdc,
- .delay = ravb_bb_delay,
- },
-};
-int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
-
static const struct eth_ops ravb_ops = {
.start = ravb_start,
.send = ravb_send,
@@ -658,8 +672,6 @@ int ravb_of_to_plat(struct udevice *dev)
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 1000);
- sprintf(bb_miiphy_buses[0].name, dev->name);
-
return 0;
}
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index f1ce994cfd5..f695a3a41d2 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -643,6 +643,97 @@ static void sh_ether_stop(struct udevice *dev)
sh_eth_stop(&priv->shdev);
}
+/******* for bb_miiphy *******/
+static int sh_eth_bb_mdio_active(struct mii_dev *miidev)
+{
+ struct sh_eth_dev *eth = miidev->priv;
+ struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
+ sh_eth_write(port_info, sh_eth_read(port_info, PIR) | PIR_MMD, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_mdio_tristate(struct mii_dev *miidev)
+{
+ struct sh_eth_dev *eth = miidev->priv;
+ struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
+ sh_eth_write(port_info, sh_eth_read(port_info, PIR) & ~PIR_MMD, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_set_mdio(struct mii_dev *miidev, int v)
+{
+ struct sh_eth_dev *eth = miidev->priv;
+ struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
+ if (v)
+ sh_eth_write(port_info,
+ sh_eth_read(port_info, PIR) | PIR_MDO, PIR);
+ else
+ sh_eth_write(port_info,
+ sh_eth_read(port_info, PIR) & ~PIR_MDO, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_get_mdio(struct mii_dev *miidev, int *v)
+{
+ struct sh_eth_dev *eth = miidev->priv;
+ struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
+ *v = (sh_eth_read(port_info, PIR) & PIR_MDI) >> 3;
+
+ return 0;
+}
+
+static int sh_eth_bb_set_mdc(struct mii_dev *miidev, int v)
+{
+ struct sh_eth_dev *eth = miidev->priv;
+ struct sh_eth_info *port_info = &eth->port_info[eth->port];
+
+ if (v)
+ sh_eth_write(port_info,
+ sh_eth_read(port_info, PIR) | PIR_MDC, PIR);
+ else
+ sh_eth_write(port_info,
+ sh_eth_read(port_info, PIR) & ~PIR_MDC, PIR);
+
+ return 0;
+}
+
+static int sh_eth_bb_delay(struct mii_dev *miidev)
+{
+ udelay(10);
+
+ return 0;
+}
+
+static const struct bb_miiphy_bus_ops sh_ether_bb_miiphy_bus_ops = {
+ .mdio_active = sh_eth_bb_mdio_active,
+ .mdio_tristate = sh_eth_bb_mdio_tristate,
+ .set_mdio = sh_eth_bb_set_mdio,
+ .get_mdio = sh_eth_bb_get_mdio,
+ .set_mdc = sh_eth_bb_set_mdc,
+ .delay = sh_eth_bb_delay,
+};
+
+static int sh_eth_bb_miiphy_read(struct mii_dev *miidev, int addr,
+ int devad, int reg)
+{
+ return bb_miiphy_read(miidev, &sh_ether_bb_miiphy_bus_ops,
+ addr, devad, reg);
+}
+
+static int sh_eth_bb_miiphy_write(struct mii_dev *miidev, int addr,
+ int devad, int reg, u16 value)
+{
+ return bb_miiphy_write(miidev, &sh_ether_bb_miiphy_bus_ops,
+ addr, devad, reg, value);
+}
+
static int sh_ether_probe(struct udevice *udev)
{
struct eth_pdata *pdata = dev_get_plat(udev);
@@ -664,16 +755,16 @@ static int sh_ether_probe(struct udevice *udev)
return ret;
}
- mdiodev->read = bb_miiphy_read;
- mdiodev->write = bb_miiphy_write;
- bb_miiphy_buses[0].priv = eth;
+ mdiodev->read = sh_eth_bb_miiphy_read;
+ mdiodev->write = sh_eth_bb_miiphy_write;
+ mdiodev->priv = eth;
snprintf(mdiodev->name, sizeof(mdiodev->name), udev->name);
ret = mdio_register(mdiodev);
if (ret < 0)
goto err_mdio_register;
- priv->bus = miiphy_get_dev_by_name(udev->name);
+ priv->bus = mdiodev;
eth->port = CFG_SH_ETHER_USE_PORT;
eth->port_info[eth->port].phy_addr = CFG_SH_ETHER_PHY_ADDR;
@@ -748,8 +839,6 @@ int sh_ether_of_to_plat(struct udevice *dev)
if (cell)
pdata->max_speed = fdt32_to_cpu(*cell);
- sprintf(bb_miiphy_buses[0].name, dev->name);
-
return 0;
}
@@ -775,91 +864,3 @@ U_BOOT_DRIVER(eth_sh_ether) = {
.plat_auto = sizeof(struct eth_pdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
-
-/******* for bb_miiphy *******/
-static int sh_eth_bb_init(struct bb_miiphy_bus *bus)
-{
- return 0;
-}
-
-static int sh_eth_bb_mdio_active(struct bb_miiphy_bus *bus)
-{
- struct sh_eth_dev *eth = bus->priv;
- struct sh_eth_info *port_info = &eth->port_info[eth->port];
-
- sh_eth_write(port_info, sh_eth_read(port_info, PIR) | PIR_MMD, PIR);
-
- return 0;
-}
-
-static int sh_eth_bb_mdio_tristate(struct bb_miiphy_bus *bus)
-{
- struct sh_eth_dev *eth = bus->priv;
- struct sh_eth_info *port_info = &eth->port_info[eth->port];
-
- sh_eth_write(port_info, sh_eth_read(port_info, PIR) & ~PIR_MMD, PIR);
-
- return 0;
-}
-
-static int sh_eth_bb_set_mdio(struct bb_miiphy_bus *bus, int v)
-{
- struct sh_eth_dev *eth = bus->priv;
- struct sh_eth_info *port_info = &eth->port_info[eth->port];
-
- if (v)
- sh_eth_write(port_info,
- sh_eth_read(port_info, PIR) | PIR_MDO, PIR);
- else
- sh_eth_write(port_info,
- sh_eth_read(port_info, PIR) & ~PIR_MDO, PIR);
-
- return 0;
-}
-
-static int sh_eth_bb_get_mdio(struct bb_miiphy_bus *bus, int *v)
-{
- struct sh_eth_dev *eth = bus->priv;
- struct sh_eth_info *port_info = &eth->port_info[eth->port];
-
- *v = (sh_eth_read(port_info, PIR) & PIR_MDI) >> 3;
-
- return 0;
-}
-
-static int sh_eth_bb_set_mdc(struct bb_miiphy_bus *bus, int v)
-{
- struct sh_eth_dev *eth = bus->priv;
- struct sh_eth_info *port_info = &eth->port_info[eth->port];
-
- if (v)
- sh_eth_write(port_info,
- sh_eth_read(port_info, PIR) | PIR_MDC, PIR);
- else
- sh_eth_write(port_info,
- sh_eth_read(port_info, PIR) & ~PIR_MDC, PIR);
-
- return 0;
-}
-
-static int sh_eth_bb_delay(struct bb_miiphy_bus *bus)
-{
- udelay(10);
-
- return 0;
-}
-
-struct bb_miiphy_bus bb_miiphy_buses[] = {
- {
- .name = "sh_eth",
- .init = sh_eth_bb_init,
- .mdio_active = sh_eth_bb_mdio_active,
- .mdio_tristate = sh_eth_bb_mdio_tristate,
- .set_mdio = sh_eth_bb_set_mdio,
- .get_mdio = sh_eth_bb_get_mdio,
- .set_mdc = sh_eth_bb_set_mdc,
- .delay = sh_eth_bb_delay,
- }
-};
-
-int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c
index c70b42f6bcc..3c62fc0b428 100644
--- a/drivers/net/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ti/am65-cpsw-nuss.c
@@ -661,7 +661,7 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev)
dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed);
if (pdata->max_speed)
- dev_err(dev, "Port %u speed froced to %uMbit\n",
+ dev_err(dev, "Port %u speed forced to %uMbit\n",
priv->port_id, pdata->max_speed);
return 0;
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index 90f81886445..e68e31a8227 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -107,7 +107,8 @@ static void dm_pciauto_setup_device(struct udevice *dev,
}
if (prefetch &&
- (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+ (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
+ (found_mem64 || prefetch->bus_lower < 0x100000000ULL))
bar_res = prefetch;
else
bar_res = mem;
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index e12347e8a03..d3fe90d939e 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -163,8 +163,8 @@ config PHY_RCAR_GEN2
config PHY_RCAR_GEN3
tristate "Renesas R-Car Gen3 USB PHY"
- depends on PHY && RCAR_GEN3 && CLK && DM_REGULATOR
- default y if RCAR_GEN3
+ depends on PHY && CLK && DM_REGULATOR && (RCAR_GEN3 || RZG2L)
+ default y if (RCAR_GEN3 || RZG2L)
help
Support for the Renesas R-Car Gen3 USB PHY. This driver operates the
PHY connected to EHCI USB module and controls USB OTG operation.
@@ -309,5 +309,6 @@ source "drivers/phy/cadence/Kconfig"
source "drivers/phy/ti/Kconfig"
source "drivers/phy/qcom/Kconfig"
source "drivers/phy/renesas/Kconfig"
+source "drivers/phy/starfive/Kconfig"
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c35f9294dd9..ce4ea28b299 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -44,3 +44,4 @@ obj-y += cadence/
obj-y += ti/
obj-y += qcom/
obj-y += renesas/
+obj-y += starfive/
diff --git a/drivers/phy/phy-rcar-gen3.c b/drivers/phy/phy-rcar-gen3.c
index 8c004eaf4c6..d06861c4f79 100644
--- a/drivers/phy/phy-rcar-gen3.c
+++ b/drivers/phy/phy-rcar-gen3.c
@@ -55,6 +55,7 @@
/* VBCTRL */
#define USB2_VBCTRL_DRVVBUSSEL BIT(8)
+#define USB2_VBCTRL_VBOUT BIT(0)
/* LINECTRL1 */
#define USB2_LINECTRL1_DPRPD_EN BIT(19)
@@ -68,6 +69,13 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
+/* RZ/G2L specific */
+#define USB2_OBINT_IDCHG_EN BIT(0)
+#define USB2_LINECTRL1_USB2_IDMON BIT(0)
+
+/* Device flags */
+#define RCAR_GEN3_PHY_NO_ADPCTRL BIT(0)
+
struct rcar_gen3_phy {
fdt_addr_t regs;
struct clk clk;
@@ -122,15 +130,50 @@ static int rcar_gen3_phy_phy_power_off(struct phy *phy)
return regulator_set_enable(priv->vbus_supply, false);
}
+static bool rcar_gen3_phy_check_id(struct phy *phy)
+{
+ const u32 adpdevmask = USB2_ADPCTRL_IDDIG | USB2_ADPCTRL_OTGSESSVLD;
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+ ulong flags = dev_get_driver_data(phy->dev);
+ u32 val;
+
+ if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
+ val = readl(priv->regs + USB2_LINECTRL1);
+ return !!(val & USB2_LINECTRL1_USB2_IDMON);
+ }
+
+ val = readl(priv->regs + USB2_ADPCTRL);
+ return (val & adpdevmask) == adpdevmask;
+}
+
+static void rcar_gen3_phy_set_vbus(struct phy *phy, bool enable)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+ ulong flags = dev_get_driver_data(phy->dev);
+ u32 bits = USB2_ADPCTRL_DRVVBUS;
+ u64 reg = USB2_ADPCTRL;
+
+ if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
+ bits = USB2_VBCTRL_VBOUT;
+ reg = USB2_VBCTRL;
+ }
+
+ if (enable)
+ setbits_le32(priv->regs + reg, bits);
+ else
+ clrbits_le32(priv->regs + reg, bits);
+}
+
static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
- const u32 adpdevmask = USB2_ADPCTRL_IDDIG | USB2_ADPCTRL_OTGSESSVLD;
struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
- u32 adpctrl;
+ ulong flags = dev_get_driver_data(phy->dev);
if (mode == PHY_MODE_USB_OTG) {
if (submode) {
+ u32 obint_enable_bits;
+
/* OTG submode is used as initialization indicator */
writel(USB2_INT_ENABLE_UCOM_INTEN |
USB2_INT_ENABLE_USBH_INTB_EN |
@@ -138,13 +181,16 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
priv->regs + USB2_INT_ENABLE);
setbits_le32(priv->regs + USB2_VBCTRL,
USB2_VBCTRL_DRVVBUSSEL);
- writel(USB2_OBINT_SESSVLDCHG | USB2_OBINT_IDDIGCHG,
- priv->regs + USB2_OBINTSTA);
- setbits_le32(priv->regs + USB2_OBINTEN,
- USB2_OBINT_SESSVLDCHG |
- USB2_OBINT_IDDIGCHG);
- setbits_le32(priv->regs + USB2_ADPCTRL,
- USB2_ADPCTRL_IDPULLUP);
+ if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
+ obint_enable_bits = USB2_OBINT_IDCHG_EN;
+ } else {
+ obint_enable_bits = USB2_OBINT_SESSVLDCHG |
+ USB2_OBINT_IDDIGCHG;
+ setbits_le32(priv->regs + USB2_ADPCTRL,
+ USB2_ADPCTRL_IDPULLUP);
+ }
+ writel(obint_enable_bits, priv->regs + USB2_OBINTSTA);
+ setbits_le32(priv->regs + USB2_OBINTEN, obint_enable_bits);
clrsetbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD |
USB2_LINECTRL1_DM_RPD |
@@ -154,8 +200,7 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
USB2_LINECTRL1_DMRPD_EN);
}
- adpctrl = readl(priv->regs + USB2_ADPCTRL);
- if ((adpctrl & adpdevmask) == adpdevmask)
+ if (rcar_gen3_phy_check_id(phy))
mode = PHY_MODE_USB_DEVICE;
else
mode = PHY_MODE_USB_HOST;
@@ -165,13 +210,13 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
clrbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
setbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
- setbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS);
+ rcar_gen3_phy_set_vbus(phy, true);
} else if (mode == PHY_MODE_USB_DEVICE) {
setbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
clrsetbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD,
USB2_LINECTRL1_DM_RPD);
- clrbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS);
+ rcar_gen3_phy_set_vbus(phy, false);
} else {
dev_err(phy->dev, "Unknown mode %d\n", mode);
return -EINVAL;
@@ -226,7 +271,13 @@ static int rcar_gen3_phy_remove(struct udevice *dev)
}
static const struct udevice_id rcar_gen3_phy_of_match[] = {
- { .compatible = "renesas,rcar-gen3-usb2-phy", },
+ {
+ .compatible = "renesas,rcar-gen3-usb2-phy",
+ },
+ {
+ .compatible = "renesas,rzg2l-usb2-phy",
+ .data = RCAR_GEN3_PHY_NO_ADPCTRL,
+ },
{ },
};
diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig
new file mode 100644
index 00000000000..d11338ed484
--- /dev/null
+++ b/drivers/phy/starfive/Kconfig
@@ -0,0 +1,21 @@
+#
+# PHY drivers for Starfive platforms
+#
+
+menu "Starfive PHY driver"
+
+config PHY_STARFIVE_JH7110_PCIE
+ bool "Starfive JH7110 PCIe 2.0 PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Starfive JH7110 PCIE 2.0/USB 3.0 PHY.
+ Generic PHY driver JH7110 USB 3.0/ PCIe 2.0.
+
+config PHY_STARFIVE_JH7110_USB2
+ bool "Starfive JH7110 USB 2.0 PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Starfive JH7110 USB 2.0 PHY.
+ Generic PHY driver JH7110 USB 2.0.
+
+endmenu
diff --git a/drivers/phy/starfive/Makefile b/drivers/phy/starfive/Makefile
new file mode 100644
index 00000000000..82f25aa21b7
--- /dev/null
+++ b/drivers/phy/starfive/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2023 Starfive
+#
+
+obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o
+obj-$(CONFIG_PHY_STARFIVE_JH7110_USB2) += phy-jh7110-usb2.o
diff --git a/drivers/phy/starfive/phy-jh7110-pcie.c b/drivers/phy/starfive/phy-jh7110-pcie.c
new file mode 100644
index 00000000000..a30582821d9
--- /dev/null
+++ b/drivers/phy/starfive/phy-jh7110-pcie.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * StarFive JH7110 PCIe 2.0 PHY driver
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Minda Chen <minda.chen@starfivetech.com>
+ */
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <soc.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#include "phy-jh7110-usb-syscon.h"
+
+#define PCIE_KVCO_LEVEL_OFF 0x28
+#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c
+#define PCIE_USB3_PHY_SS_MODE BIT(4)
+#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80
+#define PHY_KVCO_FINE_TUNE_LEVEL 0x91
+#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc
+
+#define PCIE_USB3_PHY_MODE 0x1
+#define PCIE_BUS_WIDTH 0x2
+#define PCIE_USB3_PHY_ENABLE 0x1
+#define PCIE_USB3_PHY_SPLIT 0x1
+
+struct jh7110_pcie_phy {
+ struct phy *phy;
+ struct regmap *stg_syscon;
+ struct regmap *sys_syscon;
+ void __iomem *regs;
+ struct regmap_field *phy_mode;
+ struct regmap_field *bus_width;
+ struct regmap_field *usb3_phy_en;
+ struct regmap_field *usb_split;
+ enum phy_mode mode;
+};
+
+static int phy_pcie_mode_set(struct jh7110_pcie_phy *data, bool usb_mode)
+{
+ unsigned int phy_mode, width, usb3_phy, ss_mode, split;
+
+ /* default is PCIe mode */
+ if (!data->stg_syscon || !data->sys_syscon) {
+ if (usb_mode) {
+ dev_err(data->phy->dev, "doesn't support USB3 mode\n");
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ if (usb_mode) {
+ phy_mode = PCIE_USB3_PHY_MODE;
+ width = 0;
+ usb3_phy = PCIE_USB3_PHY_ENABLE;
+ ss_mode = PCIE_USB3_PHY_SS_MODE;
+ split = 0;
+ } else {
+ phy_mode = 0;
+ width = PCIE_BUS_WIDTH;
+ usb3_phy = 0;
+ ss_mode = 0;
+ split = PCIE_USB3_PHY_SPLIT;
+ }
+
+ regmap_field_write(data->phy_mode, phy_mode);
+ regmap_field_write(data->bus_width, width);
+ regmap_field_write(data->usb3_phy_en, usb3_phy);
+ clrsetbits_le32(data->regs + PCIE_USB3_PHY_PLL_CTL_OFF,
+ PCIE_USB3_PHY_SS_MODE, ss_mode);
+ regmap_field_write(data->usb_split, split);
+
+ return 0;
+}
+
+static void phy_kvco_gain_set(struct jh7110_pcie_phy *phy)
+{
+ /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */
+ writel(PHY_KVCO_FINE_TUNE_LEVEL, phy->regs + PCIE_KVCO_LEVEL_OFF);
+ writel(PHY_KVCO_FINE_TUNE_SIGNALS, phy->regs + PCIE_KVCO_TUNE_SIGNAL_OFF);
+}
+
+static int jh7110_pcie_phy_set_mode(struct phy *phy,
+ enum phy_mode mode, int submode)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_pcie_phy *pcie_phy = dev_get_priv(dev);
+ int ret;
+
+ if (mode == pcie_phy->mode)
+ return 0;
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ case PHY_MODE_USB_DEVICE:
+ case PHY_MODE_USB_OTG:
+ ret = phy_pcie_mode_set(pcie_phy, 1);
+ if (ret)
+ return ret;
+ break;
+ case PHY_MODE_PCIE:
+ phy_pcie_mode_set(pcie_phy, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(phy->dev, "Changing PHY mode to %d\n", mode);
+ pcie_phy->mode = mode;
+
+ return 0;
+}
+
+static const struct phy_ops jh7110_pcie_phy_ops = {
+ .set_mode = jh7110_pcie_phy_set_mode,
+};
+
+static int phy_stg_regfield_init(struct udevice *dev, int mode, int usb3)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ struct reg_field phy_mode = REG_FIELD(mode, 20, 21);
+ struct reg_field bus_width = REG_FIELD(usb3, 2, 3);
+ struct reg_field usb3_phy_en = REG_FIELD(usb3, 4, 4);
+
+ phy->phy_mode = devm_regmap_field_alloc(dev, phy->stg_syscon, phy_mode);
+ if (IS_ERR(phy->phy_mode)) {
+ dev_err(dev, "PHY mode reg field init failed\n");
+ return PTR_ERR(phy->phy_mode);
+ }
+
+ phy->bus_width = devm_regmap_field_alloc(dev, phy->stg_syscon, bus_width);
+ if (IS_ERR(phy->bus_width)) {
+ dev_err(dev, "PHY bus width reg field init failed\n");
+ return PTR_ERR(phy->bus_width);
+ }
+
+ phy->usb3_phy_en = devm_regmap_field_alloc(dev, phy->stg_syscon, usb3_phy_en);
+ if (IS_ERR(phy->usb3_phy_en)) {
+ dev_err(dev, "USB3 PHY enable field init failed\n");
+ return PTR_ERR(phy->bus_width);
+ }
+
+ return 0;
+}
+
+static int phy_sys_regfield_init(struct udevice *dev, int split)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ struct reg_field usb_split = REG_FIELD(split, USB_PDRSTN_SPLIT_BIT, USB_PDRSTN_SPLIT_BIT);
+
+ phy->usb_split = devm_regmap_field_alloc(dev, phy->sys_syscon, usb_split);
+ if (IS_ERR(phy->usb_split)) {
+ dev_err(dev, "USB split field init failed\n");
+ return PTR_ERR(phy->usb_split);
+ }
+
+ return 0;
+}
+
+static int starfive_pcie_phy_get_syscon(struct udevice *dev)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ struct ofnode_phandle_args sys_phandle, stg_phandle;
+ int ret;
+
+ /* get corresponding syscon phandle */
+ ret = dev_read_phandle_with_args(dev, "starfive,sys-syscon", NULL, 1, 0,
+ &sys_phandle);
+
+ if (ret < 0) {
+ dev_err(dev, "Can't get sys cfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ ret = dev_read_phandle_with_args(dev, "starfive,stg-syscon", NULL, 2, 0,
+ &stg_phandle);
+
+ if (ret < 0) {
+ dev_err(dev, "Can't get stg cfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ phy->sys_syscon = syscon_node_to_regmap(sys_phandle.node);
+ /* get syscon register offset */
+ if (!IS_ERR(phy->sys_syscon)) {
+ ret = phy_sys_regfield_init(dev, SYSCON_USB_PDRSTN_REG_OFFSET);
+ if (ret)
+ return ret;
+ } else {
+ phy->sys_syscon = NULL;
+ }
+
+ phy->stg_syscon = syscon_node_to_regmap(stg_phandle.node);
+ if (!IS_ERR(phy->stg_syscon))
+ return phy_stg_regfield_init(dev, stg_phandle.args[0],
+ stg_phandle.args[1]);
+ else
+ phy->stg_syscon = NULL;
+
+ return 0;
+}
+
+int jh7110_pcie_phy_probe(struct udevice *dev)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ int rc;
+
+ phy->regs = dev_read_addr_ptr(dev);
+ if (!phy->regs)
+ return -EINVAL;
+
+ rc = starfive_pcie_phy_get_syscon(dev);
+ if (rc)
+ return rc;
+
+ phy_kvco_gain_set(phy);
+
+ return 0;
+}
+
+static const struct udevice_id jh7110_pcie_phy[] = {
+ { .compatible = "starfive,jh7110-pcie-phy"},
+ {},
+};
+
+U_BOOT_DRIVER(jh7110_pcie_phy) = {
+ .name = "jh7110_pcie_phy",
+ .id = UCLASS_PHY,
+ .of_match = jh7110_pcie_phy,
+ .probe = jh7110_pcie_phy_probe,
+ .ops = &jh7110_pcie_phy_ops,
+ .priv_auto = sizeof(struct jh7110_pcie_phy),
+};
diff --git a/drivers/phy/starfive/phy-jh7110-usb-syscon.h b/drivers/phy/starfive/phy-jh7110-usb-syscon.h
new file mode 100644
index 00000000000..0eb66f0d859
--- /dev/null
+++ b/drivers/phy/starfive/phy-jh7110-usb-syscon.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef PHY_JH7110_USB_SYSCON_H_
+#define PHY_JH7110_USB_SYSCON_H_
+
+#define SYSCON_USB_PDRSTN_REG_OFFSET 0x18
+#define USB_PDRSTN_SPLIT_BIT 17
+
+#endif
diff --git a/drivers/phy/starfive/phy-jh7110-usb2.c b/drivers/phy/starfive/phy-jh7110-usb2.c
new file mode 100644
index 00000000000..1a28381e0df
--- /dev/null
+++ b/drivers/phy/starfive/phy-jh7110-usb2.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * StarFive JH7110 USB 2.0 PHY driver
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Minda Chen <minda.chen@starfivetech.com>
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <soc.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#include "phy-jh7110-usb-syscon.h"
+
+#define USB_LS_KEEPALIVE_OFF 0x4
+#define USB_LS_KEEPALIVE_ENABLE BIT(4)
+#define USB_PHY_CLK_RATE 125000000
+
+struct jh7110_usb2_phy {
+ struct phy *phy;
+ struct regmap *sys_syscon;
+ void __iomem *regs;
+ struct clk *usb_125m_clk;
+ struct clk *app_125m;
+ struct regmap_field *usb_split;
+ enum phy_mode mode;
+};
+
+static void usb2_set_ls_keepalive(struct jh7110_usb2_phy *phy, bool set)
+{
+ /* Host mode enable the LS speed keep-alive signal */
+ clrsetbits_le32(phy->regs + USB_LS_KEEPALIVE_OFF,
+ USB_LS_KEEPALIVE_ENABLE,
+ set ? USB_LS_KEEPALIVE_ENABLE : 0);
+}
+
+static int usb2_phy_set_mode(struct phy *phy,
+ enum phy_mode mode, int submode)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
+
+ if (mode == usb2_phy->mode)
+ return 0;
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ case PHY_MODE_USB_DEVICE:
+ case PHY_MODE_USB_OTG:
+ dev_dbg(dev, "Changing PHY to %d\n", mode);
+ usb2_phy->mode = mode;
+ usb2_set_ls_keepalive(usb2_phy, (mode != PHY_MODE_USB_DEVICE));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set default split usb 2.0 only mode */
+ regmap_field_write(usb2_phy->usb_split, true);
+
+ return 0;
+}
+
+static int jh7110_usb2_phy_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_set_rate(usb2_phy->usb_125m_clk, USB_PHY_CLK_RATE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set 125m clock\n");
+ return ret;
+ }
+
+ return clk_prepare_enable(usb2_phy->app_125m);
+}
+
+static int jh7110_usb2_phy_exit(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
+
+ clk_disable_unprepare(usb2_phy->app_125m);
+
+ return 0;
+}
+
+struct phy_ops jh7110_usb2_phy_ops = {
+ .init = jh7110_usb2_phy_init,
+ .exit = jh7110_usb2_phy_exit,
+ .set_mode = usb2_phy_set_mode,
+};
+
+int jh7110_usb2_phy_probe(struct udevice *dev)
+{
+ struct jh7110_usb2_phy *phy = dev_get_priv(dev);
+ ofnode node;
+ struct reg_field usb_split;
+ int ret;
+
+ phy->regs = dev_read_addr_ptr(dev);
+ if (!phy->regs)
+ return -EINVAL;
+
+ node = ofnode_by_compatible(ofnode_null(), "starfive,jh7110-sys-syscon");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "Can't get syscon dev node\n");
+ return -ENODEV;
+ }
+
+ phy->sys_syscon = syscon_node_to_regmap(node);
+ if (IS_ERR(phy->sys_syscon)) {
+ dev_err(dev, "Can't get syscon regmap: %d\n", ret);
+ return PTR_ERR(phy->sys_syscon);
+ }
+
+ usb_split.reg = SYSCON_USB_PDRSTN_REG_OFFSET;
+ usb_split.lsb = USB_PDRSTN_SPLIT_BIT;
+ usb_split.msb = USB_PDRSTN_SPLIT_BIT;
+ phy->usb_split = devm_regmap_field_alloc(dev, phy->sys_syscon, usb_split);
+ if (IS_ERR(phy->usb_split)) {
+ dev_err(dev, "USB split field init failed\n");
+ return PTR_ERR(phy->usb_split);
+ }
+
+ phy->usb_125m_clk = devm_clk_get(dev, "125m");
+ if (IS_ERR(phy->usb_125m_clk)) {
+ dev_err(dev, "Failed to get 125m clock\n");
+ return PTR_ERR(phy->usb_125m_clk);
+ }
+
+ phy->app_125m = devm_clk_get(dev, "app_125m");
+ if (IS_ERR(phy->app_125m)) {
+ dev_err(dev, "Failed to get app 125m clock\n");
+ return PTR_ERR(phy->app_125m);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id jh7110_usb2_phy[] = {
+ { .compatible = "starfive,jh7110-usb-phy"},
+ {},
+};
+
+U_BOOT_DRIVER(jh7110_usb2_phy) = {
+ .name = "jh7110_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = jh7110_usb2_phy,
+ .probe = jh7110_usb2_phy_probe,
+ .ops = &jh7110_usb2_phy_ops,
+ .priv_auto = sizeof(struct jh7110_usb2_phy),
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 6ee7dc1cce8..687fb339ea0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -178,6 +178,14 @@ config PINCTRL_APPLE
both the GPIO definitions and pin control functions for each
available multiplex function.
+config PINCTRL_ADI
+ bool "ADI pinctrl driver"
+ depends on DM && ARCH_SC5XX
+ help
+ This driver enables pinctrl support on SC5xx processors. This
+ driver covers only the pin configuration functionality, and
+ GPIO functionality is contained in the separate GPIO driver.
+
config PINCTRL_AR933X
bool "QCA/Athores ar933x pin control driver"
depends on DM && SOC_AR933X
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 634047a91f4..6deb6aaf6eb 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -3,6 +3,7 @@
obj-y += pinctrl-uclass.o
obj-$(CONFIG_$(XPL_)PINCTRL_GENERIC) += pinctrl-generic.o
+obj-$(CONFIG_PINCTRL_ADI) += pinctrl-adi-adsp.o
obj-$(CONFIG_PINCTRL_APPLE) += pinctrl-apple.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o
@@ -15,7 +16,6 @@ obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
obj-$(CONFIG_ARCH_NPCM) += nuvoton/
obj-$(CONFIG_PINCTRL_QCOM) += qcom/
obj-$(CONFIG_ARCH_RENESAS) += renesas/
-obj-$(CONFIG_ARCH_RZN1) += renesas/
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/
obj-$(CONFIG_$(XPL_)PINCTRL_TEGRA) += tegra/
diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig
index 316a8fe27fd..0d8bfc53c11 100644
--- a/drivers/pinctrl/intel/Kconfig
+++ b/drivers/pinctrl/intel/Kconfig
@@ -8,9 +8,6 @@ config INTEL_PINCTRL_DUAL_ROUTE_SUPPORT
bool
default y
-config INTEL_PINCTRL_PADCFG_PADTOL
- bool n
-
config INTEL_PINCTRL_IOSTANDBY
bool
default y
diff --git a/drivers/pinctrl/pinctrl-adi-adsp.c b/drivers/pinctrl/pinctrl-adi-adsp.c
new file mode 100644
index 00000000000..debf434212d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-adi-adsp.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Author: Greg Malysa <greg.malysa@timesys.com>
+ * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ *
+ * dm pinctrl implementation for ADI ADSP SoCs
+ *
+ */
+
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define ADSP_PORT_MMIO_SIZE 0x80
+#define ADSP_PORT_PIN_SIZE 16
+
+#define ADSP_PORT_PORT_MUX_BITS 2
+#define ADSP_PORT_PORT_MUX_MASK 0x03
+#define ADSP_PINCTRL_FUNCTION_COUNT 4
+
+#define ADSP_PORT_REG_FER 0x00
+#define ADSP_PORT_REG_FER_SET 0x04
+#define ADSP_PORT_REG_FER_CLEAR 0x08
+#define ADSP_PORT_REG_DATA 0x0c
+#define ADSP_PORT_REG_DATA_SET 0x10
+#define ADSP_PORT_REG_DATA_CLEAR 0x14
+#define ADSP_PORT_REG_DIR 0x18
+#define ADSP_PORT_REG_DIR_SET 0x1c
+#define ADSP_PORT_REG_DIR_CLEAR 0x20
+#define ADSP_PORT_REG_INEN 0x24
+#define ADSP_PORT_REG_INEN_SET 0x28
+#define ADSP_PORT_REG_INEN_CLEAR 0x2c
+#define ADSP_PORT_REG_PORT_MUX 0x30
+#define ADSP_PORT_REG_DATA_TGL 0x34
+#define ADSP_PORT_REG_POLAR 0x38
+#define ADSP_PORT_REG_POLAR_SET 0x3c
+#define ADSP_PORT_REG_POLAR_CLEAR 0x40
+#define ADSP_PORT_REG_LOCK 0x44
+#define ADSP_PORT_REG_TRIG_TGL 0x48
+
+struct adsp_pinctrl_priv {
+ void __iomem *base;
+ int npins;
+ char pinbuf[16];
+};
+
+static u32 get_port(unsigned int pin)
+{
+ return pin / ADSP_PORT_PIN_SIZE;
+}
+
+static u32 get_offset(unsigned int pin)
+{
+ return pin % ADSP_PORT_PIN_SIZE;
+}
+
+static int adsp_pinctrl_pinmux_set(struct udevice *udev, unsigned int pin, unsigned int func)
+{
+ struct adsp_pinctrl_priv *priv = dev_get_priv(udev);
+ void __iomem *portbase;
+ u32 port, offset;
+ u32 val;
+
+ if (pin >= priv->npins)
+ return -ENODEV;
+
+ if (func >= ADSP_PINCTRL_FUNCTION_COUNT)
+ return -EINVAL;
+
+ port = get_port(pin);
+ offset = get_offset(pin);
+ portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
+
+ val = ioread32(portbase + ADSP_PORT_REG_PORT_MUX);
+ val &= ~(ADSP_PORT_PORT_MUX_MASK << (ADSP_PORT_PORT_MUX_BITS * offset));
+ val |= func << (ADSP_PORT_PORT_MUX_BITS * offset);
+ iowrite32(val, portbase + ADSP_PORT_REG_PORT_MUX);
+
+ iowrite32(BIT(offset), portbase + ADSP_PORT_REG_FER_SET);
+ return 0;
+}
+
+static int adsp_pinctrl_set_state(struct udevice *udev, struct udevice *config)
+{
+ const struct fdt_property *pinlist;
+ int length = 0;
+ int ret, i;
+ u32 pin, function;
+
+ pinlist = dev_read_prop(config, "adi,pins", &length);
+ if (!pinlist) {
+ dev_err(udev, "missing adi,pins property in pinctrl config node\n");
+ return -EINVAL;
+ }
+
+ if (length % (sizeof(uint32_t) * 2)) {
+ dev_err(udev, "adi,pins property must be a multiple of two uint32_ts\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < length / sizeof(uint32_t); i += 2) {
+ ret = dev_read_u32_index(config, "adi,pins", i, &pin);
+ if (ret)
+ return ret;
+
+ ret = dev_read_u32_index(config, "adi,pins", i + 1, &function);
+ if (ret)
+ return ret;
+
+ ret = adsp_pinctrl_pinmux_set(udev, pin, function);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct pinctrl_ops adsp_pinctrl_ops = {
+ .set_state = adsp_pinctrl_set_state,
+};
+
+static int adsp_pinctrl_probe(struct udevice *udev)
+{
+ struct adsp_pinctrl_priv *priv = dev_get_priv(udev);
+
+ priv->base = dev_read_addr_ptr(udev);
+ priv->npins = dev_read_u32_default(udev, "adi,npins", 0);
+
+ if (!priv->base) {
+ dev_err(udev, "Missing or invalid pinctrl base address\n");
+ return -ENOENT;
+ }
+
+ if (!priv->npins) {
+ dev_err(udev, "Missing adi,npins property!\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id adsp_pinctrl_match[] = {
+ { .compatible = "adi,adsp-pinctrl" },
+ { },
+};
+
+U_BOOT_DRIVER(adi_adsp_pinctrl) = {
+ .name = "adi_adsp_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = adsp_pinctrl_match,
+ .probe = adsp_pinctrl_probe,
+ .priv_auto = sizeof(struct adsp_pinctrl_priv),
+ .ops = &adsp_pinctrl_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 5038cb535e3..2938635ed95 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -9,6 +9,8 @@
#include <dm.h>
#include <log.h>
#include <asm/global_data.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
#include <dm/pinctrl.h>
#include <asm/hardware.h>
#include <linux/bitops.h>
@@ -492,21 +494,58 @@ const struct pinctrl_ops at91_pinctrl_ops = {
.set_state = at91_pinctrl_set_state,
};
+/**
+ * at91_pinctrl_bind() - Iterates through all subnodes of the pinctrl device
+ * in the DT and binds them to U-Boot's device model. Each subnode
+ * typically represents a GPIO controller or pin configuration data.
+ *
+ * @dev: Pointer to the pinctrl device
+ *
+ * Returns 0 on success or negative error on failure
+ */
+static int at91_pinctrl_bind(struct udevice *dev)
+{
+ ofnode gpio_node;
+ struct udevice *gpio;
+ int ret;
+
+ ofnode_for_each_subnode(gpio_node, dev_ofnode(dev)) {
+ ret = lists_bind_fdt(dev, gpio_node, &gpio, NULL, false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int at91_pinctrl_probe(struct udevice *dev)
{
struct at91_pinctrl_priv *priv = dev_get_priv(dev);
fdt_addr_t addr_base;
+ struct udevice *gpio_node;
int index;
- for (index = 0; index < MAX_GPIO_BANKS; index++) {
- addr_base = devfdt_get_addr_index(dev, index);
- if (addr_base == FDT_ADDR_T_NONE)
- break;
+ if (list_empty(&dev->child_head)) {
+ for (index = 0; index < MAX_GPIO_BANKS; index++) {
+ addr_base = devfdt_get_addr_index(dev, index);
+ if (addr_base == FDT_ADDR_T_NONE)
+ break;
- priv->reg_base[index] = (struct at91_port *)addr_base;
+ priv->reg_base[index] = (struct at91_port *)addr_base;
+ }
+ } else {
+ index = 0;
+ list_for_each_entry(gpio_node, &dev->child_head, sibling_node) {
+ addr_base = dev_read_addr(gpio_node);
+ if (addr_base == FDT_ADDR_T_NONE)
+ break;
+
+ priv->reg_base[index] = (struct at91_port *)addr_base;
+ index++;
+ }
}
- priv->nbanks = index;
+ priv->nbanks = index < MAX_GPIO_BANKS ? index : MAX_GPIO_BANKS;
return 0;
}
@@ -524,6 +563,7 @@ U_BOOT_DRIVER(atmel_sama5d3_pinctrl) = {
.id = UCLASS_PINCTRL,
.of_match = at91_pinctrl_match,
.probe = at91_pinctrl_probe,
+ .bind = at91_pinctrl_bind,
.priv_auto = sizeof(struct at91_pinctrl_priv),
.ops = &at91_pinctrl_ops,
};
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index d3eb6998551..f4a3942ee2f 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -7,84 +7,98 @@ config PINCTRL_QCOM
menu "Qualcomm pinctrl drivers"
config PINCTRL_QCOM_APQ8016
- bool "Qualcomm APQ8016 GCC"
+ bool "Qualcomm APQ8016 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the MSM8916 / APQ8016
Snapdragon 410 SoC, as well as the associated GPIO driver.
config PINCTRL_QCOM_APQ8096
- bool "Qualcomm APQ8096 GCC"
+ bool "Qualcomm APQ8096 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the MSM8996 / APQ8096
Snapdragon 820 SoC, as well as the associated GPIO driver.
config PINCTRL_QCOM_IPQ4019
- bool "Qualcomm IPQ4019 GCC"
+ bool "Qualcomm IPQ4019 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the IPQ4019 SoC,
as well as the associated GPIO driver.
+config PINCTRL_QCOM_IPQ9574
+ bool "Qualcomm IPQ9574 Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the IPQ9574 SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_QCM2290
- bool "Qualcomm QCM2290 GCC"
+ bool "Qualcomm QCM2290 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon QCM2290 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_QCS404
- bool "Qualcomm QCS404 GCC"
+ bool "Qualcomm QCS404 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon QCS404 SoC,
as well as the associated GPIO driver.
+config PINCTRL_QCOM_SC7280
+ bool "Qualcomm SC7280/QCM6490 Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_SDM845
- bool "Qualcomm SDM845 GCC"
+ bool "Qualcomm SDM845 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon 845 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_SM6115
- bool "Qualcomm SM6115 GCC"
+ bool "Qualcomm SM6115 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SM6115 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_SM8150
- bool "Qualcomm SM8150 GCC"
+ bool "Qualcomm SM8150 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SM8150 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_SM8250
- bool "Qualcomm SM8250 GCC"
+ bool "Qualcomm SM8250 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SM8250 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_SM8550
- bool "Qualcomm SM8550 GCC"
+ bool "Qualcomm SM8550 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SM8550 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_SM8650
- bool "Qualcomm SM8650 GCC"
+ bool "Qualcomm SM8650 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SM8650 SoC,
as well as the associated GPIO driver.
config PINCTRL_QCOM_X1E80100
- bool "Qualcomm X1E80100 GCC"
+ bool "Qualcomm X1E80100 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon X1E80100 SoC,
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 06d3c95f93a..94cdc6e4a62 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -5,9 +5,11 @@
obj-$(CONFIG_PINCTRL_QCOM) += pinctrl-qcom.o
obj-$(CONFIG_PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o
obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o
+obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o
obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o
obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o
obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o
+obj-$(CONFIG_PINCTRL_QCOM_SC7280) += pinctrl-sc7280.o
obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o
obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8016.c b/drivers/pinctrl/qcom/pinctrl-apq8016.c
index 0c7437822ff..9ae07d43d93 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8016.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8016.c
@@ -50,8 +50,8 @@ static const char *apq8016_get_pin_name(struct udevice *dev,
}
}
-static unsigned int apq8016_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int apq8016_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8096.c b/drivers/pinctrl/qcom/pinctrl-apq8096.c
index 132ece868bf..eaa927c6e22 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8096.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8096.c
@@ -43,8 +43,8 @@ static const char *apq8096_get_pin_name(struct udevice *dev,
}
}
-static unsigned int apq8096_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int apq8096_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index 3215c677b26..dafcd494df4 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -311,8 +311,7 @@ static const char *ipq4019_get_pin_name(struct udevice *dev,
return pin_name;
}
-static unsigned int ipq4019_get_function_mux(unsigned int pin,
- unsigned int selector)
+static int ipq4019_get_function_mux(unsigned int pin, unsigned int selector)
{
unsigned int i;
const msm_pin_function *func = ipq4019_pin_functions + pin;
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq9574.c b/drivers/pinctrl/qcom/pinctrl-ipq9574.c
new file mode 100644
index 00000000000..ce09072ae3c
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-ipq9574.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pinctrl driver for Qualcomm ipq9574
+ *
+ * (C) Copyright 2025 Linaro Ltd.
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+enum ipq9574_functions {
+ msm_mux_blsp0_spi,
+ msm_mux_blsp0_uart,
+ msm_mux_blsp1_i2c,
+ msm_mux_blsp1_spi,
+ msm_mux_blsp1_uart,
+ msm_mux_blsp2_i2c,
+ msm_mux_blsp2_spi,
+ msm_mux_blsp2_uart,
+ msm_mux_blsp3_i2c,
+ msm_mux_blsp3_spi,
+ msm_mux_blsp3_uart,
+ msm_mux_blsp4_i2c,
+ msm_mux_blsp4_spi,
+ msm_mux_blsp4_uart,
+ msm_mux_blsp5_i2c,
+ msm_mux_blsp5_uart,
+ msm_mux_gpio,
+ msm_mux_mdc,
+ msm_mux_mdio,
+ msm_mux_pcie0_clk,
+ msm_mux_pcie0_wake,
+ msm_mux_pcie1_clk,
+ msm_mux_pcie1_wake,
+ msm_mux_pcie2_clk,
+ msm_mux_pcie2_wake,
+ msm_mux_pcie3_clk,
+ msm_mux_pcie3_wake,
+ msm_mux_qspi_data,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_sdc_data,
+ msm_mux_sdc_clk,
+ msm_mux_sdc_cmd,
+ msm_mux_sdc_rclk,
+ msm_mux_NA,
+};
+
+#define MSM_PIN_FUNCTION(fname) \
+ [msm_mux_##fname] = {#fname, msm_mux_##fname}
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ MSM_PIN_FUNCTION(blsp0_spi),
+ MSM_PIN_FUNCTION(blsp0_uart),
+ MSM_PIN_FUNCTION(blsp1_i2c),
+ MSM_PIN_FUNCTION(blsp1_spi),
+ MSM_PIN_FUNCTION(blsp1_uart),
+ MSM_PIN_FUNCTION(blsp2_i2c),
+ MSM_PIN_FUNCTION(blsp2_spi),
+ MSM_PIN_FUNCTION(blsp2_uart),
+ MSM_PIN_FUNCTION(blsp3_i2c),
+ MSM_PIN_FUNCTION(blsp3_spi),
+ MSM_PIN_FUNCTION(blsp3_uart),
+ MSM_PIN_FUNCTION(blsp4_i2c),
+ MSM_PIN_FUNCTION(blsp4_spi),
+ MSM_PIN_FUNCTION(blsp4_uart),
+ MSM_PIN_FUNCTION(blsp5_i2c),
+ MSM_PIN_FUNCTION(blsp5_uart),
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(mdc),
+ MSM_PIN_FUNCTION(mdio),
+ MSM_PIN_FUNCTION(pcie0_clk),
+ MSM_PIN_FUNCTION(pcie0_wake),
+ MSM_PIN_FUNCTION(pcie1_clk),
+ MSM_PIN_FUNCTION(pcie1_wake),
+ MSM_PIN_FUNCTION(pcie2_clk),
+ MSM_PIN_FUNCTION(pcie2_wake),
+ MSM_PIN_FUNCTION(pcie3_clk),
+ MSM_PIN_FUNCTION(pcie3_wake),
+ MSM_PIN_FUNCTION(qspi_data),
+ MSM_PIN_FUNCTION(qspi_clk),
+ MSM_PIN_FUNCTION(qspi_cs),
+ MSM_PIN_FUNCTION(sdc_data),
+ MSM_PIN_FUNCTION(sdc_clk),
+ MSM_PIN_FUNCTION(sdc_cmd),
+ MSM_PIN_FUNCTION(sdc_rclk),
+};
+
+typedef unsigned int msm_pin_function[10];
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ [id] = { msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9, \
+ }
+
+static const msm_pin_function ipq9574_pin_functions[] = {
+ PINGROUP(0, sdc_data, qspi_data, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(1, sdc_data, qspi_data, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(2, sdc_data, qspi_data, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(3, sdc_data, qspi_data, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(4, sdc_cmd, qspi_cs, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(5, sdc_clk, qspi_clk, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(6, sdc_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(7, sdc_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(8, sdc_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(9, sdc_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(10, sdc_rclk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(11, blsp0_spi, blsp0_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(12, blsp0_spi, blsp0_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(13, blsp0_spi, blsp0_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(14, blsp0_spi, blsp0_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(15, blsp3_spi, blsp3_i2c, blsp3_uart, NA, NA, NA, NA, NA, NA),
+ PINGROUP(16, blsp3_spi, blsp3_i2c, blsp3_uart, NA, NA, NA, NA, NA, NA),
+ PINGROUP(17, blsp3_spi, blsp3_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(18, blsp3_spi, blsp3_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(19, blsp3_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(20, blsp3_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(21, blsp3_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(22, pcie0_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(23, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(24, pcie0_wake, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, pcie1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(26, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(27, pcie1_wake, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(28, pcie2_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(29, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(30, pcie2_wake, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(31, pcie3_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(33, pcie3_wake, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(34, blsp2_uart, blsp2_i2c, blsp2_spi, blsp1_uart, NA, NA, NA, NA, NA),
+ PINGROUP(35, blsp2_uart, blsp2_i2c, blsp2_spi, blsp1_uart, NA, NA, NA, NA, NA),
+ PINGROUP(36, blsp1_uart, blsp1_i2c, blsp2_spi, NA, NA, NA, NA, NA, NA),
+ PINGROUP(37, blsp1_uart, blsp1_i2c, blsp2_spi, NA, NA, NA, NA, NA, NA),
+ PINGROUP(38, mdc, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, mdio, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(40, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(41, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(42, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(43, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(44, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(46, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(47, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(48, blsp5_i2c, blsp5_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(49, blsp5_i2c, blsp5_uart, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, blsp4_uart, blsp4_i2c, blsp4_spi, NA, NA, NA, NA, NA, NA),
+ PINGROUP(51, blsp4_uart, blsp4_i2c, blsp4_spi, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, blsp4_uart, blsp4_spi, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(53, blsp4_uart, blsp4_spi, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(61, blsp1_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(62, blsp1_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(63, blsp1_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(64, blsp1_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+};
+
+static const char *ipq9574_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *ipq9574_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+ return pin_name;
+}
+
+static int ipq9574_get_function_mux(unsigned int pin, unsigned int selector)
+{
+ unsigned int i;
+ const msm_pin_function *func = ipq9574_pin_functions + pin;
+
+ for (i = 0; i < 10; i++)
+ if ((*func)[i] == selector)
+ return i;
+
+ debug("Can't find requested function for pin:selector %u:%u\n",
+ pin, selector);
+
+ return -EINVAL;
+}
+
+static const struct msm_pinctrl_data ipq9574_data = {
+ .pin_data = {
+ .pin_count = 65,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = ipq9574_get_function_name,
+ .get_function_mux = ipq9574_get_function_mux,
+ .get_pin_name = ipq9574_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,ipq9574-tlmm", .data = (ulong)&ipq9574_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_ipq9574) = {
+ .name = "pinctrl_ipq9574",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-qcm2290.c b/drivers/pinctrl/qcom/pinctrl-qcm2290.c
index af969e177d7..0c2222ce663 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcm2290.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcm2290.c
@@ -38,7 +38,7 @@ static const char *qcm2290_get_pin_name(struct udevice *dev, unsigned int select
return pin_name;
}
-static unsigned int qcm2290_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+static int qcm2290_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index 26a3fba194a..24d031947a3 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -92,7 +92,10 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
unsigned int func_selector)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
- u32 func = priv->data->get_function_mux(pin_selector, func_selector);
+ int func = priv->data->get_function_mux(pin_selector, func_selector);
+
+ if (func < 0)
+ return func;
/* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.h b/drivers/pinctrl/qcom/pinctrl-qcom.h
index 49b7bfbc001..cd167e63868 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.h
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.h
@@ -18,8 +18,7 @@ struct msm_pinctrl_data {
int functions_count;
const char *(*get_function_name)(struct udevice *dev,
unsigned int selector);
- unsigned int (*get_function_mux)(unsigned int pin,
- unsigned int selector);
+ int (*get_function_mux)(unsigned int pin, unsigned int selector);
const char *(*get_pin_name)(struct udevice *dev,
unsigned int selector);
};
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
index fb6defaeddf..c272595aa2a 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -93,8 +93,8 @@ static const char *qcs404_get_pin_name(struct udevice *dev,
}
}
-static unsigned int qcs404_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int qcs404_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c
new file mode 100644
index 00000000000..fe87947fbbf
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm sc7280 pinctrl
+ *
+ * (C) Copyright 2024 Linaro Ltd.
+ *
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define WEST 0x00000000
+#define SOUTH 0x00400000
+#define NORTH 0x00800000
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ { "qup05", 1 },
+ { "gpio", 0 },
+ { "pcie1_clkreqn", 3},
+};
+#define SDC_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+static const struct msm_special_pin_data sc7280_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", SOUTH + 0xbe000),
+ [1] = SDC_PINGROUP("sdc1_rclk", 0xb3004, 0, 6),
+ [2] = SDC_PINGROUP("sdc1_clk", 0xb3000, 13, 6),
+ [3] = SDC_PINGROUP("sdc1_cmd", 0xb3000, 11, 3),
+ [4] = SDC_PINGROUP("sdc1_data", 0xb3000, 9, 0),
+ [5] = SDC_PINGROUP("sdc2_clk", 0xb4000, 14, 6),
+ [6] = SDC_PINGROUP("sdc2_cmd", 0xb4000, 11, 3),
+ [7] = SDC_PINGROUP("sdc2_data", 0xb4000, 9, 0),
+};
+
+static const char *sc7280_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *sc7280_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ if (selector >= 175 && selector <= 182)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ sc7280_special_pins_data[selector - 175].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sc7280_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static struct msm_pinctrl_data sc7280_data = {
+ .pin_data = {
+ .pin_count = 183,
+ .special_pins_start = 175,
+ .special_pins_data = sc7280_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = sc7280_get_function_name,
+ .get_function_mux = sc7280_get_function_mux,
+ .get_pin_name = sc7280_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ {
+ .compatible = "qcom,sc7280-pinctrl",
+ .data = (ulong)&sc7280_data
+ },
+ { /* Sentinel */ } };
+
+U_BOOT_DRIVER(pinctrl_sc7280) = {
+ .name = "pinctrl_sc7280",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index f1a23f51099..3f55fc81c8e 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -80,8 +80,8 @@ static const char *sdm845_get_pin_name(struct udevice *dev,
return pin_name;
}
-static unsigned int sdm845_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int sdm845_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115.c b/drivers/pinctrl/qcom/pinctrl-sm6115.c
index f07f39f4ac3..7e80ea39a12 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm6115.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm6115.c
@@ -167,7 +167,7 @@ static const char *sm6115_get_pin_name(struct udevice *dev, unsigned int selecto
return pin_name;
}
-static unsigned int sm6115_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+static int sm6115_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c
index 1fb2ffb9597..fe789e8639b 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8150.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c
@@ -123,8 +123,8 @@ static const char *sm8150_get_pin_name(struct udevice *dev,
return pin_name;
}
-static unsigned int sm8150_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int sm8150_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c
index b21cdc4d24b..d5447651695 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8250.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c
@@ -99,7 +99,7 @@ static const char *sm8250_get_pin_name(struct udevice *dev, unsigned int selecto
return pin_name;
}
-static unsigned int sm8250_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+static int sm8250_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c
index 25b972a6d82..f7fcad0e4aa 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8550.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c
@@ -68,8 +68,8 @@ static const char *sm8550_get_pin_name(struct udevice *dev,
return pin_name;
}
-static unsigned int sm8550_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int sm8550_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650.c b/drivers/pinctrl/qcom/pinctrl-sm8650.c
index 9146d6abd9a..6b9d56b1058 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8650.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8650.c
@@ -69,8 +69,8 @@ static const char *sm8650_get_pin_name(struct udevice *dev,
return pin_name;
}
-static unsigned int sm8650_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int sm8650_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c
index f39dc426d68..319667bfc16 100644
--- a/drivers/pinctrl/qcom/pinctrl-x1e80100.c
+++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c
@@ -72,8 +72,8 @@ static const char *x1e80100_get_pin_name(struct udevice *dev,
return pin_name;
}
-static unsigned int x1e80100_get_function_mux(__maybe_unused unsigned int pin,
- unsigned int selector)
+static int x1e80100_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
{
return msm_pinctrl_functions[selector].val;
}
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index cbd61795986..65e8192a99a 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -124,6 +124,16 @@ config PINCTRL_SUN50I_H616_R
default MACH_SUN50I_H616
select PINCTRL_SUNXI
+config PINCTRL_SUN50I_A100
+ bool "Support for the Allwinner A100/A133 PIO"
+ default MACH_SUN50I_A133
+ select PINCTRL_SUNXI
+
+config PINCTRL_SUN50I_A100_R
+ bool "Support for the Allwinner A100/A133 R-PIO"
+ default MACH_SUN50I_A133
+ select PINCTRL_SUNXI
+
config PINCTRL_SUN20I_D1
bool "Support for the Allwinner D1/R528 PIO"
default MACH_SUN8I_R528
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 37ea93715d1..c38edf7d4f5 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -774,6 +774,41 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_r_pinctrl_desc
.num_banks = 1,
};
+static const struct sunxi_pinctrl_function sun50i_a100_pinctrl_functions[] = {
+ { "emac0", 5 }, /* PH0-PH16 */
+ { "gpio_in", 0 },
+ { "gpio_out", 1 },
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC0-PC16 */
+ { "spi0", 4 }, /* PC2-PC4, PC7, PC12, PC15-PC16 */
+#if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+#else
+ { "uart0", 2 }, /* PB9-PB10 */
+#endif
+};
+
+static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a100_pinctrl_desc = {
+ .functions = sun50i_a100_pinctrl_functions,
+ .num_functions = ARRAY_SIZE(sun50i_a100_pinctrl_functions),
+ .first_bank = SUNXI_GPIO_A,
+ .num_banks = 8,
+};
+
+static const struct sunxi_pinctrl_function sun50i_a100_r_pinctrl_functions[] = {
+ { "gpio_in", 0 },
+ { "gpio_out", 1 },
+ { "s_i2c0", 2 },
+};
+
+static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a100_r_pinctrl_desc = {
+ .functions = sun50i_a100_r_pinctrl_functions,
+ .num_functions = ARRAY_SIZE(sun50i_a100_r_pinctrl_functions),
+ .first_bank = SUNXI_GPIO_L,
+ .num_banks = 1,
+};
+
static const struct udevice_id sunxi_pinctrl_ids[] = {
#ifdef CONFIG_PINCTRL_SUNIV_F1C100S
{
@@ -937,6 +972,18 @@ static const struct udevice_id sunxi_pinctrl_ids[] = {
.data = (ulong)&sun50i_h616_r_pinctrl_desc,
},
#endif
+#ifdef CONFIG_PINCTRL_SUN50I_A100
+ {
+ .compatible = "allwinner,sun50i-a100-pinctrl",
+ .data = (ulong)&sun50i_a100_pinctrl_desc,
+ },
+#endif
+#ifdef CONFIG_PINCTRL_SUN50I_A100_R
+ {
+ .compatible = "allwinner,sun50i-a100-r-pinctrl",
+ .data = (ulong)&sun50i_a100_r_pinctrl_desc,
+ },
+#endif
{}
};
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index ad7112a05e6..b04be168bc8 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -23,18 +23,18 @@ static void tegra_pinctrl_set_drive(struct udevice *config, int drvcnt)
return;
}
- drive_group[0].slwf = dev_read_u32_default(config, "nvidia,slew-rate-falling", 0);
- drive_group[0].slwr = dev_read_u32_default(config, "nvidia,slew-rate-rising", 0);
- drive_group[0].drvup = dev_read_u32_default(config, "nvidia,pull-up-strength", 0);
- drive_group[0].drvdn = dev_read_u32_default(config, "nvidia,pull-down-strength", 0);
+ drive_group[0].slwf = dev_read_u32_default(config, "nvidia,slew-rate-falling", PMUX_SLWF_NONE);
+ drive_group[0].slwr = dev_read_u32_default(config, "nvidia,slew-rate-rising", PMUX_SLWR_NONE);
+ drive_group[0].drvup = dev_read_u32_default(config, "nvidia,pull-up-strength", PMUX_DRVUP_NONE);
+ drive_group[0].drvdn = dev_read_u32_default(config, "nvidia,pull-down-strength", PMUX_DRVDN_NONE);
#ifdef TEGRA_PMX_GRPS_HAVE_LPMD
- drive_group[0].lpmd = dev_read_u32_default(config, "nvidia,low-power-mode", 0);
+ drive_group[0].lpmd = dev_read_u32_default(config, "nvidia,low-power-mode", PMUX_LPMD_NONE);
#endif
#ifdef TEGRA_PMX_GRPS_HAVE_SCHMT
- drive_group[0].schmt = dev_read_u32_default(config, "nvidia,schmitt", 0);
+ drive_group[0].schmt = dev_read_u32_default(config, "nvidia,schmitt", PMUX_SCHMT_NONE);
#endif
#ifdef TEGRA_PMX_GRPS_HAVE_HSM
- drive_group[0].hsm = dev_read_u32_default(config, "nvidia,high-speed-mode", 0);
+ drive_group[0].hsm = dev_read_u32_default(config, "nvidia,high-speed-mode", PMUX_HSM_NONE);
#endif
for (i = 1; i < drvcnt; i++)
@@ -67,6 +67,58 @@ exit:
kfree(drive_group);
}
+#ifdef TEGRA_PMX_SOC_HAS_MIPI_PAD_CTRL_GRPS
+static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt)
+{
+ struct pmux_mipipadctrlgrp_config *mipipad_group;
+ int i, ret, pad_id;
+ const char *function;
+ const char **pads;
+
+ mipipad_group = kmalloc_array(padcnt, sizeof(*mipipad_group), GFP_KERNEL);
+ if (!mipipad_group) {
+ log_debug("%s: cannot allocate mipi pad group array\n", __func__);
+ return;
+ }
+
+ /* decode function id and fill the first copy of pmux_mipipadctrlgrp_config */
+ function = dev_read_string(config, "nvidia,function");
+ if (function)
+ for (i = 0; i < PMUX_FUNC_COUNT; i++)
+ if (tegra_pinctrl_to_func[i])
+ if (!strcmp(function, tegra_pinctrl_to_func[i]))
+ break;
+
+ mipipad_group[0].func = i;
+
+ for (i = 1; i < padcnt; i++)
+ memcpy(&mipipad_group[i], &mipipad_group[0], sizeof(mipipad_group[0]));
+
+ ret = dev_read_string_list(config, "nvidia,pins", &pads);
+ if (ret < 0) {
+ log_debug("%s: could not parse property nvidia,pins\n", __func__);
+ goto exit;
+ }
+
+ for (i = 0; i < padcnt; i++) {
+ for (pad_id = 0; pad_id < PMUX_MIPIPADCTRLGRP_COUNT; pad_id++)
+ if (tegra_pinctrl_to_mipipadgrp[pad_id])
+ if (!strcmp(pads[i], tegra_pinctrl_to_mipipadgrp[pad_id])) {
+ mipipad_group[i].grp = pad_id;
+ break;
+ }
+ }
+
+ pinmux_config_mipipadctrlgrp_table(mipipad_group, padcnt);
+
+ free(pads);
+exit:
+ kfree(mipipad_group);
+}
+#else
+static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt) { }
+#endif
+
static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt)
{
struct pmux_pingrp_config *pinmux_group;
@@ -90,31 +142,31 @@ static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt)
pinmux_group[0].func = i;
- pinmux_group[0].pull = dev_read_u32_default(config, "nvidia,pull", 0);
- pinmux_group[0].tristate = dev_read_u32_default(config, "nvidia,tristate", 0);
+ pinmux_group[0].pull = dev_read_u32_default(config, "nvidia,pull", PMUX_PULL_NORMAL);
+ pinmux_group[0].tristate = dev_read_u32_default(config, "nvidia,tristate", PMUX_TRI_TRISTATE);
#ifdef TEGRA_PMX_PINS_HAVE_E_INPUT
- pinmux_group[0].io = dev_read_u32_default(config, "nvidia,enable-input", 0);
+ pinmux_group[0].io = dev_read_u32_default(config, "nvidia,enable-input", PMUX_PIN_NONE);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_LOCK
- pinmux_group[0].lock = dev_read_u32_default(config, "nvidia,lock", 0);
+ pinmux_group[0].lock = dev_read_u32_default(config, "nvidia,lock", PMUX_PIN_LOCK_DEFAULT);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_OD
- pinmux_group[0].od = dev_read_u32_default(config, "nvidia,open-drain", 0);
+ pinmux_group[0].od = dev_read_u32_default(config, "nvidia,open-drain", PMUX_PIN_OD_DEFAULT);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_IO_RESET
- pinmux_group[0].ioreset = dev_read_u32_default(config, "nvidia,io-reset", 0);
+ pinmux_group[0].ioreset = dev_read_u32_default(config, "nvidia,io-reset", PMUX_PIN_IO_RESET_DEFAULT);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL
- pinmux_group[0].rcv_sel = dev_read_u32_default(config, "nvidia,rcv-sel", 0);
+ pinmux_group[0].rcv_sel = dev_read_u32_default(config, "nvidia,rcv-sel", PMUX_PIN_RCV_SEL_DEFAULT);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV
- pinmux_group[0].e_io_hv = dev_read_u32_default(config, "nvidia,io-hv", 0);
+ pinmux_group[0].e_io_hv = dev_read_u32_default(config, "nvidia,io-hv", PMUX_PIN_E_IO_HV_DEFAULT);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_SCHMT
- pinmux_group[0].schmt = dev_read_u32_default(config, "nvidia,schmitt", 0);
+ pinmux_group[0].schmt = dev_read_u32_default(config, "nvidia,schmitt", PMUX_SCHMT_NONE);
#endif
#ifdef TEGRA_PMX_PINS_HAVE_HSM
- pinmux_group[0].hsm = dev_read_u32_default(config, "nvidia,high-speed-mode", 0);
+ pinmux_group[0].hsm = dev_read_u32_default(config, "nvidia,high-speed-mode", PMUX_HSM_NONE);
#endif
for (i = 1; i < pincnt; i++)
@@ -170,6 +222,9 @@ static int tegra_pinctrl_set_state(struct udevice *dev, struct udevice *config)
if (!strncmp(name, "drive_", 6))
/* Drive node is detected */
tegra_pinctrl_set_drive(child, ret);
+ else if (!strncmp(name, "mipi_pad_ctrl_", 14))
+ /* Handle T124 specific pinconfig */
+ tegra_pinctrl_set_mipipad(child, ret);
else
/* Pin node is detected */
tegra_pinctrl_set_pin(child, ret);
@@ -236,6 +291,7 @@ static int tegra_pinctrl_bind(struct udevice *dev)
static const struct udevice_id tegra_pinctrl_ids[] = {
{ .compatible = "nvidia,tegra30-pinmux" },
{ .compatible = "nvidia,tegra114-pinmux" },
+ { .compatible = "nvidia,tegra124-pinmux" },
{ },
};
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 4b81aeb7497..eed65058e66 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -116,6 +116,12 @@ config AXP717_POWER
---help---
Select this to enable support for the AXP717 PMIC found on some boards.
+config AXP803_POWER
+ bool "AXP803 PMIC support"
+ select AXP_PMIC_BUS
+ ---help---
+ Select this to enable support for the AXP803 PMIC found on some boards.
+
config AXP809_POWER
bool "axp809 pmic support"
depends on MACH_SUN9I
@@ -142,10 +148,20 @@ config SY8106A_POWER
endchoice
+config AXP_I2C_ADDRESS
+ hex "AXP PMIC I2C address"
+ depends on ARCH_SUNXI && !SUNXI_NO_PMIC
+ default 0x36 if AXP305_POWER
+ default 0x36 if AXP313_POWER
+ default 0x30 if AXP152_POWER
+ default 0x34
+ ---help---
+ I2C address of the AXP PMIC, used for the SPL only.
+
config AXP_DCDC1_VOLT
int "axp pmic dcdc1 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
- default 3300 if AXP818_POWER || MACH_SUN8I_R40
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER
+ default 3300 if AXP818_POWER || MACH_SUN8I_R40 || AXP803_POWER
default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
---help---
Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to
@@ -158,11 +174,12 @@ config AXP_DCDC1_VOLT
config AXP_DCDC2_VOLT
int "axp pmic dcdc2 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER || AXP717_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER || AXP717_POWER || AXP803_POWER
default 900 if AXP818_POWER
default 1400 if AXP152_POWER || AXP209_POWER
default 1000 if AXP313_POWER
default 1000 if AXP717_POWER
+ default 1000 if AXP803_POWER
default 1200 if MACH_SUN6I
default 1100 if MACH_SUN8I
default 0 if MACH_SUN9I
@@ -219,7 +236,7 @@ config AXP_DCDC4_VOLT
config AXP_DCDC5_VOLT
int "axp pmic dcdc5 voltage"
- depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER
default 1500 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
---help---
Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 3f4d56f5139..3363191fdc8 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_AXP313_POWER) += axp_spl.o
obj-$(CONFIG_AXP717_POWER) += axp_spl.o
obj-$(CONFIG_AXP809_POWER) += axp809.o
obj-$(CONFIG_AXP818_POWER) += axp818.o
+obj-$(CONFIG_AXP803_POWER) += axp_spl.o
endif
obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
obj-$(CONFIG_SY8106A_POWER) += sy8106a.o
diff --git a/drivers/power/axp_spl.c b/drivers/power/axp_spl.c
index 3c86eb20ab4..7c51a9b3dfb 100644
--- a/drivers/power/axp_spl.c
+++ b/drivers/power/axp_spl.c
@@ -36,6 +36,23 @@ static const struct axp_reg_desc_spl axp_spl_dcdc_regulators[] = {
#define AXP_SHUTDOWN_REG 0x27
#define AXP_SHUTDOWN_MASK BIT(0)
+#elif defined(CONFIG_AXP803_POWER) /* AXP803 */
+
+static const struct axp_reg_desc_spl axp_spl_dcdc_regulators[] = {
+ { 0x10, BIT(0), 0x20, 0x1f, 1600, 3400, 100, NA },
+ { 0x10, BIT(1), 0x21, 0x7f, 500, 1300, 10, 70 },
+ { 0x10, BIT(2), 0x22, 0x7f, 500, 1300, 10, 70 },
+ { 0x10, BIT(3), 0x23, 0x7f, 500, 1300, 10, 70 },
+ { 0x10, BIT(4), 0x24, 0x7f, 800, 1840, 10, 32 },
+ { 0x10, BIT(5), 0x25, 0x7f, 600, 1520, 10, 50 },
+};
+
+#define AXP_CHIP_VERSION 0x3
+#define AXP_CHIP_VERSION_MASK 0xcf
+#define AXP_CHIP_ID 0x41
+#define AXP_SHUTDOWN_REG 0x32
+#define AXP_SHUTDOWN_MASK BIT(7)
+
#elif defined(CONFIG_AXP313_POWER) /* AXP313 */
static const struct axp_reg_desc_spl axp_spl_dcdc_regulators[] = {
diff --git a/drivers/power/domain/ti-power-domain.c b/drivers/power/domain/ti-power-domain.c
index 5e7a4c5648d..c3519307340 100644
--- a/drivers/power/domain/ti-power-domain.c
+++ b/drivers/power/domain/ti-power-domain.c
@@ -94,6 +94,8 @@ static const struct soc_attr ti_k3_soc_pd_data[] = {
.family = "J721E",
.data = &j721e_pd_platdata,
},
+#endif
+#if IS_ENABLED(CONFIG_SOC_K3_J7200)
{
.family = "J7200",
.data = &j7200_pd_platdata,
@@ -116,6 +118,10 @@ static const struct soc_attr ti_k3_soc_pd_data[] = {
.family = "J784S4",
.data = &j784s4_pd_platdata,
},
+ {
+ .family = "J742S2",
+ .data = &j784s4_pd_platdata,
+ },
#endif
{ /* sentinel */ }
};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 958f337c7e7..8f102a92c23 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -478,3 +478,11 @@ config DM_REGULATOR_TPS65219
features for REGULATOR TPS65219 and the family of TPS65219 PMICs.
TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs.
The driver implements get/set api for value and enable.
+
+config REGULATOR_RZG2L_USBPHY
+ bool "Enable driver for RZ/G2L USB PHY VBUS supply"
+ depends on DM_REGULATOR
+ help
+ Enable this option to support controlling the VBUS supply in
+ the USB PHY peripheral of the Renesas RZ/G2L SoC. This option
+ is required in order to use the USB OTG port.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index ca6c89d13b5..4382d4b3ab9 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
obj-$(CONFIG_$(XPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS65219) += tps65219_regulator.o
+obj-$(CONFIG_REGULATOR_RZG2L_USBPHY) += rzg2l-usbphy-regulator.o
diff --git a/drivers/power/regulator/rzg2l-usbphy-regulator.c b/drivers/power/regulator/rzg2l-usbphy-regulator.c
new file mode 100644
index 00000000000..451f04c140e
--- /dev/null
+++ b/drivers/power/regulator/rzg2l-usbphy-regulator.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Renesas Electronics Corporation
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <power/regulator.h>
+#include <renesas/rzg2l-usbphy.h>
+
+#define VBENCTL 0x03c
+#define VBENCTL_VBUS_SEL BIT(0)
+
+static int rzg2l_usbphy_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev->parent);
+
+ if (enable)
+ clrbits_le32(priv->regs + VBENCTL, VBENCTL_VBUS_SEL);
+ else
+ setbits_le32(priv->regs + VBENCTL, VBENCTL_VBUS_SEL);
+
+ return 0;
+}
+
+static int rzg2l_usbphy_regulator_get_enable(struct udevice *dev)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev->parent);
+
+ return !!readl(priv->regs + VBENCTL) & VBENCTL_VBUS_SEL;
+}
+
+static const struct dm_regulator_ops rzg2l_usbphy_regulator_ops = {
+ .get_enable = rzg2l_usbphy_regulator_get_enable,
+ .set_enable = rzg2l_usbphy_regulator_set_enable,
+};
+
+U_BOOT_DRIVER(rzg2l_usbphy_regulator) = {
+ .name = "rzg2l_usbphy_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &rzg2l_usbphy_regulator_ops,
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6e79868d0ef..de312656746 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -105,6 +105,14 @@ config PWM_TEGRA
32KHz clock is supported by the driver but the duty cycle is
configurable.
+config PWM_STM32
+ bool "Enable support for STM32 PWM"
+ depends on DM_PWM && MFD_STM32_TIMERS
+ help
+ This enables PWM driver for STMicroelectronics STM32 pulse width
+ modulation. It uses STM32 timer devices that can have up to 4 output
+ channels, with complementary outputs and configurable polarity.
+
config PWM_SUNXI
bool "Enable support for the Allwinner Sunxi PWM"
depends on DM_PWM
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index e4d10c8dc3e..76305b93bc9 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -22,5 +22,6 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
+obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
obj-$(CONFIG_PWM_TI_EHRPWM) += pwm-ti-ehrpwm.o
diff --git a/drivers/pwm/pwm-mtk.c b/drivers/pwm/pwm-mtk.c
index 5cf2eba2ba0..898e353b370 100644
--- a/drivers/pwm/pwm-mtk.c
+++ b/drivers/pwm/pwm-mtk.c
@@ -30,6 +30,7 @@
enum mtk_pwm_reg_ver {
PWM_REG_V1,
PWM_REG_V2,
+ PWM_REG_V3,
};
static const unsigned int mtk_pwm_reg_offset_v1[] = {
@@ -40,6 +41,10 @@ static const unsigned int mtk_pwm_reg_offset_v2[] = {
0x0080, 0x00c0, 0x0100, 0x0140, 0x0180, 0x01c0, 0x0200, 0x0240
};
+static const unsigned int mtk_pwm_reg_offset_v3[] = {
+ 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x600, 0x700, 0x0800
+};
+
struct mtk_pwm_soc {
unsigned int num_pwms;
bool pwm45_fixup;
@@ -60,6 +65,10 @@ static void mtk_pwm_w32(struct udevice *dev, uint channel, uint reg, uint val)
u32 offset;
switch (priv->soc->reg_ver) {
+ case PWM_REG_V3:
+ offset = mtk_pwm_reg_offset_v3[channel];
+ break;
+
case PWM_REG_V2:
offset = mtk_pwm_reg_offset_v2[channel];
break;
@@ -203,6 +212,12 @@ static const struct mtk_pwm_soc mt7986_data = {
.reg_ver = PWM_REG_V1,
};
+static const struct mtk_pwm_soc mt7987_data = {
+ .num_pwms = 3,
+ .pwm45_fixup = false,
+ .reg_ver = PWM_REG_V3,
+};
+
static const struct mtk_pwm_soc mt7988_data = {
.num_pwms = 8,
.pwm45_fixup = false,
@@ -215,6 +230,7 @@ static const struct udevice_id mtk_pwm_ids[] = {
{ .compatible = "mediatek,mt7629-pwm", .data = (ulong)&mt7629_data },
{ .compatible = "mediatek,mt7981-pwm", .data = (ulong)&mt7981_data },
{ .compatible = "mediatek,mt7986-pwm", .data = (ulong)&mt7986_data },
+ { .compatible = "mediatek,mt7987-pwm", .data = (ulong)&mt7987_data },
{ .compatible = "mediatek,mt7988-pwm", .data = (ulong)&mt7988_data },
{ }
};
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 00000000000..5fa649b5903
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ * Author: Cheick Traore <cheick.traore@foss.st.com>
+ *
+ * Originally based on the Linux kernel v6.10 drivers/pwm/pwm-stm32.c.
+ */
+
+#include <div64.h>
+#include <dm.h>
+#include <pwm.h>
+#include <asm/io.h>
+#include <asm/arch/timers.h>
+#include <dm/device_compat.h>
+#include <linux/time.h>
+
+#define CCMR_CHANNEL_SHIFT 8
+#define CCMR_CHANNEL_MASK 0xFF
+
+struct stm32_pwm_priv {
+ bool have_complementary_output;
+ bool invert_polarity;
+};
+
+static u32 active_channels(struct stm32_timers_plat *plat)
+{
+ return readl(plat->base + TIM_CCER) & TIM_CCER_CCXE;
+}
+
+static int stm32_pwm_set_config(struct udevice *dev, uint channel,
+ uint period_ns, uint duty_ns)
+{
+ struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
+ struct stm32_timers_priv *priv = dev_get_priv(dev_get_parent(dev));
+ unsigned long long prd, div, dty;
+ unsigned int prescaler = 0;
+ u32 ccmr, mask, shift;
+
+ if (duty_ns > period_ns)
+ return -EINVAL;
+
+ /*
+ * Period and prescaler values depends on clock rate
+ * First we need to find the minimal value for prescaler such that
+ *
+ * period_ns * clkrate
+ * ------------------------------ < max_arr + 1
+ * NSEC_PER_SEC * (prescaler + 1)
+ *
+ * This equation is equivalent to
+ *
+ * period_ns * clkrate
+ * ---------------------------- < prescaler + 1
+ * NSEC_PER_SEC * (max_arr + 1)
+ *
+ * Using integer division and knowing that the right hand side is
+ * integer, this is further equivalent to
+ *
+ * (period_ns * clkrate) // (NSEC_PER_SEC * (max_arr + 1)) ≤ prescaler
+ */
+
+ div = (unsigned long long)priv->rate * period_ns;
+ do_div(div, NSEC_PER_SEC);
+ prd = div;
+
+ do_div(div, priv->max_arr + 1);
+ prescaler = div;
+ if (prescaler > MAX_TIM_PSC)
+ return -EINVAL;
+
+ do_div(prd, prescaler + 1);
+ if (!prd)
+ return -EINVAL;
+
+ /*
+ * All channels share the same prescaler and counter so when two
+ * channels are active at the same time we can't change them
+ */
+ if (active_channels(plat) & ~(1 << channel * 4)) {
+ u32 psc, arr;
+
+ psc = readl(plat->base + TIM_PSC);
+ arr = readl(plat->base + TIM_ARR);
+ if (psc != prescaler || arr != prd - 1)
+ return -EBUSY;
+ }
+
+ writel(prescaler, plat->base + TIM_PSC);
+ writel(prd - 1, plat->base + TIM_ARR);
+ setbits_le32(plat->base + TIM_CR1, TIM_CR1_ARPE);
+
+ /* Calculate the duty cycles */
+ dty = prd * duty_ns;
+ do_div(dty, period_ns);
+
+ writel(dty, plat->base + TIM_CCRx(channel + 1));
+
+ /* Configure output mode */
+ shift = (channel & 0x1) * CCMR_CHANNEL_SHIFT;
+ ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+ mask = CCMR_CHANNEL_MASK << shift;
+ if (channel < 2)
+ clrsetbits_le32(plat->base + TIM_CCMR1, mask, ccmr);
+ else
+ clrsetbits_le32(plat->base + TIM_CCMR2, mask, ccmr);
+
+ setbits_le32(plat->base + TIM_BDTR, TIM_BDTR_MOE);
+
+ return 0;
+}
+
+static int stm32_pwm_set_enable(struct udevice *dev, uint channel,
+ bool enable)
+{
+ struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
+ struct stm32_pwm_priv *priv = dev_get_priv(dev);
+ u32 mask;
+
+ /* Enable channel */
+ mask = TIM_CCER_CC1E << (channel * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NE << (channel * 4);
+
+ if (enable) {
+ setbits_le32(plat->base + TIM_CCER, mask);
+ /* Make sure that registers are updated */
+ setbits_le32(plat->base + TIM_EGR, TIM_EGR_UG);
+ /* Enable controller */
+ setbits_le32(plat->base + TIM_CR1, TIM_CR1_CEN);
+ } else {
+ clrbits_le32(plat->base + TIM_CCER, mask);
+ /* When all channels are disabled, we can disable the controller */
+ if (!active_channels(plat))
+ clrbits_le32(plat->base + TIM_CR1, TIM_CR1_CEN);
+ }
+
+ return 0;
+}
+
+static int stm32_pwm_set_invert(struct udevice *dev, uint channel,
+ bool polarity)
+{
+ struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
+ struct stm32_pwm_priv *priv = dev_get_priv(dev);
+ u32 mask;
+
+ mask = TIM_CCER_CC1P << (channel * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NP << (channel * 4);
+
+ clrsetbits_le32(plat->base + TIM_CCER, mask, polarity ? mask : 0);
+
+ return 0;
+}
+
+static void stm32_pwm_detect_complementary(struct udevice *dev)
+{
+ struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
+ struct stm32_pwm_priv *priv = dev_get_priv(dev);
+ u32 ccer;
+
+ /*
+ * If complementary bit doesn't exist writing 1 will have no
+ * effect so we can detect it.
+ */
+ setbits_le32(plat->base + TIM_CCER, TIM_CCER_CC1NE);
+ ccer = readl(plat->base + TIM_CCER);
+ clrbits_le32(plat->base + TIM_CCER, TIM_CCER_CC1NE);
+
+ priv->have_complementary_output = (ccer != 0);
+}
+
+static int stm32_pwm_probe(struct udevice *dev)
+{
+ struct stm32_timers_priv *timer = dev_get_priv(dev_get_parent(dev));
+
+ if (timer->rate > 1000000000) {
+ dev_err(dev, "Clock freq too high (%lu)\n", timer->rate);
+ return -EINVAL;
+ }
+
+ stm32_pwm_detect_complementary(dev);
+
+ return 0;
+}
+
+static const struct pwm_ops stm32_pwm_ops = {
+ .set_config = stm32_pwm_set_config,
+ .set_enable = stm32_pwm_set_enable,
+ .set_invert = stm32_pwm_set_invert,
+};
+
+static const struct udevice_id stm32_pwm_ids[] = {
+ { .compatible = "st,stm32-pwm" },
+ { }
+};
+
+U_BOOT_DRIVER(stm32_pwm) = {
+ .name = "stm32_pwm",
+ .id = UCLASS_PWM,
+ .of_match = stm32_pwm_ids,
+ .ops = &stm32_pwm_ops,
+ .probe = stm32_pwm_probe,
+ .priv_auto = sizeof(struct stm32_pwm_priv),
+};
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index 899d7585489..2a40b0c9f81 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -71,7 +71,7 @@ choice
depends on K3_DDRSS
prompt "K3 DDRSS Arch Support"
- default K3_J721E_DDRSS if SOC_K3_J721E || SOC_K3_J721S2 || SOC_K3_J784S4
+ default K3_J721E_DDRSS if SOC_K3_J721E || SOC_K3_J7200 || SOC_K3_J721S2 || SOC_K3_J784S4
default K3_AM64_DDRSS if SOC_K3_AM642
default K3_AM64_DDRSS if SOC_K3_AM625
default K3_AM62A_DDRSS if SOC_K3_AM62A7 || SOC_K3_AM62P5 || SOC_K3_J722S
diff --git a/drivers/ram/renesas/dbsc5/dram.c b/drivers/ram/renesas/dbsc5/dram.c
index 6f78afb0ab5..ca8a7fb4783 100644
--- a/drivers/ram/renesas/dbsc5/dram.c
+++ b/drivers/ram/renesas/dbsc5/dram.c
@@ -1325,6 +1325,11 @@ static const u32 PI_DARRAY3_1_CSx_Fx[CS_CNT][3] = {
#define DBSC_DBACEN 0x200
#define DBSC_DBRFEN 0x204
#define DBSC_DBCMD 0x208
+#define DBSC_DBCMD_CMD_OPCODE_PD 0x8
+#define DBSC_DBCMD_CMD_OPCODE_MRW 0xe
+#define DBSC_DBCMD_CMD_OPCODE_MRR 0xf
+#define DBSC_DBCMD_CMD_CHANNEL_ALL 0x8
+#define DBSC_DBCMD_CMD_RANK_ALL 0x4
#define DBSC_DBWAIT 0x210
#define DBSC_DBBL 0x400
#define DBSC_DBBLA 0x400
@@ -1736,24 +1741,20 @@ static void dbsc5_reg_write(void __iomem *addr, u32 data)
}
/**
- * dbsc5_reg_write() - DRAM Command Write Access
+ * dbsc5_wait_dbwait() - DRAM Command Wait Access Completion
* @dev: DBSC5 device
- * @cmd DRAM command.
*
- * First, execute the dummy read to DBSC_DBCMD.
- * Confirm that no DBSC command operation is in progress 0.
- * Write the contents of the command to be sent to DRAM.
+ * Wait for DRAM access completion. This is used before sending a command
+ * to the DRAM to assure no other command is in flight already, or while
+ * waiting for MRR command to complete.
*/
-static void dbsc5_send_dbcmd2(struct udevice *dev, u32 cmd)
+static void dbsc5_wait_dbwait(struct udevice *dev)
{
struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev);
void __iomem *regs_dbsc_d = priv->regs + DBSC5_DBSC_D_OFFSET;
u32 val;
int ret;
- /* dummy read */
- readl(regs_dbsc_d + DBSC_DBCMD);
-
ret = readl_poll_timeout(regs_dbsc_d + DBSC_DBWAIT, val, ((val & BIT(0)) == 0), 1000000);
if (ret < 0) {
printf("%s DBWAIT bit 0 timeout\n", __func__);
@@ -1765,6 +1766,32 @@ static void dbsc5_send_dbcmd2(struct udevice *dev, u32 cmd)
printf("%s DBWAIT + 0x4000 bit 0 timeout\n", __func__);
hang();
}
+}
+
+/**
+ * dbsc5_send_dbcmd2() - DRAM Command Write Access
+ * @dev: DBSC5 device
+ * @opcode DRAM controller opcode
+ * @channel DRAM controller channel (0..3)
+ * @rank DRAM controller rank (0..1)
+ * @arg Command and argument bits (command specific encoding)
+ *
+ * First, execute the dummy read to DBSC_DBCMD.
+ * Confirm that no DBSC command operation is in progress 0.
+ * Write the contents of the command to be sent to DRAM.
+ */
+static void dbsc5_send_dbcmd2(struct udevice *dev, const u8 opcode,
+ const u8 channel, const u8 rank,
+ const u16 arg)
+{
+ const u32 cmd = (opcode << 24) | (channel << 20) | (rank << 16) | arg;
+ struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev);
+ void __iomem *regs_dbsc_d = priv->regs + DBSC5_DBSC_D_OFFSET;
+
+ /* dummy read */
+ readl(regs_dbsc_d + DBSC_DBCMD);
+
+ dbsc5_wait_dbwait(dev);
dbsc5_reg_write(regs_dbsc_d + DBSC_DBCMD, cmd);
}
@@ -2950,10 +2977,14 @@ static u32 dbsc5_pi_training(struct udevice *dev)
writel(0x21, regs_dbsc_d + DBSC_DBDFICNT(ch));
/* Dummy PDE */
- dbsc5_send_dbcmd2(dev, 0x8840000);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_PD,
+ DBSC_DBCMD_CMD_CHANNEL_ALL,
+ DBSC_DBCMD_CMD_RANK_ALL, 0);
/* PDX */
- dbsc5_send_dbcmd2(dev, 0x8840001);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_PD,
+ DBSC_DBCMD_CMD_CHANNEL_ALL,
+ DBSC_DBCMD_CMD_RANK_ALL, 1);
/* Wait init_complete */
for (retry = 0; retry < retry_max; retry++) {
@@ -4085,25 +4116,27 @@ static u32 dbsc5_read_training(struct udevice *dev)
}
/**
- * dbsc5_ddr_register_set() - DDR mode register setting
+ * dbsc5_ddr_register_mr28_set() - DDR mode register MR28 set
* @dev: DBSC5 device
*
* Set the mode register 28 of the SDRAM.
* ZQ Mode: Command-Based ZQ Calibration
* ZQ interval: Background Cal Interval < 64ms
*/
-static void dbsc5_ddr_register_set(struct udevice *dev)
+static void dbsc5_ddr_register_mr28_set(struct udevice *dev)
{
- dbsc5_send_dbcmd2(dev, 0xE841C24);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_MRW,
+ DBSC_DBCMD_CMD_CHANNEL_ALL,
+ DBSC_DBCMD_CMD_RANK_ALL, (28 << 8) | 0x24);
}
/**
- * dbsc5_ddr_register_read() - DDR mode register read
+ * dbsc5_ddr_register_mr27_mr57_read() - DDR mode register MR27/MR57 read
* @dev: DBSC5 device
*
* Set the mode register 27 and 57 of the SDRAM.
*/
-static void dbsc5_ddr_register_read(struct udevice *dev)
+static void dbsc5_ddr_register_mr27_mr57_read(struct udevice *dev)
{
struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev);
@@ -4111,17 +4144,21 @@ static void dbsc5_ddr_register_read(struct udevice *dev)
return;
/* MR27 rank0 */
- dbsc5_send_dbcmd2(dev, 0xF801B00);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_MRR,
+ DBSC_DBCMD_CMD_CHANNEL_ALL, 0, 27 << 8);
/* MR57 rank0 */
- dbsc5_send_dbcmd2(dev, 0xF803900);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_MRR,
+ DBSC_DBCMD_CMD_CHANNEL_ALL, 0, 57 << 8);
if (!priv->ch_have_this_cs[1])
return;
/* MR27 rank1 */
- dbsc5_send_dbcmd2(dev, 0xF811B00);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_MRR,
+ DBSC_DBCMD_CMD_CHANNEL_ALL, 1, 27 << 8);
/* MR57 rank1 */
- dbsc5_send_dbcmd2(dev, 0xF813900);
+ dbsc5_send_dbcmd2(dev, DBSC_DBCMD_CMD_OPCODE_MRR,
+ DBSC_DBCMD_CMD_CHANNEL_ALL, 1, 57 << 8);
}
/**
@@ -4200,8 +4237,8 @@ static u32 dbsc5_init_ddr(struct udevice *dev)
dbsc5_dbsc_regset(dev);
/* Frequency selection change (F1->F2) */
- dbsc5_ddr_setval_all_ch(dev, PHY_FREQ_SEL_INDEX, 0x1);
- dbsc5_ddr_setval_all_ch(dev, PHY_FREQ_SEL_MULTICAST_EN, 0x0);
+ dbsc5_ddr_setval_all_ch(dev, PHY_FREQ_SEL_INDEX, 0x1);
+ dbsc5_ddr_setval_all_ch(dev, PHY_FREQ_SEL_MULTICAST_EN, 0x0);
/* dfi_init_start (start ddrphy) & execute pi_training */
phytrainingok = dbsc5_pi_training(dev);
@@ -4278,10 +4315,10 @@ static u32 dbsc5_init_ddr(struct udevice *dev)
/* setup DDR mode registers */
/* MRS */
- dbsc5_ddr_register_set(dev);
+ dbsc5_ddr_register_mr28_set(dev);
/* MRR */
- dbsc5_ddr_register_read(dev);
+ dbsc5_ddr_register_mr27_mr57_read(dev);
/* training complete, setup DBSC */
dbsc5_dbsc_regset_post(dev);
@@ -4296,10 +4333,13 @@ static u32 dbsc5_init_ddr(struct udevice *dev)
/**
* dbsc5_get_board_data() - Obtain board specific DRAM configuration
+ * @dev: DBSC5 device
+ * @modemr0: MODEMR0 register content
*
* Return board specific DRAM configuration structure pointer.
*/
-__weak const struct renesas_dbsc5_board_config *dbsc5_get_board_data(void)
+__weak const struct renesas_dbsc5_board_config *
+dbsc5_get_board_data(struct udevice *dev, const u32 modemr0)
{
return &renesas_v4h_dbsc5_board_config;
}
@@ -4335,7 +4375,7 @@ static int renesas_dbsc5_dram_probe(struct udevice *dev)
u32 ch, cs;
/* Get board data */
- priv->dbsc5_board_config = dbsc5_get_board_data();
+ priv->dbsc5_board_config = dbsc5_get_board_data(dev, modemr0);
priv->ddr_phyvalid = (u32)(priv->dbsc5_board_config->bdcfg_phyvalid);
priv->max_density = 0;
priv->cpg_regs = (void __iomem *)ofnode_get_addr(cnode);
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 2790b168b19..a3ecea05e20 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -13,6 +13,7 @@ config REMOTEPROC
depends on DM
# Please keep the configuration alphabetically sorted.
+
config K3_SYSTEM_CONTROLLER
bool "Support for TI' K3 System Controller"
select REMOTEPROC
@@ -22,6 +23,16 @@ config K3_SYSTEM_CONTROLLER
help
Say 'y' here to add support for TI' K3 System Controller.
+config REMOTEPROC_ADI_SC5XX
+ bool "Support for ADI SC5xx SHARC cores"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_SC5XX
+ depends on SYSCON
+ help
+ Say 'y' here to add support for loading code onto SHARC cores in
+ an ADSP-SC5xx SoC from Analog Devices
+
config REMOTEPROC_RENESAS_APMU
bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor"
select REMOTEPROC
@@ -55,6 +66,7 @@ config REMOTEPROC_TI_K3_ARM64
depends on DM
depends on ARCH_K3
depends on OF_CONTROL
+ default y if SYS_K3_SPL_ATF
help
Say y here to support TI's ARM64 processor subsystems
on various TI K3 family of SoCs through the remote processor
@@ -70,6 +82,16 @@ config REMOTEPROC_TI_K3_DSP
on various TI K3 family of SoCs through the remote processor
framework.
+config REMOTEPROC_TI_K3_M4F
+ bool "TI K3 M4F remoteproc support"
+ select REMOTEPROC
+ depends on ARCH_K3
+ depends on TI_SCI_PROTOCOL
+ help
+ Say y here to support TI's M4F remote processor subsystems
+ on various TI K3 family of SoCs through the remote processor
+ framework.
+
config REMOTEPROC_TI_K3_R5F
bool "TI K3 R5F remoteproc support"
select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 3a092b7660e..bd94ea771be 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,11 +8,13 @@ obj-$(CONFIG_$(XPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
+obj-$(CONFIG_REMOTEPROC_ADI_SC5XX) += adi_sc5xx_rproc.o
obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o
+obj-$(CONFIG_REMOTEPROC_TI_K3_M4F) += ti_k3_m4_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
obj-$(CONFIG_REMOTEPROC_TI_PRU) += pru_rproc.o
diff --git a/drivers/remoteproc/adi_sc5xx_rproc.c b/drivers/remoteproc/adi_sc5xx_rproc.c
new file mode 100644
index 00000000000..86acd1b98c7
--- /dev/null
+++ b/drivers/remoteproc/adi_sc5xx_rproc.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * Analog Devices SC5xx remoteproc driver for loading code onto SHARC cores
+ */
+
+#include <dm.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <syscon.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+/* Register offsets */
+#ifdef CONFIG_SC58X
+#define ADI_RCU_REG_CTL 0x00
+#define ADI_RCU_REG_STAT 0x04
+#define ADI_RCU_REG_CRCTL 0x08
+#define ADI_RCU_REG_CRSTAT 0x0c
+#define ADI_RCU_REG_SIDIS 0x10
+#define ADI_RCU_REG_SISTAT 0x14
+#define ADI_RCU_REG_BCODE 0x1c
+#define ADI_RCU_REG_SVECT0 0x20
+#define ADI_RCU_REG_SVECT1 0x24
+#define ADI_RCU_REG_SVECT2 0x28
+#define ADI_RCU_REG_MSG 0x60
+#define ADI_RCU_REG_MSG_SET 0x64
+#define ADI_RCU_REG_MSG_CLR 0x68
+#else
+#define ADI_RCU_REG_CTL 0x00
+#define ADI_RCU_REG_STAT 0x04
+#define ADI_RCU_REG_CRCTL 0x08
+#define ADI_RCU_REG_CRSTAT 0x0c
+#define ADI_RCU_REG_SRRQSTAT 0x18
+#define ADI_RCU_REG_SIDIS 0x1c
+#define ADI_RCU_REG_SISTAT 0x20
+#define ADI_RCU_REG_SVECT_LCK 0x24
+#define ADI_RCU_REG_BCODE 0x28
+#define ADI_RCU_REG_SVECT0 0x2c
+#define ADI_RCU_REG_SVECT1 0x30
+#define ADI_RCU_REG_SVECT2 0x34
+#define ADI_RCU_REG_MSG 0x6c
+#define ADI_RCU_REG_MSG_SET 0x70
+#define ADI_RCU_REG_MSG_CLR 0x74
+#endif /* CONFIG_SC58X */
+
+/* Register bit definitions */
+#define ADI_RCU_CTL_SYSRST BIT(0)
+
+/* Bit values for the RCU0_MSG register */
+#define RCU0_MSG_C0IDLE 0x00000100 /* Core 0 Idle */
+#define RCU0_MSG_C1IDLE 0x00000200 /* Core 1 Idle */
+#define RCU0_MSG_C2IDLE 0x00000400 /* Core 2 Idle */
+#define RCU0_MSG_CRR0 0x00001000 /* Core 0 reset request */
+#define RCU0_MSG_CRR1 0x00002000 /* Core 1 reset request */
+#define RCU0_MSG_CRR2 0x00004000 /* Core 2 reset request */
+#define RCU0_MSG_C1ACTIVATE 0x00080000 /* Core 1 Activated */
+#define RCU0_MSG_C2ACTIVATE 0x00100000 /* Core 2 Activated */
+
+struct sc5xx_rproc_data {
+ /* Address to load to svect when rebooting core */
+ u32 load_addr;
+
+ /* RCU parameters */
+ struct regmap *rcu;
+ u32 svect_offset;
+ u32 coreid;
+};
+
+struct block_code_flag {
+ u32 bcode:4, /* 0-3 */
+ bflag_save:1, /* 4 */
+ bflag_aux:1, /* 5 */
+ breserved:1, /* 6 */
+ bflag_forward:1, /* 7 */
+ bflag_fill:1, /* 8 */
+ bflag_quickboot:1, /* 9 */
+ bflag_callback:1, /* 10 */
+ bflag_init:1, /* 11 */
+ bflag_ignore:1, /* 12 */
+ bflag_indirect:1, /* 13 */
+ bflag_first:1, /* 14 */
+ bflag_final:1, /* 15 */
+ bhdrchk:8, /* 16-23 */
+ bhdrsign:8; /* 0xAD, 0xAC or 0xAB */
+};
+
+struct ldr_hdr {
+ struct block_code_flag bcode_flag;
+ u32 target_addr;
+ u32 byte_count;
+ u32 argument;
+};
+
+static int is_final(struct ldr_hdr *hdr)
+{
+ return hdr->bcode_flag.bflag_final;
+}
+
+static int is_empty(struct ldr_hdr *hdr)
+{
+ return hdr->bcode_flag.bflag_ignore || (hdr->byte_count == 0);
+}
+
+static int adi_valid_firmware(struct ldr_hdr *adi_ldr_hdr)
+{
+ if (!adi_ldr_hdr->byte_count &&
+ (adi_ldr_hdr->bcode_flag.bhdrsign == 0xAD ||
+ adi_ldr_hdr->bcode_flag.bhdrsign == 0xAC ||
+ adi_ldr_hdr->bcode_flag.bhdrsign == 0xAB))
+ return 1;
+
+ return 0;
+}
+
+static int sharc_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct sc5xx_rproc_data *priv = dev_get_priv(dev);
+ size_t offset;
+ u8 *buf = (u8 *)addr;
+ struct ldr_hdr *ldr = (struct ldr_hdr *)addr;
+ struct ldr_hdr *block_hdr;
+ struct ldr_hdr *next_hdr;
+
+ if (!adi_valid_firmware(ldr)) {
+ dev_err(dev, "Firmware at 0x%lx does not appear to be an LDR image\n", addr);
+ dev_err(dev, "Note: Signed firmware is not currently supported\n");
+ return -EINVAL;
+ }
+
+ do {
+ block_hdr = (struct ldr_hdr *)buf;
+ offset = sizeof(struct ldr_hdr) + (block_hdr->bcode_flag.bflag_fill ?
+ 0 : block_hdr->byte_count);
+ next_hdr = (struct ldr_hdr *)(buf + offset);
+
+ if (block_hdr->bcode_flag.bflag_first)
+ priv->load_addr = (unsigned long)block_hdr->target_addr;
+
+ if (!is_empty(block_hdr)) {
+ if (block_hdr->bcode_flag.bflag_fill) {
+ memset_io((void *)(phys_addr_t)block_hdr->target_addr,
+ block_hdr->argument,
+ block_hdr->byte_count);
+ } else {
+ memcpy_toio((void *)(phys_addr_t)block_hdr->target_addr,
+ buf + sizeof(struct ldr_hdr),
+ block_hdr->byte_count);
+ }
+ }
+
+ if (is_final(block_hdr))
+ break;
+
+ buf += offset;
+ } while (1);
+
+ return 0;
+}
+
+static void sharc_reset(struct sc5xx_rproc_data *priv)
+{
+ u32 coreid = priv->coreid;
+ u32 val;
+
+ /* First put core in reset.
+ * Clear CRSTAT bit for given coreid.
+ */
+ regmap_write(priv->rcu, ADI_RCU_REG_CRSTAT, 1 << coreid);
+
+ /* Set SIDIS to disable the system interface */
+ regmap_read(priv->rcu, ADI_RCU_REG_SIDIS, &val);
+ regmap_write(priv->rcu, ADI_RCU_REG_SIDIS, val | (1 << (coreid - 1)));
+
+ /*
+ * Wait for access to coreX have been disabled and all the pending
+ * transactions have completed
+ */
+ udelay(50);
+
+ /* Set CRCTL bit to put core in reset */
+ regmap_read(priv->rcu, ADI_RCU_REG_CRCTL, &val);
+ regmap_write(priv->rcu, ADI_RCU_REG_CRCTL, val | (1 << coreid));
+
+ /* Poll until Core is in reset */
+ while (!(regmap_read(priv->rcu, ADI_RCU_REG_CRSTAT, &val), val & (1 << coreid)))
+ ;
+
+ /* Clear SIDIS to reenable the system interface */
+ regmap_read(priv->rcu, ADI_RCU_REG_SIDIS, &val);
+ regmap_write(priv->rcu, ADI_RCU_REG_SIDIS, val & ~(1 << (coreid - 1)));
+
+ udelay(50);
+
+ /* Take Core out of reset */
+ regmap_read(priv->rcu, ADI_RCU_REG_CRCTL, &val);
+ regmap_write(priv->rcu, ADI_RCU_REG_CRCTL, val & ~(1 << coreid));
+
+ /* Wait for done */
+ udelay(50);
+}
+
+static int sharc_start(struct udevice *dev)
+{
+ struct sc5xx_rproc_data *priv = dev_get_priv(dev);
+
+ /* Write load address to appropriate SVECT for core */
+ regmap_write(priv->rcu, priv->svect_offset, priv->load_addr);
+
+ sharc_reset(priv);
+
+ /* Clear the IDLE bit when start the SHARC core */
+ regmap_write(priv->rcu, ADI_RCU_REG_MSG_CLR, RCU0_MSG_C0IDLE << priv->coreid);
+
+ /* Notify CCES */
+ regmap_write(priv->rcu, ADI_RCU_REG_MSG_SET, RCU0_MSG_C1ACTIVATE << (priv->coreid - 1));
+ return 0;
+}
+
+static const struct dm_rproc_ops sc5xx_ops = {
+ .load = sharc_load,
+ .start = sharc_start,
+};
+
+static int sc5xx_probe(struct udevice *dev)
+{
+ struct sc5xx_rproc_data *priv = dev_get_priv(dev);
+ u32 coreid;
+
+ if (dev_read_u32(dev, "coreid", &coreid)) {
+ dev_err(dev, "Missing property coreid\n");
+ return -ENOENT;
+ }
+
+ priv->coreid = coreid;
+ switch (coreid) {
+ case 1:
+ priv->svect_offset = ADI_RCU_REG_SVECT1;
+ break;
+ case 2:
+ priv->svect_offset = ADI_RCU_REG_SVECT2;
+ break;
+ default:
+ dev_err(dev, "Invalid value %d for coreid, must be 1 or 2\n", coreid);
+ return -EINVAL;
+ }
+
+ priv->rcu = syscon_regmap_lookup_by_phandle(dev, "adi,rcu");
+ if (IS_ERR(priv->rcu))
+ return PTR_ERR(priv->rcu);
+
+ dev_err(dev, "sc5xx remoteproc core %d available\n", priv->coreid);
+
+ return 0;
+}
+
+static const struct udevice_id sc5xx_ids[] = {
+ { .compatible = "adi,sc5xx-rproc" },
+ { }
+};
+
+U_BOOT_DRIVER(adi_sc5xx_rproc) = {
+ .name = "adi_sc5xx_rproc",
+ .of_match = sc5xx_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &sc5xx_ops,
+ .probe = sc5xx_probe,
+ .priv_auto = sizeof(struct sc5xx_rproc_data),
+ .flags = 0,
+};
diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index e90f75a188c..5a7d6377283 100644
--- a/drivers/remoteproc/ti_k3_dsp_rproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -15,6 +15,7 @@
#include <clk.h>
#include <reset.h>
#include <asm/io.h>
+#include <asm/system.h>
#include <power-domain.h>
#include <dm/device_compat.h>
#include <linux/err.h>
@@ -56,7 +57,9 @@ struct k3_dsp_boot_data {
* @data: Pointer to DSP specific boot data structure
* @mem: Array of available memories
* @num_mem: Number of available memories
- * @in_use: flag to tell if the core is already in use.
+ * @cached_addr: Cached memory address
+ * @cached_size: Cached memory size
+ * @in_use: flag to tell if the core is already in use.
*/
struct k3_dsp_privdata {
struct reset_ctl dsp_rst;
@@ -64,6 +67,8 @@ struct k3_dsp_privdata {
struct k3_dsp_boot_data *data;
struct k3_dsp_mem *mem;
int num_mems;
+ void __iomem *cached_addr;
+ size_t cached_size;
bool in_use;
};
@@ -158,6 +163,13 @@ static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
goto unprepare;
}
+ if (dsp->cached_addr && IS_ENABLED(CONFIG_SYS_DISABLE_DCACHE_OPS)) {
+ dev_dbg(dev, "final flush 0x%lx to 0x%lx\n",
+ (ulong)dsp->cached_addr, dsp->cached_size);
+ __asm_invalidate_dcache_range((u64)dsp->cached_addr,
+ (u64)dsp->cached_addr + (u64)dsp->cached_size);
+ }
+
boot_vector = rproc_elf_get_boot_addr(dev, addr);
if (boot_vector & (data->boot_align_addr - 1)) {
ret = -EINVAL;
@@ -253,7 +265,6 @@ static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
phys_addr_t bus_addr, dev_addr;
- void __iomem *va = NULL;
size_t size;
u32 offset;
int i;
@@ -263,6 +274,16 @@ static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
if (len <= 0)
return NULL;
+ if (dsp->cached_addr && IS_ENABLED(CONFIG_SYS_DISABLE_DCACHE_OPS)) {
+ dev_dbg(dev, "flush 0x%lx to 0x%lx\n", (ulong)dsp->cached_addr,
+ dsp->cached_size);
+ __asm_invalidate_dcache_range((u64)dsp->cached_addr,
+ (u64)dsp->cached_addr + (u64)dsp->cached_size);
+ }
+
+ dsp->cached_size = len;
+ dsp->cached_addr = NULL;
+
for (i = 0; i < dsp->num_mems; i++) {
bus_addr = dsp->mem[i].bus_addr;
dev_addr = dsp->mem[i].dev_addr;
@@ -270,19 +291,20 @@ static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
if (da >= dev_addr && ((da + len) <= (dev_addr + size))) {
offset = da - dev_addr;
- va = dsp->mem[i].cpu_addr + offset;
- return (__force void *)va;
+ dsp->cached_addr = dsp->mem[i].cpu_addr + offset;
}
if (da >= bus_addr && (da + len) <= (bus_addr + size)) {
offset = da - bus_addr;
- va = dsp->mem[i].cpu_addr + offset;
- return (__force void *)va;
+ dsp->cached_addr = dsp->mem[i].cpu_addr + offset;
}
}
/* Assume it is DDR region and return da */
- return map_physmem(da, len, MAP_NOCACHE);
+ if (!dsp->cached_addr)
+ dsp->cached_addr = map_physmem(da, len, MAP_NOCACHE);
+
+ return dsp->cached_addr;
}
static const struct dm_rproc_ops k3_dsp_ops = {
diff --git a/drivers/remoteproc/ti_k3_m4_rproc.c b/drivers/remoteproc/ti_k3_m4_rproc.c
new file mode 100644
index 00000000000..31b9de71579
--- /dev/null
+++ b/drivers/remoteproc/ti_k3_m4_rproc.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 M4 Remoteproc driver
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
+ * Hari Nagalla <hnagalla@ti.com>
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <remoteproc.h>
+#include <errno.h>
+#include <clk.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <power-domain.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/sizes.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include "ti_sci_proc.h"
+#include <mach/security.h>
+
+/**
+ * struct k3_m4_mem - internal memory structure
+ * @cpu_addr: MPU virtual address of the memory region
+ * @bus_addr: Bus address used to access the memory region
+ * @dev_addr: Device address from remoteproc view
+ * @size: Size of the memory region
+ */
+struct k3_m4_mem {
+ void __iomem *cpu_addr;
+ phys_addr_t bus_addr;
+ phys_addr_t dev_addr;
+ size_t size;
+};
+
+/**
+ * struct k3_m4_mem_data - memory definitions for m4 remote core
+ * @name: name for this memory entry
+ * @dev_addr: device address for the memory entry
+ */
+struct k3_m4_mem_data {
+ const char *name;
+ const u32 dev_addr;
+};
+
+/**
+ * struct k3_m4_boot_data - internal data structure used for boot
+ * @boot_align_addr: Boot vector address alignment granularity
+ */
+struct k3_m4_boot_data {
+ u32 boot_align_addr;
+};
+
+/**
+ * struct k3_m4_privdata - Structure representing Remote processor data.
+ * @m4_rst: m4 rproc reset control data
+ * @tsp: Pointer to TISCI proc contrl handle
+ * @data: Pointer to DSP specific boot data structure
+ * @mem: Array of available memories
+ * @num_mem: Number of available memories
+ */
+struct k3_m4_privdata {
+ struct reset_ctl m4_rst;
+ struct ti_sci_proc tsp;
+ struct k3_m4_boot_data *data;
+ struct k3_m4_mem *mem;
+ int num_mems;
+};
+
+/*
+ * The M4 cores have a local reset that affects only the CPU, and a
+ * generic module reset that powers on the device and allows the M4 internal
+ * memories to be accessed while the local reset is asserted. This function is
+ * used to release the global reset on M4F to allow loading into the M4F
+ * internal RAMs. This helper function is invoked in k3_m4_load() before any
+ * actual firmware loading happens and is undone only in k3_m4_stop(). The local
+ * reset cannot be released on M4 cores until after the firmware images are loaded.
+ */
+static int k3_m4_prepare(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+ int ret;
+
+ ret = ti_sci_proc_power_domain_on(&m4->tsp);
+ if (ret)
+ dev_err(dev, "cannot enable internal RAM loading, ret = %d\n",
+ ret);
+
+ return ret;
+}
+
+/*
+ * This function is the counterpart to k3_m4_prepare() and is used to assert
+ * the global reset on M4 cores. This completes the second step of powering
+ * down the M4 cores. The cores themselves are halted through the local reset
+ * in first step. This function is invoked in k3_m4_stop() after the local
+ * reset is asserted.
+ */
+static int k3_m4_unprepare(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+
+ return ti_sci_proc_power_domain_off(&m4->tsp);
+}
+
+/**
+ * k3_m4_load() - Load up the Remote processor image
+ * @dev: rproc device pointer
+ * @addr: Address at which image is available
+ * @size: size of the image
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_m4_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+ void *image_addr = (void *)addr;
+ int ret;
+
+ ret = ti_sci_proc_request(&m4->tsp);
+ if (ret)
+ return ret;
+
+ ret = k3_m4_prepare(dev);
+ if (ret) {
+ dev_err(dev, "Prepare failed for core %d\n",
+ m4->tsp.proc_id);
+ goto proc_release;
+ }
+
+ ti_secure_image_post_process(&image_addr, &size);
+
+ ret = rproc_elf_load_image(dev, addr, size);
+ if (ret < 0) {
+ dev_err(dev, "Loading elf failed %d\n", ret);
+ goto unprepare;
+ }
+
+unprepare:
+ if (ret)
+ k3_m4_unprepare(dev);
+proc_release:
+ ti_sci_proc_release(&m4->tsp);
+ return ret;
+}
+
+/**
+ * k3_m4_start() - Start the remote processor
+ * @dev: rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_m4_start(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+ int ret;
+
+ ret = ti_sci_proc_request(&m4->tsp);
+ if (ret)
+ return ret;
+
+ ret = reset_deassert(&m4->m4_rst);
+
+ ti_sci_proc_release(&m4->tsp);
+
+ return ret;
+}
+
+static int k3_m4_stop(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+
+ ti_sci_proc_request(&m4->tsp);
+ reset_assert(&m4->m4_rst);
+ k3_m4_unprepare(dev);
+ ti_sci_proc_release(&m4->tsp);
+
+ return 0;
+}
+
+static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+ phys_addr_t bus_addr, dev_addr;
+ void __iomem *va = NULL;
+ size_t size;
+ u32 offset;
+ int i;
+
+ if (len <= 0)
+ return NULL;
+
+ for (i = 0; i < m4->num_mems; i++) {
+ bus_addr = m4->mem[i].bus_addr;
+ dev_addr = m4->mem[i].dev_addr;
+ size = m4->mem[i].size;
+
+ if (da >= dev_addr && ((da + len) <= (dev_addr + size))) {
+ offset = da - dev_addr;
+ va = m4->mem[i].cpu_addr + offset;
+ return (__force void *)va;
+ }
+
+ if (da >= bus_addr && (da + len) <= (bus_addr + size)) {
+ offset = da - bus_addr;
+ va = m4->mem[i].cpu_addr + offset;
+ return (__force void *)va;
+ }
+ }
+
+ /* Assume it is DDR region and return da */
+ return map_physmem(da, len, MAP_NOCACHE);
+}
+
+static const struct dm_rproc_ops k3_m4_ops = {
+ .load = k3_m4_load,
+ .start = k3_m4_start,
+ .stop = k3_m4_stop,
+ .device_to_virt = k3_m4_da_to_va,
+};
+
+static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
+{
+ u32 ids[2];
+ int ret;
+
+ tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(tsp->sci)) {
+ dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
+ return PTR_ERR(tsp->sci);
+ }
+
+ ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2);
+ if (ret) {
+ dev_err(dev, "Proc IDs not populated %d\n", ret);
+ return ret;
+ }
+
+ tsp->ops = &tsp->sci->ops.proc_ops;
+ tsp->proc_id = ids[0];
+ tsp->host_id = ids[1];
+ tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id",
+ TI_SCI_RESOURCE_NULL);
+ if (tsp->dev_id == TI_SCI_RESOURCE_NULL) {
+ dev_err(dev, "Device ID not populated %d\n", ret);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct k3_m4_mem_data am6_m4_mems[] = {
+ { .name = "iram", .dev_addr = 0x0 },
+ { .name = "dram", .dev_addr = 0x30000 },
+};
+
+static int k3_m4_of_get_memories(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+ int i;
+
+ m4->num_mems = ARRAY_SIZE(am6_m4_mems);
+ m4->mem = calloc(m4->num_mems, sizeof(*m4->mem));
+ if (!m4->mem)
+ return -ENOMEM;
+
+ for (i = 0; i < m4->num_mems; i++) {
+ m4->mem[i].bus_addr = dev_read_addr_size_name(dev,
+ am6_m4_mems[i].name,
+ (fdt_addr_t *)&m4->mem[i].size);
+ if (m4->mem[i].bus_addr == FDT_ADDR_T_NONE) {
+ dev_err(dev, "%s bus address not found\n",
+ am6_m4_mems[i].name);
+ return -EINVAL;
+ }
+ m4->mem[i].cpu_addr = map_physmem(m4->mem[i].bus_addr,
+ m4->mem[i].size,
+ MAP_NOCACHE);
+ m4->mem[i].dev_addr = am6_m4_mems[i].dev_addr;
+ }
+
+ return 0;
+}
+
+/**
+ * k3_of_to_priv() - generate private data from device tree
+ * @dev: corresponding k3 m4 processor device
+ * @m4: pointer to driver specific private data
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_m4_of_to_priv(struct udevice *dev, struct k3_m4_privdata *m4)
+{
+ int ret;
+
+ ret = reset_get_by_index(dev, 0, &m4->m4_rst);
+ if (ret) {
+ dev_err(dev, "reset_get() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = ti_sci_proc_of_to_priv(dev, &m4->tsp);
+ if (ret)
+ return ret;
+
+ ret = k3_m4_of_get_memories(dev);
+ if (ret)
+ return ret;
+
+ m4->data = (struct k3_m4_boot_data *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+/**
+ * k3_m4_probe() - Basic probe
+ * @dev: corresponding k3 remote processor device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_m4_probe(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4;
+ int ret;
+
+ m4 = dev_get_priv(dev);
+ ret = k3_m4_of_to_priv(dev, m4);
+ if (ret)
+ return ret;
+
+ /*
+ * The M4 local resets are deasserted by default on Power-On-Reset.
+ * Assert the local resets to ensure the M4s don't execute bogus code
+ * in .load() callback when the module reset is released to support
+ * internal memory loading. This is needed for M4 cores.
+ */
+ reset_assert(&m4->m4_rst);
+
+ return 0;
+}
+
+static int k3_m4_remove(struct udevice *dev)
+{
+ struct k3_m4_privdata *m4 = dev_get_priv(dev);
+
+ free(m4->mem);
+
+ return 0;
+}
+
+static const struct k3_m4_boot_data m4_data = {
+ .boot_align_addr = SZ_1K,
+};
+
+static const struct udevice_id k3_m4_ids[] = {
+ { .compatible = "ti,am64-m4fss", .data = (ulong)&m4_data, },
+ {}
+};
+
+U_BOOT_DRIVER(k3_m4) = {
+ .name = "k3_m4",
+ .of_match = k3_m4_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &k3_m4_ops,
+ .probe = k3_m4_probe,
+ .remove = k3_m4_remove,
+ .priv_auto = sizeof(struct k3_m4_privdata),
+};
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index d78b3fa1bbd..57268e7f8ff 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -886,6 +886,7 @@ static const struct udevice_id k3_r5f_rproc_ids[] = {
{ .compatible = "ti,j7200-r5f", .data = (ulong)&j7200_j721s2_data, },
{ .compatible = "ti,j721s2-r5f", .data = (ulong)&j7200_j721s2_data, },
{ .compatible = "ti,am62-r5f", .data = (ulong)&am62_data, },
+ { .compatible = "ti,am64-r5f", .data = (ulong)&j7200_j721s2_data, },
{}
};
@@ -930,6 +931,7 @@ static const struct udevice_id k3_r5fss_ids[] = {
{ .compatible = "ti,j7200-r5fss"},
{ .compatible = "ti,j721s2-r5fss"},
{ .compatible = "ti,am62-r5fss"},
+ { .compatible = "ti,am64-r5fss"},
{}
};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index fe5c1214f57..a0d079c4555 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -49,6 +49,13 @@ config TEGRA186_RESET
Enable support for manipulating Tegra's on-SoC reset signals via IPC
requests to the BPMP (Boot and Power Management Processor).
+config RESET_AIROHA
+ bool "Reset controller driver for Airoha SoCs"
+ depends on DM_RESET && ARCH_AIROHA
+ default y
+ help
+ Support for reset controller on Airoha SoCs.
+
config RESET_TI_SCI
bool "TI System Control Interface (TI SCI) reset driver"
depends on DM_RESET && TI_SCI_PROTOCOL
@@ -235,4 +242,20 @@ config RESET_AT91
This enables the Reset Controller driver support for Microchip/Atmel
SoCs. Mainly used to expose assert/deassert methods to other drivers
that require it.
+
+config RESET_RZG2L_USBPHY_CTRL
+ bool "Enable support for Renesas RZ/G2L USB 2.0 PHY control"
+ depends on DM_RESET
+ select REGULATOR_RZG2L_USBPHY
+ help
+ Enable support for controlling USB 2.0 PHY resets on the Renesas
+ RZ/G2L SoC. This is required for USB 2.0 functionality to work on this
+ SoC.
+
+config RESET_SPACEMIT_K1
+ bool "Support for SPACEMIT's K1 Reset driver"
+ depends on DM_RESET
+ help
+ Support for SPACEMIT's K1 Reset system. Basic Assert/Deassert
+ is supported.
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index d99a78c9828..b9494396013 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_STI_RESET) += sti-reset.o
obj-$(CONFIG_STM32_RESET) += stm32-reset.o
obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o
obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
+obj-$(CONFIG_RESET_AIROHA) += reset-airoha.o
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
@@ -33,3 +34,5 @@ obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o
obj-$(CONFIG_RESET_DRA7) += reset-dra7.o
obj-$(CONFIG_RESET_AT91) += reset-at91.o
obj-$(CONFIG_$(PHASE_)RESET_JH7110) += reset-jh7110.o
+obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
+obj-$(CONFIG_RESET_SPACEMIT_K1) += reset-spacemit-k1.o
diff --git a/drivers/reset/reset-airoha.c b/drivers/reset/reset-airoha.c
new file mode 100644
index 00000000000..e878af6167c
--- /dev/null
+++ b/drivers/reset/reset-airoha.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on Linux drivers/clk/clk-en7523.c reworked
+ * and detached to a dedicated driver
+ *
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org> (original driver)
+ * Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <dm.h>
+#include <linux/io.h>
+#include <reset-uclass.h>
+
+#include <dt-bindings/reset/airoha,en7581-reset.h>
+
+#define RST_NR_PER_BANK 32
+
+#define REG_RESET_CONTROL2 0x830
+#define REG_RESET_CONTROL1 0x834
+
+struct airoha_reset_priv {
+ const u16 *bank_ofs;
+ const u16 *idx_map;
+ void __iomem *base;
+};
+
+static const u16 en7581_rst_ofs[] = {
+ REG_RESET_CONTROL2,
+ REG_RESET_CONTROL1,
+};
+
+static const u16 en7581_rst_map[] = {
+ /* RST_CTRL2 */
+ [EN7581_XPON_PHY_RST] = 0,
+ [EN7581_CPU_TIMER2_RST] = 2,
+ [EN7581_HSUART_RST] = 3,
+ [EN7581_UART4_RST] = 4,
+ [EN7581_UART5_RST] = 5,
+ [EN7581_I2C2_RST] = 6,
+ [EN7581_XSI_MAC_RST] = 7,
+ [EN7581_XSI_PHY_RST] = 8,
+ [EN7581_NPU_RST] = 9,
+ [EN7581_I2S_RST] = 10,
+ [EN7581_TRNG_RST] = 11,
+ [EN7581_TRNG_MSTART_RST] = 12,
+ [EN7581_DUAL_HSI0_RST] = 13,
+ [EN7581_DUAL_HSI1_RST] = 14,
+ [EN7581_HSI_RST] = 15,
+ [EN7581_DUAL_HSI0_MAC_RST] = 16,
+ [EN7581_DUAL_HSI1_MAC_RST] = 17,
+ [EN7581_HSI_MAC_RST] = 18,
+ [EN7581_WDMA_RST] = 19,
+ [EN7581_WOE0_RST] = 20,
+ [EN7581_WOE1_RST] = 21,
+ [EN7581_HSDMA_RST] = 22,
+ [EN7581_TDMA_RST] = 24,
+ [EN7581_EMMC_RST] = 25,
+ [EN7581_SOE_RST] = 26,
+ [EN7581_PCIE2_RST] = 27,
+ [EN7581_XFP_MAC_RST] = 28,
+ [EN7581_USB_HOST_P1_RST] = 29,
+ [EN7581_USB_HOST_P1_U3_PHY_RST] = 30,
+ /* RST_CTRL1 */
+ [EN7581_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [EN7581_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
+ [EN7581_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
+ [EN7581_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
+ [EN7581_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [EN7581_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [EN7581_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [EN7581_UART_RST] = RST_NR_PER_BANK + 12,
+ [EN7581_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [EN7581_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [EN7581_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [EN7581_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [EN7581_SFC_RST] = RST_NR_PER_BANK + 18,
+ [EN7581_UART2_RST] = RST_NR_PER_BANK + 19,
+ [EN7581_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [EN7581_FE_RST] = RST_NR_PER_BANK + 21,
+ [EN7581_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [EN7581_GSW_RST] = RST_NR_PER_BANK + 23,
+ [EN7581_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [EN7581_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [EN7581_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
+ [EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+};
+
+static int airoha_reset_update(struct airoha_reset_priv *priv,
+ unsigned long id, bool assert)
+{
+ void __iomem *addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+ u32 val;
+
+ val = readl(addr);
+ if (assert)
+ val |= BIT(id % RST_NR_PER_BANK);
+ else
+ val &= ~BIT(id % RST_NR_PER_BANK);
+ writel(val, addr);
+
+ return 0;
+}
+
+static int airoha_reset_assert(struct reset_ctl *reset_ctl)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+
+ return airoha_reset_update(priv, id, true);
+}
+
+static int airoha_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+
+ return airoha_reset_update(priv, id, false);
+}
+
+static int airoha_reset_status(struct reset_ctl *reset_ctl)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+ void __iomem *addr;
+
+ addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+
+ return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
+}
+
+static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
+ struct ofnode_phandle_args *args)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+ if (args->args[0] >= ARRAY_SIZE(en7581_rst_map))
+ return -EINVAL;
+
+ reset_ctl->id = priv->idx_map[args->args[0]];
+
+ return 0;
+}
+
+static struct reset_ops airoha_reset_ops = {
+ .of_xlate = airoha_reset_xlate,
+ .rst_assert = airoha_reset_assert,
+ .rst_deassert = airoha_reset_deassert,
+ .rst_status = airoha_reset_status,
+};
+
+static int airoha_reset_probe(struct udevice *dev)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr(dev);
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->bank_ofs = en7581_rst_ofs;
+ priv->idx_map = en7581_rst_map;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(airoha_reset) = {
+ .name = "airoha-reset",
+ .id = UCLASS_RESET,
+ .probe = airoha_reset_probe,
+ .ops = &airoha_reset_ops,
+ .priv_auto = sizeof(struct airoha_reset_priv),
+};
diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
new file mode 100644
index 00000000000..622d7b9cf4f
--- /dev/null
+++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Renesas Electronics Corporation
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <renesas/rzg2l-usbphy.h>
+#include <reset-uclass.h>
+#include <reset.h>
+
+#define RESET 0x000
+
+#define RESET_SEL_PLLRESET BIT(12)
+#define RESET_PLLRESET BIT(8)
+
+#define RESET_SEL_P2RESET BIT(5)
+#define RESET_SEL_P1RESET BIT(4)
+#define RESET_PHYRST_2 BIT(1)
+#define RESET_PHYRST_1 BIT(0)
+
+#define PHY_RESET_MASK (RESET_PHYRST_1 | RESET_PHYRST_2)
+
+#define NUM_PORTS 2
+
+static int rzg2l_usbphy_ctrl_assert(struct reset_ctl *reset_ctl)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(reset_ctl->dev);
+ u32 val;
+
+ val = readl(priv->regs + RESET);
+ val |= reset_ctl->id ? RESET_PHYRST_2 : RESET_PHYRST_1;
+
+ /* If both ports are in reset, we can also place the PLL into reset. */
+ if ((val & PHY_RESET_MASK) == PHY_RESET_MASK)
+ val |= RESET_PLLRESET;
+
+ writel(val, priv->regs + RESET);
+ return 0;
+}
+
+static int rzg2l_usbphy_ctrl_deassert(struct reset_ctl *reset_ctl)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(reset_ctl->dev);
+ u32 val = reset_ctl->id ? RESET_PHYRST_2 : RESET_PHYRST_1;
+
+ /* If either port is out of reset, the PLL must also be out of reset. */
+ val |= RESET_PLLRESET;
+
+ clrbits_le32(priv->regs + RESET, val);
+ return 0;
+}
+
+static int rzg2l_usbphy_ctrl_of_xlate(struct reset_ctl *reset_ctl,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args[0] >= NUM_PORTS)
+ return -EINVAL;
+
+ reset_ctl->id = args->args[0];
+ return 0;
+}
+
+struct reset_ops rzg2l_usbphy_ctrl_ops = {
+ .rst_assert = rzg2l_usbphy_ctrl_assert,
+ .rst_deassert = rzg2l_usbphy_ctrl_deassert,
+ .of_xlate = rzg2l_usbphy_ctrl_of_xlate,
+};
+
+static int rzg2l_usbphy_ctrl_probe(struct udevice *dev)
+{
+ struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev);
+ struct reset_ctl rst;
+ int ret;
+
+ priv->regs = dev_read_addr(dev);
+
+ ret = reset_get_by_index(dev, 0, &rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to get reset line: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_deassert(&rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to de-assert reset line: %d\n", ret);
+ return ret;
+ }
+
+ /* put pll and phy into reset state */
+ setbits_le32(priv->regs + RESET,
+ RESET_SEL_PLLRESET | RESET_PLLRESET |
+ RESET_SEL_P1RESET | RESET_PHYRST_1 |
+ RESET_SEL_P2RESET | RESET_PHYRST_2);
+
+ return 0;
+}
+
+static const struct udevice_id rzg2l_usbphy_ctrl_ids[] = {
+ { .compatible = "renesas,rzg2l-usbphy-ctrl", },
+ { /* sentinel */ }
+};
+
+static int rzg2l_usbphy_ctrl_bind(struct udevice *dev)
+{
+ struct driver *drv;
+ ofnode node;
+ int ret;
+
+ node = ofnode_find_subnode(dev_ofnode(dev), "regulator-vbus");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "Failed to find vbus regulator devicetree node\n");
+ return -ENOENT;
+ }
+
+ drv = lists_driver_lookup_name("rzg2l_usbphy_regulator");
+ if (!drv) {
+ dev_err(dev, "Failed to find vbus regulator driver\n");
+ return -ENOENT;
+ }
+
+ ret = device_bind(dev, drv, dev->name, NULL, node, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to bind vbus regulator: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(rzg2l_usbphy_ctrl) = {
+ .name = "rzg2l_usbphy_ctrl",
+ .id = UCLASS_RESET,
+ .of_match = rzg2l_usbphy_ctrl_ids,
+ .bind = rzg2l_usbphy_ctrl_bind,
+ .probe = rzg2l_usbphy_ctrl_probe,
+ .ops = &rzg2l_usbphy_ctrl_ops,
+ .priv_auto = sizeof(struct rzg2l_usbphy_ctrl_priv),
+};
diff --git a/drivers/reset/reset-spacemit-k1.c b/drivers/reset/reset-spacemit-k1.c
new file mode 100644
index 00000000000..613e002fc4f
--- /dev/null
+++ b/drivers/reset/reset-spacemit-k1.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Spacemit Inc.
+ * Copyright (C) 2025 Huan Zhou <pericycle.cc@gmail.com>
+ */
+
+#include <asm/io.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dt-bindings/reset/spacemit-k1-reset.h>
+#include <linux/bitops.h>
+#include <reset-uclass.h>
+
+/* APBC register offset */
+#define APBC_UART1_CLK_RST 0x0
+#define APBC_UART2_CLK_RST 0x4
+#define APBC_GPIO_CLK_RST 0x8
+#define APBC_PWM0_CLK_RST 0xc
+#define APBC_PWM1_CLK_RST 0x10
+#define APBC_PWM2_CLK_RST 0x14
+#define APBC_PWM3_CLK_RST 0x18
+#define APBC_TWSI8_CLK_RST 0x20
+#define APBC_UART3_CLK_RST 0x24
+#define APBC_RTC_CLK_RST 0x28
+#define APBC_TWSI0_CLK_RST 0x2c
+#define APBC_TWSI1_CLK_RST 0x30
+#define APBC_TIMERS1_CLK_RST 0x34
+#define APBC_TWSI2_CLK_RST 0x38
+#define APBC_AIB_CLK_RST 0x3c
+#define APBC_TWSI4_CLK_RST 0x40
+#define APBC_TIMERS2_CLK_RST 0x44
+#define APBC_ONEWIRE_CLK_RST 0x48
+#define APBC_TWSI5_CLK_RST 0x4c
+#define APBC_DRO_CLK_RST 0x58
+#define APBC_IR_CLK_RST 0x5c
+#define APBC_TWSI6_CLK_RST 0x60
+#define APBC_TWSI7_CLK_RST 0x68
+#define APBC_TSEN_CLK_RST 0x6c
+
+#define APBC_UART4_CLK_RST 0x70
+#define APBC_UART5_CLK_RST 0x74
+#define APBC_UART6_CLK_RST 0x78
+#define APBC_SSP3_CLK_RST 0x7c
+
+#define APBC_SSPA0_CLK_RST 0x80
+#define APBC_SSPA1_CLK_RST 0x84
+
+#define APBC_IPC_AP2AUD_CLK_RST 0x90
+#define APBC_UART7_CLK_RST 0x94
+#define APBC_UART8_CLK_RST 0x98
+#define APBC_UART9_CLK_RST 0x9c
+
+#define APBC_CAN0_CLK_RST 0xa0
+#define APBC_PWM4_CLK_RST 0xa8
+#define APBC_PWM5_CLK_RST 0xac
+#define APBC_PWM6_CLK_RST 0xb0
+#define APBC_PWM7_CLK_RST 0xb4
+#define APBC_PWM8_CLK_RST 0xb8
+#define APBC_PWM9_CLK_RST 0xbc
+#define APBC_PWM10_CLK_RST 0xc0
+#define APBC_PWM11_CLK_RST 0xc4
+#define APBC_PWM12_CLK_RST 0xc8
+#define APBC_PWM13_CLK_RST 0xcc
+#define APBC_PWM14_CLK_RST 0xd0
+#define APBC_PWM15_CLK_RST 0xd4
+#define APBC_PWM16_CLK_RST 0xd8
+#define APBC_PWM17_CLK_RST 0xdc
+#define APBC_PWM18_CLK_RST 0xe0
+#define APBC_PWM19_CLK_RST 0xe4
+/* end of APBC register offset */
+
+/* MPMU register offset */
+#define MPMU_WDTPCR 0x200
+/* end of MPMU register offset */
+
+/* APMU register offset */
+#define APMU_JPG_CLK_RES_CTRL 0x20
+#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24
+#define APMU_ISP_CLK_RES_CTRL 0x38
+#define APMU_LCD_CLK_RES_CTRL1 0x44
+#define APMU_LCD_SPI_CLK_RES_CTRL 0x48
+#define APMU_LCD_CLK_RES_CTRL2 0x4c
+#define APMU_CCIC_CLK_RES_CTRL 0x50
+#define APMU_SDH0_CLK_RES_CTRL 0x54
+#define APMU_SDH1_CLK_RES_CTRL 0x58
+#define APMU_USB_CLK_RES_CTRL 0x5c
+#define APMU_QSPI_CLK_RES_CTRL 0x60
+#define APMU_USB_CLK_RES_CTRL 0x5c
+#define APMU_DMA_CLK_RES_CTRL 0x64
+#define APMU_AES_CLK_RES_CTRL 0x68
+#define APMU_VPU_CLK_RES_CTRL 0xa4
+#define APMU_GPU_CLK_RES_CTRL 0xcc
+#define APMU_SDH2_CLK_RES_CTRL 0xe0
+#define APMU_PMUA_MC_CTRL 0xe8
+#define APMU_PMU_CC2_AP 0x100
+#define APMU_PMUA_EM_CLK_RES_CTRL 0x104
+
+#define APMU_AUDIO_CLK_RES_CTRL 0x14c
+#define APMU_HDMI_CLK_RES_CTRL 0x1B8
+
+#define APMU_PCIE_CLK_RES_CTRL_0 0x3cc
+#define APMU_PCIE_CLK_RES_CTRL_1 0x3d4
+#define APMU_PCIE_CLK_RES_CTRL_2 0x3dc
+
+#define APMU_EMAC0_CLK_RES_CTRL 0x3e4
+#define APMU_EMAC1_CLK_RES_CTRL 0x3ec
+/* end of APMU register offset */
+
+/* APBC2 register offset */
+#define APBC2_UART1_CLK_RST 0x00
+#define APBC2_SSP2_CLK_RST 0x04
+#define APBC2_TWSI3_CLK_RST 0x08
+#define APBC2_RTC_CLK_RST 0x0c
+#define APBC2_TIMERS0_CLK_RST 0x10
+#define APBC2_KPC_CLK_RST 0x14
+#define APBC2_GPIO_CLK_RST 0x1c
+/* end of APBC2 register offset */
+
+enum spacemit_reset_base_type {
+ RST_BASE_TYPE_MPMU = 0,
+ RST_BASE_TYPE_APMU = 1,
+ RST_BASE_TYPE_APBC = 2,
+ RST_BASE_TYPE_APBS = 3,
+ RST_BASE_TYPE_CIU = 4,
+ RST_BASE_TYPE_DCIU = 5,
+ RST_BASE_TYPE_DDRC = 6,
+ RST_BASE_TYPE_AUDC = 7,
+ RST_BASE_TYPE_APBC2 = 8,
+};
+
+struct spacemit_reset_signal {
+ u32 offset;
+ u32 mask;
+ u32 deassert_val;
+ u32 assert_val;
+ enum spacemit_reset_base_type type;
+};
+
+struct spacemit_reset_base {
+ void __iomem *mpmu_base;
+ void __iomem *apmu_base;
+ void __iomem *apbc_base;
+ void __iomem *apbs_base;
+ void __iomem *ciu_base;
+ void __iomem *dciu_base;
+ void __iomem *ddrc_base;
+ void __iomem *audio_ctrl_base;
+ void __iomem *apbc2_base;
+};
+
+struct spacemit_reset {
+ struct spacemit_reset_base io_base;
+ const struct spacemit_reset_signal *signals;
+};
+
+enum {
+ RESET_TWSI6_SPL = 0,
+ RESET_TWSI8_SPL,
+ RESET_SDH_AXI_SPL,
+ RESET_SDH0_SPL,
+ RESET_USB_AXI_SPL,
+ RESET_USBP1_AXI_SPL,
+ RESET_USB3_0_SPL,
+ RESET_QSPI_SPL,
+ RESET_QSPI_BUS_SPL,
+ RESET_AES_SPL,
+ RESET_SDH2_SPL,
+ RESET_NUMBER_SPL
+};
+
+static const struct spacemit_reset_signal
+ k1_reset_signals[RESET_NUMBER] = {
+ [RESET_UART1] = { APBC_UART1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART2] = { APBC_UART2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_GPIO] = { APBC_GPIO_CLK_RST, BIT(2), 0,
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM0] = { APBC_PWM0_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM1] = { APBC_PWM1_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM2] = { APBC_PWM2_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM3] = { APBC_PWM3_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM4] = { APBC_PWM4_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM5] = { APBC_PWM5_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM6] = { APBC_PWM6_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM7] = { APBC_PWM7_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM8] = { APBC_PWM8_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM9] = { APBC_PWM9_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM10] = { APBC_PWM10_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM11] = { APBC_PWM11_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM12] = { APBC_PWM12_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM13] = { APBC_PWM13_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM14] = { APBC_PWM14_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM15] = { APBC_PWM15_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM16] = { APBC_PWM16_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM17] = { APBC_PWM17_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM18] = { APBC_PWM18_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_PWM19] = { APBC_PWM19_CLK_RST,
+ BIT(2) | BIT(0),
+ BIT(0),
+ BIT(2),
+ RST_BASE_TYPE_APBC },
+ [RESET_SSP3] = { APBC_SSP3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART3] = { APBC_UART3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_RTC] = { APBC_RTC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI0] = { APBC_TWSI0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TIMERS1] = { APBC_TIMERS1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_AIB] = { APBC_AIB_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TIMERS2] = { APBC_TIMERS2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_ONEWIRE] = { APBC_ONEWIRE_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_SSPA0] = { APBC_SSPA0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_SSPA1] = { APBC_SSPA1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_DRO] = { APBC_DRO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_IR] = { APBC_IR_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI1] = { APBC_TWSI1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TSEN] = { APBC_TSEN_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI2] = { APBC_TWSI2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI4] = { APBC_TWSI4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI5] = { APBC_TWSI5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI6] = { APBC_TWSI6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI7] = { APBC_TWSI7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_TWSI8] = { APBC_TWSI8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_IPC_AP2AUD] = { APBC_IPC_AP2AUD_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART4] = { APBC_UART4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART5] = { APBC_UART5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART6] = { APBC_UART6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART7] = { APBC_UART7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART8] = { APBC_UART8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_UART9] = { APBC_UART9_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ [RESET_CAN0] = { APBC_CAN0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC },
+ /* MPMU */
+ [RESET_WDT] = { MPMU_WDTPCR, BIT(2), 0, BIT(2), RST_BASE_TYPE_MPMU },
+ /* APMU */
+ [RESET_JPG] = { APMU_JPG_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_CSI] = { APMU_CSI_CCIC2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_CCIC2_PHY] = { APMU_CSI_CCIC2_CLK_RES_CTRL,
+ BIT(2),
+ BIT(2),
+ 0,
+ RST_BASE_TYPE_APMU },
+ [RESET_CCIC3_PHY] = { APMU_CSI_CCIC2_CLK_RES_CTRL,
+ BIT(29),
+ BIT(29),
+ 0,
+ RST_BASE_TYPE_APMU },
+ [RESET_ISP] = { APMU_ISP_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_ISP_AHB] = { APMU_ISP_CLK_RES_CTRL, BIT(3), BIT(3), 0, RST_BASE_TYPE_APMU },
+ [RESET_ISP_CI] = { APMU_ISP_CLK_RES_CTRL, BIT(16), BIT(16), 0, RST_BASE_TYPE_APMU },
+ [RESET_ISP_CPP] = { APMU_ISP_CLK_RES_CTRL, BIT(27), BIT(27), 0, RST_BASE_TYPE_APMU },
+ [RESET_LCD] = { APMU_LCD_CLK_RES_CTRL1, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+ [RESET_DSI_ESC] = { APMU_LCD_CLK_RES_CTRL1, BIT(3), BIT(3), 0, RST_BASE_TYPE_APMU },
+ [RESET_V2D] = { APMU_LCD_CLK_RES_CTRL1, BIT(27), BIT(27), 0, RST_BASE_TYPE_APMU },
+ [RESET_MIPI] = { APMU_LCD_CLK_RES_CTRL1, BIT(15), BIT(15), 0, RST_BASE_TYPE_APMU },
+ [RESET_LCD_SPI] = { APMU_LCD_SPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_LCD_SPI_BUS] = { APMU_LCD_SPI_CLK_RES_CTRL,
+ BIT(4),
+ BIT(4),
+ 0,
+ RST_BASE_TYPE_APMU },
+ [RESET_LCD_SPI_HBUS] = { APMU_LCD_SPI_CLK_RES_CTRL,
+ BIT(2),
+ BIT(2),
+ 0,
+ RST_BASE_TYPE_APMU },
+ [RESET_LCD_MCLK] = { APMU_LCD_CLK_RES_CTRL2, BIT(9), BIT(9), 0, RST_BASE_TYPE_APMU },
+ [RESET_CCIC_4X] = { APMU_CCIC_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_CCIC1_PHY] = { APMU_CCIC_CLK_RES_CTRL, BIT(2), BIT(2), 0, RST_BASE_TYPE_APMU },
+ [RESET_SDH_AXI] = { APMU_SDH0_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_SDH0] = { APMU_SDH0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_SDH1] = { APMU_SDH1_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_USB_AXI] = { APMU_USB_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_USBP1_AXI] = { APMU_USB_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+ [RESET_USB3_0] = { APMU_USB_CLK_RES_CTRL,
+ BIT(9) | BIT(10) | BIT(11),
+ BIT(9) | BIT(10) | BIT(11),
+ 0,
+ RST_BASE_TYPE_APMU },
+ [RESET_QSPI] = { APMU_QSPI_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_QSPI_BUS] = { APMU_QSPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_DMA] = { APMU_DMA_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_AES] = { APMU_AES_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU },
+ [RESET_VPU] = { APMU_VPU_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_GPU] = { APMU_GPU_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_SDH2] = { APMU_SDH2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_MC] = { APMU_PMUA_MC_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_EM_AXI] = { APMU_PMUA_EM_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU },
+ [RESET_EM] = { APMU_PMUA_EM_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_AUDIO_SYS] = { APMU_AUDIO_CLK_RES_CTRL,
+ BIT(0) | BIT(2) | BIT(3),
+ BIT(0) | BIT(2) | BIT(3),
+ 0,
+ RST_BASE_TYPE_APMU },
+ [RESET_HDMI] = { APMU_HDMI_CLK_RES_CTRL, BIT(9), BIT(9), 0, RST_BASE_TYPE_APMU },
+ [RESET_PCIE0] = { APMU_PCIE_CLK_RES_CTRL_0,
+ BIT(3) | BIT(4) | BIT(5) | BIT(8),
+ BIT(3) | BIT(4) | BIT(5),
+ BIT(8),
+ RST_BASE_TYPE_APMU },
+ [RESET_PCIE1] = { APMU_PCIE_CLK_RES_CTRL_1,
+ BIT(3) | BIT(4) | BIT(5) | BIT(8),
+ BIT(3) | BIT(4) | BIT(5),
+ BIT(8),
+ RST_BASE_TYPE_APMU },
+ [RESET_PCIE2] = { APMU_PCIE_CLK_RES_CTRL_2, 0x138, 0x38, 0x100, RST_BASE_TYPE_APMU },
+ [RESET_EMAC0] = { APMU_EMAC0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_EMAC1] = { APMU_EMAC1_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU },
+ [RESET_SEC_UART1] = { APBC2_UART1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ [RESET_SEC_SSP2] = { APBC2_SSP2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ [RESET_SEC_TWSI3] = { APBC2_TWSI3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ [RESET_SEC_RTC] = { APBC2_RTC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ [RESET_SEC_TIMERS0] = { APBC2_TIMERS0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ [RESET_SEC_KPC] = { APBC2_KPC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ [RESET_SEC_GPIO] = { APBC2_GPIO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 },
+ };
+
+static u32 spacemit_reset_read(struct spacemit_reset *reset, u32 id)
+{
+ void __iomem *base;
+
+ switch (reset->signals[id].type) {
+ case RST_BASE_TYPE_APMU:
+ base = reset->io_base.apmu_base;
+ break;
+ case RST_BASE_TYPE_APBC:
+ base = reset->io_base.apbc_base;
+ break;
+ default:
+ base = reset->io_base.apbc_base;
+ break;
+ }
+
+ return readl(base + reset->signals[id].offset);
+}
+
+static void spacemit_reset_write(struct spacemit_reset *reset, u32 value, u32 id)
+{
+ void __iomem *base;
+
+ switch (reset->signals[id].type) {
+ case RST_BASE_TYPE_APMU:
+ base = reset->io_base.apmu_base;
+ break;
+ case RST_BASE_TYPE_APBC:
+ base = reset->io_base.apbc_base;
+ break;
+ default:
+ base = reset->io_base.apbc_base;
+ break;
+ }
+
+ writel(value, base + reset->signals[id].offset);
+}
+
+static void spacemit_reset_set(struct reset_ctl *rst, u32 id, bool assert)
+{
+ u32 value;
+ struct spacemit_reset *reset = dev_get_priv(rst->dev);
+
+ value = spacemit_reset_read(reset, id);
+
+ if (assert) {
+ value &= ~reset->signals[id].mask;
+ value |= reset->signals[id].assert_val;
+ } else {
+ value &= ~reset->signals[id].mask;
+ value |= reset->signals[id].deassert_val;
+ }
+
+ spacemit_reset_write(reset, value, id);
+}
+
+static int spacemit_reset_update(struct reset_ctl *rst, bool assert)
+{
+ if (rst->id < RESET_UART1 || rst->id >= RESET_NUMBER)
+ return 0;
+
+ /* can not write to twsi8 */
+ if (rst->id == RESET_TWSI8)
+ return 0;
+
+ spacemit_reset_set(rst, rst->id, assert);
+ return 0;
+}
+
+static int spacemit_reset_assert(struct reset_ctl *rst)
+{
+ return spacemit_reset_update(rst, true);
+}
+
+static int spacemit_reset_deassert(struct reset_ctl *rst)
+{
+ return spacemit_reset_update(rst, false);
+}
+
+static int spacemit_k1_reset_probe(struct udevice *dev)
+{
+ struct spacemit_reset *reset = dev_get_priv(dev);
+
+ reset->io_base.mpmu_base = (void *)dev_remap_addr_index(dev, 0);
+ if (!reset->io_base.mpmu_base) {
+ pr_err("failed to map mpmu registers\n");
+ goto out;
+ }
+
+ reset->io_base.apmu_base = (void *)dev_remap_addr_index(dev, 1);
+ if (!reset->io_base.apmu_base) {
+ pr_err("failed to map apmu registers\n");
+ goto out;
+ }
+
+ reset->io_base.apbc_base = (void *)dev_remap_addr_index(dev, 2);
+ if (!reset->io_base.apbc_base) {
+ pr_err("failed to map apbc registers\n");
+ goto out;
+ }
+
+ reset->io_base.apbs_base = (void *)dev_remap_addr_index(dev, 3);
+ if (!reset->io_base.apbs_base) {
+ pr_err("failed to map apbs registers\n");
+ goto out;
+ }
+
+ reset->io_base.ciu_base = (void *)dev_remap_addr_index(dev, 4);
+ if (!reset->io_base.ciu_base) {
+ pr_err("failed to map ciu registers\n");
+ goto out;
+ }
+
+ reset->io_base.dciu_base = (void *)dev_remap_addr_index(dev, 5);
+ if (!reset->io_base.dciu_base) {
+ pr_err("failed to map dragon ciu registers\n");
+ goto out;
+ }
+
+ reset->io_base.ddrc_base = (void *)dev_remap_addr_index(dev, 6);
+ if (!reset->io_base.ddrc_base) {
+ pr_err("failed to map ddrc registers\n");
+ goto out;
+ }
+
+ reset->io_base.apbc2_base = (void *)dev_remap_addr_index(dev, 7);
+ if (!reset->io_base.apbc2_base) {
+ pr_err("failed to map apbc2 registers\n");
+ goto out;
+ }
+
+ reset->signals = k1_reset_signals;
+
+out:
+ return 0;
+}
+
+const struct reset_ops k1_reset_ops = {
+ .rst_assert = spacemit_reset_assert,
+ .rst_deassert = spacemit_reset_deassert,
+};
+
+static const struct udevice_id k1_reset_ids[] = {
+ { .compatible = "spacemit,k1-reset", },
+ {},
+};
+
+U_BOOT_DRIVER(k1_reset) = {
+ .name = "spacemit,k1-reset",
+ .id = UCLASS_RESET,
+ .ops = &k1_reset_ops,
+ .of_match = k1_reset_ids,
+ .probe = spacemit_k1_reset_probe,
+ .priv_auto = sizeof(struct spacemit_reset),
+};
diff --git a/drivers/rng/msm_rng.c b/drivers/rng/msm_rng.c
index f790d3b60f9..aab602c5ed0 100644
--- a/drivers/rng/msm_rng.c
+++ b/drivers/rng/msm_rng.c
@@ -44,6 +44,11 @@ static int msm_rng_read(struct udevice *dev, void *data, size_t len)
u32 *retdata = data;
size_t maxsize;
u32 val;
+ int ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret < 0)
+ return ret;
/* calculate max size bytes to transfer back to caller */
maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, len);
@@ -66,6 +71,8 @@ static int msm_rng_read(struct udevice *dev, void *data, size_t len)
break;
} while (currsize < maxsize);
+ clk_disable(&priv->clk);
+
return 0;
}
@@ -76,7 +83,7 @@ static int msm_rng_enable(struct msm_rng_priv *priv, int enable)
if (enable) {
/* Enable PRNG only if it is not already enabled */
val = readl_relaxed(priv->base + PRNG_CONFIG);
- if (val & PRNG_CONFIG_HW_ENABLE) {
+ if (!(val & PRNG_CONFIG_HW_ENABLE)) {
val = readl_relaxed(priv->base + PRNG_LFSR_CFG);
val &= ~PRNG_LFSR_CFG_MASK;
val |= PRNG_LFSR_CFG_CLOCKS;
@@ -118,7 +125,9 @@ static int msm_rng_probe(struct udevice *dev)
if (ret < 0)
return ret;
- return msm_rng_enable(priv, 1);
+ ret = msm_rng_enable(priv, 1);
+ clk_disable(&priv->clk);
+ return ret;
}
static int msm_rng_remove(struct udevice *dev)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index c4f4a8d78df..84130524c2d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -789,6 +789,12 @@ config SPL_SYS_NS16550_SERIAL
default y if SYS_NS16550_SERIAL || ARCH_SUNXI || ARCH_OMAP2PLUS
select SYS_NS16550
+config TPL_SYS_NS16550_SERIAL
+ bool "NS16550 UART or compatible legacy driver in TPL"
+ depends on TPL && !TPL_DM_SERIAL
+ default y if SPL_SYS_NS16550_SERIAL
+ select SYS_NS16550
+
config SYS_NS16550
bool "NS16550 UART or compatible"
help
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index ebe692a9963..2ef8ba20cf5 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -63,7 +63,4 @@ obj-$(CONFIG_XEN_SERIAL) += serial_xen.o
obj-$(CONFIG_XTENSA_SEMIHOSTING_SERIAL) += serial_xtensa_semihosting.o
obj-$(CONFIG_S5P4418_PL011_SERIAL) += serial_s5p4418_pl011.o
-ifndef CONFIG_XPL_BUILD
-obj-$(CONFIG_USB_TTY) += usbtty.o
-endif
obj-$(CONFIG_UART4_SERIAL) += serial_adi_uart4.o
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 0e267d097c5..4f7de3ea215 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -112,9 +112,9 @@ static void serial_out_dynamic(struct ns16550_plat *plat, u8 *addr,
} else if (plat->reg_width == 4) {
if (plat->flags & NS16550_FLAG_ENDIAN) {
if (plat->flags & NS16550_FLAG_BE)
- out_be32(addr, value);
+ out_be32((u32 *)addr, value);
else
- out_le32(addr, value);
+ out_le32((u32 *)addr, value);
} else {
writel(value, addr);
}
@@ -132,9 +132,9 @@ static int serial_in_dynamic(struct ns16550_plat *plat, u8 *addr)
} else if (plat->reg_width == 4) {
if (plat->flags & NS16550_FLAG_ENDIAN) {
if (plat->flags & NS16550_FLAG_BE)
- return in_be32(addr);
+ return in_be32((u32 *)addr);
else
- return in_le32(addr);
+ return in_le32((u32 *)addr);
} else {
return readl(addr);
}
@@ -294,13 +294,9 @@ void ns16550_putc(struct ns16550 *com_port, char c)
#if !CONFIG_IS_ENABLED(NS16550_MIN_FUNCTIONS)
char ns16550_getc(struct ns16550 *com_port)
{
- while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) {
-#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_TTY)
- extern void usbtty_poll(void);
- usbtty_poll();
-#endif
+ while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0)
schedule();
- }
+
return serial_in(&com_port->rbr);
}
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index 77a1558db68..cc0491bc3c8 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -63,7 +63,7 @@ static int sandbox_serial_probe(struct udevice *dev)
if (state->term_raw != STATE_TERM_RAW)
disable_ctrlc(1);
- membuff_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf));
+ membuf_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf));
return 0;
}
@@ -138,15 +138,15 @@ static int sandbox_serial_pending(struct udevice *dev, bool input)
return 0;
os_usleep(100);
- avail = membuff_putraw(&priv->buf, 100, false, &data);
+ avail = membuf_putraw(&priv->buf, 100, false, &data);
if (!avail)
return 1; /* buffer full */
count = os_read(0, data, avail);
if (count > 0)
- membuff_putraw(&priv->buf, count, true, &data);
+ membuf_putraw(&priv->buf, count, true, &data);
- return membuff_avail(&priv->buf);
+ return membuf_avail(&priv->buf);
}
static int sandbox_serial_getc(struct udevice *dev)
@@ -156,7 +156,7 @@ static int sandbox_serial_getc(struct udevice *dev)
if (!sandbox_serial_pending(dev, true))
return -EAGAIN; /* buffer empty */
- return membuff_getbyte(&priv->buf);
+ return membuf_getbyte(&priv->buf);
}
#ifdef CONFIG_DEBUG_UART_SANDBOX
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index c5fd740be4d..28f4435d01d 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -3,6 +3,7 @@
* (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>
*/
+#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <watchdog.h>
@@ -312,7 +313,17 @@ int mxc_serial_setbrg(struct udevice *dev, int baudrate)
static int mxc_serial_probe(struct udevice *dev)
{
struct mxc_serial_plat *plat = dev_get_plat(dev);
+#if CONFIG_IS_ENABLED(CLK_CCF)
+ int ret;
+ ret = clk_get_bulk(dev, &plat->clks);
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(&plat->clks);
+ if (ret)
+ return ret;
+#endif
_mxc_serial_init(plat->reg, plat->use_dte);
return 0;
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index 1ee58142b3f..1675a9cb9d1 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -299,13 +299,19 @@ static inline struct stm32_uart_info *_debug_uart_info(void)
static inline void _debug_uart_init(void)
{
- void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE);
- struct stm32_uart_info *uart_info = _debug_uart_info();
+ void __maybe_unused __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE);
+ struct stm32_uart_info *uart_info __maybe_unused = _debug_uart_info();
- _stm32_serial_init(base, uart_info);
- _stm32_serial_setbrg(base, uart_info,
- CONFIG_DEBUG_UART_CLOCK,
- CONFIG_BAUDRATE);
+ /*
+ * debug_uart_init() is only usable when SPL_BUILD is enabled
+ * (STM32MP1 case only)
+ */
+ if (IS_ENABLED(CONFIG_DEBUG_UART) && IS_ENABLED(CONFIG_SPL_BUILD)) {
+ _stm32_serial_init(base, uart_info);
+ _stm32_serial_setbrg(base, uart_info,
+ CONFIG_DEBUG_UART_CLOCK,
+ CONFIG_BAUDRATE);
+ }
}
static inline void _debug_uart_putc(int c)
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
deleted file mode 100644
index b7d77fbb6a9..00000000000
--- a/drivers/serial/usbtty.c
+++ /dev/null
@@ -1,983 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * (C) Copyright 2006
- * Bryan O'Donoghue, bodonoghue@codehermit.ie
- */
-
-#include <config.h>
-#include <circbuf.h>
-#include <env.h>
-#include <serial.h>
-#include <stdio_dev.h>
-#include <asm/unaligned.h>
-#include "usbtty.h"
-#include "usb_cdc_acm.h"
-#include "usbdescriptors.h"
-
-#ifdef DEBUG
-#define TTYDBG(fmt,args...)\
- serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
-#else
-#define TTYDBG(fmt,args...) do{}while(0)
-#endif
-
-#if 1
-#define TTYERR(fmt,args...)\
- serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\
- __LINE__,##args)
-#else
-#define TTYERR(fmt,args...) do{}while(0)
-#endif
-
-/*
- * Defines
- */
-#define NUM_CONFIGS 1
-#define MAX_INTERFACES 2
-#define NUM_ENDPOINTS 3
-#define ACM_TX_ENDPOINT 3
-#define ACM_RX_ENDPOINT 2
-#define GSERIAL_TX_ENDPOINT 2
-#define GSERIAL_RX_ENDPOINT 1
-#define NUM_ACM_INTERFACES 2
-#define NUM_GSERIAL_INTERFACES 1
-#define CFG_USBD_DATA_INTERFACE_STR "Bulk Data Interface"
-#define CFG_USBD_CTRL_INTERFACE_STR "Control Interface"
-
-/*
- * Buffers to hold input and output data
- */
-#define USBTTY_BUFFER_SIZE 2048
-static circbuf_t usbtty_input;
-static circbuf_t usbtty_output;
-
-/*
- * Instance variables
- */
-static struct stdio_dev usbttydev;
-static struct usb_device_instance device_instance[1];
-static struct usb_bus_instance bus_instance[1];
-static struct usb_configuration_instance config_instance[NUM_CONFIGS];
-static struct usb_interface_instance interface_instance[MAX_INTERFACES];
-static struct usb_alternate_instance alternate_instance[MAX_INTERFACES];
-/* one extra for control endpoint */
-static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
-
-/*
- * Global flag
- */
-int usbtty_configured_flag = 0;
-
-/*
- * Serial number
- */
-static char serial_number[16];
-
-/*
- * Descriptors, Strings, Local variables.
- */
-
-/* defined and used by gadget/ep0.c */
-extern struct usb_string_descriptor **usb_strings;
-
-/* Indicies, References */
-static unsigned short rx_endpoint = 0;
-static unsigned short tx_endpoint = 0;
-static unsigned short interface_count = 0;
-static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];
-
-/* USB Descriptor Strings */
-static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
-static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
-static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
-static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];
-static u8 wstrConfiguration[2 + 2*(sizeof(CFG_USBD_CONFIGURATION_STR)-1)];
-static u8 wstrDataInterface[2 + 2*(sizeof(CFG_USBD_DATA_INTERFACE_STR)-1)];
-static u8 wstrCtrlInterface[2 + 2*(sizeof(CFG_USBD_DATA_INTERFACE_STR)-1)];
-
-/* Standard USB Data Structures */
-static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES];
-static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
-static struct usb_configuration_descriptor *configuration_descriptor = 0;
-static struct usb_device_descriptor device_descriptor = {
- .bLength = sizeof(struct usb_device_descriptor),
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(USB_BCD_VERSION),
- .bDeviceSubClass = 0x00,
- .bDeviceProtocol = 0x00,
- .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
- .idVendor = cpu_to_le16(CONFIG_USBD_VENDORID),
- .bcdDevice = cpu_to_le16(USBTTY_BCD_DEVICE),
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIAL,
- .bNumConfigurations = NUM_CONFIGS
-};
-
-/*
- * Static CDC ACM specific descriptors
- */
-
-struct acm_config_desc {
- struct usb_configuration_descriptor configuration_desc;
-
- /* Master Interface */
- struct usb_interface_descriptor interface_desc;
-
- struct usb_class_header_function_descriptor usb_class_header;
- struct usb_class_call_management_descriptor usb_class_call_mgt;
- struct usb_class_abstract_control_descriptor usb_class_acm;
- struct usb_class_union_function_descriptor usb_class_union;
- struct usb_endpoint_descriptor notification_endpoint;
-
- /* Slave Interface */
- struct usb_interface_descriptor data_class_interface;
- struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS-1];
-} __attribute__((packed));
-
-static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
- {
- .configuration_desc ={
- .bLength =
- sizeof(struct usb_configuration_descriptor),
- .bDescriptorType = USB_DT_CONFIG,
- .wTotalLength =
- cpu_to_le16(sizeof(struct acm_config_desc)),
- .bNumInterfaces = NUM_ACM_INTERFACES,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG,
- .bmAttributes =
- BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
- .bMaxPower = USBTTY_MAXPOWER
- },
- /* Interface 1 */
- .interface_desc = {
- .bLength = sizeof(struct usb_interface_descriptor),
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0x01,
- .bInterfaceClass =
- COMMUNICATIONS_INTERFACE_CLASS_CONTROL,
- .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS,
- .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL,
- .iInterface = STR_CTRL_INTERFACE,
- },
- .usb_class_header = {
- .bFunctionLength =
- sizeof(struct usb_class_header_function_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_ST_HEADER,
- .bcdCDC = cpu_to_le16(110),
- },
- .usb_class_call_mgt = {
- .bFunctionLength =
- sizeof(struct usb_class_call_management_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_ST_CMF,
- .bmCapabilities = 0x00,
- .bDataInterface = 0x01,
- },
- .usb_class_acm = {
- .bFunctionLength =
- sizeof(struct usb_class_abstract_control_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_ST_ACMF,
- .bmCapabilities = 0x00,
- },
- .usb_class_union = {
- .bFunctionLength =
- sizeof(struct usb_class_union_function_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_ST_UF,
- .bMasterInterface = 0x00,
- .bSlaveInterface0 = 0x01,
- },
- .notification_endpoint = {
- .bLength =
- sizeof(struct usb_endpoint_descriptor),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = UDC_INT_ENDPOINT | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize
- = cpu_to_le16(CFG_USBD_SERIAL_INT_PKTSIZE),
- .bInterval = 0xFF,
- },
-
- /* Interface 2 */
- .data_class_interface = {
- .bLength =
- sizeof(struct usb_interface_descriptor),
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0x01,
- .bAlternateSetting = 0x00,
- .bNumEndpoints = 0x02,
- .bInterfaceClass =
- COMMUNICATIONS_INTERFACE_CLASS_DATA,
- .bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE,
- .bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE,
- .iInterface = STR_DATA_INTERFACE,
- },
- .data_endpoints = {
- {
- .bLength =
- sizeof(struct usb_endpoint_descriptor),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = UDC_OUT_ENDPOINT | USB_DIR_OUT,
- .bmAttributes =
- USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize =
- cpu_to_le16(CFG_USBD_SERIAL_BULK_PKTSIZE),
- .bInterval = 0xFF,
- },
- {
- .bLength =
- sizeof(struct usb_endpoint_descriptor),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = UDC_IN_ENDPOINT | USB_DIR_IN,
- .bmAttributes =
- USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize =
- cpu_to_le16(CFG_USBD_SERIAL_BULK_PKTSIZE),
- .bInterval = 0xFF,
- },
- },
- },
-};
-
-static struct rs232_emu rs232_desc={
- .dter = 115200,
- .stop_bits = 0x00,
- .parity = 0x00,
- .data_bits = 0x08
-};
-
-/*
- * Static Generic Serial specific data
- */
-
-struct gserial_config_desc {
-
- struct usb_configuration_descriptor configuration_desc;
- struct usb_interface_descriptor interface_desc[NUM_GSERIAL_INTERFACES];
- struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS];
-
-} __attribute__((packed));
-
-static struct gserial_config_desc
-gserial_configuration_descriptors[NUM_CONFIGS] ={
- {
- .configuration_desc ={
- .bLength = sizeof(struct usb_configuration_descriptor),
- .bDescriptorType = USB_DT_CONFIG,
- .wTotalLength =
- cpu_to_le16(sizeof(struct gserial_config_desc)),
- .bNumInterfaces = NUM_GSERIAL_INTERFACES,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG,
- .bmAttributes =
- BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
- .bMaxPower = USBTTY_MAXPOWER
- },
- .interface_desc = {
- {
- .bLength =
- sizeof(struct usb_interface_descriptor),
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = NUM_ENDPOINTS,
- .bInterfaceClass =
- COMMUNICATIONS_INTERFACE_CLASS_VENDOR,
- .bInterfaceSubClass =
- COMMUNICATIONS_NO_SUBCLASS,
- .bInterfaceProtocol =
- COMMUNICATIONS_NO_PROTOCOL,
- .iInterface = STR_DATA_INTERFACE
- },
- },
- .data_endpoints = {
- {
- .bLength =
- sizeof(struct usb_endpoint_descriptor),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = UDC_OUT_ENDPOINT | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize =
- cpu_to_le16(CFG_USBD_SERIAL_OUT_PKTSIZE),
- .bInterval= 0xFF,
- },
- {
- .bLength =
- sizeof(struct usb_endpoint_descriptor),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = UDC_IN_ENDPOINT | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize =
- cpu_to_le16(CFG_USBD_SERIAL_IN_PKTSIZE),
- .bInterval = 0xFF,
- },
- {
- .bLength =
- sizeof(struct usb_endpoint_descriptor),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = UDC_INT_ENDPOINT | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize =
- cpu_to_le16(CFG_USBD_SERIAL_INT_PKTSIZE),
- .bInterval = 0xFF,
- },
- },
- },
-};
-
-/*
- * Static Function Prototypes
- */
-
-static void usbtty_init_strings (void);
-static void usbtty_init_instances (void);
-static void usbtty_init_endpoints (void);
-static void usbtty_init_terminal_type(short type);
-static void usbtty_event_handler (struct usb_device_instance *device,
- usb_device_event_t event, int data);
-static int usbtty_cdc_setup(struct usb_device_request *request,
- struct urb *urb);
-static int usbtty_configured (void);
-static int write_buffer (circbuf_t * buf);
-static int fill_buffer (circbuf_t * buf);
-
-void usbtty_poll (void);
-
-/* utility function for converting char* to wide string used by USB */
-static void str2wide (char *str, u16 * wide)
-{
- int i;
- for (i = 0; i < strlen (str) && str[i]; i++){
- #if defined(__LITTLE_ENDIAN)
- wide[i] = (u16) str[i];
- #elif defined(__BIG_ENDIAN)
- wide[i] = ((u16)(str[i])<<8);
- #else
- #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined"
- #endif
- }
-}
-
-/*
- * Test whether a character is in the RX buffer
- */
-
-int usbtty_tstc(struct stdio_dev *dev)
-{
- struct usb_endpoint_instance *endpoint =
- &endpoint_instance[rx_endpoint];
-
- /* If no input data exists, allow more RX to be accepted */
- if(usbtty_input.size <= 0){
- udc_unset_nak(endpoint->endpoint_address&0x03);
- }
-
- usbtty_poll ();
- return (usbtty_input.size > 0);
-}
-
-/*
- * Read a single byte from the usb client port. Returns 1 on success, 0
- * otherwise. When the function is succesfull, the character read is
- * written into its argument c.
- */
-
-int usbtty_getc(struct stdio_dev *dev)
-{
- char c;
- struct usb_endpoint_instance *endpoint =
- &endpoint_instance[rx_endpoint];
-
- while (usbtty_input.size <= 0) {
- udc_unset_nak(endpoint->endpoint_address&0x03);
- usbtty_poll ();
- }
-
- buf_pop (&usbtty_input, &c, 1);
- udc_set_nak(endpoint->endpoint_address&0x03);
-
- return c;
-}
-
-/*
- * Output a single byte to the usb client port.
- */
-void usbtty_putc(struct stdio_dev *dev, const char c)
-{
- if (!usbtty_configured ())
- return;
-
- /* If \n, also do \r */
- if (c == '\n')
- buf_push (&usbtty_output, "\r", 1);
-
- buf_push(&usbtty_output, &c, 1);
-
- /* Poll at end to handle new data... */
- if ((usbtty_output.size + 2) >= usbtty_output.totalsize) {
- usbtty_poll ();
- }
-}
-
-/* usbtty_puts() helper function for finding the next '\n' in a string */
-static int next_nl_pos (const char *s)
-{
- int i;
-
- for (i = 0; s[i] != '\0'; i++) {
- if (s[i] == '\n')
- return i;
- }
- return i;
-}
-
-/*
- * Output a string to the usb client port - implementing flow control
- */
-
-static void __usbtty_puts (const char *str, int len)
-{
- int maxlen = usbtty_output.totalsize;
- int space, n;
-
- /* break str into chunks < buffer size, if needed */
- while (len > 0) {
- usbtty_poll ();
-
- space = maxlen - usbtty_output.size;
- /* Empty buffer here, if needed, to ensure space... */
- if (space) {
- write_buffer (&usbtty_output);
-
- n = min(space, min(len, maxlen));
- buf_push (&usbtty_output, str, n);
-
- str += n;
- len -= n;
- }
- }
-}
-
-void usbtty_puts(struct stdio_dev *dev, const char *str)
-{
- int n;
- int len;
-
- if (!usbtty_configured ())
- return;
-
- len = strlen (str);
- /* add '\r' for each '\n' */
- while (len > 0) {
- n = next_nl_pos (str);
-
- if (str[n] == '\n') {
- __usbtty_puts(str, n);
- __usbtty_puts("\r\n", 2);
- str += (n + 1);
- len -= (n + 1);
- } else {
- /* No \n found. All done. */
- __usbtty_puts (str, n);
- break;
- }
- }
-
- /* Poll at end to handle new data... */
- usbtty_poll ();
-}
-
-/*
- * Initialize the usb client port.
- *
- */
-int drv_usbtty_init (void)
-{
- int rc;
- char * sn;
- char * tt;
- int snlen;
-
- /* Get serial number */
- sn = env_get("serial#");
- if (!sn)
- sn = "000000000000";
- snlen = strlen(sn);
- if (snlen > sizeof(serial_number) - 1) {
- printf ("Warning: serial number %s is too long (%d > %lu)\n",
- sn, snlen, (ulong)(sizeof(serial_number) - 1));
- snlen = sizeof(serial_number) - 1;
- }
- memcpy (serial_number, sn, snlen);
- serial_number[snlen] = '\0';
-
- /* Decide on which type of UDC device to be.
- */
- tt = env_get("usbtty");
- if (!tt)
- tt = "generic";
- usbtty_init_terminal_type(strcmp(tt,"cdc_acm"));
-
- /* prepare buffers... */
- buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);
- buf_init (&usbtty_output, USBTTY_BUFFER_SIZE);
-
- /* Now, set up USB controller and infrastructure */
- udc_init (); /* Basic USB initialization */
-
- usbtty_init_strings ();
- usbtty_init_instances ();
-
- usbtty_init_endpoints ();
-
- udc_startup_events (device_instance);/* Enable dev, init udc pointers */
- udc_connect (); /* Enable pullup for host detection */
-
- /* Device initialization */
- memset (&usbttydev, 0, sizeof (usbttydev));
-
- strcpy (usbttydev.name, "usbtty");
- usbttydev.ext = 0; /* No extensions */
- usbttydev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT;
- usbttydev.tstc = usbtty_tstc; /* 'tstc' function */
- usbttydev.getc = usbtty_getc; /* 'getc' function */
- usbttydev.putc = usbtty_putc; /* 'putc' function */
- usbttydev.puts = usbtty_puts; /* 'puts' function */
-
- rc = stdio_register (&usbttydev);
-
- return (rc == 0) ? 1 : rc;
-}
-
-static void usbtty_init_strings (void)
-{
- struct usb_string_descriptor *string;
-
- usbtty_string_table[STR_LANG] =
- (struct usb_string_descriptor*)wstrLang;
-
- string = (struct usb_string_descriptor *) wstrManufacturer;
- string->bLength = sizeof(wstrManufacturer);
- string->bDescriptorType = USB_DT_STRING;
- str2wide (CONFIG_USBD_MANUFACTURER, string->wData);
- usbtty_string_table[STR_MANUFACTURER]=string;
-
- string = (struct usb_string_descriptor *) wstrProduct;
- string->bLength = sizeof(wstrProduct);
- string->bDescriptorType = USB_DT_STRING;
- str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData);
- usbtty_string_table[STR_PRODUCT]=string;
-
- string = (struct usb_string_descriptor *) wstrSerial;
- string->bLength = sizeof(serial_number);
- string->bDescriptorType = USB_DT_STRING;
- str2wide (serial_number, string->wData);
- usbtty_string_table[STR_SERIAL]=string;
-
- string = (struct usb_string_descriptor *) wstrConfiguration;
- string->bLength = sizeof(wstrConfiguration);
- string->bDescriptorType = USB_DT_STRING;
- str2wide (CFG_USBD_CONFIGURATION_STR, string->wData);
- usbtty_string_table[STR_CONFIG]=string;
-
- string = (struct usb_string_descriptor *) wstrDataInterface;
- string->bLength = sizeof(wstrDataInterface);
- string->bDescriptorType = USB_DT_STRING;
- str2wide (CFG_USBD_DATA_INTERFACE_STR, string->wData);
- usbtty_string_table[STR_DATA_INTERFACE]=string;
-
- string = (struct usb_string_descriptor *) wstrCtrlInterface;
- string->bLength = sizeof(wstrCtrlInterface);
- string->bDescriptorType = USB_DT_STRING;
- str2wide (CFG_USBD_CTRL_INTERFACE_STR, string->wData);
- usbtty_string_table[STR_CTRL_INTERFACE]=string;
-
- /* Now, initialize the string table for ep0 handling */
- usb_strings = usbtty_string_table;
-}
-
-#define init_wMaxPacketSize(x) le16_to_cpu(get_unaligned(\
- &ep_descriptor_ptrs[(x) - 1]->wMaxPacketSize));
-
-static void usbtty_init_instances (void)
-{
- int i;
-
- /* initialize device instance */
- memset (device_instance, 0, sizeof (struct usb_device_instance));
- device_instance->device_state = STATE_INIT;
- device_instance->device_descriptor = &device_descriptor;
- device_instance->event = usbtty_event_handler;
- device_instance->cdc_recv_setup = usbtty_cdc_setup;
- device_instance->bus = bus_instance;
- device_instance->configurations = NUM_CONFIGS;
- device_instance->configuration_instance_array = config_instance;
-
- /* initialize bus instance */
- memset (bus_instance, 0, sizeof (struct usb_bus_instance));
- bus_instance->device = device_instance;
- bus_instance->endpoint_array = endpoint_instance;
- bus_instance->max_endpoints = 1;
- bus_instance->maxpacketsize = 64;
- bus_instance->serial_number_str = serial_number;
-
- /* configuration instance */
- memset (config_instance, 0,
- sizeof (struct usb_configuration_instance));
- config_instance->interfaces = interface_count;
- config_instance->configuration_descriptor = configuration_descriptor;
- config_instance->interface_instance_array = interface_instance;
-
- /* interface instance */
- memset (interface_instance, 0,
- sizeof (struct usb_interface_instance));
- interface_instance->alternates = 1;
- interface_instance->alternates_instance_array = alternate_instance;
-
- /* alternates instance */
- memset (alternate_instance, 0,
- sizeof (struct usb_alternate_instance));
- alternate_instance->interface_descriptor = interface_descriptors;
- alternate_instance->endpoints = NUM_ENDPOINTS;
- alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs;
-
- /* endpoint instances */
- memset (&endpoint_instance[0], 0,
- sizeof (struct usb_endpoint_instance));
- endpoint_instance[0].endpoint_address = 0;
- endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE;
- endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL;
- endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE;
- endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL;
- udc_setup_ep (device_instance, 0, &endpoint_instance[0]);
-
- for (i = 1; i <= NUM_ENDPOINTS; i++) {
- memset (&endpoint_instance[i], 0,
- sizeof (struct usb_endpoint_instance));
-
- endpoint_instance[i].endpoint_address =
- ep_descriptor_ptrs[i - 1]->bEndpointAddress;
-
- endpoint_instance[i].rcv_attributes =
- ep_descriptor_ptrs[i - 1]->bmAttributes;
-
- endpoint_instance[i].rcv_packetSize = init_wMaxPacketSize(i);
-
- endpoint_instance[i].tx_attributes =
- ep_descriptor_ptrs[i - 1]->bmAttributes;
-
- endpoint_instance[i].tx_packetSize = init_wMaxPacketSize(i);
-
- endpoint_instance[i].tx_attributes =
- ep_descriptor_ptrs[i - 1]->bmAttributes;
-
- urb_link_init (&endpoint_instance[i].rcv);
- urb_link_init (&endpoint_instance[i].rdy);
- urb_link_init (&endpoint_instance[i].tx);
- urb_link_init (&endpoint_instance[i].done);
-
- if (endpoint_instance[i].endpoint_address & USB_DIR_IN)
- endpoint_instance[i].tx_urb =
- usbd_alloc_urb (device_instance,
- &endpoint_instance[i]);
- else
- endpoint_instance[i].rcv_urb =
- usbd_alloc_urb (device_instance,
- &endpoint_instance[i]);
- }
-}
-
-static void usbtty_init_endpoints (void)
-{
- int i;
-
- bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
- for (i = 1; i <= NUM_ENDPOINTS; i++) {
- udc_setup_ep (device_instance, i, &endpoint_instance[i]);
- }
-}
-
-/* usbtty_init_terminal_type
- *
- * Do some late binding for our device type.
- */
-static void usbtty_init_terminal_type(short type)
-{
- switch(type){
- /* CDC ACM */
- case 0:
- /* Assign endpoint descriptors */
- ep_descriptor_ptrs[0] =
- &acm_configuration_descriptors[0].notification_endpoint;
- ep_descriptor_ptrs[1] =
- &acm_configuration_descriptors[0].data_endpoints[0];
- ep_descriptor_ptrs[2] =
- &acm_configuration_descriptors[0].data_endpoints[1];
-
- /* Enumerate Device Descriptor */
- device_descriptor.bDeviceClass =
- COMMUNICATIONS_DEVICE_CLASS;
- device_descriptor.idProduct =
- cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM);
-
- /* Assign endpoint indices */
- tx_endpoint = ACM_TX_ENDPOINT;
- rx_endpoint = ACM_RX_ENDPOINT;
-
- /* Configuration Descriptor */
- configuration_descriptor =
- (struct usb_configuration_descriptor*)
- &acm_configuration_descriptors;
-
- /* Interface count */
- interface_count = NUM_ACM_INTERFACES;
- break;
-
- /* BULK IN/OUT & Default */
- case 1:
- default:
- /* Assign endpoint descriptors */
- ep_descriptor_ptrs[0] =
- &gserial_configuration_descriptors[0].data_endpoints[0];
- ep_descriptor_ptrs[1] =
- &gserial_configuration_descriptors[0].data_endpoints[1];
- ep_descriptor_ptrs[2] =
- &gserial_configuration_descriptors[0].data_endpoints[2];
-
- /* Enumerate Device Descriptor */
- device_descriptor.bDeviceClass = 0xFF;
- device_descriptor.idProduct =
- cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL);
- /* Assign endpoint indices */
- tx_endpoint = GSERIAL_TX_ENDPOINT;
- rx_endpoint = GSERIAL_RX_ENDPOINT;
-
- /* Configuration Descriptor */
- configuration_descriptor =
- (struct usb_configuration_descriptor*)
- &gserial_configuration_descriptors;
-
- /* Interface count */
- interface_count = NUM_GSERIAL_INTERFACES;
- break;
- }
-}
-
-/******************************************************************************/
-
-static struct urb *next_urb (struct usb_device_instance *device,
- struct usb_endpoint_instance *endpoint)
-{
- struct urb *current_urb = NULL;
- int space;
-
- /* If there's a queue, then we should add to the last urb */
- if (!endpoint->tx_queue) {
- current_urb = endpoint->tx_urb;
- } else {
- /* Last urb from tx chain */
- current_urb =
- p2surround (struct urb, link, endpoint->tx.prev);
- }
-
- /* Make sure this one has enough room */
- space = current_urb->buffer_length - current_urb->actual_length;
- if (space > 0) {
- return current_urb;
- } else { /* No space here */
- /* First look at done list */
- current_urb = first_urb_detached (&endpoint->done);
- if (!current_urb) {
- current_urb = usbd_alloc_urb (device, endpoint);
- }
-
- urb_append (&endpoint->tx, current_urb);
- endpoint->tx_queue++;
- }
- return current_urb;
-}
-
-static int write_buffer (circbuf_t * buf)
-{
- if (!usbtty_configured ()) {
- return 0;
- }
-
- struct usb_endpoint_instance *endpoint =
- &endpoint_instance[tx_endpoint];
- struct urb *current_urb = NULL;
-
- /* TX data still exists - send it now
- */
- if(endpoint->sent < endpoint->tx_urb->actual_length){
- if(udc_endpoint_write (endpoint)){
- /* Write pre-empted by RX */
- return -1;
- }
- }
-
- if (buf->size) {
- char *dest;
-
- int space_avail;
- int popnum, popped;
- int total = 0;
-
- /* Break buffer into urb sized pieces,
- * and link each to the endpoint
- */
- while (buf->size > 0) {
-
- current_urb = next_urb (device_instance, endpoint);
-
- dest = (char*)current_urb->buffer +
- current_urb->actual_length;
-
- space_avail =
- current_urb->buffer_length -
- current_urb->actual_length;
- popnum = min(space_avail, (int)buf->size);
- if (popnum == 0)
- break;
-
- popped = buf_pop (buf, dest, popnum);
- if (popped == 0)
- break;
- current_urb->actual_length += popped;
- total += popped;
-
- /* If endpoint->last == 0, then transfers have
- * not started on this endpoint
- */
- if (endpoint->last == 0) {
- if(udc_endpoint_write (endpoint)){
- /* Write pre-empted by RX */
- return -1;
- }
- }
-
- }/* end while */
- return total;
- }
-
- return 0;
-}
-
-static int fill_buffer (circbuf_t * buf)
-{
- struct usb_endpoint_instance *endpoint =
- &endpoint_instance[rx_endpoint];
-
- if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
- unsigned int nb = 0;
- char *src = (char *) endpoint->rcv_urb->buffer;
- unsigned int rx_avail = buf->totalsize - buf->size;
-
- if(rx_avail >= endpoint->rcv_urb->actual_length){
-
- nb = endpoint->rcv_urb->actual_length;
- buf_push (buf, src, nb);
- endpoint->rcv_urb->actual_length = 0;
-
- }
- return nb;
- }
- return 0;
-}
-
-static int usbtty_configured (void)
-{
- return usbtty_configured_flag;
-}
-
-/******************************************************************************/
-
-static void usbtty_event_handler (struct usb_device_instance *device,
- usb_device_event_t event, int data)
-{
- switch (event) {
- case DEVICE_RESET:
- case DEVICE_BUS_INACTIVE:
- usbtty_configured_flag = 0;
- break;
- case DEVICE_CONFIGURED:
- usbtty_configured_flag = 1;
- break;
-
- case DEVICE_ADDRESS_ASSIGNED:
- usbtty_init_endpoints ();
-
- default:
- break;
- }
-}
-
-/******************************************************************************/
-
-int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb)
-{
- switch (request->bRequest){
-
- case ACM_SET_CONTROL_LINE_STATE: /* Implies DTE ready */
- break;
- case ACM_SEND_ENCAPSULATED_COMMAND : /* Required */
- break;
- case ACM_SET_LINE_ENCODING : /* DTE stop/parity bits
- * per character */
- break;
- case ACM_GET_ENCAPSULATED_RESPONSE : /* request response */
- break;
- case ACM_GET_LINE_ENCODING : /* request DTE rate,
- * stop/parity bits */
- memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc));
- urb->actual_length = sizeof(rs232_desc);
-
- break;
- default:
- return 1;
- }
- return 0;
-}
-
-/******************************************************************************/
-
-/*
- * Since interrupt handling has not yet been implemented, we use this function
- * to handle polling. This is called by the tstc,getc,putc,puts routines to
- * update the USB state.
- */
-void usbtty_poll (void)
-{
- /* New interrupts? */
- udc_irq();
-
- /* Write any output data to host buffer
- * (do this before checking interrupts to avoid missing one)
- */
- if (usbtty_configured ()) {
- write_buffer (&usbtty_output);
- }
-
- /* New interrupts? */
- udc_irq();
-
- /* Check for new data from host..
- * (do this after checking interrupts to get latest data)
- */
- if (usbtty_configured ()) {
- fill_buffer (&usbtty_input);
- }
-
- /* New interrupts? */
- udc_irq();
-
-}
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
deleted file mode 100644
index b176a7961b8..00000000000
--- a/drivers/serial/usbtty.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * (C) Copyright 2006
- * Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit
- */
-
-#ifndef __USB_TTY_H__
-#define __USB_TTY_H__
-
-#include <usbdevice.h>
-#if defined(CONFIG_PPC)
-#include <usb/mpc8xx_udc.h>
-#elif defined(CONFIG_CI_UDC)
-#include <usb/ci_udc.h>
-#endif
-
-#include <usb/udc.h>
-#include <version.h>
-
-#ifndef CFG_USBD_CONFIGURATION_STR
-#define CFG_USBD_CONFIGURATION_STR "TTY via USB"
-#endif
-
-#define CFG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT
-#define CFG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE
-#define CFG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT
-#define CFG_USBD_SERIAL_IN_PKTSIZE UDC_IN_PACKET_SIZE
-#define CFG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT
-#define CFG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE
-#define CFG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_PACKET_SIZE
-
-#define USBTTY_DEVICE_CLASS COMMUNICATIONS_DEVICE_CLASS
-
-#define USBTTY_BCD_DEVICE 0x00
-#define USBTTY_MAXPOWER 0x00
-
-#define STR_LANG 0x00
-#define STR_MANUFACTURER 0x01
-#define STR_PRODUCT 0x02
-#define STR_SERIAL 0x03
-#define STR_CONFIG 0x04
-#define STR_DATA_INTERFACE 0x05
-#define STR_CTRL_INTERFACE 0x06
-#define STR_COUNT 0x07
-
-#endif
diff --git a/drivers/soc/soc_ti_k3.c b/drivers/soc/soc_ti_k3.c
index a3acca4d394..b34cbd08e07 100644
--- a/drivers/soc/soc_ti_k3.c
+++ b/drivers/soc/soc_ti_k3.c
@@ -18,8 +18,12 @@ struct soc_ti_k3_plat {
static const char *get_family_string(u32 idreg)
{
const char *family;
+ u32 jtag_dev_id;
+ u32 pkg;
u32 soc;
+ jtag_dev_id = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
+
soc = (idreg & JTAG_ID_PARTNO_MASK) >> JTAG_ID_PARTNO_SHIFT;
switch (soc) {
@@ -51,8 +55,16 @@ static const char *get_family_string(u32 idreg)
family = "J722S";
break;
case JTAG_ID_PARTNO_J784S4:
- family = "J784S4";
- break;
+ {
+ /* Keep default family as J784S4 */
+ family = "J784S4";
+
+ pkg = (jtag_dev_id & JTAG_DEV_J742S2_PKG_MASK) >> JTAG_DEV_J742S2_PKG_SHIFT;
+ if (pkg == JTAG_ID_PKG_J742S2)
+ family = "J742S2";
+
+ break;
+ }
default:
family = "Unknown Silicon";
};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 96ea033082b..f475f341c9c 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -52,6 +52,13 @@ config SPI_DIRMAP
if DM_SPI
+config ADI_SPI3
+ bool "Enable ADI SPI Driver"
+ depends on ARCH_SC5XX
+ help
+ Enable the ADI (Analog Devices) SPI controller driver. This
+ driver enables the support for SC5XX spi controller.
+
config ALTERA_SPI
bool "Altera SPI driver"
help
@@ -85,7 +92,7 @@ config ATH79_SPI
config ATMEL_QSPI
bool "Atmel Quad SPI Controller"
- depends on ARCH_AT91
+ depends on ARCH_AT91 && SPI_MEM
help
Enable the Atmel Quad SPI controller in master mode. This driver
does not support generic SPI. The implementation supports only the
@@ -135,7 +142,7 @@ config BCMSTB_SPI
config CORTINA_SFLASH
bool "Cortina-Access Serial Flash controller driver"
- depends on DM_SPI && SPI_MEM
+ depends on SPI_MEM
help
Enable the Cortina-Access Serial Flash controller driver. This driver
can be used to access the SPI NOR/NAND flash on platforms embedding this
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 7051e2a00c6..21895d46429 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@ obj-y += spi.o
obj-$(CONFIG_SPI_MEM) += spi-mem-nodm.o
endif
+obj-$(CONFIG_ADI_SPI3) += adi_spi3.o
obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
obj-$(CONFIG_APPLE_SPI) += apple_spi.o
obj-$(CONFIG_ATH79_SPI) += ath79_spi.o
diff --git a/drivers/spi/adi_spi3.c b/drivers/spi/adi_spi3.c
new file mode 100644
index 00000000000..2125d25561a
--- /dev/null
+++ b/drivers/spi/adi_spi3.c
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Converted to driver model by Nathan Barrett-Morrison
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ * Contact: Ian Roberts <ian.roberts@timesys.com>
+ * Contact: Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>
+ *
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <dm/device_compat.h>
+#include <linux/io.h>
+
+#define SPI_IDLE_VAL 0xff
+
+#define MAX_CTRL_CS 7
+
+/* SPI_CONTROL */
+#define SPI_CTL_EN 0x00000001 /* Enable */
+#define SPI_CTL_MSTR 0x00000002 /* Master/Slave */
+#define SPI_CTL_PSSE 0x00000004 /* controls modf error in master mode */
+#define SPI_CTL_ODM 0x00000008 /* Open Drain Mode */
+#define SPI_CTL_CPHA 0x00000010 /* Clock Phase */
+#define SPI_CTL_CPOL 0x00000020 /* Clock Polarity */
+#define SPI_CTL_ASSEL 0x00000040 /* Slave Select Pin Control */
+#define SPI_CTL_SELST 0x00000080 /* Slave Select Polarity in transfers */
+#define SPI_CTL_EMISO 0x00000100 /*Enable MISO */
+#define SPI_CTL_SIZE 0x00000600 /*Word Transfer Size */
+#define SPI_CTL_SIZE08 0x00000000 /*SIZE: 8 bits */
+#define SPI_CTL_SIZE16 0x00000200 /*SIZE: 16 bits */
+#define SPI_CTL_SIZE32 0x00000400 /*SIZE: 32 bits */
+#define SPI_CTL_LSBF 0x00001000 /*LSB First */
+#define SPI_CTL_FCEN 0x00002000 /*Flow-Control Enable */
+#define SPI_CTL_FCCH 0x00004000 /*Flow-Control Channel Selection */
+#define SPI_CTL_FCPL 0x00008000 /*Flow-Control Polarity */
+#define SPI_CTL_FCWM 0x00030000 /*Flow-Control Water-Mark */
+#define SPI_CTL_FIFO0 0x00000000 /*FCWM: Tx empty or Rx Full */
+#define SPI_CTL_FIFO1 0x00010000 /*FCWM: Tx empty or Rx full (>=75%) */
+#define SPI_CTL_FIFO2 0x00020000 /*FCWM: Tx empty or Rx full (>=50%) */
+#define SPI_CTL_FMODE 0x00040000 /*Fast-mode Enable */
+#define SPI_CTL_MIOM 0x00300000 /*Multiple I/O Mode */
+#define SPI_CTL_MIO_DIS 0x00000000 /*MIOM: Disable */
+#define SPI_CTL_MIO_DUAL 0x00100000 /*MIOM: Enable DIOM (Dual I/O Mode) */
+#define SPI_CTL_MIO_QUAD 0x00200000 /*MIOM: Enable QUAD (Quad SPI Mode) */
+#define SPI_CTL_SOSI 0x00400000 /*Start on MOSI */
+#define SPI_CTL_MMWEM 0x40000000 /*Start on MMWEM */
+#define SPI_CTL_MMSE 0x80000000 /*Start on MMSE */
+/* SPI_RX_CONTROL */
+#define SPI_RXCTL_REN 0x00000001 /*Receive Channel Enable */
+#define SPI_RXCTL_RTI 0x00000004 /*Receive Transfer Initiate */
+#define SPI_RXCTL_RWCEN 0x00000008 /*Receive Word Counter Enable */
+#define SPI_RXCTL_RDR 0x00000070 /*Receive Data Request */
+#define SPI_RXCTL_RDR_DIS 0x00000000 /*RDR: Disabled */
+#define SPI_RXCTL_RDR_NE 0x00000010 /*RDR: RFIFO not empty */
+#define SPI_RXCTL_RDR_25 0x00000020 /*RDR: RFIFO 25% full */
+#define SPI_RXCTL_RDR_50 0x00000030 /*RDR: RFIFO 50% full */
+#define SPI_RXCTL_RDR_75 0x00000040 /*RDR: RFIFO 75% full */
+#define SPI_RXCTL_RDR_FULL 0x00000050 /*RDR: RFIFO full */
+#define SPI_RXCTL_RDO 0x00000100 /*Receive Data Over-Run */
+#define SPI_RXCTL_RRWM 0x00003000 /*FIFO Regular Water-Mark */
+#define SPI_RXCTL_RWM_0 0x00000000 /*RRWM: RFIFO Empty */
+#define SPI_RXCTL_RWM_25 0x00001000 /*RRWM: RFIFO 25% full */
+#define SPI_RXCTL_RWM_50 0x00002000 /*RRWM: RFIFO 50% full */
+#define SPI_RXCTL_RWM_75 0x00003000 /*RRWM: RFIFO 75% full */
+#define SPI_RXCTL_RUWM 0x00070000 /*FIFO Urgent Water-Mark */
+#define SPI_RXCTL_UWM_DIS 0x00000000 /*RUWM: Disabled */
+#define SPI_RXCTL_UWM_25 0x00010000 /*RUWM: RFIFO 25% full */
+#define SPI_RXCTL_UWM_50 0x00020000 /*RUWM: RFIFO 50% full */
+#define SPI_RXCTL_UWM_75 0x00030000 /*RUWM: RFIFO 75% full */
+#define SPI_RXCTL_UWM_FULL 0x00040000 /*RUWM: RFIFO full */
+/* SPI_TX_CONTROL */
+#define SPI_TXCTL_TEN 0x00000001 /*Transmit Channel Enable */
+#define SPI_TXCTL_TTI 0x00000004 /*Transmit Transfer Initiate */
+#define SPI_TXCTL_TWCEN 0x00000008 /*Transmit Word Counter Enable */
+#define SPI_TXCTL_TDR 0x00000070 /*Transmit Data Request */
+#define SPI_TXCTL_TDR_DIS 0x00000000 /*TDR: Disabled */
+#define SPI_TXCTL_TDR_NF 0x00000010 /*TDR: TFIFO not full */
+#define SPI_TXCTL_TDR_25 0x00000020 /*TDR: TFIFO 25% empty */
+#define SPI_TXCTL_TDR_50 0x00000030 /*TDR: TFIFO 50% empty */
+#define SPI_TXCTL_TDR_75 0x00000040 /*TDR: TFIFO 75% empty */
+#define SPI_TXCTL_TDR_EMPTY 0x00000050 /*TDR: TFIFO empty */
+#define SPI_TXCTL_TDU 0x00000100 /*Transmit Data Under-Run */
+#define SPI_TXCTL_TRWM 0x00003000 /*FIFO Regular Water-Mark */
+#define SPI_TXCTL_RWM_FULL 0x00000000 /*TRWM: TFIFO full */
+#define SPI_TXCTL_RWM_25 0x00001000 /*TRWM: TFIFO 25% empty */
+#define SPI_TXCTL_RWM_50 0x00002000 /*TRWM: TFIFO 50% empty */
+#define SPI_TXCTL_RWM_75 0x00003000 /*TRWM: TFIFO 75% empty */
+#define SPI_TXCTL_TUWM 0x00070000 /*FIFO Urgent Water-Mark */
+#define SPI_TXCTL_UWM_DIS 0x00000000 /*TUWM: Disabled */
+#define SPI_TXCTL_UWM_25 0x00010000 /*TUWM: TFIFO 25% empty */
+#define SPI_TXCTL_UWM_50 0x00020000 /*TUWM: TFIFO 50% empty */
+#define SPI_TXCTL_UWM_75 0x00030000 /*TUWM: TFIFO 75% empty */
+#define SPI_TXCTL_UWM_EMPTY 0x00040000 /*TUWM: TFIFO empty */
+/* SPI_CLOCK */
+#define SPI_CLK_BAUD 0x0000FFFF /*Baud Rate */
+/* SPI_DELAY */
+#define SPI_DLY_STOP 0x000000FF /*Transfer delay time */
+#define SPI_DLY_LEADX 0x00000100 /*Extended (1 SCK) LEAD Control */
+#define SPI_DLY_LAGX 0x00000200 /*Extended (1 SCK) LAG control */
+/* SPI_SSEL */
+#define SPI_SLVSEL_SSE1 0x00000002 /*SPISSEL1 Enable */
+#define SPI_SLVSEL_SSE2 0x00000004 /*SPISSEL2 Enable */
+#define SPI_SLVSEL_SSE3 0x00000008 /*SPISSEL3 Enable */
+#define SPI_SLVSEL_SSE4 0x00000010 /*SPISSEL4 Enable */
+#define SPI_SLVSEL_SSE5 0x00000020 /*SPISSEL5 Enable */
+#define SPI_SLVSEL_SSE6 0x00000040 /*SPISSEL6 Enable */
+#define SPI_SLVSEL_SSE7 0x00000080 /*SPISSEL7 Enable */
+#define SPI_SLVSEL_SSEL1 0x00000200 /*SPISSEL1 Value */
+#define SPI_SLVSEL_SSEL2 0x00000400 /*SPISSEL2 Value */
+#define SPI_SLVSEL_SSEL3 0x00000800 /*SPISSEL3 Value */
+#define SPI_SLVSEL_SSEL4 0x00001000 /*SPISSEL4 Value */
+#define SPI_SLVSEL_SSEL5 0x00002000 /*SPISSEL5 Value */
+#define SPI_SLVSEL_SSEL6 0x00004000 /*SPISSEL6 Value */
+#define SPI_SLVSEL_SSEL7 0x00008000 /*SPISSEL7 Value */
+/* SPI_RWC */
+#define SPI_RWC_VALUE 0x0000FFFF /*Received Word-Count */
+/* SPI_RWCR */
+#define SPI_RWCR_VALUE 0x0000FFFF /*Received Word-Count Reload */
+/* SPI_TWC */
+#define SPI_TWC_VALUE 0x0000FFFF /*Transmitted Word-Count */
+/* SPI_TWCR */
+#define SPI_TWCR_VALUE 0x0000FFFF /*Transmitted Word-Count Reload */
+/* SPI_IMASK */
+#define SPI_IMSK_RUWM 0x00000002 /*Receive Water-Mark Interrupt Mask */
+#define SPI_IMSK_TUWM 0x00000004 /*Transmit Water-Mark Interrupt Mask */
+#define SPI_IMSK_ROM 0x00000010 /*Receive Over-Run Interrupt Mask */
+#define SPI_IMSK_TUM 0x00000020 /*Transmit Under-Run Interrupt Mask */
+#define SPI_IMSK_TCM 0x00000040 /*Transmit Collision Interrupt Mask */
+#define SPI_IMSK_MFM 0x00000080 /*Mode Fault Interrupt Mask */
+#define SPI_IMSK_RSM 0x00000100 /*Receive Start Interrupt Mask */
+#define SPI_IMSK_TSM 0x00000200 /*Transmit Start Interrupt Mask */
+#define SPI_IMSK_RFM 0x00000400 /*Receive Finish Interrupt Mask */
+#define SPI_IMSK_TFM 0x00000800 /*Transmit Finish Interrupt Mask */
+/* SPI_IMASKCL */
+#define SPI_IMSK_CLR_RUW 0x00000002 /*Receive Water-Mark Interrupt Mask */
+#define SPI_IMSK_CLR_TUWM 0x00000004 /*Transmit Water-Mark Interrupt Mask */
+#define SPI_IMSK_CLR_ROM 0x00000010 /*Receive Over-Run Interrupt Mask */
+#define SPI_IMSK_CLR_TUM 0x00000020 /*Transmit Under-Run Interrupt Mask */
+#define SPI_IMSK_CLR_TCM 0x00000040 /*Transmit Collision Interrupt Mask */
+#define SPI_IMSK_CLR_MFM 0x00000080 /*Mode Fault Interrupt Mask */
+#define SPI_IMSK_CLR_RSM 0x00000100 /*Receive Start Interrupt Mask */
+#define SPI_IMSK_CLR_TSM 0x00000200 /*Transmit Start Interrupt Mask */
+#define SPI_IMSK_CLR_RFM 0x00000400 /*Receive Finish Interrupt Mask */
+#define SPI_IMSK_CLR_TFM 0x00000800 /*Transmit Finish Interrupt Mask */
+/* SPI_IMASKST */
+#define SPI_IMSK_SET_RUWM 0x00000002 /*Receive Water-Mark Interrupt Mask */
+#define SPI_IMSK_SET_TUWM 0x00000004 /*Transmit Water-Mark Interrupt Mask */
+#define SPI_IMSK_SET_ROM 0x00000010 /*Receive Over-Run Interrupt Mask */
+#define SPI_IMSK_SET_TUM 0x00000020 /*Transmit Under-Run Interrupt Mask */
+#define SPI_IMSK_SET_TCM 0x00000040 /*Transmit Collision Interrupt Mask */
+#define SPI_IMSK_SET_MFM 0x00000080 /*Mode Fault Interrupt Mask */
+#define SPI_IMSK_SET_RSM 0x00000100 /*Receive Start Interrupt Mask */
+#define SPI_IMSK_SET_TSM 0x00000200 /*Transmit Start Interrupt Mask */
+#define SPI_IMSK_SET_RFM 0x00000400 /*Receive Finish Interrupt Mask */
+#define SPI_IMSK_SET_TFM 0x00000800 /*Transmit Finish Interrupt Mask */
+/* SPI_STATUS */
+#define SPI_STAT_SPIF 0x00000001 /*SPI Finished */
+#define SPI_STAT_RUWM 0x00000002 /*Receive Water-Mark Breached */
+#define SPI_STAT_TUWM 0x00000004 /*Transmit Water-Mark Breached */
+#define SPI_STAT_ROE 0x00000010 /*Receive Over-Run Indication */
+#define SPI_STAT_TUE 0x00000020 /*Transmit Under-Run Indication */
+#define SPI_STAT_TCE 0x00000040 /*Transmit Collision Indication */
+#define SPI_STAT_MODF 0x00000080 /*Mode Fault Indication */
+#define SPI_STAT_RS 0x00000100 /*Receive Start Indication */
+#define SPI_STAT_TS 0x00000200 /*Transmit Start Indication */
+#define SPI_STAT_RF 0x00000400 /*Receive Finish Indication */
+#define SPI_STAT_TF 0x00000800 /*Transmit Finish Indication */
+#define SPI_STAT_RFS 0x00007000 /*SPI_RFIFO status */
+#define SPI_STAT_RFIFO_EMPTY 0x00000000 /*RFS: RFIFO Empty */
+#define SPI_STAT_RFIFO_25 0x00001000 /*RFS: RFIFO 25% Full */
+#define SPI_STAT_RFIFO_50 0x00002000 /*RFS: RFIFO 50% Full */
+#define SPI_STAT_RFIFO_75 0x00003000 /*RFS: RFIFO 75% Full */
+#define SPI_STAT_RFIFO_FULL 0x00004000 /*RFS: RFIFO Full */
+#define SPI_STAT_TFS 0x00070000 /*SPI_TFIFO status */
+#define SPI_STAT_TFIFO_FULL 0x00000000 /*TFS: TFIFO full */
+#define SPI_STAT_TFIFO_25 0x00010000 /*TFS: TFIFO 25% empty */
+#define SPI_STAT_TFIFO_50 0x00020000 /*TFS: TFIFO 50% empty */
+#define SPI_STAT_TFIFO_75 0x00030000 /*TFS: TFIFO 75% empty */
+#define SPI_STAT_TFIFO_EMPTY 0x00040000 /*TFS: TFIFO empty */
+#define SPI_STAT_FCS 0x00100000 /*Flow-Control Stall Indication */
+#define SPI_STAT_RFE 0x00400000 /*SPI_RFIFO Empty */
+#define SPI_STAT_TFF 0x00800000 /*SPI_TFIFO Full */
+/* SPI_ILAT */
+#define SPI_ILAT_RUWMI 0x00000002 /*Receive Water Mark Interrupt */
+#define SPI_ILAT_TUWMI 0x00000004 /*Transmit Water Mark Interrupt */
+#define SPI_ILAT_ROI 0x00000010 /*Receive Over-Run Indication */
+#define SPI_ILAT_TUI 0x00000020 /*Transmit Under-Run Indication */
+#define SPI_ILAT_TCI 0x00000040 /*Transmit Collision Indication */
+#define SPI_ILAT_MFI 0x00000080 /*Mode Fault Indication */
+#define SPI_ILAT_RSI 0x00000100 /*Receive Start Indication */
+#define SPI_ILAT_TSI 0x00000200 /*Transmit Start Indication */
+#define SPI_ILAT_RFI 0x00000400 /*Receive Finish Indication */
+#define SPI_ILAT_TFI 0x00000800 /*Transmit Finish Indication */
+/* SPI_ILATCL */
+#define SPI_ILAT_CLR_RUWMI 0x00000002 /*Receive Water Mark Interrupt */
+#define SPI_ILAT_CLR_TUWMI 0x00000004 /*Transmit Water Mark Interrupt */
+#define SPI_ILAT_CLR_ROI 0x00000010 /*Receive Over-Run Indication */
+#define SPI_ILAT_CLR_TUI 0x00000020 /*Transmit Under-Run Indication */
+#define SPI_ILAT_CLR_TCI 0x00000040 /*Transmit Collision Indication */
+#define SPI_ILAT_CLR_MFI 0x00000080 /*Mode Fault Indication */
+#define SPI_ILAT_CLR_RSI 0x00000100 /*Receive Start Indication */
+#define SPI_ILAT_CLR_TSI 0x00000200 /*Transmit Start Indication */
+#define SPI_ILAT_CLR_RFI 0x00000400 /*Receive Finish Indication */
+#define SPI_ILAT_CLR_TFI 0x00000800 /*Transmit Finish Indication */
+/* SPI_MMRDH */
+#define SPI_MMRDH_MERGE 0x04000000 /*Merge Enable */
+#define SPI_MMRDH_DMY_SZ 0x00007000 /*Bytes of Dummy */
+#define SPI_MMRDH_ADDR_PINS 0x00000800 /*Pins used for Address */
+#define SPI_MMRDH_ADDR_SZ 0x00000700 /*Bytes of Read Address */
+#define SPI_MMRDH_OPCODE 0x000000FF /*Read Opcode */
+
+#define SPI_MMRDH_TRIDMY_OFF 24 /*Bytes of Dummy offset */
+#define SPI_MMRDH_DMY_SZ_OFF 12 /*Bytes of Dummy offset */
+#define SPI_MMRDH_ADDR_SZ_OFF 8 /*Bytes of Read Address offset */
+
+#define BIT_SSEL_VAL(x) ((1 << 8) << (x)) /* Slave Select input value bit */
+#define BIT_SSEL_EN(x) (1 << (x)) /* Slave Select enable bit*/
+
+struct adi_spi_regs {
+ u32 revid;
+ u32 control;
+ u32 rx_control;
+ u32 tx_control;
+ u32 clock;
+ u32 delay;
+ u32 ssel;
+ u32 rwc;
+ u32 rwcr;
+ u32 twc;
+ u32 twcr;
+ u32 reserved0;
+ u32 emask;
+ u32 emaskcl;
+ u32 emaskst;
+ u32 reserved1;
+ u32 status;
+ u32 elat;
+ u32 elatcl;
+ u32 reserved2;
+ u32 rfifo;
+ u32 reserved3;
+ u32 tfifo;
+ u32 reserved4;
+ u32 mmrdh;
+ u32 mmtop;
+};
+
+struct adi_spi_platdata {
+ u32 max_hz;
+ u32 bus_num;
+ struct adi_spi_regs __iomem *regs;
+};
+
+struct adi_spi_priv {
+ u32 control;
+ u32 clock;
+ u32 bus_num;
+ u32 max_cs;
+ struct adi_spi_regs __iomem *regs;
+};
+
+/**
+ * By convention, this driver uses the same CS numbering that is used with the SSEL bit
+ * definitions (both here and in the TRM on which this is based), which are 1-indexed not
+ * 0-indexed. The valid CS range is therefore [1,max_cs], in contrast with other drivers
+ * where it is [0,max_cs-1].
+ */
+static int adi_spi_cs_info(struct udevice *bus, uint cs,
+ struct spi_cs_info *info)
+{
+ struct adi_spi_priv *priv = dev_get_priv(bus);
+
+ if (cs == 0 || cs > priv->max_cs) {
+ dev_err(bus, "invalid chipselect %u\n", cs);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int adi_spi_of_to_plat(struct udevice *bus)
+{
+ struct adi_spi_platdata *plat = dev_get_plat(bus);
+ fdt_addr_t addr;
+
+ plat->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 500000);
+ plat->bus_num = dev_read_u32_default(bus, "bus-num", 0);
+ addr = dev_read_addr(bus);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->regs = map_sysmem(addr, sizeof(*plat->regs));
+
+ return 0;
+}
+
+static int adi_spi_probe(struct udevice *bus)
+{
+ struct adi_spi_platdata *plat = dev_get_plat(bus);
+ struct adi_spi_priv *priv = dev_get_priv(bus);
+
+ priv->bus_num = plat->bus_num;
+ priv->regs = plat->regs;
+ priv->max_cs = dev_read_u32_default(bus, "num-cs", MAX_CTRL_CS);
+
+ iowrite32(0x0, &plat->regs->control);
+ iowrite32(0x0, &plat->regs->rx_control);
+ iowrite32(0x0, &plat->regs->tx_control);
+
+ return 0;
+}
+
+static int adi_spi_remove(struct udevice *dev)
+{
+ return -ENODEV;
+}
+
+static int adi_spi_claim_bus(struct udevice *dev)
+{
+ struct adi_spi_priv *priv;
+ struct udevice *bus = dev->parent;
+
+ priv = dev_get_priv(bus);
+
+ debug("%s: control:%i clock:%i\n",
+ __func__, priv->control, priv->clock);
+
+ iowrite32(priv->control, &priv->regs->control);
+ iowrite32(priv->clock, &priv->regs->clock);
+ iowrite32(0x0, &priv->regs->delay);
+
+ return 0;
+}
+
+static int adi_spi_release_bus(struct udevice *dev)
+{
+ struct adi_spi_priv *priv;
+ struct udevice *bus = dev->parent;
+
+ priv = dev_get_priv(bus);
+
+ debug("%s: control:%i clock:%i\n",
+ __func__, priv->control, priv->clock);
+
+ iowrite32(0x0, &priv->regs->rx_control);
+ iowrite32(0x0, &priv->regs->tx_control);
+ iowrite32(0x0, &priv->regs->control);
+
+ return 0;
+}
+
+void adi_spi_enable_ssel(struct adi_spi_priv *priv, int cs)
+{
+ setbits_32(&priv->regs->ssel, BIT_SSEL_EN(cs));
+}
+
+void adi_spi_set_ssel(struct adi_spi_priv *priv, int cs, int high)
+{
+ if (high)
+ setbits_32(&priv->regs->ssel, BIT_SSEL_VAL(cs));
+ else
+ clrbits_32(&priv->regs->ssel, BIT_SSEL_VAL(cs));
+}
+
+void adi_spi_cs_activate(struct adi_spi_priv *priv, struct dm_spi_slave_plat *slave_plat)
+{
+ bool high = slave_plat->mode & SPI_CS_HIGH;
+
+ adi_spi_set_ssel(priv, slave_plat->cs[0], high);
+ adi_spi_enable_ssel(priv, slave_plat->cs[0]);
+}
+
+void adi_spi_cs_deactivate(struct adi_spi_priv *priv, struct dm_spi_slave_plat *slave_plat)
+{
+ bool high = slave_plat->mode & SPI_CS_HIGH;
+
+ /* invert CS for matching SSEL to deactivate */
+ adi_spi_set_ssel(priv, slave_plat->cs[0], !high);
+}
+
+static void discard_rx_fifo_contents(struct adi_spi_regs *regs)
+{
+ while (!(ioread32(&regs->status) & SPI_STAT_RFE))
+ ioread32(&regs->rfifo);
+}
+
+static int adi_spi_fifo_mio_xfer(struct adi_spi_priv *priv, const u8 *tx, u8 *rx,
+ uint bytes, uint32_t mio_mode)
+{
+ u8 value;
+
+ /* switch current SPI transfer to mio SPI mode */
+ clrsetbits_32(&priv->regs->control, SPI_CTL_SOSI, mio_mode);
+ /*
+ * Data can only be transferred in one direction in multi-io SPI
+ * modes, trigger the transfer in respective direction.
+ */
+ if (rx) {
+ iowrite32(0x0, &priv->regs->tx_control);
+ iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI, &priv->regs->rx_control);
+
+ while (bytes--) {
+ while (ioread32(&priv->regs->status) &
+ SPI_STAT_RFE)
+ if (ctrlc())
+ return -1;
+ value = ioread32(&priv->regs->rfifo);
+ *rx++ = value;
+ }
+ } else if (tx) {
+ iowrite32(0x0, &priv->regs->rx_control);
+ iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &priv->regs->tx_control);
+
+ while (bytes--) {
+ value = *tx++;
+ iowrite32(value, &priv->regs->tfifo);
+ while (ioread32(&priv->regs->status) &
+ SPI_STAT_TFF)
+ if (ctrlc())
+ return -1;
+ }
+
+ /* Wait till the tfifo is empty */
+ while ((ioread32(&priv->regs->status) & SPI_STAT_TFS) != SPI_STAT_TFIFO_EMPTY)
+ if (ctrlc())
+ return -1;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+static int adi_spi_fifo_1x_xfer(struct adi_spi_priv *priv, const u8 *tx, u8 *rx,
+ uint bytes)
+{
+ u8 value;
+
+ /*
+ * Set current SPI transfer in normal mode and trigger
+ * the bi-direction transfer by tx write operation.
+ */
+ iowrite32(priv->control, &priv->regs->control);
+ iowrite32(SPI_RXCTL_REN, &priv->regs->rx_control);
+ iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, &priv->regs->tx_control);
+
+ while (bytes--) {
+ value = (tx ? *tx++ : SPI_IDLE_VAL);
+ debug("%s: tx:%x ", __func__, value);
+ iowrite32(value, &priv->regs->tfifo);
+ while (ioread32(&priv->regs->status) & SPI_STAT_RFE)
+ if (ctrlc())
+ return -1;
+ value = ioread32(&priv->regs->rfifo);
+ if (rx)
+ *rx++ = value;
+ debug("rx:%x\n", value);
+ }
+ return 0;
+}
+
+static int adi_spi_fifo_xfer(struct adi_spi_priv *priv, int buswidth,
+ const u8 *tx, u8 *rx, uint bytes)
+{
+ switch (buswidth) {
+ case 1:
+ return adi_spi_fifo_1x_xfer(priv, tx, rx, bytes);
+ case 2:
+ return adi_spi_fifo_mio_xfer(priv, tx, rx, bytes, SPI_CTL_MIO_DUAL);
+ case 4:
+ return adi_spi_fifo_mio_xfer(priv, tx, rx, bytes, SPI_CTL_MIO_QUAD);
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static int adi_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct adi_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+
+ const u8 *tx = dout;
+ u8 *rx = din;
+ uint bytes = bitlen / 8;
+ int ret = 0;
+
+ debug("%s: bus_num:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
+ priv->bus_num, slave_plat->cs[0], bitlen, bytes, flags);
+
+ if (flags & SPI_XFER_BEGIN)
+ adi_spi_cs_activate(priv, slave_plat);
+
+ if (bitlen == 0)
+ goto done;
+
+ /* we can only do 8 bit transfers */
+ if (bitlen % 8) {
+ flags |= SPI_XFER_END;
+ goto done;
+ }
+
+ /* Discard invalid rx data and empty rfifo */
+ discard_rx_fifo_contents(priv->regs);
+
+ ret = adi_spi_fifo_1x_xfer(priv, tx, rx, bytes);
+
+ done:
+ if (flags & SPI_XFER_END)
+ adi_spi_cs_deactivate(priv, slave_plat);
+
+ return ret;
+}
+
+static int adi_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct adi_spi_platdata *plat = dev_get_plat(bus);
+ struct adi_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+ u32 clock, spi_base_clk;
+ struct clk spi_clk;
+
+ ret = clk_get_by_name(bus, "spi", &spi_clk);
+ if (ret < 0) {
+ dev_err(bus, "Can't get SPI clk: %d\n", ret);
+ return ret;
+ }
+ spi_base_clk = clk_get_rate(&spi_clk);
+
+ if (speed > plat->max_hz)
+ speed = plat->max_hz;
+
+ if (speed > spi_base_clk)
+ return -ENODEV;
+
+ clock = spi_base_clk / speed;
+ if (clock)
+ clock--;
+
+ priv->clock = clock;
+
+ debug("%s: priv->clock: %x, speed: %x, get_spi_clk(): %x\n",
+ __func__, clock, speed, spi_base_clk);
+
+ return 0;
+}
+
+static int adi_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct adi_spi_priv *priv = dev_get_priv(bus);
+ u32 reg;
+
+ reg = SPI_CTL_EN | SPI_CTL_MSTR;
+ if (mode & SPI_CPHA)
+ reg |= SPI_CTL_CPHA;
+ if (mode & SPI_CPOL)
+ reg |= SPI_CTL_CPOL;
+ if (mode & SPI_LSB_FIRST)
+ reg |= SPI_CTL_LSBF;
+ reg &= ~SPI_CTL_ASSEL;
+
+ priv->control = reg;
+
+ debug("%s: control=%d, cs_pol=%d\n", __func__, reg, mode & SPI_CS_HIGH ? 1 : 0);
+
+ return 0;
+}
+
+/**
+ * U-boot's version of spi-mem does not support mixed bus-width
+ * commands nor anything more than 1x mode.
+ * Using a custom exec_op implementation, we can support it.
+ */
+static int adi_spi_mem_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ int rv = 0;
+ struct udevice *bus = slave->dev->parent;
+ struct adi_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev);
+ u8 tmpbuf[64];
+ int i;
+
+ if ((op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes) >
+ sizeof(tmpbuf))
+ return -ENOMEM;
+
+ for (i = 0; i < op->cmd.nbytes; i++)
+ tmpbuf[i] = op->cmd.opcode >>
+ (8 * (op->cmd.nbytes - i - 1));
+ for (i = 0; i < op->addr.nbytes; i++)
+ tmpbuf[i + op->cmd.nbytes] = op->addr.val >>
+ (8 * (op->addr.nbytes - i - 1));
+ memset(tmpbuf + op->addr.nbytes + op->cmd.nbytes, 0xff,
+ op->dummy.nbytes);
+
+ adi_spi_cs_activate(priv, slave_plat);
+ discard_rx_fifo_contents(priv->regs);
+
+ if (op->cmd.nbytes) {
+ rv = adi_spi_fifo_xfer(priv, op->cmd.buswidth,
+ tmpbuf, NULL, op->cmd.nbytes);
+ if (rv != 0)
+ goto cleanup;
+ }
+
+ if (op->addr.nbytes) {
+ rv = adi_spi_fifo_xfer(priv, op->addr.buswidth,
+ tmpbuf + op->cmd.nbytes, NULL,
+ op->addr.nbytes);
+ if (rv != 0)
+ goto cleanup;
+ }
+
+ if (op->dummy.nbytes) {
+ rv = adi_spi_fifo_xfer(priv, op->dummy.buswidth,
+ tmpbuf + op->cmd.nbytes +
+ op->addr.nbytes,
+ NULL, op->dummy.nbytes);
+ if (rv != 0)
+ goto cleanup;
+ }
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ rv = adi_spi_fifo_xfer(priv, op->data.buswidth,
+ NULL, op->data.buf.in,
+ op->data.nbytes);
+ else if (op->data.dir == SPI_MEM_DATA_OUT)
+ rv = adi_spi_fifo_xfer(priv, op->data.buswidth,
+ op->data.buf.out, NULL,
+ op->data.nbytes);
+
+cleanup:
+ adi_spi_cs_deactivate(priv, slave_plat);
+ return rv;
+}
+
+static const struct spi_controller_mem_ops adi_spi_mem_ops = {
+ .exec_op = adi_spi_mem_exec_op,
+};
+
+static const struct dm_spi_ops adi_spi_ops = {
+ .claim_bus = adi_spi_claim_bus,
+ .release_bus = adi_spi_release_bus,
+ .xfer = adi_spi_xfer,
+ .set_speed = adi_spi_set_speed,
+ .set_mode = adi_spi_set_mode,
+ .cs_info = adi_spi_cs_info,
+ .mem_ops = &adi_spi_mem_ops,
+};
+
+static const struct udevice_id adi_spi_ids[] = {
+ { .compatible = "adi,spi3" },
+ { }
+};
+
+U_BOOT_DRIVER(adi_spi3) = {
+ .name = "adi_spi3",
+ .id = UCLASS_SPI,
+ .of_match = adi_spi_ids,
+ .ops = &adi_spi_ops,
+ .of_to_plat = adi_spi_of_to_plat,
+ .probe = adi_spi_probe,
+ .remove = adi_spi_remove,
+ .plat_auto = sizeof(struct adi_spi_platdata),
+ .priv_auto = sizeof(struct adi_spi_priv),
+ .per_child_auto = sizeof(struct spi_slave),
+};
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 3efb661803b..8aa7a83aef4 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -10,11 +10,13 @@
*/
#include <malloc.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
+#include <log.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
@@ -258,6 +260,7 @@ struct atmel_qspi_caps {
struct atmel_qspi_priv_ops;
+#define MAX_CS_COUNT 2
struct atmel_qspi {
void __iomem *regs;
void __iomem *mem;
@@ -267,6 +270,7 @@ struct atmel_qspi {
struct udevice *dev;
ulong bus_clk_rate;
u32 mr;
+ struct gpio_desc cs_gpios[MAX_CS_COUNT];
};
struct atmel_qspi_priv_ops {
@@ -395,6 +399,26 @@ static void atmel_qspi_write(u32 value, struct atmel_qspi *aq, u32 offset)
writel(value, aq->regs + offset);
}
+static int atmel_qspi_reg_sync(struct atmel_qspi *aq)
+{
+ u32 val;
+
+ return readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_SYNCBSY),
+ ATMEL_QSPI_SYNC_TIMEOUT);
+}
+
+static int atmel_qspi_update_config(struct atmel_qspi *aq)
+{
+ int ret;
+
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR);
+ return atmel_qspi_reg_sync(aq);
+}
+
static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op,
const struct atmel_qspi_mode *mode)
{
@@ -458,6 +482,29 @@ static bool atmel_qspi_supports_op(struct spi_slave *slave,
return true;
}
+/*
+ * Switch QSPI controller between regular SPI mode or Serial Memory Mode (SMM).
+ */
+static int atmel_qspi_set_serial_memory_mode(struct atmel_qspi *aq,
+ bool enable)
+{
+ int ret = 0;
+
+ /* only write if designated state differs from current state */
+ if (!!(aq->mr & QSPI_MR_SMM) != enable) {
+ if (enable)
+ aq->mr |= QSPI_MR_SMM;
+ else
+ aq->mr &= ~QSPI_MR_SMM;
+ atmel_qspi_write(aq->mr, aq, QSPI_MR);
+
+ if (aq->caps->has_gclk)
+ ret = atmel_qspi_update_config(aq);
+ }
+
+ return ret;
+}
+
static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
const struct spi_mem_op *op, u32 *offset)
{
@@ -474,7 +521,7 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
return mode;
ifr |= atmel_qspi_modes[mode].config;
- if (op->dummy.buswidth && op->dummy.nbytes)
+ if (op->dummy.nbytes)
dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
/*
@@ -529,43 +576,39 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
if (dummy_cycles)
ifr |= QSPI_IFR_NBDUM(dummy_cycles);
- /* Set data enable */
- if (op->data.nbytes)
+ /* Set data enable and data transfer type. */
+ if (op->data.nbytes) {
ifr |= QSPI_IFR_DATAEN;
- /*
- * If the QSPI controller is set in regular SPI mode, set it in
- * Serial Memory Mode (SMM).
- */
- if (aq->mr != QSPI_MR_SMM) {
- atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
- aq->mr = QSPI_MR_SMM;
+ if (op->addr.nbytes)
+ ifr |= QSPI_IFR_TFRTYP_MEM;
}
+ mode = atmel_qspi_set_serial_memory_mode(aq, true);
+ if (mode < 0)
+ return mode;
+
/* Clear pending interrupts */
(void)atmel_qspi_read(aq, QSPI_SR);
- if (aq->caps->has_ricr) {
- if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN)
- ifr |= QSPI_IFR_APBTFRTYP_READ;
-
- /* Set QSPI Instruction Frame registers */
+ /* Set QSPI Instruction Frame registers. */
+ if (op->addr.nbytes && !op->data.nbytes)
atmel_qspi_write(iar, aq, QSPI_IAR);
+
+ if (aq->caps->has_ricr) {
if (op->data.dir == SPI_MEM_DATA_IN)
atmel_qspi_write(icr, aq, QSPI_RICR);
else
atmel_qspi_write(icr, aq, QSPI_WICR);
- atmel_qspi_write(ifr, aq, QSPI_IFR);
} else {
- if (op->data.dir == SPI_MEM_DATA_OUT)
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR;
- /* Set QSPI Instruction Frame registers */
- atmel_qspi_write(iar, aq, QSPI_IAR);
atmel_qspi_write(icr, aq, QSPI_ICR);
- atmel_qspi_write(ifr, aq, QSPI_IFR);
}
+ atmel_qspi_write(ifr, aq, QSPI_IFR);
+
return 0;
}
@@ -597,26 +640,6 @@ static int atmel_qspi_transfer(struct atmel_qspi *aq,
ATMEL_QSPI_TIMEOUT);
}
-static int atmel_qspi_reg_sync(struct atmel_qspi *aq)
-{
- u32 val;
-
- return readl_poll_timeout(aq->regs + QSPI_SR2, val,
- !(val & QSPI_SR2_SYNCBSY),
- ATMEL_QSPI_SYNC_TIMEOUT);
-}
-
-static int atmel_qspi_update_config(struct atmel_qspi *aq)
-{
- int ret;
-
- ret = atmel_qspi_reg_sync(aq);
- if (ret)
- return ret;
- atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR);
- return atmel_qspi_reg_sync(aq);
-}
-
static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq,
const struct spi_mem_op *op, u32 *offset)
{
@@ -668,17 +691,9 @@ static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq,
ifr |= QSPI_IFR_TFRTYP_MEM;
}
- /*
- * If the QSPI controller is set in regular SPI mode, set it in
- * Serial Memory Mode (SMM).
- */
- if (aq->mr != QSPI_MR_SMM) {
- atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR);
- ret = atmel_qspi_update_config(aq);
- if (ret)
- return ret;
- aq->mr = QSPI_MR_SMM;
- }
+ ret = atmel_qspi_set_serial_memory_mode(aq, true);
+ if (ret < 0)
+ return ret;
/* Clear pending interrupts */
(void)atmel_qspi_read(aq, QSPI_SR);
@@ -902,11 +917,10 @@ static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz)
}
/* Set the QSPI controller by default in Serial Memory Mode */
- atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR);
- ret = atmel_qspi_update_config(aq);
- if (ret)
+ aq->mr |= QSPI_MR_DQSDLYEN;
+ ret = atmel_qspi_set_serial_memory_mode(aq, true);
+ if (ret < 0)
return ret;
- aq->mr = QSPI_MR_SMM;
/* Enable the QSPI controller. */
ret = atmel_qspi_reg_sync(aq);
@@ -930,6 +944,135 @@ static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz)
return ret;
}
+static int atmel_qspi_claim_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct atmel_qspi *aq = dev_get_priv(bus);
+ int ret;
+
+ aq->mr &= ~QSPI_MR_CSMODE_MASK;
+ aq->mr |= QSPI_MR_CSMODE_LASTXFER | QSPI_MR_WDRBT;
+ atmel_qspi_write(aq->mr, aq, QSPI_MR);
+
+ ret = atmel_qspi_set_serial_memory_mode(aq, false);
+ if (ret)
+ return log_ret(ret);
+
+ /* de-assert all chip selects */
+ if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) {
+ if (dm_gpio_is_valid(&aq->cs_gpios[i]))
+ dm_gpio_set_value(&aq->cs_gpios[i], 0);
+ }
+ }
+
+ atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+
+ return 0;
+}
+
+static int atmel_qspi_release_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct atmel_qspi *aq = dev_get_priv(bus);
+
+ /* de-assert all chip selects */
+ if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) {
+ if (dm_gpio_is_valid(&aq->cs_gpios[i]))
+ dm_gpio_set_value(&aq->cs_gpios[i], 0);
+ }
+ }
+
+ atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+
+ return 0;
+}
+
+static int atmel_qspi_set_cs(struct udevice *dev, int value)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct atmel_qspi *aq = dev_get_priv(bus);
+ int cs = spi_chip_select(dev);
+
+ if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ if (!dm_gpio_is_valid(&aq->cs_gpios[cs]))
+ return log_ret(-ENOENT);
+
+ return dm_gpio_set_value(&aq->cs_gpios[cs], value);
+ } else {
+ return -ENOENT;
+ }
+}
+
+static int atmel_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct atmel_qspi *aq = dev_get_priv(bus);
+ unsigned int len, len_rx, len_tx;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ u32 reg;
+ int ret;
+
+ if (bitlen == 0)
+ goto out;
+
+ if (bitlen % 8) {
+ flags |= SPI_XFER_END;
+ goto out;
+ }
+
+ len = bitlen / 8;
+
+ if (flags & SPI_XFER_BEGIN) {
+ ret = atmel_qspi_set_cs(dev, 1);
+ if (ret)
+ return log_ret(ret);
+ reg = atmel_qspi_read(aq, QSPI_RD);
+ }
+
+ for (len_tx = 0, len_rx = 0; len_rx < len; ) {
+ u32 status = atmel_qspi_read(aq, QSPI_SR);
+ u8 value;
+
+ if (status & QSPI_SR_OVRES)
+ return log_ret(-1);
+
+ if (len_tx < len && (status & QSPI_SR_TDRE)) {
+ if (txp)
+ value = *txp++;
+ else
+ value = 0;
+ atmel_qspi_write(value, aq, QSPI_TD);
+ len_tx++;
+ }
+
+ if (status & QSPI_SR_RDRF) {
+ value = atmel_qspi_read(aq, QSPI_RD);
+ if (rxp)
+ *rxp++ = value;
+ len_rx++;
+ }
+ }
+
+out:
+ if (flags & SPI_XFER_END) {
+ readl_poll_timeout(aq->regs + QSPI_SR, reg,
+ reg & QSPI_SR_TXEMPTY,
+ ATMEL_QSPI_TIMEOUT);
+
+ atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
+
+ ret = atmel_qspi_set_cs(dev, 0);
+ if (ret)
+ return log_ret(ret);
+ }
+
+ return 0;
+}
+
static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
{
struct atmel_qspi *aq = dev_get_priv(bus);
@@ -939,6 +1082,7 @@ static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
return atmel_qspi_sama7g5_set_speed(bus, hz);
/* Compute the QSPI baudrate */
+ dev_dbg(bus, "bus_clk_rate: %lu, hz: %u\n", aq->bus_clk_rate, hz);
scbr = DIV_ROUND_UP(aq->bus_clk_rate, hz);
if (scbr > 0)
scbr--;
@@ -1046,10 +1190,6 @@ static int atmel_qspi_init(struct atmel_qspi *aq)
/* Reset the QSPI controller */
atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
- /* Set the QSPI controller by default in Serial Memory Mode */
- atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
- aq->mr = QSPI_MR_SMM;
-
/* Enable the QSPI controller */
atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
@@ -1075,7 +1215,7 @@ static int atmel_qspi_probe(struct udevice *dev)
aq->caps = (struct atmel_qspi_caps *)dev_get_driver_data(dev);
if (!aq->caps) {
dev_err(dev, "Could not retrieve QSPI caps\n");
- return -EINVAL;
+ return log_ret(-EINVAL);
};
if (aq->caps->has_gclk)
@@ -1083,36 +1223,53 @@ static int atmel_qspi_probe(struct udevice *dev)
else
aq->ops = &atmel_qspi_priv_ops;
+ if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ ret = gpio_request_list_by_name(dev, "cs-gpios", aq->cs_gpios,
+ ARRAY_SIZE(aq->cs_gpios), 0);
+ if (ret < 0) {
+ pr_err("Can't get %s gpios! Error: %d", dev->name, ret);
+ return log_ret(ret);
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) {
+ if (!dm_gpio_is_valid(&aq->cs_gpios[i]))
+ continue;
+
+ dm_gpio_set_dir_flags(&aq->cs_gpios[i],
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ }
+ }
+
/* Map the registers */
ret = dev_read_resource_byname(dev, "qspi_base", &res);
if (ret) {
dev_err(dev, "missing registers\n");
- return ret;
+ return log_ret(ret);
}
aq->regs = devm_ioremap(dev, res.start, resource_size(&res));
if (IS_ERR(aq->regs))
- return PTR_ERR(aq->regs);
+ return log_ret(PTR_ERR(aq->regs));
/* Map the AHB memory */
ret = dev_read_resource_byname(dev, "qspi_mmap", &res);
if (ret) {
dev_err(dev, "missing AHB memory\n");
- return ret;
+ return log_ret(ret);
}
aq->mem = devm_ioremap(dev, res.start, resource_size(&res));
if (IS_ERR(aq->mem))
- return PTR_ERR(aq->mem);
+ return log_ret(PTR_ERR(aq->mem));
aq->mmap_size = resource_size(&res);
ret = atmel_qspi_enable_clk(dev);
if (ret)
- return ret;
+ return log_ret(ret);
aq->dev = dev;
- return atmel_qspi_init(aq);
+ return log_ret(atmel_qspi_init(aq));
}
static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
@@ -1121,9 +1278,12 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
};
static const struct dm_spi_ops atmel_qspi_ops = {
+ .claim_bus = atmel_qspi_claim_bus,
+ .release_bus = atmel_qspi_release_bus,
+ .xfer = atmel_qspi_xfer,
+ .mem_ops = &atmel_qspi_mem_ops,
.set_speed = atmel_qspi_set_speed,
.set_mode = atmel_qspi_set_mode,
- .mem_ops = &atmel_qspi_mem_ops,
};
static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {};
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index a8ec2f4f7b4..50bd7be5640 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -124,8 +124,19 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8 *rxd = din;
int cpha = !!(priv->mode & SPI_CPHA);
int cidle = !!(priv->mode & SPI_CPOL);
+ int txrx = plat->flags;
unsigned int j;
+ if (priv->mode & SPI_3WIRE) {
+ if (txd && rxd)
+ return -EINVAL;
+
+ txrx = txd ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
+ dm_gpio_set_dir_flags(&plat->mosi,
+ txd ? GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE :
+ GPIOD_IS_IN | GPIOD_PULL_UP);
+ }
+
debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n",
dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd,
bitlen);
@@ -160,7 +171,7 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
*/
if (cpha)
soft_spi_scl(dev, !cidle);
- if ((plat->flags & SPI_MASTER_NO_TX) == 0)
+ if ((txrx & SPI_MASTER_NO_TX) == 0)
soft_spi_sda(dev, !!(tmpdout & 0x80));
udelay(plat->spi_delay_us);
@@ -174,8 +185,10 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
else
soft_spi_scl(dev, cidle);
tmpdin <<= 1;
- if ((plat->flags & SPI_MASTER_NO_RX) == 0)
- tmpdin |= dm_gpio_get_value(&plat->miso);
+ if ((txrx & SPI_MASTER_NO_RX) == 0)
+ tmpdin |= dm_gpio_get_value((priv->mode & SPI_3WIRE) ?
+ &plat->mosi :
+ &plat->miso);
tmpdout <<= 1;
udelay(plat->spi_delay_us);
diff --git a/drivers/sysinfo/Kconfig b/drivers/sysinfo/Kconfig
index 2030e4babc9..df83df69ffb 100644
--- a/drivers/sysinfo/Kconfig
+++ b/drivers/sysinfo/Kconfig
@@ -31,6 +31,13 @@ config SYSINFO_RCAR3
help
Support querying SoC version information for Renesas R-Car Gen3.
+config SYSINFO_IOT2050
+ bool "Enable sysinfo driver for the Siemens IOT2050"
+ depends on TARGET_IOT2050_A53
+ default y if TARGET_IOT2050_A53
+ help
+ Support querying device information for Siemens IOT2050.
+
config SYSINFO_SANDBOX
bool "Enable sysinfo driver for the Sandbox board"
help
diff --git a/drivers/sysinfo/Makefile b/drivers/sysinfo/Makefile
index 680dde77fe8..26ca3150999 100644
--- a/drivers/sysinfo/Makefile
+++ b/drivers/sysinfo/Makefile
@@ -5,6 +5,7 @@
obj-y += sysinfo-uclass.o
obj-$(CONFIG_SYSINFO_GAZERBEAM) += gazerbeam.o
obj-$(CONFIG_SYSINFO_GPIO) += gpio.o
+obj-$(CONFIG_SYSINFO_IOT2050) += iot2050.o
obj-$(CONFIG_SYSINFO_RCAR3) += rcar3.o
obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o
obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.o
diff --git a/drivers/sysinfo/iot2050.c b/drivers/sysinfo/iot2050.c
new file mode 100644
index 00000000000..579a9f4711d
--- /dev/null
+++ b/drivers/sysinfo/iot2050.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Siemens AG, 2025
+ */
+
+#include <dm.h>
+#include <sysinfo.h>
+#include <net.h>
+#include <u-boot/uuid.h>
+#include <asm/arch/hardware.h>
+
+#include "iot2050.h"
+
+#define IOT2050_INFO_MAGIC 0x20502050
+
+#define IOT2050_UUID_STR_LEN (32)
+
+struct iot2050_info {
+ u32 magic;
+ u16 size;
+ char name[20 + 1];
+ char serial[16 + 1];
+ char mlfb[18 + 1];
+ char uuid[IOT2050_UUID_STR_LEN + 1];
+ char a5e[18 + 1];
+ u8 mac_addr_cnt;
+ u8 mac_addr[8][ARP_HLEN];
+ char seboot_version[40 + 1];
+ u8 padding[3];
+ u32 ddr_size_mb;
+} __packed;
+
+/**
+ * struct sysinfo_iot2050_priv - sysinfo private data
+ * @info: iot2050 board info
+ */
+struct sysinfo_iot2050_priv {
+ struct iot2050_info *info;
+ u8 uuid_smbios[16];
+};
+
+static int sysinfo_iot2050_detect(struct udevice *dev)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+
+ if (!priv->info || priv->info->magic != IOT2050_INFO_MAGIC)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int sysinfo_iot2050_get_str(struct udevice *dev, int id, size_t size,
+ char *val)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case BOARD_NAME:
+ case SYSID_SM_BASEBOARD_VERSION:
+ strlcpy(val, priv->info->name, size);
+ break;
+ case SYSID_SM_SYSTEM_SERIAL:
+ strlcpy(val, priv->info->serial, size);
+ break;
+ case BOARD_MLFB:
+ case SYSID_SM_SYSTEM_VERSION:
+ strlcpy(val, priv->info->mlfb, size);
+ break;
+ case BOARD_UUID:
+ strlcpy(val, priv->info->uuid, size);
+ break;
+ case BOARD_A5E:
+ case SYSID_SM_BASEBOARD_PRODUCT:
+ strlcpy(val, priv->info->a5e, size);
+ break;
+ case BOARD_SEBOOT_VER:
+ case SYSID_PRIOR_STAGE_VERSION:
+ strlcpy(val, priv->info->seboot_version, size);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ val[size - 1] = '\0';
+ return 0;
+}
+
+static int sysinfo_iot2050_get_int(struct udevice *dev, int id, int *val)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case SYSID_BOARD_RAM_SIZE_MB:
+ *val = priv->info->ddr_size_mb;
+ return 0;
+ default:
+ return -EINVAL;
+ };
+}
+
+static int sysinfo_iot2050_get_data(struct udevice *dev, int id, void **data,
+ size_t *size)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case SYSID_SM_SYSTEM_UUID:
+ *data = priv->uuid_smbios;
+ *size = 16;
+ return 0;
+ default:
+ return -EINVAL;
+ };
+}
+
+static int sysinfo_iot2050_get_item_count(struct udevice *dev, int id)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case SYSID_BOARD_MAC_ADDR:
+ return priv->info->mac_addr_cnt;
+ default:
+ return -EINVAL;
+ };
+}
+
+static int sysinfo_iot2050_get_data_by_index(struct udevice *dev, int id,
+ int index, void **data,
+ size_t *size)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case SYSID_BOARD_MAC_ADDR:
+ if (index >= priv->info->mac_addr_cnt)
+ return -EINVAL;
+ *data = priv->info->mac_addr[index];
+ *size = ARP_HLEN;
+ return 0;
+ default:
+ return -EINVAL;
+ };
+}
+
+static const struct sysinfo_ops sysinfo_iot2050_ops = {
+ .detect = sysinfo_iot2050_detect,
+ .get_str = sysinfo_iot2050_get_str,
+ .get_int = sysinfo_iot2050_get_int,
+ .get_data = sysinfo_iot2050_get_data,
+ .get_item_count = sysinfo_iot2050_get_item_count,
+ .get_data_by_index = sysinfo_iot2050_get_data_by_index,
+};
+
+/**
+ * @brief Convert the IOT2050 UUID string to the SMBIOS format
+ *
+ * @param uuid_raw The IOT2050 UUID string parsed from the eeprom
+ * @param uuid_smbios The buffer to hold the SMBIOS formatted UUID
+ */
+static void sysinfo_iot2050_convert_uuid(const char *uuid_iot2050,
+ u8 *uuid_smbios)
+{
+ char uuid_rfc4122_str[IOT2050_UUID_STR_LEN + 4 + 1] = {0};
+ char *tmp = uuid_rfc4122_str;
+
+ for (int i = 0; i < 16; i++) {
+ memcpy(tmp, uuid_iot2050 + i * 2, 2);
+ tmp += 2;
+ if (i == 3 || i == 5 || i == 7 || i == 9)
+ *tmp++ = '-';
+ }
+ uuid_str_to_bin(uuid_rfc4122_str, uuid_smbios, UUID_STR_FORMAT_GUID);
+}
+
+static int sysinfo_iot2050_probe(struct udevice *dev)
+{
+ struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
+ unsigned long offset;
+
+ offset = dev_read_u32_default(dev, "offset",
+ TI_SRAM_SCRATCH_BOARD_EEPROM_START);
+ priv->info = (struct iot2050_info *)offset;
+
+ sysinfo_iot2050_convert_uuid(priv->info->uuid, priv->uuid_smbios);
+
+ return 0;
+}
+
+static const struct udevice_id sysinfo_iot2050_ids[] = {
+ { .compatible = "siemens,sysinfo-iot2050" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sysinfo_iot2050) = {
+ .name = "sysinfo_iot2050",
+ .id = UCLASS_SYSINFO,
+ .of_match = sysinfo_iot2050_ids,
+ .ops = &sysinfo_iot2050_ops,
+ .priv_auto = sizeof(struct sysinfo_iot2050_priv),
+ .probe = sysinfo_iot2050_probe,
+};
diff --git a/drivers/sysinfo/iot2050.h b/drivers/sysinfo/iot2050.h
new file mode 100644
index 00000000000..657221db096
--- /dev/null
+++ b/drivers/sysinfo/iot2050.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Siemens AG, 2025
+ */
+
+#include <sysinfo.h>
+
+enum sysinfo_id_iot2050 {
+ BOARD_MLFB = SYSID_USER,
+ BOARD_A5E,
+ BOARD_NAME,
+ BOARD_UUID,
+ BOARD_SEBOOT_VER,
+};
diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c
index 3c0cd51273e..f04998ef8bb 100644
--- a/drivers/sysinfo/sysinfo-uclass.c
+++ b/drivers/sysinfo/sysinfo-uclass.c
@@ -119,6 +119,35 @@ int sysinfo_get_data(struct udevice *dev, int id, void **data, size_t *size)
return ops->get_data(dev, id, data, size);
}
+int sysinfo_get_item_count(struct udevice *dev, int id)
+{
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
+ struct sysinfo_ops *ops = sysinfo_get_ops(dev);
+
+ if (!priv->detected)
+ return -EPERM;
+
+ if (!ops->get_item_count)
+ return -ENOSYS;
+
+ return ops->get_item_count(dev, id);
+}
+
+int sysinfo_get_data_by_index(struct udevice *dev, int id, int index,
+ void **data, size_t *size)
+{
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
+ struct sysinfo_ops *ops = sysinfo_get_ops(dev);
+
+ if (!priv->detected)
+ return -EPERM;
+
+ if (!ops->get_data_by_index)
+ return -ENOSYS;
+
+ return ops->get_data_by_index(dev, id, index, data, size);
+}
+
UCLASS_DRIVER(sysinfo) = {
.id = UCLASS_SYSINFO,
.name = "sysinfo",
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 121194e4418..475540ffac7 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -242,7 +242,6 @@ config SYSRESET_RAA215300
config SYSRESET_QCOM_PSHOLD
bool "Support sysreset for Qualcomm SoCs via PSHOLD"
- depends on ARCH_IPQ40XX
help
Add support for the system reboot on Qualcomm SoCs via PSHOLD.
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index e8b54a02965..c1baf3c69ec 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -18,6 +18,11 @@ void timer_test_add_offset(unsigned long offset)
sandbox_timer_offset += offset;
}
+ulong timer_test_get_offset(void)
+{
+ return sandbox_timer_offset;
+};
+
u64 notrace timer_early_get_count(void)
{
return os_get_nsec() / 1000 + sandbox_timer_offset * 1000;
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index f7d8c40c448..91f6ad3bfef 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -19,6 +19,7 @@
#include <malloc.h>
#include <hexdump.h>
#include <scsi.h>
+#include <ufs.h>
#include <asm/io.h>
#include <asm/dma-mapping.h>
#include <linux/bitops.h>
@@ -313,16 +314,12 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
&tx_lanes);
for (i = 0; i < tx_lanes; i++) {
+ unsigned int val = UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i));
if (!peer)
- err = ufshcd_dme_set(hba,
- UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
- UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
- 0);
+ err = ufshcd_dme_set(hba, val, 0);
else
- err = ufshcd_dme_peer_set(hba,
- UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
- UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
- 0);
+ err = ufshcd_dme_peer_set(hba, val, 0);
if (err) {
dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n",
__func__, peer, i, err);
@@ -1034,8 +1031,8 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
/**
* ufshcd_query_flag() - API function for sending flag query requests
*/
-int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
- enum flag_idn idn, bool *flag_res)
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+ enum flag_idn idn, bool *flag_res)
{
struct ufs_query_req *request = NULL;
struct ufs_query_res *response = NULL;
@@ -1170,9 +1167,9 @@ out:
/**
* ufshcd_query_descriptor_retry - API function for sending descriptor requests
*/
-int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode,
- enum desc_idn idn, u8 index, u8 selector,
- u8 *desc_buf, int *buf_len)
+static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode,
+ enum desc_idn idn, u8 index, u8 selector,
+ u8 *desc_buf, int *buf_len)
{
int err;
int retries;
@@ -1264,8 +1261,8 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
* ufshcd_map_desc_id_to_length - map descriptor IDN to its length
*
*/
-int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
- int *desc_len)
+static int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
+ int *desc_len)
{
switch (desc_id) {
case QUERY_DESC_IDN_DEVICE:
@@ -1302,15 +1299,14 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
}
return 0;
}
-EXPORT_SYMBOL(ufshcd_map_desc_id_to_length);
/**
* ufshcd_read_desc_param - read the specified descriptor parameter
*
*/
-int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
- int desc_index, u8 param_offset, u8 *param_read_buf,
- u8 param_size)
+static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
+ int desc_index, u8 param_offset,
+ u8 *param_read_buf, u8 param_size)
{
int ret;
u8 *desc_buf;
@@ -1569,8 +1565,8 @@ static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
* ufshcd_read_string_desc - read string descriptor
*
*/
-int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
- u8 *buf, u32 size, bool ascii)
+static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
+ u8 *buf, u32 size, bool ascii)
{
int err = 0;
@@ -1881,7 +1877,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
}
-int ufs_start(struct ufs_hba *hba)
+static int ufs_start(struct ufs_hba *hba)
{
struct ufs_dev_desc card = {0};
int ret;
@@ -1962,7 +1958,7 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
ufshcd_ops_init(hba);
- /* Read capabilties registers */
+ /* Read capabilities registers */
hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS)
hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT;
@@ -2001,7 +1997,7 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
REG_INTERRUPT_STATUS);
ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE);
- mb();
+ mb(); /* flush previous writes */
/* Reset the attached device */
ufshcd_device_reset(hba);
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index 00ecca350c3..53137fae3a8 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -4,6 +4,7 @@
#include <linux/types.h>
#include <asm/io.h>
+#include "ufshci.h"
#include "unipro.h"
struct udevice;
@@ -14,11 +15,6 @@ struct udevice;
#define RESPONSE_UPIU_SENSE_DATA_LENGTH 18
#define UFS_MAX_LUNS 0x7F
-enum {
- TASK_REQ_UPIU_SIZE_DWORDS = 8,
- TASK_RSP_UPIU_SIZE_DWORDS = 8,
- ALIGNED_UPIU_SIZE = 512,
-};
/* UFS device power modes */
enum ufs_dev_pwr_mode {
@@ -84,44 +80,6 @@ enum {
/* Offset of the response code in the UPIU header */
#define UPIU_RSP_CODE_OFFSET 8
-/* To accommodate UFS2.0 required Command type */
-enum {
- UTP_CMD_TYPE_UFS_STORAGE = 0x1,
-};
-
-enum {
- UTP_SCSI_COMMAND = 0x00000000,
- UTP_NATIVE_UFS_COMMAND = 0x10000000,
- UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000,
- UTP_REQ_DESC_INT_CMD = 0x01000000,
-};
-
-/* UTP Transfer Request Data Direction (DD) */
-enum {
- UTP_NO_DATA_TRANSFER = 0x00000000,
- UTP_HOST_TO_DEVICE = 0x02000000,
- UTP_DEVICE_TO_HOST = 0x04000000,
-};
-
-/* Overall command status values */
-enum {
- OCS_SUCCESS = 0x0,
- OCS_INVALID_CMD_TABLE_ATTR = 0x1,
- OCS_INVALID_PRDT_ATTR = 0x2,
- OCS_MISMATCH_DATA_BUF_SIZE = 0x3,
- OCS_MISMATCH_RESP_UPIU_SIZE = 0x4,
- OCS_PEER_COMM_FAILURE = 0x5,
- OCS_ABORTED = 0x6,
- OCS_FATAL_ERROR = 0x7,
- OCS_INVALID_COMMAND_STATUS = 0x0F,
- MASK_OCS = 0x0F,
-};
-
-/* The maximum length of the data byte count field in the PRDT is 256KB */
-#define PRDT_DATA_BYTE_COUNT_MAX (256 * 1024)
-/* The granularity of the data byte count field in the PRDT is 32-bit */
-#define PRDT_DATA_BYTE_COUNT_PAD 4
-
#define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req))
#define QUERY_DESC_MAX_SIZE 255
#define QUERY_DESC_MIN_SIZE 2
@@ -130,8 +88,8 @@ enum {
(sizeof(struct utp_upiu_header)))
#define RESPONSE_UPIU_SENSE_DATA_LENGTH 18
#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
- cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
- (byte1 << 8) | (byte0))
+ cpu_to_be32(((byte3) << 24) | ((byte2) << 16) |\
+ ((byte1) << 8) | (byte0))
/*
* UFS Protocol Information Unit related definitions
*/
@@ -297,79 +255,6 @@ enum desc_header_offset {
QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
};
-struct ufshcd_sg_entry {
- __le32 base_addr;
- __le32 upper_addr;
- __le32 reserved;
- __le32 size;
-};
-
-#define MAX_BUFF 128
-/**
- * struct utp_transfer_cmd_desc - UFS Command Descriptor structure
- * @command_upiu: Command UPIU Frame address
- * @response_upiu: Response UPIU Frame address
- * @prd_table: Physical Region Descriptor
- */
-struct utp_transfer_cmd_desc {
- u8 command_upiu[ALIGNED_UPIU_SIZE];
- u8 response_upiu[ALIGNED_UPIU_SIZE];
- struct ufshcd_sg_entry prd_table[MAX_BUFF];
-};
-
-/**
- * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
- * @dword0: Descriptor Header DW0
- * @dword1: Descriptor Header DW1
- * @dword2: Descriptor Header DW2
- * @dword3: Descriptor Header DW3
- */
-struct request_desc_header {
- __le32 dword_0;
- __le32 dword_1;
- __le32 dword_2;
- __le32 dword_3;
-};
-
-/**
- * struct utp_transfer_req_desc - UTRD structure
- * @header: UTRD header DW-0 to DW-3
- * @command_desc_base_addr_lo: UCD base address low DW-4
- * @command_desc_base_addr_hi: UCD base address high DW-5
- * @response_upiu_length: response UPIU length DW-6
- * @response_upiu_offset: response UPIU offset DW-6
- * @prd_table_length: Physical region descriptor length DW-7
- * @prd_table_offset: Physical region descriptor offset DW-7
- */
-struct utp_transfer_req_desc {
- /* DW 0-3 */
- struct request_desc_header header;
-
- /* DW 4-5*/
- __le32 command_desc_base_addr_lo;
- __le32 command_desc_base_addr_hi;
-
- /* DW 6 */
- __le16 response_upiu_length;
- __le16 response_upiu_offset;
-
- /* DW 7 */
- __le16 prd_table_length;
- __le16 prd_table_offset;
-};
-
-/**
- * struct utp_upiu_header - UPIU header structure
- * @dword_0: UPIU header DW-0
- * @dword_1: UPIU header DW-1
- * @dword_2: UPIU header DW-2
- */
-struct utp_upiu_header {
- __be32 dword_0;
- __be32 dword_1;
- __be32 dword_2;
-};
-
/**
* struct utp_upiu_query - upiu request buffer structure for
* query request.
@@ -403,27 +288,6 @@ struct utp_upiu_cmd {
u8 cdb[UFS_CDB_SIZE];
};
-/*
- * UTMRD structure.
- */
-struct utp_task_req_desc {
- /* DW 0-3 */
- struct request_desc_header header;
-
- /* DW 4-11 - Task request UPIU structure */
- struct utp_upiu_header req_header;
- __be32 input_param1;
- __be32 input_param2;
- __be32 input_param3;
- __be32 __reserved1[2];
-
- /* DW 12-19 - Task Management Response UPIU structure */
- struct utp_upiu_header rsp_header;
- __be32 output_param1;
- __be32 output_param2;
- __be32 __reserved2[3];
-};
-
/**
* struct utp_upiu_req - general upiu request structure
* @header:UPIU header structure DW-0 to DW-2
@@ -551,63 +415,6 @@ struct uic_command {
int result;
};
-/* GenSelectorIndex calculation macros for M-PHY attributes */
-#define UIC_ARG_MPHY_TX_GEN_SEL_INDEX(lane) (lane)
-#define UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane) (PA_MAXDATALANES + (lane))
-
-#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
- ((sel) & 0xFFFF))
-#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0)
-#define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16)
-#define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF)
-
-/* Link Status*/
-enum link_status {
- UFSHCD_LINK_IS_DOWN = 1,
- UFSHCD_LINK_IS_UP = 2,
-};
-
-#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
- ((sel) & 0xFFFF))
-#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0)
-#define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16)
-#define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF)
-
-/* UIC Commands */
-enum uic_cmd_dme {
- UIC_CMD_DME_GET = 0x01,
- UIC_CMD_DME_SET = 0x02,
- UIC_CMD_DME_PEER_GET = 0x03,
- UIC_CMD_DME_PEER_SET = 0x04,
- UIC_CMD_DME_POWERON = 0x10,
- UIC_CMD_DME_POWEROFF = 0x11,
- UIC_CMD_DME_ENABLE = 0x12,
- UIC_CMD_DME_RESET = 0x14,
- UIC_CMD_DME_END_PT_RST = 0x15,
- UIC_CMD_DME_LINK_STARTUP = 0x16,
- UIC_CMD_DME_HIBER_ENTER = 0x17,
- UIC_CMD_DME_HIBER_EXIT = 0x18,
- UIC_CMD_DME_TEST_MODE = 0x1A,
-};
-
-/* UIC Config result code / Generic error code */
-enum {
- UIC_CMD_RESULT_SUCCESS = 0x00,
- UIC_CMD_RESULT_INVALID_ATTR = 0x01,
- UIC_CMD_RESULT_FAILURE = 0x01,
- UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02,
- UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03,
- UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04,
- UIC_CMD_RESULT_BAD_INDEX = 0x05,
- UIC_CMD_RESULT_LOCKED_ATTR = 0x06,
- UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07,
- UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08,
- UIC_CMD_RESULT_BUSY = 0x09,
- UIC_CMD_RESULT_DME_FAILURE = 0x0A,
-};
-
-#define MASK_UIC_COMMAND_RESULT 0xFF
-
/* Host <-> Device UniPro Link state */
enum uic_link_state {
UIC_LINK_OFF_STATE = 0, /* Link powered down or disabled */
@@ -915,7 +722,7 @@ static inline int ufshcd_ops_get_max_pwr_mode(struct ufs_hba *hba,
}
static inline int ufshcd_ops_hce_enable_notify(struct ufs_hba *hba,
- bool status)
+ bool status)
{
if (hba->ops && hba->ops->hce_enable_notify)
return hba->ops->hce_enable_notify(hba, status);
@@ -940,17 +747,6 @@ static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
return 0;
}
-/* Controller UFSHCI version */
-enum {
- UFSHCI_VERSION_10 = 0x00010000, /* 1.0 */
- UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */
- UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
- UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
- UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */
- UFSHCI_VERSION_31 = 0x00000310, /* 3.1 */
- UFSHCI_VERSION_40 = 0x00000400, /* 4.0 */
-};
-
/* Interrupt disable masks */
enum {
/* Interrupt disable mask for UFSHCI v1.0 */
@@ -964,123 +760,6 @@ enum {
INTERRUPT_MASK_ALL_VER_21 = 0x71FFF,
};
-/* UFSHCI Registers */
-enum {
- REG_CONTROLLER_CAPABILITIES = 0x00,
- REG_UFS_VERSION = 0x08,
- REG_CONTROLLER_DEV_ID = 0x10,
- REG_CONTROLLER_PROD_ID = 0x14,
- REG_AUTO_HIBERNATE_IDLE_TIMER = 0x18,
- REG_INTERRUPT_STATUS = 0x20,
- REG_INTERRUPT_ENABLE = 0x24,
- REG_CONTROLLER_STATUS = 0x30,
- REG_CONTROLLER_ENABLE = 0x34,
- REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER = 0x38,
- REG_UIC_ERROR_CODE_DATA_LINK_LAYER = 0x3C,
- REG_UIC_ERROR_CODE_NETWORK_LAYER = 0x40,
- REG_UIC_ERROR_CODE_TRANSPORT_LAYER = 0x44,
- REG_UIC_ERROR_CODE_DME = 0x48,
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL = 0x4C,
- REG_UTP_TRANSFER_REQ_LIST_BASE_L = 0x50,
- REG_UTP_TRANSFER_REQ_LIST_BASE_H = 0x54,
- REG_UTP_TRANSFER_REQ_DOOR_BELL = 0x58,
- REG_UTP_TRANSFER_REQ_LIST_CLEAR = 0x5C,
- REG_UTP_TRANSFER_REQ_LIST_RUN_STOP = 0x60,
- REG_UTP_TASK_REQ_LIST_BASE_L = 0x70,
- REG_UTP_TASK_REQ_LIST_BASE_H = 0x74,
- REG_UTP_TASK_REQ_DOOR_BELL = 0x78,
- REG_UTP_TASK_REQ_LIST_CLEAR = 0x7C,
- REG_UTP_TASK_REQ_LIST_RUN_STOP = 0x80,
- REG_UIC_COMMAND = 0x90,
- REG_UIC_COMMAND_ARG_1 = 0x94,
- REG_UIC_COMMAND_ARG_2 = 0x98,
- REG_UIC_COMMAND_ARG_3 = 0x9C,
-
- UFSHCI_REG_SPACE_SIZE = 0xA0,
-
- REG_UFS_CCAP = 0x100,
- REG_UFS_CRYPTOCAP = 0x104,
-
- UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400,
-};
-
-/* Controller capability masks */
-enum {
- MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F,
- MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000,
- MASK_AUTO_HIBERN8_SUPPORT = 0x00800000,
- MASK_64_ADDRESSING_SUPPORT = 0x01000000,
- MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,
- MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000,
-};
-
-/* Interrupt Status 20h */
-#define UTP_TRANSFER_REQ_COMPL 0x1
-#define UIC_DME_END_PT_RESET 0x2
-#define UIC_ERROR 0x4
-#define UIC_TEST_MODE 0x8
-#define UIC_POWER_MODE 0x10
-#define UIC_HIBERNATE_EXIT 0x20
-#define UIC_HIBERNATE_ENTER 0x40
-#define UIC_LINK_LOST 0x80
-#define UIC_LINK_STARTUP 0x100
-#define UTP_TASK_REQ_COMPL 0x200
-#define UIC_COMMAND_COMPL 0x400
-#define DEVICE_FATAL_ERROR 0x800
-#define CONTROLLER_FATAL_ERROR 0x10000
-#define SYSTEM_BUS_FATAL_ERROR 0x20000
-
-#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\
- UIC_HIBERNATE_EXIT |\
- UIC_POWER_MODE)
-
-#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UIC_POWER_MODE)
-
-#define UFSHCD_ERROR_MASK (UIC_ERROR |\
- DEVICE_FATAL_ERROR |\
- CONTROLLER_FATAL_ERROR |\
- SYSTEM_BUS_FATAL_ERROR)
-
-#define INT_FATAL_ERRORS (DEVICE_FATAL_ERROR |\
- CONTROLLER_FATAL_ERROR |\
- SYSTEM_BUS_FATAL_ERROR)
-
-/* Host Controller Enable 0x34h */
-#define CONTROLLER_ENABLE 0x1
-#define CONTROLLER_DISABLE 0x0
-/* HCS - Host Controller Status 30h */
-#define DEVICE_PRESENT 0x1
-#define UTP_TRANSFER_REQ_LIST_READY 0x2
-#define UTP_TASK_REQ_LIST_READY 0x4
-#define UIC_COMMAND_READY 0x8
-#define HOST_ERROR_INDICATOR 0x10
-#define DEVICE_ERROR_INDICATOR 0x20
-#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8)
-
-#define UFSHCD_STATUS_READY (UTP_TRANSFER_REQ_LIST_READY |\
- UTP_TASK_REQ_LIST_READY |\
- UIC_COMMAND_READY)
-
-enum {
- PWR_OK = 0x0,
- PWR_LOCAL = 0x01,
- PWR_REMOTE = 0x02,
- PWR_BUSY = 0x03,
- PWR_ERROR_CAP = 0x04,
- PWR_FATAL_ERROR = 0x05,
-};
-
-/* UICCMD - UIC Command */
-#define COMMAND_OPCODE_MASK 0xFF
-#define GEN_SELECTOR_INDEX_MASK 0xFFFF
-
-#define MIB_ATTRIBUTE_MASK UFS_MASK(0xFFFF, 16)
-#define RESET_LEVEL 0xFF
-
-#define ATTR_SET_TYPE_MASK UFS_MASK(0xFF, 16)
-#define CFG_RESULT_CODE_MASK 0xFF
-#define GENERIC_ERROR_CODE_MASK 0xFF
-
#define ufshcd_writel(hba, val, reg) \
writel((val), (hba)->mmio_base + (reg))
#define ufshcd_readl(hba, reg) \
@@ -1103,12 +782,6 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
ufshcd_writel(hba, tmp, reg);
}
-/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */
-#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT 0x1
-
-/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
-#define UTP_TASK_REQ_LIST_RUN_STOP_BIT 0x1
-
int ufshcd_probe(struct udevice *dev, struct ufs_hba_ops *hba_ops);
#endif
diff --git a/drivers/ufs/ufshci.h b/drivers/ufs/ufshci.h
new file mode 100644
index 00000000000..90cbf87a3a4
--- /dev/null
+++ b/drivers/ufs/ufshci.h
@@ -0,0 +1,469 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __UFSHCI_H
+#define __UFSHCI_H
+
+enum {
+ TASK_REQ_UPIU_SIZE_DWORDS = 8,
+ TASK_RSP_UPIU_SIZE_DWORDS = 8,
+ ALIGNED_UPIU_SIZE = 512,
+};
+
+/* UFSHCI Registers */
+enum {
+ REG_CONTROLLER_CAPABILITIES = 0x00,
+ REG_MCQCAP = 0x04,
+ REG_UFS_VERSION = 0x08,
+ REG_EXT_CONTROLLER_CAPABILITIES = 0x0C,
+ REG_CONTROLLER_PID = 0x10,
+ REG_CONTROLLER_MID = 0x14,
+ REG_AUTO_HIBERNATE_IDLE_TIMER = 0x18,
+ REG_INTERRUPT_STATUS = 0x20,
+ REG_INTERRUPT_ENABLE = 0x24,
+ REG_CONTROLLER_STATUS = 0x30,
+ REG_CONTROLLER_ENABLE = 0x34,
+ REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER = 0x38,
+ REG_UIC_ERROR_CODE_DATA_LINK_LAYER = 0x3C,
+ REG_UIC_ERROR_CODE_NETWORK_LAYER = 0x40,
+ REG_UIC_ERROR_CODE_TRANSPORT_LAYER = 0x44,
+ REG_UIC_ERROR_CODE_DME = 0x48,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL = 0x4C,
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L = 0x50,
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H = 0x54,
+ REG_UTP_TRANSFER_REQ_DOOR_BELL = 0x58,
+ REG_UTP_TRANSFER_REQ_LIST_CLEAR = 0x5C,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP = 0x60,
+ REG_UTP_TASK_REQ_LIST_BASE_L = 0x70,
+ REG_UTP_TASK_REQ_LIST_BASE_H = 0x74,
+ REG_UTP_TASK_REQ_DOOR_BELL = 0x78,
+ REG_UTP_TASK_REQ_LIST_CLEAR = 0x7C,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP = 0x80,
+ REG_UIC_COMMAND = 0x90,
+ REG_UIC_COMMAND_ARG_1 = 0x94,
+ REG_UIC_COMMAND_ARG_2 = 0x98,
+ REG_UIC_COMMAND_ARG_3 = 0x9C,
+
+ UFSHCI_REG_SPACE_SIZE = 0xA0,
+
+ REG_UFS_CCAP = 0x100,
+ REG_UFS_CRYPTOCAP = 0x104,
+
+ REG_UFS_MEM_CFG = 0x300,
+ REG_UFS_MCQ_CFG = 0x380,
+ REG_UFS_ESILBA = 0x384,
+ REG_UFS_ESIUBA = 0x388,
+ UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400,
+};
+
+/* Controller capability masks */
+enum {
+ MASK_TRANSFER_REQUESTS_SLOTS_SDB = 0x0000001F,
+ MASK_TRANSFER_REQUESTS_SLOTS_MCQ = 0x000000FF,
+ MASK_NUMBER_OUTSTANDING_RTT = 0x0000FF00,
+ MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000,
+ MASK_EHSLUTRD_SUPPORTED = 0x00400000,
+ MASK_AUTO_HIBERN8_SUPPORT = 0x00800000,
+ MASK_64_ADDRESSING_SUPPORT = 0x01000000,
+ MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,
+ MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000,
+ MASK_CRYPTO_SUPPORT = 0x10000000,
+ MASK_LSDB_SUPPORT = 0x20000000,
+ MASK_MCQ_SUPPORT = 0x40000000,
+};
+
+/* MCQ capability mask */
+enum {
+ MASK_EXT_IID_SUPPORT = 0x00000400,
+};
+
+enum {
+ REG_SQATTR = 0x0,
+ REG_SQLBA = 0x4,
+ REG_SQUBA = 0x8,
+ REG_SQDAO = 0xC,
+ REG_SQISAO = 0x10,
+
+ REG_CQATTR = 0x20,
+ REG_CQLBA = 0x24,
+ REG_CQUBA = 0x28,
+ REG_CQDAO = 0x2C,
+ REG_CQISAO = 0x30,
+};
+
+enum {
+ REG_SQHP = 0x0,
+ REG_SQTP = 0x4,
+ REG_SQRTC = 0x8,
+ REG_SQCTI = 0xC,
+ REG_SQRTS = 0x10,
+};
+
+enum {
+ REG_CQHP = 0x0,
+ REG_CQTP = 0x4,
+};
+
+enum {
+ REG_CQIS = 0x0,
+ REG_CQIE = 0x4,
+};
+
+enum {
+ SQ_START = 0x0,
+ SQ_STOP = 0x1,
+ SQ_ICU = 0x2,
+};
+
+enum {
+ SQ_STS = 0x1,
+ SQ_CUS = 0x2,
+};
+
+#define SQ_ICU_ERR_CODE_MASK GENMASK(7, 4)
+#define UFS_MASK(mask, offset) ((mask) << (offset))
+
+/* UFS Version 08h */
+#define MINOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 0)
+#define MAJOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 16)
+
+/* Controller UFSHCI version */
+enum {
+ UFSHCI_VERSION_10 = 0x00010000, /* 1.0 */
+ UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */
+ UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
+ UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
+ UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */
+ UFSHCI_VERSION_31 = 0x00000310, /* 3.1 */
+ UFSHCI_VERSION_40 = 0x00000400, /* 4.0 */
+};
+
+/*
+ * IS - Interrupt Status - 20h
+ */
+#define UTP_TRANSFER_REQ_COMPL 0x1
+#define UIC_DME_END_PT_RESET 0x2
+#define UIC_ERROR 0x4
+#define UIC_TEST_MODE 0x8
+#define UIC_POWER_MODE 0x10
+#define UIC_HIBERNATE_EXIT 0x20
+#define UIC_HIBERNATE_ENTER 0x40
+#define UIC_LINK_LOST 0x80
+#define UIC_LINK_STARTUP 0x100
+#define UTP_TASK_REQ_COMPL 0x200
+#define UIC_COMMAND_COMPL 0x400
+#define DEVICE_FATAL_ERROR 0x800
+#define CONTROLLER_FATAL_ERROR 0x10000
+#define SYSTEM_BUS_FATAL_ERROR 0x20000
+#define CRYPTO_ENGINE_FATAL_ERROR 0x40000
+#define MCQ_CQ_EVENT_STATUS 0x100000
+
+#define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\
+ UIC_HIBERNATE_EXIT)
+
+#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\
+ UIC_POWER_MODE)
+
+#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
+
+#define UFSHCD_ERROR_MASK (UIC_ERROR | INT_FATAL_ERRORS)
+
+#define INT_FATAL_ERRORS (DEVICE_FATAL_ERROR |\
+ CONTROLLER_FATAL_ERROR |\
+ SYSTEM_BUS_FATAL_ERROR |\
+ CRYPTO_ENGINE_FATAL_ERROR |\
+ UIC_LINK_LOST)
+
+/* HCS - Host Controller Status 30h */
+#define DEVICE_PRESENT 0x1
+#define UTP_TRANSFER_REQ_LIST_READY 0x2
+#define UTP_TASK_REQ_LIST_READY 0x4
+#define UIC_COMMAND_READY 0x8
+#define HOST_ERROR_INDICATOR 0x10
+#define DEVICE_ERROR_INDICATOR 0x20
+#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8)
+
+#define UFSHCD_STATUS_READY (UTP_TRANSFER_REQ_LIST_READY |\
+ UTP_TASK_REQ_LIST_READY |\
+ UIC_COMMAND_READY)
+
+enum {
+ PWR_OK = 0x0,
+ PWR_LOCAL = 0x01,
+ PWR_REMOTE = 0x02,
+ PWR_BUSY = 0x03,
+ PWR_ERROR_CAP = 0x04,
+ PWR_FATAL_ERROR = 0x05,
+};
+
+/* HCE - Host Controller Enable 34h */
+#define CONTROLLER_ENABLE 0x1
+#define CONTROLLER_DISABLE 0x0
+#define CRYPTO_GENERAL_ENABLE 0x2
+
+/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
+#define UIC_PHY_ADAPTER_LAYER_ERROR 0x80000000
+#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F
+#define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK 0xF
+#define UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR 0x10
+
+/* UECDL - Host UIC Error Code Data Link Layer 3Ch */
+#define UIC_DATA_LINK_LAYER_ERROR 0x80000000
+#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0xFFFF
+#define UIC_DATA_LINK_LAYER_ERROR_TCX_REP_TIMER_EXP 0x2
+#define UIC_DATA_LINK_LAYER_ERROR_AFCX_REQ_TIMER_EXP 0x4
+#define UIC_DATA_LINK_LAYER_ERROR_FCX_PRO_TIMER_EXP 0x8
+#define UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF 0x20
+#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT 0x2000
+#define UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED 0x0001
+#define UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT 0x0002
+
+/* UECN - Host UIC Error Code Network Layer 40h */
+#define UIC_NETWORK_LAYER_ERROR 0x80000000
+#define UIC_NETWORK_LAYER_ERROR_CODE_MASK 0x7
+#define UIC_NETWORK_UNSUPPORTED_HEADER_TYPE 0x1
+#define UIC_NETWORK_BAD_DEVICEID_ENC 0x2
+#define UIC_NETWORK_LHDR_TRAP_PACKET_DROPPING 0x4
+
+/* UECT - Host UIC Error Code Transport Layer 44h */
+#define UIC_TRANSPORT_LAYER_ERROR 0x80000000
+#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK 0x7F
+#define UIC_TRANSPORT_UNSUPPORTED_HEADER_TYPE 0x1
+#define UIC_TRANSPORT_UNKNOWN_CPORTID 0x2
+#define UIC_TRANSPORT_NO_CONNECTION_RX 0x4
+#define UIC_TRANSPORT_CONTROLLED_SEGMENT_DROPPING 0x8
+#define UIC_TRANSPORT_BAD_TC 0x10
+#define UIC_TRANSPORT_E2E_CREDIT_OVERFOW 0x20
+#define UIC_TRANSPORT_SAFETY_VALUE_DROPPING 0x40
+
+/* UECDME - Host UIC Error Code DME 48h */
+#define UIC_DME_ERROR 0x80000000
+#define UIC_DME_ERROR_CODE_MASK 0x1
+
+/* UTRIACR - Interrupt Aggregation control register - 0x4Ch */
+#define INT_AGGR_TIMEOUT_VAL_MASK 0xFF
+#define INT_AGGR_COUNTER_THRESHOLD_MASK UFS_MASK(0x1F, 8)
+#define INT_AGGR_COUNTER_AND_TIMER_RESET 0x10000
+#define INT_AGGR_STATUS_BIT 0x100000
+#define INT_AGGR_PARAM_WRITE 0x1000000
+#define INT_AGGR_ENABLE 0x80000000
+
+/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */
+#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT 0x1
+
+/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
+#define UTP_TASK_REQ_LIST_RUN_STOP_BIT 0x1
+
+/* REG_UFS_MEM_CFG - Global Config Registers 300h */
+#define MCQ_MODE_SELECT BIT(0)
+
+/* CQISy - CQ y Interrupt Status Register */
+#define UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS 0x1
+
+/* UICCMD - UIC Command */
+#define COMMAND_OPCODE_MASK 0xFF
+#define GEN_SELECTOR_INDEX_MASK 0xFFFF
+
+#define MIB_ATTRIBUTE_MASK UFS_MASK(0xFFFF, 16)
+#define RESET_LEVEL 0xFF
+
+#define ATTR_SET_TYPE_MASK UFS_MASK(0xFF, 16)
+#define CFG_RESULT_CODE_MASK 0xFF
+#define GENERIC_ERROR_CODE_MASK 0xFF
+
+/* GenSelectorIndex calculation macros for M-PHY attributes */
+#define UIC_ARG_MPHY_TX_GEN_SEL_INDEX(lane) (lane)
+#define UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane) (PA_MAXDATALANES + (lane))
+
+#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
+ ((sel) & 0xFFFF))
+#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0)
+#define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16)
+#define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF)
+
+/* Link Status*/
+enum link_status {
+ UFSHCD_LINK_IS_DOWN = 1,
+ UFSHCD_LINK_IS_UP = 2,
+};
+
+/* UIC Commands */
+enum uic_cmd_dme {
+ UIC_CMD_DME_GET = 0x01,
+ UIC_CMD_DME_SET = 0x02,
+ UIC_CMD_DME_PEER_GET = 0x03,
+ UIC_CMD_DME_PEER_SET = 0x04,
+ UIC_CMD_DME_POWERON = 0x10,
+ UIC_CMD_DME_POWEROFF = 0x11,
+ UIC_CMD_DME_ENABLE = 0x12,
+ UIC_CMD_DME_RESET = 0x14,
+ UIC_CMD_DME_END_PT_RST = 0x15,
+ UIC_CMD_DME_LINK_STARTUP = 0x16,
+ UIC_CMD_DME_HIBER_ENTER = 0x17,
+ UIC_CMD_DME_HIBER_EXIT = 0x18,
+ UIC_CMD_DME_TEST_MODE = 0x1A,
+};
+
+/* UIC Config result code / Generic error code */
+enum {
+ UIC_CMD_RESULT_SUCCESS = 0x00,
+ UIC_CMD_RESULT_INVALID_ATTR = 0x01,
+ UIC_CMD_RESULT_FAILURE = 0x01,
+ UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02,
+ UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03,
+ UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04,
+ UIC_CMD_RESULT_BAD_INDEX = 0x05,
+ UIC_CMD_RESULT_LOCKED_ATTR = 0x06,
+ UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07,
+ UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08,
+ UIC_CMD_RESULT_BUSY = 0x09,
+ UIC_CMD_RESULT_DME_FAILURE = 0x0A,
+};
+
+#define MASK_UIC_COMMAND_RESULT 0xFF
+
+#define INT_AGGR_COUNTER_THLD_VAL(c) (((c) & 0x1F) << 8)
+#define INT_AGGR_TIMEOUT_VAL(t) (((t) & 0xFF) << 0)
+
+/*
+ * Request Descriptor Definitions
+ */
+
+/* To accommodate UFS2.0 required Command type */
+enum {
+ UTP_CMD_TYPE_UFS_STORAGE = 0x1,
+};
+
+enum {
+ UTP_SCSI_COMMAND = 0x00000000,
+ UTP_REQ_DESC_INT_CMD = 0x01000000,
+ UTP_NATIVE_UFS_COMMAND = 0x10000000,
+ UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000,
+};
+
+/* UTP Transfer Request Data Direction (DD) */
+enum utp_data_direction {
+ UTP_NO_DATA_TRANSFER = 0,
+ UTP_HOST_TO_DEVICE = 1,
+ UTP_DEVICE_TO_HOST = 2,
+};
+
+/* Overall command status values */
+enum utp_ocs {
+ OCS_SUCCESS = 0x0,
+ OCS_INVALID_CMD_TABLE_ATTR = 0x1,
+ OCS_INVALID_PRDT_ATTR = 0x2,
+ OCS_MISMATCH_DATA_BUF_SIZE = 0x3,
+ OCS_MISMATCH_RESP_UPIU_SIZE = 0x4,
+ OCS_PEER_COMM_FAILURE = 0x5,
+ OCS_ABORTED = 0x6,
+ OCS_FATAL_ERROR = 0x7,
+ OCS_DEVICE_FATAL_ERROR = 0x8,
+ OCS_INVALID_CRYPTO_CONFIG = 0x9,
+ OCS_GENERAL_CRYPTO_ERROR = 0xA,
+ OCS_INVALID_COMMAND_STATUS = 0x0F,
+};
+
+enum {
+ MASK_OCS = 0x0F,
+};
+
+/* The maximum length of the data byte count field in the PRDT is 256KB */
+#define PRDT_DATA_BYTE_COUNT_MAX SZ_256K
+/* The granularity of the data byte count field in the PRDT is 32-bit */
+#define PRDT_DATA_BYTE_COUNT_PAD 4
+
+
+struct ufshcd_sg_entry {
+ __le32 base_addr;
+ __le32 upper_addr;
+ __le32 reserved;
+ __le32 size;
+};
+
+#define MAX_BUFF 128
+/**
+ * struct utp_transfer_cmd_desc - UFS Command Descriptor structure
+ * @command_upiu: Command UPIU Frame address
+ * @response_upiu: Response UPIU Frame address
+ * @prd_table: Physical Region Descriptor
+ */
+struct utp_transfer_cmd_desc {
+ u8 command_upiu[ALIGNED_UPIU_SIZE];
+ u8 response_upiu[ALIGNED_UPIU_SIZE];
+ struct ufshcd_sg_entry prd_table[MAX_BUFF];
+};
+
+/**
+ * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
+ * @dword0: Descriptor Header DW0
+ * @dword1: Descriptor Header DW1
+ * @dword2: Descriptor Header DW2
+ * @dword3: Descriptor Header DW3
+ */
+struct request_desc_header {
+ __le32 dword_0;
+ __le32 dword_1;
+ __le32 dword_2;
+ __le32 dword_3;
+};
+
+/**
+ * struct utp_transfer_req_desc - UTRD structure
+ * @header: UTRD header DW-0 to DW-3
+ * @command_desc_base_addr_lo: UCD base address low DW-4
+ * @command_desc_base_addr_hi: UCD base address high DW-5
+ * @response_upiu_length: response UPIU length DW-6
+ * @response_upiu_offset: response UPIU offset DW-6
+ * @prd_table_length: Physical region descriptor length DW-7
+ * @prd_table_offset: Physical region descriptor offset DW-7
+ */
+struct utp_transfer_req_desc {
+ /* DW 0-3 */
+ struct request_desc_header header;
+
+ /* DW 4-5*/
+ __le32 command_desc_base_addr_lo;
+ __le32 command_desc_base_addr_hi;
+
+ /* DW 6 */
+ __le16 response_upiu_length;
+ __le16 response_upiu_offset;
+
+ /* DW 7 */
+ __le16 prd_table_length;
+ __le16 prd_table_offset;
+};
+
+/**
+ * struct utp_upiu_header - UPIU header structure
+ * @dword_0: UPIU header DW-0
+ * @dword_1: UPIU header DW-1
+ * @dword_2: UPIU header DW-2
+ */
+struct utp_upiu_header {
+ __be32 dword_0;
+ __be32 dword_1;
+ __be32 dword_2;
+};
+
+/*
+ * UTMRD structure.
+ */
+struct utp_task_req_desc {
+ /* DW 0-3 */
+ struct request_desc_header header;
+
+ /* DW 4-11 - Task request UPIU structure */
+ struct utp_upiu_header req_header;
+ __be32 input_param1;
+ __be32 input_param2;
+ __be32 input_param3;
+ __be32 __reserved1[2];
+
+ /* DW 12-19 - Task Management Response UPIU structure */
+ struct utp_upiu_header rsp_header;
+ __be32 output_param1;
+ __be32 output_param2;
+ __be32 __reserved2[3];
+};
+
+#endif
diff --git a/drivers/ufs/unipro.h b/drivers/ufs/unipro.h
index 6df953e6e60..56833602b77 100644
--- a/drivers/ufs/unipro.h
+++ b/drivers/ufs/unipro.h
@@ -34,6 +34,18 @@
/*
* M-RX Configuration Attributes
*/
+#define RX_HS_G1_SYNC_LENGTH_CAP 0x008B
+#define RX_HS_G1_PREP_LENGTH_CAP 0x008C
+#define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F
+#define RX_HIBERN8TIME_CAPABILITY 0x0092
+#define RX_HS_G2_SYNC_LENGTH_CAP 0x0094
+#define RX_HS_G3_SYNC_LENGTH_CAP 0x0095
+#define RX_HS_G2_PREP_LENGTH_CAP 0x0096
+#define RX_HS_G3_PREP_LENGTH_CAP 0x0097
+#define RX_ADV_GRANULARITY_CAP 0x0098
+#define RX_HIBERN8TIME_CAP 0x0092
+#define RX_ADV_HIBERN8TIME_CAP 0x0099
+#define RX_ADV_MIN_ACTIVATETIME_CAP 0x009A
#define RX_MODE 0x00A1
#define RX_HSRATE_SERIES 0x00A2
#define RX_HSGEAR 0x00A3
@@ -42,24 +54,27 @@
#define RX_HS_UNTERMINATED_ENABLE 0x00A6
#define RX_ENTER_HIBERN8 0x00A7
#define RX_BYPASS_8B10B_ENABLE 0x00A8
-#define RX_TERMINATION_FORCE_ENABLE 0x0089
-#define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F
-#define RX_HIBERN8TIME_CAPABILITY 0x0092
+#define RX_TERMINATION_FORCE_ENABLE 0x00A9
+#define RXCALCTRL 0x00B4
+#define RXSQCTRL 0x00B5
+#define CFGRXCDR8 0x00BA
+#define CFGRXOVR8 0x00BD
+#define CFGRXOVR6 0x00BF
+#define RXDIRECTCTRL2 0x00C7
+#define CFGRXOVR4 0x00E9
#define RX_REFCLKFREQ 0x00EB
#define RX_CFGCLKFREQVAL 0x00EC
#define CFGWIDEINLN 0x00F0
-#define CFGRXCDR8 0x00BA
#define ENARXDIRECTCFG4 0x00F2
-#define CFGRXOVR8 0x00BD
-#define RXDIRECTCTRL2 0x00C7
#define ENARXDIRECTCFG3 0x00F3
-#define RXCALCTRL 0x00B4
#define ENARXDIRECTCFG2 0x00F4
-#define CFGRXOVR4 0x00E9
-#define RXSQCTRL 0x00B5
-#define CFGRXOVR6 0x00BF
-#define is_mphy_tx_attr(attr) (attr < RX_MODE)
+#define is_mphy_tx_attr(attr) ((attr) < RX_MODE)
+#define RX_ADV_FINE_GRAN_STEP(x) ((((x) & 0x3) << 1) | 0x1)
+#define SYNC_LEN_FINE(x) ((x) & 0x3F)
+#define SYNC_LEN_COARSE(x) ((1 << 6) | ((x) & 0x3F))
+#define PREP_LEN(x) ((x) & 0xF)
+
#define RX_MIN_ACTIVATETIME_UNIT_US 100
#define HIBERN8TIME_UNIT_US 100
@@ -77,51 +92,54 @@
#define CBPRGPLL2 UNIPRO_CB_OFFSET(0x00F8)
#define CBPRGTUNING UNIPRO_CB_OFFSET(0x00FB)
-#define UNIPRO_CB_OFFSET(x) (0x8000 | x)
+#define UNIPRO_CB_OFFSET(x) (0x8000 | (x))
/*
- * PHY Adpater attributes
+ * PHY Adapter attributes
*/
-#define PA_ACTIVETXDATALANES 0x1560
-#define PA_ACTIVERXDATALANES 0x1580
-#define PA_TXTRAILINGCLOCKS 0x1564
#define PA_PHY_TYPE 0x1500
#define PA_AVAILTXDATALANES 0x1520
-#define PA_AVAILRXDATALANES 0x1540
-#define PA_MINRXTRAILINGCLOCKS 0x1543
-#define PA_TXPWRSTATUS 0x1567
-#define PA_RXPWRSTATUS 0x1582
-#define PA_TXFORCECLOCK 0x1562
-#define PA_TXPWRMODE 0x1563
-#define PA_LEGACYDPHYESCDL 0x1570
#define PA_MAXTXSPEEDFAST 0x1521
#define PA_MAXTXSPEEDSLOW 0x1522
#define PA_MAXRXSPEEDFAST 0x1541
#define PA_MAXRXSPEEDSLOW 0x1542
#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_AVAILRXDATALANES 0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
#define PA_LOCAL_TX_LCC_ENABLE 0x155E
+#define PA_ACTIVETXDATALANES 0x1560
+#define PA_CONNECTEDTXDATALANES 0x1561
+#define PA_TXFORCECLOCK 0x1562
+#define PA_TXPWRMODE 0x1563
+#define PA_TXTRAILINGCLOCKS 0x1564
#define PA_TXSPEEDFAST 0x1565
#define PA_TXSPEEDSLOW 0x1566
-#define PA_REMOTEVERINFO 0x15A0
+#define PA_TXPWRSTATUS 0x1567
#define PA_TXGEAR 0x1568
#define PA_TXTERMINATION 0x1569
#define PA_HSSERIES 0x156A
+#define PA_LEGACYDPHYESCDL 0x1570
#define PA_PWRMODE 0x1571
+#define PA_ACTIVERXDATALANES 0x1580
+#define PA_CONNECTEDRXDATALANES 0x1581
+#define PA_RXPWRSTATUS 0x1582
#define PA_RXGEAR 0x1583
#define PA_RXTERMINATION 0x1584
#define PA_MAXRXPWMGEAR 0x1586
#define PA_MAXRXHSGEAR 0x1587
-#define PA_RXHSUNTERMCAP 0x15A5
-#define PA_RXLSTERMCAP 0x15A6
-#define PA_GRANULARITY 0x15AA
#define PA_PACPREQTIMEOUT 0x1590
#define PA_PACPREQEOBTIMEOUT 0x1591
+#define PA_REMOTEVERINFO 0x15A0
+#define PA_LOGICALLANEMAP 0x15A1
+#define PA_SLEEPNOCONFIGTIME 0x15A2
+#define PA_STALLNOCONFIGTIME 0x15A3
+#define PA_SAVECONFIGTIME 0x15A4
+#define PA_RXHSUNTERMCAP 0x15A5
+#define PA_RXLSTERMCAP 0x15A6
#define PA_HIBERN8TIME 0x15A7
#define PA_LOCALVERINFO 0x15A9
+#define PA_GRANULARITY 0x15AA
#define PA_TACTIVATE 0x15A8
-#define PA_PACPFRAMECOUNT 0x15C0
-#define PA_PACPERRORCOUNT 0x15C1
-#define PA_PHYTESTCONTROL 0x15C2
#define PA_PWRMODEUSERDATA0 0x15B0
#define PA_PWRMODEUSERDATA1 0x15B1
#define PA_PWRMODEUSERDATA2 0x15B2
@@ -134,12 +152,9 @@
#define PA_PWRMODEUSERDATA9 0x15B9
#define PA_PWRMODEUSERDATA10 0x15BA
#define PA_PWRMODEUSERDATA11 0x15BB
-#define PA_CONNECTEDTXDATALANES 0x1561
-#define PA_CONNECTEDRXDATALANES 0x1581
-#define PA_LOGICALLANEMAP 0x15A1
-#define PA_SLEEPNOCONFIGTIME 0x15A2
-#define PA_STALLNOCONFIGTIME 0x15A3
-#define PA_SAVECONFIGTIME 0x15A4
+#define PA_PACPFRAMECOUNT 0x15C0
+#define PA_PACPERRORCOUNT 0x15C1
+#define PA_PHYTESTCONTROL 0x15C2
#define PA_TXHSADAPTTYPE 0x15D4
/* Adapt type for PA_TXHSADAPTTYPE attribute */
@@ -151,9 +166,9 @@
#define PA_HIBERN8_TIME_UNIT_US 100
/*Other attributes*/
+#define VS_POWERSTATE 0xD083
#define VS_MPHYCFGUPDT 0xD085
#define VS_DEBUGOMC 0xD09E
-#define VS_POWERSTATE 0xD083
#define VS_MPHYDISABLE 0xD0C1
#define PA_GRANULARITY_MIN_VAL 1
@@ -163,7 +178,7 @@
#define PA_MAXDATALANES 4
/* PA power modes */
-enum {
+enum ufs_pa_pwr_mode {
FAST_MODE = 1,
SLOW_MODE = 2,
FASTAUTO_MODE = 4,
@@ -171,8 +186,11 @@ enum {
UNCHANGED = 7,
};
+#define PWRMODE_MASK 0xF
+#define PWRMODE_RX_OFFSET 4
+
/* PA TX/RX Frequency Series */
-enum {
+enum ufs_hs_gear_rate {
PA_HS_MODE_A = 1,
PA_HS_MODE_B = 2,
};
@@ -193,14 +211,24 @@ enum ufs_hs_gear_tag {
UFS_HS_G1, /* HS Gear 1 (default for reset) */
UFS_HS_G2, /* HS Gear 2 */
UFS_HS_G3, /* HS Gear 3 */
+ UFS_HS_G4, /* HS Gear 4 */
+ UFS_HS_G5 /* HS Gear 5 */
+};
+
+enum ufs_lanes {
+ UFS_LANE_DONT_CHANGE, /* Don't change Lane */
+ UFS_LANE_1, /* Lane 1 (default for reset) */
+ UFS_LANE_2, /* Lane 2 */
};
enum ufs_unipro_ver {
UFS_UNIPRO_VER_RESERVED = 0,
UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */
UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */
- UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */
- UFS_UNIPRO_VER_MAX = 4, /* UniPro unsupported version */
+ UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */
+ UFS_UNIPRO_VER_1_61 = 4, /* UniPro version 1.61 */
+ UFS_UNIPRO_VER_1_8 = 5, /* UniPro version 1.8 */
+ UFS_UNIPRO_VER_MAX = 6, /* UniPro unsupported version */
/* UniPro version field mask in PA_LOCALVERINFO */
UFS_UNIPRO_VER_MASK = 0xF,
};
@@ -208,27 +236,27 @@ enum ufs_unipro_ver {
/*
* Data Link Layer Attributes
*/
+#define DL_TXPREEMPTIONCAP 0x2000
+#define DL_TC0TXMAXSDUSIZE 0x2001
+#define DL_TC0RXINITCREDITVAL 0x2002
+#define DL_TC1TXMAXSDUSIZE 0x2003
+#define DL_TC1RXINITCREDITVAL 0x2004
+#define DL_TC0TXBUFFERSIZE 0x2005
+#define DL_TC1TXBUFFERSIZE 0x2006
#define DL_TC0TXFCTHRESHOLD 0x2040
#define DL_FC0PROTTIMEOUTVAL 0x2041
#define DL_TC0REPLAYTIMEOUTVAL 0x2042
#define DL_AFC0REQTIMEOUTVAL 0x2043
#define DL_AFC0CREDITTHRESHOLD 0x2044
#define DL_TC0OUTACKTHRESHOLD 0x2045
+#define DL_PEERTC0PRESENT 0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
#define DL_TC1TXFCTHRESHOLD 0x2060
#define DL_FC1PROTTIMEOUTVAL 0x2061
#define DL_TC1REPLAYTIMEOUTVAL 0x2062
#define DL_AFC1REQTIMEOUTVAL 0x2063
#define DL_AFC1CREDITTHRESHOLD 0x2064
#define DL_TC1OUTACKTHRESHOLD 0x2065
-#define DL_TXPREEMPTIONCAP 0x2000
-#define DL_TC0TXMAXSDUSIZE 0x2001
-#define DL_TC0RXINITCREDITVAL 0x2002
-#define DL_TC0TXBUFFERSIZE 0x2005
-#define DL_PEERTC0PRESENT 0x2046
-#define DL_PEERTC0RXINITCREVAL 0x2047
-#define DL_TC1TXMAXSDUSIZE 0x2003
-#define DL_TC1RXINITCREDITVAL 0x2004
-#define DL_TC1TXBUFFERSIZE 0x2006
#define DL_PEERTC1PRESENT 0x2066
#define DL_PEERTC1RXINITCREVAL 0x2067
diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
index 35b61497d9c..1d5e4afac6c 100644
--- a/drivers/usb/cdns3/Kconfig
+++ b/drivers/usb/cdns3/Kconfig
@@ -49,6 +49,13 @@ config SPL_USB_CDNS3_HOST
Host controller is compliant with XHCI so it will use
standard XHCI driver.
+config USB_CDNS3_STARFIVE
+ tristate "Cadence USB3 support on Starfive platforms"
+ default y if STARFIVE_JH7110
+ help
+ Say 'Y' here if you are building for Starfive platforms
+ that contain Cadence USB3 controller core. E.g.: JH7110.
+
config USB_CDNS3_TI
tristate "Cadence USB3 support on TI platforms"
default USB_CDNS3
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
index d6047856091..1f00f23f704 100644
--- a/drivers/usb/cdns3/Makefile
+++ b/drivers/usb/cdns3/Makefile
@@ -8,4 +8,5 @@ cdns3-$(CONFIG_$(XPL_)USB_CDNS3_GADGET) += gadget.o ep0.o
cdns3-$(CONFIG_$(XPL_)USB_CDNS3_HOST) += host.o
+obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o
obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o
diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c
new file mode 100644
index 00000000000..78ceb831b19
--- /dev/null
+++ b/drivers/usb/cdns3/cdns3-starfive.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ *
+ * Author: Minda Chen <minda.chen@starfivetech.com>
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/usb/otg.h>
+#include <malloc.h>
+#include <reset.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include "core.h"
+
+#define USB_STRAP_HOST BIT(17)
+#define USB_STRAP_DEVICE BIT(18)
+#define USB_STRAP_MASK GENMASK(18, 16)
+
+#define USB_SUSPENDM_HOST BIT(19)
+#define USB_SUSPENDM_MASK BIT(19)
+
+#define USB_MISC_CFG_MASK GENMASK(23, 20)
+#define USB_SUSPENDM_BYPS BIT(20)
+#define USB_PLL_EN BIT(22)
+#define USB_REFCLK_MODE BIT(23)
+
+struct cdns_starfive {
+ struct udevice *dev;
+ struct regmap *stg_syscon;
+ struct reset_ctl_bulk resets;
+ struct clk_bulk clks;
+ u32 stg_usb_mode;
+ enum usb_dr_mode mode;
+};
+
+static void cdns_mode_init(struct cdns_starfive *data, enum usb_dr_mode mode)
+{
+ unsigned int strap, suspendm;
+
+ regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
+ USB_MISC_CFG_MASK,
+ USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE);
+
+ switch (mode) {
+ case USB_DR_MODE_HOST:
+ strap = USB_STRAP_HOST;
+ suspendm = USB_SUSPENDM_HOST;
+ break;
+ case USB_DR_MODE_PERIPHERAL:
+ strap = USB_STRAP_DEVICE;
+ suspendm = 0;
+ break;
+ default:
+ return;
+ }
+
+ regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
+ USB_SUSPENDM_MASK | USB_STRAP_MASK,
+ strap | suspendm);
+}
+
+static void cdns_clk_rst_deinit(struct cdns_starfive *data)
+{
+ reset_assert_bulk(&data->resets);
+ clk_disable_bulk(&data->clks);
+}
+
+static int cdns_clk_rst_init(struct cdns_starfive *data)
+{
+ int ret;
+
+ ret = clk_get_bulk(data->dev, &data->clks);
+ if (ret)
+ return ret;
+
+ ret = reset_get_bulk(data->dev, &data->resets);
+ if (ret)
+ goto err_clk;
+
+ ret = clk_enable_bulk(&data->clks);
+ if (ret) {
+ dev_err(data->dev, "clk enable failed: %d\n", ret);
+ goto err_en_clk;
+ }
+
+ ret = reset_deassert_bulk(&data->resets);
+ if (ret) {
+ dev_err(data->dev, "reset deassert failed: %d\n", ret);
+ goto err_reset;
+ }
+
+ return 0;
+
+err_reset:
+ clk_disable_bulk(&data->clks);
+err_en_clk:
+ reset_release_bulk(&data->resets);
+err_clk:
+ clk_release_bulk(&data->clks);
+
+ return ret;
+}
+
+static int cdns_starfive_get_syscon(struct cdns_starfive *data)
+{
+ struct ofnode_phandle_args phandle;
+ int ret;
+
+ ret = dev_read_phandle_with_args(data->dev, "starfive,stg-syscon", NULL, 1, 0,
+ &phandle);
+ if (ret < 0) {
+ dev_err(data->dev, "Can't get stg cfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ data->stg_syscon = syscon_node_to_regmap(phandle.node);
+ if (IS_ERR(data->stg_syscon)) {
+ dev_err(data->dev, "fail to get regmap: %d\n", (int)PTR_ERR(data->stg_syscon));
+ return PTR_ERR(data->stg_syscon);
+ }
+
+ data->stg_usb_mode = phandle.args[0];
+
+ return 0;
+}
+
+static int cdns_starfive_probe(struct udevice *dev)
+{
+ struct cdns_starfive *data = dev_get_plat(dev);
+ enum usb_dr_mode dr_mode;
+ int ret;
+
+ data->dev = dev;
+
+ ret = cdns_starfive_get_syscon(data);
+ if (ret)
+ return ret;
+
+ dr_mode = usb_get_dr_mode(dev_ofnode(dev));
+
+ data->mode = dr_mode;
+ ret = cdns_clk_rst_init(data);
+ if (ret) {
+ dev_err(data->dev, "clk reset failed: %d\n", ret);
+ return ret;
+ }
+ cdns_mode_init(data, dr_mode);
+
+ return 0;
+}
+
+static int cdns_starfive_remove(struct udevice *dev)
+{
+ struct cdns_starfive *data = dev_get_plat(dev);
+
+ cdns_clk_rst_deinit(data);
+ return 0;
+}
+
+static const struct udevice_id cdns_starfive_of_match[] = {
+ { .compatible = "starfive,jh7110-usb", },
+ {},
+};
+
+U_BOOT_DRIVER(cdns_starfive) = {
+ .name = "cdns-starfive",
+ .id = UCLASS_NOP,
+ .of_match = cdns_starfive_of_match,
+ .bind = cdns3_bind,
+ .probe = cdns_starfive_probe,
+ .remove = cdns_starfive_remove,
+ .plat_auto = sizeof(struct cdns_starfive),
+ .flags = DM_FLAG_OS_PREPARE,
+};
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index 4cfd38ec245..4434dc15bec 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -410,6 +410,9 @@ int cdns3_bind(struct udevice *parent)
name = ofnode_get_name(node);
dr_mode = usb_get_dr_mode(node);
+ if (dr_mode == USB_DR_MODE_UNKNOWN)
+ dr_mode = usb_get_dr_mode(dev_ofnode(parent));
+
switch (dr_mode) {
#if defined(CONFIG_SPL_USB_HOST) || \
(!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST))
diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c
index 47874fec29e..cbb13342343 100644
--- a/drivers/usb/cdns3/drd.c
+++ b/drivers/usb/cdns3/drd.c
@@ -217,15 +217,19 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns)
int cdns3_drd_update_mode(struct cdns3 *cdns)
{
int ret = 0;
+ int mode;
switch (cdns->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
+ mode = PHY_MODE_USB_DEVICE;
ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
break;
case USB_DR_MODE_HOST:
+ mode = PHY_MODE_USB_HOST;
ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST);
break;
case USB_DR_MODE_OTG:
+ mode = PHY_MODE_USB_OTG;
ret = cdns3_init_otg_mode(cdns);
break;
default:
@@ -234,6 +238,16 @@ int cdns3_drd_update_mode(struct cdns3 *cdns)
return -EINVAL;
}
+ ret = generic_phy_set_mode(&cdns->usb2_phy, mode, 0);
+ if (ret) {
+ dev_err(cdns->dev, "Set usb 2.0 PHY mode failed %d\n", ret);
+ return ret;
+ }
+
+ ret = generic_phy_set_mode(&cdns->usb3_phy, mode, 0);
+ if (ret)
+ dev_err(cdns->dev, "Set usb 3.0 PHY mode failed %d\n", ret);
+
return ret;
}
diff --git a/drivers/usb/emul/sandbox_keyb.c b/drivers/usb/emul/sandbox_keyb.c
index db769883ba3..5ed8c2c799a 100644
--- a/drivers/usb/emul/sandbox_keyb.c
+++ b/drivers/usb/emul/sandbox_keyb.c
@@ -38,7 +38,7 @@ enum {
*
*/
struct sandbox_keyb_priv {
- struct membuff in;
+ struct membuf in;
};
struct sandbox_keyb_plat {
@@ -167,7 +167,7 @@ int sandbox_usb_keyb_add_string(struct udevice *dev,
struct sandbox_keyb_priv *priv = dev_get_priv(dev);
int ret;
- ret = membuff_put(&priv->in, scancode, USB_KBD_BOOT_REPORT_SIZE);
+ ret = membuf_put(&priv->in, scancode, USB_KBD_BOOT_REPORT_SIZE);
if (ret != USB_KBD_BOOT_REPORT_SIZE)
return -ENOSPC;
@@ -194,7 +194,7 @@ static int sandbox_keyb_interrupt(struct udevice *dev, struct usb_device *udev,
if (length < USB_KBD_BOOT_REPORT_SIZE)
return 0;
- membuff_get(&priv->in, buffer, USB_KBD_BOOT_REPORT_SIZE);
+ membuf_get(&priv->in, buffer, USB_KBD_BOOT_REPORT_SIZE);
return 0;
}
@@ -220,7 +220,7 @@ static int sandbox_keyb_probe(struct udevice *dev)
struct sandbox_keyb_priv *priv = dev_get_priv(dev);
/* Provide an 80 character keyboard buffer */
- return membuff_new(&priv->in, 80 * USB_KBD_BOOT_REPORT_SIZE);
+ return membuf_new(&priv->in, 80 * USB_KBD_BOOT_REPORT_SIZE);
}
static const struct dm_usb_ops sandbox_usb_keyb_ops = {
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 4bda224ff1a..db5f8895a33 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,7 +35,3 @@ endif
endif
obj-$(CONFIG_CI_UDC) += ci_udc.o
-
-# Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
-# This is really only N900 and USBTTY now.
-obj-$(CONFIG_USB_DEVICE) += core.o ep0.o
diff --git a/drivers/usb/gadget/core.c b/drivers/usb/gadget/core.c
deleted file mode 100644
index bcb1ad3082c..00000000000
--- a/drivers/usb/gadget/core.c
+++ /dev/null
@@ -1,621 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- */
-
-#include <log.h>
-#include <malloc.h>
-#include <serial.h>
-#include <usbdevice.h>
-
-#define MAX_INTERFACES 2
-
-int maxstrings = 20;
-
-/* Global variables ************************************************************************** */
-
-struct usb_string_descriptor **usb_strings;
-
-int usb_devices;
-
-extern struct usb_function_driver ep0_driver;
-
-int registered_functions;
-int registered_devices;
-
-__maybe_unused static char *usbd_device_events[] = {
- "DEVICE_UNKNOWN",
- "DEVICE_INIT",
- "DEVICE_CREATE",
- "DEVICE_HUB_CONFIGURED",
- "DEVICE_RESET",
- "DEVICE_ADDRESS_ASSIGNED",
- "DEVICE_CONFIGURED",
- "DEVICE_SET_INTERFACE",
- "DEVICE_SET_FEATURE",
- "DEVICE_CLEAR_FEATURE",
- "DEVICE_DE_CONFIGURED",
- "DEVICE_BUS_INACTIVE",
- "DEVICE_BUS_ACTIVITY",
- "DEVICE_POWER_INTERRUPTION",
- "DEVICE_HUB_RESET",
- "DEVICE_DESTROY",
- "DEVICE_FUNCTION_PRIVATE",
-};
-
-__maybe_unused static char *usbd_device_status[] = {
- "USBD_OPENING",
- "USBD_OK",
- "USBD_SUSPENDED",
- "USBD_CLOSING",
-};
-
-#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
-
-/* Descriptor support functions ************************************************************** */
-
-/**
- * usbd_get_string - find and return a string descriptor
- * @index: string index to return
- *
- * Find an indexed string and return a pointer to a it.
- */
-struct usb_string_descriptor *usbd_get_string (__u8 index)
-{
- if (index >= maxstrings) {
- return NULL;
- }
- return usb_strings[index];
-}
-
-/* Access to device descriptor functions ***************************************************** */
-
-/* *
- * usbd_device_configuration_instance - find a configuration instance for this device
- * @device:
- * @configuration: index to configuration, 0 - N-1
- *
- * Get specifed device configuration. Index should be bConfigurationValue-1.
- */
-static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
- unsigned int port, unsigned int configuration)
-{
- if (configuration >= device->configurations)
- return NULL;
-
- return device->configuration_instance_array + configuration;
-}
-
-/* *
- * usbd_device_interface_instance
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- *
- * Return the specified interface descriptor for the specified device.
- */
-struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
-{
- struct usb_configuration_instance *configuration_instance;
-
- if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
- return NULL;
- }
- if (interface >= configuration_instance->interfaces) {
- return NULL;
- }
- return configuration_instance->interface_instance_array + interface;
-}
-
-/* *
- * usbd_device_alternate_descriptor_list
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified alternate descriptor for the specified device.
- */
-struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
-{
- struct usb_interface_instance *interface_instance;
-
- if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
- return NULL;
- }
-
- if (alternate >= interface_instance->alternates) {
- return NULL;
- }
-
- return interface_instance->alternates_instance_array + alternate;
-}
-
-/* *
- * usbd_device_device_descriptor
- * @device: which device
- * @configuration: index to configuration, 0 - N-1
- * @port: which port
- *
- * Return the specified configuration descriptor for the specified device.
- */
-struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
-{
- return (device->device_descriptor);
-}
-
-/**
- * usbd_device_configuration_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- *
- * Return the specified configuration descriptor for the specified device.
- */
-struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
- usb_device_instance
- *device, int port, int configuration)
-{
- struct usb_configuration_instance *configuration_instance;
- if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
- return NULL;
- }
- return (configuration_instance->configuration_descriptor);
-}
-
-/**
- * usbd_device_interface_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified interface descriptor for the specified device.
- */
-struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
- *device, int port, int configuration, int interface, int alternate)
-{
- struct usb_interface_instance *interface_instance;
- if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
- return NULL;
- }
- if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
- return NULL;
- }
- return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
-}
-
-/**
- * usbd_device_endpoint_descriptor_index
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: index setting
- * @index: which index
- *
- * Return the specified endpoint descriptor for the specified device.
- */
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
- *device, int port, int configuration, int interface, int alternate, int index)
-{
- struct usb_alternate_instance *alternate_instance;
-
- if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
- return NULL;
- }
- if (index >= alternate_instance->endpoints) {
- return NULL;
- }
- return *(alternate_instance->endpoints_descriptor_array + index);
-}
-
-/**
- * usbd_device_endpoint_transfersize
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @index: which index
- *
- * Return the specified endpoint transfer size;
- */
-int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
-{
- struct usb_alternate_instance *alternate_instance;
-
- if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
- return 0;
- }
- if (index >= alternate_instance->endpoints) {
- return 0;
- }
- return *(alternate_instance->endpoint_transfersize_array + index);
-}
-
-/**
- * usbd_device_endpoint_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- * @endpoint: which endpoint
- *
- * Return the specified endpoint descriptor for the specified device.
- */
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
-{
- struct usb_endpoint_descriptor *endpoint_descriptor;
- int i;
-
- for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
- if (endpoint_descriptor->bEndpointAddress == endpoint) {
- return endpoint_descriptor;
- }
- }
- return NULL;
-}
-
-/**
- * usbd_endpoint_halted
- * @device: point to struct usb_device_instance
- * @endpoint: endpoint to check
- *
- * Return non-zero if endpoint is halted.
- */
-int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
-{
- return (device->status == USB_STATUS_HALT);
-}
-
-/**
- * usbd_rcv_complete - complete a receive
- * @endpoint:
- * @len:
- * @urb_bad:
- *
- * Called from rcv interrupt to complete.
- */
-void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
-{
- if (endpoint) {
- struct urb *rcv_urb;
-
- /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
-
- /* if we had an urb then update actual_length, dispatch if neccessary */
- if ((rcv_urb = endpoint->rcv_urb)) {
-
- /*usbdbg("actual: %d buffer: %d\n", */
- /*rcv_urb->actual_length, rcv_urb->buffer_length); */
-
- /* check the urb is ok, are we adding data less than the packetsize */
- if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
- /*usbdbg("updating actual_length by %d\n",len); */
-
- /* increment the received data size */
- rcv_urb->actual_length += len;
-
- } else {
- usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
- rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
-
- rcv_urb->actual_length = 0;
- rcv_urb->status = RECV_ERROR;
- }
- } else {
- usberr("no rcv_urb!");
- }
- } else {
- usberr("no endpoint!");
- }
-
-}
-
-/**
- * usbd_tx_complete - complete a transmit
- * @endpoint:
- * @resetart:
- *
- * Called from tx interrupt to complete.
- */
-void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
-{
- if (endpoint) {
- struct urb *tx_urb;
-
- /* if we have a tx_urb advance or reset, finish if complete */
- if ((tx_urb = endpoint->tx_urb)) {
- int sent = endpoint->last;
- endpoint->sent += sent;
- endpoint->last -= sent;
-
- if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
- tx_urb->actual_length = 0;
- endpoint->sent = 0;
- endpoint->last = 0;
-
- /* Remove from active, save for re-use */
- urb_detach(tx_urb);
- urb_append(&endpoint->done, tx_urb);
- /*usbdbg("done->next %p, tx_urb %p, done %p", */
- /* endpoint->done.next, tx_urb, &endpoint->done); */
-
- endpoint->tx_urb = first_urb_detached(&endpoint->tx);
- if( endpoint->tx_urb ) {
- endpoint->tx_queue--;
- usbdbg("got urb from tx list");
- }
- if( !endpoint->tx_urb ) {
- /*usbdbg("taking urb from done list"); */
- endpoint->tx_urb = first_urb_detached(&endpoint->done);
- }
- if( !endpoint->tx_urb ) {
- usbdbg("allocating new urb for tx_urb");
- endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
- }
- }
- }
- }
-}
-
-/* URB linked list functions ***************************************************** */
-
-/*
- * Initialize an urb_link to be a single element list.
- * If the urb_link is being used as a distinguished list head
- * the list is empty when the head is the only link in the list.
- */
-void urb_link_init (urb_link * ul)
-{
- if (ul) {
- ul->prev = ul->next = ul;
- }
-}
-
-/*
- * Detach an urb_link from a list, and set it
- * up as a single element list, so no dangling
- * pointers can be followed, and so it can be
- * joined to another list if so desired.
- */
-void urb_detach (struct urb *urb)
-{
- if (urb) {
- urb_link *ul = &urb->link;
- ul->next->prev = ul->prev;
- ul->prev->next = ul->next;
- urb_link_init (ul);
- }
-}
-
-/*
- * Return the first urb_link in a list with a distinguished
- * head "hd", or NULL if the list is empty. This will also
- * work as a predicate, returning NULL if empty, and non-NULL
- * otherwise.
- */
-urb_link *first_urb_link (urb_link * hd)
-{
- urb_link *nx;
- if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
- /* There is at least one element in the list */
- /* (besides the distinguished head). */
- return (nx);
- }
- /* The list is empty */
- return (NULL);
-}
-
-/*
- * Return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- */
-struct urb *first_urb (urb_link * hd)
-{
- urb_link *nx;
- if (NULL == (nx = first_urb_link (hd))) {
- /* The list is empty */
- return (NULL);
- }
- return (p2surround (struct urb, link, nx));
-}
-
-/*
- * Detach and return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- *
- */
-struct urb *first_urb_detached (urb_link * hd)
-{
- struct urb *urb;
- if ((urb = first_urb (hd))) {
- urb_detach (urb);
- }
- return urb;
-}
-
-/*
- * Append an urb_link (or a whole list of
- * urb_links) to the tail of another list
- * of urb_links.
- */
-void urb_append (urb_link * hd, struct urb *urb)
-{
- if (hd && urb) {
- urb_link *new = &urb->link;
-
- /* This allows the new urb to be a list of urbs, */
- /* with new pointing at the first, but the link */
- /* must be initialized. */
- /* Order is important here... */
- urb_link *pul = hd->prev;
- new->prev->next = hd;
- hd->prev = new->prev;
- new->prev = pul;
- pul->next = new;
- }
-}
-
-/* URB create/destroy functions ***************************************************** */
-
-/**
- * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
- * @device: device instance
- * @endpoint: endpoint
- *
- * Allocate an urb structure. The usb device urb structure is used to
- * contain all data associated with a transfer, including a setup packet for
- * control transfers.
- *
- * NOTE: endpoint_address MUST contain a direction flag.
- */
-struct urb *usbd_alloc_urb (struct usb_device_instance *device,
- struct usb_endpoint_instance *endpoint)
-{
- struct urb *urb;
-
- if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
- usberr (" F A T A L: malloc(%zu) FAILED!!!!",
- sizeof (struct urb));
- return NULL;
- }
-
- /* Fill in known fields */
- memset (urb, 0, sizeof (struct urb));
- urb->endpoint = endpoint;
- urb->device = device;
- urb->buffer = (u8 *) urb->buffer_data;
- urb->buffer_length = sizeof (urb->buffer_data);
-
- urb_link_init (&urb->link);
-
- return urb;
-}
-
-/**
- * usbd_dealloc_urb - deallocate an URB and associated buffer
- * @urb: pointer to an urb structure
- *
- * Deallocate an urb structure and associated data.
- */
-void usbd_dealloc_urb (struct urb *urb)
-{
- if (urb) {
- free (urb);
- }
-}
-
-/* Event signaling functions ***************************************************** */
-
-/**
- * usbd_device_event - called to respond to various usb events
- * @device: pointer to struct device
- * @event: event to respond to
- *
- * Used by a Bus driver to indicate an event.
- */
-void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
-{
- usb_device_state_t state;
-
- if (!device || !device->bus) {
- usberr("(%p,%d) NULL device or device->bus", device, event);
- return;
- }
-
- state = device->device_state;
-
- usbinfo("%s", usbd_device_events[event]);
-
- switch (event) {
- case DEVICE_UNKNOWN:
- break;
- case DEVICE_INIT:
- device->device_state = STATE_INIT;
- break;
-
- case DEVICE_CREATE:
- device->device_state = STATE_ATTACHED;
- break;
-
- case DEVICE_HUB_CONFIGURED:
- device->device_state = STATE_POWERED;
- break;
-
- case DEVICE_RESET:
- device->device_state = STATE_DEFAULT;
- device->address = 0;
- break;
-
- case DEVICE_ADDRESS_ASSIGNED:
- device->device_state = STATE_ADDRESSED;
- break;
-
- case DEVICE_CONFIGURED:
- device->device_state = STATE_CONFIGURED;
- break;
-
- case DEVICE_DE_CONFIGURED:
- device->device_state = STATE_ADDRESSED;
- break;
-
- case DEVICE_BUS_INACTIVE:
- if (device->status != USBD_CLOSING) {
- device->status = USBD_SUSPENDED;
- }
- break;
- case DEVICE_BUS_ACTIVITY:
- if (device->status != USBD_CLOSING) {
- device->status = USBD_OK;
- }
- break;
-
- case DEVICE_SET_INTERFACE:
- break;
- case DEVICE_SET_FEATURE:
- break;
- case DEVICE_CLEAR_FEATURE:
- break;
-
- case DEVICE_POWER_INTERRUPTION:
- device->device_state = STATE_POWERED;
- break;
- case DEVICE_HUB_RESET:
- device->device_state = STATE_ATTACHED;
- break;
- case DEVICE_DESTROY:
- device->device_state = STATE_UNKNOWN;
- break;
-
- case DEVICE_FUNCTION_PRIVATE:
- break;
-
- default:
- usbdbg("event %d - not handled",event);
- break;
- }
- debug("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
- device->name, event, state,
- device->device_state, device->status, device->address);
-
- /* tell the bus interface driver */
- if( device->event ) {
- /* usbdbg("calling device->event"); */
- device->event(device, event, data);
- }
-}
diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c
deleted file mode 100644
index 8c7fc17c2ea..00000000000
--- a/drivers/usb/gadget/ep0.c
+++ /dev/null
@@ -1,619 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * (C) Copyright 2006
- * Bryan O'Donoghue, deckard@CodeHermit.ie
- *
- * Based on
- * linux/drivers/usbd/ep0.c
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- */
-
-/*
- * This is the builtin ep0 control function. It implements all required functionality
- * for responding to control requests (SETUP packets).
- *
- * XXX
- *
- * Currently we do not pass any SETUP packets (or other) to the configured
- * function driver. This may need to change.
- *
- * XXX
- *
- * As alluded to above, a simple callback cdc_recv_setup has been implemented
- * in the usb_device data structure to facilicate passing
- * Common Device Class packets to a function driver.
- *
- * XXX
- */
-
-#include <serial.h>
-#include <usbdevice.h>
-
-#if 0
-#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
-#else
-#define dbg_ep0(lvl,fmt,args...)
-#endif
-
-__maybe_unused static char *usbd_device_descriptors[] = {
- "UNKNOWN", /* 0 */
- "DEVICE", /* 1 */
- "CONFIG", /* 2 */
- "STRING", /* 3 */
- "INTERFACE", /* 4 */
- "ENDPOINT", /* 5 */
- "DEVICE QUALIFIER", /* 6 */
- "OTHER SPEED", /* 7 */
- "INTERFACE POWER", /* 8 */
-};
-
-#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
- usbd_device_descriptors[x] : "UNKNOWN")
-
-__maybe_unused static char *usbd_device_states[] = {
- "STATE_INIT",
- "STATE_CREATED",
- "STATE_ATTACHED",
- "STATE_POWERED",
- "STATE_DEFAULT",
- "STATE_ADDRESSED",
- "STATE_CONFIGURED",
- "STATE_UNKNOWN",
-};
-
-#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
-
-__maybe_unused static char *usbd_device_requests[] = {
- "GET STATUS", /* 0 */
- "CLEAR FEATURE", /* 1 */
- "RESERVED", /* 2 */
- "SET FEATURE", /* 3 */
- "RESERVED", /* 4 */
- "SET ADDRESS", /* 5 */
- "GET DESCRIPTOR", /* 6 */
- "SET DESCRIPTOR", /* 7 */
- "GET CONFIGURATION", /* 8 */
- "SET CONFIGURATION", /* 9 */
- "GET INTERFACE", /* 10 */
- "SET INTERFACE", /* 11 */
- "SYNC FRAME", /* 12 */
-};
-
-#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
-
-/* EP0 Configuration Set ********************************************************************* */
-
-/**
- * ep0_get_status - fill in URB data with appropriate status
- * @device:
- * @urb:
- * @index:
- * @requesttype:
- *
- */
-static int ep0_get_status (struct usb_device_instance *device,
- struct urb *urb, int index, int requesttype)
-{
- char *cp;
-
- urb->actual_length = 2;
- cp = (char*)urb->buffer;
- cp[0] = cp[1] = 0;
-
- switch (requesttype) {
- case USB_REQ_RECIPIENT_DEVICE:
- cp[0] = USB_STATUS_SELFPOWERED;
- break;
- case USB_REQ_RECIPIENT_INTERFACE:
- break;
- case USB_REQ_RECIPIENT_ENDPOINT:
- cp[0] = usbd_endpoint_halted (device, index);
- break;
- case USB_REQ_RECIPIENT_OTHER:
- urb->actual_length = 0;
- default:
- break;
- }
- dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
- return 0;
-}
-
-/**
- * ep0_get_one
- * @device:
- * @urb:
- * @result:
- *
- * Set a single byte value in the urb send buffer. Return non-zero to signal
- * a request error.
- */
-static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
- __u8 result)
-{
- urb->actual_length = 1; /* XXX 2? */
- ((char *) urb->buffer)[0] = result;
- return 0;
-}
-
-/**
- * copy_config
- * @urb: pointer to urb
- * @data: pointer to configuration data
- * @length: length of data
- *
- * Copy configuration data to urb transfer buffer if there is room for it.
- */
-void copy_config (struct urb *urb, void *data, int max_length,
- int max_buf)
-{
- int available;
- int length;
-
- /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
- /* urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
-
- if (!data) {
- dbg_ep0 (1, "data is NULL");
- return;
- }
- length = max_length;
-
- if (length > max_length) {
- dbg_ep0 (1, "length: %d >= max_length: %d", length,
- max_length);
- return;
- }
- /*dbg_ep0(1, " actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
- /* urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
-
- if ((available =
- /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
- return;
- }
- /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
- /* urb->actual_length, urb->buffer_length, max_buf, length, available); */
-
- if (length > available) {
- length = available;
- }
- /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
- /* urb->actual_length, urb->buffer_length, max_buf, length, available); */
-
- memcpy (urb->buffer + urb->actual_length, data, length);
- urb->actual_length += length;
-
- dbg_ep0 (3,
- "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
- urb->actual_length, urb->buffer_length, max_buf, max_length,
- available);
-}
-
-/**
- * ep0_get_descriptor
- * @device:
- * @urb:
- * @max:
- * @descriptor_type:
- * @index:
- *
- * Called by ep0_rx_process for a get descriptor device command. Determine what
- * descriptor is being requested, copy to send buffer. Return zero if ok to send,
- * return non-zero to signal a request error.
- */
-static int ep0_get_descriptor (struct usb_device_instance *device,
- struct urb *urb, int max, int descriptor_type,
- int index)
-{
- int port = 0; /* XXX compound device */
-
- /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
-
- if (!urb || !urb->buffer || !urb->buffer_length
- || (urb->buffer_length < 255)) {
- dbg_ep0 (2, "invalid urb %p", urb);
- return -1L;
- }
-
- /* setup tx urb */
- urb->actual_length = 0;
-
- dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
-
- switch (descriptor_type) {
- case USB_DESCRIPTOR_TYPE_DEVICE:
- {
- struct usb_device_descriptor *device_descriptor;
- if (!
- (device_descriptor =
- usbd_device_device_descriptor (device, port))) {
- return -1;
- }
- /* copy descriptor for this device */
- copy_config (urb, device_descriptor,
- sizeof (struct usb_device_descriptor),
- max);
-
- /* correct the correct control endpoint 0 max packet size into the descriptor */
- device_descriptor =
- (struct usb_device_descriptor *) urb->buffer;
-
- }
- dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
- break;
-
- case USB_DESCRIPTOR_TYPE_CONFIGURATION:
- {
- struct usb_configuration_descriptor
- *configuration_descriptor;
- struct usb_device_descriptor *device_descriptor;
- if (!
- (device_descriptor =
- usbd_device_device_descriptor (device, port))) {
- return -1;
- }
- /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
- if (index >= device_descriptor->bNumConfigurations) {
- dbg_ep0 (0, "index too large: %d >= %d", index,
- device_descriptor->
- bNumConfigurations);
- return -1;
- }
-
- if (!
- (configuration_descriptor =
- usbd_device_configuration_descriptor (device,
- port,
- index))) {
- dbg_ep0 (0,
- "usbd_device_configuration_descriptor failed: %d",
- index);
- return -1;
- }
- dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
- copy_config (urb, configuration_descriptor,
-
- cpu_to_le16(configuration_descriptor->wTotalLength),
- max);
- }
-
- break;
-
- case USB_DESCRIPTOR_TYPE_STRING:
- {
- struct usb_string_descriptor *string_descriptor;
- if (!(string_descriptor = usbd_get_string (index))) {
- dbg_ep0(0, "Invalid string index %d\n", index);
- return -1;
- }
- dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
- copy_config (urb, string_descriptor, string_descriptor->bLength, max);
- }
- break;
- case USB_DESCRIPTOR_TYPE_INTERFACE:
- dbg_ep0(2, "USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
- return -1;
- case USB_DESCRIPTOR_TYPE_ENDPOINT:
- dbg_ep0(2, "USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
- return -1;
- case USB_DESCRIPTOR_TYPE_HID:
- {
- dbg_ep0(2, "USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
- return -1; /* unsupported at this time */
-#if 0
- int bNumInterface =
- le16_to_cpu (urb->device_request.wIndex);
- int bAlternateSetting = 0;
- int class = 0;
- struct usb_class_descriptor *class_descriptor;
-
- if (!(class_descriptor =
- usbd_device_class_descriptor_index (device,
- port, 0,
- bNumInterface,
- bAlternateSetting,
- class))
- || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
- dbg_ep0 (3, "[%d] interface is not HID",
- bNumInterface);
- return -1;
- }
- /* copy descriptor for this class */
- copy_config (urb, class_descriptor,
- class_descriptor->descriptor.hid.bLength,
- max);
-#endif
- }
- break;
- case USB_DESCRIPTOR_TYPE_REPORT:
- {
- dbg_ep0(2, "USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
- return -1; /* unsupported at this time */
-#if 0
- int bNumInterface =
- le16_to_cpu (urb->device_request.wIndex);
- int bAlternateSetting = 0;
- int class = 0;
- struct usb_class_report_descriptor *report_descriptor;
-
- if (!(report_descriptor =
- usbd_device_class_report_descriptor_index
- (device, port, 0, bNumInterface,
- bAlternateSetting, class))
- || report_descriptor->bDescriptorType !=
- USB_DT_REPORT) {
- dbg_ep0 (3, "[%d] descriptor is not REPORT",
- bNumInterface);
- return -1;
- }
- /* copy report descriptor for this class */
- /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
- if (max - urb->actual_length > 0) {
- int length =
- min(report_descriptor->wLength,
- max - urb->actual_length);
- memcpy (urb->buffer + urb->actual_length,
- &report_descriptor->bData[0], length);
- urb->actual_length += length;
- }
-#endif
- }
- break;
- case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
- return -1;
-
- default:
- return -1;
- }
-
- dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
- urb->buffer, urb->buffer_length, urb->actual_length,
- device->bus->endpoint_array[0].tx_packetSize);
-/*
- if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
- dbg_ep0(0, "adding null byte");
- urb->buffer[urb->actual_length++] = 0;
- dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
- urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
- }
-*/
- return 0;
-
-}
-
-/**
- * ep0_recv_setup - called to indicate URB has been received
- * @urb: pointer to struct urb
- *
- * Check if this is a setup packet, process the device request, put results
- * back into the urb and return zero or non-zero to indicate success (DATA)
- * or failure (STALL).
- *
- */
-int ep0_recv_setup (struct urb *urb)
-{
- /*struct usb_device_request *request = urb->buffer; */
- /*struct usb_device_instance *device = urb->device; */
-
- struct usb_device_request *request;
- struct usb_device_instance *device;
- int address;
-
- dbg_ep0 (0, "entering ep0_recv_setup()");
- if (!urb || !urb->device) {
- dbg_ep0 (3, "invalid URB %p", urb);
- return -1;
- }
-
- request = &urb->device_request;
- device = urb->device;
-
- dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
-
- /*dbg_ep0(2, "- - - - - - - - - -"); */
-
- dbg_ep0 (2,
- "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
- request->bmRequestType, request->bRequest,
- le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
- le16_to_cpu (request->wLength),
- USBD_DEVICE_REQUESTS (request->bRequest));
-
- /* handle USB Standard Request (c.f. USB Spec table 9-2) */
- if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
- if(device->device_state <= STATE_CONFIGURED){
- /* Attempt to handle a CDC specific request if we are
- * in the configured state.
- */
- return device->cdc_recv_setup(request,urb);
- }
- dbg_ep0 (1, "non standard request: %x",
- request->bmRequestType & USB_REQ_TYPE_MASK);
- return -1; /* Stall here */
- }
-
- switch (device->device_state) {
- case STATE_CREATED:
- case STATE_ATTACHED:
- case STATE_POWERED:
- /* It actually is important to allow requests in these states,
- * Windows will request descriptors before assigning an
- * address to the client.
- */
-
- /*dbg_ep0 (1, "request %s not allowed in this state: %s", */
- /* USBD_DEVICE_REQUESTS(request->bRequest), */
- /* usbd_device_states[device->device_state]); */
- /*return -1; */
- break;
-
- case STATE_INIT:
- case STATE_DEFAULT:
- switch (request->bRequest) {
- case USB_REQ_GET_STATUS:
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- case USB_REQ_SET_DESCRIPTOR:
- /* case USB_REQ_SET_CONFIGURATION: */
- case USB_REQ_SET_INTERFACE:
- dbg_ep0 (1,
- "request %s not allowed in DEFAULT state: %s",
- USBD_DEVICE_REQUESTS (request->bRequest),
- usbd_device_states[device->device_state]);
- return -1;
-
- case USB_REQ_SET_CONFIGURATION:
- case USB_REQ_SET_ADDRESS:
- case USB_REQ_GET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- break;
- }
- case STATE_ADDRESSED:
- case STATE_CONFIGURED:
- break;
- case STATE_UNKNOWN:
- dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
- USBD_DEVICE_REQUESTS (request->bRequest),
- usbd_device_states[device->device_state]);
- return -1;
- }
-
- /* handle all requests that return data (direction bit set on bm RequestType) */
- if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
-
- dbg_ep0 (3, "Device-to-Host");
-
- switch (request->bRequest) {
-
- case USB_REQ_GET_STATUS:
- return ep0_get_status (device, urb, request->wIndex,
- request->bmRequestType &
- USB_REQ_RECIPIENT_MASK);
-
- case USB_REQ_GET_DESCRIPTOR:
- return ep0_get_descriptor (device, urb,
- le16_to_cpu (request->wLength),
- le16_to_cpu (request->wValue) >> 8,
- le16_to_cpu (request->wValue) & 0xff);
-
- case USB_REQ_GET_CONFIGURATION:
- dbg_ep0(2, "get config %d\n", device->configuration);
- return ep0_get_one (device, urb,
- device->configuration);
-
- case USB_REQ_GET_INTERFACE:
- return ep0_get_one (device, urb, device->alternate);
-
- case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
- return -1;
-
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- case USB_REQ_SET_ADDRESS:
- case USB_REQ_SET_DESCRIPTOR:
- case USB_REQ_SET_CONFIGURATION:
- case USB_REQ_SET_INTERFACE:
- return -1;
- }
- }
- /* handle the requests that do not return data */
- else {
-
- /*dbg_ep0(3, "Host-to-Device"); */
- switch (request->bRequest) {
-
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- dbg_ep0 (0, "Host-to-Device");
- switch (request->
- bmRequestType & USB_REQ_RECIPIENT_MASK) {
- case USB_REQ_RECIPIENT_DEVICE:
- /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
- /* XXX fall through for now as we do not support either */
- case USB_REQ_RECIPIENT_INTERFACE:
- case USB_REQ_RECIPIENT_OTHER:
- dbg_ep0 (0, "request %s not",
- USBD_DEVICE_REQUESTS (request->bRequest));
- default:
- return -1;
-
- case USB_REQ_RECIPIENT_ENDPOINT:
- dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
- if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
- /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
- /* request->bRequest == USB_REQ_SET_FEATURE); */
- /* NEED TO IMPLEMENT THIS!!! */
- return -1;
- } else {
- dbg_ep0 (1, "request %s bad wValue: %04x",
- USBD_DEVICE_REQUESTS
- (request->bRequest),
- le16_to_cpu (request->wValue));
- return -1;
- }
- }
-
- case USB_REQ_SET_ADDRESS:
- /* check if this is a re-address, reset first if it is (this shouldn't be possible) */
- if (device->device_state != STATE_DEFAULT) {
- dbg_ep0 (1, "set_address: %02x state: %s",
- le16_to_cpu (request->wValue),
- usbd_device_states[device->device_state]);
- return -1;
- }
- address = le16_to_cpu (request->wValue);
- if ((address & 0x7f) != address) {
- dbg_ep0 (1, "invalid address %04x %04x",
- address, address & 0x7f);
- return -1;
- }
- device->address = address;
-
- /*dbg_ep0(2, "address: %d %d %d", */
- /* request->wValue, le16_to_cpu(request->wValue), device->address); */
-
- return 0;
-
- case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */
- dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
- return -1;
-
- case USB_REQ_SET_CONFIGURATION:
- /* c.f. 9.4.7 - the top half of wValue is reserved */
- device->configuration = le16_to_cpu(request->wValue) & 0xff;
-
- /* reset interface and alternate settings */
- device->interface = device->alternate = 0;
-
- /*dbg_ep0(2, "set configuration: %d", device->configuration); */
- /*dbg_ep0(2, "DEVICE_CONFIGURED.. event?\n"); */
- return 0;
-
- case USB_REQ_SET_INTERFACE:
- device->interface = le16_to_cpu (request->wIndex);
- device->alternate = le16_to_cpu (request->wValue);
- /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
- dbg_ep0(2, "DEVICE_SET_INTERFACE.. event?\n");
- return 0;
-
- case USB_REQ_GET_STATUS:
- case USB_REQ_GET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
- return -1;
- }
- }
- return -1;
-}
diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index c52afd41a75..ad9072a5327 100644
--- a/drivers/usb/musb-new/Kconfig
+++ b/drivers/usb/musb-new/Kconfig
@@ -22,6 +22,13 @@ config USB_MUSB_GADGET
Enables the MUSB USB dual-role controller in gadget mode.
if USB_MUSB_HOST || USB_MUSB_GADGET
+config USB_MUSB_SC5XX
+ bool "Analog Devices MUSB support"
+ depends on (SC57X || SC58X)
+ help
+ Say y here to enable support for the USB controller on
+ ADI SC57X/SC58X processors.
+
config USB_MUSB_DA8XX
bool "Enable DA8xx MUSB Controller"
depends on ARCH_DAVINCI
diff --git a/drivers/usb/musb-new/Makefile b/drivers/usb/musb-new/Makefile
index 396ff02654b..6638772daca 100644
--- a/drivers/usb/musb-new/Makefile
+++ b/drivers/usb/musb-new/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
+obj-$(CONFIG_USB_MUSB_SC5XX) += sc5xx.o
ccflags-y := $(call cc-option,-Wno-unused-variable) \
$(call cc-option,-Wno-unused-but-set-variable) \
diff --git a/drivers/usb/musb-new/sc5xx.c b/drivers/usb/musb-new/sc5xx.c
new file mode 100644
index 00000000000..16201480b43
--- /dev/null
+++ b/drivers/usb/musb-new/sc5xx.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * ADI SC5XX MUSB "glue layer"
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Loosely ported from Linux driver:
+ * Author: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ *
+ */
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/usb/musb.h>
+#include "linux-compat.h"
+#include "musb_core.h"
+#include "musb_uboot.h"
+
+#define MUSB_SOFTRST 0x7f
+#define MUSB_SOFTRST_NRST BIT(0)
+#define MUSB_SOFTRST_NRSTX BIT(1)
+
+#define REG_USB_VBUS_CTL 0x380
+#define REG_USB_ID_CTL 0x382
+#define REG_USB_PHY_CTL 0x394
+#define REG_USB_PLL_OSC 0x398
+#define REG_USB_UTMI_CTL 0x39c
+
+/* controller data */
+struct sc5xx_musb_data {
+ struct musb_host_data mdata;
+ struct device dev;
+};
+
+#define to_sc5xx_musb_data(d) \
+ container_of(d, struct sc5xx_musb_data, dev)
+
+static void sc5xx_musb_disable(struct musb *musb)
+{
+ /* no way to shut the controller */
+}
+
+static int sc5xx_musb_enable(struct musb *musb)
+{
+ /* soft reset by NRSTx */
+ musb_writeb(musb->mregs, MUSB_SOFTRST, MUSB_SOFTRST_NRSTX);
+ /* set mode */
+ musb_platform_set_mode(musb, musb->board_mode);
+
+ return 0;
+}
+
+static irqreturn_t sc5xx_interrupt(int irq, void *hci)
+{
+ struct musb *musb = hci;
+ irqreturn_t ret = IRQ_NONE;
+ u8 devctl;
+
+ musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+ musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+ musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+
+ if (musb->int_usb & MUSB_INTR_VBUSERROR) {
+ musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+ devctl = musb_readw(musb->mregs, MUSB_DEVCTL);
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+ }
+ if (musb->int_usb || musb->int_tx || musb->int_rx) {
+ musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+ musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+ musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+ ret = musb_interrupt(musb);
+ }
+
+ if (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))
+ musb_writeb(musb->mregs, REG_USB_VBUS_CTL, 0x0);
+
+ return ret;
+}
+
+static int sc5xx_musb_set_mode(struct musb *musb, u8 mode)
+{
+ struct device *dev = musb->controller;
+ struct sc5xx_musb_data *pdata = to_sc5xx_musb_data(dev);
+
+ switch (mode) {
+ case MUSB_HOST:
+ musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x1);
+ break;
+ case MUSB_PERIPHERAL:
+ musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x3);
+ break;
+ case MUSB_OTG:
+ musb_writeb(musb->mregs, REG_USB_ID_CTL, 0x0);
+ break;
+ default:
+ dev_err(dev, "unsupported mode %d\n", mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sc5xx_musb_init(struct musb *musb)
+{
+ struct sc5xx_musb_data *pdata = to_sc5xx_musb_data(musb->controller);
+
+ musb->isr = sc5xx_interrupt;
+
+ musb_writel(musb->mregs, REG_USB_PLL_OSC, 20 << 1);
+ musb_writeb(musb->mregs, REG_USB_VBUS_CTL, 0x0);
+ musb_writeb(musb->mregs, REG_USB_PHY_CTL, 0x80);
+ musb_writel(musb->mregs, REG_USB_UTMI_CTL,
+ 0x40 | musb_readl(musb->mregs, REG_USB_UTMI_CTL));
+
+ return 0;
+}
+
+const struct musb_platform_ops sc5xx_musb_ops = {
+ .init = sc5xx_musb_init,
+ .set_mode = sc5xx_musb_set_mode,
+ .disable = sc5xx_musb_disable,
+ .enable = sc5xx_musb_enable,
+};
+
+static struct musb_hdrc_config sc5xx_musb_config = {
+ .multipoint = 1,
+ .dyn_fifo = 1,
+ .num_eps = 16,
+ .ram_bits = 12,
+};
+
+/* has one MUSB controller which can be host or gadget */
+static struct musb_hdrc_platform_data sc5xx_musb_plat = {
+ .mode = MUSB_HOST,
+ .config = &sc5xx_musb_config,
+ .power = 100,
+ .platform_ops = &sc5xx_musb_ops,
+};
+
+static int musb_usb_probe(struct udevice *dev)
+{
+ struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+ struct sc5xx_musb_data *pdata = dev_get_priv(dev);
+ struct musb_host_data *mdata = &pdata->mdata;
+ void __iomem *mregs;
+ int ret;
+
+ priv->desc_before_addr = true;
+
+ mregs = dev_remap_addr(dev);
+ if (!mregs)
+ return -EINVAL;
+
+ /* init controller */
+ if (IS_ENABLED(CONFIG_USB_MUSB_HOST)) {
+ mdata->host = musb_init_controller(&sc5xx_musb_plat,
+ &pdata->dev, mregs);
+ if (!mdata->host)
+ return -EIO;
+
+ ret = musb_lowlevel_init(mdata);
+ } else {
+ sc5xx_musb_plat.mode = MUSB_PERIPHERAL;
+ mdata->host = musb_register(&sc5xx_musb_plat, &pdata->dev, mregs);
+ if (!mdata->host)
+ return -EIO;
+ }
+ return ret;
+}
+
+static int musb_usb_remove(struct udevice *dev)
+{
+ struct sc5xx_musb_data *pdata = dev_get_priv(dev);
+
+ musb_stop(pdata->mdata.host);
+
+ return 0;
+}
+
+static const struct udevice_id sc5xx_musb_ids[] = {
+ { .compatible = "adi,sc5xx-musb" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_musb) = {
+ .name = "sc5xx-musb",
+ .id = UCLASS_USB,
+ .of_match = sc5xx_musb_ids,
+ .probe = musb_usb_probe,
+ .remove = musb_usb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+ .ops = &musb_usb_ops,
+#endif
+ .plat_auto = sizeof(struct usb_plat),
+ .priv_auto = sizeof(struct sc5xx_musb_data),
+};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3c3cebaacd0..df607303616 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -293,27 +293,6 @@ config PANEL_HX8238D
source "drivers/video/fonts/Kconfig"
-config VIDCONSOLE_AS_LCD
- bool "Use 'vidconsole' when CONFIG_VIDCONSOLE_AS_NAME string is seen in stdout"
- help
- This is a work-around for boards which have 'lcd' or 'vga' in their
- stdout environment variable, but have moved to use driver model for
- video. In this case the console will no-longer work. While it is
- possible to update the environment, the breakage may be confusing for
- users. This option will be removed around the end of 2020.
-
-config VIDCONSOLE_AS_NAME
- string "Use 'vidconsole' when string defined here is seen in stdout"
- depends on VIDCONSOLE_AS_LCD
- default "lcd" if LCD || TEGRA_COMMON
- default "vga" if !LCD
- help
- This is a work-around for boards which have 'lcd' or 'vga' in their
- stdout environment variable, but have moved to use driver model for
- video. In this case the console will no-longer work. While it is
- possible to update the environment, the breakage may be confusing for
- users. This option will be removed around the end of 2020.
-
config VIDEO_BOCHS
bool "Enable Bochs video emulation for QEMU"
help
@@ -599,6 +578,15 @@ config VIDEO_LCD_SAMSUNG_LTL106HL02
LCD module found in Microsoft Surface 2. The panel has a FullHD
resolution (1920x1080).
+config VIDEO_LCD_SHARP_LQ079L1SX01
+ tristate "Sharp LQ079L1SX01 1536x2048 DSI video mode panel"
+ depends on PANEL && BACKLIGHT
+ select VIDEO_MIPI_DSI
+ help
+ Say Y here if you want to enable support for Sharp LQ079L1SX01
+ LCD module found in Xiaomi Mi Pad tablet. The panel has a QXGA
+ resolution (1536x2048).
+
config VIDEO_LCD_SHARP_LQ101R1SX01
tristate "Sharp LQ101R1SX01 2560x1600 DSI video mode panel"
depends on PANEL && BACKLIGHT
@@ -712,6 +700,12 @@ config I2C_EDID
help
This enables library for accessing EDID data from an LCD panel.
+config I2C_EDID_STANDARD
+ bool "Enable standard timings EDID library expansion"
+ depends on I2C_EDID
+ help
+ This enables standard timings expansion for EDID data from an LCD panel.
+
config DISPLAY
bool "Enable Display support"
depends on DM
@@ -743,6 +737,16 @@ config BACKLIGHT_LM3533
LM3533 Lighting Power chip. Only Bank A is supported as for now.
Supported backlight level range is from 2 to 255 with step of 1.
+config BACKLIGHT_LP855x
+ bool "Backlight Driver for LP855x"
+ depends on BACKLIGHT
+ select DM_I2C
+ help
+ Say Y to enable the backlight driver for National Semiconductor / TI
+ LP8550/1/2/3/5/6/7 LED Backlight Driver. Only register driven mode is
+ supported for now, PWM mode can be added if there will be any need in
+ it. Supported backlight level range is from 0 to 255 with step of 1.
+
source "drivers/video/ti/Kconfig"
source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 5a00438ce06..6073bc5234a 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_$(PHASE_)BMP) += bmp.o
endif
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_backlight.o
+obj-$(CONFIG_BACKLIGHT_LP855x) += lp855x_backlight.o
obj-${CONFIG_EXYNOS_FB} += exynos/
obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
obj-${CONFIG_VIDEO_STM32} += stm32/
@@ -64,6 +65,7 @@ obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
obj-$(CONFIG_VIDEO_LCD_RENESAS_R61307) += renesas-r61307.o
obj-$(CONFIG_VIDEO_LCD_RENESAS_R69328) += renesas-r69328.o
obj-$(CONFIG_VIDEO_LCD_SAMSUNG_LTL106HL02) += samsung-ltl106hl02.o
+obj-$(CONFIG_VIDEO_LCD_SHARP_LQ079L1SX01) += sharp-lq079l1sx01.o
obj-$(CONFIG_VIDEO_LCD_SHARP_LQ101R1SX01) += sharp-lq101r1sx01.o
obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
diff --git a/drivers/video/bridge/Kconfig b/drivers/video/bridge/Kconfig
index ab917273720..be53034bd3d 100644
--- a/drivers/video/bridge/Kconfig
+++ b/drivers/video/bridge/Kconfig
@@ -9,7 +9,7 @@ config VIDEO_BRIDGE
config VIDEO_BRIDGE_PARADE_DP501
bool "Support Parade DP501 DP & DVI/HDMI dual mode transmitter"
- depends on PANEL && DM_GPIO
+ depends on VIDEO_BRIDGE && PANEL && DM_GPIO
select DM_I2C
help
The Parade DP501 is a DP & DVI/HDMI dual-mode transmitter. It
@@ -46,16 +46,23 @@ config VIDEO_BRIDGE_ANALOGIX_ANX6345
config VIDEO_BRIDGE_SOLOMON_SSD2825
bool "Solomon SSD2825 bridge driver"
- depends on PANEL && DM_GPIO
+ depends on VIDEO_BRIDGE && PANEL && DM_GPIO
select VIDEO_MIPI_DSI
help
- Solomon SSD2824 SPI RGB-DSI bridge driver wrapped into panel uClass.
+ Solomon SSD2824 SPI RGB-DSI bridge driver.
config VIDEO_BRIDGE_TOSHIBA_TC358768
bool "Support Toshiba TC358768 MIPI DSI bridge"
- depends on PANEL && DM_GPIO
+ depends on VIDEO_BRIDGE && PANEL && DM_GPIO
select VIDEO_MIPI_DSI
select DM_I2C
help
Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver.
Found in Asus Transformer Infinity TF700T.
+
+config VIDEO_BRIDGE_LVDS_CODEC
+ bool "Transparent LVDS encoders and decoders support"
+ depends on VIDEO_BRIDGE && PANEL && DM_GPIO
+ help
+ Support for transparent LVDS encoders and decoders that don't
+ require any configuration.
diff --git a/drivers/video/bridge/Makefile b/drivers/video/bridge/Makefile
index 58697e3cbe9..63dc6e62c49 100644
--- a/drivers/video/bridge/Makefile
+++ b/drivers/video/bridge/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o
obj-$(CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345) += anx6345.o
obj-$(CONFIG_VIDEO_BRIDGE_SOLOMON_SSD2825) += ssd2825.o
obj-$(CONFIG_VIDEO_BRIDGE_TOSHIBA_TC358768) += tc358768.o
+obj-$(CONFIG_VIDEO_BRIDGE_LVDS_CODEC) += lvds-codec.o
diff --git a/drivers/video/bridge/dp501.c b/drivers/video/bridge/dp501.c
index 095e3e71fed..9937cfe095b 100644
--- a/drivers/video/bridge/dp501.c
+++ b/drivers/video/bridge/dp501.c
@@ -9,6 +9,7 @@
#include <log.h>
#include <backlight.h>
#include <panel.h>
+#include <video_bridge.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <power/regulator.h>
@@ -206,7 +207,6 @@ struct dp501_priv {
struct udevice *chip2;
struct udevice *vdd;
- struct gpio_desc reset_gpio;
struct gpio_desc enable_gpio;
};
@@ -484,16 +484,19 @@ static int dp501_panel_timings(struct udevice *dev,
return 0;
}
-static void dp501_hw_init(struct dp501_priv *priv)
+static void dp501_hw_init(struct udevice *dev)
{
- dm_gpio_set_value(&priv->reset_gpio, 1);
+ struct dp501_priv *priv = dev_get_priv(dev);
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ dm_gpio_set_value(&uc_priv->reset, 1);
regulator_set_enable_if_allowed(priv->vdd, 1);
dm_gpio_set_value(&priv->enable_gpio, 1);
udelay(100);
- dm_gpio_set_value(&priv->reset_gpio, 0);
+ dm_gpio_set_value(&uc_priv->reset, 0);
mdelay(80);
}
@@ -521,14 +524,6 @@ static int dp501_setup(struct udevice *dev)
}
/* get gpios */
- ret = gpio_request_by_name(dev, "reset-gpios", 0,
- &priv->reset_gpio, GPIOD_IS_OUT);
- if (ret) {
- log_debug("%s: Could not decode reset-gpios (%d)\n",
- __func__, ret);
- return ret;
- }
-
ret = gpio_request_by_name(dev, "enable-gpios", 0,
&priv->enable_gpio, GPIOD_IS_OUT);
if (ret) {
@@ -544,7 +539,7 @@ static int dp501_setup(struct udevice *dev)
return ret;
}
- dp501_hw_init(priv);
+ dp501_hw_init(dev);
/* get EDID */
return panel_get_display_timing(priv->panel, &priv->timing);
@@ -558,8 +553,8 @@ static int dp501_probe(struct udevice *dev)
return dp501_setup(dev);
}
-struct panel_ops dp501_ops = {
- .enable_backlight = dp501_attach,
+static const struct video_bridge_ops dp501_ops = {
+ .attach = dp501_attach,
.set_backlight = dp501_set_backlight,
.get_display_timing = dp501_panel_timings,
};
@@ -571,7 +566,7 @@ static const struct udevice_id dp501_ids[] = {
U_BOOT_DRIVER(dp501) = {
.name = "dp501",
- .id = UCLASS_PANEL,
+ .id = UCLASS_VIDEO_BRIDGE,
.of_match = dp501_ids,
.ops = &dp501_ops,
.probe = dp501_probe,
diff --git a/drivers/video/bridge/lvds-codec.c b/drivers/video/bridge/lvds-codec.c
new file mode 100644
index 00000000000..6cd8368a39e
--- /dev/null
+++ b/drivers/video/bridge/lvds-codec.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ * Loosely based on Linux lvds-codec.c driver
+ */
+
+#include <dm.h>
+#include <dm/ofnode_graph.h>
+#include <log.h>
+#include <panel.h>
+#include <video_bridge.h>
+#include <asm/gpio.h>
+#include <power/regulator.h>
+
+struct lvds_codec_priv {
+ struct udevice *panel;
+ struct display_timing timing;
+
+ struct gpio_desc powerdown_gpio;
+ struct udevice *power;
+};
+
+static int lvds_codec_attach(struct udevice *dev)
+{
+ struct lvds_codec_priv *priv = dev_get_priv(dev);
+
+ regulator_set_enable_if_allowed(priv->power, 1);
+ dm_gpio_set_value(&priv->powerdown_gpio, 0);
+
+ return panel_enable_backlight(priv->panel);
+}
+
+static int lvds_codec_set_panel(struct udevice *dev, int percent)
+{
+ struct lvds_codec_priv *priv = dev_get_priv(dev);
+
+ return panel_set_backlight(priv->panel, percent);
+}
+
+static int lvds_codec_panel_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ struct lvds_codec_priv *priv = dev_get_priv(dev);
+
+ memcpy(timing, &priv->timing, sizeof(*timing));
+
+ return 0;
+}
+
+/* Function is purely for sandbox testing */
+static int lvds_codec_read_edid(struct udevice *dev, u8 *buf, int buf_size)
+{
+ return 0;
+}
+
+static int lvds_codec_get_panel(struct udevice *dev)
+{
+ struct lvds_codec_priv *priv = dev_get_priv(dev);
+ int i, ret;
+
+ u32 num = ofnode_graph_get_port_count(dev_ofnode(dev));
+
+ for (i = 0; i < num; i++) {
+ ofnode remote = ofnode_graph_get_remote_node(dev_ofnode(dev), i, -1);
+
+ ret = uclass_get_device_by_of_offset(UCLASS_PANEL,
+ ofnode_to_offset(remote),
+ &priv->panel);
+ if (!ret)
+ return 0;
+ }
+
+ /* If this point is reached, no panels were found */
+ return -ENODEV;
+}
+
+static int lvds_codec_probe(struct udevice *dev)
+{
+ struct lvds_codec_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = lvds_codec_get_panel(dev);
+ if (ret) {
+ log_debug("%s: cannot get panel: ret=%d\n", __func__, ret);
+ return log_ret(ret);
+ }
+
+ panel_get_display_timing(priv->panel, &priv->timing);
+
+ ret = gpio_request_by_name(dev, "powerdown-gpios", 0,
+ &priv->powerdown_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_debug("%s: could not get powerdown-gpios (%d)\n", __func__, ret);
+ if (ret != -ENOENT)
+ return log_ret(ret);
+ }
+
+ ret = device_get_supply_regulator(dev, "power-supply", &priv->power);
+ if (ret) {
+ log_debug("%s: power regulator error: %d\n", __func__, ret);
+ if (ret != -ENOENT)
+ return log_ret(ret);
+ }
+
+ return 0;
+}
+
+static const struct video_bridge_ops lvds_codec_ops = {
+ .attach = lvds_codec_attach,
+ .set_backlight = lvds_codec_set_panel,
+ .get_display_timing = lvds_codec_panel_timings,
+ .read_edid = lvds_codec_read_edid,
+};
+
+static const struct udevice_id lvds_codec_ids[] = {
+ { .compatible = "lvds-decoder" },
+ { .compatible = "lvds-encoder" },
+ { }
+};
+
+U_BOOT_DRIVER(lvds_codec) = {
+ .name = "lvds_codec",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = lvds_codec_ids,
+ .ops = &lvds_codec_ops,
+ .probe = lvds_codec_probe,
+ .priv_auto = sizeof(struct lvds_codec_priv),
+};
diff --git a/drivers/video/bridge/ssd2825.c b/drivers/video/bridge/ssd2825.c
index f978021c860..a307993377c 100644
--- a/drivers/video/bridge/ssd2825.c
+++ b/drivers/video/bridge/ssd2825.c
@@ -5,12 +5,15 @@
#include <clk.h>
#include <dm.h>
+#include <dm/ofnode_graph.h>
#include <log.h>
#include <misc.h>
#include <mipi_display.h>
#include <mipi_dsi.h>
#include <backlight.h>
+#include <video_bridge.h>
#include <panel.h>
+#include <power/regulator.h>
#include <spi.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -106,6 +109,10 @@
#define SSD2825_LP_MIN_CLK 5000 /* KHz */
#define SSD2825_REF_MIN_CLK 2000 /* KHz */
+static const char * const ssd2825_supplies[] = {
+ "dvdd-supply", "avdd-supply", "vddio-supply"
+};
+
struct ssd2825_bridge_priv {
struct mipi_dsi_host host;
struct mipi_dsi_device device;
@@ -113,12 +120,16 @@ struct ssd2825_bridge_priv {
struct udevice *panel;
struct display_timing timing;
+ struct udevice *supplies[ARRAY_SIZE(ssd2825_supplies)];
+
struct gpio_desc power_gpio;
- struct gpio_desc reset_gpio;
struct clk *tx_clk;
u32 pll_freq_kbps; /* PLL in kbps */
+
+ u32 hzd; /* HS Zero Delay in ns */
+ u32 hpd; /* HS Prepare Delay is ns */
};
static int ssd2825_spi_write(struct udevice *dev, int reg,
@@ -231,7 +242,6 @@ static ssize_t ssd2825_bridge_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct udevice *dev = (struct udevice *)host->dev;
- u8 buf = *(u8 *)msg->tx_buf;
u16 config;
int ret;
@@ -260,15 +270,6 @@ static ssize_t ssd2825_bridge_transfer(struct mipi_dsi_host *host,
ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
ssd2825_write_dsi(dev, msg->tx_buf, msg->tx_len);
- if (buf == MIPI_DCS_SET_DISPLAY_ON) {
- ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG,
- SSD2825_CONF_REG_HS | SSD2825_CONF_REG_VEN |
- SSD2825_CONF_REG_DCS | SSD2825_CONF_REG_ECD |
- SSD2825_CONF_REG_EOT);
- ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0001);
- ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
- }
-
return 0;
}
@@ -312,9 +313,14 @@ static void ssd2825_setup_pll(struct udevice *dev)
struct mipi_dsi_device *device = &priv->device;
struct display_timing *dt = &priv->timing;
u16 pll_config, lp_div;
+ u32 nibble_delay, nibble_freq_khz;
u32 pclk_mult, tx_freq_khz, pd_lines;
+ u8 hzd, hpd;
tx_freq_khz = clk_get_rate(priv->tx_clk) / 1000;
+ if (!tx_freq_khz || tx_freq_khz < 0)
+ tx_freq_khz = SSD2825_REF_MIN_CLK;
+
pd_lines = mipi_dsi_pixel_format_to_bpp(device->format);
pclk_mult = pd_lines / device->lanes + 1;
@@ -324,12 +330,19 @@ static void ssd2825_setup_pll(struct udevice *dev)
lp_div = priv->pll_freq_kbps / (SSD2825_LP_MIN_CLK * 8);
+ /* nibble_delay in nanoseconds */
+ nibble_freq_khz = priv->pll_freq_kbps / 4;
+ nibble_delay = 1000 * 1000 / nibble_freq_khz;
+
+ hzd = priv->hzd / nibble_delay;
+ hpd = (priv->hpd - 4 * nibble_delay) / nibble_delay;
+
/* Disable PLL */
ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0000);
ssd2825_write_register(dev, SSD2825_LINE_CTRL_REG, 0x0001);
/* Set delays */
- ssd2825_write_register(dev, SSD2825_DELAY_ADJ_REG_1, 0x2103);
+ ssd2825_write_register(dev, SSD2825_DELAY_ADJ_REG_1, (hzd << 8) | hpd);
/* Set PLL coeficients */
ssd2825_write_register(dev, SSD2825_PLL_CONFIGURATION_REG, pll_config);
@@ -343,11 +356,30 @@ static void ssd2825_setup_pll(struct udevice *dev)
ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
}
-static int ssd2825_bridge_enable_panel(struct udevice *dev)
+static int ssd2825_bridge_attach(struct udevice *dev)
{
struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
struct mipi_dsi_device *device = &priv->device;
struct display_timing *dt = &priv->timing;
+ u8 pixel_format;
+ int ret;
+
+ /* Set pixel format */
+ switch (device->format) {
+ case MIPI_DSI_FMT_RGB565:
+ pixel_format = 0x00;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ pixel_format = 0x01;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ pixel_format = 0x02;
+ break;
+ case MIPI_DSI_FMT_RGB888:
+ default:
+ pixel_format = 0x03;
+ break;
+ }
/* Perform SW reset */
ssd2825_write_register(dev, SSD2825_OPERATION_CTRL_REG, 0x0100);
@@ -367,7 +399,7 @@ static int ssd2825_bridge_enable_panel(struct udevice *dev)
ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_6,
SSD2825_HSYNC_HIGH | SSD2825_VSYNC_HIGH |
SSD2825_PCKL_HIGH | SSD2825_NON_BURST |
- (3 - device->format));
+ pixel_format);
ssd2825_write_register(dev, SSD2825_LANE_CONFIGURATION_REG,
device->lanes - 1);
ssd2825_write_register(dev, SSD2825_TEST_REG, 0x0004);
@@ -384,7 +416,18 @@ static int ssd2825_bridge_enable_panel(struct udevice *dev)
ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
/* Perform panel setup */
- return panel_enable_backlight(priv->panel);
+ ret = panel_enable_backlight(priv->panel);
+ if (ret)
+ return ret;
+
+ ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG,
+ SSD2825_CONF_REG_HS | SSD2825_CONF_REG_VEN |
+ SSD2825_CONF_REG_DCS | SSD2825_CONF_REG_ECD |
+ SSD2825_CONF_REG_EOT);
+ ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0001);
+ ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+
+ return 0;
}
static int ssd2825_bridge_set_panel(struct udevice *dev, int percent)
@@ -407,7 +450,8 @@ static int ssd2825_bridge_panel_timings(struct udevice *dev,
static int ssd2825_bridge_hw_init(struct udevice *dev)
{
struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
- int ret;
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
+ int i, ret;
ret = clk_prepare_enable(priv->tx_clk);
if (ret) {
@@ -416,25 +460,28 @@ static int ssd2825_bridge_hw_init(struct udevice *dev)
return ret;
}
- ret = dm_gpio_set_value(&priv->power_gpio, 1);
- if (ret) {
- log_debug("%s: error changing power-gpios (%d)\n",
- __func__, ret);
- return ret;
+ /* enable supplies */
+ for (i = 0; i < ARRAY_SIZE(ssd2825_supplies); i++) {
+ ret = regulator_set_enable_if_allowed(priv->supplies[i], 1);
+ if (ret) {
+ log_debug("%s: cannot enable %s %d\n", __func__,
+ ssd2825_supplies[i], ret);
+ return ret;
+ }
}
mdelay(10);
- ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ ret = dm_gpio_set_value(&uc_priv->reset, 1);
if (ret) {
- log_debug("%s: error changing reset-gpios (%d)\n",
+ log_debug("%s: error entering reset (%d)\n",
__func__, ret);
return ret;
}
mdelay(10);
- ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ ret = dm_gpio_set_value(&uc_priv->reset, 0);
if (ret) {
- log_debug("%s: error changing reset-gpios (%d)\n",
+ log_debug("%s: error exiting reset (%d)\n",
__func__, ret);
return ret;
}
@@ -443,13 +490,33 @@ static int ssd2825_bridge_hw_init(struct udevice *dev)
return 0;
}
+static int ssd2825_bridge_get_panel(struct udevice *dev)
+{
+ struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+ int i, ret;
+
+ u32 num = ofnode_graph_get_port_count(dev_ofnode(dev));
+
+ for (i = 0; i < num; i++) {
+ ofnode remote = ofnode_graph_get_remote_node(dev_ofnode(dev), i, -1);
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PANEL, remote,
+ &priv->panel);
+ if (!ret)
+ return 0;
+ }
+
+ /* If this point is reached, no panels were found */
+ return -ENODEV;
+}
+
static int ssd2825_bridge_probe(struct udevice *dev)
{
struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
struct spi_slave *slave = dev_get_parent_priv(dev);
struct mipi_dsi_device *device = &priv->device;
struct mipi_dsi_panel_plat *mipi_plat;
- int ret;
+ int i, ret;
ret = spi_claim_bus(slave);
if (ret) {
@@ -457,10 +524,9 @@ static int ssd2825_bridge_probe(struct udevice *dev)
return ret;
}
- ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
- "panel", &priv->panel);
+ ret = ssd2825_bridge_get_panel(dev);
if (ret) {
- log_err("cannot get panel: ret=%d\n", ret);
+ log_debug("%s: panel not found, ret %d\n", __func__, ret);
return ret;
}
@@ -477,33 +543,33 @@ static int ssd2825_bridge_probe(struct udevice *dev)
device->format = mipi_plat->format;
device->mode_flags = mipi_plat->mode_flags;
- /* get panel gpios */
- ret = gpio_request_by_name(dev, "power-gpios", 0,
- &priv->power_gpio, GPIOD_IS_OUT);
- if (ret) {
- log_err("could not decode power-gpios (%d)\n", ret);
- return ret;
- }
-
- ret = gpio_request_by_name(dev, "reset-gpios", 0,
- &priv->reset_gpio, GPIOD_IS_OUT);
- if (ret) {
- log_err("could not decode reset-gpios (%d)\n", ret);
- return ret;
+ /* get supplies */
+ for (i = 0; i < ARRAY_SIZE(ssd2825_supplies); i++) {
+ ret = device_get_supply_regulator(dev, ssd2825_supplies[i],
+ &priv->supplies[i]);
+ if (ret) {
+ log_debug("%s: cannot get %s %d\n", __func__,
+ ssd2825_supplies[i], ret);
+ if (ret != -ENOENT)
+ return log_ret(ret);
+ }
}
/* get clk */
- priv->tx_clk = devm_clk_get(dev, "tx_clk");
+ priv->tx_clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(priv->tx_clk)) {
log_err("cannot get tx_clk: %ld\n", PTR_ERR(priv->tx_clk));
return PTR_ERR(priv->tx_clk);
}
+ priv->hzd = dev_read_u32_default(dev, "solomon,hs-zero-delay-ns", 133);
+ priv->hpd = dev_read_u32_default(dev, "solomon,hs-prep-delay-ns", 40);
+
return ssd2825_bridge_hw_init(dev);
}
-static const struct panel_ops ssd2825_bridge_ops = {
- .enable_backlight = ssd2825_bridge_enable_panel,
+static const struct video_bridge_ops ssd2825_bridge_ops = {
+ .attach = ssd2825_bridge_attach,
.set_backlight = ssd2825_bridge_set_panel,
.get_display_timing = ssd2825_bridge_panel_timings,
};
@@ -515,9 +581,10 @@ static const struct udevice_id ssd2825_bridge_ids[] = {
U_BOOT_DRIVER(ssd2825) = {
.name = "ssd2825",
- .id = UCLASS_PANEL,
+ .id = UCLASS_VIDEO_BRIDGE,
.of_match = ssd2825_bridge_ids,
.ops = &ssd2825_bridge_ops,
+ .bind = dm_scan_fdt_dev,
.probe = ssd2825_bridge_probe,
.priv_auto = sizeof(struct ssd2825_bridge_priv),
};
diff --git a/drivers/video/bridge/tc358768.c b/drivers/video/bridge/tc358768.c
index 19b6ca29d3e..358004f30f2 100644
--- a/drivers/video/bridge/tc358768.c
+++ b/drivers/video/bridge/tc358768.c
@@ -6,12 +6,14 @@
#include <clk.h>
#include <dm.h>
+#include <dm/ofnode_graph.h>
#include <i2c.h>
#include <log.h>
#include <mipi_display.h>
#include <mipi_dsi.h>
#include <backlight.h>
#include <panel.h>
+#include <video_bridge.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
@@ -122,6 +124,10 @@
#define NANO 1000000000UL
#define PICO 1000000000000ULL
+static const char * const tc358768_supplies[] = {
+ "vddc-supply", "vddmipi-supply", "vddio-supply"
+};
+
struct tc358768_priv {
struct mipi_dsi_host host;
struct mipi_dsi_device device;
@@ -129,9 +135,7 @@ struct tc358768_priv {
struct udevice *panel;
struct display_timing timing;
- struct udevice *vddc;
- struct udevice *vddmipi;
- struct udevice *vddio;
+ struct udevice *supplies[ARRAY_SIZE(tc358768_supplies)];
struct clk *refclk;
@@ -265,25 +269,27 @@ static void tc358768_sw_reset(struct udevice *dev)
tc358768_write(dev, TC358768_SYSCTL, 0);
}
-static void tc358768_hw_enable(struct tc358768_priv *priv)
+static void tc358768_hw_enable(struct udevice *dev)
{
+ struct tc358768_priv *priv = dev_get_priv(dev);
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
int ret;
ret = clk_prepare_enable(priv->refclk);
if (ret)
log_debug("%s: error enabling refclk (%d)\n", __func__, ret);
- ret = regulator_set_enable_if_allowed(priv->vddc, true);
+ ret = regulator_set_enable_if_allowed(priv->supplies[0], true);
if (ret)
log_debug("%s: error enabling vddc (%d)\n", __func__, ret);
- ret = regulator_set_enable_if_allowed(priv->vddmipi, true);
+ ret = regulator_set_enable_if_allowed(priv->supplies[1], true);
if (ret)
log_debug("%s: error enabling vddmipi (%d)\n", __func__, ret);
mdelay(10);
- ret = regulator_set_enable_if_allowed(priv->vddio, true);
+ ret = regulator_set_enable_if_allowed(priv->supplies[2], true);
if (ret)
log_debug("%s: error enabling vddio (%d)\n", __func__, ret);
@@ -293,7 +299,7 @@ static void tc358768_hw_enable(struct tc358768_priv *priv)
* The RESX is active low (GPIO_ACTIVE_LOW).
* DEASSERT (value = 0) the reset_gpio to enable the chip
*/
- ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ ret = dm_gpio_set_value(&uc_priv->reset, 0);
if (ret)
log_debug("%s: error changing reset-gpio (%d)\n", __func__, ret);
@@ -477,7 +483,7 @@ static int tc358768_attach(struct udevice *dev)
device->mode_flags &= ~MIPI_DSI_CLOCK_NON_CONTINUOUS;
}
- tc358768_hw_enable(priv);
+ tc358768_hw_enable(dev);
tc358768_sw_reset(dev);
tc358768_setup_pll(dev);
@@ -874,12 +880,33 @@ static int tc358768_panel_timings(struct udevice *dev,
return 0;
}
+static int tc358768_get_panel(struct udevice *dev)
+{
+ struct tc358768_priv *priv = dev_get_priv(dev);
+ int i, ret;
+
+ u32 num = ofnode_graph_get_port_count(dev_ofnode(dev));
+
+ for (i = 0; i < num; i++) {
+ ofnode remote = ofnode_graph_get_remote_node(dev_ofnode(dev), i, -1);
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PANEL, remote,
+ &priv->panel);
+ if (!ret)
+ return 0;
+ }
+
+ /* If this point is reached, no panels were found */
+ return -ENODEV;
+}
+
static int tc358768_setup(struct udevice *dev)
{
struct tc358768_priv *priv = dev_get_priv(dev);
+ struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
struct mipi_dsi_device *device = &priv->device;
struct mipi_dsi_panel_plat *mipi_plat;
- int ret;
+ int i, ret;
/* The bridge uses 16 bit registers */
ret = i2c_set_chip_offset_len(dev, 2);
@@ -889,11 +916,10 @@ static int tc358768_setup(struct udevice *dev)
return ret;
}
- ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
- "panel", &priv->panel);
+ ret = tc358768_get_panel(dev);
if (ret) {
- log_debug("%s: Cannot get panel: ret=%d\n", __func__, ret);
- return log_ret(ret);
+ log_debug("%s: panel not found, ret %d\n", __func__, ret);
+ return ret;
}
panel_get_display_timing(priv->panel, &priv->timing);
@@ -913,44 +939,26 @@ static int tc358768_setup(struct udevice *dev)
priv->dsi_lanes = device->lanes;
/* get regulators */
- ret = device_get_supply_regulator(dev, "vddc-supply", &priv->vddc);
- if (ret) {
- log_debug("%s: vddc regulator error: %d\n", __func__, ret);
- if (ret != -ENOENT)
- return log_ret(ret);
- }
-
- ret = device_get_supply_regulator(dev, "vddmipi-supply", &priv->vddmipi);
- if (ret) {
- log_debug("%s: vddmipi regulator error: %d\n", __func__, ret);
- if (ret != -ENOENT)
- return log_ret(ret);
- }
-
- ret = device_get_supply_regulator(dev, "vddio-supply", &priv->vddio);
- if (ret) {
- log_debug("%s: vddio regulator error: %d\n", __func__, ret);
- if (ret != -ENOENT)
- return log_ret(ret);
+ for (i = 0; i < ARRAY_SIZE(tc358768_supplies); i++) {
+ ret = device_get_supply_regulator(dev, tc358768_supplies[i],
+ &priv->supplies[i]);
+ if (ret) {
+ log_debug("%s: cannot get %s %d\n", __func__,
+ tc358768_supplies[i], ret);
+ if (ret != -ENOENT)
+ return log_ret(ret);
+ }
}
/* get clk */
- priv->refclk = devm_clk_get(dev, "refclk");
+ priv->refclk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->refclk)) {
log_debug("%s: Could not get refclk: %ld\n",
__func__, PTR_ERR(priv->refclk));
return PTR_ERR(priv->refclk);
}
- /* get gpios */
- ret = gpio_request_by_name(dev, "reset-gpios", 0,
- &priv->reset_gpio, GPIOD_IS_OUT);
- if (ret) {
- log_debug("%s: Could not decode reset-gpios (%d)\n", __func__, ret);
- return ret;
- }
-
- dm_gpio_set_value(&priv->reset_gpio, 1);
+ dm_gpio_set_value(&uc_priv->reset, 1);
return 0;
}
@@ -963,8 +971,8 @@ static int tc358768_probe(struct udevice *dev)
return tc358768_setup(dev);
}
-struct panel_ops tc358768_ops = {
- .enable_backlight = tc358768_attach,
+static const struct video_bridge_ops tc358768_ops = {
+ .attach = tc358768_attach,
.set_backlight = tc358768_set_backlight,
.get_display_timing = tc358768_panel_timings,
};
@@ -977,9 +985,10 @@ static const struct udevice_id tc358768_ids[] = {
U_BOOT_DRIVER(tc358768) = {
.name = "tc358768",
- .id = UCLASS_PANEL,
+ .id = UCLASS_VIDEO_BRIDGE,
.of_match = tc358768_ids,
.ops = &tc358768_ops,
+ .bind = dm_scan_fdt_dev,
.probe = tc358768_probe,
.priv_auto = sizeof(struct tc358768_priv),
};
diff --git a/drivers/video/bridge/video-bridge-uclass.c b/drivers/video/bridge/video-bridge-uclass.c
index 2084a2e03ee..1b8aa12b9e8 100644
--- a/drivers/video/bridge/video-bridge-uclass.c
+++ b/drivers/video/bridge/video-bridge-uclass.c
@@ -33,6 +33,17 @@ int video_bridge_attach(struct udevice *dev)
return ops->attach(dev);
}
+int video_bridge_get_display_timing(struct udevice *dev,
+ struct display_timing *timings)
+{
+ struct video_bridge_ops *ops = video_bridge_get_ops(dev);
+
+ if (!ops->get_display_timing)
+ return -ENOSYS;
+
+ return ops->get_display_timing(dev, timings);
+}
+
int video_bridge_check_attached(struct udevice *dev)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
diff --git a/drivers/video/endeavoru-panel.c b/drivers/video/endeavoru-panel.c
index d4ba4d8b6da..9950ff8bb05 100644
--- a/drivers/video/endeavoru-panel.c
+++ b/drivers/video/endeavoru-panel.c
@@ -117,6 +117,18 @@ static int endeavoru_panel_set_backlight(struct udevice *dev, int percent)
struct endeavoru_panel_priv *priv = dev_get_priv(dev);
int ret;
+ /*
+ * Due to the use of the Tegra DC backlight feature, backlight
+ * requests MUST NOT be made during probe or earlier. This is
+ * because it creates a loop, as the backlight is a DC child.
+ */
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+ "backlight", &priv->backlight);
+ if (ret) {
+ log_err("cannot get backlight: ret = %d\n", ret);
+ return ret;
+ }
+
ret = backlight_enable(priv->backlight);
if (ret)
return ret;
@@ -136,13 +148,6 @@ static int endeavoru_panel_of_to_plat(struct udevice *dev)
struct endeavoru_panel_priv *priv = dev_get_priv(dev);
int ret;
- ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
- "backlight", &priv->backlight);
- if (ret) {
- log_err("cannot get backlight: ret = %d\n", ret);
- return ret;
- }
-
ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
"vdd-supply", &priv->vdd);
if (ret) {
@@ -231,7 +236,7 @@ static int endeavoru_panel_probe(struct udevice *dev)
/* fill characteristics of DSI data link */
plat->lanes = 2;
plat->format = MIPI_DSI_FMT_RGB888;
- plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
return endeavoru_panel_hw_init(dev);
}
diff --git a/drivers/video/lg-ld070wx3.c b/drivers/video/lg-ld070wx3.c
index 610a06ffe7b..3676e45bc65 100644
--- a/drivers/video/lg-ld070wx3.c
+++ b/drivers/video/lg-ld070wx3.c
@@ -158,7 +158,7 @@ static int lg_ld070wx3_probe(struct udevice *dev)
/* fill characteristics of DSI data link */
plat->lanes = 4;
plat->format = MIPI_DSI_FMT_RGB888;
- plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
return lg_ld070wx3_hw_init(dev);
}
diff --git a/drivers/video/lm3533_backlight.c b/drivers/video/lm3533_backlight.c
index 6b51fa0628e..7b87b6bd40b 100644
--- a/drivers/video/lm3533_backlight.c
+++ b/drivers/video/lm3533_backlight.c
@@ -7,6 +7,7 @@
#include <backlight.h>
#include <dm.h>
+#include <dm/ofnode.h>
#include <i2c.h>
#include <log.h>
#include <linux/delay.h>
@@ -17,56 +18,79 @@
#define LM3533_BL_MAX_BRIGHTNESS 0xFF
#define LM3533_SINK_OUTPUT_CONFIG_1 0x10
-#define LM3533_CONTROL_BANK_A_PWM 0x14
+#define LM3533_CONTROL_PWM_BASE 0x14
+#define PWM_MAX GENMASK(5, 0)
#define LM3533_CONTROL_BANK_AB_BRIGHTNESS 0x1A
-#define LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT 0x1F
+#define LM3533_CONTROL_FULLSCALE_CURRENT_BASE 0x1F
+#define MAX_CURRENT_MIN 5000
+#define MAX_CURRENT_MAX 29800
+#define MAX_CURRENT_STEP 800
#define LM3533_CONTROL_BANK_ENABLE 0x27
#define LM3533_OVP_FREQUENCY_PWM_POLARITY 0x2C
+#define BOOST_OVP_MASK GENMASK(2, 1)
+#define BOOST_OVP_SHIFT 1
+#define BOOST_FREQ_MASK BIT(0)
+#define BOOST_FREQ_SHIFT 0
#define LM3533_BRIGHTNESS_REGISTER_A 0x40
+#define LM3533_BOOST_OVP_16V 16000000UL
+#define LM3533_BOOST_FREQ_500KHZ 500000UL
+
struct lm3533_backlight_priv {
struct gpio_desc enable_gpio;
u32 def_bl_lvl;
+
+ /* Core */
+ u32 boost_ovp;
+ u32 boost_freq;
+
+ /* Backlight */
+ u32 reg;
+ u16 max_current; /* 5000 - 29800 uA (800 uA step) */
+ u8 pwm; /* 0 - 0x3f */
+ bool linear;
+ bool hvled;
};
static int lm3533_backlight_enable(struct udevice *dev)
{
struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+ u8 val, id = priv->reg;
int ret;
- dm_gpio_set_value(&priv->enable_gpio, 1);
- mdelay(5);
+ if (priv->linear) {
+ ret = dm_i2c_reg_clrset(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS,
+ BIT(2 * id + 1), BIT(2 * id + 1));
+ if (ret)
+ return ret;
+ }
- /* HVLED 1 & 2 are controlled by Bank A */
- ret = dm_i2c_reg_write(dev, LM3533_SINK_OUTPUT_CONFIG_1, 0x00);
- if (ret)
- return ret;
+ if (priv->hvled) {
+ ret = dm_i2c_reg_clrset(dev, LM3533_SINK_OUTPUT_CONFIG_1,
+ BIT(0) | BIT(1), id | id << 1);
+ if (ret)
+ return ret;
+ }
- /* PWM input is disabled for CABC */
- ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_PWM, 0x00);
- if (ret)
- return ret;
+ /* Set current */
+ if (priv->max_current < MAX_CURRENT_MIN || priv->max_current > MAX_CURRENT_MAX)
+ return -EINVAL;
- /* Linear & Control Bank A is configured for register Current control */
- ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS, 0x02);
+ val = (priv->max_current - MAX_CURRENT_MIN) / MAX_CURRENT_STEP;
+ ret = dm_i2c_reg_write(dev, LM3533_CONTROL_FULLSCALE_CURRENT_BASE + id, val);
if (ret)
return ret;
- /* Full-Scale Current (20.2mA) */
- ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT, 0x13);
- if (ret)
- return ret;
+ /* Set PWM mask */
+ if (priv->pwm > PWM_MAX)
+ return -EINVAL;
- /* Control Bank A is enable */
- ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_ENABLE, 0x01);
+ ret = dm_i2c_reg_write(dev, LM3533_CONTROL_PWM_BASE + id, priv->pwm);
if (ret)
return ret;
- ret = dm_i2c_reg_write(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY, 0x0A);
- if (ret)
- return ret;
-
- return 0;
+ /* Enable Control Bank */
+ return dm_i2c_reg_clrset(dev, LM3533_CONTROL_BANK_ENABLE, BIT(id), BIT(id));
}
static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
@@ -92,6 +116,56 @@ static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
return 0;
}
+static int lm3533_backlight_of_to_plat(struct udevice *dev)
+{
+ struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+ ofnode child;
+ int ret;
+
+ ret = gpio_request_by_name(dev, "enable-gpios", 0,
+ &priv->enable_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("Could not decode enable-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ priv->boost_ovp = dev_read_u32_default(dev, "ti,boost-ovp-microvolt",
+ LM3533_BOOST_OVP_16V);
+
+ /* boost_ovp is defined in microvolts, convert to enum value */
+ priv->boost_ovp = priv->boost_ovp / (8 * 1000 * 1000) - 2;
+
+ priv->boost_freq = dev_read_u32_default(dev, "ti,boost-freq-hz",
+ LM3533_BOOST_FREQ_500KHZ);
+
+ /* boost_freq is defined in Hz, convert to enum value */
+ priv->boost_freq = priv->boost_freq / (500 * 1000) - 1;
+
+ /* Backlight is one of children but has no dedicated driver */
+ ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+ if (ofnode_device_is_compatible(child, "ti,lm3533-backlight")) {
+ const char *node_name = ofnode_get_name(child);
+
+ if (!strcmp(&node_name[10], "1"))
+ priv->reg = 1;
+ else
+ priv->reg = 0;
+
+ priv->max_current = ofnode_read_u32_default(child, "ti,max-current-microamp",
+ 5000);
+ priv->pwm = ofnode_read_u32_default(child, "ti,pwm-config-mask", 0);
+
+ priv->def_bl_lvl = ofnode_read_u32_default(child, "default-brightness",
+ LM3533_BL_MAX_BRIGHTNESS);
+
+ priv->linear = ofnode_read_bool(child, "ti,linear-mapping-mode");
+ priv->hvled = ofnode_read_bool(child, "ti,hardware-controlled");
+ }
+ }
+
+ return 0;
+}
+
static int lm3533_backlight_probe(struct udevice *dev)
{
struct lm3533_backlight_priv *priv = dev_get_priv(dev);
@@ -100,15 +174,22 @@ static int lm3533_backlight_probe(struct udevice *dev)
if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
return -EPROTONOSUPPORT;
- ret = gpio_request_by_name(dev, "enable-gpios", 0,
- &priv->enable_gpio, GPIOD_IS_OUT);
+ dm_gpio_set_value(&priv->enable_gpio, 1);
+ mdelay(5);
+
+ ret = dm_i2c_reg_clrset(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY,
+ BOOST_FREQ_MASK, priv->boost_freq << BOOST_FREQ_SHIFT);
if (ret) {
- log_err("Could not decode enable-gpios (%d)\n", ret);
+ log_debug("%s: freq config failed %d\n", __func__, ret);
return ret;
}
- priv->def_bl_lvl = dev_read_u32_default(dev, "default-brightness-level",
- LM3533_BL_MAX_BRIGHTNESS);
+ ret = dm_i2c_reg_clrset(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY,
+ BOOST_OVP_MASK, priv->boost_ovp << BOOST_OVP_SHIFT);
+ if (ret) {
+ log_debug("%s: ovp config failed %d\n", __func__, ret);
+ return ret;
+ }
return 0;
}
@@ -127,6 +208,7 @@ U_BOOT_DRIVER(lm3533_backlight) = {
.name = "lm3533_backlight",
.id = UCLASS_PANEL_BACKLIGHT,
.of_match = lm3533_backlight_ids,
+ .of_to_plat = lm3533_backlight_of_to_plat,
.probe = lm3533_backlight_probe,
.ops = &lm3533_backlight_ops,
.priv_auto = sizeof(struct lm3533_backlight_priv),
diff --git a/drivers/video/lp855x_backlight.c b/drivers/video/lp855x_backlight.c
new file mode 100644
index 00000000000..5debc0aa453
--- /dev/null
+++ b/drivers/video/lp855x_backlight.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 Texas Instruments
+ * Copyright (c) 2024 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <malloc.h>
+#include <backlight.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/gpio.h>
+#include <power/regulator.h>
+
+#define LP855x_MIN_BRIGHTNESS 0x00
+#define LP855x_MAX_BRIGHTNESS 0xff
+
+/* LP8550/1/2/3/6 Registers */
+#define LP855X_BRIGHTNESS_CTRL 0x00
+#define LP855X_DEVICE_CTRL 0x01
+#define LP855X_EEPROM_START 0xa0
+#define LP855X_EEPROM_END 0xa7
+#define LP8556_EPROM_START 0x98
+#define LP8556_EPROM_END 0xaf
+
+/* LP8555/7 Registers */
+#define LP8557_BL_CMD 0x00
+#define LP8557_BL_MASK 0x01
+#define LP8557_BL_ON 0x01
+#define LP8557_BL_OFF 0x00
+#define LP8557_BRIGHTNESS_CTRL 0x04
+#define LP8557_CONFIG 0x10
+#define LP8555_EPROM_START 0x10
+#define LP8555_EPROM_END 0x7a
+#define LP8557_EPROM_START 0x10
+#define LP8557_EPROM_END 0x1e
+
+struct lp855x_rom_data {
+ u8 addr;
+ u8 val;
+};
+
+struct lp855x_backlight_priv;
+
+/*
+ * struct lp855x_device_config
+ * @pre_init_device: init device function call before updating the brightness
+ * @reg_brightness: register address for brigthenss control
+ * @reg_devicectrl: register address for device control
+ * @post_init_device: late init device function call
+ */
+struct lp855x_device_config {
+ int (*pre_init_device)(struct udevice *dev);
+ u8 reg_brightness;
+ u8 reg_devicectrl;
+ u8 reg_eepromstart;
+ u8 reg_eepromend;
+ int (*post_init_device)(struct udevice *dev);
+};
+
+struct lp855x_backlight_priv {
+ struct udevice *supply; /* regulator for VDD input */
+ struct udevice *enable; /* regulator for EN/VDDIO input */
+
+ u8 device_control;
+ u8 initial_brightness;
+
+ int size_program;
+ struct lp855x_rom_data *rom_data;
+ struct lp855x_device_config *cfg;
+};
+
+static int lp855x_backlight_enable(struct udevice *dev)
+{
+ struct lp855x_backlight_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regulator_set_enable_if_allowed(priv->supply, 1);
+ if (ret) {
+ log_debug("%s: enabling power-supply failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = regulator_set_enable_if_allowed(priv->enable, 1);
+ if (ret) {
+ log_debug("%s: enabling enable-supply failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ mdelay(2);
+
+ if (priv->cfg->pre_init_device) {
+ ret = priv->cfg->pre_init_device(dev);
+ if (ret) {
+ log_debug("%s: pre init device err: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ ret = dm_i2c_reg_write(dev, priv->cfg->reg_brightness,
+ priv->initial_brightness);
+ if (ret)
+ return ret;
+
+ ret = dm_i2c_reg_write(dev, priv->cfg->reg_devicectrl,
+ priv->device_control);
+ if (ret)
+ return ret;
+
+ if (priv->size_program > 0) {
+ int i;
+ u8 val, addr;
+
+ for (i = 0; i < priv->size_program; i++) {
+ addr = priv->rom_data[i].addr;
+ val = priv->rom_data[i].val;
+
+ if (addr < priv->cfg->reg_eepromstart &&
+ addr > priv->cfg->reg_eepromend)
+ continue;
+
+ ret = dm_i2c_reg_write(dev, addr, val);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (priv->cfg->post_init_device) {
+ ret = priv->cfg->post_init_device(dev);
+ if (ret) {
+ log_debug("%s: post init device err: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int lp855x_backlight_set_brightness(struct udevice *dev, int percent)
+{
+ struct lp855x_backlight_priv *priv = dev_get_priv(dev);
+
+ if (percent == BACKLIGHT_DEFAULT)
+ percent = priv->initial_brightness;
+
+ if (percent < LP855x_MIN_BRIGHTNESS)
+ percent = LP855x_MIN_BRIGHTNESS;
+
+ if (percent > LP855x_MAX_BRIGHTNESS)
+ percent = LP855x_MAX_BRIGHTNESS;
+
+ /* Set brightness level */
+ return dm_i2c_reg_write(dev, priv->cfg->reg_brightness,
+ percent);
+}
+
+static int lp855x_backlight_probe(struct udevice *dev)
+{
+ struct lp855x_backlight_priv *priv = dev_get_priv(dev);
+ int rom_length, ret;
+
+ if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
+ return -EPROTONOSUPPORT;
+
+ priv->cfg = (struct lp855x_device_config *)dev_get_driver_data(dev);
+
+ dev_read_u8(dev, "dev-ctrl", &priv->device_control);
+ dev_read_u8(dev, "init-brt", &priv->initial_brightness);
+
+ /* Fill ROM platform data if defined */
+ rom_length = dev_get_child_count(dev);
+ if (rom_length > 0) {
+ struct lp855x_rom_data *rom;
+ ofnode child;
+ int i = 0;
+
+ rom = devm_kcalloc(dev, rom_length, sizeof(*rom), GFP_KERNEL);
+ if (!rom)
+ return -ENOMEM;
+
+ dev_for_each_subnode(child, dev) {
+ ofnode_read_u8(child, "rom-addr", &rom[i].addr);
+ ofnode_read_u8(child, "rom-val", &rom[i].val);
+ i++;
+ }
+
+ priv->size_program = rom_length;
+ priv->rom_data = &rom[0];
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "power-supply", &priv->supply);
+ if (ret) {
+ log_err("%s: cannot get power-supply: ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "enable-supply", &priv->enable);
+ if (ret) {
+ log_err("%s: cannot get enable-supply: ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct backlight_ops lp855x_backlight_ops = {
+ .enable = lp855x_backlight_enable,
+ .set_brightness = lp855x_backlight_set_brightness,
+};
+
+static int lp8556_bl_rst(struct udevice *dev)
+{
+ int ret;
+
+ /* Reset backlight after updating EPROM settings */
+ ret = dm_i2c_reg_clrset(dev, LP855X_DEVICE_CTRL, LP8557_BL_MASK,
+ LP8557_BL_OFF);
+ if (ret)
+ return ret;
+
+ mdelay(10);
+
+ return dm_i2c_reg_clrset(dev, LP855X_DEVICE_CTRL, LP8557_BL_MASK,
+ LP8557_BL_ON);
+}
+
+static int lp8557_bl_off(struct udevice *dev)
+{
+ /* BL_ON = 0 before updating EPROM settings */
+ return dm_i2c_reg_clrset(dev, LP8557_BL_CMD, LP8557_BL_MASK,
+ LP8557_BL_OFF);
+}
+
+static int lp8557_bl_on(struct udevice *dev)
+{
+ /* BL_ON = 1 after updating EPROM settings */
+ return dm_i2c_reg_clrset(dev, LP8557_BL_CMD, LP8557_BL_MASK,
+ LP8557_BL_ON);
+}
+
+static struct lp855x_device_config lp855x_dev_cfg = {
+ .reg_brightness = LP855X_BRIGHTNESS_CTRL,
+ .reg_devicectrl = LP855X_DEVICE_CTRL,
+ .reg_eepromstart = LP855X_EEPROM_START,
+ .reg_eepromend = LP855X_EEPROM_END,
+};
+
+static struct lp855x_device_config lp8555_dev_cfg = {
+ .reg_brightness = LP8557_BRIGHTNESS_CTRL,
+ .reg_devicectrl = LP8557_CONFIG,
+ .reg_eepromstart = LP8555_EPROM_START,
+ .reg_eepromend = LP8555_EPROM_END,
+ .pre_init_device = lp8557_bl_off,
+ .post_init_device = lp8557_bl_on,
+};
+
+static struct lp855x_device_config lp8556_dev_cfg = {
+ .reg_brightness = LP855X_BRIGHTNESS_CTRL,
+ .reg_devicectrl = LP855X_DEVICE_CTRL,
+ .reg_eepromstart = LP8556_EPROM_START,
+ .reg_eepromend = LP8556_EPROM_END,
+ .post_init_device = lp8556_bl_rst,
+};
+
+static struct lp855x_device_config lp8557_dev_cfg = {
+ .reg_brightness = LP8557_BRIGHTNESS_CTRL,
+ .reg_devicectrl = LP8557_CONFIG,
+ .reg_eepromstart = LP8557_EPROM_START,
+ .reg_eepromend = LP8557_EPROM_END,
+ .pre_init_device = lp8557_bl_off,
+ .post_init_device = lp8557_bl_on,
+};
+
+static const struct udevice_id lp855x_backlight_ids[] = {
+ { .compatible = "ti,lp8550", .data = (ulong)&lp855x_dev_cfg },
+ { .compatible = "ti,lp8551", .data = (ulong)&lp855x_dev_cfg },
+ { .compatible = "ti,lp8552", .data = (ulong)&lp855x_dev_cfg },
+ { .compatible = "ti,lp8553", .data = (ulong)&lp855x_dev_cfg },
+ { .compatible = "ti,lp8555", .data = (ulong)&lp8555_dev_cfg },
+ { .compatible = "ti,lp8556", .data = (ulong)&lp8556_dev_cfg },
+ { .compatible = "ti,lp8557", .data = (ulong)&lp8557_dev_cfg },
+ { }
+};
+
+U_BOOT_DRIVER(lp855x_backlight) = {
+ .name = "lp855x_backlight",
+ .id = UCLASS_PANEL_BACKLIGHT,
+ .of_match = lp855x_backlight_ids,
+ .probe = lp855x_backlight_probe,
+ .ops = &lp855x_backlight_ops,
+ .priv_auto = sizeof(struct lp855x_backlight_priv),
+};
diff --git a/drivers/video/renesas-r61307.c b/drivers/video/renesas-r61307.c
index a3697bce5ee..ef6fab1e953 100644
--- a/drivers/video/renesas-r61307.c
+++ b/drivers/video/renesas-r61307.c
@@ -254,17 +254,17 @@ static int renesas_r61307_hw_init(struct udevice *dev)
return ret;
}
- ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
if (ret) {
- log_debug("%s: changing reset-gpio failed (%d)\n",
+ log_debug("%s: entering reset failed (%d)\n",
__func__, ret);
return ret;
}
mdelay(5);
- ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
if (ret) {
- log_debug("%s: changing reset-gpio failed (%d)\n",
+ log_debug("%s: exiting reset failed (%d)\n",
__func__, ret);
return ret;
}
@@ -281,7 +281,8 @@ static int renesas_r61307_probe(struct udevice *dev)
/* fill characteristics of DSI data link */
plat->lanes = 4;
plat->format = MIPI_DSI_FMT_RGB888;
- plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
return renesas_r61307_hw_init(dev);
}
@@ -294,7 +295,7 @@ static const struct panel_ops renesas_r61307_ops = {
static const struct udevice_id renesas_r61307_ids[] = {
{ .compatible = "koe,tx13d100vm0eaa" },
- { .compatible = "hitachi,tx13d100vm0eaa" },
+ { .compatible = "hit,tx13d100vm0eaa" },
{ }
};
diff --git a/drivers/video/renesas-r69328.c b/drivers/video/renesas-r69328.c
index 9861c3fef11..0954b04b62e 100644
--- a/drivers/video/renesas-r69328.c
+++ b/drivers/video/renesas-r69328.c
@@ -32,9 +32,11 @@
#define R69328_POWER_SET 0xD1
struct renesas_r69328_priv {
+ struct udevice *vdd;
+ struct udevice *vddio;
+
struct udevice *backlight;
- struct gpio_desc enable_gpio;
struct gpio_desc reset_gpio;
};
@@ -159,10 +161,15 @@ static int renesas_r69328_of_to_plat(struct udevice *dev)
return ret;
}
- ret = gpio_request_by_name(dev, "enable-gpios", 0,
- &priv->enable_gpio, GPIOD_IS_OUT);
+ ret = device_get_supply_regulator(dev, "vdd-supply", &priv->vdd);
if (ret) {
- log_err("could not decode enable-gpios (%d)\n", ret);
+ log_err("Cannot get vdd-supply: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vddio-supply", &priv->vddio);
+ if (ret) {
+ log_err("Cannot get vddio-supply: ret = %d\n", ret);
return ret;
}
@@ -181,25 +188,32 @@ static int renesas_r69328_hw_init(struct udevice *dev)
struct renesas_r69328_priv *priv = dev_get_priv(dev);
int ret;
- ret = dm_gpio_set_value(&priv->enable_gpio, 1);
+ ret = regulator_set_enable_if_allowed(priv->vddio, 1);
if (ret) {
- log_debug("%s: error changing enable-gpios (%d)\n",
+ log_debug("%s: enabling vddio-supply failed (%d)\n",
__func__, ret);
return ret;
}
mdelay(5);
- ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ ret = regulator_set_enable_if_allowed(priv->vdd, 1);
if (ret) {
- log_debug("%s: error changing reset-gpios (%d)\n",
+ log_debug("%s: enabling vdd-supply failed (%d)\n",
__func__, ret);
return ret;
}
- mdelay(5);
ret = dm_gpio_set_value(&priv->reset_gpio, 1);
if (ret) {
- log_debug("%s: error changing reset-gpios (%d)\n",
+ log_debug("%s: error entering reset (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_debug("%s: error exiting reset (%d)\n",
__func__, ret);
return ret;
}
@@ -216,7 +230,8 @@ static int renesas_r69328_probe(struct udevice *dev)
/* fill characteristics of DSI data link */
plat->lanes = 4;
plat->format = MIPI_DSI_FMT_RGB888;
- plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
return renesas_r69328_hw_init(dev);
}
diff --git a/drivers/video/samsung-ltl106hl02.c b/drivers/video/samsung-ltl106hl02.c
index 5e6c11c4be3..1efc9fca610 100644
--- a/drivers/video/samsung-ltl106hl02.c
+++ b/drivers/video/samsung-ltl106hl02.c
@@ -129,7 +129,7 @@ static int samsung_ltl106hl02_probe(struct udevice *dev)
/* fill characteristics of DSI data link */
plat->lanes = 4;
plat->format = MIPI_DSI_FMT_RGB888;
- plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
return samsung_ltl106hl02_hw_init(dev);
}
diff --git a/drivers/video/sharp-lq079l1sx01.c b/drivers/video/sharp-lq079l1sx01.c
new file mode 100644
index 00000000000..a8197f40fc7
--- /dev/null
+++ b/drivers/video/sharp-lq079l1sx01.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sharp LQ079L1SX01 DSI panel driver
+ *
+ * Copyright (c) 2024 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <backlight.h>
+#include <dm.h>
+#include <panel.h>
+#include <log.h>
+#include <mipi_dsi.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+#include <power/regulator.h>
+
+struct sharp_lq079l1sx01_priv {
+ struct udevice *backlight;
+ struct udevice *panel_sec;
+
+ struct udevice *avdd;
+ struct udevice *vddio;
+ struct udevice *vsp;
+ struct udevice *vsn;
+
+ struct gpio_desc reset_gpio;
+};
+
+static struct display_timing default_timing = {
+ .pixelclock.typ = 215000000,
+ .hactive.typ = 1536,
+ .hfront_porch.typ = 136,
+ .hback_porch.typ = 28,
+ .hsync_len.typ = 28,
+ .vactive.typ = 2048,
+ .vfront_porch.typ = 14,
+ .vback_porch.typ = 8,
+ .vsync_len.typ = 2,
+};
+
+static int dcs_write_one(struct mipi_dsi_device *dsi, u8 cmd, u8 data)
+{
+ return mipi_dsi_dcs_write(dsi, cmd, &data, 1);
+}
+
+static int sharp_lq079l1sx01_configure_link(struct udevice *dev)
+{
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+ struct mipi_dsi_device *dsi = plat->device;
+ int ret;
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ log_debug("%s: failed to exit sleep mode %s: %d\n",
+ __func__, dev->parent->name, ret);
+ }
+ mdelay(120);
+
+ ret = dcs_write_one(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff);
+ if (ret < 0) {
+ log_debug("%s: failed to SET_DISPLAY_BRIGHTNESS %s: %d\n",
+ __func__, dev->parent->name, ret);
+ }
+ ret = dcs_write_one(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x01);
+ if (ret < 0) {
+ log_debug("%s: failed to WRITE_POWER_SAVE %s: %d\n",
+ __func__, dev->parent->name, ret);
+ }
+ ret = dcs_write_one(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c);
+ if (ret < 0) {
+ log_debug("%s: failed to WRITE_CONTROL_DISPLAY %s: %d\n",
+ __func__, dev->parent->name, ret);
+ }
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ log_debug("%s: failed to set panel on %s: %d\n",
+ __func__, dev->parent->name, ret);
+ }
+
+ return 0;
+}
+
+static int sharp_lq079l1sx01_enable_backlight(struct udevice *dev)
+{
+ struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev);
+
+ if (!priv->panel_sec)
+ return 0;
+
+ sharp_lq079l1sx01_configure_link(dev);
+ sharp_lq079l1sx01_configure_link(priv->panel_sec);
+
+ return 0;
+}
+
+static int sharp_lq079l1sx01_set_backlight(struct udevice *dev, int percent)
+{
+ struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (!priv->panel_sec)
+ return 0;
+
+ ret = backlight_enable(priv->backlight);
+ if (ret)
+ return ret;
+
+ return backlight_set_brightness(priv->backlight, percent);
+}
+
+static int sharp_lq079l1sx01_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ memcpy(timing, &default_timing, sizeof(*timing));
+ return 0;
+}
+
+static int sharp_lq079l1sx01_of_to_plat(struct udevice *dev)
+{
+ struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* If node has no link2 it is secondary panel */
+ if (!dev_read_bool(dev, "link2"))
+ return 0;
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
+ "link2", &priv->panel_sec);
+ if (ret) {
+ log_debug("%s: cannot get secondary panel: ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+ "backlight", &priv->backlight);
+ if (ret) {
+ log_debug("%s: cannot get backlight: ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "avdd-supply", &priv->avdd);
+ if (ret) {
+ log_debug("%s: cannot get avdd-supply: ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "vddio-supply", &priv->vddio);
+ if (ret) {
+ log_debug("%s: cannot get vddio-supply: ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "vsp-supply", &priv->vsp);
+ if (ret) {
+ log_debug("%s: cannot get vsp-supply: ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "vsn-supply", &priv->vsn);
+ if (ret) {
+ log_debug("%s: cannot get vsn-supply: ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_debug("%s: cannot get reser-gpios (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sharp_lq079l1sx01_hw_init(struct udevice *dev)
+{
+ struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (!priv->panel_sec)
+ return 0;
+
+ ret = regulator_set_enable_if_allowed(priv->vddio, 1);
+ if (ret) {
+ log_debug("%s: enabling vddio-supply failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = regulator_set_enable_if_allowed(priv->avdd, 1);
+ if (ret) {
+ log_debug("%s: enabling avdd-supply failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ mdelay(12);
+
+ ret = regulator_set_enable_if_allowed(priv->vsp, 1);
+ if (ret) {
+ log_debug("%s: enabling vsp-supply failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ mdelay(12);
+
+ ret = regulator_set_enable_if_allowed(priv->vsn, 1);
+ if (ret) {
+ log_debug("%s: enabling vsn-supply failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ mdelay(24);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_debug("%s: error disabling reset-gpios (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ udelay(3);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_debug("%s: error enabling reset-gpios (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ udelay(3);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_debug("%s: error disabling reset-gpios (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ mdelay(32);
+
+ return 0;
+}
+
+static int sharp_lq079l1sx01_probe(struct udevice *dev)
+{
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+ /* fill characteristics of DSI data link */
+ plat->lanes = 4;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
+
+ return sharp_lq079l1sx01_hw_init(dev);
+}
+
+static const struct panel_ops sharp_lq079l1sx01_ops = {
+ .enable_backlight = sharp_lq079l1sx01_enable_backlight,
+ .set_backlight = sharp_lq079l1sx01_set_backlight,
+ .get_display_timing = sharp_lq079l1sx01_timings,
+};
+
+static const struct udevice_id sharp_lq079l1sx01_ids[] = {
+ { .compatible = "sharp,lq079l1sx01" },
+ { }
+};
+
+U_BOOT_DRIVER(sharp_lq079l1sx01) = {
+ .name = "sharp_lq079l1sx01",
+ .id = UCLASS_PANEL,
+ .of_match = sharp_lq079l1sx01_ids,
+ .ops = &sharp_lq079l1sx01_ops,
+ .of_to_plat = sharp_lq079l1sx01_of_to_plat,
+ .probe = sharp_lq079l1sx01_probe,
+ .plat_auto = sizeof(struct mipi_dsi_panel_plat),
+ .priv_auto = sizeof(struct sharp_lq079l1sx01_priv),
+};
diff --git a/drivers/video/sharp-lq101r1sx01.c b/drivers/video/sharp-lq101r1sx01.c
index 5d8453fd796..4fdf0da8a94 100644
--- a/drivers/video/sharp-lq101r1sx01.c
+++ b/drivers/video/sharp-lq101r1sx01.c
@@ -255,6 +255,7 @@ static int sharp_lq101r1sx01_probe(struct udevice *dev)
/* fill characteristics of DSI data link */
plat->lanes = 4;
plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_LPM;
return sharp_lq101r1sx01_hw_init(dev);
}
diff --git a/drivers/video/tegra20/Kconfig b/drivers/video/tegra20/Kconfig
index f5c4843e119..598f9ea1f21 100644
--- a/drivers/video/tegra20/Kconfig
+++ b/drivers/video/tegra20/Kconfig
@@ -1,6 +1,11 @@
+config HOST1X_TEGRA
+ bool "NVIDIA Tegra host1x BUS support"
+ depends on SIMPLE_BUS
+
config VIDEO_TEGRA20
bool "Enable Display Controller support on Tegra20 and Tegra 30"
depends on OF_CONTROL
+ select HOST1X_TEGRA
help
T20/T30 support video output to an attached LCD panel as well as
other options such as HDMI. Only the LCD is supported in U-Boot.
@@ -9,13 +14,22 @@ config VIDEO_TEGRA20
config VIDEO_DSI_TEGRA30
bool "Enable Tegra 30 DSI support"
- depends on PANEL && DM_GPIO
+ depends on VIDEO_BRIDGE && PANEL && DM_GPIO
select VIDEO_TEGRA20
select VIDEO_MIPI_DSI
help
T30 has native support for DSI panels. This option enables support
for such panels which can be used on endeavoru and tf600t.
+config VIDEO_HDMI_TEGRA
+ bool "Enable Tegra HDMI support"
+ depends on VIDEO_BRIDGE && DM_I2C
+ select I2C_EDID
+ select VIDEO_TEGRA20
+ help
+ Tegra has native support for HDMI. This option enables support
+ for such connection and can be used for any supported device.
+
config TEGRA_BACKLIGHT_PWM
bool "Enable Tegra DC PWM backlight support"
depends on BACKLIGHT
diff --git a/drivers/video/tegra20/Makefile b/drivers/video/tegra20/Makefile
index a75aea2a875..78521405749 100644
--- a/drivers/video/tegra20/Makefile
+++ b/drivers/video/tegra20/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
+obj-$(CONFIG_HOST1X_TEGRA) += tegra-host1x.o
obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o
obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o tegra-mipi.o mipi-phy.o
+obj-$(CONFIG_VIDEO_HDMI_TEGRA) += tegra-hdmi.o
obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o
diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c
index d24aa375b39..1f43153ff27 100644
--- a/drivers/video/tegra20/tegra-dc.c
+++ b/drivers/video/tegra20/tegra-dc.c
@@ -1,28 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (c) 2024 Svyatoslav Ryhel <clamor95@gmail.com>
*/
#include <backlight.h>
#include <cpu_func.h>
+#include <clk.h>
#include <dm.h>
+#include <dm/ofnode_graph.h>
#include <fdtdec.h>
#include <log.h>
#include <panel.h>
-#include <part.h>
-#include <pwm.h>
#include <video.h>
-#include <asm/cache.h>
-#include <asm/global_data.h>
+#include <video_bridge.h>
#include <asm/system.h>
-#include <asm/gpio.h>
#include <asm/io.h>
-
#include <asm/arch/clock.h>
-#include <asm/arch/funcmux.h>
-#include <asm/arch/pinmux.h>
#include <asm/arch/powergate.h>
-#include <asm/arch/pwm.h>
#include "tegra-dc.h"
@@ -39,12 +34,14 @@ struct tegra_lcd_priv {
int height; /* height in pixels */
enum video_log2_bpp log2_bpp; /* colour depth */
struct display_timing timing;
- struct udevice *panel;
+ struct udevice *panel; /* Panels attached to RGB */
+ struct udevice *bridge; /* Bridge linked with DC */
struct dc_ctlr *dc; /* Display controller regmap */
const struct tegra_dc_soc_info *soc;
fdt_addr_t frame_buffer; /* Address of frame buffer */
unsigned pixel_clock; /* Pixel clock in Hz */
- int dc_clk[2]; /* Contains clk and its parent */
+ struct clk *clk;
+ struct clk *clk_parent;
ulong scdiv; /* Clock divider used by disp_clk_ctrl */
bool rotation; /* 180 degree panel turn */
int pipe; /* DC controller: 0 for A, 1 for B */
@@ -144,10 +141,9 @@ static int update_display_mode(struct tegra_lcd_priv *priv)
val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT;
val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT;
writel(val, &disp->disp_interface_ctrl);
- }
- if (priv->soc->has_rgb)
writel(0x00010001, &disp->shift_clk_opt);
+ }
val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT;
val |= priv->scdiv << SHIFT_CLK_DIVIDER_SHIFT;
@@ -267,7 +263,9 @@ static int setup_window(struct tegra_lcd_priv *priv,
win->out_h = priv->height;
win->phys_addr = priv->frame_buffer;
win->stride = priv->width * (1 << priv->log2_bpp) / 8;
- debug("%s: depth = %d\n", __func__, priv->log2_bpp);
+
+ log_debug("%s: depth = %d\n", __func__, priv->log2_bpp);
+
switch (priv->log2_bpp) {
case VIDEO_BPP32:
win->fmt = COLOR_DEPTH_R8G8B8A8;
@@ -279,7 +277,7 @@ static int setup_window(struct tegra_lcd_priv *priv,
break;
default:
- debug("Unsupported LCD bit depth");
+ log_debug("Unsupported LCD bit depth\n");
return -1;
}
@@ -301,7 +299,8 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv,
void *default_lcd_base)
{
struct disp_ctl_win window;
- unsigned long rate = clock_get_rate(priv->dc_clk[1]);
+ unsigned long rate = clk_get_rate(priv->clk_parent);
+ int ret;
priv->frame_buffer = (u32)default_lcd_base;
@@ -309,15 +308,10 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv,
* We halve the rate if DISP1 parent is PLLD, since actual parent
* is plld_out0 which is PLLD divided by 2.
*/
- if (priv->dc_clk[1] == CLOCK_ID_DISPLAY)
+ if (priv->clk_parent->id == CLOCK_ID_DISPLAY ||
+ priv->clk_parent->id == CLOCK_ID_DISPLAY2)
rate /= 2;
-#ifndef CONFIG_TEGRA20
- /* PLLD2 obeys same rules as PLLD but it is present only on T30+ */
- if (priv->dc_clk[1] == CLOCK_ID_DISPLAY2)
- rate /= 2;
-#endif
-
/*
* The pixel clock divider is in 7.1 format (where the bottom bit
* represents 0.5). Here we calculate the divider needed to get from
@@ -327,14 +321,9 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv,
if (!priv->scdiv)
priv->scdiv = ((rate * 2 + priv->pixel_clock / 2)
/ priv->pixel_clock) - 2;
- debug("Display clock %lu, divider %lu\n", rate, priv->scdiv);
+ log_debug("Display clock %lu, divider %lu\n", rate, priv->scdiv);
- /*
- * HOST1X is init by default at 150MHz with PLLC as parent
- */
- clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL,
- 150 * 1000000);
- clock_start_periph_pll(priv->dc_clk[0], priv->dc_clk[1],
+ clock_start_periph_pll(priv->clk->id, priv->clk_parent->id,
rate);
basic_init(&priv->dc->cmd);
@@ -348,8 +337,9 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv,
if (priv->pixel_clock)
update_display_mode(priv);
- if (setup_window(priv, &window))
- return -1;
+ ret = setup_window(priv, &window);
+ if (ret)
+ return ret;
update_window(priv, &window);
@@ -364,10 +354,6 @@ static int tegra_lcd_probe(struct udevice *dev)
int ret;
/* Initialize the Tegra display controller */
-#ifdef CONFIG_TEGRA20
- funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
-#endif
-
if (priv->soc->has_pgate) {
uint powergate;
@@ -378,44 +364,51 @@ static int tegra_lcd_probe(struct udevice *dev)
ret = tegra_powergate_power_off(powergate);
if (ret < 0) {
- log_err("failed to power off DISP gate: %d", ret);
+ log_debug("failed to power off DISP gate: %d", ret);
return ret;
}
ret = tegra_powergate_sequence_power_up(powergate,
- priv->dc_clk[0]);
+ priv->clk->id);
if (ret < 0) {
- log_err("failed to power up DISP gate: %d", ret);
+ log_debug("failed to power up DISP gate: %d", ret);
return ret;
}
}
/* Get shift clock divider from Tegra DSI if used */
- if (!strcmp(priv->panel->name, TEGRA_DSI_A) ||
- !strcmp(priv->panel->name, TEGRA_DSI_B)) {
- struct tegra_dc_plat *dc_plat = dev_get_plat(priv->panel);
+ if (priv->bridge) {
+ if (!strcmp(priv->bridge->driver->name, "tegra_dsi")) {
+ struct tegra_dc_plat *dc_plat = dev_get_plat(priv->bridge);
- priv->scdiv = dc_plat->scdiv;
+ priv->scdiv = dc_plat->scdiv;
+ }
}
/* Clean the framebuffer area */
memset((u8 *)plat->base, 0, plat->size);
flush_dcache_all();
- if (tegra_display_probe(priv, (void *)plat->base)) {
- debug("%s: Failed to probe display driver\n", __func__);
- return -1;
+ ret = tegra_display_probe(priv, (void *)plat->base);
+ if (ret) {
+ log_debug("%s: Failed to probe display driver\n", __func__);
+ return ret;
}
-#ifdef CONFIG_TEGRA20
- pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM);
- pinmux_tristate_disable(PMUX_PINGRP_GPU);
-#endif
+ if (priv->panel) {
+ ret = panel_enable_backlight(priv->panel);
+ if (ret) {
+ log_debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret);
+ return ret;
+ }
+ }
- ret = panel_enable_backlight(priv->panel);
- if (ret) {
- debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret);
- return ret;
+ if (priv->bridge) {
+ ret = video_bridge_attach(priv->bridge);
+ if (ret) {
+ log_debug("%s: Cannot attach bridge, ret=%d\n", __func__, ret);
+ return ret;
+ }
}
mmu_set_region_dcache_behaviour(priv->frame_buffer, plat->size,
@@ -427,81 +420,198 @@ static int tegra_lcd_probe(struct udevice *dev)
uc_priv->xsize = priv->width;
uc_priv->ysize = priv->height;
uc_priv->bpix = priv->log2_bpp;
- debug("LCD frame buffer at %08x, size %x\n", priv->frame_buffer,
- plat->size);
+ log_debug("LCD frame buffer at %08x, size %x\n", priv->frame_buffer,
+ plat->size);
- return panel_set_backlight(priv->panel, BACKLIGHT_DEFAULT);
+ if (priv->panel) {
+ ret = panel_set_backlight(priv->panel, BACKLIGHT_DEFAULT);
+ if (ret)
+ return ret;
+ }
+
+ if (priv->bridge) {
+ ret = video_bridge_set_backlight(priv->bridge, BACKLIGHT_DEFAULT);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra_lcd_configure_rgb(struct udevice *dev, ofnode rgb)
+{
+ struct tegra_lcd_priv *priv = dev_get_priv(dev);
+ ofnode remote;
+ int ret;
+
+ /* DC can have only 1 port */
+ remote = ofnode_graph_get_remote_node(rgb, -1, -1);
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PANEL, remote, &priv->panel);
+ if (!ret)
+ return 0;
+
+ ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_BRIDGE, remote, &priv->bridge);
+ if (!ret)
+ return 0;
+
+ /* Try legacy method if graph did not work */
+ remote = ofnode_parse_phandle(rgb, "nvidia,panel", 0);
+ if (!ofnode_valid(remote))
+ return -EINVAL;
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PANEL, remote, &priv->panel);
+ if (ret) {
+ log_debug("%s: Cannot find panel for '%s' (ret=%d)\n",
+ __func__, dev->name, ret);
+
+ ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_BRIDGE, remote,
+ &priv->bridge);
+ if (ret) {
+ log_err("%s: Cannot find panel or bridge for '%s' (ret=%d)\n",
+ __func__, dev->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra_lcd_configure_internal(struct udevice *dev)
+{
+ struct tegra_lcd_priv *priv = dev_get_priv(dev);
+ struct tegra_dc_plat *dc_plat;
+ ofnode host1x = ofnode_get_parent(dev_ofnode(dev));
+ ofnode node;
+ int ret;
+
+ switch (priv->pipe) {
+ case 0: /* DC0 is usually used for DSI */
+ /* Check for ganged DSI configuration */
+ ofnode_for_each_subnode(node, host1x)
+ if (ofnode_name_eq(node, "dsi") && ofnode_is_enabled(node) &&
+ ofnode_read_bool(node, "nvidia,ganged-mode"))
+ goto exit;
+
+ /* If no master DSI found loop for any active DSI */
+ ofnode_for_each_subnode(node, host1x)
+ if (ofnode_name_eq(node, "dsi") && ofnode_is_enabled(node))
+ goto exit;
+
+ log_err("%s: failed to find DSI device for '%s'\n",
+ __func__, dev->name);
+
+ return -ENODEV;
+ case 1: /* DC1 is usually used for HDMI */
+ ofnode_for_each_subnode(node, host1x)
+ if (ofnode_name_eq(node, "hdmi"))
+ goto exit;
+
+ log_err("%s: failed to find HDMI device for '%s'\n",
+ __func__, dev->name);
+
+ return -ENODEV;
+ default:
+ log_debug("Unsupported DC selection\n");
+ return -EINVAL;
+ }
+
+exit:
+ ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_BRIDGE, node, &priv->bridge);
+ if (ret) {
+ log_err("%s: failed to get DSI/HDMI device for '%s' (ret %d)\n",
+ __func__, dev->name, ret);
+ return ret;
+ }
+
+ priv->clk_parent = devm_clk_get(priv->bridge, "parent");
+ if (IS_ERR(priv->clk_parent)) {
+ log_debug("%s: Could not get DC clock parent from DSI/HDMI: %ld\n",
+ __func__, PTR_ERR(priv->clk_parent));
+ return PTR_ERR(priv->clk_parent);
+ }
+
+ dc_plat = dev_get_plat(priv->bridge);
+
+ /* Fill the platform data for internal devices */
+ dc_plat->dev = dev;
+ dc_plat->dc = priv->dc;
+ dc_plat->pipe = priv->pipe;
+
+ return 0;
}
static int tegra_lcd_of_to_plat(struct udevice *dev)
{
struct tegra_lcd_priv *priv = dev_get_priv(dev);
- const void *blob = gd->fdt_blob;
struct display_timing *timing;
- int node = dev_of_offset(dev);
- int panel_node;
- int rgb;
+ ofnode rgb;
int ret;
priv->dc = (struct dc_ctlr *)dev_read_addr_ptr(dev);
if (!priv->dc) {
- debug("%s: No display controller address\n", __func__);
+ log_debug("%s: No display controller address\n", __func__);
return -EINVAL;
}
priv->soc = (struct tegra_dc_soc_info *)dev_get_driver_data(dev);
- ret = clock_decode_pair(dev, priv->dc_clk);
- if (ret < 0) {
- debug("%s: Cannot decode clocks for '%s' (ret = %d)\n",
- __func__, dev->name, ret);
- return -EINVAL;
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ log_debug("%s: Could not get DC clock: %ld\n",
+ __func__, PTR_ERR(priv->clk));
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->clk_parent = devm_clk_get(dev, "parent");
+ if (IS_ERR(priv->clk_parent)) {
+ log_debug("%s: Could not get DC clock parent: %ld\n",
+ __func__, PTR_ERR(priv->clk_parent));
+ return PTR_ERR(priv->clk_parent);
}
priv->rotation = dev_read_bool(dev, "nvidia,180-rotation");
priv->pipe = dev_read_u32_default(dev, "nvidia,head", 0);
- rgb = fdt_subnode_offset(blob, node, "rgb");
- if (rgb < 0) {
- debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n",
- __func__, dev->name, rgb);
- return -EINVAL;
- }
-
/*
- * Sadly the panel phandle is in an rgb subnode so we cannot use
- * uclass_get_device_by_phandle().
+ * Usual logic of Tegra video routing should be next:
+ * 1. Check rgb subnode for RGB/LVDS panels or bridges
+ * 2. If none found, then iterate through bridges bound,
+ * looking for DSIA or DSIB for DC0 and HDMI for DC1.
+ * If none of above is valid, then configuration is not
+ * valid.
*/
- panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
- if (panel_node < 0) {
- debug("%s: Cannot find panel information\n", __func__);
- return -EINVAL;
- }
- ret = uclass_get_device_by_of_offset(UCLASS_PANEL, panel_node,
- &priv->panel);
- if (ret) {
- debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
- dev->name, ret);
- return ret;
+ rgb = dev_read_subnode(dev, "rgb");
+ if (ofnode_valid(rgb) && ofnode_is_enabled(rgb)) {
+ /* RGB is available, use it */
+ ret = tegra_lcd_configure_rgb(dev, rgb);
+ if (ret)
+ return ret;
+ } else {
+ /* RGB is not available, check for internal devices */
+ ret = tegra_lcd_configure_internal(dev);
+ if (ret)
+ return ret;
}
- /* Fill the platform data for internal devices */
- if (!strcmp(priv->panel->name, TEGRA_DSI_A) ||
- !strcmp(priv->panel->name, TEGRA_DSI_B)) {
- struct tegra_dc_plat *dc_plat = dev_get_plat(priv->panel);
-
- dc_plat->dev = dev;
- dc_plat->dc = priv->dc;
- dc_plat->pipe = priv->pipe;
+ if (priv->panel) {
+ ret = panel_get_display_timing(priv->panel, &priv->timing);
+ if (ret) {
+ ret = ofnode_decode_display_timing(rgb, 0, &priv->timing);
+ if (ret) {
+ log_debug("%s: Cannot read display timing for '%s' (ret=%d)\n",
+ __func__, dev->name, ret);
+ return -EINVAL;
+ }
+ }
}
- ret = panel_get_display_timing(priv->panel, &priv->timing);
- if (ret) {
- ret = fdtdec_decode_display_timing(blob, rgb, 0, &priv->timing);
+ if (priv->bridge) {
+ ret = video_bridge_get_display_timing(priv->bridge, &priv->timing);
if (ret) {
- debug("%s: Cannot read display timing for '%s' (ret=%d)\n",
- __func__, dev->name, ret);
+ log_debug("%s: Cannot read display timing for '%s' (ret=%d)\n",
+ __func__, dev->name, ret);
return -EINVAL;
}
}
@@ -518,23 +628,13 @@ static int tegra_lcd_of_to_plat(struct udevice *dev)
static int tegra_lcd_bind(struct udevice *dev)
{
struct video_uc_plat *plat = dev_get_uclass_plat(dev);
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(dev);
- int rgb;
-
- rgb = fdt_subnode_offset(blob, node, "rgb");
- if ((rgb < 0) || !fdtdec_get_is_enabled(blob, rgb))
- return -ENODEV;
plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
(1 << LCD_MAX_LOG2_BPP) / 8;
- return 0;
+ return dm_scan_fdt_dev(dev);
}
-static const struct video_ops tegra_lcd_ops = {
-};
-
static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
.has_timer = true,
.has_rgb = true,
@@ -564,6 +664,9 @@ static const struct udevice_id tegra_lcd_ids[] = {
.compatible = "nvidia,tegra114-dc",
.data = (ulong)&tegra114_dc_soc_info
}, {
+ .compatible = "nvidia,tegra124-dc",
+ .data = (ulong)&tegra114_dc_soc_info
+ }, {
/* sentinel */
}
};
@@ -572,7 +675,6 @@ U_BOOT_DRIVER(tegra_lcd) = {
.name = "tegra_lcd",
.id = UCLASS_VIDEO,
.of_match = tegra_lcd_ids,
- .ops = &tegra_lcd_ops,
.bind = tegra_lcd_bind,
.probe = tegra_lcd_probe,
.of_to_plat = tegra_lcd_of_to_plat,
diff --git a/drivers/video/tegra20/tegra-dc.h b/drivers/video/tegra20/tegra-dc.h
index 7d0c189ec80..2a4013b3355 100644
--- a/drivers/video/tegra20/tegra-dc.h
+++ b/drivers/video/tegra20/tegra-dc.h
@@ -14,9 +14,6 @@
/* arch-tegra/dc exists only because T124 uses it */
#include <asm/arch-tegra/dc.h>
-#define TEGRA_DSI_A "dsi@54300000"
-#define TEGRA_DSI_B "dsi@54400000"
-
struct tegra_dc_plat {
struct udevice *dev; /* Display controller device */
struct dc_ctlr *dc; /* Display controller regmap */
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c
index 6327266dd22..a2a22fa0fe2 100644
--- a/drivers/video/tegra20/tegra-dsi.c
+++ b/drivers/video/tegra20/tegra-dsi.c
@@ -5,11 +5,13 @@
*/
#include <dm.h>
+#include <clk.h>
#include <log.h>
#include <misc.h>
#include <mipi_display.h>
#include <mipi_dsi.h>
#include <backlight.h>
+#include <video_bridge.h>
#include <panel.h>
#include <reset.h>
#include <linux/delay.h>
@@ -46,10 +48,13 @@ struct tegra_dsi_priv {
enum tegra_dsi_format format;
- int dsi_clk;
+ struct clk *clk;
+ struct clk *clk_parent;
+
int video_fifo_depth;
int host_fifo_depth;
+ u32 calibration_pads;
u32 version;
/* for ganged-mode support */
@@ -246,6 +251,9 @@ static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
+ if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
+ value |= DSI_HOST_CONTROL_HS;
+
/*
* The host FIFO has a maximum of 64 words, so larger transmissions
* need to use the video FIFO.
@@ -515,8 +523,9 @@ static void tegra_dsi_pad_calibrate(struct dsi_pad_ctrl_reg *pad)
writel(value, TEGRA_VI_BASE + (CSI_CIL_PAD_CONFIG << 2));
}
-static void tegra_dsi_mipi_calibrate(struct tegra_dsi_priv *priv)
+static void tegra_dsi_mipi_calibrate(struct udevice *dev)
{
+ struct tegra_dsi_priv *priv = dev_get_priv(dev);
struct dsi_pad_ctrl_reg *pad = &priv->dsi->pad;
u32 value;
int ret;
@@ -545,15 +554,20 @@ static void tegra_dsi_mipi_calibrate(struct tegra_dsi_priv *priv)
DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
writel(value, &pad->pad_ctrl_3);
- ret = misc_write(priv->mipi, 0, NULL, 0);
+ ret = misc_write(priv->mipi, priv->calibration_pads, NULL, 0);
if (ret)
log_debug("%s: MIPI calibration failed %d\n", __func__, ret);
+
+ if (priv->slave)
+ tegra_dsi_mipi_calibrate(priv->slave);
}
-static void tegra_dsi_set_timeout(struct dsi_timeout_reg *rtimeout,
+static void tegra_dsi_set_timeout(struct udevice *dev,
unsigned long bclk,
unsigned int vrefresh)
{
+ struct tegra_dsi_priv *priv = dev_get_priv(dev);
+ struct dsi_timeout_reg *rtimeout = &priv->dsi->timeout;
unsigned int timeout;
u32 value;
@@ -569,12 +583,17 @@ static void tegra_dsi_set_timeout(struct dsi_timeout_reg *rtimeout,
value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
writel(value, &rtimeout->dsi_to_tally);
+
+ if (priv->slave)
+ tegra_dsi_set_timeout(priv->slave, bclk, vrefresh);
}
-static void tegra_dsi_set_phy_timing(struct dsi_timing_reg *ptiming,
+static void tegra_dsi_set_phy_timing(struct udevice *dev,
unsigned long period,
const struct mipi_dphy_timing *dphy_timing)
{
+ struct tegra_dsi_priv *priv = dev_get_priv(dev);
+ struct dsi_timing_reg *ptiming = &priv->dsi->ptiming;
u32 value;
value = DSI_TIMING_FIELD(dphy_timing->hsexit, period, 1) << 24 |
@@ -598,6 +617,31 @@ static void tegra_dsi_set_phy_timing(struct dsi_timing_reg *ptiming,
DSI_TIMING_FIELD(dphy_timing->tasure, period, 1) << 8 |
DSI_TIMING_FIELD(dphy_timing->tago, period, 1);
writel(value, &ptiming->dsi_bta_timing);
+
+ if (priv->slave)
+ tegra_dsi_set_phy_timing(priv->slave, period, dphy_timing);
+}
+
+static u32 tegra_dsi_get_lanes(struct udevice *dev)
+{
+ struct tegra_dsi_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+
+ if (priv->master) {
+ struct tegra_dsi_priv *mpriv = dev_get_priv(priv->master);
+ struct mipi_dsi_device *mdevice = &mpriv->device;
+
+ return mdevice->lanes + device->lanes;
+ }
+
+ if (priv->slave) {
+ struct tegra_dsi_priv *spriv = dev_get_priv(priv->slave);
+ struct mipi_dsi_device *sdevice = &spriv->device;
+
+ return device->lanes + sdevice->lanes;
+ }
+
+ return device->lanes;
}
static void tegra_dsi_ganged_enable(struct udevice *dev, unsigned int start,
@@ -611,7 +655,7 @@ static void tegra_dsi_ganged_enable(struct udevice *dev, unsigned int start,
writel(DSI_GANGED_MODE_CONTROL_ENABLE, &ganged->ganged_mode_ctrl);
}
-static void tegra_dsi_configure(struct udevice *dev,
+static void tegra_dsi_configure(struct udevice *dev, unsigned int pipe,
unsigned long mode_flags)
{
struct tegra_dsi_priv *priv = dev_get_priv(dev);
@@ -642,7 +686,7 @@ static void tegra_dsi_configure(struct udevice *dev,
value = DSI_CONTROL_CHANNEL(0) |
DSI_CONTROL_FORMAT(priv->format) |
DSI_CONTROL_LANES(device->lanes - 1) |
- DSI_CONTROL_SOURCE(0);
+ DSI_CONTROL_SOURCE(pipe);
writel(value, &misc->dsi_ctrl);
writel(priv->video_fifo_depth, &misc->dsi_max_threshold);
@@ -680,12 +724,19 @@ static void tegra_dsi_configure(struct udevice *dev,
/* horizontal back porch */
hbp = timing->hback_porch.typ * mul / div;
- if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
- hbp += hsw;
-
/* horizontal front porch */
hfp = timing->hfront_porch.typ * mul / div;
+ if (priv->master || priv->slave) {
+ hact /= 2;
+ hsw /= 2;
+ hbp = hbp / 2 - 1;
+ hfp /= 2;
+ }
+
+ if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
+ hbp += hsw;
+
/* subtract packet overhead */
hsw -= 10;
hbp -= 14;
@@ -695,9 +746,6 @@ static void tegra_dsi_configure(struct udevice *dev,
writel(hact << 16 | hbp, &len->dsi_pkt_len_2_3);
writel(hfp, &len->dsi_pkt_len_4_5);
writel(0x0f0f << 16, &len->dsi_pkt_len_6_7);
-
- /* set SOL delay (for non-burst mode only) */
- writel(8 * mul / div, &misc->dsi_sol_delay);
} else {
if (priv->master || priv->slave) {
/*
@@ -717,32 +765,33 @@ static void tegra_dsi_configure(struct udevice *dev,
value = MIPI_DCS_WRITE_MEMORY_START << 8 |
MIPI_DCS_WRITE_MEMORY_CONTINUE;
writel(value, &len->dsi_dcs_cmds);
+ }
- /* set SOL delay */
- if (priv->master || priv->slave) {
- unsigned long delay, bclk, bclk_ganged;
- unsigned int lanes = device->lanes;
- unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ +
- timing->hback_porch.typ + timing->hsync_len.typ;
-
- /* SOL to valid, valid to FIFO and FIFO write delay */
- delay = 4 + 4 + 2;
- delay = DIV_ROUND_UP(delay * mul, div * lanes);
- /* FIFO read delay */
- delay = delay + 6;
-
- bclk = DIV_ROUND_UP(htotal * mul, div * lanes);
- bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
- value = bclk - bclk_ganged + delay + 20;
- } else {
- /* TODO: revisit for non-ganged mode */
- value = 8 * mul / div;
- }
-
- writel(value, &misc->dsi_sol_delay);
+ /* set SOL delay */
+ if (priv->master || priv->slave) {
+ unsigned long delay, bclk, bclk_ganged;
+ unsigned int lanes = tegra_dsi_get_lanes(dev);
+ unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ +
+ timing->hback_porch.typ + timing->hsync_len.typ;
+
+ /* SOL to valid, valid to FIFO and FIFO write delay */
+ delay = 4 + 4 + 2;
+ delay = DIV_ROUND_UP(delay * mul, div * lanes);
+ /* FIFO read delay */
+ delay = delay + 6;
+
+ bclk = DIV_ROUND_UP(htotal * mul, div * lanes);
+ bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
+ value = bclk - bclk_ganged + delay + 20;
+ } else {
+ /* set SOL delay (for non-burst mode only) */
+ value = 8 * mul / div;
}
+ writel(value, &misc->dsi_sol_delay);
+
if (priv->slave) {
+ tegra_dsi_configure(priv->slave, pipe, mode_flags);
/*
* TODO: Support modes other than symmetrical left-right
* split.
@@ -753,15 +802,31 @@ static void tegra_dsi_configure(struct udevice *dev,
}
}
+static void tegra_dsi_enable(struct udevice *dev)
+{
+ struct tegra_dsi_priv *priv = dev_get_priv(dev);
+ struct dsi_misc_reg *misc = &priv->dsi->misc;
+ u32 value;
+
+ /* enable DSI controller */
+ value = readl(&misc->dsi_pwr_ctrl);
+ value |= DSI_POWER_CONTROL_ENABLE;
+ writel(value, &misc->dsi_pwr_ctrl);
+
+ if (priv->slave)
+ tegra_dsi_enable(priv->slave);
+}
+
static int tegra_dsi_encoder_enable(struct udevice *dev)
{
struct tegra_dsi_priv *priv = dev_get_priv(dev);
+ struct tegra_dc_plat *dc_plat = dev_get_plat(dev);
struct mipi_dsi_device *device = &priv->device;
struct display_timing *timing = &priv->timing;
struct dsi_misc_reg *misc = &priv->dsi->misc;
unsigned int mul, div;
unsigned long bclk, plld, period;
- u32 value;
+ u32 value, lanes;
int ret;
/* If for some reasone DSI is enabled then it needs to
@@ -780,16 +845,17 @@ static int tegra_dsi_encoder_enable(struct udevice *dev)
writel(0, &misc->int_enable);
if (priv->version)
- tegra_dsi_mipi_calibrate(priv);
+ tegra_dsi_mipi_calibrate(dev);
else
tegra_dsi_pad_calibrate(&priv->dsi->pad);
tegra_dsi_get_muldiv(device->format, &mul, &div);
/* compute byte clock */
- bclk = (timing->pixelclock.typ * mul) / (div * device->lanes);
+ lanes = tegra_dsi_get_lanes(dev);
+ bclk = (timing->pixelclock.typ * mul) / (div * lanes);
- tegra_dsi_set_timeout(&priv->dsi->timeout, bclk, 60);
+ tegra_dsi_set_timeout(dev, bclk, 60);
/*
* Compute bit clock and round up to the next MHz.
@@ -813,25 +879,18 @@ static int tegra_dsi_encoder_enable(struct udevice *dev)
* The D-PHY timing fields are expressed in byte-clock cycles, so
* multiply the period by 8.
*/
- tegra_dsi_set_phy_timing(&priv->dsi->ptiming,
- period * 8, &priv->dphy_timing);
+ tegra_dsi_set_phy_timing(dev, period * 8, &priv->dphy_timing);
/* Perform panel HW setup */
ret = panel_enable_backlight(priv->panel);
if (ret)
return ret;
- tegra_dsi_configure(dev, device->mode_flags);
+ tegra_dsi_configure(dev, dc_plat->pipe, device->mode_flags);
tegra_dc_enable_controller(dev);
- /* enable DSI controller */
- value = readl(&misc->dsi_pwr_ctrl);
- value |= DSI_POWER_CONTROL_ENABLE;
- writel(value, &misc->dsi_pwr_ctrl);
-
- if (priv->slave)
- tegra_dsi_encoder_enable(priv->slave);
+ tegra_dsi_enable(dev);
return 0;
}
@@ -859,21 +918,35 @@ static void tegra_dsi_init_clocks(struct udevice *dev)
struct tegra_dsi_priv *priv = dev_get_priv(dev);
struct tegra_dc_plat *dc_plat = dev_get_plat(dev);
struct mipi_dsi_device *device = &priv->device;
- unsigned int mul, div;
+ unsigned int mul, div, lanes;
unsigned long bclk, plld;
- if (!priv->slave) {
+ /* Switch parents of DSI clocks in case of not standard parent */
+ if (priv->clk->id == PERIPH_ID_DSI &&
+ priv->clk_parent->id == CLOCK_ID_DISPLAY2) {
+ /* Change DSIA clock parent to PLLD2 */
+ struct clk_rst_ctlr *clkrst =
+ (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+ /* DSIA_CLK_SRC */
+ setbits_le32(&clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_base,
+ BIT(25));
+ }
+
+ if (priv->clk->id == PERIPH_ID_DSIB &&
+ priv->clk_parent->id == CLOCK_ID_DISPLAY) {
/* Change DSIB clock parent to match DSIA */
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
- clrbits_le32(&clkrst->plld2.pll_base, BIT(25)); /* DSIB_CLK_SRC */
+ /* DSIB_CLK_SRC */
+ clrbits_le32(&clkrst->plld2.pll_base, BIT(25));
}
tegra_dsi_get_muldiv(device->format, &mul, &div);
- bclk = (priv->timing.pixelclock.typ * mul) /
- (div * device->lanes);
+ lanes = tegra_dsi_get_lanes(dev);
+ bclk = (priv->timing.pixelclock.typ * mul) / (div * lanes);
plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC);
@@ -893,16 +966,16 @@ static void tegra_dsi_init_clocks(struct udevice *dev)
switch (clock_get_osc_freq()) {
case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
- clock_set_rate(CLOCK_ID_DISPLAY, plld, 12, 0, 8);
+ clock_set_rate(priv->clk_parent->id, plld, 12, 0, 8);
break;
case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
- clock_set_rate(CLOCK_ID_DISPLAY, plld, 26, 0, 8);
+ clock_set_rate(priv->clk_parent->id, plld, 26, 0, 8);
break;
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
- clock_set_rate(CLOCK_ID_DISPLAY, plld, 13, 0, 8);
+ clock_set_rate(priv->clk_parent->id, plld, 13, 0, 8);
break;
case CLOCK_OSC_FREQ_19_2:
@@ -914,11 +987,7 @@ static void tegra_dsi_init_clocks(struct udevice *dev)
break;
}
- priv->dsi_clk = clock_decode_periph_id(dev);
-
- clock_enable(priv->dsi_clk);
- udelay(2);
- reset_set_enable(priv->dsi_clk, 0);
+ clk_enable(priv->clk);
}
static int tegra_dsi_ganged_probe(struct udevice *dev)
@@ -926,7 +995,7 @@ static int tegra_dsi_ganged_probe(struct udevice *dev)
struct tegra_dsi_priv *mpriv = dev_get_priv(dev);
struct udevice *gangster;
- uclass_get_device_by_phandle(UCLASS_PANEL, dev,
+ uclass_get_device_by_phandle(UCLASS_VIDEO_BRIDGE, dev,
"nvidia,ganged-mode", &gangster);
if (gangster) {
/* Ganged mode is set */
@@ -955,6 +1024,20 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
return -EINVAL;
}
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ log_debug("%s: Could not get DSI clock: %ld\n",
+ __func__, PTR_ERR(priv->clk));
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->clk_parent = devm_clk_get(dev, "parent");
+ if (IS_ERR(priv->clk_parent)) {
+ log_debug("%s: Could not get DSI clock parent: %ld\n",
+ __func__, PTR_ERR(priv->clk_parent));
+ return PTR_ERR(priv->clk_parent);
+ }
+
priv->video_fifo_depth = 1920;
priv->host_fifo_depth = 64;
@@ -973,10 +1056,22 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
debug("%s: Cannot get avdd-dsi-csi-supply: error %d\n",
__func__, ret);
- ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
- "panel", &priv->panel);
+ /* Check all DSI children */
+ device_foreach_child(priv->panel, dev) {
+ if (device_get_uclass_id(priv->panel) == UCLASS_PANEL)
+ break;
+ }
+
+ /* if loop exits without panel device return error */
+ if (device_get_uclass_id(priv->panel) != UCLASS_PANEL) {
+ log_debug("%s: panel not found, ret %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = uclass_get_device_by_ofnode(UCLASS_PANEL, dev_ofnode(priv->panel),
+ &priv->panel);
if (ret) {
- printf("%s: Cannot get panel: error %d\n", __func__, ret);
+ log_debug("%s: Cannot get panel: error %d\n", __func__, ret);
return log_ret(ret);
}
@@ -988,6 +1083,14 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
log_debug("%s: cannot get MIPI: error %d\n", __func__, ret);
return ret;
}
+
+ ret = dev_read_u32_index(dev, "nvidia,mipi-calibrate", 1,
+ &priv->calibration_pads);
+ if (ret) {
+ log_debug("%s: cannot get calibration pads: error %d\n",
+ __func__, ret);
+ return ret;
+ }
}
panel_get_display_timing(priv->panel, &priv->timing);
@@ -1019,8 +1122,8 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
return 0;
}
-static const struct panel_ops tegra_dsi_bridge_ops = {
- .enable_backlight = tegra_dsi_encoder_enable,
+static const struct video_bridge_ops tegra_dsi_bridge_ops = {
+ .attach = tegra_dsi_encoder_enable,
.set_backlight = tegra_dsi_bridge_set_panel,
.get_display_timing = tegra_dsi_panel_timings,
};
@@ -1028,14 +1131,16 @@ static const struct panel_ops tegra_dsi_bridge_ops = {
static const struct udevice_id tegra_dsi_bridge_ids[] = {
{ .compatible = "nvidia,tegra30-dsi", .data = DSI_V0 },
{ .compatible = "nvidia,tegra114-dsi", .data = DSI_V1 },
+ { .compatible = "nvidia,tegra124-dsi", .data = DSI_V1 },
{ }
};
U_BOOT_DRIVER(tegra_dsi) = {
.name = "tegra_dsi",
- .id = UCLASS_PANEL,
+ .id = UCLASS_VIDEO_BRIDGE,
.of_match = tegra_dsi_bridge_ids,
.ops = &tegra_dsi_bridge_ops,
+ .bind = dm_scan_fdt_dev,
.probe = tegra_dsi_bridge_probe,
.plat_auto = sizeof(struct tegra_dc_plat),
.priv_auto = sizeof(struct tegra_dsi_priv),
diff --git a/drivers/video/tegra20/tegra-hdmi.c b/drivers/video/tegra20/tegra-hdmi.c
new file mode 100644
index 00000000000..bda69919d92
--- /dev/null
+++ b/drivers/video/tegra20/tegra-hdmi.c
@@ -0,0 +1,623 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ * Copyright (c) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <edid.h>
+#include <i2c.h>
+#include <log.h>
+#include <misc.h>
+#include <panel.h>
+#include <reset.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <power/regulator.h>
+#include <video_bridge.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+
+#include "tegra-dc.h"
+#include "tegra-hdmi.h"
+
+#define DDCCI_ENTRY_ADDR 0x37
+#define DDCCI_SOURSE_ADDR 0x51
+#define DDCCI_COMMAND_WRITE 0x03
+#define DDCCI_CTRL_BRIGHTNESS 0x10
+
+#define HDMI_EDID_I2C_ADDR 0x50
+#define HDMI_REKEY_DEFAULT 56
+
+static const char * const hdmi_supplies[] = {
+ "hdmi-supply", "pll-supply", "vdd-supply"
+};
+
+struct tmds_config {
+ unsigned int pclk;
+ u32 pll0;
+ u32 pll1;
+ u32 pe_current;
+ u32 drive_current;
+ u32 peak_current;
+};
+
+struct tegra_hdmi_config {
+ const struct tmds_config *tmds;
+ unsigned int num_tmds;
+ unsigned int max_pclk;
+
+ /* to be filled */
+};
+
+struct tegra_hdmi_priv {
+ struct hdmi_ctlr *hdmi_regmap;
+
+ struct udevice *supplies[ARRAY_SIZE(hdmi_supplies)];
+ struct udevice *hdmi_ddc;
+
+ struct gpio_desc hpd; /* hotplug detection gpio */
+ struct display_timing timing;
+
+ struct clk *clk;
+ struct clk *clk_parent;
+
+ int panel_bits_per_colourp;
+ const struct tegra_hdmi_config *config;
+};
+
+/* 1280x720p 60hz: EIA/CEA-861-B Format 4 */
+static struct display_timing default_720p_timing = {
+ .pixelclock.typ = 74250000,
+ .hactive.typ = 1280,
+ .hfront_porch.typ = 110,
+ .hback_porch.typ = 220,
+ .hsync_len.typ = 40,
+ .vactive.typ = 720,
+ .vfront_porch.typ = 5,
+ .vback_porch.typ = 20,
+ .vsync_len.typ = 5,
+ .flags = DISPLAY_FLAGS_HSYNC_HIGH |
+ DISPLAY_FLAGS_VSYNC_HIGH,
+};
+
+static const struct tmds_config tegra20_tmds_config[] = {
+ { /* slow pixel clock modes */
+ .pclk = 27000000,
+ .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
+ SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) |
+ SOR_PLL_TX_REG_LOAD(3),
+ .pll1 = SOR_PLL_TMDS_TERM_ENABLE,
+ .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) |
+ PE_CURRENT1(PE_CURRENT_0_0_mA) |
+ PE_CURRENT2(PE_CURRENT_0_0_mA) |
+ PE_CURRENT3(PE_CURRENT_0_0_mA),
+ .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) |
+ DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
+ DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
+ DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
+ },
+ { /* high pixel clock modes */
+ .pclk = UINT_MAX,
+ .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
+ SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) |
+ SOR_PLL_TX_REG_LOAD(3),
+ .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
+ .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) |
+ PE_CURRENT1(PE_CURRENT_6_0_mA) |
+ PE_CURRENT2(PE_CURRENT_6_0_mA) |
+ PE_CURRENT3(PE_CURRENT_6_0_mA),
+ .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) |
+ DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
+ DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
+ DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
+ },
+};
+
+static const struct tmds_config tegra30_tmds_config[] = {
+ { /* 480p modes */
+ .pclk = 27000000,
+ .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
+ SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) |
+ SOR_PLL_TX_REG_LOAD(0),
+ .pll1 = SOR_PLL_TMDS_TERM_ENABLE,
+ .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) |
+ PE_CURRENT1(PE_CURRENT_0_0_mA) |
+ PE_CURRENT2(PE_CURRENT_0_0_mA) |
+ PE_CURRENT3(PE_CURRENT_0_0_mA),
+ .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA),
+ }, { /* 720p modes */
+ .pclk = 74250000,
+ .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
+ SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) |
+ SOR_PLL_TX_REG_LOAD(0),
+ .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
+ .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) |
+ PE_CURRENT1(PE_CURRENT_5_0_mA) |
+ PE_CURRENT2(PE_CURRENT_5_0_mA) |
+ PE_CURRENT3(PE_CURRENT_5_0_mA),
+ .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA),
+ }, { /* 1080p modes */
+ .pclk = UINT_MAX,
+ .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
+ SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(3) |
+ SOR_PLL_TX_REG_LOAD(0),
+ .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
+ .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) |
+ PE_CURRENT1(PE_CURRENT_5_0_mA) |
+ PE_CURRENT2(PE_CURRENT_5_0_mA) |
+ PE_CURRENT3(PE_CURRENT_5_0_mA),
+ .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) |
+ DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA),
+ },
+};
+
+static void tegra_dc_enable_controller(struct udevice *dev)
+{
+ struct tegra_dc_plat *dc_plat = dev_get_plat(dev);
+ struct dc_ctlr *dc = dc_plat->dc;
+ u32 value;
+
+ value = readl(&dc->disp.disp_win_opt);
+ value |= HDMI_ENABLE;
+ writel(value, &dc->disp.disp_win_opt);
+
+ writel(GENERAL_UPDATE, &dc->cmd.state_ctrl);
+ writel(GENERAL_ACT_REQ, &dc->cmd.state_ctrl);
+}
+
+static void tegra_hdmi_setup_tmds(struct tegra_hdmi_priv *priv,
+ const struct tmds_config *tmds)
+{
+ struct hdmi_ctlr *hdmi = priv->hdmi_regmap;
+ u32 value;
+
+ writel(tmds->pll0, &hdmi->nv_pdisp_sor_pll0);
+ writel(tmds->pll1, &hdmi->nv_pdisp_sor_pll1);
+ writel(tmds->pe_current, &hdmi->nv_pdisp_pe_current);
+
+ writel(tmds->drive_current, &hdmi->nv_pdisp_sor_lane_drive_current);
+
+ value = readl(&hdmi->nv_pdisp_sor_lane_drive_current);
+ value |= BIT(31);
+ writel(value, &hdmi->nv_pdisp_sor_lane_drive_current);
+}
+
+static int tegra_hdmi_encoder_enable(struct udevice *dev)
+{
+ struct tegra_dc_plat *dc_plat = dev_get_plat(dev);
+ struct tegra_hdmi_priv *priv = dev_get_priv(dev);
+ struct dc_ctlr *dc = dc_plat->dc;
+ struct display_timing *dt = &priv->timing;
+ struct hdmi_ctlr *hdmi = priv->hdmi_regmap;
+ unsigned long rate, div82;
+ unsigned int pulse_start, rekey;
+ int retries = 1000;
+ u32 value;
+ int i;
+
+ /* power up sequence */
+ value = readl(&hdmi->nv_pdisp_sor_pll0);
+ value &= ~SOR_PLL_PDBG;
+ writel(value, &hdmi->nv_pdisp_sor_pll0);
+
+ udelay(20);
+
+ value = readl(&hdmi->nv_pdisp_sor_pll0);
+ value &= ~SOR_PLL_PWR;
+ writel(value, &hdmi->nv_pdisp_sor_pll0);
+
+ writel(VSYNC_H_POSITION(1), &dc->disp.disp_timing_opt);
+ writel(DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE_888,
+ &dc->disp.disp_color_ctrl);
+
+ /* video_preamble uses h_pulse2 */
+ pulse_start = 1 + dt->hsync_len.typ + dt->hback_porch.typ - 10;
+
+ writel(H_PULSE2_ENABLE, &dc->disp.disp_signal_opt0);
+
+ value = PULSE_MODE_NORMAL | PULSE_POLARITY_HIGH |
+ PULSE_QUAL_VACTIVE | PULSE_LAST_END_A;
+ writel(value, &dc->disp.h_pulse[H_PULSE2].h_pulse_ctrl);
+
+ value = PULSE_START(pulse_start) | PULSE_END(pulse_start + 8);
+ writel(value, &dc->disp.h_pulse[H_PULSE2].h_pulse_pos[H_PULSE0_POSITION_A]);
+
+ value = VSYNC_WINDOW_END(0x210) | VSYNC_WINDOW_START(0x200) |
+ VSYNC_WINDOW_ENABLE;
+ writel(value, &hdmi->nv_pdisp_hdmi_vsync_window);
+
+ if (dc_plat->pipe)
+ value = HDMI_SRC_DISPLAYB;
+ else
+ value = HDMI_SRC_DISPLAYA;
+
+ if (dt->hactive.typ == 720 && (dt->vactive.typ == 480 ||
+ dt->vactive.typ == 576))
+ writel(value | ARM_VIDEO_RANGE_FULL,
+ &hdmi->nv_pdisp_input_control);
+ else
+ writel(value | ARM_VIDEO_RANGE_LIMITED,
+ &hdmi->nv_pdisp_input_control);
+
+ rate = clock_get_periph_rate(priv->clk->id, priv->clk_parent->id);
+ div82 = rate / USEC_PER_SEC * 4;
+ value = SOR_REFCLK_DIV_INT(div82 >> 2) | SOR_REFCLK_DIV_FRAC(div82);
+ writel(value, &hdmi->nv_pdisp_sor_refclk);
+
+ rekey = HDMI_REKEY_DEFAULT;
+ value = HDMI_CTRL_REKEY(rekey);
+ value |= HDMI_CTRL_MAX_AC_PACKET((dt->hsync_len.typ + dt->hback_porch.typ +
+ dt->hfront_porch.typ - rekey - 18) / 32);
+ writel(value, &hdmi->nv_pdisp_hdmi_ctrl);
+
+ /* TMDS CONFIG */
+ for (i = 0; i < priv->config->num_tmds; i++) {
+ if (dt->pixelclock.typ <= priv->config->tmds[i].pclk) {
+ tegra_hdmi_setup_tmds(priv, &priv->config->tmds[i]);
+ break;
+ }
+ }
+
+ writel(SOR_SEQ_PU_PC(0) | SOR_SEQ_PU_PC_ALT(0) | SOR_SEQ_PD_PC(8) |
+ SOR_SEQ_PD_PC_ALT(8), &hdmi->nv_pdisp_sor_seq_ctl);
+
+ value = SOR_SEQ_INST_WAIT_TIME(1) | SOR_SEQ_INST_WAIT_UNITS_VSYNC |
+ SOR_SEQ_INST_HALT | SOR_SEQ_INST_PIN_A_LOW |
+ SOR_SEQ_INST_PIN_B_LOW | SOR_SEQ_INST_DRIVE_PWM_OUT_LO;
+
+ writel(value, &hdmi->nv_pdisp_sor_seq_inst0);
+ writel(value, &hdmi->nv_pdisp_sor_seq_inst8);
+
+ value = readl(&hdmi->nv_pdisp_sor_cstm);
+
+ value &= ~SOR_CSTM_ROTCLK(~0);
+ value |= SOR_CSTM_ROTCLK(2);
+ value |= SOR_CSTM_PLLDIV;
+ value &= ~SOR_CSTM_LVDS_ENABLE;
+ value &= ~SOR_CSTM_MODE_MASK;
+ value |= SOR_CSTM_MODE_TMDS;
+
+ writel(value, &hdmi->nv_pdisp_sor_cstm);
+
+ /* start SOR */
+ writel(SOR_PWR_NORMAL_STATE_PU | SOR_PWR_NORMAL_START_NORMAL |
+ SOR_PWR_SAFE_STATE_PD | SOR_PWR_SETTING_NEW_TRIGGER,
+ &hdmi->nv_pdisp_sor_pwr);
+ writel(SOR_PWR_NORMAL_STATE_PU | SOR_PWR_NORMAL_START_NORMAL |
+ SOR_PWR_SAFE_STATE_PD | SOR_PWR_SETTING_NEW_DONE,
+ &hdmi->nv_pdisp_sor_pwr);
+
+ do {
+ if (--retries < 0)
+ return -ETIME;
+ value = readl(&hdmi->nv_pdisp_sor_pwr);
+ } while (value & SOR_PWR_SETTING_NEW_PENDING);
+
+ value = SOR_STATE_ASY_CRCMODE_COMPLETE |
+ SOR_STATE_ASY_OWNER_HEAD0 |
+ SOR_STATE_ASY_SUBOWNER_BOTH |
+ SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A |
+ SOR_STATE_ASY_DEPOL_POS;
+
+ /* setup sync polarities */
+ if (dt->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ value |= SOR_STATE_ASY_HSYNCPOL_POS;
+
+ if (dt->flags & DISPLAY_FLAGS_HSYNC_LOW)
+ value |= SOR_STATE_ASY_HSYNCPOL_NEG;
+
+ if (dt->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ value |= SOR_STATE_ASY_VSYNCPOL_POS;
+
+ if (dt->flags & DISPLAY_FLAGS_VSYNC_LOW)
+ value |= SOR_STATE_ASY_VSYNCPOL_NEG;
+
+ writel(value, &hdmi->nv_pdisp_sor_state2);
+
+ value = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL;
+ writel(value, &hdmi->nv_pdisp_sor_state1);
+
+ writel(0, &hdmi->nv_pdisp_sor_state0);
+ writel(SOR_STATE_UPDATE, &hdmi->nv_pdisp_sor_state0);
+ writel(value | SOR_STATE_ATTACHED,
+ &hdmi->nv_pdisp_sor_state1);
+ writel(0, &hdmi->nv_pdisp_sor_state0);
+
+ tegra_dc_enable_controller(dev);
+
+ return 0;
+}
+
+/* DDC/CI backlight control */
+static int tegra_hdmi_set_connector(struct udevice *dev, int percent)
+{
+ struct tegra_hdmi_priv *priv = dev_get_priv(dev);
+ struct udevice *ddc_entry;
+ struct i2c_msg msg[1];
+ u8 checksum = DDCCI_ENTRY_ADDR << 1;
+ int i, ret;
+
+ ret = dm_i2c_probe(priv->hdmi_ddc, DDCCI_ENTRY_ADDR, 0, &ddc_entry);
+ if (ret) {
+ log_debug("%s: cannot probe DDC/CI entry: error %d\n",
+ __func__, ret);
+ return 0;
+ }
+
+ /*
+ * payload[1] is length: hithest bit OR last 4 bits indicate
+ * the number of following bytes (excluding checksum)
+ */
+ u8 payload[7] = { DDCCI_SOURSE_ADDR, BIT(7) | (sizeof(payload) - 3),
+ DDCCI_COMMAND_WRITE, DDCCI_CTRL_BRIGHTNESS,
+ (u8)(percent & 0xff), (u8)(percent & 0xff), 0 };
+
+ /* DDC/CI checksum is a simple XOR of all preceding bytes */
+ for (i = 0; i < (sizeof(payload) - 1); i++)
+ checksum ^= payload[i];
+
+ payload[6] = checksum;
+
+ msg->addr = DDCCI_ENTRY_ADDR;
+ msg->flags = 0;
+ msg->len = sizeof(payload);
+ msg->buf = payload;
+
+ dm_i2c_xfer(ddc_entry, msg, 1);
+
+ return 0;
+}
+
+static int tegra_hdmi_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ struct tegra_hdmi_priv *priv = dev_get_priv(dev);
+
+ memcpy(timing, &priv->timing, sizeof(*timing));
+
+ return 0;
+}
+
+static void tegra_hdmi_init_clocks(struct udevice *dev)
+{
+ struct tegra_hdmi_priv *priv = dev_get_priv(dev);
+ u32 n = priv->timing.pixelclock.typ * 2 / USEC_PER_SEC;
+
+ switch (clock_get_osc_freq()) {
+ case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+ case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
+ clock_set_rate(priv->clk_parent->id, n, 12, 0, 8);
+ break;
+
+ case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
+ clock_set_rate(priv->clk_parent->id, n, 26, 0, 8);
+ break;
+
+ case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+ case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
+ clock_set_rate(priv->clk_parent->id, n, 13, 0, 8);
+ break;
+
+ case CLOCK_OSC_FREQ_19_2:
+ case CLOCK_OSC_FREQ_38_4:
+ default:
+ /*
+ * These are not supported.
+ */
+ break;
+ }
+
+ clock_start_periph_pll(priv->clk->id, priv->clk_parent->id,
+ priv->timing.pixelclock.typ);
+}
+
+static bool tegra_hdmi_mode_valid(void *hdmi_priv, const struct display_timing *timing)
+{
+ struct tegra_hdmi_priv *priv = hdmi_priv;
+
+ if (timing->pixelclock.typ > priv->config->max_pclk)
+ return false;
+
+ return true;
+}
+
+static int tegra_hdmi_decode_edid(struct udevice *dev)
+{
+ struct tegra_hdmi_priv *priv = dev_get_priv(dev);
+ struct udevice *hdmi_edid;
+ uchar edid_buf[EDID_SIZE] = { 0 };
+ int i, ret;
+
+ /* Poll for 1 sec in case EDID is not ready right after hpd */
+ for (i = 0; i < 10; i++) {
+ ret = dm_i2c_probe(priv->hdmi_ddc, HDMI_EDID_I2C_ADDR, 0,
+ &hdmi_edid);
+ if (!ret)
+ break;
+
+ mdelay(100);
+ }
+ if (ret) {
+ log_debug("%s: cannot probe EDID: error %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = dm_i2c_read(hdmi_edid, 0, edid_buf, sizeof(edid_buf));
+ if (ret) {
+ log_debug("%s: cannot dump EDID buffer: error %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = edid_get_timing_validate(edid_buf, sizeof(edid_buf), &priv->timing,
+ &priv->panel_bits_per_colourp,
+ tegra_hdmi_mode_valid, priv);
+ if (ret) {
+ log_debug("%s: cannot decode EDID info: error %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra_hdmi_wait_hpd(struct tegra_hdmi_priv *priv)
+{
+ int i;
+
+ /* Poll 1 second for HPD signal */
+ for (i = 0; i < 10; i++) {
+ if (dm_gpio_get_value(&priv->hpd))
+ return 0;
+
+ mdelay(100);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int tegra_hdmi_probe(struct udevice *dev)
+{
+ struct tegra_hdmi_priv *priv = dev_get_priv(dev);
+ struct reset_ctl reset_ctl;
+ int i, ret;
+
+ priv->hdmi_regmap = (struct hdmi_ctlr *)dev_read_addr_ptr(dev);
+ if (!priv->hdmi_regmap) {
+ log_debug("%s: no display controller address\n", __func__);
+ return -EINVAL;
+ }
+
+ priv->config = (struct tegra_hdmi_config *)dev_get_driver_data(dev);
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ log_debug("%s: Could not get HDMI clock: %ld\n",
+ __func__, PTR_ERR(priv->clk));
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->clk_parent = devm_clk_get(dev, "parent");
+ if (IS_ERR(priv->clk_parent)) {
+ log_debug("%s: Could not get HDMI clock parent: %ld\n",
+ __func__, PTR_ERR(priv->clk_parent));
+ return PTR_ERR(priv->clk_parent);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hdmi_supplies); i++) {
+ ret = device_get_supply_regulator(dev, hdmi_supplies[i],
+ &priv->supplies[i]);
+ if (ret) {
+ log_debug("%s: cannot get %s %d\n", __func__,
+ hdmi_supplies[i], ret);
+ if (ret != -ENOENT)
+ return log_ret(ret);
+ }
+
+ ret = regulator_set_enable_if_allowed(priv->supplies[i], true);
+ if (ret && ret != -ENOSYS) {
+ log_debug("%s: cannot enable %s: error %d\n",
+ __func__, hdmi_supplies[i], ret);
+ return ret;
+ }
+ }
+
+ ret = reset_get_by_name(dev, "hdmi", &reset_ctl);
+ if (ret) {
+ log_debug("%s: reset_get_by_name() failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_I2C, dev,
+ "nvidia,ddc-i2c-bus",
+ &priv->hdmi_ddc);
+ if (ret) {
+ log_debug("%s: cannot get hdmi ddc i2c bus: error %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "nvidia,hpd-gpio", 0,
+ &priv->hpd, GPIOD_IS_IN);
+ if (ret) {
+ log_debug("%s: Could not decode hpd-gpios (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* wait for connector */
+ ret = tegra_hdmi_wait_hpd(priv);
+ if (ret) {
+ /* HPD failed, use default timings */
+ memcpy(&priv->timing, &default_720p_timing,
+ sizeof(default_720p_timing));
+ } else {
+ ret = tegra_hdmi_decode_edid(dev);
+ if (ret)
+ memcpy(&priv->timing, &default_720p_timing,
+ sizeof(default_720p_timing));
+ }
+
+ reset_assert(&reset_ctl);
+ tegra_hdmi_init_clocks(dev);
+
+ mdelay(2);
+ reset_deassert(&reset_ctl);
+
+ return 0;
+}
+
+static const struct tegra_hdmi_config tegra20_hdmi_config = {
+ .tmds = tegra20_tmds_config,
+ .num_tmds = ARRAY_SIZE(tegra20_tmds_config),
+ .max_pclk = 148500000, /* 1080p */
+};
+
+static const struct tegra_hdmi_config tegra30_hdmi_config = {
+ .tmds = tegra30_tmds_config,
+ .num_tmds = ARRAY_SIZE(tegra30_tmds_config),
+ .max_pclk = 148500000, /* 1080p */
+};
+
+static const struct video_bridge_ops tegra_hdmi_ops = {
+ .attach = tegra_hdmi_encoder_enable,
+ .set_backlight = tegra_hdmi_set_connector,
+ .get_display_timing = tegra_hdmi_timings,
+};
+
+static const struct udevice_id tegra_hdmi_ids[] = {
+ {
+ .compatible = "nvidia,tegra20-hdmi",
+ .data = (ulong)&tegra20_hdmi_config
+ }, {
+ .compatible = "nvidia,tegra30-hdmi",
+ .data = (ulong)&tegra30_hdmi_config
+ }, {
+ /* sentinel */
+ }
+};
+
+U_BOOT_DRIVER(tegra_hdmi) = {
+ .name = "tegra_hdmi",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = tegra_hdmi_ids,
+ .ops = &tegra_hdmi_ops,
+ .probe = tegra_hdmi_probe,
+ .plat_auto = sizeof(struct tegra_dc_plat),
+ .priv_auto = sizeof(struct tegra_hdmi_priv),
+};
diff --git a/drivers/video/tegra20/tegra-hdmi.h b/drivers/video/tegra20/tegra-hdmi.h
new file mode 100644
index 00000000000..d17655973e3
--- /dev/null
+++ b/drivers/video/tegra20/tegra-hdmi.h
@@ -0,0 +1,648 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2010
+ * NVIDIA Corporation <www.nvidia.com>
+ */
+
+#ifndef _TEGRA_HDMI_H
+#define _TEGRA_HDMI_H
+
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#endif
+
+/* Register definitions for the Tegra high-definition multimedia interface */
+
+/* High-Definition Multimedia Interface (HDMI_) regs */
+struct hdmi_ctlr {
+ /* Address 0x000 ~ 0x0d2 */
+ uint ctxsw; /* _CTXSW */ /* 0x00 */
+
+ uint nv_pdisp_sor_state0; /* _NV_PDISP_SOR_STATE0 */
+ uint nv_pdisp_sor_state1; /* _NV_PDISP_SOR_STATE1 */
+ uint nv_pdisp_sor_state2; /* _NV_PDISP_SOR_STATE2 */
+
+ uint nv_pdisp_rg_hdcp_an_msb; /* _NV_PDISP_RG_HDCP_AN_MSB */
+ uint nv_pdisp_rg_hdcp_an_lsb; /* _NV_PDISP_RG_HDCP_AN_LSB */
+ uint nv_pdisp_rg_hdcp_cn_msb; /* _NV_PDISP_RG_HDCP_CN_MSB */
+ uint nv_pdisp_rg_hdcp_cn_lsb; /* _NV_PDISP_RG_HDCP_CN_LSB */
+ uint nv_pdisp_rg_hdcp_aksv_msb; /* _NV_PDISP_RG_HDCP_AKSV_MSB */
+ uint nv_pdisp_rg_hdcp_aksv_lsb; /* _NV_PDISP_RG_HDCP_AKSV_LSB */
+ uint nv_pdisp_rg_hdcp_bksv_msb; /* _NV_PDISP_RG_HDCP_BKSV_MSB */
+ uint nv_pdisp_rg_hdcp_bksv_lsb; /* _NV_PDISP_RG_HDCP_BKSV_LSB */
+ uint nv_pdisp_rg_hdcp_cksv_msb; /* _NV_PDISP_RG_HDCP_CKSV_MSB */
+ uint nv_pdisp_rg_hdcp_cksv_lsb; /* _NV_PDISP_RG_HDCP_CKSV_LSB */
+ uint nv_pdisp_rg_hdcp_dksv_msb; /* _NV_PDISP_RG_HDCP_DKSV_MSB */
+ uint nv_pdisp_rg_hdcp_dksv_lsb; /* _NV_PDISP_RG_HDCP_DKSV_LSB */
+ uint nv_pdisp_rg_hdcp_ctrl; /* _NV_PDISP_RG_HDCP_CTRL */ /* 0x10 */
+ uint nv_pdisp_rg_hdcp_cmode; /* _NV_PDISP_RG_HDCP_CMODE */
+ uint nv_pdisp_rg_hdcp_mprime_msb; /* _NV_PDISP_RG_HDCP_MPRIME_MSB */
+ uint nv_pdisp_rg_hdcp_mprime_lsb; /* _NV_PDISP_RG_HDCP_MPRIME_LSB */
+ uint nv_pdisp_rg_hdcp_sprime_msb; /* _NV_PDISP_RG_HDCP_SPRIME_MSB */
+ uint nv_pdisp_rg_hdcp_sprime_lsb2; /* _NV_PDISP_RG_HDCP_SPRIME_LSB2 */
+ uint nv_pdisp_rg_hdcp_sprime_lsb1; /* _NV_PDISP_RG_HDCP_SPRIME_LSB1 */
+ uint nv_pdisp_rg_hdcp_ri; /* _NV_PDISP_RG_HDCP_RI */
+ uint nv_pdisp_rg_hdcp_cs_msb; /* _NV_PDISP_RG_HDCP_CS_MSB */
+ uint nv_pdisp_rg_hdcp_cs_lsb; /* _NV_PDISP_RG_HDCP_CS_LSB */
+
+ uint nv_pdisp_hdmi_audio_emu0; /* _NV_PDISP_HDMI_AUDIO_EMU0 */
+ uint nv_pdisp_hdmi_audio_emu_rdata0; /* _NV_PDISP_HDMI_AUDIO_EMU_RDATA0 */
+ uint nv_pdisp_hdmi_audio_emu1; /* _NV_PDISP_HDMI_AUDIO_EMU1 */
+ uint nv_pdisp_hdmi_audio_emu2; /* _NV_PDISP_HDMI_AUDIO_EMU2 */
+ uint nv_pdisp_hdmi_audio_infoframe_ctrl; /* _NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL */
+ uint nv_pdisp_hdmi_audio_infoframe_status; /* _NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS */
+ uint nv_pdisp_hdmi_audio_infoframe_header; /* _NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER */ /* 0x20 */
+ uint nv_pdisp_hdmi_audio_infoframe_subpack0_low; /* _NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW */
+ uint nv_pdisp_hdmi_audio_infoframe_subpack0_high; /* _NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH */
+
+ uint nv_pdisp_hdmi_avi_infoframe_ctrl; /* _NV_PDISP_HDMI_AVI_INFOFRAME_CTRL */
+ uint nv_pdisp_hdmi_avi_infoframe_status; /* _NV_PDISP_HDMI_AVI_INFOFRAME_STATUS */
+ uint nv_pdisp_hdmi_avi_infoframe_header; /* _NV_PDISP_HDMI_AVI_INFOFRAME_HEADER */
+ uint nv_pdisp_hdmi_avi_infoframe_subpack0_low; /* _NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW */
+ uint nv_pdisp_hdmi_avi_infoframe_subpack0_high; /* _NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH */
+ uint nv_pdisp_hdmi_avi_infoframe_subpack1_low; /* _NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW */
+ uint nv_pdisp_hdmi_avi_infoframe_subpack1_high; /* _NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH */
+
+ uint nv_pdisp_hdmi_generic_ctrl; /* _NV_PDISP_HDMI_GENERIC_CTRL */
+ uint nv_pdisp_hdmi_generic_status; /* _NV_PDISP_HDMI_GENERIC_STATUS */
+ uint nv_pdisp_hdmi_generic_header; /* _NV_PDISP_HDMI_GENERIC_HEADER */
+ uint nv_pdisp_hdmi_generic_subpack0_low; /* _NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW */
+ uint nv_pdisp_hdmi_generic_subpack0_high; /* _NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH */
+ uint nv_pdisp_hdmi_generic_subpack1_low; /* _NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW */
+ uint nv_pdisp_hdmi_generic_subpack1_high; /* _NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH */
+ uint nv_pdisp_hdmi_generic_subpack2_low; /* _NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW */
+ uint nv_pdisp_hdmi_generic_subpack2_high; /* _NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH */
+ uint nv_pdisp_hdmi_generic_subpack3_low; /* _NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW */
+ uint nv_pdisp_hdmi_generic_subpack3_high; /* _NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH */
+
+ uint nv_pdisp_hdmi_acr_ctrl; /* _NV_PDISP_HDMI_ACR_CTRL */
+ uint nv_pdisp_hdmi_acr_0320_subpack_low; /* _NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_0320_subpack_high; /* _NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH */
+ uint nv_pdisp_hdmi_acr_0441_subpack_low; /* _NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_0441_subpack_high; /* _NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH */
+ uint nv_pdisp_hdmi_acr_0882_subpack_low; /* _NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_0882_subpack_high; /* _NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH */
+ uint nv_pdisp_hdmi_acr_1764_subpack_low; /* _NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_1764_subpack_high; /* _NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH */
+ uint nv_pdisp_hdmi_acr_0480_subpack_low; /* _NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_0480_subpack_high; /* _NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH */
+ uint nv_pdisp_hdmi_acr_0960_subpack_low; /* _NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_0960_subpack_high; /* _NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH */
+ uint nv_pdisp_hdmi_acr_1920_subpack_low; /* _NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW */
+ uint nv_pdisp_hdmi_acr_1920_subpack_high; /* _NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH */
+
+ uint nv_pdisp_hdmi_ctrl; /* _NV_PDISP_HDMI_CTRL */
+ uint nv_pdisp_hdmi_vsync_keepout; /* _NV_PDISP_HDMI_VSYNC_KEEPOUT */
+ uint nv_pdisp_hdmi_vsync_window; /* _NV_PDISP_HDMI_VSYNC_WINDOW */
+ uint nv_pdisp_hdmi_gcp_ctrl; /* _NV_PDISP_HDMI_GCP_CTRL */
+ uint nv_pdisp_hdmi_gcp_status; /* _NV_PDISP_HDMI_GCP_STATUS */
+ uint nv_pdisp_hdmi_gcp_subpack; /* _NV_PDISP_HDMI_GCP_SUBPACK */
+ uint nv_pdisp_hdmi_channel_status1; /* _NV_PDISP_HDMI_CHANNEL_STATUS1 */
+ uint nv_pdisp_hdmi_channel_status2; /* _NV_PDISP_HDMI_CHANNEL_STATUS2 */
+ uint nv_pdisp_hdmi_emu0; /* _NV_PDISP_HDMI_EMU0 */
+ uint nv_pdisp_hdmi_emu1; /* _NV_PDISP_HDMI_EMU1 */
+ uint nv_pdisp_hdmi_emu1_rdata; /* _NV_PDISP_HDMI_EMU1_RDATA */
+ uint nv_pdisp_hdmi_spare; /* _NV_PDISP_HDMI_SPARE */
+ uint nv_pdisp_hdmi_spdif_chn_status1; /* _NV_PDISP_HDMI_SPDIF_CHN_STATUS1 */
+ uint nv_pdisp_hdmi_spdif_chn_status2; /* _NV_PDISP_HDMI_SPDIF_CHN_STATUS2 */
+
+ uint nv_pdisp_hdcprif_rom_ctrl; /* _NV_PDISP_HDCPRIF_ROM_CTRL */
+
+ uint unused;
+
+ uint nv_pdisp_sor_cap; /* _NV_PDISP_SOR_CAP */
+ uint nv_pdisp_sor_pwr; /* _NV_PDISP_SOR_PWR */
+ uint nv_pdisp_sor_test; /* _NV_PDISP_SOR_TEST */
+ uint nv_pdisp_sor_pll0; /* _NV_PDISP_SOR_PLL0 */
+ uint nv_pdisp_sor_pll1; /* _NV_PDISP_SOR_PLL1 */
+ uint nv_pdisp_sor_pll2; /* _NV_PDISP_SOR_PLL2 */
+ uint nv_pdisp_sor_cstm; /* _NV_PDISP_SOR_CSTM */
+ uint nv_pdisp_sor_lvds; /* _NV_PDISP_SOR_LVDS */
+ uint nv_pdisp_sor_crca; /* _NV_PDISP_SOR_CRCA */
+ uint nv_pdisp_sor_crcb; /* _NV_PDISP_SOR_CRCB */
+ uint nv_pdisp_sor_blank; /* _NV_PDISP_SOR_BLANK */
+
+ uint nv_pdisp_sor_seq_ctl; /* _NV_PDISP_SOR_SEQ_CTL */
+ uint nv_pdisp_sor_seq_inst0; /* _NV_PDISP_SOR_SEQ_INST0 */
+ uint nv_pdisp_sor_seq_inst1; /* _NV_PDISP_SOR_SEQ_INST1 */
+ uint nv_pdisp_sor_seq_inst2; /* _NV_PDISP_SOR_SEQ_INST2 */
+ uint nv_pdisp_sor_seq_inst3; /* _NV_PDISP_SOR_SEQ_INST3 */
+ uint nv_pdisp_sor_seq_inst4; /* _NV_PDISP_SOR_SEQ_INST4 */
+ uint nv_pdisp_sor_seq_inst5; /* _NV_PDISP_SOR_SEQ_INST5 */
+ uint nv_pdisp_sor_seq_inst6; /* _NV_PDISP_SOR_SEQ_INST6 */
+ uint nv_pdisp_sor_seq_inst7; /* _NV_PDISP_SOR_SEQ_INST7 */
+ uint nv_pdisp_sor_seq_inst8; /* _NV_PDISP_SOR_SEQ_INST8 */
+ uint nv_pdisp_sor_seq_inst9; /* _NV_PDISP_SOR_SEQ_INST9 */
+ uint nv_pdisp_sor_seq_insta; /* _NV_PDISP_SOR_SEQ_INSTA */
+ uint nv_pdisp_sor_seq_instb; /* _NV_PDISP_SOR_SEQ_INSTB */
+ uint nv_pdisp_sor_seq_instc; /* _NV_PDISP_SOR_SEQ_INSTC */
+ uint nv_pdisp_sor_seq_instd; /* _NV_PDISP_SOR_SEQ_INSTD */
+ uint nv_pdisp_sor_seq_inste; /* _NV_PDISP_SOR_SEQ_INSTE */
+ uint nv_pdisp_sor_seq_instf; /* _NV_PDISP_SOR_SEQ_INSTF */
+
+ uint unused1[2];
+
+ uint nv_pdisp_sor_vcrca0; /* _NV_PDISP_SOR_VCRCA0 */
+ uint nv_pdisp_sor_vcrca1; /* _NV_PDISP_SOR_VCRCA1 */
+ uint nv_pdisp_sor_ccrca0; /* _NV_PDISP_SOR_CCRCA0 */
+ uint nv_pdisp_sor_ccrca1; /* _NV_PDISP_SOR_CCRCA1 */
+
+ uint nv_pdisp_sor_edataa0; /* _NV_PDISP_SOR_EDATAA0 */
+ uint nv_pdisp_sor_edataa1; /* _NV_PDISP_SOR_EDATAA1 */
+
+ uint nv_pdisp_sor_counta0; /* _NV_PDISP_SOR_COUNTA0 */
+ uint nv_pdisp_sor_counta1; /* _NV_PDISP_SOR_COUNTA1 */
+
+ uint nv_pdisp_sor_debuga0; /* _NV_PDISP_SOR_DEBUGA0 */
+ uint nv_pdisp_sor_debuga1; /* _NV_PDISP_SOR_DEBUGA1 */
+
+ uint nv_pdisp_sor_trig; /* _NV_PDISP_SOR_TRIG */
+ uint nv_pdisp_sor_mscheck; /* _NV_PDISP_SOR_MSCHECK */
+ uint nv_pdisp_sor_lane_drive_current; /* _NV_PDISP_SOR_LANE_DRIVE_CURRENT */
+
+ uint nv_pdisp_audio_debug0; /* _NV_PDISP_AUDIO_DEBUG0 0x7f */
+ uint nv_pdisp_audio_debug1; /* _NV_PDISP_AUDIO_DEBUG1 0x80 */
+ uint nv_pdisp_audio_debug2; /* _NV_PDISP_AUDIO_DEBUG2 0x81 */
+
+ uint nv_pdisp_audio_fs1; /* _NV_PDISP_AUDIO_FS1 0x82 */
+ uint nv_pdisp_audio_fs2; /* _NV_PDISP_AUDIO_FS2 */
+ uint nv_pdisp_audio_fs3; /* _NV_PDISP_AUDIO_FS3 */
+ uint nv_pdisp_audio_fs4; /* _NV_PDISP_AUDIO_FS4 */
+ uint nv_pdisp_audio_fs5; /* _NV_PDISP_AUDIO_FS5 */
+ uint nv_pdisp_audio_fs6; /* _NV_PDISP_AUDIO_FS6 */
+ uint nv_pdisp_audio_fs7; /* _NV_PDISP_AUDIO_FS7 0x88 */
+
+ uint nv_pdisp_audio_pulse_width; /* _NV_PDISP_AUDIO_PULSE_WIDTH */
+ uint nv_pdisp_audio_threshold; /* _NV_PDISP_AUDIO_THRESHOLD */
+ uint nv_pdisp_audio_cntrl0; /* _NV_PDISP_AUDIO_CNTRL0 */
+ uint nv_pdisp_audio_n; /* _NV_PDISP_AUDIO_N */
+ uint nv_pdisp_audio_nval[7]; /* _NV_PDISP_AUDIO_NVAL */
+
+ uint nv_pdisp_hdcprif_rom_timing; /* _NV_PDISP_HDCPRIF_ROM_TIMING */
+ uint nv_pdisp_sor_refclk; /* _NV_PDISP_SOR_REFCLK */
+ uint nv_pdisp_crc_control; /* _NV_PDISP_CRC_CONTROL */
+ uint nv_pdisp_input_control; /* _NV_PDISP_INPUT_CONTROL */
+ uint nv_pdisp_scratch; /* _NV_PDISP_SCRATCH */
+ uint nv_pdisp_pe_current; /* _NV_PDISP_PE_CURRENT */
+
+ uint nv_pdisp_key_ctrl; /* _NV_PDISP_KEY_CTRL */
+ uint nv_pdisp_key_debug0; /* _NV_PDISP_KEY_DEBUG0 */
+ uint nv_pdisp_key_debug1; /* _NV_PDISP_KEY_DEBUG1 */
+ uint nv_pdisp_key_debug2; /* _NV_PDISP_KEY_DEBUG2 */
+ uint nv_pdisp_key_hdcp_key_0; /* _NV_PDISP_KEY_HDCP_KEY_0 */
+ uint nv_pdisp_key_hdcp_key_1; /* _NV_PDISP_KEY_HDCP_KEY_1 */
+ uint nv_pdisp_key_hdcp_key_2; /* _NV_PDISP_KEY_HDCP_KEY_2 */
+ uint nv_pdisp_key_hdcp_key_3; /* _NV_PDISP_KEY_HDCP_KEY_3 */
+ uint nv_pdisp_key_hdcp_key_trig; /* _NV_PDISP_KEY_HDCP_KEY_3 */
+ uint nv_pdisp_key_skey_index; /* _NV_PDISP_KEY_HDCP_KEY_3 */ /* 0xa3 */
+
+ uint unused2[8];
+
+ uint nv_pdisp_sor_audio_cntrl0; /* _NV_PDISP_SOR_AUDIO_CNTRL0 */ /* 0xac */
+ uint nv_pdisp_sor_audio_debug; /* _NV_PDISP_SOR_AUDIO_DEBUG */
+ uint nv_pdisp_sor_audio_spare0; /* _NV_PDISP_SOR_AUDIO_SPARE0 */
+ uint nv_pdisp_sor_audio_nval[7]; /* _NV_PDISP_SOR_AUDIO_NVAL 0xaf ~ 0xb5 */
+ uint nv_pdisp_sor_audio_hda_scratch[4]; /* _NV_PDISP_SOR_AUDIO_HDA_SCRATCH 0xb6 ~ 0xb9 */
+ uint nv_pdisp_sor_audio_hda_codec_scratch[2]; /* _NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH 0xba ~ 0xbb */
+
+ uint nv_pdisp_sor_audio_hda_eld_bufwr; /* _NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR */
+ uint nv_pdisp_sor_audio_hda_presense; /* _NV_PDISP_SOR_AUDIO_HDA_PRESENSE */
+ uint nv_pdisp_sor_audio_hda_cp; /* _NV_PDISP_SOR_AUDIO_HDA_CP */
+ uint nv_pdisp_sor_audio_aval[8]; /* _NV_PDISP_SOR_AUDIO_AVAL */
+ uint nv_pdisp_sor_audio_gen_ctrl; /* _NV_PDISP_SOR_AUDIO_GEN_CTRL */
+
+ uint unused3[4];
+
+ uint nv_pdisp_int_status; /* _NV_PDISP_INT_STATUS */
+ uint nv_pdisp_int_mask; /* _NV_PDISP_INT_MASK */
+ uint nv_pdisp_int_enable; /* _NV_PDISP_INT_ENABLE */
+
+ uint unused4[2];
+
+ uint nv_pdisp_sor_io_peak_current; /* _NV_PDISP_SOR_IO_PEAK_CURRENT */
+ uint nv_pdisp_sor_pad_ctls0; /* _NV_PDISP_SOR_PAD_CTLS0 */
+};
+
+/* HDMI_NV_PDISP_SOR_STATE0 0x01 */
+#define SOR_STATE_UPDATE BIT(0)
+
+/* HDMI_NV_PDISP_SOR_STATE1 0x02 */
+#define SOR_STATE_ASY_HEAD_OPMODE_AWAKE BIT(1)
+#define SOR_STATE_ASY_ORMODE_NORMAL BIT(2)
+#define SOR_STATE_ATTACHED BIT(3)
+
+/* HDMI_NV_PDISP_SOR_STATE2 0x03 */
+#define SOR_STATE_ASY_OWNER_NONE (0 << 0)
+#define SOR_STATE_ASY_OWNER_HEAD0 (1 << 0)
+#define SOR_STATE_ASY_SUBOWNER_NONE (0 << 4)
+#define SOR_STATE_ASY_SUBOWNER_SUBHEAD0 (1 << 4)
+#define SOR_STATE_ASY_SUBOWNER_SUBHEAD1 (2 << 4)
+#define SOR_STATE_ASY_SUBOWNER_BOTH (3 << 4)
+#define SOR_STATE_ASY_CRCMODE_ACTIVE (0 << 6)
+#define SOR_STATE_ASY_CRCMODE_COMPLETE (1 << 6)
+#define SOR_STATE_ASY_CRCMODE_NON_ACTIVE (2 << 6)
+#define SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A (1 << 8)
+#define SOR_STATE_ASY_PROTOCOL_CUSTOM (15 << 8)
+#define SOR_STATE_ASY_HSYNCPOL_POS (0 << 12)
+#define SOR_STATE_ASY_HSYNCPOL_NEG (1 << 12)
+#define SOR_STATE_ASY_VSYNCPOL_POS (0 << 13)
+#define SOR_STATE_ASY_VSYNCPOL_NEG (1 << 13)
+#define SOR_STATE_ASY_DEPOL_POS (0 << 14)
+#define SOR_STATE_ASY_DEPOL_NEG (1 << 14)
+
+#define INFOFRAME_CTRL_ENABLE BIT(0)
+#define INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
+#define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
+#define INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16)
+
+/* HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x2a */
+#define GENERIC_CTRL_ENABLE BIT(0)
+#define GENERIC_CTRL_OTHER BIT(4)
+#define GENERIC_CTRL_SINGLE BIT(8)
+#define GENERIC_CTRL_HBLANK BIT(12)
+#define GENERIC_CTRL_AUDIO BIT(16)
+
+/* HDMI_NV_PDISP_HDMI_ACR_* */
+#define ACR_SUBPACK_CTS(x) (((x) & 0xffffff) << 8)
+#define ACR_SUBPACK_N(x) (((x) & 0xffffff) << 0)
+#define ACR_ENABLE BIT(31)
+
+/* HDMI_NV_PDISP_HDMI_CTRL 0x44 */
+#define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0)
+#define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16)
+#define HDMI_CTRL_ENABLE BIT(30)
+
+/* HDMI_NV_PDISP_HDMI_VSYNC_* */
+#define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0)
+#define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16)
+#define VSYNC_WINDOW_ENABLE BIT(31)
+
+/* HDMI_NV_PDISP_HDMI_SPARE 0x4f */
+#define SPARE_HW_CTS BIT(0)
+#define SPARE_FORCE_SW_CTS BIT(1)
+#define SPARE_CTS_RESET_VAL(x) (((x) & 0x7) << 16)
+
+/* HDMI_NV_PDISP_SOR_PWR 0x55 */
+#define SOR_PWR_NORMAL_STATE_PD (0 << 0)
+#define SOR_PWR_NORMAL_STATE_PU (1 << 0)
+#define SOR_PWR_NORMAL_START_NORMAL (0 << 1)
+#define SOR_PWR_NORMAL_START_ALT (1 << 1)
+#define SOR_PWR_SAFE_STATE_PD (0 << 16)
+#define SOR_PWR_SAFE_STATE_PU (1 << 16)
+#define SOR_PWR_SETTING_NEW_DONE (0 << 31)
+#define SOR_PWR_SETTING_NEW_PENDING (1 << 31)
+#define SOR_PWR_SETTING_NEW_TRIGGER (1 << 31)
+
+/* HDMI_NV_PDISP_SOR_PLL0 0x57 */
+#define SOR_PLL_PWR BIT(0)
+#define SOR_PLL_PDBG BIT(1)
+#define SOR_PLL_VCAPD BIT(2)
+#define SOR_PLL_PDPORT BIT(3)
+#define SOR_PLL_RESISTORSEL BIT(4)
+#define SOR_PLL_PULLDOWN BIT(5)
+#define SOR_PLL_VCOCAP(x) (((x) & 0xf) << 8)
+#define SOR_PLL_BG_V17_S(x) (((x) & 0xf) << 12)
+#define SOR_PLL_FILTER(x) (((x) & 0xf) << 16)
+#define SOR_PLL_ICHPMP(x) (((x) & 0xf) << 24)
+#define SOR_PLL_TX_REG_LOAD(x) (((x) & 0xf) << 28)
+
+/* HDMI_NV_PDISP_SOR_PLL1 0x58 */
+#define SOR_PLL_TMDS_TERM_ENABLE BIT(8)
+#define SOR_PLL_TMDS_TERMADJ(x) (((x) & 0xf) << 9)
+#define SOR_PLL_LOADADJ(x) (((x) & 0xf) << 20)
+#define SOR_PLL_PE_EN BIT(28)
+#define SOR_PLL_HALF_FULL_PE BIT(29)
+#define SOR_PLL_S_D_PIN_PE BIT(30)
+
+/* HDMI_NV_PDISP_SOR_CSTM 0x5a */
+#define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24)
+#define SOR_CSTM_PLLDIV BIT(21)
+#define SOR_CSTM_LVDS_ENABLE BIT(16)
+#define SOR_CSTM_MODE_LVDS (0 << 12)
+#define SOR_CSTM_MODE_TMDS (1 << 12)
+#define SOR_CSTM_MODE_MASK (3 << 12)
+
+/* HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f */
+#define SOR_SEQ_PU_PC(x) (((x) & 0xf) << 0)
+#define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4)
+#define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8)
+#define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12)
+#define SOR_SEQ_PC(x) (((x) & 0xf) << 16)
+#define SOR_SEQ_STATUS BIT(28)
+#define SOR_SEQ_SWITCH BIT(30)
+
+/* HDMI_NV_PDISP_SOR_SEQ_INST(x) (0x60 + (x)) */
+#define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0)
+#define SOR_SEQ_INST_WAIT_UNITS_VSYNC (2 << 12)
+#define SOR_SEQ_INST_HALT (1 << 15)
+#define SOR_SEQ_INST_PIN_A_LOW (0 << 21)
+#define SOR_SEQ_INST_PIN_A_HIGH (1 << 21)
+#define SOR_SEQ_INST_PIN_B_LOW (0 << 22)
+#define SOR_SEQ_INST_PIN_B_HIGH (1 << 22)
+#define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23)
+
+/* HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x7e */
+#define DRIVE_CURRENT_LANE0(x) (((x) & 0x3f) << 0)
+#define DRIVE_CURRENT_LANE1(x) (((x) & 0x3f) << 8)
+#define DRIVE_CURRENT_LANE2(x) (((x) & 0x3f) << 16)
+#define DRIVE_CURRENT_LANE3(x) (((x) & 0x3f) << 24)
+#define DRIVE_CURRENT_LANE0_T114(x) (((x) & 0x7f) << 0)
+#define DRIVE_CURRENT_LANE1_T114(x) (((x) & 0x7f) << 8)
+#define DRIVE_CURRENT_LANE2_T114(x) (((x) & 0x7f) << 16)
+#define DRIVE_CURRENT_LANE3_T114(x) (((x) & 0x7f) << 24)
+
+/* Drive current list */
+enum {
+ DRIVE_CURRENT_1_500_mA,
+ DRIVE_CURRENT_1_875_mA,
+ DRIVE_CURRENT_2_250_mA,
+ DRIVE_CURRENT_2_625_mA,
+ DRIVE_CURRENT_3_000_mA,
+ DRIVE_CURRENT_3_375_mA,
+ DRIVE_CURRENT_3_750_mA,
+ DRIVE_CURRENT_4_125_mA,
+ DRIVE_CURRENT_4_500_mA,
+ DRIVE_CURRENT_4_875_mA,
+ DRIVE_CURRENT_5_250_mA,
+ DRIVE_CURRENT_5_625_mA,
+ DRIVE_CURRENT_6_000_mA,
+ DRIVE_CURRENT_6_375_mA,
+ DRIVE_CURRENT_6_750_mA,
+ DRIVE_CURRENT_7_125_mA,
+ DRIVE_CURRENT_7_500_mA,
+ DRIVE_CURRENT_7_875_mA,
+ DRIVE_CURRENT_8_250_mA,
+ DRIVE_CURRENT_8_625_mA,
+ DRIVE_CURRENT_9_000_mA,
+ DRIVE_CURRENT_9_375_mA,
+ DRIVE_CURRENT_9_750_mA,
+ DRIVE_CURRENT_10_125_mA,
+ DRIVE_CURRENT_10_500_mA,
+ DRIVE_CURRENT_10_875_mA,
+ DRIVE_CURRENT_11_250_mA,
+ DRIVE_CURRENT_11_625_mA,
+ DRIVE_CURRENT_12_000_mA,
+ DRIVE_CURRENT_12_375_mA,
+ DRIVE_CURRENT_12_750_mA,
+ DRIVE_CURRENT_13_125_mA,
+ DRIVE_CURRENT_13_500_mA,
+ DRIVE_CURRENT_13_875_mA,
+ DRIVE_CURRENT_14_250_mA,
+ DRIVE_CURRENT_14_625_mA,
+ DRIVE_CURRENT_15_000_mA,
+ DRIVE_CURRENT_15_375_mA,
+ DRIVE_CURRENT_15_750_mA,
+ DRIVE_CURRENT_16_125_mA,
+ DRIVE_CURRENT_16_500_mA,
+ DRIVE_CURRENT_16_875_mA,
+ DRIVE_CURRENT_17_250_mA,
+ DRIVE_CURRENT_17_625_mA,
+ DRIVE_CURRENT_18_000_mA,
+ DRIVE_CURRENT_18_375_mA,
+ DRIVE_CURRENT_18_750_mA,
+ DRIVE_CURRENT_19_125_mA,
+ DRIVE_CURRENT_19_500_mA,
+ DRIVE_CURRENT_19_875_mA,
+ DRIVE_CURRENT_20_250_mA,
+ DRIVE_CURRENT_20_625_mA,
+ DRIVE_CURRENT_21_000_mA,
+ DRIVE_CURRENT_21_375_mA,
+ DRIVE_CURRENT_21_750_mA,
+ DRIVE_CURRENT_22_125_mA,
+ DRIVE_CURRENT_22_500_mA,
+ DRIVE_CURRENT_22_875_mA,
+ DRIVE_CURRENT_23_250_mA,
+ DRIVE_CURRENT_23_625_mA,
+ DRIVE_CURRENT_24_000_mA,
+ DRIVE_CURRENT_24_375_mA,
+ DRIVE_CURRENT_24_750_mA,
+};
+
+/* Drive current list for T114 */
+enum {
+ DRIVE_CURRENT_0_000_mA_T114,
+ DRIVE_CURRENT_0_400_mA_T114,
+ DRIVE_CURRENT_0_800_mA_T114,
+ DRIVE_CURRENT_1_200_mA_T114,
+ DRIVE_CURRENT_1_600_mA_T114,
+ DRIVE_CURRENT_2_000_mA_T114,
+ DRIVE_CURRENT_2_400_mA_T114,
+ DRIVE_CURRENT_2_800_mA_T114,
+ DRIVE_CURRENT_3_200_mA_T114,
+ DRIVE_CURRENT_3_600_mA_T114,
+ DRIVE_CURRENT_4_000_mA_T114,
+ DRIVE_CURRENT_4_400_mA_T114,
+ DRIVE_CURRENT_4_800_mA_T114,
+ DRIVE_CURRENT_5_200_mA_T114,
+ DRIVE_CURRENT_5_600_mA_T114,
+ DRIVE_CURRENT_6_000_mA_T114,
+ DRIVE_CURRENT_6_400_mA_T114,
+ DRIVE_CURRENT_6_800_mA_T114,
+ DRIVE_CURRENT_7_200_mA_T114,
+ DRIVE_CURRENT_7_600_mA_T114,
+ DRIVE_CURRENT_8_000_mA_T114,
+ DRIVE_CURRENT_8_400_mA_T114,
+ DRIVE_CURRENT_8_800_mA_T114,
+ DRIVE_CURRENT_9_200_mA_T114,
+ DRIVE_CURRENT_9_600_mA_T114,
+ DRIVE_CURRENT_10_000_mA_T114,
+ DRIVE_CURRENT_10_400_mA_T114,
+ DRIVE_CURRENT_10_800_mA_T114,
+ DRIVE_CURRENT_11_200_mA_T114,
+ DRIVE_CURRENT_11_600_mA_T114,
+ DRIVE_CURRENT_12_000_mA_T114,
+ DRIVE_CURRENT_12_400_mA_T114,
+ DRIVE_CURRENT_12_800_mA_T114,
+ DRIVE_CURRENT_13_200_mA_T114,
+ DRIVE_CURRENT_13_600_mA_T114,
+ DRIVE_CURRENT_14_000_mA_T114,
+ DRIVE_CURRENT_14_400_mA_T114,
+ DRIVE_CURRENT_14_800_mA_T114,
+ DRIVE_CURRENT_15_200_mA_T114,
+ DRIVE_CURRENT_15_600_mA_T114,
+ DRIVE_CURRENT_16_000_mA_T114,
+ DRIVE_CURRENT_16_400_mA_T114,
+ DRIVE_CURRENT_16_800_mA_T114,
+ DRIVE_CURRENT_17_200_mA_T114,
+ DRIVE_CURRENT_17_600_mA_T114,
+ DRIVE_CURRENT_18_000_mA_T114,
+ DRIVE_CURRENT_18_400_mA_T114,
+ DRIVE_CURRENT_18_800_mA_T114,
+ DRIVE_CURRENT_19_200_mA_T114,
+ DRIVE_CURRENT_19_600_mA_T114,
+ DRIVE_CURRENT_20_000_mA_T114,
+ DRIVE_CURRENT_20_400_mA_T114,
+ DRIVE_CURRENT_20_800_mA_T114,
+ DRIVE_CURRENT_21_200_mA_T114,
+ DRIVE_CURRENT_21_600_mA_T114,
+ DRIVE_CURRENT_22_000_mA_T114,
+ DRIVE_CURRENT_22_400_mA_T114,
+ DRIVE_CURRENT_22_800_mA_T114,
+ DRIVE_CURRENT_23_200_mA_T114,
+ DRIVE_CURRENT_23_600_mA_T114,
+ DRIVE_CURRENT_24_000_mA_T114,
+ DRIVE_CURRENT_24_400_mA_T114,
+ DRIVE_CURRENT_24_800_mA_T114,
+ DRIVE_CURRENT_25_200_mA_T114,
+ DRIVE_CURRENT_25_400_mA_T114,
+ DRIVE_CURRENT_25_800_mA_T114,
+ DRIVE_CURRENT_26_200_mA_T114,
+ DRIVE_CURRENT_26_600_mA_T114,
+ DRIVE_CURRENT_27_000_mA_T114,
+ DRIVE_CURRENT_27_400_mA_T114,
+ DRIVE_CURRENT_27_800_mA_T114,
+ DRIVE_CURRENT_28_200_mA_T114,
+};
+
+/* HDMI_NV_PDISP_AUDIO_FS */
+#define AUDIO_FS_LOW(x) (((x) & 0xfff) << 0)
+#define AUDIO_FS_HIGH(x) (((x) & 0xfff) << 16)
+
+/* HDMI_NV_PDISP_AUDIO_CNTRL0 0x8b */
+#define AUDIO_CNTRL0_ERROR_TOLERANCE(x) (((x) & 0xff) << 0)
+#define AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20)
+#define AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20)
+#define AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20)
+#define AUDIO_CNTRL0_FRAMES_PER_BLOCK(x) (((x) & 0xff) << 24)
+
+/* HDMI_NV_PDISP_AUDIO_N 0x8c */
+#define AUDIO_N_VALUE(x) (((x) & 0xfffff) << 0)
+#define AUDIO_N_RESETF (1 << 20)
+#define AUDIO_N_GENERATE_NORMAL (0 << 24)
+#define AUDIO_N_GENERATE_ALTERNATE (1 << 24)
+
+/* HDMI_NV_PDISP_SOR_REFCLK 0x95 */
+#define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8)
+#define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x03) << 6)
+
+/* HDMI_NV_PDISP_INPUT_CONTROL 0x97 */
+#define HDMI_SRC_DISPLAYA (0 << 0)
+#define HDMI_SRC_DISPLAYB (1 << 0)
+#define ARM_VIDEO_RANGE_FULL (0 << 1)
+#define ARM_VIDEO_RANGE_LIMITED (1 << 1)
+
+/* HDMI_NV_PDISP_PE_CURRENT 0x99 */
+#define PE_CURRENT0(x) (((x) & 0xf) << 0)
+#define PE_CURRENT1(x) (((x) & 0xf) << 8)
+#define PE_CURRENT2(x) (((x) & 0xf) << 16)
+#define PE_CURRENT3(x) (((x) & 0xf) << 24)
+
+enum {
+ PE_CURRENT_0_0_mA,
+ PE_CURRENT_0_5_mA,
+ PE_CURRENT_1_0_mA,
+ PE_CURRENT_1_5_mA,
+ PE_CURRENT_2_0_mA,
+ PE_CURRENT_2_5_mA,
+ PE_CURRENT_3_0_mA,
+ PE_CURRENT_3_5_mA,
+ PE_CURRENT_4_0_mA,
+ PE_CURRENT_4_5_mA,
+ PE_CURRENT_5_0_mA,
+ PE_CURRENT_5_5_mA,
+ PE_CURRENT_6_0_mA,
+ PE_CURRENT_6_5_mA,
+ PE_CURRENT_7_0_mA,
+ PE_CURRENT_7_5_mA,
+};
+
+enum {
+ PE_CURRENT_0_mA_T114,
+ PE_CURRENT_1_mA_T114,
+ PE_CURRENT_2_mA_T114,
+ PE_CURRENT_3_mA_T114,
+ PE_CURRENT_4_mA_T114,
+ PE_CURRENT_5_mA_T114,
+ PE_CURRENT_6_mA_T114,
+ PE_CURRENT_7_mA_T114,
+ PE_CURRENT_8_mA_T114,
+ PE_CURRENT_9_mA_T114,
+ PE_CURRENT_10_mA_T114,
+ PE_CURRENT_11_mA_T114,
+ PE_CURRENT_12_mA_T114,
+ PE_CURRENT_13_mA_T114,
+ PE_CURRENT_14_mA_T114,
+ PE_CURRENT_15_mA_T114,
+};
+
+/* HDMI_NV_PDISP_SOR_AUDIO_CNTRL0 0xac */
+#define SOR_AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20)
+#define SOR_AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20)
+#define SOR_AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20)
+#define SOR_AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29)
+
+/* HDMI_NV_PDISP_SOR_AUDIO_SPARE0 0xae */
+#define SOR_AUDIO_SPARE0_HBR_ENABLE BIT(27)
+
+/* HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0 0xba */
+#define SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID BIT(30)
+#define SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK 0xffff
+
+/* HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE 0xbd */
+#define SOR_AUDIO_HDA_PRESENSE_VALID BIT(1)
+#define SOR_AUDIO_HDA_PRESENSE_PRESENT BIT(0)
+
+/* HDMI_NV_PDISP_INT_STATUS 0xcc */
+#define INT_SCRATCH BIT(3)
+#define INT_CP_REQUEST BIT(2)
+#define INT_CODEC_SCRATCH1 BIT(1)
+#define INT_CODEC_SCRATCH0 BIT(0)
+
+/* HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT 0xd1 */
+#define PEAK_CURRENT_LANE0(x) (((x) & 0x7f) << 0)
+#define PEAK_CURRENT_LANE1(x) (((x) & 0x7f) << 8)
+#define PEAK_CURRENT_LANE2(x) (((x) & 0x7f) << 16)
+#define PEAK_CURRENT_LANE3(x) (((x) & 0x7f) << 24)
+
+enum {
+ PEAK_CURRENT_0_000_mA,
+ PEAK_CURRENT_0_200_mA,
+ PEAK_CURRENT_0_400_mA,
+ PEAK_CURRENT_0_600_mA,
+ PEAK_CURRENT_0_800_mA,
+ PEAK_CURRENT_1_000_mA,
+ PEAK_CURRENT_1_200_mA,
+ PEAK_CURRENT_1_400_mA,
+ PEAK_CURRENT_1_600_mA,
+ PEAK_CURRENT_1_800_mA,
+ PEAK_CURRENT_2_000_mA,
+ PEAK_CURRENT_2_200_mA,
+ PEAK_CURRENT_2_400_mA,
+ PEAK_CURRENT_2_600_mA,
+ PEAK_CURRENT_2_800_mA,
+ PEAK_CURRENT_3_000_mA,
+ PEAK_CURRENT_3_200_mA,
+ PEAK_CURRENT_3_400_mA,
+ PEAK_CURRENT_3_600_mA,
+ PEAK_CURRENT_3_800_mA,
+ PEAK_CURRENT_4_000_mA,
+ PEAK_CURRENT_4_200_mA,
+ PEAK_CURRENT_4_400_mA,
+ PEAK_CURRENT_4_600_mA,
+ PEAK_CURRENT_4_800_mA,
+ PEAK_CURRENT_5_000_mA,
+ PEAK_CURRENT_5_200_mA,
+ PEAK_CURRENT_5_400_mA,
+ PEAK_CURRENT_5_600_mA,
+ PEAK_CURRENT_5_800_mA,
+ PEAK_CURRENT_6_000_mA,
+ PEAK_CURRENT_6_200_mA,
+ PEAK_CURRENT_6_400_mA,
+ PEAK_CURRENT_6_600_mA,
+ PEAK_CURRENT_6_800_mA,
+ PEAK_CURRENT_7_000_mA,
+ PEAK_CURRENT_7_200_mA,
+ PEAK_CURRENT_7_400_mA,
+ PEAK_CURRENT_7_600_mA,
+ PEAK_CURRENT_7_800_mA,
+ PEAK_CURRENT_8_000_mA,
+ PEAK_CURRENT_8_200_mA,
+ PEAK_CURRENT_8_400_mA,
+ PEAK_CURRENT_8_600_mA,
+ PEAK_CURRENT_8_800_mA,
+ PEAK_CURRENT_9_000_mA,
+ PEAK_CURRENT_9_200_mA,
+ PEAK_CURRENT_9_400_mA,
+};
+
+#endif /* _TEGRA_HDMI_H */
diff --git a/drivers/video/tegra20/tegra-host1x.c b/drivers/video/tegra20/tegra-host1x.c
new file mode 100644
index 00000000000..58ab871a3b4
--- /dev/null
+++ b/drivers/video/tegra20/tegra-host1x.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <clk.h>
+#include <log.h>
+#include <reset.h>
+#include <linux/delay.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/clk_rst.h>
+
+struct tegra_host1x_info {
+ u32 clk_parent;
+ u32 rate;
+};
+
+static int tegra_host1x_probe(struct udevice *dev)
+{
+ struct clk *clk;
+ struct reset_ctl reset_ctl;
+ const struct tegra_host1x_info *info;
+ int ret;
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ log_debug("%s: cannot get HOST1X clock: %ld\n",
+ __func__, PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ ret = reset_get_by_name(dev, "host1x", &reset_ctl);
+ if (ret) {
+ log_debug("%s: cannot get HOST1X reset: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ info = (struct tegra_host1x_info *)dev_get_driver_data(dev);
+
+ reset_assert(&reset_ctl);
+ clock_start_periph_pll(clk->id, info->clk_parent, info->rate);
+
+ mdelay(2);
+ reset_deassert(&reset_ctl);
+
+ return 0;
+}
+
+static const struct tegra_host1x_info tegra20_host1x_info = {
+ .clk_parent = CLOCK_ID_CGENERAL,
+ .rate = 150000000, /* 150 MHz */
+};
+
+static const struct tegra_host1x_info tegra114_host1x_info = {
+ .clk_parent = CLOCK_ID_PERIPH,
+ .rate = 136000000, /* 136 MHz */
+};
+
+static const struct udevice_id tegra_host1x_ids[] = {
+ {
+ .compatible = "nvidia,tegra20-host1x",
+ .data = (ulong)&tegra20_host1x_info
+ }, {
+ .compatible = "nvidia,tegra30-host1x",
+ .data = (ulong)&tegra20_host1x_info
+ }, {
+ .compatible = "nvidia,tegra114-host1x",
+ .data = (ulong)&tegra114_host1x_info
+ }, {
+ .compatible = "nvidia,tegra124-host1x",
+ .data = (ulong)&tegra114_host1x_info
+ }, {
+ /* sentinel */
+ }
+};
+
+U_BOOT_DRIVER(tegra_host1x) = {
+ .name = "tegra_host1x",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = tegra_host1x_ids,
+ .probe = tegra_host1x_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/video/tegra20/tegra-mipi.c b/drivers/video/tegra20/tegra-mipi.c
index 2df3c1a9942..a4f4343d008 100644
--- a/drivers/video/tegra20/tegra-mipi.c
+++ b/drivers/video/tegra20/tegra-mipi.c
@@ -10,9 +10,10 @@
#include <linux/delay.h>
#include <linux/iopoll.h>
+#include <asm/arch/clock.h>
#include <asm/io.h>
-/* MIPI control registers 0x00 ~ 0x60 */
+/* MIPI control registers 0x00 ~ 0x74 */
struct mipi_ctlr {
uint mipi_cal_ctrl;
uint mipi_cal_autocal_ctrl;
@@ -38,8 +39,17 @@ struct mipi_ctlr {
uint mipi_cal_bias_pad_cfg0;
uint mipi_cal_bias_pad_cfg1;
uint mipi_cal_bias_pad_cfg2;
+
+ uint mipi_cal_dsia_config_2;
+ uint mipi_cal_dsib_config_2;
+ uint mipi_cal_cilc_config_2;
+ uint mipi_cal_cild_config_2;
+ uint mipi_cal_csie_config_2;
};
+#define MIPI_DSIA_PADS 0x60
+#define MIPI_DSIB_PADS 0x180
+
#define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26)
#define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24)
#define MIPI_CAL_CTRL_CLKEN_OVR BIT(4)
@@ -64,26 +74,25 @@ struct mipi_ctlr {
#define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4)
#define MIPI_CAL_BIAS_PAD_PDVREG BIT(1)
+#define MIPI_CAL_HSCLKPDOSDSI(x) (((x) & 0x1f) << 8)
+#define MIPI_CAL_HSCLKPUOSDSI(x) (((x) & 0x1f) << 0)
+
struct tegra_mipi_priv {
struct mipi_ctlr *mipi;
struct clk *mipi_cal;
+ u32 version;
};
-static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf,
- int size)
+enum {
+ T114,
+ T124,
+};
+
+static void tegra114_mipi_pads_cal(struct tegra_mipi_priv *priv,
+ int calibration_pads)
{
- struct tegra_mipi_priv *priv = dev_get_priv(dev);
u32 value;
- value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) |
- MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0);
- writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1);
-
- value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2);
- value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
- value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
- writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2);
-
value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) |
MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x4) |
MIPI_CAL_TERMOS(0x5);
@@ -99,6 +108,95 @@ static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf
value = readl(&priv->mipi->mipi_cal_config_dsid);
value &= ~(MIPI_CAL_SEL(0x1));
writel(value, &priv->mipi->mipi_cal_config_dsid);
+}
+
+static void tegra124_mipi_pads_cal(struct tegra_mipi_priv *priv,
+ int calibration_pads)
+{
+ u32 value;
+
+ /* Calibrate DSI-A */
+ if (calibration_pads == MIPI_DSIA_PADS) {
+ printf("Calibrating DSI-A pads\n");
+
+ value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) |
+ MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x0) |
+ MIPI_CAL_TERMOS(0x0);
+ writel(value, &priv->mipi->mipi_cal_config_dsia);
+ writel(value, &priv->mipi->mipi_cal_config_dsib);
+
+ value = MIPI_CAL_SEL(0x1) |
+ MIPI_CAL_HSCLKPDOSDSI(0x1) |
+ MIPI_CAL_HSCLKPUOSDSI(0x2);
+ writel(value, &priv->mipi->mipi_cal_dsia_config_2);
+ writel(value, &priv->mipi->mipi_cal_dsib_config_2);
+
+ /* Deselect PAD C */
+ value = readl(&priv->mipi->mipi_cal_cilc_config_2);
+ value &= ~(MIPI_CAL_SEL(0x1));
+ writel(value, &priv->mipi->mipi_cal_cilc_config_2);
+
+ /* Deselect PAD D */
+ value = readl(&priv->mipi->mipi_cal_cild_config_2);
+ value &= ~(MIPI_CAL_SEL(0x1));
+ writel(value, &priv->mipi->mipi_cal_cild_config_2);
+ }
+
+ /* Calibrate DSI-B */
+ if (calibration_pads == MIPI_DSIB_PADS) {
+ printf("Calibrating DSI-B pads\n");
+
+ value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) |
+ MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x0) |
+ MIPI_CAL_TERMOS(0x0);
+ writel(value, &priv->mipi->mipi_cal_config_csic);
+ writel(value, &priv->mipi->mipi_cal_config_csid);
+
+ value = MIPI_CAL_SEL(0x1) |
+ MIPI_CAL_HSCLKPDOSDSI(0x1) |
+ MIPI_CAL_HSCLKPUOSDSI(0x2);
+ writel(value, &priv->mipi->mipi_cal_cilc_config_2);
+ writel(value, &priv->mipi->mipi_cal_cild_config_2);
+
+ /* Deselect PAD A */
+ value = readl(&priv->mipi->mipi_cal_dsia_config_2);
+ value &= ~(MIPI_CAL_SEL(0x1));
+ writel(value, &priv->mipi->mipi_cal_dsia_config_2);
+
+ /* Deselect PAD B */
+ value = readl(&priv->mipi->mipi_cal_dsib_config_2);
+ value &= ~(MIPI_CAL_SEL(0x1));
+ writel(value, &priv->mipi->mipi_cal_dsib_config_2);
+ }
+}
+
+static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf,
+ int size)
+{
+ struct tegra_mipi_priv *priv = dev_get_priv(dev);
+ u32 value;
+
+ value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) |
+ MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0);
+ writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1);
+
+ value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2);
+ value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
+ value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
+ writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2);
+
+ switch (priv->version) {
+ case T114:
+ tegra114_mipi_pads_cal(priv, offset);
+ break;
+
+ case T124:
+ tegra124_mipi_pads_cal(priv, offset);
+ break;
+
+ default:
+ return -EINVAL;
+ }
value = readl(&priv->mipi->mipi_cal_ctrl);
value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
@@ -134,6 +232,11 @@ static int tegra_mipi_enable(struct udevice *dev, bool val)
struct tegra_mipi_priv *priv = dev_get_priv(dev);
u32 value;
+ reset_set_enable(priv->mipi_cal->id, 1);
+ mdelay(100);
+ reset_set_enable(priv->mipi_cal->id, 0);
+ mdelay(1);
+
clk_enable(priv->mipi_cal);
value = readl(&priv->mipi->mipi_cal_bias_pad_cfg0);
@@ -157,6 +260,8 @@ static int tegra_mipi_probe(struct udevice *dev)
{
struct tegra_mipi_priv *priv = dev_get_priv(dev);
+ priv->version = dev_get_driver_data(dev);
+
priv->mipi = (struct mipi_ctlr *)dev_read_addr_ptr(dev);
if (!priv->mipi) {
log_debug("%s: no MIPI controller address\n", __func__);
@@ -174,7 +279,8 @@ static int tegra_mipi_probe(struct udevice *dev)
}
static const struct udevice_id tegra_mipi_ids[] = {
- { .compatible = "nvidia,tegra114-mipi" },
+ { .compatible = "nvidia,tegra114-mipi", .data = T114 },
+ { .compatible = "nvidia,tegra124-mipi", .data = T124 },
{ }
};
diff --git a/drivers/video/tegra20/tegra-pwm-backlight.c b/drivers/video/tegra20/tegra-pwm-backlight.c
index 79d8a021a3a..998f0df1991 100644
--- a/drivers/video/tegra20/tegra-pwm-backlight.c
+++ b/drivers/video/tegra20/tegra-pwm-backlight.c
@@ -17,9 +17,6 @@
#include "tegra-dc.h"
-#define TEGRA_DISPLAY_A_BASE 0x54200000
-#define TEGRA_DISPLAY_B_BASE 0x54240000
-
#define TEGRA_PWM_BL_MIN_BRIGHTNESS 0x10
#define TEGRA_PWM_BL_MAX_BRIGHTNESS 0xFF
@@ -106,14 +103,11 @@ static int tegra_pwm_backlight_enable(struct udevice *dev)
static int tegra_pwm_backlight_probe(struct udevice *dev)
{
struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+ ofnode dc = ofnode_get_parent(dev_ofnode(dev));
- if (dev_read_bool(dev, "nvidia,display-b-base"))
- priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_B_BASE;
- else
- priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_A_BASE;
-
+ priv->dc = (struct dc_ctlr *)ofnode_get_addr(dc);
if (!priv->dc) {
- log_err("no display controller address\n");
+ log_err("%s: failed to get DC controller\n", __func__);
return -EINVAL;
}
diff --git a/drivers/video/ti/tilcdc.c b/drivers/video/ti/tilcdc.c
index 493e2f18cd2..340c79299ba 100644
--- a/drivers/video/ti/tilcdc.c
+++ b/drivers/video/ti/tilcdc.c
@@ -234,7 +234,7 @@ static int tilcdc_probe(struct udevice *dev)
return -EINVAL;
}
- err = uclass_get_device_by_name(UCLASS_CLK, "lcd_gclk@534", &clk_dev);
+ err = uclass_get_device_by_name(UCLASS_CLK, "clock-lcd-gclk@534", &clk_dev);
if (err) {
dev_err(dev, "failed to get lcd_gclk device\n");
return err;
@@ -252,7 +252,7 @@ static int tilcdc_probe(struct udevice *dev)
return rate;
}
- err = uclass_get_device_by_name(UCLASS_CLK, "dpll_disp_m2_ck@4a4",
+ err = uclass_get_device_by_name(UCLASS_CLK, "clock-dpll-disp-m2@4a4",
&clk_dev);
if (err) {
dev_err(dev, "failed to get dpll_disp_m2 clock device\n");
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b39b2546e5c..1bb67f50352 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -95,6 +95,15 @@ config WDT_APPLE
The watchdog will perform a full SoC reset resulting in a
reboot of the entire system.
+config WDT_ADI
+ bool "Analog Devices watchdog timer support"
+ select WDT
+ select SPL_WDT if SPL
+ depends on ARCH_SC5XX
+ help
+ Enable this to support Watchdog Timer on ADI SC57X, SC58X, SC59X,
+ and SC59X_64 processors
+
config WDT_ARMADA_37XX
bool "Marvell Armada 37xx watchdog timer support"
depends on WDT && ARMADA_3700
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 9b6b1a8e8ad..e6bd4c587af 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
+obj-$(CONFIG_WDT_ADI) += adi_wdt.o
diff --git a/drivers/watchdog/adi_wdt.c b/drivers/watchdog/adi_wdt.c
new file mode 100644
index 00000000000..6f5b3d5d042
--- /dev/null
+++ b/drivers/watchdog/adi_wdt.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright 2022 - Analog Devices, Inc.
+ *
+ * Written and/or maintained by Timesys Corporation
+ *
+ * Converted to driver model by Nathan Barrett-Morrison
+ *
+ * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
+ * Contact: Greg Malysa <greg.malysa@timesys.com>
+ *
+ * adi_wtd.c - driver for ADI on-chip watchdog
+ *
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <wdt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#define WDOG_CTL 0x0
+#define WDOG_CNT 0x4
+#define WDOG_STAT 0x8
+
+#define RCU_CTL 0x0
+#define RCU_STAT 0x4
+
+#define SEC_GCTL 0x0
+#define SEC_FCTL 0x10
+#define SEC_SCTL0 0x800
+
+#define WDEN 0x0010
+#define WDDIS 0x0AD0
+
+struct adi_wdt_priv {
+ void __iomem *rcu_base;
+ void __iomem *sec_base;
+ void __iomem *wdt_base;
+ struct clk clock;
+};
+
+static int adi_wdt_reset(struct udevice *dev)
+{
+ struct adi_wdt_priv *priv = dev_get_priv(dev);
+
+ iowrite32(0, priv->wdt_base + WDOG_STAT);
+
+ return 0;
+}
+
+static int adi_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+{
+ struct adi_wdt_priv *priv = dev_get_priv(dev);
+
+ /* Disable SYSCD_RESETb input and clear the RCU0 reset status */
+ iowrite32(0xf, priv->rcu_base + RCU_STAT);
+ iowrite32(0x0, priv->rcu_base + RCU_CTL);
+
+ /* reset the SEC controller */
+ iowrite32(0x2, priv->sec_base + SEC_GCTL);
+ iowrite32(0x2, priv->sec_base + SEC_FCTL);
+
+ udelay(50);
+
+ /* enable SEC fault event */
+ iowrite32(0x1, priv->sec_base + SEC_GCTL);
+
+ /* ANOMALY 36100004 Spurious External Fault event occurs when FCTL
+ * is re-programmed when currently active fault is not cleared
+ */
+ iowrite32(0xc0, priv->sec_base + SEC_FCTL);
+ iowrite32(0xc1, priv->sec_base + SEC_FCTL);
+
+ /* enable SEC fault source for watchdog0 */
+ setbits_32(priv->sec_base + SEC_SCTL0 + (3*8), 0x6);
+
+ /* Enable SYSCD_RESETb input */
+ iowrite32(0x100, priv->rcu_base + RCU_CTL);
+
+ /* enable watchdog0 */
+ iowrite32(WDDIS, priv->wdt_base + WDOG_CTL);
+
+ iowrite32(timeout_ms / 1000 *
+ (clk_get_rate(&priv->clock) / (IS_ENABLED(CONFIG_SC58X) ? 2 : 1)),
+ priv->wdt_base + WDOG_CNT);
+
+ iowrite32(0, priv->wdt_base + WDOG_STAT);
+ iowrite32(WDEN, priv->wdt_base + WDOG_CTL);
+
+ return 0;
+}
+
+static int adi_wdt_probe(struct udevice *dev)
+{
+ struct adi_wdt_priv *priv = dev_get_priv(dev);
+ int ret;
+ struct resource res;
+
+ ret = dev_read_resource_byname(dev, "rcu", &res);
+ if (ret)
+ return ret;
+ priv->rcu_base = devm_ioremap(dev, res.start, resource_size(&res));
+
+ ret = dev_read_resource_byname(dev, "sec", &res);
+ if (ret)
+ return ret;
+ priv->sec_base = devm_ioremap(dev, res.start, resource_size(&res));
+
+ ret = dev_read_resource_byname(dev, "wdt", &res);
+ if (ret)
+ return ret;
+ priv->wdt_base = devm_ioremap(dev, res.start, resource_size(&res));
+
+ ret = clk_get_by_name(dev, "sclk0", &priv->clock);
+ if (ret < 0) {
+ printf("Can't get WDT clk: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct wdt_ops adi_wdt_ops = {
+ .start = adi_wdt_start,
+ .reset = adi_wdt_reset,
+};
+
+static const struct udevice_id adi_wdt_ids[] = {
+ { .compatible = "adi,wdt" },
+ {}
+};
+
+U_BOOT_DRIVER(adi_wdt) = {
+ .name = "adi_wdt",
+ .id = UCLASS_WDT,
+ .of_match = adi_wdt_ids,
+ .probe = adi_wdt_probe,
+ .ops = &adi_wdt_ops,
+ .priv_auto = sizeof(struct adi_wdt_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/watchdog/da9063-wdt.c b/drivers/watchdog/da9063-wdt.c
index b7216b57863..ec9bc033011 100644
--- a/drivers/watchdog/da9063-wdt.c
+++ b/drivers/watchdog/da9063-wdt.c
@@ -145,5 +145,4 @@ U_BOOT_DRIVER(da9063_wdt) = {
.id = UCLASS_WDT,
.of_match = da9063_wdt_ids,
.ops = &da9063_wdt_ops,
- .flags = DM_FLAG_PROBE_AFTER_BIND,
};