summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-10-05 20:05:46 +0300
committerTom Rini <trini@konsulko.com>2020-10-05 21:10:59 +0300
commitb7e7831e5d5be047f421ddc1f308afc22764a893 (patch)
tree7d5f27c82b260278ed0b3ea96bce592b0505b898 /drivers
parent050acee119b3757fee3bd128f55d720fdd9bb890 (diff)
parentcaebff09efe8c061b4d99b82262c67fb2db9bbcf (diff)
downloadu-boot-b7e7831e5d5be047f421ddc1f308afc22764a893.tar.xz
Merge branch 'next'
Bring in the assorted changes that have been staged in the 'next' branch prior to release. Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/ata/dwc_ahci.c4
-rw-r--r--drivers/clk/Kconfig8
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/aspeed/clk_ast2500.c40
-rw-r--r--drivers/clk/at91/Kconfig7
-rw-r--r--drivers/clk/at91/Makefile15
-rw-r--r--drivers/clk/at91/clk-generated.c178
-rw-r--r--drivers/clk/at91/clk-generic.c202
-rw-r--r--drivers/clk/at91/clk-h32mx.c56
-rw-r--r--drivers/clk/at91/clk-main.c381
-rw-r--r--drivers/clk/at91/clk-master.c331
-rw-r--r--drivers/clk/at91/clk-peripheral.c291
-rw-r--r--drivers/clk/at91/clk-plla.c54
-rw-r--r--drivers/clk/at91/clk-plladiv.c85
-rw-r--r--drivers/clk/at91/clk-programmable.c208
-rw-r--r--drivers/clk/at91/clk-sam9x60-pll.c442
-rw-r--r--drivers/clk/at91/clk-slow.c36
-rw-r--r--drivers/clk/at91/clk-system.c143
-rw-r--r--drivers/clk/at91/clk-usb.c147
-rw-r--r--drivers/clk/at91/clk-utmi.c234
-rw-r--r--drivers/clk/at91/compat.c1023
-rw-r--r--drivers/clk/at91/pmc.c218
-rw-r--r--drivers/clk/at91/pmc.h140
-rw-r--r--drivers/clk/at91/sama7g5.c1401
-rw-r--r--drivers/clk/at91/sckc.c169
-rw-r--r--drivers/clk/clk-uclass.c51
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/clk/clk_fixed_rate.c1
-rw-r--r--drivers/clk/clk_scmi.c99
-rw-r--r--drivers/clk/clk_zynqmp.c2
-rw-r--r--drivers/clk/kendryte/clk.c4
-rw-r--r--drivers/core/Kconfig9
-rw-r--r--drivers/core/device.c22
-rw-r--r--drivers/core/of_access.c7
-rw-r--r--drivers/core/ofnode.c3
-rw-r--r--drivers/core/regmap.c163
-rw-r--r--drivers/core/syscon-uclass.c12
-rw-r--r--drivers/cpu/Makefile1
-rw-r--r--drivers/cpu/at91_cpu.c123
-rw-r--r--drivers/cpu/cpu_sandbox.c39
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/firmware-zynqmp.c2
-rw-r--r--drivers/firmware/scmi/Kconfig19
-rw-r--r--drivers/firmware/scmi/Makefile5
-rw-r--r--drivers/firmware/scmi/mailbox_agent.c102
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c410
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_devices.c113
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c119
-rw-r--r--drivers/firmware/scmi/smccc_agent.c89
-rw-r--r--drivers/firmware/scmi/smt.c139
-rw-r--r--drivers/firmware/scmi/smt.h86
-rw-r--r--drivers/firmware/ti_sci.c23
-rw-r--r--drivers/fpga/zynqmppl.c10
-rw-r--r--drivers/gpio/gpio-uclass.c71
-rw-r--r--drivers/gpio/stm32_gpio.c15
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/acpi_i2c.c226
-rw-r--r--drivers/i2c/acpi_i2c.h15
-rw-r--r--drivers/i2c/i2c-cdns.c2
-rw-r--r--drivers/i2c/i2c-uclass.c17
-rw-r--r--drivers/i2c/mxc_i2c.c7
-rw-r--r--drivers/mailbox/k3-sec-proxy.c6
-rw-r--r--drivers/mailbox/stm32-ipcc.c9
-rw-r--r--drivers/mailbox/zynqmp-ipi.c2
-rw-r--r--drivers/mmc/atmel_sdhci.c13
-rw-r--r--drivers/mmc/bcm2835_sdhost.c34
-rw-r--r--drivers/mmc/mtk-sd.c24
-rw-r--r--drivers/mmc/zynq_sdhci.c2
-rw-r--r--drivers/mtd/nand/raw/Kconfig2
-rw-r--r--drivers/mtd/nand/raw/arasan_nfc.c2
-rw-r--r--drivers/mtd/nand/raw/atmel_nand.c69
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c20
-rw-r--r--drivers/mtd/nand/raw/pxa3xx_nand.c30
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c45
-rw-r--r--drivers/mtd/nand/raw/vf610_nfc.c38
-rw-r--r--drivers/mtd/nand/raw/zynq_nand.c2
-rw-r--r--drivers/mtd/nand/spi/core.c8
-rw-r--r--drivers/mtd/spi/spi-nor-core.c1
-rw-r--r--drivers/mtd/spi/spi-nor-tiny.c21
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/bcm6368-eth.c3
-rw-r--r--drivers/net/dwc_eth_qos.c7
-rw-r--r--drivers/net/fsl_mdio.c28
-rw-r--r--drivers/net/ftgmac100.c4
-rw-r--r--drivers/net/mvneta.c56
-rw-r--r--drivers/net/mvpp2.c87
-rw-r--r--drivers/net/phy/mscc.c129
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/qe/Kconfig9
-rw-r--r--drivers/net/qe/Makefile5
-rw-r--r--drivers/net/qe/dm_qe_uec.c1167
-rw-r--r--drivers/net/qe/dm_qe_uec.h22
-rw-r--r--drivers/net/qe/dm_qe_uec_phy.c163
-rw-r--r--drivers/net/qe/uccf.c507
-rw-r--r--drivers/net/qe/uccf.h119
-rw-r--r--drivers/net/qe/uec.h693
-rw-r--r--drivers/net/ravb.c2
-rw-r--r--drivers/net/sun8i_emac.c9
-rw-r--r--drivers/net/sunxi_emac.c5
-rw-r--r--drivers/net/ti/cpsw.c6
-rw-r--r--drivers/net/tsec.c57
-rw-r--r--drivers/net/xilinx_axi_emac.c48
-rw-r--r--drivers/net/zynq_gem.c10
-rw-r--r--drivers/pci/pci-uclass.c3
-rw-r--r--drivers/phy/Kconfig13
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c12
-rw-r--r--drivers/phy/marvell/comphy_core.c6
-rw-r--r--drivers/phy/phy-bcm-sr-pcie.c177
-rw-r--r--drivers/phy/phy-qcom-ipq4019-usb.c145
-rw-r--r--drivers/phy/phy-stm32-usbphyc.c2
-rw-r--r--drivers/phy/phy-ti-am654.c4
-rw-r--r--drivers/phy/phy-uclass.c45
-rw-r--r--drivers/phy/rockchip/phy-rockchip-pcie.c14
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c6
-rw-r--r--drivers/pinctrl/Kconfig7
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/broadcom/pinctrl-bcm283x.c21
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c1
-rw-r--r--drivers/pinctrl/pinctrl-qe-io.c255
-rw-r--r--drivers/pinctrl/pinctrl_stm32.c48
-rw-r--r--drivers/pinctrl/renesas/Kconfig20
-rw-r--r--drivers/qe/Kconfig2
-rw-r--r--drivers/qe/qe.c96
-rw-r--r--drivers/qe/uccf.c449
-rw-r--r--drivers/qe/uccf.h90
-rw-r--r--drivers/qe/uec.c598
-rw-r--r--drivers/qe/uec.h381
-rw-r--r--drivers/qe/uec_phy.c334
-rw-r--r--drivers/qe/uec_phy.h71
-rw-r--r--drivers/ram/sifive/fu540_ddr.c17
-rw-r--r--drivers/remoteproc/k3_system_controller.c9
-rw-r--r--drivers/remoteproc/rproc-elf-loader.c16
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c123
-rw-r--r--drivers/reset/Kconfig16
-rw-r--r--drivers/reset/Makefile2
-rw-r--r--drivers/reset/reset-ipq4019.c173
-rw-r--r--drivers/reset/reset-scmi.c81
-rw-r--r--drivers/reset/reset-uclass.c118
-rw-r--r--drivers/reset/sandbox-reset-test.c51
-rw-r--r--drivers/reset/sandbox-reset.c19
-rw-r--r--drivers/serial/Kconfig4
-rw-r--r--drivers/serial/serial_xuartlite.c64
-rw-r--r--drivers/smem/Kconfig2
-rw-r--r--drivers/smem/msm_smem.c2
-rw-r--r--drivers/sound/max98357a.c2
-rw-r--r--drivers/spi/Kconfig3
-rw-r--r--drivers/spi/omap3_spi.c107
-rw-r--r--drivers/spi/spi-sunxi.c6
-rw-r--r--drivers/spi/spi-uclass.c2
-rw-r--r--drivers/spi/zynqmp_gqspi.c6
-rw-r--r--drivers/sysreset/sysreset-ti-sci.c3
-rw-r--r--drivers/timer/Kconfig11
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/mchp-pit64b-timer.c109
-rw-r--r--drivers/timer/riscv_timer.c39
-rw-r--r--drivers/timer/sandbox_timer.c4
-rw-r--r--drivers/timer/timer-uclass.c31
-rw-r--r--drivers/tpm/cr50_i2c.c55
-rw-r--r--drivers/usb/cdns3/ep0.c5
-rw-r--r--drivers/usb/cdns3/gadget.c3
-rw-r--r--drivers/usb/dwc3/core.c15
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c2
-rw-r--r--drivers/usb/dwc3/ep0.c1
-rw-r--r--drivers/usb/dwc3/gadget.c23
-rw-r--r--drivers/usb/dwc3/ti_usb_phy.c4
-rw-r--r--drivers/usb/host/Kconfig3
-rw-r--r--drivers/usb/host/dwc2.c39
-rw-r--r--drivers/usb/host/ehci-hcd.c8
-rw-r--r--drivers/usb/host/ohci-generic.c8
-rw-r--r--drivers/usb/host/xhci-mem.c18
-rw-r--r--drivers/usb/host/xhci-mtk.c1
-rw-r--r--drivers/usb/host/xhci-rcar.c1
-rw-r--r--drivers/usb/host/xhci-ring.c141
-rw-r--r--drivers/usb/host/xhci.c37
-rw-r--r--drivers/usb/musb-new/sunxi.c13
-rw-r--r--drivers/video/cfb_console.c8
-rw-r--r--drivers/video/dw_mipi_dsi.c24
-rw-r--r--drivers/video/stm32/stm32_dsi.c3
-rw-r--r--drivers/video/stm32/stm32_ltdc.c3
183 files changed, 12818 insertions, 2724 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 33126b2da7..9eb51453e5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/
obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/
obj-$(CONFIG_$(SPL_)BOARD) += board/
obj-$(CONFIG_XEN) += xen/
+obj-$(CONFIG_$(SPL_)FPGA) += fpga/
ifndef CONFIG_TPL_BUILD
ifdef CONFIG_SPL_BUILD
@@ -60,7 +61,6 @@ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/
obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/
obj-$(CONFIG_SPL_SATA_SUPPORT) += ata/ scsi/
obj-$(CONFIG_HAVE_BLOCK_DEVICE) += block/
-obj-$(CONFIG_SPL_FPGA_SUPPORT) += fpga/
obj-$(CONFIG_SPL_THERMAL) += thermal/
endif
@@ -85,7 +85,6 @@ obj-y += cache/
obj-$(CONFIG_CPU) += cpu/
obj-y += crypto/
obj-$(CONFIG_FASTBOOT) += fastboot/
-obj-$(CONFIG_FPGA) += fpga/
obj-y += misc/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_NVME) += nvme/
diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c
index 825fe57f85..ed0527c976 100644
--- a/drivers/ata/dwc_ahci.c
+++ b/drivers/ata/dwc_ahci.c
@@ -62,13 +62,13 @@ static int dwc_ahci_probe(struct udevice *dev)
ret = generic_phy_init(&phy);
if (ret) {
- pr_err("unable to initialize the sata phy\n");
+ pr_debug("unable to initialize the sata phy\n");
return ret;
}
ret = generic_phy_power_on(&phy);
if (ret) {
- pr_err("unable to power on the sata phy\n");
+ pr_debug("unable to power on the sata phy\n");
return ret;
}
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 6003e140b5..4dfbad7986 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -159,6 +159,14 @@ config CLK_CDCE9XX
Enable the clock synthesizer driver for CDCE913/925/937/949
series of chips.
+config CLK_SCMI
+ bool "Enable SCMI clock driver"
+ depends on SCMI_FIRMWARE
+ help
+ Enable this option if you want to support clock devices exposed
+ by a SCMI agent based on SCMI clock protocol communication
+ with a SCMI server.
+
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/at91/Kconfig"
source "drivers/clk/exynos/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cda4b4b605..d1e295ac7c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
obj-$(CONFIG_CLK_OWL) += owl/
obj-$(CONFIG_CLK_RENESAS) += renesas/
+obj-$(CONFIG_CLK_SCMI) += clk_scmi.o
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c
index d1940f1884..aab7d14deb 100644
--- a/drivers/clk/aspeed/clk_ast2500.c
+++ b/drivers/clk/aspeed/clk_ast2500.c
@@ -10,7 +10,7 @@
#include <asm/io.h>
#include <asm/arch/scu_ast2500.h>
#include <dm/lists.h>
-#include <dt-bindings/clock/ast2500-scu.h>
+#include <dt-bindings/clock/aspeed-clock.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -122,8 +122,7 @@ static ulong ast2500_clk_get_rate(struct clk *clk)
ulong rate;
switch (clk->id) {
- case PLL_HPLL:
- case ARMCLK:
+ case ASPEED_CLK_HPLL:
/*
* This ignores dynamic/static slowdown of ARMCLK and may
* be inaccurate.
@@ -131,11 +130,11 @@ static ulong ast2500_clk_get_rate(struct clk *clk)
rate = ast2500_get_hpll_rate(clkin,
readl(&priv->scu->h_pll_param));
break;
- case MCLK_DDR:
+ case ASPEED_CLK_MPLL:
rate = ast2500_get_mpll_rate(clkin,
readl(&priv->scu->m_pll_param));
break;
- case BCLK_PCLK:
+ case ASPEED_CLK_APB:
{
ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1)
& SCU_PCLK_DIV_MASK)
@@ -146,7 +145,7 @@ static ulong ast2500_clk_get_rate(struct clk *clk)
rate = rate / apb_div;
}
break;
- case BCLK_SDCLK:
+ case ASPEED_CLK_SDIO:
{
ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1)
& SCU_SDCLK_DIV_MASK)
@@ -157,19 +156,19 @@ static ulong ast2500_clk_get_rate(struct clk *clk)
rate = rate / apb_div;
}
break;
- case PCLK_UART1:
+ case ASPEED_CLK_GATE_UART1CLK:
rate = ast2500_get_uart_clk_rate(priv->scu, 1);
break;
- case PCLK_UART2:
+ case ASPEED_CLK_GATE_UART2CLK:
rate = ast2500_get_uart_clk_rate(priv->scu, 2);
break;
- case PCLK_UART3:
+ case ASPEED_CLK_GATE_UART3CLK:
rate = ast2500_get_uart_clk_rate(priv->scu, 3);
break;
- case PCLK_UART4:
+ case ASPEED_CLK_GATE_UART4CLK:
rate = ast2500_get_uart_clk_rate(priv->scu, 4);
break;
- case PCLK_UART5:
+ case ASPEED_CLK_GATE_UART5CLK:
rate = ast2500_get_uart_clk_rate(priv->scu, 5);
break;
default:
@@ -431,11 +430,10 @@ static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate)
ulong new_rate;
switch (clk->id) {
- case PLL_MPLL:
- case MCLK_DDR:
+ case ASPEED_CLK_MPLL:
new_rate = ast2500_configure_ddr(priv->scu, rate);
break;
- case PLL_D2PLL:
+ case ASPEED_CLK_D2PLL:
new_rate = ast2500_configure_d2pll(priv->scu, rate);
break;
default:
@@ -450,7 +448,7 @@ static int ast2500_clk_enable(struct clk *clk)
struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
- case BCLK_SDCLK:
+ case ASPEED_CLK_SDIO:
if (readl(&priv->scu->clk_stop_ctrl1) & SCU_CLKSTOP_SDCLK) {
ast_scu_unlock(priv->scu);
@@ -471,13 +469,13 @@ static int ast2500_clk_enable(struct clk *clk)
* configured based on whether RGMII or RMII mode has been selected
* through hardware strapping.
*/
- case PCLK_MAC1:
+ case ASPEED_CLK_GATE_MAC1CLK:
ast2500_configure_mac(priv->scu, 1);
break;
- case PCLK_MAC2:
+ case ASPEED_CLK_GATE_MAC2CLK:
ast2500_configure_mac(priv->scu, 2);
break;
- case PLL_D2PLL:
+ case ASPEED_CLK_D2PLL:
ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE);
break;
default:
@@ -497,9 +495,9 @@ static int ast2500_clk_ofdata_to_platdata(struct udevice *dev)
{
struct ast2500_clk_priv *priv = dev_get_priv(dev);
- priv->scu = dev_read_addr_ptr(dev);
- if (!priv->scu)
- return -EINVAL;
+ priv->scu = devfdt_get_addr_ptr(dev);
+ if (IS_ERR(priv->scu))
+ return PTR_ERR(priv->scu);
return 0;
}
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig
index 8d482a2752..4abc8026b4 100644
--- a/drivers/clk/at91/Kconfig
+++ b/drivers/clk/at91/Kconfig
@@ -54,3 +54,10 @@ config AT91_GENERIC_CLK
that may be different from the system clock. This second
clock is the generic clock (GCLK) and is managed by
the PMC via PMC_PCR register.
+
+config AT91_SAM9X60_PLL
+ bool "PLL support for SAM9X60 SoCs"
+ depends on CLK_AT91
+ help
+ This option is used to enable the AT91 SAM9X60's PLL clock
+ driver.
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 8c197ff949..2453c38af1 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -2,11 +2,14 @@
# Makefile for at91 specific clk
#
-obj-y += pmc.o sckc.o
-obj-y += clk-slow.o clk-main.o clk-plla.o clk-plladiv.o clk-master.o
-obj-y += clk-system.o clk-peripheral.o
+ifdef CONFIG_CLK_CCF
+obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o clk-system.o
+obj-y += clk-peripheral.o
+obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generic.o
obj-$(CONFIG_AT91_UTMI) += clk-utmi.o
-obj-$(CONFIG_AT91_USB_CLK) += clk-usb.o
-obj-$(CONFIG_AT91_H32MX) += clk-h32mx.o
-obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generated.o
+obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
+obj-$(CONFIG_SAMA7G5) += sama7g5.o
+else
+obj-y += compat.o
+endif
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
deleted file mode 100644
index c0610940c3..0000000000
--- a/drivers/clk/at91/clk-generated.c
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <log.h>
-#include <malloc.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define GENERATED_SOURCE_MAX 6
-#define GENERATED_MAX_DIV 255
-
-/**
- * generated_clk_bind() - for the generated clock driver
- * Recursively bind its children as clk devices.
- *
- * @return: 0 on success, or negative error code on failure
- */
-static int generated_clk_bind(struct udevice *dev)
-{
- return at91_clk_sub_device_bind(dev, "generic-clk");
-}
-
-static const struct udevice_id generated_clk_match[] = {
- { .compatible = "atmel,sama5d2-clk-generated" },
- {}
-};
-
-U_BOOT_DRIVER(generated_clk) = {
- .name = "generated-clk",
- .id = UCLASS_MISC,
- .of_match = generated_clk_match,
- .bind = generated_clk_bind,
-};
-
-/*-------------------------------------------------------------*/
-
-struct generic_clk_priv {
- u32 num_parents;
-};
-
-static ulong generic_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk parent;
- ulong clk_rate;
- u32 tmp, gckdiv;
- u8 clock_source, parent_index;
- int ret;
-
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- tmp = readl(&pmc->pcr);
- clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) &
- AT91_PMC_PCR_GCKCSS_MASK;
- gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
-
- parent_index = clock_source - 1;
- ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent);
- if (ret)
- return 0;
-
- clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
-
- clk_free(&parent);
-
- return clk_rate;
-}
-
-static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct generic_clk_priv *priv = dev_get_priv(clk->dev);
- struct clk parent, best_parent;
- ulong tmp_rate, best_rate = rate, parent_rate;
- int tmp_diff, best_diff = -1;
- u32 div, best_div = 0;
- u8 best_parent_index, best_clock_source = 0;
- u8 i;
- u32 tmp;
- int ret;
-
- for (i = 0; i < priv->num_parents; i++) {
- ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
- if (ret)
- return ret;
-
- parent_rate = clk_get_rate(&parent);
- if (IS_ERR_VALUE(parent_rate))
- return parent_rate;
-
- for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
- tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
- tmp_diff = abs(rate - tmp_rate);
-
- if (best_diff < 0 || best_diff > tmp_diff) {
- best_rate = tmp_rate;
- best_diff = tmp_diff;
-
- best_div = div - 1;
- best_parent = parent;
- best_parent_index = i;
- best_clock_source = best_parent_index + 1;
- }
-
- if (!best_diff || tmp_rate < rate)
- break;
- }
-
- if (!best_diff)
- break;
- }
-
- debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n",
- best_parent.dev->name, best_rate, best_div);
-
- ret = clk_enable(&best_parent);
- if (ret)
- return ret;
-
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- tmp = readl(&pmc->pcr);
- tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS);
- tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) |
- AT91_PMC_PCR_CMD_WRITE |
- AT91_PMC_PCR_GCKDIV_(best_div) |
- AT91_PMC_PCR_GCKEN;
- writel(tmp, &pmc->pcr);
-
- while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY))
- ;
-
- return 0;
-}
-
-static struct clk_ops generic_clk_ops = {
- .of_xlate = at91_clk_of_xlate,
- .get_rate = generic_clk_get_rate,
- .set_rate = generic_clk_set_rate,
-};
-
-static int generic_clk_ofdata_to_platdata(struct udevice *dev)
-{
- struct generic_clk_priv *priv = dev_get_priv(dev);
- u32 cells[GENERATED_SOURCE_MAX];
- u32 num_parents;
-
- num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
- dev_of_offset(dev_get_parent(dev)), "clocks", cells,
- GENERATED_SOURCE_MAX);
-
- if (!num_parents)
- return -1;
-
- priv->num_parents = num_parents;
-
- return 0;
-}
-
-U_BOOT_DRIVER(generic_clk) = {
- .name = "generic-clk",
- .id = UCLASS_CLK,
- .probe = at91_clk_probe,
- .ofdata_to_platdata = generic_clk_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct generic_clk_priv),
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &generic_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-generic.c b/drivers/clk/at91/clk-generic.c
new file mode 100644
index 0000000000..87738b7b5b
--- /dev/null
+++ b/drivers/clk/at91/clk-generic.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generic clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-generated.c from Linux.
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_GCK "at91-gck-clk"
+
+#define GENERATED_MAX_DIV 255
+
+struct clk_gck {
+ void __iomem *base;
+ const u32 *clk_mux_table;
+ const u32 *mux_table;
+ const struct clk_pcr_layout *layout;
+ struct clk_range range;
+ struct clk clk;
+ u32 num_parents;
+ u32 id;
+};
+
+#define to_clk_gck(_c) container_of(_c, struct clk_gck, clk)
+
+static int clk_gck_enable(struct clk *clk)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ gck->layout->cmd | AT91_PMC_PCR_GCKEN,
+ gck->layout->cmd | AT91_PMC_PCR_GCKEN);
+
+ return 0;
+}
+
+static int clk_gck_disable(struct clk *clk)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ gck->layout->cmd | AT91_PMC_PCR_GCKEN,
+ gck->layout->cmd);
+
+ return 0;
+}
+
+static int clk_gck_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+ int index;
+
+ index = at91_clk_mux_val_to_index(gck->clk_mux_table, gck->num_parents,
+ parent->id);
+ if (index < 0)
+ return index;
+
+ index = at91_clk_mux_index_to_val(gck->mux_table, gck->num_parents,
+ index);
+ if (index < 0)
+ return index;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ gck->layout->gckcss_mask | gck->layout->cmd,
+ (index << (ffs(gck->layout->gckcss_mask) - 1)) |
+ gck->layout->cmd);
+
+ return 0;
+}
+
+static ulong clk_gck_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 div;
+
+ if (!rate || !parent_rate)
+ return 0;
+
+ if (gck->range.max && rate > gck->range.max)
+ return 0;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ if (div > GENERATED_MAX_DIV + 1 || !div)
+ return 0;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ AT91_PMC_PCR_GCKDIV_MASK | gck->layout->cmd,
+ ((div - 1) << (ffs(AT91_PMC_PCR_GCKDIV_MASK) - 1)) |
+ gck->layout->cmd);
+
+ return parent_rate / div;
+}
+
+static ulong clk_gck_get_rate(struct clk *clk)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 val, div;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_read(gck->base, gck->layout->offset, &val);
+
+ div = (val & AT91_PMC_PCR_GCKDIV_MASK) >>
+ (ffs(AT91_PMC_PCR_GCKDIV_MASK) - 1);
+
+ return parent_rate / (div + 1);
+}
+
+static const struct clk_ops gck_ops = {
+ .enable = clk_gck_enable,
+ .disable = clk_gck_disable,
+ .set_parent = clk_gck_set_parent,
+ .set_rate = clk_gck_set_rate,
+ .get_rate = clk_gck_get_rate,
+};
+
+struct clk *
+at91_clk_register_generic(void __iomem *base,
+ const struct clk_pcr_layout *layout,
+ const char *name, const char * const *parent_names,
+ const u32 *clk_mux_table, const u32 *mux_table,
+ u8 num_parents, u8 id,
+ const struct clk_range *range)
+{
+ struct clk_gck *gck;
+ struct clk *clk;
+ int ret, index;
+ u32 val;
+
+ if (!base || !layout || !name || !parent_names || !num_parents ||
+ !clk_mux_table || !mux_table || !range)
+ return ERR_PTR(-EINVAL);
+
+ gck = kzalloc(sizeof(*gck), GFP_KERNEL);
+ if (!gck)
+ return ERR_PTR(-ENOMEM);
+
+ gck->id = id;
+ gck->base = base;
+ gck->range = *range;
+ gck->layout = layout;
+ gck->clk_mux_table = clk_mux_table;
+ gck->mux_table = mux_table;
+ gck->num_parents = num_parents;
+
+ clk = &gck->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_read(gck->base, gck->layout->offset, &val);
+
+ val = (val & gck->layout->gckcss_mask) >>
+ (ffs(gck->layout->gckcss_mask) - 1);
+
+ index = at91_clk_mux_val_to_index(gck->mux_table, gck->num_parents,
+ val);
+ if (index < 0) {
+ kfree(gck);
+ return ERR_PTR(index);
+ }
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_GCK, name,
+ parent_names[index]);
+ if (ret) {
+ kfree(gck);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_gck_clk) = {
+ .name = UBOOT_DM_CLK_AT91_GCK,
+ .id = UCLASS_CLK,
+ .ops = &gck_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
deleted file mode 100644
index 86bb71f612..0000000000
--- a/drivers/clk/at91/clk-h32mx.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <dm/device_compat.h>
-#include <dm/util.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define H32MX_MAX_FREQ 90000000
-
-static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- ulong rate = gd->arch.mck_rate_hz;
-
- if (readl(&pmc->mckr) & AT91_PMC_MCKR_H32MXDIV)
- rate /= 2;
-
- if (rate > H32MX_MAX_FREQ)
- dev_dbg(clk->dev, "H32MX clock is too fast\n");
-
- return rate;
-}
-
-static struct clk_ops sama5d4_h32mx_clk_ops = {
- .get_rate = sama5d4_h32mx_clk_get_rate,
-};
-
-static int sama5d4_h32mx_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id sama5d4_h32mx_clk_match[] = {
- { .compatible = "atmel,sama5d4-clk-h32mx" },
- {}
-};
-
-U_BOOT_DRIVER(sama5d4_h32mx_clk) = {
- .name = "sama5d4-h32mx-clk",
- .id = UCLASS_CLK,
- .of_match = sama5d4_h32mx_clk_match,
- .probe = sama5d4_h32mx_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &sama5d4_h32mx_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index b31a1cb682..b52d926f33 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -1,54 +1,387 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Main clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-main.c from Linux.
*/
+#include <asm/processor.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/delay.h>
#include <linux/io.h>
-#include <mach/at91_pmc.h>
#include "pmc.h"
-DECLARE_GLOBAL_DATA_PTR;
+#define UBOOT_DM_CLK_AT91_MAIN_RC "at91-main-rc-clk"
+#define UBOOT_DM_CLK_AT91_MAIN_OSC "at91-main-osc-clk"
+#define UBOOT_DM_CLK_AT91_RM9200_MAIN "at91-rm9200-main-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X5_MAIN "at91-sam9x5-main-clk"
-static int main_osc_clk_enable(struct clk *clk)
+#define MOR_KEY_MASK GENMASK(23, 16)
+#define USEC_PER_SEC 1000000UL
+#define SLOW_CLOCK_FREQ 32768
+
+#define clk_main_parent_select(s) (((s) & \
+ (AT91_PMC_MOSCEN | \
+ AT91_PMC_OSCBYPASS)) ? 1 : 0)
+
+struct clk_main_rc {
+ void __iomem *reg;
+ struct clk clk;
+};
+
+#define to_clk_main_rc(_clk) container_of(_clk, struct clk_main_rc, clk)
+
+struct clk_main_osc {
+ void __iomem *reg;
+ struct clk clk;
+};
+
+#define to_clk_main_osc(_clk) container_of(_clk, struct clk_main_osc, clk)
+
+struct clk_main {
+ void __iomem *reg;
+ const unsigned int *clk_mux_table;
+ const char * const *parent_names;
+ unsigned int num_parents;
+ int type;
+ struct clk clk;
+};
+
+#define to_clk_main(_clk) container_of(_clk, struct clk_main, clk)
+
+static int main_rc_enable(struct clk *clk)
+{
+ struct clk_main_rc *main_rc = to_clk_main_rc(clk);
+ void __iomem *reg = main_rc->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+
+ if (!(val & AT91_PMC_MOSCRCEN)) {
+ pmc_update_bits(reg, AT91_CKGR_MOR,
+ MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
+ AT91_PMC_KEY | AT91_PMC_MOSCRCEN);
+ }
+
+ pmc_read(reg, AT91_PMC_SR, &val);
+ while (!(val & AT91_PMC_MOSCRCS)) {
+ pmc_read(reg, AT91_PMC_SR, &val);
+ debug("waiting for main rc...\n");
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int main_rc_disable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
+ struct clk_main_rc *main_rc = to_clk_main_rc(clk);
+ struct reg *reg = main_rc->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
- if (readl(&pmc->sr) & AT91_PMC_MOSCSELS)
+ if (!(val & AT91_PMC_MOSCRCEN))
return 0;
- return -EINVAL;
+ pmc_update_bits(reg, AT91_CKGR_MOR, MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
+ AT91_PMC_KEY);
+
+ return 0;
}
-static ulong main_osc_clk_get_rate(struct clk *clk)
+static const struct clk_ops main_rc_clk_ops = {
+ .enable = main_rc_enable,
+ .disable = main_rc_disable,
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
+ const char *parent_name)
{
- return gd->arch.main_clk_rate_hz;
+ struct clk_main_rc *main_rc;
+ struct clk *clk;
+ int ret;
+
+ if (!reg || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ main_rc = kzalloc(sizeof(*main_rc), GFP_KERNEL);
+ if (!main_rc)
+ return ERR_PTR(-ENOMEM);
+
+ main_rc->reg = reg;
+ clk = &main_rc->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_RC, name,
+ parent_name);
+ if (ret) {
+ kfree(main_rc);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
}
-static struct clk_ops main_osc_clk_ops = {
- .enable = main_osc_clk_enable,
- .get_rate = main_osc_clk_get_rate,
+U_BOOT_DRIVER(at91_main_rc_clk) = {
+ .name = UBOOT_DM_CLK_AT91_MAIN_RC,
+ .id = UCLASS_CLK,
+ .ops = &main_rc_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
-static int main_osc_clk_probe(struct udevice *dev)
+static int clk_main_osc_enable(struct clk *clk)
{
- return at91_pmc_core_probe(dev);
+ struct clk_main_osc *main = to_clk_main_osc(clk);
+ void __iomem *reg = main->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+ val &= ~MOR_KEY_MASK;
+
+ if (val & AT91_PMC_OSCBYPASS)
+ return 0;
+
+ if (!(val & AT91_PMC_MOSCEN)) {
+ val |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
+ pmc_write(reg, AT91_CKGR_MOR, val);
+ }
+
+ pmc_read(reg, AT91_PMC_SR, &val);
+ while (!(val & AT91_PMC_MOSCS)) {
+ pmc_read(reg, AT91_PMC_SR, &val);
+ debug("waiting for main osc..\n");
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int clk_main_osc_disable(struct clk *clk)
+{
+ struct clk_main_osc *main = to_clk_main_osc(clk);
+ void __iomem *reg = main->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+ if (val & AT91_PMC_OSCBYPASS)
+ return 0;
+
+ if (!(val & AT91_PMC_MOSCEN))
+ return 0;
+
+ val &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
+ pmc_write(reg, AT91_CKGR_MOR, val | AT91_PMC_KEY);
+
+ return 0;
}
-static const struct udevice_id main_osc_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-main" },
- {}
+static const struct clk_ops main_osc_clk_ops = {
+ .enable = clk_main_osc_enable,
+ .disable = clk_main_osc_disable,
+ .get_rate = clk_generic_get_rate,
};
-U_BOOT_DRIVER(at91sam9x5_main_osc_clk) = {
- .name = "at91sam9x5-main-osc-clk",
+struct clk *at91_clk_main_osc(void __iomem *reg, const char *name,
+ const char *parent_name, bool bypass)
+{
+ struct clk_main_osc *main;
+ struct clk *clk;
+ int ret;
+
+ if (!reg || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ main = kzalloc(sizeof(*main), GFP_KERNEL);
+ if (!main)
+ return ERR_PTR(-ENOMEM);
+
+ main->reg = reg;
+ clk = &main->clk;
+
+ if (bypass) {
+ pmc_update_bits(reg, AT91_CKGR_MOR,
+ MOR_KEY_MASK | AT91_PMC_OSCBYPASS,
+ AT91_PMC_KEY | AT91_PMC_OSCBYPASS);
+ }
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_OSC, name, parent_name);
+ if (ret) {
+ kfree(main);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_main_osc_clk) = {
+ .name = UBOOT_DM_CLK_AT91_MAIN_OSC,
.id = UCLASS_CLK,
- .of_match = main_osc_clk_match,
- .probe = main_osc_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
.ops = &main_osc_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int clk_main_probe_frequency(void __iomem *reg)
+{
+ unsigned int cycles = 16;
+ unsigned int cycle = DIV_ROUND_UP(USEC_PER_SEC, SLOW_CLOCK_FREQ);
+ unsigned int mcfr;
+
+ while (cycles--) {
+ pmc_read(reg, AT91_CKGR_MCFR, &mcfr);
+ if (mcfr & AT91_PMC_MAINRDY)
+ return 0;
+ udelay(cycle);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int clk_rm9200_main_enable(struct clk *clk)
+{
+ struct clk_main *main = to_clk_main(clk);
+
+ return clk_main_probe_frequency(main->reg);
+}
+
+static const struct clk_ops rm9200_main_clk_ops = {
+ .enable = clk_rm9200_main_enable,
+};
+
+struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name,
+ const char *parent_name)
+{
+ struct clk_main *main;
+ struct clk *clk;
+ int ret;
+
+ if (!reg || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ main = kzalloc(sizeof(*main), GFP_KERNEL);
+ if (!main)
+ return ERR_PTR(-ENOMEM);
+
+ main->reg = reg;
+ clk = &main->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_RM9200_MAIN, name,
+ parent_name);
+ if (ret) {
+ kfree(main);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_rm9200_main_clk) = {
+ .name = UBOOT_DM_CLK_AT91_RM9200_MAIN,
+ .id = UCLASS_CLK,
+ .ops = &rm9200_main_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static inline bool clk_sam9x5_main_ready(void __iomem *reg)
+{
+ unsigned int val;
+
+ pmc_read(reg, AT91_PMC_SR, &val);
+
+ return !!(val & AT91_PMC_MOSCSELS);
+}
+
+static int clk_sam9x5_main_enable(struct clk *clk)
+{
+ struct clk_main *main = to_clk_main(clk);
+ void __iomem *reg = main->reg;
+
+ while (!clk_sam9x5_main_ready(reg)) {
+ debug("waiting for main...");
+ cpu_relax();
+ }
+
+ return clk_main_probe_frequency(reg);
+}
+
+static int clk_sam9x5_main_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_main *main = to_clk_main(clk);
+ void __iomem *reg = main->reg;
+ unsigned int tmp, index;
+
+ index = at91_clk_mux_val_to_index(main->clk_mux_table,
+ main->num_parents, AT91_CLK_ID_TO_DID(parent->id));
+ if (index < 0)
+ return index;
+
+ pmc_read(reg, AT91_CKGR_MOR, &tmp);
+ tmp &= ~MOR_KEY_MASK;
+ tmp |= AT91_PMC_KEY;
+
+ if (index && !(tmp & AT91_PMC_MOSCSEL))
+ pmc_write(reg, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
+ else if (!index && (tmp & AT91_PMC_MOSCSEL))
+ pmc_write(reg, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
+
+ while (!clk_sam9x5_main_ready(reg))
+ cpu_relax();
+
+ return 0;
+}
+
+static const struct clk_ops sam9x5_main_clk_ops = {
+ .enable = clk_sam9x5_main_enable,
+ .set_parent = clk_sam9x5_main_set_parent,
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name,
+ const char * const *parent_names,
+ int num_parents, const u32 *clk_mux_table,
+ int type)
+{
+ struct clk *clk = ERR_PTR(-ENOMEM);
+ struct clk_main *main = NULL;
+ unsigned int val;
+ int ret;
+
+ if (!reg || !name || !parent_names || !num_parents || !clk_mux_table)
+ return ERR_PTR(-EINVAL);
+
+ main = kzalloc(sizeof(*main), GFP_KERNEL);
+ if (!main)
+ return ERR_PTR(-ENOMEM);
+
+ main->reg = reg;
+ main->parent_names = parent_names;
+ main->num_parents = num_parents;
+ main->clk_mux_table = clk_mux_table;
+ main->type = type;
+ clk = &main->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_MAIN, name,
+ main->parent_names[clk_main_parent_select(val)]);
+ if (ret) {
+ kfree(main);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sam9x5_main_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X5_MAIN,
+ .id = UCLASS_CLK,
+ .ops = &sam9x5_main_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index e078fab7b4..759df93697 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -1,33 +1,332 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Master clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-master.c from Linux.
*/
-#include <common.h>
+#include <asm/processor.h>
#include <clk-uclass.h>
+#include <common.h>
#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_MASTER "at91-master-clk"
+#define UBOOT_DM_CLK_AT91_SAMA7G5_MASTER "at91-sama7g5-master-clk"
+
+#define MASTER_PRES_MASK 0x7
+#define MASTER_PRES_MAX MASTER_PRES_MASK
+#define MASTER_DIV_SHIFT 8
+#define MASTER_DIV_MASK 0x3
+
+#define PMC_MCR 0x30
+#define PMC_MCR_ID_MSK GENMASK(3, 0)
+#define PMC_MCR_CMD BIT(7)
+#define PMC_MCR_DIV GENMASK(10, 8)
+#define PMC_MCR_CSS GENMASK(20, 16)
+#define PMC_MCR_CSS_SHIFT (16)
+#define PMC_MCR_EN BIT(28)
+
+#define PMC_MCR_ID(x) ((x) & PMC_MCR_ID_MSK)
+
+#define MASTER_MAX_ID 4
+
+struct clk_master {
+ void __iomem *base;
+ const struct clk_master_layout *layout;
+ const struct clk_master_characteristics *characteristics;
+ const u32 *mux_table;
+ const u32 *clk_mux_table;
+ u32 num_parents;
+ struct clk clk;
+ u8 id;
+};
+
+#define to_clk_master(_clk) container_of(_clk, struct clk_master, clk)
+
+static inline bool clk_master_ready(struct clk_master *master)
+{
+ unsigned int bit = master->id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY;
+ unsigned int status;
+
+ pmc_read(master->base, AT91_PMC_SR, &status);
+
+ return !!(status & bit);
+}
+
+static int clk_master_enable(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+
+ while (!clk_master_ready(master)) {
+ debug("waiting for mck %d\n", master->id);
+ cpu_relax();
+ }
+
+ return 0;
+}
-DECLARE_GLOBAL_DATA_PTR;
+static ulong clk_master_get_rate(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+ const struct clk_master_layout *layout = master->layout;
+ const struct clk_master_characteristics *characteristics =
+ master->characteristics;
+ ulong rate = clk_get_parent_rate(clk);
+ unsigned int mckr;
+ u8 pres, div;
+
+ if (!rate)
+ return 0;
+
+ pmc_read(master->base, master->layout->offset, &mckr);
+ mckr &= layout->mask;
+
+ pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
+ div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
+
+ if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
+ rate /= 3;
+ else
+ rate >>= pres;
+
+ rate /= characteristics->divisors[div];
+
+ if (rate < characteristics->output.min)
+ pr_warn("master clk is underclocked");
+ else if (rate > characteristics->output.max)
+ pr_warn("master clk is overclocked");
+
+ return rate;
+}
+
+static const struct clk_ops master_ops = {
+ .enable = clk_master_enable,
+ .get_rate = clk_master_get_rate,
+};
-static ulong at91_master_clk_get_rate(struct clk *clk)
+struct clk *at91_clk_register_master(void __iomem *base,
+ const char *name, const char * const *parent_names,
+ int num_parents, const struct clk_master_layout *layout,
+ const struct clk_master_characteristics *characteristics,
+ const u32 *mux_table)
{
- return gd->arch.mck_rate_hz;
+ struct clk_master *master;
+ struct clk *clk;
+ unsigned int val;
+ int ret;
+
+ if (!base || !name || !num_parents || !parent_names ||
+ !layout || !characteristics || !mux_table)
+ return ERR_PTR(-EINVAL);
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return ERR_PTR(-ENOMEM);
+
+ master->layout = layout;
+ master->characteristics = characteristics;
+ master->base = base;
+ master->num_parents = num_parents;
+ master->mux_table = mux_table;
+
+ pmc_read(master->base, master->layout->offset, &val);
+ clk = &master->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_MASTER, name,
+ parent_names[val & AT91_PMC_CSS]);
+ if (ret) {
+ kfree(master);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
}
-static struct clk_ops at91_master_clk_ops = {
- .get_rate = at91_master_clk_get_rate,
+U_BOOT_DRIVER(at91_master_clk) = {
+ .name = UBOOT_DM_CLK_AT91_MASTER,
+ .id = UCLASS_CLK,
+ .ops = &master_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
-static const struct udevice_id at91_master_clk_match[] = {
- { .compatible = "atmel,at91rm9200-clk-master" },
- { .compatible = "atmel,at91sam9x5-clk-master" },
- {}
+static int clk_sama7g5_master_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_master *master = to_clk_master(clk);
+ int index;
+
+ index = at91_clk_mux_val_to_index(master->clk_mux_table,
+ master->num_parents, parent->id);
+ if (index < 0)
+ return index;
+
+ index = at91_clk_mux_index_to_val(master->mux_table,
+ master->num_parents, index);
+ if (index < 0)
+ return index;
+
+ pmc_write(master->base, PMC_MCR, PMC_MCR_ID(master->id));
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_CSS | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ (index << PMC_MCR_CSS_SHIFT) | PMC_MCR_CMD |
+ PMC_MCR_ID(master->id));
+ return 0;
+}
+
+static int clk_sama7g5_master_enable(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+
+ pmc_write(master->base, PMC_MCR, PMC_MCR_ID(master->id));
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID(master->id));
+
+ return 0;
+}
+
+static int clk_sama7g5_master_disable(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ PMC_MCR_CMD | PMC_MCR_ID(master->id));
+
+ return 0;
+}
+
+static ulong clk_sama7g5_master_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_master *master = to_clk_master(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ ulong div, rrate;
+
+ if (!parent_rate)
+ return 0;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ if ((div > (1 << (MASTER_PRES_MAX - 1))) || (div & (div - 1))) {
+ return 0;
+ } else if (div == 3) {
+ rrate = DIV_ROUND_CLOSEST(parent_rate, MASTER_PRES_MAX);
+ div = MASTER_PRES_MAX;
+ } else {
+ rrate = DIV_ROUND_CLOSEST(parent_rate, div);
+ div = ffs(div) - 1;
+ }
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_DIV | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ (div << MASTER_DIV_SHIFT) | PMC_MCR_CMD |
+ PMC_MCR_ID(master->id));
+
+ return rrate;
+}
+
+static ulong clk_sama7g5_master_get_rate(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ unsigned int val;
+ ulong div;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_read(master->base, PMC_MCR, &val);
+
+ div = (val >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
+
+ if (div == MASTER_PRES_MAX)
+ div = 3;
+ else
+ div = 1 << div;
+
+ return DIV_ROUND_CLOSEST(parent_rate, div);
+}
+
+static const struct clk_ops sama7g5_master_ops = {
+ .enable = clk_sama7g5_master_enable,
+ .disable = clk_sama7g5_master_disable,
+ .set_rate = clk_sama7g5_master_set_rate,
+ .get_rate = clk_sama7g5_master_get_rate,
+ .set_parent = clk_sama7g5_master_set_parent,
};
-U_BOOT_DRIVER(atmel_at91rm9200_clk_master) = {
- .name = "atmel_at91rm9200_clk_master",
+struct clk *at91_clk_sama7g5_register_master(void __iomem *base,
+ const char *name, const char * const *parent_names,
+ int num_parents, const u32 *mux_table, const u32 *clk_mux_table,
+ bool critical, u8 id)
+{
+ struct clk_master *master;
+ struct clk *clk;
+ u32 val, index;
+ int ret;
+
+ if (!base || !name || !num_parents || !parent_names ||
+ !mux_table || !clk_mux_table || id > MASTER_MAX_ID)
+ return ERR_PTR(-EINVAL);
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return ERR_PTR(-ENOMEM);
+
+ master->base = base;
+ master->id = id;
+ master->mux_table = mux_table;
+ master->clk_mux_table = clk_mux_table;
+ master->num_parents = num_parents;
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_read(master->base, PMC_MCR, &val);
+
+ index = at91_clk_mux_val_to_index(master->mux_table,
+ master->num_parents,
+ (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT);
+ if (index < 0) {
+ kfree(master);
+ return ERR_PTR(index);
+ }
+
+ clk = &master->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0);
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_MASTER, name,
+ parent_names[index]);
+ if (ret) {
+ kfree(master);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sama7g5_master_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAMA7G5_MASTER,
.id = UCLASS_CLK,
- .of_match = at91_master_clk_match,
- .ops = &at91_master_clk_ops,
+ .ops = &sama7g5_master_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+const struct clk_master_layout at91rm9200_master_layout = {
+ .mask = 0x31F,
+ .pres_shift = 2,
+ .offset = AT91_PMC_MCKR,
+};
+
+const struct clk_master_layout at91sam9x5_master_layout = {
+ .mask = 0x373,
+ .pres_shift = 4,
+ .offset = AT91_PMC_MCKR,
};
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index cd9d5e77c0..52cbc520ce 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -1,113 +1,254 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Peripheral clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-peripheral.c from Linux.
*/
-
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
-#include <malloc.h>
#include <linux/io.h>
-#include <mach/at91_pmc.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
#include "pmc.h"
+#define UBOOT_DM_CLK_AT91_PERIPH "at91-periph-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X5_PERIPH "at91-sam9x5-periph-clk"
+
#define PERIPHERAL_ID_MIN 2
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
-enum periph_clk_type {
- CLK_PERIPH_AT91RM9200 = 0,
- CLK_PERIPH_AT91SAM9X5,
+#define PERIPHERAL_MAX_SHIFT 3
+
+struct clk_peripheral {
+ void __iomem *base;
+ struct clk clk;
+ u32 id;
};
-/**
- * sam9x5_periph_clk_bind() - for the periph clock driver
- * Recursively bind its children as clk devices.
- *
- * @return: 0 on success, or negative error code on failure
- */
-static int sam9x5_periph_clk_bind(struct udevice *dev)
+
+#define to_clk_peripheral(_c) container_of(_c, struct clk_peripheral, clk)
+
+struct clk_sam9x5_peripheral {
+ const struct clk_pcr_layout *layout;
+ void __iomem *base;
+ struct clk clk;
+ struct clk_range range;
+ u32 id;
+ u32 div;
+ bool auto_div;
+};
+
+#define to_clk_sam9x5_peripheral(_c) \
+ container_of(_c, struct clk_sam9x5_peripheral, clk)
+
+static int clk_peripheral_enable(struct clk *clk)
{
- return at91_clk_sub_device_bind(dev, "periph-clk");
+ struct clk_peripheral *periph = to_clk_peripheral(clk);
+ int offset = AT91_PMC_PCER;
+ u32 id = periph->id;
+
+ if (id < PERIPHERAL_ID_MIN)
+ return 0;
+ if (id > PERIPHERAL_ID_MAX)
+ offset = AT91_PMC_PCER1;
+ pmc_write(periph->base, offset, PERIPHERAL_MASK(id));
+
+ return 0;
+}
+
+static int clk_peripheral_disable(struct clk *clk)
+{
+ struct clk_peripheral *periph = to_clk_peripheral(clk);
+ int offset = AT91_PMC_PCDR;
+ u32 id = periph->id;
+
+ if (id < PERIPHERAL_ID_MIN)
+ return -EINVAL;
+
+ if (id > PERIPHERAL_ID_MAX)
+ offset = AT91_PMC_PCDR1;
+ pmc_write(periph->base, offset, PERIPHERAL_MASK(id));
+
+ return 0;
}
-static const struct udevice_id sam9x5_periph_clk_match[] = {
- {
- .compatible = "atmel,at91rm9200-clk-peripheral",
- .data = CLK_PERIPH_AT91RM9200,
- },
- {
- .compatible = "atmel,at91sam9x5-clk-peripheral",
- .data = CLK_PERIPH_AT91SAM9X5,
- },
- {}
+static const struct clk_ops peripheral_ops = {
+ .enable = clk_peripheral_enable,
+ .disable = clk_peripheral_disable,
+ .get_rate = clk_generic_get_rate,
};
-U_BOOT_DRIVER(atmel_at91rm9200_clk_peripheral) = {
- .name = "atmel_at91rm9200_clk_peripheral",
- .id = UCLASS_MISC,
- .of_match = sam9x5_periph_clk_match,
- .bind = sam9x5_periph_clk_bind,
+struct clk *
+at91_clk_register_peripheral(void __iomem *base, const char *name,
+ const char *parent_name, u32 id)
+{
+ struct clk_peripheral *periph;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !name || !parent_name || id > PERIPHERAL_ID_MAX)
+ return ERR_PTR(-EINVAL);
+
+ periph = kzalloc(sizeof(*periph), GFP_KERNEL);
+ if (!periph)
+ return ERR_PTR(-ENOMEM);
+
+ periph->id = id;
+ periph->base = base;
+
+ clk = &periph->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_PERIPH, name, parent_name);
+ if (ret) {
+ kfree(periph);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_periph_clk) = {
+ .name = UBOOT_DM_CLK_AT91_PERIPH,
+ .id = UCLASS_CLK,
+ .ops = &peripheral_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
-/*---------------------------------------------------------*/
+static int clk_sam9x5_peripheral_enable(struct clk *clk)
+{
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+ if (periph->id < PERIPHERAL_ID_MIN)
+ return 0;
+
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_update_bits(periph->base, periph->layout->offset,
+ periph->layout->cmd | AT91_PMC_PCR_EN,
+ periph->layout->cmd | AT91_PMC_PCR_EN);
-static int periph_clk_enable(struct clk *clk)
+ return 0;
+}
+
+static int clk_sam9x5_peripheral_disable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- enum periph_clk_type clk_type;
- void *addr;
-
- if (clk->id < PERIPHERAL_ID_MIN)
- return -1;
-
- clk_type = dev_get_driver_data(dev_get_parent(clk->dev));
- if (clk_type == CLK_PERIPH_AT91RM9200) {
- addr = &pmc->pcer;
- if (clk->id > PERIPHERAL_ID_MAX)
- addr = &pmc->pcer1;
-
- setbits_le32(addr, PERIPHERAL_MASK(clk->id));
- } else {
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- setbits_le32(&pmc->pcr,
- AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
- }
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+ if (periph->id < PERIPHERAL_ID_MIN)
+ return -EINVAL;
+
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_update_bits(periph->base, periph->layout->offset,
+ AT91_PMC_PCR_EN | periph->layout->cmd,
+ periph->layout->cmd);
return 0;
}
-static ulong periph_get_rate(struct clk *clk)
+static ulong clk_sam9x5_peripheral_get_rate(struct clk *clk)
{
- struct udevice *dev;
- struct clk clk_dev;
- ulong clk_rate;
- int ret;
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 val, shift = ffs(periph->layout->div_mask) - 1;
- dev = dev_get_parent(clk->dev);
+ if (!parent_rate)
+ return 0;
- ret = clk_get_by_index(dev, 0, &clk_dev);
- if (ret)
- return ret;
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_read(periph->base, periph->layout->offset, &val);
+ shift = (val & periph->layout->div_mask) >> shift;
- clk_rate = clk_get_rate(&clk_dev);
+ return parent_rate >> shift;
+}
+
+static ulong clk_sam9x5_peripheral_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ int shift;
+
+ if (!parent_rate)
+ return 0;
+
+ if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
+ if (parent_rate == rate)
+ return rate;
+ else
+ return 0;
+ }
+
+ if (periph->range.max && rate > periph->range.max)
+ return 0;
+
+ for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+ if (parent_rate >> shift <= rate)
+ break;
+ }
+ if (shift == PERIPHERAL_MAX_SHIFT + 1)
+ return 0;
- clk_free(&clk_dev);
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_update_bits(periph->base, periph->layout->offset,
+ periph->layout->div_mask | periph->layout->cmd,
+ (shift << (ffs(periph->layout->div_mask) - 1)) |
+ periph->layout->cmd);
- return clk_rate;
+ return parent_rate >> shift;
}
-static struct clk_ops periph_clk_ops = {
- .of_xlate = at91_clk_of_xlate,
- .enable = periph_clk_enable,
- .get_rate = periph_get_rate,
+static const struct clk_ops sam9x5_peripheral_ops = {
+ .enable = clk_sam9x5_peripheral_enable,
+ .disable = clk_sam9x5_peripheral_disable,
+ .get_rate = clk_sam9x5_peripheral_get_rate,
+ .set_rate = clk_sam9x5_peripheral_set_rate,
};
-U_BOOT_DRIVER(clk_periph) = {
- .name = "periph-clk",
- .id = UCLASS_CLK,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .probe = at91_clk_probe,
- .ops = &periph_clk_ops,
+struct clk *
+at91_clk_register_sam9x5_peripheral(void __iomem *base,
+ const struct clk_pcr_layout *layout,
+ const char *name, const char *parent_name,
+ u32 id, const struct clk_range *range)
+{
+ struct clk_sam9x5_peripheral *periph;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !layout || !name || !parent_name || !range)
+ return ERR_PTR(-EINVAL);
+
+ periph = kzalloc(sizeof(*periph), GFP_KERNEL);
+ if (!periph)
+ return ERR_PTR(-ENOMEM);
+
+ periph->id = id;
+ periph->base = base;
+ periph->layout = layout;
+ periph->range = *range;
+
+ clk = &periph->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_PERIPH, name,
+ parent_name);
+ if (ret) {
+ kfree(periph);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sam9x5_periph_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X5_PERIPH,
+ .id = UCLASS_CLK,
+ .ops = &sam9x5_peripheral_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/clk-plla.c b/drivers/clk/at91/clk-plla.c
deleted file mode 100644
index 79d725819f..0000000000
--- a/drivers/clk/at91/clk-plla.c
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static int plla_clk_enable(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
-
- if (readl(&pmc->sr) & AT91_PMC_LOCKA)
- return 0;
-
- return -EINVAL;
-}
-
-static ulong plla_clk_get_rate(struct clk *clk)
-{
- return gd->arch.plla_rate_hz;
-}
-
-static struct clk_ops plla_clk_ops = {
- .enable = plla_clk_enable,
- .get_rate = plla_clk_get_rate,
-};
-
-static int plla_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id plla_clk_match[] = {
- { .compatible = "atmel,sama5d3-clk-pll" },
- {}
-};
-
-U_BOOT_DRIVER(at91_plla_clk) = {
- .name = "at91-plla-clk",
- .id = UCLASS_CLK,
- .of_match = plla_clk_match,
- .probe = plla_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &plla_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-plladiv.c b/drivers/clk/at91/clk-plladiv.c
deleted file mode 100644
index ca6158ef6a..0000000000
--- a/drivers/clk/at91/clk-plladiv.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018 Microhip / Atmel Corporation
- * Wenyou.Yang <wenyou.yang@microchip.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm/device.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-static int at91_plladiv_clk_enable(struct clk *clk)
-{
- return 0;
-}
-
-static ulong at91_plladiv_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk source;
- ulong clk_rate;
- int ret;
-
- ret = clk_get_by_index(clk->dev, 0, &source);
- if (ret)
- return -EINVAL;
-
- clk_rate = clk_get_rate(&source);
- if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2)
- clk_rate /= 2;
-
- return clk_rate;
-}
-
-static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk source;
- ulong parent_rate;
- int ret;
-
- ret = clk_get_by_index(clk->dev, 0, &source);
- if (ret)
- return -EINVAL;
-
- parent_rate = clk_get_rate(&source);
- if ((parent_rate != rate) && ((parent_rate) / 2 != rate))
- return -EINVAL;
-
- if (parent_rate != rate) {
- writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2),
- &pmc->mckr);
- }
-
- return 0;
-}
-
-static struct clk_ops at91_plladiv_clk_ops = {
- .enable = at91_plladiv_clk_enable,
- .get_rate = at91_plladiv_clk_get_rate,
- .set_rate = at91_plladiv_clk_set_rate,
-};
-
-static int at91_plladiv_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id at91_plladiv_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-plldiv" },
- {}
-};
-
-U_BOOT_DRIVER(at91_plladiv_clk) = {
- .name = "at91-plladiv-clk",
- .id = UCLASS_CLK,
- .of_match = at91_plladiv_clk_match,
- .probe = at91_plladiv_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &at91_plladiv_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
new file mode 100644
index 0000000000..868de4b177
--- /dev/null
+++ b/drivers/clk/at91/clk-programmable.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Programmable clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-programmable.c from Linux.
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_PROG "at91-prog-clk"
+
+#define PROG_ID_MAX 7
+
+#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
+#define PROG_PRES(_l, _p) (((_p) >> (_l)->pres_shift) & (_l)->pres_mask)
+#define PROG_MAX_RM9200_CSS 3
+
+struct clk_programmable {
+ void __iomem *base;
+ const u32 *clk_mux_table;
+ const u32 *mux_table;
+ const struct clk_programmable_layout *layout;
+ u32 num_parents;
+ struct clk clk;
+ u8 id;
+};
+
+#define to_clk_programmable(_c) container_of(_c, struct clk_programmable, clk)
+
+static ulong clk_programmable_get_rate(struct clk *clk)
+{
+ struct clk_programmable *prog = to_clk_programmable(clk);
+ const struct clk_programmable_layout *layout = prog->layout;
+ ulong rate, parent_rate = clk_get_parent_rate(clk);
+ unsigned int pckr;
+
+ pmc_read(prog->base, AT91_PMC_PCKR(prog->id), &pckr);
+
+ if (layout->is_pres_direct)
+ rate = parent_rate / (PROG_PRES(layout, pckr) + 1);
+ else
+ rate = parent_rate >> PROG_PRES(layout, pckr);
+
+ return rate;
+}
+
+static int clk_programmable_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_programmable *prog = to_clk_programmable(clk);
+ const struct clk_programmable_layout *layout = prog->layout;
+ unsigned int mask = layout->css_mask;
+ int index;
+
+ index = at91_clk_mux_val_to_index(prog->clk_mux_table,
+ prog->num_parents, parent->id);
+ if (index < 0)
+ return index;
+
+ index = at91_clk_mux_index_to_val(prog->mux_table, prog->num_parents,
+ index);
+ if (index < 0)
+ return index;
+
+ if (layout->have_slck_mck)
+ mask |= AT91_PMC_CSSMCK_MCK;
+
+ if (index > layout->css_mask) {
+ if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
+ return -EINVAL;
+
+ index |= AT91_PMC_CSSMCK_MCK;
+ }
+
+ pmc_update_bits(prog->base, AT91_PMC_PCKR(prog->id), mask, index);
+
+ return 0;
+}
+
+static ulong clk_programmable_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_programmable *prog = to_clk_programmable(clk);
+ const struct clk_programmable_layout *layout = prog->layout;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ ulong div = parent_rate / rate;
+ int shift = 0;
+
+ if (!parent_rate || !div)
+ return -EINVAL;
+
+ if (layout->is_pres_direct) {
+ shift = div - 1;
+
+ if (shift > layout->pres_mask)
+ return -EINVAL;
+ } else {
+ shift = fls(div) - 1;
+
+ if (div != (1 << shift))
+ return -EINVAL;
+
+ if (shift >= layout->pres_mask)
+ return -EINVAL;
+ }
+
+ pmc_update_bits(prog->base, AT91_PMC_PCKR(prog->id),
+ layout->pres_mask << layout->pres_shift,
+ shift << layout->pres_shift);
+
+ if (layout->is_pres_direct)
+ return (parent_rate / shift + 1);
+
+ return parent_rate >> shift;
+}
+
+static const struct clk_ops programmable_ops = {
+ .get_rate = clk_programmable_get_rate,
+ .set_parent = clk_programmable_set_parent,
+ .set_rate = clk_programmable_set_rate,
+};
+
+struct clk *at91_clk_register_programmable(void __iomem *base, const char *name,
+ const char *const *parent_names, u8 num_parents, u8 id,
+ const struct clk_programmable_layout *layout,
+ const u32 *clk_mux_table, const u32 *mux_table)
+{
+ struct clk_programmable *prog;
+ struct clk *clk;
+ u32 val, tmp;
+ int ret;
+
+ if (!base || !name || !parent_names || !num_parents ||
+ !layout || !clk_mux_table || !mux_table || id > PROG_ID_MAX)
+ return ERR_PTR(-EINVAL);
+
+ prog = kzalloc(sizeof(*prog), GFP_KERNEL);
+ if (!prog)
+ return ERR_PTR(-ENOMEM);
+
+ prog->id = id;
+ prog->layout = layout;
+ prog->base = base;
+ prog->clk_mux_table = clk_mux_table;
+ prog->mux_table = mux_table;
+ prog->num_parents = num_parents;
+
+ pmc_read(prog->base, AT91_PMC_PCKR(prog->id), &tmp);
+ val = tmp & prog->layout->css_mask;
+ if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !val)
+ ret = PROG_MAX_RM9200_CSS + 1;
+ else
+ ret = at91_clk_mux_val_to_index(prog->mux_table,
+ prog->num_parents, val);
+ if (ret < 0) {
+ kfree(prog);
+ return ERR_PTR(ret);
+ }
+
+ clk = &prog->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_PROG, name,
+ parent_names[ret]);
+ if (ret) {
+ kfree(prog);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_prog_clk) = {
+ .name = UBOOT_DM_CLK_AT91_PROG,
+ .id = UCLASS_CLK,
+ .ops = &programmable_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+const struct clk_programmable_layout at91rm9200_programmable_layout = {
+ .pres_mask = 0x7,
+ .pres_shift = 2,
+ .css_mask = 0x3,
+ .have_slck_mck = 0,
+ .is_pres_direct = 0,
+};
+
+const struct clk_programmable_layout at91sam9g45_programmable_layout = {
+ .pres_mask = 0x7,
+ .pres_shift = 2,
+ .css_mask = 0x3,
+ .have_slck_mck = 1,
+ .is_pres_direct = 0,
+};
+
+const struct clk_programmable_layout at91sam9x5_programmable_layout = {
+ .pres_mask = 0x7,
+ .pres_shift = 4,
+ .css_mask = 0x7,
+ .have_slck_mck = 0,
+ .is_pres_direct = 0,
+};
diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c
new file mode 100644
index 0000000000..1bfae5fd01
--- /dev/null
+++ b/drivers/clk/at91/clk-sam9x60-pll.c
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SAM9X60's PLL clock support.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-sam9x60-pll.c from Linux.
+ *
+ */
+
+#include <asm/processor.h>
+#include <common.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/delay.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL "at91-sam9x60-div-pll-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL "at91-sam9x60-frac-pll-clk"
+
+#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0)
+#define PMC_PLL_CTRL1_MUL_MSK GENMASK(31, 24)
+#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
+
+#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
+#define UPLL_DIV 2
+#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
+
+#define FCORE_MIN (600000000)
+#define FCORE_MAX (1200000000)
+
+#define PLL_MAX_ID 7
+
+struct sam9x60_pll {
+ void __iomem *base;
+ const struct clk_pll_characteristics *characteristics;
+ const struct clk_pll_layout *layout;
+ struct clk clk;
+ u8 id;
+};
+
+#define to_sam9x60_pll(_clk) container_of(_clk, struct sam9x60_pll, clk)
+
+static inline bool sam9x60_pll_ready(void __iomem *base, int id)
+{
+ unsigned int status;
+
+ pmc_read(base, AT91_PMC_PLL_ISR0, &status);
+
+ return !!(status & BIT(id));
+}
+
+static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
+ ulong parent_rate)
+{
+ unsigned long tmprate, remainder;
+ unsigned long nmul = 0;
+ unsigned long nfrac = 0;
+
+ if (rate < FCORE_MIN || rate > FCORE_MAX)
+ return -ERANGE;
+
+ /*
+ * Calculate the multiplier associated with the current
+ * divider that provide the closest rate to the requested one.
+ */
+ nmul = mult_frac(rate, 1, parent_rate);
+ tmprate = mult_frac(parent_rate, nmul, 1);
+ remainder = rate - tmprate;
+
+ if (remainder) {
+ nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
+ parent_rate);
+
+ tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
+ (1 << 22));
+ }
+
+ /* Check if resulted rate is valid. */
+ if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
+ return -ERANGE;
+
+ *mul = nmul - 1;
+ *frac = nfrac;
+
+ return tmprate;
+}
+
+static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 nmul, cmul, nfrac, cfrac, val;
+ bool ready = sam9x60_pll_ready(base, pll->id);
+ long ret;
+
+ if (!parent_rate)
+ return 0;
+
+ ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate,
+ parent_rate);
+ if (ret < 0)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
+ cmul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
+ cfrac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
+
+ /* Check against current values. */
+ if (sam9x60_pll_ready(base, pll->id) &&
+ nmul == cmul && nfrac == cfrac)
+ return 0;
+
+ /* Update it to hardware. */
+ pmc_write(base, AT91_PMC_PLL_CTRL1,
+ (nmul << pll->layout->mul_shift) |
+ (nfrac << pll->layout->frac_shift));
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (ready && !sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return parent_rate * (nmul + 1) + ((u64)parent_rate * nfrac >> 22);
+}
+
+static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 mul, frac, val;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
+ mul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
+ frac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
+
+ return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
+}
+
+static int sam9x60_frac_pll_enable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ unsigned int val;
+ ulong crate;
+
+ crate = sam9x60_frac_pll_get_rate(clk);
+ if (crate < FCORE_MIN || crate > FCORE_MAX)
+ return -ERANGE;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
+
+ if (sam9x60_pll_ready(base, pll->id))
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PMM_UPDT_STUPTIM_MSK |
+ AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id);
+
+ /* Recommended value for AT91_PMC_PLL_ACR */
+ if (pll->characteristics->upll)
+ val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
+ else
+ val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
+ pmc_write(base, AT91_PMC_PLL_ACR, val);
+
+ if (pll->characteristics->upll) {
+ /* Enable the UTMI internal bandgap */
+ val |= AT91_PMC_PLL_ACR_UTMIBG;
+ pmc_write(base, AT91_PMC_PLL_ACR, val);
+
+ udelay(10);
+
+ /* Enable the UTMI internal regulator */
+ val |= AT91_PMC_PLL_ACR_UTMIVR;
+ pmc_write(base, AT91_PMC_PLL_ACR, val);
+
+ udelay(10);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE |
+ AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+ }
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
+ AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (!sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int sam9x60_frac_pll_disable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ AT91_PMC_PLL_CTRL0_ENPLL, 0);
+
+ if (pll->characteristics->upll)
+ pmc_update_bits(base, AT91_PMC_PLL_ACR,
+ AT91_PMC_PLL_ACR_UTMIBG |
+ AT91_PMC_PLL_ACR_UTMIVR, 0);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ return 0;
+}
+
+static const struct clk_ops sam9x60_frac_pll_ops = {
+ .enable = sam9x60_frac_pll_enable,
+ .disable = sam9x60_frac_pll_disable,
+ .set_rate = sam9x60_frac_pll_set_rate,
+ .get_rate = sam9x60_frac_pll_get_rate,
+};
+
+static int sam9x60_div_pll_enable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ unsigned int val;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
+
+ /* Stop if enabled. */
+ if (val & pll->layout->endiv_mask)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ pll->layout->endiv_mask,
+ (1 << pll->layout->endiv_shift));
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (!sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int sam9x60_div_pll_disable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ pll->layout->endiv_mask, 0);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ return 0;
+}
+
+static ulong sam9x60_div_pll_set_rate(struct clk *clk, ulong rate)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ const struct clk_pll_characteristics *characteristics =
+ pll->characteristics;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u8 div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate) - 1;
+ ulong req_rate = parent_rate / (div + 1);
+ bool ready = sam9x60_pll_ready(base, pll->id);
+ u32 val;
+
+ if (!parent_rate || div > pll->layout->div_mask ||
+ req_rate < characteristics->output[0].min ||
+ req_rate > characteristics->output[0].max)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
+ /* Compare against current value. */
+ if (div == ((val & pll->layout->div_mask) >> pll->layout->div_shift))
+ return 0;
+
+ /* Update it to hardware. */
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ pll->layout->div_mask,
+ div << pll->layout->div_shift);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (ready && !sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return req_rate;
+}
+
+static ulong sam9x60_div_pll_get_rate(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 val;
+ u8 div;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+
+ pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
+
+ div = (val & pll->layout->div_mask) >> pll->layout->div_shift;
+
+ return parent_rate / (div + 1);
+}
+
+static const struct clk_ops sam9x60_div_pll_ops = {
+ .enable = sam9x60_div_pll_enable,
+ .disable = sam9x60_div_pll_disable,
+ .set_rate = sam9x60_div_pll_set_rate,
+ .get_rate = sam9x60_div_pll_get_rate,
+};
+
+static struct clk *
+sam9x60_clk_register_pll(void __iomem *base, const char *type,
+ const char *name, const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, u32 flags)
+{
+ struct sam9x60_pll *pll;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !type || !name || !parent_name || !characteristics ||
+ !layout || id > PLL_MAX_ID)
+ return ERR_PTR(-EINVAL);
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->id = id;
+ pll->characteristics = characteristics;
+ pll->layout = layout;
+ pll->base = base;
+ clk = &pll->clk;
+ clk->flags = flags;
+
+ ret = clk_register(clk, type, name, parent_name);
+ if (ret) {
+ kfree(pll);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+struct clk *
+sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical)
+{
+ return sam9x60_clk_register_pll(base,
+ UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, name, parent_name, id,
+ characteristics, layout,
+ CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
+}
+
+struct clk *
+sam9x60_clk_register_frac_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical)
+{
+ return sam9x60_clk_register_pll(base,
+ UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL, name, parent_name, id,
+ characteristics, layout,
+ CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
+}
+
+U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_div_pll_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_frac_pll_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
deleted file mode 100644
index 1f8665768b..0000000000
--- a/drivers/clk/at91/clk-slow.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-
-static int at91_slow_clk_enable(struct clk *clk)
-{
- return 0;
-}
-
-static ulong at91_slow_clk_get_rate(struct clk *clk)
-{
- return CONFIG_SYS_AT91_SLOW_CLOCK;
-}
-
-static struct clk_ops at91_slow_clk_ops = {
- .enable = at91_slow_clk_enable,
- .get_rate = at91_slow_clk_get_rate,
-};
-
-static const struct udevice_id at91_slow_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-slow" },
- {}
-};
-
-U_BOOT_DRIVER(at91_slow_clk) = {
- .name = "at91-slow-clk",
- .id = UCLASS_CLK,
- .of_match = at91_slow_clk_match,
- .ops = &at91_slow_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 76b1958670..82f79e74a1 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -1,111 +1,112 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * System clock support for AT91 architectures.
+ *
+ * Copyright (C) Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-system.c from Linux.
*/
-
+#include <asm/processor.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
-#include <linux/bitops.h>
#include <linux/io.h>
-#include <mach/at91_pmc.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
#include "pmc.h"
-#define SYSTEM_MAX_ID 31
+#define UBOOT_DM_CLK_AT91_SYSTEM "at91-system-clk"
-/**
- * at91_system_clk_bind() - for the system clock driver
- * Recursively bind its children as clk devices.
- *
- * @return: 0 on success, or negative error code on failure
- */
-static int at91_system_clk_bind(struct udevice *dev)
-{
- return at91_clk_sub_device_bind(dev, "system-clk");
-}
-
-static const struct udevice_id at91_system_clk_match[] = {
- { .compatible = "atmel,at91rm9200-clk-system" },
- {}
-};
+#define SYSTEM_MAX_ID 31
-U_BOOT_DRIVER(at91_system_clk) = {
- .name = "at91-system-clk",
- .id = UCLASS_MISC,
- .of_match = at91_system_clk_match,
- .bind = at91_system_clk_bind,
+struct clk_system {
+ void __iomem *base;
+ struct clk clk;
+ u8 id;
};
-/*----------------------------------------------------------*/
+#define to_clk_system(_c) container_of(_c, struct clk_system, clk)
static inline int is_pck(int id)
{
return (id >= 8) && (id <= 15);
}
-static ulong system_clk_get_rate(struct clk *clk)
+static inline bool clk_system_ready(void __iomem *base, int id)
{
- struct clk clk_dev;
- int ret;
+ unsigned int status;
- ret = clk_get_by_index(clk->dev, 0, &clk_dev);
- if (ret)
- return -EINVAL;
+ pmc_read(base, AT91_PMC_SR, &status);
- return clk_get_rate(&clk_dev);
+ return !!(status & (1 << id));
}
-static ulong system_clk_set_rate(struct clk *clk, ulong rate)
+static int clk_system_enable(struct clk *clk)
{
- struct clk clk_dev;
- int ret;
+ struct clk_system *sys = to_clk_system(clk);
- ret = clk_get_by_index(clk->dev, 0, &clk_dev);
- if (ret)
- return -EINVAL;
+ pmc_write(sys->base, AT91_PMC_SCER, 1 << sys->id);
- return clk_set_rate(&clk_dev, rate);
+ if (!is_pck(sys->id))
+ return 0;
+
+ while (!clk_system_ready(sys->base, sys->id)) {
+ debug("waiting for pck%u\n", sys->id);
+ cpu_relax();
+ }
+
+ return 0;
}
-static int system_clk_enable(struct clk *clk)
+static int clk_system_disable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- u32 mask;
+ struct clk_system *sys = to_clk_system(clk);
- if (clk->id > SYSTEM_MAX_ID)
- return -EINVAL;
+ pmc_write(sys->base, AT91_PMC_SCDR, 1 << sys->id);
- mask = BIT(clk->id);
+ return 0;
+}
- writel(mask, &pmc->scer);
+static const struct clk_ops system_ops = {
+ .enable = clk_system_enable,
+ .disable = clk_system_disable,
+ .get_rate = clk_generic_get_rate,
+};
- /**
- * For the programmable clocks the Ready status in the PMC
- * status register should be checked after enabling.
- * For other clocks this is unnecessary.
- */
- if (!is_pck(clk->id))
- return 0;
+struct clk *at91_clk_register_system(void __iomem *base, const char *name,
+ const char *parent_name, u8 id)
+{
+ struct clk_system *sys;
+ struct clk *clk;
+ int ret;
- while (!(readl(&pmc->sr) & mask))
- ;
+ if (!base || !name || !parent_name || id > SYSTEM_MAX_ID)
+ return ERR_PTR(-EINVAL);
- return 0;
-}
+ sys = kzalloc(sizeof(*sys), GFP_KERNEL);
+ if (!sys)
+ return ERR_PTR(-ENOMEM);
-static struct clk_ops system_clk_ops = {
- .of_xlate = at91_clk_of_xlate,
- .get_rate = system_clk_get_rate,
- .set_rate = system_clk_set_rate,
- .enable = system_clk_enable,
-};
+ sys->id = id;
+ sys->base = base;
-U_BOOT_DRIVER(system_clk) = {
- .name = "system-clk",
+ clk = &sys->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SYSTEM, name, parent_name);
+ if (ret) {
+ kfree(sys);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_system_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SYSTEM,
.id = UCLASS_CLK,
- .probe = at91_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &system_clk_ops,
+ .ops = &system_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
deleted file mode 100644
index af9d724369..0000000000
--- a/drivers/clk/at91/clk-usb.c
+++ /dev/null
@@ -1,147 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018 Microhip / Atmel Corporation
- * Wenyou.Yang <wenyou.yang@microchip.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <log.h>
-#include <dm/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define AT91_USB_CLK_SOURCE_MAX 2
-#define AT91_USB_CLK_MAX_DIV 15
-
-struct at91_usb_clk_priv {
- u32 num_clksource;
-};
-
-static ulong at91_usb_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk source;
- u32 tmp, usbdiv;
- u8 source_index;
- int ret;
-
- tmp = readl(&pmc->pcr);
- source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) &
- AT91_PMC_USB_USBS_MASK;
- usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK;
-
- ret = clk_get_by_index(clk->dev, source_index, &source);
- if (ret)
- return 0;
-
- return clk_get_rate(&source) / (usbdiv + 1);
-}
-
-static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev);
- struct clk source, best_source;
- ulong tmp_rate, best_rate = rate, source_rate;
- int tmp_diff, best_diff = -1;
- u32 div, best_div = 0;
- u8 best_source_index = 0;
- u8 i;
- u32 tmp;
- int ret;
-
- for (i = 0; i < priv->num_clksource; i++) {
- ret = clk_get_by_index(clk->dev, i, &source);
- if (ret)
- return ret;
-
- source_rate = clk_get_rate(&source);
- if (IS_ERR_VALUE(source_rate))
- return source_rate;
-
- for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) {
- tmp_rate = DIV_ROUND_CLOSEST(source_rate, div);
- tmp_diff = abs(rate - tmp_rate);
-
- if (best_diff < 0 || best_diff > tmp_diff) {
- best_rate = tmp_rate;
- best_diff = tmp_diff;
-
- best_div = div - 1;
- best_source = source;
- best_source_index = i;
- }
-
- if (!best_diff || tmp_rate < rate)
- break;
- }
-
- if (!best_diff)
- break;
- }
-
- debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n",
- best_source.dev->name, best_rate, best_div);
-
- ret = clk_enable(&best_source);
- if (ret)
- return ret;
-
- tmp = AT91_PMC_USB_USBS_(best_source_index) |
- AT91_PMC_USB_DIV_(best_div);
- writel(tmp, &pmc->usb);
-
- return 0;
-}
-
-static struct clk_ops at91_usb_clk_ops = {
- .get_rate = at91_usb_clk_get_rate,
- .set_rate = at91_usb_clk_set_rate,
-};
-
-static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev)
-{
- struct at91_usb_clk_priv *priv = dev_get_priv(dev);
- u32 cells[AT91_USB_CLK_SOURCE_MAX];
- u32 num_clksource;
-
- num_clksource = fdtdec_get_int_array_count(gd->fdt_blob,
- dev_of_offset(dev),
- "clocks", cells,
- AT91_USB_CLK_SOURCE_MAX);
-
- if (!num_clksource)
- return -1;
-
- priv->num_clksource = num_clksource;
-
- return 0;
-}
-
-static int at91_usb_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id at91_usb_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-usb" },
- {}
-};
-
-U_BOOT_DRIVER(at91_usb_clk) = {
- .name = "at91-usb-clk",
- .id = UCLASS_CLK,
- .of_match = at91_usb_clk_match,
- .probe = at91_usb_clk_probe,
- .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv),
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &at91_usb_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index 18af0bfeaa..7c8bcfb51d 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -1,49 +1,65 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * UTMI clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-utmi.c from Linux.
*/
-
+#include <asm/processor.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
-#include <syscon.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
#include <mach/at91_sfr.h>
+#include <regmap.h>
+#include <syscon.h>
+
#include "pmc.h"
+#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk"
+#define UBOOT_DM_CLK_AT91_SAMA7G5_UTMI "at91-sama7g5-utmi-clk"
+
/*
* The purpose of this clock is to generate a 480 MHz signal. A different
* rate can't be configured.
*/
#define UTMI_RATE 480000000
-static int utmi_clk_enable(struct clk *clk)
+struct clk_utmi {
+ void __iomem *base;
+ struct regmap *regmap_sfr;
+ struct clk clk;
+};
+
+#define to_clk_utmi(_clk) container_of(_clk, struct clk_utmi, clk)
+
+static inline bool clk_utmi_ready(struct regmap *regmap)
+{
+ unsigned int status;
+
+ pmc_read(regmap, AT91_PMC_SR, &status);
+
+ return !!(status & AT91_PMC_LOCKU);
+}
+
+static int clk_utmi_enable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk clk_dev;
- ulong clk_rate;
- u32 utmi_ref_clk_freq;
- u32 tmp;
- int err;
- int timeout = 2000000;
-
- if (readl(&pmc->sr) & AT91_PMC_LOCKU)
- return 0;
+ struct clk_utmi *utmi = to_clk_utmi(clk);
+ unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
+ AT91_PMC_BIASEN;
+ unsigned int utmi_ref_clk_freq;
+ ulong parent_rate = clk_get_parent_rate(clk);
/*
* If mainck rate is different from 12 MHz, we have to configure the
* FREQ field of the SFR_UTMICKTRIM register to generate properly
* the utmi clock.
*/
- err = clk_get_by_index(clk->dev, 0, &clk_dev);
- if (err)
- return -EINVAL;
-
- clk_rate = clk_get_rate(&clk_dev);
- switch (clk_rate) {
+ switch (parent_rate) {
case 12000000:
utmi_ref_clk_freq = 0;
break;
@@ -61,82 +77,158 @@ static int utmi_clk_enable(struct clk *clk)
utmi_ref_clk_freq = 3;
break;
default:
- printf("UTMICK: unsupported mainck rate\n");
+ debug("UTMICK: unsupported mainck rate\n");
return -EINVAL;
}
- if (plat->regmap_sfr) {
- err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp);
- if (err)
- return -EINVAL;
-
- tmp &= ~AT91_UTMICKTRIM_FREQ;
- tmp |= utmi_ref_clk_freq;
- err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp);
- if (err)
- return -EINVAL;
+ if (utmi->regmap_sfr) {
+ regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
+ AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
} else if (utmi_ref_clk_freq) {
- printf("UTMICK: sfr node required\n");
+ debug("UTMICK: sfr node required\n");
return -EINVAL;
}
- tmp = readl(&pmc->uckr);
- tmp |= AT91_PMC_UPLLEN |
- AT91_PMC_UPLLCOUNT |
- AT91_PMC_BIASEN;
- writel(tmp, &pmc->uckr);
-
- while ((--timeout) && !(readl(&pmc->sr) & AT91_PMC_LOCKU))
- ;
- if (!timeout) {
- printf("UTMICK: timeout waiting for UPLL lock\n");
- return -ETIMEDOUT;
+ pmc_update_bits(utmi->base, AT91_CKGR_UCKR, uckr, uckr);
+
+ while (!clk_utmi_ready(utmi->base)) {
+ debug("waiting for utmi...\n");
+ cpu_relax();
}
return 0;
}
-static ulong utmi_clk_get_rate(struct clk *clk)
+static int clk_utmi_disable(struct clk *clk)
+{
+ struct clk_utmi *utmi = to_clk_utmi(clk);
+
+ pmc_update_bits(utmi->base, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
+
+ return 0;
+}
+
+static ulong clk_utmi_get_rate(struct clk *clk)
{
/* UTMI clk rate is fixed. */
return UTMI_RATE;
}
-static struct clk_ops utmi_clk_ops = {
- .enable = utmi_clk_enable,
- .get_rate = utmi_clk_get_rate,
+static const struct clk_ops utmi_ops = {
+ .enable = clk_utmi_enable,
+ .disable = clk_utmi_disable,
+ .get_rate = clk_utmi_get_rate,
};
-static int utmi_clk_ofdata_to_platdata(struct udevice *dev)
+struct clk *at91_clk_register_utmi(void __iomem *base, struct udevice *dev,
+ const char *name, const char *parent_name)
{
- struct pmc_platdata *plat = dev_get_platdata(dev);
struct udevice *syscon;
+ struct clk_utmi *utmi;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !dev || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "regmap-sfr", &syscon);
+ if (ret)
+ return ERR_PTR(ret);
+
+ utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
+ if (!utmi)
+ return ERR_PTR(-ENOMEM);
+
+ utmi->base = base;
+ utmi->regmap_sfr = syscon_get_regmap(syscon);
+ if (!utmi->regmap_sfr) {
+ kfree(utmi);
+ return ERR_PTR(-ENODEV);
+ }
- uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
- "regmap-sfr", &syscon);
-
- if (syscon)
- plat->regmap_sfr = syscon_get_regmap(syscon);
+ clk = &utmi->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_UTMI, name, parent_name);
+ if (ret) {
+ kfree(utmi);
+ clk = ERR_PTR(ret);
+ }
- return 0;
+ return clk;
}
-static int utmi_clk_probe(struct udevice *dev)
+U_BOOT_DRIVER(at91_utmi_clk) = {
+ .name = UBOOT_DM_CLK_AT91_UTMI,
+ .id = UCLASS_CLK,
+ .ops = &utmi_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int clk_utmi_sama7g5_enable(struct clk *clk)
{
- return at91_pmc_core_probe(dev);
+ struct clk_utmi *utmi = to_clk_utmi(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ unsigned int val;
+
+ switch (parent_rate) {
+ case 16000000:
+ val = 0;
+ break;
+ case 20000000:
+ val = 2;
+ break;
+ case 24000000:
+ val = 3;
+ break;
+ case 32000000:
+ val = 5;
+ break;
+ default:
+ debug("UTMICK: unsupported main_xtal rate\n");
+ return -EINVAL;
+ }
+
+ pmc_write(utmi->base, AT91_PMC_XTALF, val);
+
+ return 0;
}
-static const struct udevice_id utmi_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-utmi" },
- {}
+static const struct clk_ops sama7g5_utmi_ops = {
+ .enable = clk_utmi_sama7g5_enable,
+ .get_rate = clk_utmi_get_rate,
};
-U_BOOT_DRIVER(at91sam9x5_utmi_clk) = {
- .name = "at91sam9x5-utmi-clk",
+struct clk *at91_clk_sama7g5_register_utmi(void __iomem *base,
+ const char *name, const char *parent_name)
+{
+ struct clk_utmi *utmi;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
+ if (!utmi)
+ return ERR_PTR(-ENOMEM);
+
+ utmi->base = base;
+
+ clk = &utmi->clk;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_UTMI, name,
+ parent_name);
+ if (ret) {
+ kfree(utmi);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sama7g5_utmi_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAMA7G5_UTMI,
.id = UCLASS_CLK,
- .of_match = utmi_clk_match,
- .probe = utmi_clk_probe,
- .ofdata_to_platdata = utmi_clk_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &utmi_clk_ops,
+ .ops = &sama7g5_utmi_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/compat.c b/drivers/clk/at91/compat.c
new file mode 100644
index 0000000000..8cf6254046
--- /dev/null
+++ b/drivers/clk/at91/compat.c
@@ -0,0 +1,1023 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Compatible code for non CCF AT91 platforms.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/util.h>
+#include <mach/at91_pmc.h>
+#include <mach/at91_sfr.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include "pmc.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pmc_platdata {
+ struct at91_pmc *reg_base;
+ struct regmap *regmap_sfr;
+};
+
+static const struct udevice_id at91_pmc_match[] = {
+ { .compatible = "atmel,at91rm9200-pmc" },
+ { .compatible = "atmel,at91sam9260-pmc" },
+ { .compatible = "atmel,at91sam9g45-pmc" },
+ { .compatible = "atmel,at91sam9n12-pmc" },
+ { .compatible = "atmel,at91sam9x5-pmc" },
+ { .compatible = "atmel,sama5d3-pmc" },
+ { .compatible = "atmel,sama5d2-pmc" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_pmc) = {
+ .name = "at91-pmc",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = at91_pmc_match,
+};
+
+static int at91_pmc_core_probe(struct udevice *dev)
+{
+ struct pmc_platdata *plat = dev_get_platdata(dev);
+
+ dev = dev_get_parent(dev);
+
+ plat->reg_base = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+/**
+ * at91_clk_sub_device_bind() - for the at91 clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
+{
+ const void *fdt = gd->fdt_blob;
+ int offset = dev_of_offset(dev);
+ bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+ const char *name;
+ int ret;
+
+ for (offset = fdt_first_subnode(fdt, offset);
+ offset > 0;
+ offset = fdt_next_subnode(fdt, offset)) {
+ if (pre_reloc_only &&
+ !ofnode_pre_reloc(offset_to_ofnode(offset)))
+ continue;
+ /*
+ * If this node has "compatible" property, this is not
+ * a clock sub-node, but a normal device. skip.
+ */
+ fdt_get_property(fdt, offset, "compatible", &ret);
+ if (ret >= 0)
+ continue;
+
+ if (ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ name = fdt_get_name(fdt, offset, NULL);
+ if (!name)
+ return -EINVAL;
+ ret = device_bind_driver_to_node(dev, drv_name, name,
+ offset_to_ofnode(offset), NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+{
+ int periph;
+
+ if (args->args_count) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg",
+ -1);
+ if (periph < 0)
+ return -EINVAL;
+
+ clk->id = periph;
+
+ return 0;
+}
+
+int at91_clk_probe(struct udevice *dev)
+{
+ struct udevice *dev_periph_container, *dev_pmc;
+ struct pmc_platdata *plat = dev_get_platdata(dev);
+
+ dev_periph_container = dev_get_parent(dev);
+ dev_pmc = dev_get_parent(dev_periph_container);
+
+ plat->reg_base = dev_read_addr_ptr(dev_pmc);
+
+ return 0;
+}
+
+/* SCKC specific code. */
+static const struct udevice_id at91_sckc_match[] = {
+ { .compatible = "atmel,at91sam9x5-sckc" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_sckc) = {
+ .name = "at91-sckc",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = at91_sckc_match,
+};
+
+/* Slow clock specific code. */
+static int at91_slow_clk_enable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong at91_slow_clk_get_rate(struct clk *clk)
+{
+ return CONFIG_SYS_AT91_SLOW_CLOCK;
+}
+
+static struct clk_ops at91_slow_clk_ops = {
+ .enable = at91_slow_clk_enable,
+ .get_rate = at91_slow_clk_get_rate,
+};
+
+static const struct udevice_id at91_slow_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-slow" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_slow_clk) = {
+ .name = "at91-slow-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_slow_clk_match,
+ .ops = &at91_slow_clk_ops,
+};
+
+/* Master clock specific code. */
+static ulong at91_master_clk_get_rate(struct clk *clk)
+{
+ return gd->arch.mck_rate_hz;
+}
+
+static struct clk_ops at91_master_clk_ops = {
+ .get_rate = at91_master_clk_get_rate,
+};
+
+static const struct udevice_id at91_master_clk_match[] = {
+ { .compatible = "atmel,at91rm9200-clk-master" },
+ { .compatible = "atmel,at91sam9x5-clk-master" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_master_clk) = {
+ .name = "at91-master-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_master_clk_match,
+ .ops = &at91_master_clk_ops,
+};
+
+/* Main osc clock specific code. */
+static int main_osc_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+
+ if (readl(&pmc->sr) & AT91_PMC_MOSCSELS)
+ return 0;
+
+ return -EINVAL;
+}
+
+static ulong main_osc_clk_get_rate(struct clk *clk)
+{
+ return gd->arch.main_clk_rate_hz;
+}
+
+static struct clk_ops main_osc_clk_ops = {
+ .enable = main_osc_clk_enable,
+ .get_rate = main_osc_clk_get_rate,
+};
+
+static int main_osc_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id main_osc_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-main" },
+ {}
+};
+
+U_BOOT_DRIVER(at91sam9x5_main_osc_clk) = {
+ .name = "at91sam9x5-main-osc-clk",
+ .id = UCLASS_CLK,
+ .of_match = main_osc_clk_match,
+ .probe = main_osc_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &main_osc_clk_ops,
+};
+
+/* PLLA clock specific code. */
+static int plla_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+
+ if (readl(&pmc->sr) & AT91_PMC_LOCKA)
+ return 0;
+
+ return -EINVAL;
+}
+
+static ulong plla_clk_get_rate(struct clk *clk)
+{
+ return gd->arch.plla_rate_hz;
+}
+
+static struct clk_ops plla_clk_ops = {
+ .enable = plla_clk_enable,
+ .get_rate = plla_clk_get_rate,
+};
+
+static int plla_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id plla_clk_match[] = {
+ { .compatible = "atmel,sama5d3-clk-pll" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_plla_clk) = {
+ .name = "at91-plla-clk",
+ .id = UCLASS_CLK,
+ .of_match = plla_clk_match,
+ .probe = plla_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &plla_clk_ops,
+};
+
+/* PLLA DIV clock specific code. */
+static int at91_plladiv_clk_enable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong at91_plladiv_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &source);
+ if (ret)
+ return -EINVAL;
+
+ clk_rate = clk_get_rate(&source);
+ if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2)
+ clk_rate /= 2;
+
+ return clk_rate;
+}
+
+static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ ulong parent_rate;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &source);
+ if (ret)
+ return -EINVAL;
+
+ parent_rate = clk_get_rate(&source);
+ if ((parent_rate != rate) && ((parent_rate) / 2 != rate))
+ return -EINVAL;
+
+ if (parent_rate != rate) {
+ writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2),
+ &pmc->mckr);
+ }
+
+ return 0;
+}
+
+static struct clk_ops at91_plladiv_clk_ops = {
+ .enable = at91_plladiv_clk_enable,
+ .get_rate = at91_plladiv_clk_get_rate,
+ .set_rate = at91_plladiv_clk_set_rate,
+};
+
+static int at91_plladiv_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id at91_plladiv_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-plldiv" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_plladiv_clk) = {
+ .name = "at91-plladiv-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_plladiv_clk_match,
+ .probe = at91_plladiv_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &at91_plladiv_clk_ops,
+};
+
+/* System clock specific code. */
+#define SYSTEM_MAX_ID 31
+
+/**
+ * at91_system_clk_bind() - for the system clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int at91_system_clk_bind(struct udevice *dev)
+{
+ return at91_clk_sub_device_bind(dev, "system-clk");
+}
+
+static const struct udevice_id at91_system_clk_match[] = {
+ { .compatible = "atmel,at91rm9200-clk-system" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_system_clk) = {
+ .name = "at91-system-clk",
+ .id = UCLASS_MISC,
+ .of_match = at91_system_clk_match,
+ .bind = at91_system_clk_bind,
+};
+
+static inline int is_pck(int id)
+{
+ return (id >= 8) && (id <= 15);
+}
+
+static ulong system_clk_get_rate(struct clk *clk)
+{
+ struct clk clk_dev;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (ret)
+ return -EINVAL;
+
+ return clk_get_rate(&clk_dev);
+}
+
+static ulong system_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk clk_dev;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (ret)
+ return -EINVAL;
+
+ return clk_set_rate(&clk_dev, rate);
+}
+
+static int system_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ u32 mask;
+
+ if (clk->id > SYSTEM_MAX_ID)
+ return -EINVAL;
+
+ mask = BIT(clk->id);
+
+ writel(mask, &pmc->scer);
+
+ /**
+ * For the programmable clocks the Ready status in the PMC
+ * status register should be checked after enabling.
+ * For other clocks this is unnecessary.
+ */
+ if (!is_pck(clk->id))
+ return 0;
+
+ while (!(readl(&pmc->sr) & mask))
+ ;
+
+ return 0;
+}
+
+static struct clk_ops system_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .get_rate = system_clk_get_rate,
+ .set_rate = system_clk_set_rate,
+ .enable = system_clk_enable,
+};
+
+U_BOOT_DRIVER(system_clk) = {
+ .name = "system-clk",
+ .id = UCLASS_CLK,
+ .probe = at91_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &system_clk_ops,
+};
+
+/* Peripheral clock specific code. */
+#define PERIPHERAL_ID_MIN 2
+#define PERIPHERAL_ID_MAX 31
+#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
+
+enum periph_clk_type {
+ CLK_PERIPH_AT91RM9200 = 0,
+ CLK_PERIPH_AT91SAM9X5,
+};
+
+/**
+ * sam9x5_periph_clk_bind() - for the periph clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int sam9x5_periph_clk_bind(struct udevice *dev)
+{
+ return at91_clk_sub_device_bind(dev, "periph-clk");
+}
+
+static const struct udevice_id sam9x5_periph_clk_match[] = {
+ {
+ .compatible = "atmel,at91rm9200-clk-peripheral",
+ .data = CLK_PERIPH_AT91RM9200,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-clk-peripheral",
+ .data = CLK_PERIPH_AT91SAM9X5,
+ },
+ {}
+};
+
+U_BOOT_DRIVER(sam9x5_periph_clk) = {
+ .name = "sam9x5-periph-clk",
+ .id = UCLASS_MISC,
+ .of_match = sam9x5_periph_clk_match,
+ .bind = sam9x5_periph_clk_bind,
+};
+
+static int periph_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ enum periph_clk_type clk_type;
+ void *addr;
+
+ if (clk->id < PERIPHERAL_ID_MIN)
+ return -1;
+
+ clk_type = dev_get_driver_data(dev_get_parent(clk->dev));
+ if (clk_type == CLK_PERIPH_AT91RM9200) {
+ addr = &pmc->pcer;
+ if (clk->id > PERIPHERAL_ID_MAX)
+ addr = &pmc->pcer1;
+
+ setbits_le32(addr, PERIPHERAL_MASK(clk->id));
+ } else {
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ setbits_le32(&pmc->pcr,
+ AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
+ }
+
+ return 0;
+}
+
+static ulong periph_get_rate(struct clk *clk)
+{
+ struct udevice *dev;
+ struct clk clk_dev;
+ ulong clk_rate;
+ int ret;
+
+ dev = dev_get_parent(clk->dev);
+
+ ret = clk_get_by_index(dev, 0, &clk_dev);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(&clk_dev);
+
+ clk_free(&clk_dev);
+
+ return clk_rate;
+}
+
+static struct clk_ops periph_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .enable = periph_clk_enable,
+ .get_rate = periph_get_rate,
+};
+
+U_BOOT_DRIVER(clk_periph) = {
+ .name = "periph-clk",
+ .id = UCLASS_CLK,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .probe = at91_clk_probe,
+ .ops = &periph_clk_ops,
+};
+
+/* UTMI clock specific code. */
+#ifdef CONFIG_AT91_UTMI
+
+/*
+ * The purpose of this clock is to generate a 480 MHz signal. A different
+ * rate can't be configured.
+ */
+#define UTMI_RATE 480000000
+
+static int utmi_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk clk_dev;
+ ulong clk_rate;
+ u32 utmi_ref_clk_freq;
+ u32 tmp;
+ int err;
+ int timeout = 2000000;
+
+ if (readl(&pmc->sr) & AT91_PMC_LOCKU)
+ return 0;
+
+ /*
+ * If mainck rate is different from 12 MHz, we have to configure the
+ * FREQ field of the SFR_UTMICKTRIM register to generate properly
+ * the utmi clock.
+ */
+ err = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (err)
+ return -EINVAL;
+
+ clk_rate = clk_get_rate(&clk_dev);
+ switch (clk_rate) {
+ case 12000000:
+ utmi_ref_clk_freq = 0;
+ break;
+ case 16000000:
+ utmi_ref_clk_freq = 1;
+ break;
+ case 24000000:
+ utmi_ref_clk_freq = 2;
+ break;
+ /*
+ * Not supported on SAMA5D2 but it's not an issue since MAINCK
+ * maximum value is 24 MHz.
+ */
+ case 48000000:
+ utmi_ref_clk_freq = 3;
+ break;
+ default:
+ printf("UTMICK: unsupported mainck rate\n");
+ return -EINVAL;
+ }
+
+ if (plat->regmap_sfr) {
+ err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp);
+ if (err)
+ return -EINVAL;
+
+ tmp &= ~AT91_UTMICKTRIM_FREQ;
+ tmp |= utmi_ref_clk_freq;
+ err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp);
+ if (err)
+ return -EINVAL;
+ } else if (utmi_ref_clk_freq) {
+ printf("UTMICK: sfr node required\n");
+ return -EINVAL;
+ }
+
+ tmp = readl(&pmc->uckr);
+ tmp |= AT91_PMC_UPLLEN |
+ AT91_PMC_UPLLCOUNT |
+ AT91_PMC_BIASEN;
+ writel(tmp, &pmc->uckr);
+
+ while ((--timeout) && !(readl(&pmc->sr) & AT91_PMC_LOCKU))
+ ;
+ if (!timeout) {
+ printf("UTMICK: timeout waiting for UPLL lock\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static ulong utmi_clk_get_rate(struct clk *clk)
+{
+ /* UTMI clk rate is fixed. */
+ return UTMI_RATE;
+}
+
+static struct clk_ops utmi_clk_ops = {
+ .enable = utmi_clk_enable,
+ .get_rate = utmi_clk_get_rate,
+};
+
+static int utmi_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct pmc_platdata *plat = dev_get_platdata(dev);
+ struct udevice *syscon;
+
+ uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "regmap-sfr", &syscon);
+
+ if (syscon)
+ plat->regmap_sfr = syscon_get_regmap(syscon);
+
+ return 0;
+}
+
+static int utmi_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id utmi_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-utmi" },
+ {}
+};
+
+U_BOOT_DRIVER(at91sam9x5_utmi_clk) = {
+ .name = "at91sam9x5-utmi-clk",
+ .id = UCLASS_CLK,
+ .of_match = utmi_clk_match,
+ .probe = utmi_clk_probe,
+ .ofdata_to_platdata = utmi_clk_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &utmi_clk_ops,
+};
+
+#endif /* CONFIG_AT91_UTMI */
+
+/* H32MX clock specific code. */
+#ifdef CONFIG_AT91_H32MX
+
+#define H32MX_MAX_FREQ 90000000
+
+static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ ulong rate = gd->arch.mck_rate_hz;
+
+ if (readl(&pmc->mckr) & AT91_PMC_MCKR_H32MXDIV)
+ rate /= 2;
+
+ if (rate > H32MX_MAX_FREQ)
+ dev_dbg(clk->dev, "H32MX clock is too fast\n");
+
+ return rate;
+}
+
+static struct clk_ops sama5d4_h32mx_clk_ops = {
+ .get_rate = sama5d4_h32mx_clk_get_rate,
+};
+
+static int sama5d4_h32mx_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id sama5d4_h32mx_clk_match[] = {
+ { .compatible = "atmel,sama5d4-clk-h32mx" },
+ {}
+};
+
+U_BOOT_DRIVER(sama5d4_h32mx_clk) = {
+ .name = "sama5d4-h32mx-clk",
+ .id = UCLASS_CLK,
+ .of_match = sama5d4_h32mx_clk_match,
+ .probe = sama5d4_h32mx_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &sama5d4_h32mx_clk_ops,
+};
+
+#endif /* CONFIG_AT91_H32MX */
+
+/* Generic clock specific code. */
+#ifdef CONFIG_AT91_GENERIC_CLK
+
+#define GENERATED_SOURCE_MAX 6
+#define GENERATED_MAX_DIV 255
+
+/**
+ * generated_clk_bind() - for the generated clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int generated_clk_bind(struct udevice *dev)
+{
+ return at91_clk_sub_device_bind(dev, "generic-clk");
+}
+
+static const struct udevice_id generated_clk_match[] = {
+ { .compatible = "atmel,sama5d2-clk-generated" },
+ {}
+};
+
+U_BOOT_DRIVER(generated_clk) = {
+ .name = "generated-clk",
+ .id = UCLASS_MISC,
+ .of_match = generated_clk_match,
+ .bind = generated_clk_bind,
+};
+
+struct generic_clk_priv {
+ u32 num_parents;
+};
+
+static ulong generic_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk parent;
+ ulong clk_rate;
+ u32 tmp, gckdiv;
+ u8 clock_source, parent_index;
+ int ret;
+
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ tmp = readl(&pmc->pcr);
+ clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) &
+ AT91_PMC_PCR_GCKCSS_MASK;
+ gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
+
+ parent_index = clock_source - 1;
+ ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent);
+ if (ret)
+ return 0;
+
+ clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
+
+ clk_free(&parent);
+
+ return clk_rate;
+}
+
+static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct generic_clk_priv *priv = dev_get_priv(clk->dev);
+ struct clk parent, best_parent;
+ ulong tmp_rate, best_rate = rate, parent_rate;
+ int tmp_diff, best_diff = -1;
+ u32 div, best_div = 0;
+ u8 best_parent_index, best_clock_source = 0;
+ u8 i;
+ u32 tmp;
+ int ret;
+
+ for (i = 0; i < priv->num_parents; i++) {
+ ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
+ if (ret)
+ return ret;
+
+ parent_rate = clk_get_rate(&parent);
+ if (IS_ERR_VALUE(parent_rate))
+ return parent_rate;
+
+ for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
+ tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
+ tmp_diff = abs(rate - tmp_rate);
+
+ if (best_diff < 0 || best_diff > tmp_diff) {
+ best_rate = tmp_rate;
+ best_diff = tmp_diff;
+
+ best_div = div - 1;
+ best_parent = parent;
+ best_parent_index = i;
+ best_clock_source = best_parent_index + 1;
+ }
+
+ if (!best_diff || tmp_rate < rate)
+ break;
+ }
+
+ if (!best_diff)
+ break;
+ }
+
+ debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n",
+ best_parent.dev->name, best_rate, best_div);
+
+ ret = clk_enable(&best_parent);
+ if (ret)
+ return ret;
+
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ tmp = readl(&pmc->pcr);
+ tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS);
+ tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) |
+ AT91_PMC_PCR_CMD_WRITE |
+ AT91_PMC_PCR_GCKDIV_(best_div) |
+ AT91_PMC_PCR_GCKEN;
+ writel(tmp, &pmc->pcr);
+
+ while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY))
+ ;
+
+ return 0;
+}
+
+static struct clk_ops generic_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .get_rate = generic_clk_get_rate,
+ .set_rate = generic_clk_set_rate,
+};
+
+static int generic_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct generic_clk_priv *priv = dev_get_priv(dev);
+ u32 cells[GENERATED_SOURCE_MAX];
+ u32 num_parents;
+
+ num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
+ dev_of_offset(dev_get_parent(dev)), "clocks", cells,
+ GENERATED_SOURCE_MAX);
+
+ if (!num_parents)
+ return -1;
+
+ priv->num_parents = num_parents;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(generic_clk) = {
+ .name = "generic-clk",
+ .id = UCLASS_CLK,
+ .probe = at91_clk_probe,
+ .ofdata_to_platdata = generic_clk_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct generic_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &generic_clk_ops,
+};
+
+#endif /* CONFIG_AT91_GENERIC_CLK */
+
+/* USB clock specific code. */
+#ifdef CONFIG_AT91_USB_CLK
+
+#define AT91_USB_CLK_SOURCE_MAX 2
+#define AT91_USB_CLK_MAX_DIV 15
+
+struct at91_usb_clk_priv {
+ u32 num_clksource;
+};
+
+static ulong at91_usb_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ u32 tmp, usbdiv;
+ u8 source_index;
+ int ret;
+
+ tmp = readl(&pmc->pcr);
+ source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) &
+ AT91_PMC_USB_USBS_MASK;
+ usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK;
+
+ ret = clk_get_by_index(clk->dev, source_index, &source);
+ if (ret)
+ return 0;
+
+ return clk_get_rate(&source) / (usbdiv + 1);
+}
+
+static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev);
+ struct clk source, best_source;
+ ulong tmp_rate, best_rate = rate, source_rate;
+ int tmp_diff, best_diff = -1;
+ u32 div, best_div = 0;
+ u8 best_source_index = 0;
+ u8 i;
+ u32 tmp;
+ int ret;
+
+ for (i = 0; i < priv->num_clksource; i++) {
+ ret = clk_get_by_index(clk->dev, i, &source);
+ if (ret)
+ return ret;
+
+ source_rate = clk_get_rate(&source);
+ if (IS_ERR_VALUE(source_rate))
+ return source_rate;
+
+ for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) {
+ tmp_rate = DIV_ROUND_CLOSEST(source_rate, div);
+ tmp_diff = abs(rate - tmp_rate);
+
+ if (best_diff < 0 || best_diff > tmp_diff) {
+ best_rate = tmp_rate;
+ best_diff = tmp_diff;
+
+ best_div = div - 1;
+ best_source = source;
+ best_source_index = i;
+ }
+
+ if (!best_diff || tmp_rate < rate)
+ break;
+ }
+
+ if (!best_diff)
+ break;
+ }
+
+ debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n",
+ best_source.dev->name, best_rate, best_div);
+
+ ret = clk_enable(&best_source);
+ if (ret)
+ return ret;
+
+ tmp = AT91_PMC_USB_USBS_(best_source_index) |
+ AT91_PMC_USB_DIV_(best_div);
+ writel(tmp, &pmc->usb);
+
+ return 0;
+}
+
+static struct clk_ops at91_usb_clk_ops = {
+ .get_rate = at91_usb_clk_get_rate,
+ .set_rate = at91_usb_clk_set_rate,
+};
+
+static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct at91_usb_clk_priv *priv = dev_get_priv(dev);
+ u32 cells[AT91_USB_CLK_SOURCE_MAX];
+ u32 num_clksource;
+
+ num_clksource = fdtdec_get_int_array_count(gd->fdt_blob,
+ dev_of_offset(dev),
+ "clocks", cells,
+ AT91_USB_CLK_SOURCE_MAX);
+
+ if (!num_clksource)
+ return -1;
+
+ priv->num_clksource = num_clksource;
+
+ return 0;
+}
+
+static int at91_usb_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id at91_usb_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-usb" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_usb_clk) = {
+ .name = "at91-usb-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_usb_clk_match,
+ .probe = at91_usb_clk_probe,
+ .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &at91_usb_clk_ops,
+};
+
+#endif /* CONFIG_AT91_USB_CLK */
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index ca90abef2d..660e231921 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -4,119 +4,167 @@
* Wenyou.Yang <wenyou.yang@atmel.com>
*/
-#include <common.h>
+#include <asm/io.h>
#include <clk-uclass.h>
-#include <dm.h>
-#include <log.h>
-#include <dm/lists.h>
-#include <dm/util.h>
+#include <common.h>
+
#include "pmc.h"
-DECLARE_GLOBAL_DATA_PTR;
-
-static const struct udevice_id at91_pmc_match[] = {
- { .compatible = "atmel,at91rm9200-pmc" },
- { .compatible = "atmel,at91sam9260-pmc" },
- { .compatible = "atmel,at91sam9g45-pmc" },
- { .compatible = "atmel,at91sam9n12-pmc" },
- { .compatible = "atmel,at91sam9x5-pmc" },
- { .compatible = "atmel,sama5d3-pmc" },
- { .compatible = "atmel,sama5d2-pmc" },
- {}
-};
+static int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+{
+ if (args->args_count != 2) {
+ debug("AT91: clk: Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
-U_BOOT_DRIVER(atmel_at91rm9200_pmc) = {
- .name = "atmel_at91rm9200_pmc",
- .id = UCLASS_SIMPLE_BUS,
- .of_match = at91_pmc_match,
-};
+ clk->id = AT91_TO_CLK_ID(args->args[0], args->args[1]);
+
+ return 0;
+}
+
+static ulong at91_clk_get_rate(struct clk *clk)
+{
+ struct clk *c;
+ int ret;
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ return clk_get_rate(c);
+}
+
+static ulong at91_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk *c;
+ int ret;
-U_BOOT_DRIVER_ALIAS(atmel_at91rm9200_pmc, atmel_at91sam9260_pmc)
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
-/*---------------------------------------------------------*/
+ return clk_set_rate(c, rate);
+}
-int at91_pmc_core_probe(struct udevice *dev)
+static int at91_clk_enable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(dev);
+ struct clk *c;
+ int ret;
- dev = dev_get_parent(dev);
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
- plat->reg_base = dev_read_addr_ptr(dev);
+ return clk_enable(c);
+}
- return 0;
+static int at91_clk_disable(struct clk *clk)
+{
+ struct clk *c;
+ int ret;
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ return clk_disable(c);
}
+const struct clk_ops at91_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .set_rate = at91_clk_set_rate,
+ .get_rate = at91_clk_get_rate,
+ .enable = at91_clk_enable,
+ .disable = at91_clk_disable,
+};
+
/**
- * at91_clk_sub_device_bind() - for the at91 clock driver
- * Recursively bind its children as clk devices.
+ * pmc_read() - read content at address base + off into val
*
- * @return: 0 on success, or negative error code on failure
+ * @base: base address
+ * @off: offset to read from
+ * @val: where the content of base + off is stored
+ *
+ * @return: void
*/
-int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
+void pmc_read(void __iomem *base, unsigned int off, unsigned int *val)
{
- const void *fdt = gd->fdt_blob;
- int offset = dev_of_offset(dev);
- bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
- const char *name;
- int ret;
-
- for (offset = fdt_first_subnode(fdt, offset);
- offset > 0;
- offset = fdt_next_subnode(fdt, offset)) {
- if (pre_reloc_only &&
- !ofnode_pre_reloc(offset_to_ofnode(offset)))
- continue;
- /*
- * If this node has "compatible" property, this is not
- * a clock sub-node, but a normal device. skip.
- */
- fdt_get_property(fdt, offset, "compatible", &ret);
- if (ret >= 0)
- continue;
-
- if (ret != -FDT_ERR_NOTFOUND)
- return ret;
-
- name = fdt_get_name(fdt, offset, NULL);
- if (!name)
- return -EINVAL;
- ret = device_bind_driver_to_node(dev, drv_name, name,
- offset_to_ofnode(offset), NULL);
- if (ret)
- return ret;
- }
+ *val = readl(base + off);
+}
- return 0;
+/**
+ * pmc_write() - write content of val at address base + off
+ *
+ * @base: base address
+ * @off: offset to write to
+ * @val: content to be written at base + off
+ *
+ * @return: void
+ */
+void pmc_write(void __iomem *base, unsigned int off, unsigned int val)
+{
+ writel(val, base + off);
}
-int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+/**
+ * pmc_update_bits() - update a set of bits at address base + off
+ *
+ * @base: base address
+ * @off: offset to be updated
+ * @mask: mask of bits to be updated
+ * @bits: the new value to be updated
+ *
+ * @return: void
+ */
+void pmc_update_bits(void __iomem *base, unsigned int off,
+ unsigned int mask, unsigned int bits)
{
- int periph;
+ unsigned int tmp;
- if (args->args_count) {
- debug("Invalid args_count: %d\n", args->args_count);
- return -EINVAL;
- }
+ tmp = readl(base + off);
+ tmp &= ~mask;
+ writel(tmp | (bits & mask), base + off);
+}
- periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg",
- -1);
- if (periph < 0)
+/**
+ * at91_clk_mux_val_to_index() - get parent index in mux table
+ *
+ * @table: clock mux table
+ * @num_parents: clock number of parents
+ * @val: clock id who's mux index should be retrieved
+ *
+ * @return: clock index in mux table or a negative error number in case of
+ * failure
+ */
+int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val)
+{
+ int i;
+
+ if (!table || !num_parents)
return -EINVAL;
- clk->id = periph;
+ for (i = 0; i < num_parents; i++) {
+ if (table[i] == val)
+ return i;
+ }
- return 0;
+ return -EINVAL;
}
-int at91_clk_probe(struct udevice *dev)
+/**
+ * at91_clk_mux_index_to_val() - get parent ID corresponding to an entry in
+ * clock's mux table
+ *
+ * @table: clock's mux table
+ * @num_parents: clock's number of parents
+ * @index: index in mux table which clock's ID should be retrieved
+ *
+ * @return: clock ID or a negative error number in case of failure
+ */
+int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index)
{
- struct udevice *dev_periph_container, *dev_pmc;
- struct pmc_platdata *plat = dev_get_platdata(dev);
-
- dev_periph_container = dev_get_parent(dev);
- dev_pmc = dev_get_parent(dev_periph_container);
-
- plat->reg_base = dev_read_addr_ptr(dev_pmc);
+ if (!table || !num_parents || index < 0 || index > num_parents)
+ return -EINVAL;
- return 0;
+ return table[index];
}
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 517ba1d6b4..a6a714fd22 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -7,17 +7,141 @@
#ifndef __AT91_PMC_H__
#define __AT91_PMC_H__
-#include <regmap.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
-struct pmc_platdata {
- struct at91_pmc *reg_base;
- struct regmap *regmap_sfr;
+/* Keep a range of 256 available clocks for every clock type. */
+#define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff))
+#define AT91_CLK_ID_TO_DID(_i) ((_i) & 0xff)
+
+struct clk_range {
+ unsigned long min;
+ unsigned long max;
+};
+
+struct clk_master_layout {
+ u32 offset;
+ u32 mask;
+ u8 pres_shift;
};
-int at91_pmc_core_probe(struct udevice *dev);
-int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name);
+extern const struct clk_master_layout at91rm9200_master_layout;
+extern const struct clk_master_layout at91sam9x5_master_layout;
+
+struct clk_master_characteristics {
+ struct clk_range output;
+ u32 divisors[4];
+ u8 have_div3_pres;
+};
+
+struct clk_pll_characteristics {
+ struct clk_range input;
+ int num_output;
+ const struct clk_range *output;
+ u16 *icpll;
+ u8 *out;
+ u8 upll : 1;
+};
+
+struct clk_pll_layout {
+ u32 pllr_mask;
+ u32 mul_mask;
+ u32 frac_mask;
+ u32 div_mask;
+ u32 endiv_mask;
+ u8 mul_shift;
+ u8 frac_shift;
+ u8 div_shift;
+ u8 endiv_shift;
+};
+
+struct clk_programmable_layout {
+ u8 pres_mask;
+ u8 pres_shift;
+ u8 css_mask;
+ u8 have_slck_mck;
+ u8 is_pres_direct;
+};
+
+struct clk_pcr_layout {
+ u32 offset;
+ u32 cmd;
+ u32 div_mask;
+ u32 gckcss_mask;
+ u32 pid_mask;
+};
+
+extern const struct clk_programmable_layout at91rm9200_programmable_layout;
+extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
+extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
+
+extern const struct clk_ops at91_clk_ops;
+
+struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
+ const char *parent_name);
+struct clk *at91_clk_main_osc(void __iomem *reg, const char *name,
+ const char *parent_name, bool bypass);
+struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name,
+ const char *parent_name);
+struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name,
+ const char * const *parent_names, int num_parents,
+ const u32 *mux_table, int type);
+struct clk *
+sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical);
+struct clk *
+sam9x60_clk_register_frac_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical);
+struct clk *
+at91_clk_register_master(void __iomem *base, const char *name,
+ const char * const *parent_names, int num_parents,
+ const struct clk_master_layout *layout,
+ const struct clk_master_characteristics *characteristics,
+ const u32 *mux_table);
+struct clk *
+at91_clk_sama7g5_register_master(void __iomem *base, const char *name,
+ const char * const *parent_names, int num_parents,
+ const u32 *mux_table, const u32 *clk_mux_table,
+ bool critical, u8 id);
+struct clk *
+at91_clk_register_utmi(void __iomem *base, struct udevice *dev,
+ const char *name, const char *parent_name);
+struct clk *
+at91_clk_sama7g5_register_utmi(void __iomem *base, const char *name,
+ const char *parent_name);
+struct clk *
+at91_clk_register_programmable(void __iomem *base, const char *name,
+ const char * const *parent_names, u8 num_parents, u8 id,
+ const struct clk_programmable_layout *layout,
+ const u32 *clk_mux_table, const u32 *mux_table);
+struct clk *
+at91_clk_register_system(void __iomem *base, const char *name,
+ const char *parent_name, u8 id);
+struct clk *
+at91_clk_register_peripheral(void __iomem *base, const char *name,
+ const char *parent_name, u32 id);
+struct clk *
+at91_clk_register_sam9x5_peripheral(void __iomem *base,
+ const struct clk_pcr_layout *layout,
+ const char *name, const char *parent_name,
+ u32 id, const struct clk_range *range);
+struct clk *
+at91_clk_register_generic(void __iomem *base,
+ const struct clk_pcr_layout *layout, const char *name,
+ const char * const *parent_names,
+ const u32 *clk_mux_table, const u32 *mux_table,
+ u8 num_parents, u8 id, const struct clk_range *range);
+
+int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val);
+int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index);
-int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args);
-int at91_clk_probe(struct udevice *dev);
+void pmc_read(void __iomem *base, unsigned int off, unsigned int *val);
+void pmc_write(void __iomem *base, unsigned int off, unsigned int val);
+void pmc_update_bits(void __iomem *base, unsigned int off, unsigned int mask,
+ unsigned int bits);
#endif
diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
new file mode 100644
index 0000000000..b96937673b
--- /dev/null
+++ b/drivers/clk/at91/sama7g5.c
@@ -0,0 +1,1401 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SAMA7G5 PMC clock support.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/sama7g5.c from Linux.
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dt-bindings/clk/at91.h>
+#include <linux/clk-provider.h>
+
+#include "pmc.h"
+
+/**
+ * Clock identifiers to be used in conjunction with macros like
+ * AT91_TO_CLK_ID()
+ *
+ * @ID_MD_SLCK: TD slow clock identifier
+ * @ID_TD_SLCK: MD slow clock identifier
+ * @ID_MAIN_XTAL: Main Xtal clock identifier
+ * @ID_MAIN_RC: Main RC clock identifier
+ * @ID_MAIN_RC_OSC: Main RC Oscillator clock identifier
+ * @ID_MAIN_OSC: Main Oscillator clock identifier
+ * @ID_MAINCK: MAINCK clock identifier
+ * @ID_PLL_CPU_FRAC: CPU PLL fractional clock identifier
+ * @ID_PLL_CPU_DIV: CPU PLL divider clock identifier
+ * @ID_PLL_SYS_FRAC: SYS PLL fractional clock identifier
+ * @ID_PLL_SYS_DIV: SYS PLL divider clock identifier
+ * @ID_PLL_DDR_FRAC: DDR PLL fractional clock identifier
+ * @ID_PLL_DDR_DIV: DDR PLL divider clock identifier
+ * @ID_PLL_IMG_FRAC: IMC PLL fractional clock identifier
+ * @ID_PLL_IMG_DIV: IMG PLL divider clock identifier
+ * @ID_PLL_BAUD_FRAC: Baud PLL fractional clock identifier
+ * @ID_PLL_BAUD_DIV: Baud PLL divider clock identifier
+ * @ID_PLL_AUDIO_FRAC: Audio PLL fractional clock identifier
+ * @ID_PLL_AUDIO_DIVPMC: Audio PLL PMC divider clock identifier
+ * @ID_PLL_AUDIO_DIVIO: Audio PLL IO divider clock identifier
+ * @ID_PLL_ETH_FRAC: Ethernet PLL fractional clock identifier
+ * @ID_PLL_ETH_DIV: Ethernet PLL divider clock identifier
+
+ * @ID_MCK0: MCK0 clock identifier
+ * @ID_MCK1: MCK1 clock identifier
+ * @ID_MCK2: MCK2 clock identifier
+ * @ID_MCK3: MCK3 clock identifier
+ * @ID_MCK4: MCK4 clock identifier
+
+ * @ID_UTMI: UTMI clock identifier
+
+ * @ID_PROG0: Programmable 0 clock identifier
+ * @ID_PROG1: Programmable 1 clock identifier
+ * @ID_PROG2: Programmable 2 clock identifier
+ * @ID_PROG3: Programmable 3 clock identifier
+ * @ID_PROG4: Programmable 4 clock identifier
+ * @ID_PROG5: Programmable 5 clock identifier
+ * @ID_PROG6: Programmable 6 clock identifier
+ * @ID_PROG7: Programmable 7 clock identifier
+
+ * @ID_PCK0: System clock 0 clock identifier
+ * @ID_PCK1: System clock 1 clock identifier
+ * @ID_PCK2: System clock 2 clock identifier
+ * @ID_PCK3: System clock 3 clock identifier
+ * @ID_PCK4: System clock 4 clock identifier
+ * @ID_PCK5: System clock 5 clock identifier
+ * @ID_PCK6: System clock 6 clock identifier
+ * @ID_PCK7: System clock 7 clock identifier
+ */
+enum pmc_clk_ids {
+ ID_MD_SLCK = 0,
+ ID_TD_SLCK = 1,
+ ID_MAIN_XTAL = 2,
+ ID_MAIN_RC = 3,
+ ID_MAIN_RC_OSC = 4,
+ ID_MAIN_OSC = 5,
+ ID_MAINCK = 6,
+
+ ID_PLL_CPU_FRAC = 7,
+ ID_PLL_CPU_DIV = 8,
+ ID_PLL_SYS_FRAC = 9,
+ ID_PLL_SYS_DIV = 10,
+ ID_PLL_DDR_FRAC = 11,
+ ID_PLL_DDR_DIV = 12,
+ ID_PLL_IMG_FRAC = 13,
+ ID_PLL_IMG_DIV = 14,
+ ID_PLL_BAUD_FRAC = 15,
+ ID_PLL_BAUD_DIV = 16,
+ ID_PLL_AUDIO_FRAC = 17,
+ ID_PLL_AUDIO_DIVPMC = 18,
+ ID_PLL_AUDIO_DIVIO = 19,
+ ID_PLL_ETH_FRAC = 20,
+ ID_PLL_ETH_DIV = 21,
+
+ ID_MCK0 = 22,
+ ID_MCK1 = 23,
+ ID_MCK2 = 24,
+ ID_MCK3 = 25,
+ ID_MCK4 = 26,
+
+ ID_UTMI = 27,
+
+ ID_PROG0 = 28,
+ ID_PROG1 = 29,
+ ID_PROG2 = 30,
+ ID_PROG3 = 31,
+ ID_PROG4 = 32,
+ ID_PROG5 = 33,
+ ID_PROG6 = 34,
+ ID_PROG7 = 35,
+
+ ID_PCK0 = 36,
+ ID_PCK1 = 37,
+ ID_PCK2 = 38,
+ ID_PCK3 = 39,
+ ID_PCK4 = 40,
+ ID_PCK5 = 41,
+ ID_PCK6 = 42,
+ ID_PCK7 = 43,
+
+ ID_MAX,
+};
+
+/**
+ * PLL type identifiers
+ * @PLL_TYPE_FRAC: fractional PLL identifier
+ * @PLL_TYPE_DIV: divider PLL identifier
+ */
+enum pll_type {
+ PLL_TYPE_FRAC,
+ PLL_TYPE_DIV,
+};
+
+/* Clock names used as parents for multiple clocks. */
+static const char *clk_names[] = {
+ [ID_MAIN_RC_OSC] = "main_rc_osc",
+ [ID_MAIN_OSC] = "main_osc",
+ [ID_MAINCK] = "mainck",
+ [ID_PLL_CPU_DIV] = "cpupll_divpmcck",
+ [ID_PLL_SYS_DIV] = "syspll_divpmcck",
+ [ID_PLL_DDR_DIV] = "ddrpll_divpmcck",
+ [ID_PLL_IMG_DIV] = "imgpll_divpmcck",
+ [ID_PLL_BAUD_DIV] = "baudpll_divpmcck",
+ [ID_PLL_AUDIO_DIVPMC] = "audiopll_divpmcck",
+ [ID_PLL_AUDIO_DIVIO] = "audiopll_diviock",
+ [ID_PLL_ETH_DIV] = "ethpll_divpmcck",
+ [ID_MCK0] = "mck0",
+};
+
+/* Fractional PLL output range. */
+static const struct clk_range pll_outputs[] = {
+ { .min = 2343750, .max = 1200000000 },
+};
+
+/* PLL characteristics. */
+static const struct clk_pll_characteristics pll_characteristics = {
+ .input = { .min = 12000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(pll_outputs),
+ .output = pll_outputs,
+};
+
+/* Layout for fractional PLLs. */
+static const struct clk_pll_layout pll_layout_frac = {
+ .mul_mask = GENMASK(31, 24),
+ .frac_mask = GENMASK(21, 0),
+ .mul_shift = 24,
+ .frac_shift = 0,
+};
+
+/* Layout for DIVPMC dividers. */
+static const struct clk_pll_layout pll_layout_divpmc = {
+ .div_mask = GENMASK(7, 0),
+ .endiv_mask = BIT(29),
+ .div_shift = 0,
+ .endiv_shift = 29,
+};
+
+/* Layout for DIVIO dividers. */
+static const struct clk_pll_layout pll_layout_divio = {
+ .div_mask = GENMASK(19, 12),
+ .endiv_mask = BIT(30),
+ .div_shift = 12,
+ .endiv_shift = 30,
+};
+
+/* MCK0 characteristics. */
+static const struct clk_master_characteristics mck0_characteristics = {
+ .output = { .min = 140000000, .max = 200000000 },
+ .divisors = { 1, 2, 4, 3 },
+ .have_div3_pres = 1,
+};
+
+/* MCK0 layout. */
+static const struct clk_master_layout mck0_layout = {
+ .mask = 0x373,
+ .pres_shift = 4,
+ .offset = 0x28,
+};
+
+/* Programmable clock layout. */
+static const struct clk_programmable_layout programmable_layout = {
+ .pres_mask = 0xff,
+ .pres_shift = 8,
+ .css_mask = 0x1f,
+ .have_slck_mck = 0,
+ .is_pres_direct = 1,
+};
+
+/* Peripheral clock layout. */
+static const struct clk_pcr_layout sama7g5_pcr_layout = {
+ .offset = 0x88,
+ .cmd = BIT(31),
+ .gckcss_mask = GENMASK(12, 8),
+ .pid_mask = GENMASK(6, 0),
+ .div_mask = GENMASK(15, 14),
+};
+
+/**
+ * PLL clocks description
+ * @n: clock name
+ * @p: clock parent
+ * @l: clock layout
+ * @t: clock type
+ * @c: true if clock is critical and cannot be disabled
+ * @id: clock id corresponding to PLL driver
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ const struct clk_pll_layout *l;
+ u8 t;
+ u8 c;
+ u8 id;
+ u8 cid;
+} sama7g5_plls[] = {
+ {
+ .n = "cpupll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .c = 1,
+ .id = 0,
+ .cid = ID_PLL_CPU_FRAC,
+ },
+
+ {
+ .n = "cpupll_divpmcck",
+ .p = "cpupll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .c = 1,
+ .id = 0,
+ .cid = ID_PLL_CPU_DIV,
+ },
+
+ {
+ .n = "syspll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .c = 1,
+ .id = 1,
+ .cid = ID_PLL_SYS_FRAC,
+ },
+
+ {
+ .n = "syspll_divpmcck",
+ .p = "syspll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .c = 1,
+ .id = 1,
+ .cid = ID_PLL_SYS_DIV,
+ },
+
+ {
+ .n = "ddrpll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .c = 1,
+ .id = 2,
+ .cid = ID_PLL_DDR_FRAC,
+ },
+
+ {
+ .n = "ddrpll_divpmcck",
+ .p = "ddrpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .c = 1,
+ .id = 2,
+ .cid = ID_PLL_DDR_DIV,
+ },
+
+ {
+ .n = "imgpll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 3,
+ .cid = ID_PLL_IMG_FRAC,
+ },
+
+ {
+ .n = "imgpll_divpmcck",
+ .p = "imgpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 3,
+ .cid = ID_PLL_IMG_DIV
+ },
+
+ {
+ .n = "baudpll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 4,
+ .cid = ID_PLL_BAUD_FRAC,
+ },
+
+ {
+ .n = "baudpll_divpmcck",
+ .p = "baudpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 4,
+ .cid = ID_PLL_BAUD_DIV,
+ },
+
+ {
+ .n = "audiopll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 5,
+ .cid = ID_PLL_AUDIO_FRAC,
+ },
+
+ {
+ .n = "audiopll_divpmcck",
+ .p = "audiopll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 5,
+ .cid = ID_PLL_AUDIO_DIVPMC,
+ },
+
+ {
+ .n = "audiopll_diviock",
+ .p = "audiopll_fracck",
+ .l = &pll_layout_divio,
+ .t = PLL_TYPE_DIV,
+ .id = 5,
+ .cid = ID_PLL_AUDIO_DIVIO,
+ },
+
+ {
+ .n = "ethpll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 6,
+ .cid = ID_PLL_ETH_FRAC,
+ },
+
+ {
+ .n = "ethpll_divpmcck",
+ .p = "ethpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 6,
+ .cid = ID_PLL_ETH_DIV,
+ },
+};
+
+/**
+ * Master clock (MCK[1..4]) description
+ * @n: clock name
+ * @ep: extra parents names array
+ * @ep_chg_chg_id: index in parents array that specifies the changeable
+ * parent
+ * @ep_count: extra parents count
+ * @ep_mux_table: mux table for extra parents
+ * @ep_clk_mux_table: mux table to deal with subsystem clock ids
+ * @id: clock id corresponding to MCK driver
+ * @cid: clock id corresponding to clock subsystem
+ * @c: true if clock is critical and cannot be disabled
+ */
+static const struct {
+ const char *n;
+ const char *ep[4];
+ u8 ep_count;
+ u8 ep_mux_table[4];
+ u8 ep_clk_mux_table[4];
+ u8 id;
+ u8 cid;
+ u8 c;
+} sama7g5_mckx[] = {
+ {
+ .n = "mck1",
+ .id = 1,
+ .cid = ID_MCK1,
+ .ep = { "syspll_divpmcck", },
+ .ep_mux_table = { 5, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, },
+ .ep_count = 1,
+ .c = 1,
+ },
+
+ {
+ .n = "mck2",
+ .id = 2,
+ .cid = ID_MCK2,
+ .ep = { "ddrpll_divpmcck", },
+ .ep_mux_table = { 6, },
+ .ep_clk_mux_table = { ID_PLL_DDR_DIV, },
+ .ep_count = 1,
+ .c = 1,
+ },
+
+ {
+ .n = "mck3",
+ .id = 3,
+ .cid = ID_MCK3,
+ .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
+ .ep_mux_table = { 5, 6, 7, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_DDR_DIV, ID_PLL_IMG_DIV, },
+ .ep_count = 3,
+ },
+
+ {
+ .n = "mck4",
+ .id = 4,
+ .cid = ID_MCK4,
+ .ep = { "syspll_divpmcck", },
+ .ep_mux_table = { 5, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, },
+ .ep_count = 1,
+ .c = 1,
+ },
+};
+
+/**
+ * Programmable clock description
+ * @n: clock name
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ u8 cid;
+} sama7g5_prog[] = {
+ { .n = "prog0", .cid = ID_PROG0, },
+ { .n = "prog1", .cid = ID_PROG1, },
+ { .n = "prog2", .cid = ID_PROG2, },
+ { .n = "prog3", .cid = ID_PROG3, },
+ { .n = "prog4", .cid = ID_PROG4, },
+ { .n = "prog5", .cid = ID_PROG5, },
+ { .n = "prog6", .cid = ID_PROG6, },
+ { .n = "prog7", .cid = ID_PROG7, },
+};
+
+/* Mux table for programmable clocks. */
+static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
+
+/**
+ * System clock description
+ * @n: clock name
+ * @p: parent clock name
+ * @id: clock id corresponding to system clock driver
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ u8 id;
+ u8 cid;
+} sama7g5_systemck[] = {
+ { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, },
+ { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, },
+ { .n = "pck2", .p = "prog2", .id = 10, .cid = ID_PCK2, },
+ { .n = "pck3", .p = "prog3", .id = 11, .cid = ID_PCK3, },
+ { .n = "pck4", .p = "prog4", .id = 12, .cid = ID_PCK4, },
+ { .n = "pck5", .p = "prog5", .id = 13, .cid = ID_PCK5, },
+ { .n = "pck6", .p = "prog6", .id = 14, .cid = ID_PCK6, },
+ { .n = "pck7", .p = "prog7", .id = 15, .cid = ID_PCK7, },
+};
+
+/**
+ * Peripheral clock description
+ * @n: clock name
+ * @p: clock parent name
+ * @r: clock range values
+ * @id: clock id
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ struct clk_range r;
+ u8 id;
+} sama7g5_periphck[] = {
+ { .n = "pioA_clk", .p = "mck0", .id = 11, },
+ { .n = "sfr_clk", .p = "mck1", .id = 19, },
+ { .n = "hsmc_clk", .p = "mck1", .id = 21, },
+ { .n = "xdmac0_clk", .p = "mck1", .id = 22, },
+ { .n = "xdmac1_clk", .p = "mck1", .id = 23, },
+ { .n = "xdmac2_clk", .p = "mck1", .id = 24, },
+ { .n = "acc_clk", .p = "mck1", .id = 25, },
+ { .n = "aes_clk", .p = "mck1", .id = 27, },
+ { .n = "tzaesbasc_clk", .p = "mck1", .id = 28, },
+ { .n = "asrc_clk", .p = "mck1", .id = 30, .r = { .max = 200000000, }, },
+ { .n = "cpkcc_clk", .p = "mck0", .id = 32, },
+ { .n = "csi_clk", .p = "mck3", .id = 33, .r = { .max = 266000000, }, },
+ { .n = "csi2dc_clk", .p = "mck3", .id = 34, .r = { .max = 266000000, }, },
+ { .n = "eic_clk", .p = "mck1", .id = 37, },
+ { .n = "flex0_clk", .p = "mck1", .id = 38, },
+ { .n = "flex1_clk", .p = "mck1", .id = 39, },
+ { .n = "flex2_clk", .p = "mck1", .id = 40, },
+ { .n = "flex3_clk", .p = "mck1", .id = 41, },
+ { .n = "flex4_clk", .p = "mck1", .id = 42, },
+ { .n = "flex5_clk", .p = "mck1", .id = 43, },
+ { .n = "flex6_clk", .p = "mck1", .id = 44, },
+ { .n = "flex7_clk", .p = "mck1", .id = 45, },
+ { .n = "flex8_clk", .p = "mck1", .id = 46, },
+ { .n = "flex9_clk", .p = "mck1", .id = 47, },
+ { .n = "flex10_clk", .p = "mck1", .id = 48, },
+ { .n = "flex11_clk", .p = "mck1", .id = 49, },
+ { .n = "gmac0_clk", .p = "mck1", .id = 51, },
+ { .n = "gmac1_clk", .p = "mck1", .id = 52, },
+ { .n = "gmac0_tsu_clk", .p = "mck1", .id = 53, },
+ { .n = "gmac1_tsu_clk", .p = "mck1", .id = 54, },
+ { .n = "icm_clk", .p = "mck1", .id = 55, },
+ { .n = "isc_clk", .p = "mck3", .id = 56, .r = { .max = 266000000, }, },
+ { .n = "i2smcc0_clk", .p = "mck1", .id = 57, .r = { .max = 200000000, }, },
+ { .n = "i2smcc1_clk", .p = "mck1", .id = 58, .r = { .max = 200000000, }, },
+ { .n = "matrix_clk", .p = "mck1", .id = 60, },
+ { .n = "mcan0_clk", .p = "mck1", .id = 61, .r = { .max = 200000000, }, },
+ { .n = "mcan1_clk", .p = "mck1", .id = 62, .r = { .max = 200000000, }, },
+ { .n = "mcan2_clk", .p = "mck1", .id = 63, .r = { .max = 200000000, }, },
+ { .n = "mcan3_clk", .p = "mck1", .id = 64, .r = { .max = 200000000, }, },
+ { .n = "mcan4_clk", .p = "mck1", .id = 65, .r = { .max = 200000000, }, },
+ { .n = "mcan5_clk", .p = "mck1", .id = 66, .r = { .max = 200000000, }, },
+ { .n = "pdmc0_clk", .p = "mck1", .id = 68, .r = { .max = 200000000, }, },
+ { .n = "pdmc1_clk", .p = "mck1", .id = 69, .r = { .max = 200000000, }, },
+ { .n = "pit64b0_clk", .p = "mck1", .id = 70, },
+ { .n = "pit64b1_clk", .p = "mck1", .id = 71, },
+ { .n = "pit64b2_clk", .p = "mck1", .id = 72, },
+ { .n = "pit64b3_clk", .p = "mck1", .id = 73, },
+ { .n = "pit64b4_clk", .p = "mck1", .id = 74, },
+ { .n = "pit64b5_clk", .p = "mck1", .id = 75, },
+ { .n = "pwm_clk", .p = "mck1", .id = 77, },
+ { .n = "qspi0_clk", .p = "mck1", .id = 78, },
+ { .n = "qspi1_clk", .p = "mck1", .id = 79, },
+ { .n = "sdmmc0_clk", .p = "mck1", .id = 80, },
+ { .n = "sdmmc1_clk", .p = "mck1", .id = 81, },
+ { .n = "sdmmc2_clk", .p = "mck1", .id = 82, },
+ { .n = "sha_clk", .p = "mck1", .id = 83, },
+ { .n = "spdifrx_clk", .p = "mck1", .id = 84, .r = { .max = 200000000, }, },
+ { .n = "spdiftx_clk", .p = "mck1", .id = 85, .r = { .max = 200000000, }, },
+ { .n = "ssc0_clk", .p = "mck1", .id = 86, .r = { .max = 200000000, }, },
+ { .n = "ssc1_clk", .p = "mck1", .id = 87, .r = { .max = 200000000, }, },
+ { .n = "tcb0_ch0_clk", .p = "mck1", .id = 88, .r = { .max = 200000000, }, },
+ { .n = "tcb0_ch1_clk", .p = "mck1", .id = 89, .r = { .max = 200000000, }, },
+ { .n = "tcb0_ch2_clk", .p = "mck1", .id = 90, .r = { .max = 200000000, }, },
+ { .n = "tcb1_ch0_clk", .p = "mck1", .id = 91, .r = { .max = 200000000, }, },
+ { .n = "tcb1_ch1_clk", .p = "mck1", .id = 92, .r = { .max = 200000000, }, },
+ { .n = "tcb1_ch2_clk", .p = "mck1", .id = 93, .r = { .max = 200000000, }, },
+ { .n = "tcpca_clk", .p = "mck1", .id = 94, },
+ { .n = "tcpcb_clk", .p = "mck1", .id = 95, },
+ { .n = "tdes_clk", .p = "mck1", .id = 96, },
+ { .n = "trng_clk", .p = "mck1", .id = 97, },
+ { .n = "udphsa_clk", .p = "mck1", .id = 104, },
+ { .n = "udphsb_clk", .p = "mck1", .id = 105, },
+ { .n = "uhphs_clk", .p = "mck1", .id = 106, },
+};
+
+/**
+ * Generic clock description
+ * @n: clock name
+ * @ep: extra parents names
+ * @ep_mux_table: extra parents mux table
+ * @ep_clk_mux_table: extra parents clock mux table (for CCF)
+ * @r: clock output range
+ * @ep_count: extra parents count
+ * @id: clock id
+ */
+static const struct {
+ const char *n;
+ const char *ep[8];
+ const char ep_mux_table[8];
+ const char ep_clk_mux_table[8];
+ struct clk_range r;
+ u8 ep_count;
+ u8 id;
+} sama7g5_gck[] = {
+ {
+ .n = "adc_gclk",
+ .id = 26,
+ .r = { .max = 100000000, },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 7, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 3,
+ },
+
+ {
+ .n = "asrc_gclk",
+ .id = 30,
+ .r = { .max = 200000000 },
+ .ep = { "audiopll_divpmcck", },
+ .ep_mux_table = { 9, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "csi_gclk",
+ .id = 33,
+ .r = { .max = 27000000 },
+ .ep = { "ddrpll_divpmcck", "imgpll_divpmcck", },
+ .ep_clk_mux_table = { ID_PLL_DDR_DIV, ID_PLL_IMG_DIV, },
+ .ep_mux_table = { 6, 7, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex0_gclk",
+ .id = 38,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex1_gclk",
+ .id = 39,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex2_gclk",
+ .id = 40,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex3_gclk",
+ .id = 41,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex4_gclk",
+ .id = 42,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex5_gclk",
+ .id = 43,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex6_gclk",
+ .id = 44,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex7_gclk",
+ .id = 45,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex8_gclk",
+ .id = 46,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex9_gclk",
+ .id = 47,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex10_gclk",
+ .id = 48,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex11_gclk",
+ .id = 49,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "gmac0_gclk",
+ .id = 51,
+ .r = { .max = 125000000 },
+ .ep = { "ethpll_divpmcck", },
+ .ep_clk_mux_table = { ID_PLL_ETH_DIV, },
+ .ep_mux_table = { 10, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "gmac1_gclk",
+ .id = 52,
+ .r = { .max = 50000000 },
+ .ep = { "ethpll_divpmcck", },
+ .ep_mux_table = { 10, },
+ .ep_clk_mux_table = { ID_PLL_ETH_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "gmac0_tsu_gclk",
+ .id = 53,
+ .r = { .max = 300000000 },
+ .ep = { "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_ETH_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "gmac1_tsu_gclk",
+ .id = 54,
+ .r = { .max = 300000000 },
+ .ep = { "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_ETH_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "i2smcc0_gclk",
+ .id = 57,
+ .r = { .max = 100000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "i2smcc1_gclk",
+ .id = 58,
+ .r = { .max = 100000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan0_gclk",
+ .id = 61,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan1_gclk",
+ .id = 62,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan2_gclk",
+ .id = 63,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan3_gclk",
+ .id = 64,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan4_gclk",
+ .id = 65,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan5_gclk",
+ .id = 66,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pdmc0_gclk",
+ .id = 68,
+ .r = { .max = 50000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pdmc1_gclk",
+ .id = 69,
+ .r = { .max = 50000000, },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pit64b0_gclk",
+ .id = 70,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b1_gclk",
+ .id = 71,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b2_gclk",
+ .id = 72,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b3_gclk",
+ .id = 73,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b4_gclk",
+ .id = 74,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b5_gclk",
+ .id = 75,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "qspi0_gclk",
+ .id = 78,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "qspi1_gclk",
+ .id = 79,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc0_gclk",
+ .id = 80,
+ .r = { .max = 208000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc1_gclk",
+ .id = 81,
+ .r = { .max = 208000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc2_gclk",
+ .id = 82,
+ .r = { .max = 208000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "spdifrx_gclk",
+ .id = 84,
+ .r = { .max = 150000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "spdiftx_gclk",
+ .id = 85,
+ .r = { .max = 25000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "tcb0_ch0_gclk",
+ .id = 88,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "tcb1_ch0_gclk",
+ .id = 91,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+};
+
+/**
+ * Clock setup description
+ * @cid: clock id corresponding to clock subsystem
+ * @pid: parent clock id corresponding to clock subsystem
+ * @rate: clock rate
+ * @prate: parent rate
+ */
+static const struct pmc_clk_setup {
+ unsigned int cid;
+ unsigned int pid;
+ unsigned long rate;
+ unsigned long prate;
+} sama7g5_clk_setup[] = {
+ {
+ .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_FRAC),
+ .rate = 625000000,
+ },
+
+ {
+ .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_DIV),
+ .rate = 625000000,
+ },
+};
+
+#define SAMA7G5_MAX_MUX_ALLOCS (64)
+
+#define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \
+ do { \
+ int _i; \
+ if ((_index) >= SAMA7G5_MAX_MUX_ALLOCS) { \
+ debug("%s(): AT91: MUX: insufficient space\n", \
+ __func__); \
+ goto _label; \
+ } \
+ (_dst) = kzalloc(sizeof(*(_dst)) * (_num), GFP_KERNEL); \
+ if (!(_dst)) \
+ goto _label; \
+ (_allocs)[(_index)++] = (_dst); \
+ for (_i = 0; _i < (_num); _i++) \
+ (_dst)[_i] = (_src)[_i]; \
+ } while (0)
+
+static int sama7g5_clk_probe(struct udevice *dev)
+{
+ void __iomem *base = (void *)devfdt_get_addr(dev);
+ unsigned int *clkmuxallocs[SAMA7G5_MAX_MUX_ALLOCS];
+ unsigned int *muxallocs[SAMA7G5_MAX_MUX_ALLOCS];
+ const char *p[10];
+ unsigned int cm[10], m[10], *tmpclkmux, *tmpmux;
+ struct clk clk, *c, *parent;
+ bool main_osc_bypass;
+ int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j;
+
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ memset(muxallocs, 0, ARRAY_SIZE(muxallocs));
+ memset(clkmuxallocs, 0, ARRAY_SIZE(clkmuxallocs));
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+ ret = clk_get_by_id(clk.id, &c);
+ if (ret)
+ return ret;
+ clk_names[ID_TD_SLCK] = kmemdup(clk_hw_get_name(c),
+ strlen(clk_hw_get_name(c)) + 1, GFP_KERNEL);
+ if (!clk_names[ID_TD_SLCK])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+ ret = clk_get_by_id(clk.id, &c);
+ if (ret)
+ return ret;
+ clk_names[ID_MD_SLCK] = kmemdup(clk_hw_get_name(c),
+ strlen(clk_hw_get_name(c)) + 1, GFP_KERNEL);
+ if (!clk_names[ID_MD_SLCK])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 2, &clk);
+ if (ret)
+ return ret;
+ clk_names[ID_MAIN_XTAL] = kmemdup(clk_hw_get_name(&clk),
+ strlen(clk_hw_get_name(&clk)) + 1, GFP_KERNEL);
+ if (!clk_names[ID_MAIN_XTAL])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 3, &clk);
+ if (ret)
+ goto fail;
+ clk_names[ID_MAIN_RC] = kmemdup(clk_hw_get_name(&clk),
+ strlen(clk_hw_get_name(&clk)) + 1, GFP_KERNEL);
+ if (ret)
+ goto fail;
+
+ main_osc_bypass = dev_read_bool(dev, "atmel,main-osc-bypass");
+
+ /* Register main rc oscillator. */
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC),
+ at91_clk_main_rc(base, clk_names[ID_MAIN_RC_OSC],
+ clk_names[ID_MAIN_RC]));
+
+ /* Register main oscillator. */
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC),
+ at91_clk_main_osc(base, clk_names[ID_MAIN_OSC],
+ clk_names[ID_MAIN_XTAL], main_osc_bypass));
+
+ /* Register mainck. */
+ p[0] = clk_names[ID_MAIN_RC_OSC];
+ p[1] = clk_names[ID_MAIN_OSC];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC);
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2,
+ fail);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK),
+ at91_clk_sam9x5_main(base, clk_names[ID_MAINCK], p,
+ 2, tmpclkmux, PMC_TYPE_CORE));
+
+ /* Register PLL fracs clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_plls); i++) {
+ if (sama7g5_plls[i].t != PLL_TYPE_FRAC)
+ continue;
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_plls[i].cid),
+ sam9x60_clk_register_frac_pll(base, sama7g5_plls[i].n,
+ sama7g5_plls[i].p, sama7g5_plls[i].id,
+ &pll_characteristics, sama7g5_plls[i].l,
+ sama7g5_plls[i].c));
+ }
+
+ /* Register PLL div clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_plls); i++) {
+ if (sama7g5_plls[i].t != PLL_TYPE_DIV)
+ continue;
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_plls[i].cid),
+ sam9x60_clk_register_div_pll(base, sama7g5_plls[i].n,
+ sama7g5_plls[i].p, sama7g5_plls[i].id,
+ &pll_characteristics, sama7g5_plls[i].l,
+ sama7g5_plls[i].c));
+ }
+
+ /* Register MCK0 clock. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_MAINCK];
+ p[2] = clk_names[ID_PLL_CPU_DIV];
+ p[3] = clk_names[ID_PLL_SYS_DIV];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_CPU_DIV);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_SYS_DIV);
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2,
+ fail);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0),
+ at91_clk_register_master(base, clk_names[ID_MCK0], p,
+ 4, &mck0_layout, &mck0_characteristics, tmpclkmux));
+
+ /* Register MCK1-4 clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK0];
+ m[0] = 0;
+ m[1] = 1;
+ m[2] = 2;
+ m[3] = 3;
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0);
+ for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
+ for (j = 0; j < sama7g5_mckx[i].ep_count; j++) {
+ p[4 + j] = sama7g5_mckx[i].ep[j];
+ m[4 + j] = sama7g5_mckx[i].ep_mux_table[j];
+ cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE,
+ sama7g5_mckx[i].ep_clk_mux_table[j]);
+ }
+
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 4 + sama7g5_mckx[i].ep_count, fail);
+ prepare_mux_table(muxallocs, muxallocindex, tmpmux, m,
+ 4 + sama7g5_mckx[i].ep_count, fail);
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_mckx[i].cid),
+ at91_clk_sama7g5_register_master(base,
+ sama7g5_mckx[i].n, p, 4 + sama7g5_mckx[i].ep_count,
+ tmpmux, tmpclkmux, sama7g5_mckx[i].c,
+ sama7g5_mckx[i].id));
+ }
+
+ /* Register UTMI clock. */
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_UTMI),
+ at91_clk_sama7g5_register_utmi(base, "utmick",
+ clk_names[ID_MAIN_XTAL]));
+
+ /* Register programmable clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK0];
+ p[4] = clk_names[ID_PLL_SYS_DIV];
+ p[5] = clk_names[ID_PLL_DDR_DIV];
+ p[6] = clk_names[ID_PLL_IMG_DIV];
+ p[7] = clk_names[ID_PLL_BAUD_DIV];
+ p[8] = clk_names[ID_PLL_AUDIO_DIVPMC];
+ p[9] = clk_names[ID_PLL_ETH_DIV];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0);
+ cm[4] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_SYS_DIV);
+ cm[5] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_DDR_DIV);
+ cm[6] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_IMG_DIV);
+ cm[7] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_BAUD_DIV);
+ cm[8] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_AUDIO_DIVPMC);
+ cm[9] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_DIV);
+ for (i = 0; i < ARRAY_SIZE(sama7g5_prog); i++) {
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 10, fail);
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_prog[i].cid),
+ at91_clk_register_programmable(base, sama7g5_prog[i].n,
+ p, 10, i, &programmable_layout, tmpclkmux,
+ sama7g5_prog_mux_table));
+ }
+
+ /* System clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SYSTEM, sama7g5_systemck[i].cid),
+ at91_clk_register_system(base, sama7g5_systemck[i].n,
+ sama7g5_systemck[i].p, sama7g5_systemck[i].id));
+ }
+
+ /* Peripheral clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) {
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_PERIPHERAL,
+ sama7g5_periphck[i].id),
+ at91_clk_register_sam9x5_peripheral(base,
+ &sama7g5_pcr_layout, sama7g5_periphck[i].n,
+ sama7g5_periphck[i].p, sama7g5_periphck[i].id,
+ &sama7g5_periphck[i].r));
+ }
+
+ /* Generic clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK0];
+ m[0] = 0;
+ m[1] = 1;
+ m[2] = 2;
+ m[3] = 3;
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0);
+ for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
+ for (j = 0; j < sama7g5_gck[i].ep_count; j++) {
+ p[4 + j] = sama7g5_gck[i].ep[j];
+ m[4 + j] = sama7g5_gck[i].ep_mux_table[j];
+ cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE,
+ sama7g5_gck[i].ep_clk_mux_table[j]);
+ }
+
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 4 + sama7g5_gck[i].ep_count, fail);
+ prepare_mux_table(muxallocs, muxallocindex, tmpmux, m,
+ 4 + sama7g5_gck[i].ep_count, fail);
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sama7g5_gck[i].id),
+ at91_clk_register_generic(base, &sama7g5_pcr_layout,
+ sama7g5_gck[i].n, p, tmpclkmux, tmpmux,
+ 4 + sama7g5_gck[i].ep_count, sama7g5_gck[i].id,
+ &sama7g5_gck[i].r));
+ }
+
+ /* Setup clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_clk_setup); i++) {
+ ret = clk_get_by_id(sama7g5_clk_setup[i].cid, &c);
+ if (ret)
+ goto fail;
+
+ if (sama7g5_clk_setup[i].pid) {
+ ret = clk_get_by_id(sama7g5_clk_setup[i].pid, &parent);
+ if (ret)
+ goto fail;
+
+ ret = clk_set_parent(c, parent);
+ if (ret)
+ goto fail;
+
+ if (sama7g5_clk_setup[i].prate) {
+ ret = clk_set_rate(parent,
+ sama7g5_clk_setup[i].prate);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ if (sama7g5_clk_setup[i].rate) {
+ ret = clk_set_rate(c, sama7g5_clk_setup[i].rate);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < ARRAY_SIZE(muxallocs); i++)
+ kfree(muxallocs[i]);
+
+ for (i = 0; i < ARRAY_SIZE(clkmuxallocs); i++)
+ kfree(clkmuxallocs[i]);
+
+ return -ENOMEM;
+}
+
+static const struct udevice_id sama7g5_clk_ids[] = {
+ { .compatible = "microchip,sama7g5-pmc" },
+ { /* Sentinel. */ },
+};
+
+U_BOOT_DRIVER(at91_sama7g5_pmc) = {
+ .name = "at91-sama7g5-pmc",
+ .id = UCLASS_CLK,
+ .of_match = sama7g5_clk_ids,
+ .ops = &at91_clk_ops,
+ .probe = sama7g5_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c
index a879b008ff..dd62dc5510 100644
--- a/drivers/clk/at91/sckc.c
+++ b/drivers/clk/at91/sckc.c
@@ -1,19 +1,172 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Slow clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
*/
#include <common.h>
+#include <clk-uclass.h>
#include <dm.h>
+#include <dt-bindings/clk/at91.h>
+#include <linux/clk-provider.h>
-static const struct udevice_id at91_sckc_match[] = {
- { .compatible = "atmel,at91sam9x5-sckc" },
- {}
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK "at91-sam9x60-td-slck"
+#define UBOOT_DM_CLK_AT91_SCKC "at91-sckc"
+
+#define AT91_OSC_SEL BIT(24)
+#define AT91_OSC_SEL_SHIFT (24)
+
+struct sam9x60_sckc {
+ void __iomem *reg;
+ const char **parent_names;
+ unsigned int num_parents;
+ struct clk clk;
+};
+
+#define to_sam9x60_sckc(c) container_of(c, struct sam9x60_sckc, clk)
+
+static int sam9x60_sckc_of_xlate(struct clk *clk,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count != 1) {
+ debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
+
+ return 0;
+}
+
+static const struct clk_ops sam9x60_sckc_ops = {
+ .of_xlate = sam9x60_sckc_of_xlate,
+ .get_rate = clk_generic_get_rate,
+};
+
+static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
+ u32 i;
+
+ for (i = 0; i < sckc->num_parents; i++) {
+ if (!strcmp(parent->dev->name, sckc->parent_names[i]))
+ break;
+ }
+ if (i == sckc->num_parents)
+ return -EINVAL;
+
+ pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
+
+ return 0;
+}
+
+static const struct clk_ops sam9x60_td_slck_ops = {
+ .get_rate = clk_generic_get_rate,
+ .set_parent = sam9x60_td_slck_set_parent,
+};
+
+static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
+ const char *name, const char * const *parent_names,
+ int num_parents)
+{
+ struct clk *clk;
+ int ret = -ENOMEM;
+ u32 val, i;
+
+ if (!sckc || !name || !parent_names || num_parents != 2)
+ return ERR_PTR(-EINVAL);
+
+ sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
+ GFP_KERNEL);
+ if (!sckc->parent_names)
+ return ERR_PTR(ret);
+
+ for (i = 0; i < num_parents; i++) {
+ sckc->parent_names[i] = kmemdup(parent_names[i],
+ strlen(parent_names[i]) + 1, GFP_KERNEL);
+ if (!sckc->parent_names[i])
+ goto free;
+ }
+ sckc->num_parents = num_parents;
+
+ pmc_read(sckc->reg, 0, &val);
+ val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
+
+ clk = &sckc->clk;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
+ parent_names[val]);
+ if (ret)
+ goto free;
+
+ return clk;
+
+free:
+ for (; i >= 0; i--)
+ kfree(sckc->parent_names[i]);
+ kfree(sckc->parent_names);
+
+ return ERR_PTR(ret);
+}
+
+U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_td_slck_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int at91_sam9x60_sckc_probe(struct udevice *dev)
+{
+ struct sam9x60_sckc *sckc = dev_get_priv(dev);
+ void __iomem *base = (void *)devfdt_get_addr(dev);
+ const char *slow_rc_osc, *slow_osc;
+ const char *parents[2];
+ struct clk *clk, c;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &c);
+ if (ret)
+ return ret;
+ slow_rc_osc = clk_hw_get_name(&c);
+
+ ret = clk_get_by_index(dev, 1, &c);
+ if (ret)
+ return ret;
+ slow_osc = clk_hw_get_name(&c);
+
+ clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
+
+ parents[0] = slow_rc_osc;
+ parents[1] = slow_osc;
+ sckc[1].reg = base;
+ clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
+ parents, 2);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
+
+ return 0;
+}
+
+static const struct udevice_id sam9x60_sckc_ids[] = {
+ { .compatible = "microchip,sam9x60-sckc" },
+ { /* Sentinel. */ },
};
U_BOOT_DRIVER(at91_sckc) = {
- .name = "at91-sckc",
- .id = UCLASS_SIMPLE_BUS,
- .of_match = at91_sckc_match,
+ .name = UBOOT_DM_CLK_AT91_SCKC,
+ .id = UCLASS_CLK,
+ .of_match = sam9x60_sckc_ids,
+ .priv_auto_alloc_size = sizeof(struct sam9x60_sckc) * 2,
+ .ops = &sam9x60_sckc_ops,
+ .probe = at91_sam9x60_sckc_probe,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 934cd5787a..4076535271 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -14,6 +14,7 @@
#include <errno.h>
#include <log.h>
#include <malloc.h>
+#include <dm/device-internal.h>
#include <dm/devres.h>
#include <dm/read.h>
#include <linux/bug.h>
@@ -187,9 +188,26 @@ bulk_get_err:
return ret;
}
+static struct clk *clk_set_default_get_by_id(struct clk *clk)
+{
+ struct clk *c = clk;
+
+ if (CONFIG_IS_ENABLED(CLK_CCF)) {
+ int ret = clk_get_by_id(clk->id, &c);
+
+ if (ret) {
+ debug("%s(): could not get parent clock pointer, id %lu\n",
+ __func__, clk->id);
+ ERR_PTR(ret);
+ }
+ }
+
+ return c;
+}
+
static int clk_set_default_parents(struct udevice *dev, int stage)
{
- struct clk clk, parent_clk;
+ struct clk clk, parent_clk, *c, *p;
int index;
int num_parents;
int ret;
@@ -215,6 +233,10 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
return ret;
}
+ p = clk_set_default_get_by_id(&parent_clk);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
index, &clk);
if (ret) {
@@ -234,7 +256,11 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
/* do not setup twice the parent clocks */
continue;
- ret = clk_set_parent(&clk, &parent_clk);
+ c = clk_set_default_get_by_id(&clk);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ ret = clk_set_parent(c, p);
/*
* Not all drivers may support clock-reparenting (as of now).
* Ignore errors due to this.
@@ -254,7 +280,7 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
static int clk_set_default_rates(struct udevice *dev, int stage)
{
- struct clk clk;
+ struct clk clk, *c;
int index;
int num_rates;
int size;
@@ -298,7 +324,11 @@ static int clk_set_default_rates(struct udevice *dev, int stage)
/* do not setup twice the parent clocks */
continue;
- ret = clk_set_rate(&clk, rates[index]);
+ c = clk_set_default_get_by_id(&clk);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ ret = clk_set_rate(c, rates[index]);
if (ret < 0) {
debug("%s: failed to set rate on clock index %d (%ld) for %s\n",
@@ -512,6 +542,7 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
int clk_set_parent(struct clk *clk, struct clk *parent)
{
const struct clk_ops *ops;
+ int ret;
debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
if (!clk_valid(clk))
@@ -521,7 +552,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!ops->set_parent)
return -ENOSYS;
- return ops->set_parent(clk, parent);
+ ret = ops->set_parent(clk, parent);
+ if (ret)
+ return ret;
+
+ if (CONFIG_IS_ENABLED(CLK_CCF))
+ ret = device_reparent(clk->dev, parent->dev);
+
+ return ret;
}
int clk_enable(struct clk *clk)
@@ -597,6 +635,9 @@ int clk_disable(struct clk *clk)
if (CONFIG_IS_ENABLED(CLK_CCF)) {
if (clk->id && !clk_get_by_id(clk->id, &clkp)) {
+ if (clkp->flags & CLK_IS_CRITICAL)
+ return 0;
+
if (clkp->enable_count == 0) {
printf("clk %s already disabled\n",
clkp->dev->name);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 786f4e887e..319808d433 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -57,6 +57,9 @@ ulong clk_generic_get_rate(struct clk *clk)
const char *clk_hw_get_name(const struct clk *hw)
{
+ assert(hw);
+ assert(hw->dev);
+
return hw->dev->name;
}
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index 2c20eddb0b..55e1f8caa5 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -53,4 +53,5 @@ U_BOOT_DRIVER(clk_fixed_rate) = {
.ofdata_to_platdata = clk_fixed_rate_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct clk_fixed_rate),
.ops = &clk_fixed_rate_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
new file mode 100644
index 0000000000..93a4819501
--- /dev/null
+++ b/drivers/clk/clk_scmi.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2020 Linaro Limited
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+
+static int scmi_clk_gate(struct clk *clk, int enable)
+{
+ struct scmi_clk_state_in in = {
+ .clock_id = clk->id,
+ .attributes = enable,
+ };
+ struct scmi_clk_state_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_CONFIG_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_clk_enable(struct clk *clk)
+{
+ return scmi_clk_gate(clk, 1);
+}
+
+static int scmi_clk_disable(struct clk *clk)
+{
+ return scmi_clk_gate(clk, 0);
+}
+
+static ulong scmi_clk_get_rate(struct clk *clk)
+{
+ struct scmi_clk_rate_get_in in = {
+ .clock_id = clk->id,
+ };
+ struct scmi_clk_rate_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_RATE_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
+}
+
+static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct scmi_clk_rate_set_in in = {
+ .clock_id = clk->id,
+ .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
+ .rate_lsb = (u32)rate,
+ .rate_msb = (u32)((u64)rate >> 32),
+ };
+ struct scmi_clk_rate_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_RATE_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return scmi_clk_get_rate(clk);
+}
+
+static const struct clk_ops scmi_clk_ops = {
+ .enable = scmi_clk_enable,
+ .disable = scmi_clk_disable,
+ .get_rate = scmi_clk_get_rate,
+ .set_rate = scmi_clk_set_rate,
+};
+
+U_BOOT_DRIVER(scmi_clock) = {
+ .name = "scmi_clk",
+ .id = UCLASS_CLK,
+ .ops = &scmi_clk_ops,
+};
diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c
index 2313ac0bc0..7795119756 100644
--- a/drivers/clk/clk_zynqmp.c
+++ b/drivers/clk/clk_zynqmp.c
@@ -710,7 +710,7 @@ static const struct udevice_id zynqmp_clk_ids[] = {
};
U_BOOT_DRIVER(zynqmp_clk) = {
- .name = "zynqmp-clk",
+ .name = "zynqmp_clk",
.id = UCLASS_CLK,
.of_match = zynqmp_clk_ids,
.probe = zynqmp_clk_probe,
diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c
index 981b3b7699..bb196961af 100644
--- a/drivers/clk/kendryte/clk.c
+++ b/drivers/clk/kendryte/clk.c
@@ -646,6 +646,10 @@ static int k210_clk_probe(struct udevice *dev)
REGISTER_GATE(K210_CLK_RTC, "rtc", in0);
#undef REGISTER_GATE
+ /* The MTIME register in CLINT runs at one 50th the CPU clock speed */
+ clk_dm(K210_CLK_CLINT,
+ clk_register_fixed_factor(NULL, "clint", "cpu", 0, 1, 50));
+
return 0;
}
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 00d1d80dc3..1ca5d66141 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -277,4 +277,13 @@ config ACPIGEN
things like generating device-specific tables and returning the ACPI
name of a device.
+config INTEL_ACPIGEN
+ bool "Support ACPI table generation for Intel SoCs"
+ depends on ACPIGEN
+ help
+ This option adds some functions used for programatic generation of
+ ACPI tables on Intel SoCs. This provides features for writing CPU
+ information such as P states and T stages. Also included is a way
+ to create a GNVS table and set it up.
+
endmenu
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 355dbd147a..e90d70101c 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -276,6 +276,28 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
return ret;
}
+int device_reparent(struct udevice *dev, struct udevice *new_parent)
+{
+ struct udevice *pos, *n;
+
+ assert(dev);
+ assert(new_parent);
+
+ list_for_each_entry_safe(pos, n, &dev->parent->child_head,
+ sibling_node) {
+ if (pos->driver != dev->driver)
+ continue;
+
+ list_del(&dev->sibling_node);
+ list_add_tail(&dev->sibling_node, &new_parent->child_head);
+ dev->parent = new_parent;
+
+ break;
+ }
+
+ return 0;
+}
+
static void *alloc_priv(int size, uint flags)
{
void *priv;
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 922e78f99b..bcf1644d05 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -745,13 +745,14 @@ struct device_node *of_parse_phandle(const struct device_node *np,
int of_parse_phandle_with_args(const struct device_node *np,
const char *list_name, const char *cells_name,
- int index, struct of_phandle_args *out_args)
+ int cell_count, int index,
+ struct of_phandle_args *out_args)
{
if (index < 0)
return -EINVAL;
- return __of_parse_phandle_with_args(np, list_name, cells_name, 0,
- index, out_args);
+ return __of_parse_phandle_with_args(np, list_name, cells_name,
+ cell_count, index, out_args);
}
int of_count_phandle_with_args(const struct device_node *np,
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index d02d8d33fe..79fcdf5ce2 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -409,7 +409,8 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
int ret;
ret = of_parse_phandle_with_args(ofnode_to_np(node),
- list_name, cells_name, index,
+ list_name, cells_name,
+ cell_count, index,
&args);
if (ret)
return ret;
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index a67a237b88..c2bed88eac 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -14,7 +14,24 @@
#include <regmap.h>
#include <asm/io.h>
#include <dm/of_addr.h>
+#include <dm/devres.h>
#include <linux/ioport.h>
+#include <linux/compat.h>
+#include <linux/err.h>
+#include <linux/bitops.h>
+
+/*
+ * Internal representation of a regmap field. Instead of storing the MSB and
+ * LSB, store the shift and mask. This makes the code a bit cleaner and faster
+ * because the shift and mask don't have to be calculated every time.
+ */
+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+};
DECLARE_GLOBAL_DATA_PTR;
@@ -22,16 +39,22 @@ DECLARE_GLOBAL_DATA_PTR;
* regmap_alloc() - Allocate a regmap with a given number of ranges.
*
* @count: Number of ranges to be allocated for the regmap.
+ *
+ * The default regmap width is set to REGMAP_SIZE_32. Callers can override it
+ * if they need.
+ *
* Return: A pointer to the newly allocated regmap, or NULL on error.
*/
static struct regmap *regmap_alloc(int count)
{
struct regmap *map;
+ size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count;
- map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
+ map = calloc(1, size);
if (!map)
return NULL;
map->range_count = count;
+ map->width = REGMAP_SIZE_32;
return map;
}
@@ -155,6 +178,33 @@ err:
return ret;
}
+int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size,
+ struct regmap **mapp)
+{
+ struct regmap *map;
+ struct regmap_range *range;
+
+ map = regmap_alloc(1);
+ if (!map)
+ return -ENOMEM;
+
+ range = &map->ranges[0];
+ range->start = r_start;
+ range->size = r_size;
+
+ if (ofnode_read_bool(node, "little-endian"))
+ map->endianness = REGMAP_LITTLE_ENDIAN;
+ else if (ofnode_read_bool(node, "big-endian"))
+ map->endianness = REGMAP_BIG_ENDIAN;
+ else if (ofnode_read_bool(node, "native-endian"))
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+ else /* Default: native endianness */
+ map->endianness = REGMAP_NATIVE_ENDIAN;
+
+ *mapp = map;
+ return 0;
+}
+
int regmap_init_mem(ofnode node, struct regmap **mapp)
{
struct regmap_range *range;
@@ -228,6 +278,42 @@ err:
return ret;
}
+
+static void devm_regmap_release(struct udevice *dev, void *res)
+{
+ regmap_uninit(*(struct regmap **)res);
+}
+
+struct regmap *devm_regmap_init(struct udevice *dev,
+ const struct regmap_bus *bus,
+ void *bus_context,
+ const struct regmap_config *config)
+{
+ int rc;
+ struct regmap **mapp, *map;
+
+ mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *),
+ __GFP_ZERO);
+ if (unlikely(!mapp))
+ return ERR_PTR(-ENOMEM);
+
+ if (config && config->r_size != 0)
+ rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start,
+ config->r_size, mapp);
+ else
+ rc = regmap_init_mem(dev_ofnode(dev), mapp);
+ if (rc)
+ return ERR_PTR(rc);
+
+ map = *mapp;
+ if (config) {
+ map->width = config->width;
+ map->reg_offset_shift = config->reg_offset_shift;
+ }
+
+ devres_add(dev, mapp);
+ return *mapp;
+}
#endif
void *regmap_get_range(struct regmap *map, unsigned int range_num)
@@ -310,6 +396,7 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
}
range = &map->ranges[range_num];
+ offset <<= map->reg_offset_shift;
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
@@ -347,7 +434,7 @@ int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
int regmap_read(struct regmap *map, uint offset, uint *valp)
{
- return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
+ return regmap_raw_read(map, offset, valp, map->width);
}
static inline void __write_8(u8 *addr, const u8 *val,
@@ -419,6 +506,7 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
}
range = &map->ranges[range_num];
+ offset <<= map->reg_offset_shift;
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
@@ -457,7 +545,7 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val,
int regmap_write(struct regmap *map, uint offset, uint val)
{
- return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
+ return regmap_raw_write(map, offset, &val, map->width);
}
int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
@@ -473,3 +561,72 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
return regmap_write(map, offset, reg | (val & mask));
}
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+ int ret;
+ unsigned int reg_val;
+
+ ret = regmap_read(field->regmap, field->reg, &reg_val);
+ if (ret != 0)
+ return ret;
+
+ reg_val &= field->mask;
+ reg_val >>= field->shift;
+ *val = reg_val;
+
+ return ret;
+}
+
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+ return regmap_update_bits(field->regmap, field->reg, field->mask,
+ val << field->shift);
+}
+
+static void regmap_field_init(struct regmap_field *rm_field,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ rm_field->regmap = regmap;
+ rm_field->reg = reg_field.reg;
+ rm_field->shift = reg_field.lsb;
+ rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
+}
+
+struct regmap_field *devm_regmap_field_alloc(struct udevice *dev,
+ struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field),
+ GFP_KERNEL);
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field)
+{
+ devm_kfree(dev, field);
+}
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+
+void regmap_field_free(struct regmap_field *field)
+{
+ kfree(field);
+}
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index b5cd763b6b..5be1d527a0 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -18,12 +18,16 @@
/*
* Caution:
- * This API requires the given device has alerady been bound to syscon driver.
- * For example,
+ * This API requires the given device has already been bound to the syscon
+ * driver. For example,
+ *
* compatible = "syscon", "simple-mfd";
+ *
* works, but
+ *
* compatible = "simple-mfd", "syscon";
- * does not. The behavior is different from Linux.
+ *
+ * does not. The behavior is different from Linux.
*/
struct regmap *syscon_get_regmap(struct udevice *dev)
{
@@ -66,7 +70,7 @@ static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp)
/* found node with "syscon" compatible, not bounded to SYSCON UCLASS */
if (!ofnode_device_is_compatible(node, "syscon")) {
- dev_dbg(dev, "invalid compatible for syscon device\n");
+ log_debug("invalid compatible for syscon device\n");
return -EINVAL;
}
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index 0b5dbc7c88..c8532637ca 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_CPU) += cpu-uclass.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o
+obj-$(CONFIG_ARCH_AT91) += at91_cpu.o
obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
obj-$(CONFIG_SANDBOX) += cpu_sandbox.o
diff --git a/drivers/cpu/at91_cpu.c b/drivers/cpu/at91_cpu.c
new file mode 100644
index 0000000000..058ae3a811
--- /dev/null
+++ b/drivers/cpu/at91_cpu.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <div64.h>
+#include <linux/clk-provider.h>
+
+struct at91_cpu_platdata {
+ const char *name;
+ ulong cpufreq_mhz;
+ ulong mckfreq_mhz;
+ ulong xtalfreq_mhz;
+};
+
+extern char *get_cpu_name(void);
+
+const char *at91_cpu_get_name(void)
+{
+ return get_cpu_name();
+}
+
+int at91_cpu_get_desc(const struct udevice *dev, char *buf, int size)
+{
+ struct at91_cpu_platdata *plat = dev_get_platdata(dev);
+
+ snprintf(buf, size, "%s\n"
+ "Crystal frequency: %8lu MHz\n"
+ "CPU clock : %8lu MHz\n"
+ "Master clock : %8lu MHz\n",
+ plat->name, plat->xtalfreq_mhz, plat->cpufreq_mhz,
+ plat->mckfreq_mhz);
+
+ return 0;
+}
+
+static int at91_cpu_get_info(const struct udevice *dev, struct cpu_info *info)
+{
+ struct at91_cpu_platdata *plat = dev_get_platdata(dev);
+
+ info->cpu_freq = plat->cpufreq_mhz * 1000000;
+ info->features = BIT(CPU_FEAT_L1_CACHE);
+
+ return 0;
+}
+
+static int at91_cpu_get_count(const struct udevice *dev)
+{
+ return 1;
+}
+
+static int at91_cpu_get_vendor(const struct udevice *dev, char *buf, int size)
+{
+ snprintf(buf, size, "Microchip Technology Inc.");
+
+ return 0;
+}
+
+static const struct cpu_ops at91_cpu_ops = {
+ .get_desc = at91_cpu_get_desc,
+ .get_info = at91_cpu_get_info,
+ .get_count = at91_cpu_get_count,
+ .get_vendor = at91_cpu_get_vendor,
+};
+
+static const struct udevice_id at91_cpu_ids[] = {
+ { .compatible = "arm,cortex-a7" },
+ { /* Sentinel. */ }
+};
+
+static int at91_cpu_probe(struct udevice *dev)
+{
+ struct at91_cpu_platdata *plat = dev_get_platdata(dev);
+ struct clk clk;
+ ulong rate;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate)
+ return -ENOTSUPP;
+ plat->cpufreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000);
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate)
+ return -ENOTSUPP;
+ plat->mckfreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000);
+
+ ret = clk_get_by_index(dev, 2, &clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate)
+ return -ENOTSUPP;
+ plat->xtalfreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000);
+
+ plat->name = get_cpu_name();
+
+ return 0;
+}
+
+U_BOOT_DRIVER(cpu_at91_drv) = {
+ .name = "at91-cpu",
+ .id = UCLASS_CPU,
+ .of_match = at91_cpu_ids,
+ .ops = &at91_cpu_ops,
+ .probe = at91_cpu_probe,
+ .platdata_auto_alloc_size = sizeof(struct at91_cpu_platdata),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c
index caa26e50f2..4ba0d1b99e 100644
--- a/drivers/cpu/cpu_sandbox.c
+++ b/drivers/cpu/cpu_sandbox.c
@@ -8,14 +8,15 @@
#include <dm.h>
#include <cpu.h>
-int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size)
+static int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size)
{
snprintf(buf, size, "LEG Inc. SuperMegaUltraTurbo CPU No. 1");
return 0;
}
-int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info)
+static int cpu_sandbox_get_info(const struct udevice *dev,
+ struct cpu_info *info)
{
info->cpu_freq = 42 * 42 * 42 * 42 * 42;
info->features = 0x42424242;
@@ -24,21 +25,29 @@ int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info)
return 0;
}
-int cpu_sandbox_get_count(const struct udevice *dev)
+static int cpu_sandbox_get_count(const struct udevice *dev)
{
return 42;
}
-int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf, int size)
+static int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf,
+ int size)
{
snprintf(buf, size, "Languid Example Garbage Inc.");
return 0;
}
-int cpu_sandbox_is_current(struct udevice *dev)
+static const char *cpu_current = "cpu-test1";
+
+void cpu_sandbox_set_current(const char *name)
{
- if (!strcmp(dev->name, "cpu-test1"))
+ cpu_current = name;
+}
+
+static int cpu_sandbox_is_current(struct udevice *dev)
+{
+ if (!strcmp(dev->name, cpu_current))
return 1;
return 0;
@@ -52,7 +61,22 @@ static const struct cpu_ops cpu_sandbox_ops = {
.is_current = cpu_sandbox_is_current,
};
-int cpu_sandbox_probe(struct udevice *dev)
+static int cpu_sandbox_bind(struct udevice *dev)
+{
+ int ret;
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+ /* first examine the property in current cpu node */
+ ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
+ /* if not found, then look at the parent /cpus node */
+ if (ret)
+ ret = dev_read_u32(dev->parent, "timebase-frequency",
+ &plat->timebase_freq);
+
+ return ret;
+}
+
+static int cpu_sandbox_probe(struct udevice *dev)
{
return 0;
}
@@ -67,5 +91,6 @@ U_BOOT_DRIVER(cpu_sandbox) = {
.id = UCLASS_CPU,
.ops = &cpu_sandbox_ops,
.of_match = cpu_sandbox_ids,
+ .bind = cpu_sandbox_bind,
.probe = cpu_sandbox_probe,
};
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index b70a206355..ef958b3a7a 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -36,3 +36,5 @@ config ZYNQMP_FIRMWARE
various platform management services.
Say yes to enable ZynqMP firmware interface driver.
If in doubt, say N.
+
+source "drivers/firmware/scmi/Kconfig"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index a0c250a473..7ce83d72bd 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_$(SPL_)ARM_PSCI_FW) += psci.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_SANDBOX) += firmware-sandbox.o
obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o
+obj-$(CONFIG_SCMI_FIRMWARE) += scmi/
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 903a8f5878..7583f24a20 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -202,6 +202,6 @@ static const struct udevice_id zynqmp_firmware_ids[] = {
U_BOOT_DRIVER(zynqmp_firmware) = {
.id = UCLASS_FIRMWARE,
- .name = "zynqmp-firmware",
+ .name = "zynqmp_firmware",
.of_match = zynqmp_firmware_ids,
};
diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
new file mode 100644
index 0000000000..c3a109beac
--- /dev/null
+++ b/drivers/firmware/scmi/Kconfig
@@ -0,0 +1,19 @@
+config SCMI_FIRMWARE
+ bool "Enable SCMI support"
+ select FIRMWARE
+ select OF_TRANSLATE
+ depends on SANDBOX || DM_MAILBOX || ARM_SMCCC
+ help
+ System Control and Management Interface (SCMI) is a communication
+ protocol that defines standard interfaces for power, performance
+ and system management. The SCMI specification is available at
+ https://developer.arm.com/architectures/system-architectures/software-standards/scmi
+
+ An SCMI agent communicates with a related SCMI server firmware
+ located in another sub-system, as a companion micro controller
+ or a companion host in the CPU system.
+
+ Communications between agent (client) and the SCMI server are
+ based on message exchange. Messages can be exchange over tranport
+ channels as a mailbox device or an Arm SMCCC service with some
+ piece of identified shared memory.
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
new file mode 100644
index 0000000000..e1e0224066
--- /dev/null
+++ b/drivers/firmware/scmi/Makefile
@@ -0,0 +1,5 @@
+obj-y += scmi_agent-uclass.o
+obj-y += smt.o
+obj-$(CONFIG_ARM_SMCCC) += smccc_agent.o
+obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o
+obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
new file mode 100644
index 0000000000..7d9fb3622e
--- /dev/null
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mailbox.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <dm/devres.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define TIMEOUT_US_10MS 10000
+
+/**
+ * struct scmi_mbox_channel - Description of an SCMI mailbox transport
+ * @smt: Shared memory buffer
+ * @mbox: Mailbox channel description
+ * @timeout_us: Timeout in microseconds for the mailbox transfer
+ */
+struct scmi_mbox_channel {
+ struct scmi_smt smt;
+ struct mbox_chan mbox;
+ ulong timeout_us;
+};
+
+static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_mbox_channel *chan = dev_get_priv(dev);
+ int ret;
+
+ ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
+ if (ret)
+ return ret;
+
+ /* Give shm addr to mbox in case it is meaningful */
+ ret = mbox_send(&chan->mbox, chan->smt.buf);
+ if (ret) {
+ dev_err(dev, "Message send failed: %d\n", ret);
+ goto out;
+ }
+
+ /* Receive the response */
+ ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us);
+ if (ret) {
+ dev_err(dev, "Response failed: %d, abort\n", ret);
+ goto out;
+ }
+
+ ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+
+out:
+ scmi_clear_smt_channel(&chan->smt);
+
+ return ret;
+}
+
+int scmi_mbox_probe(struct udevice *dev)
+{
+ struct scmi_mbox_channel *chan = dev_get_priv(dev);
+ int ret;
+
+ chan->timeout_us = TIMEOUT_US_10MS;
+
+ ret = mbox_get_by_index(dev, 0, &chan->mbox);
+ if (ret) {
+ dev_err(dev, "Failed to find mailbox: %d\n", ret);
+ goto out;
+ }
+
+ ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+ if (ret)
+ dev_err(dev, "Failed to get shm resources: %d\n", ret);
+
+out:
+ if (ret)
+ devm_kfree(dev, chan);
+
+ return ret;
+}
+
+static const struct udevice_id scmi_mbox_ids[] = {
+ { .compatible = "arm,scmi" },
+ { }
+};
+
+static const struct scmi_agent_ops scmi_mbox_ops = {
+ .process_msg = scmi_mbox_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_mbox) = {
+ .name = "scmi-over-mailbox",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = scmi_mbox_ids,
+ .priv_auto_alloc_size = sizeof(struct scmi_mbox_channel),
+ .probe = scmi_mbox_probe,
+ .ops = &scmi_mbox_ops,
+};
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
new file mode 100644
index 0000000000..5b6a4232af
--- /dev/null
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
+#include <asm/io.h>
+#include <asm/scmi_test.h>
+#include <dm/device_compat.h>
+
+/*
+ * The sandbox SCMI agent driver simulates to some extend a SCMI message
+ * processing. It simulates few of the SCMI services for some of the
+ * SCMI protocols embedded in U-Boot. Currently:
+ * - SCMI clock protocol: emulate 2 agents each exposing few clocks
+ * - SCMI reset protocol: emulate 1 agents each exposing a reset
+ *
+ * Agent #0 simulates 2 clocks and 1 reset domain.
+ * See IDs in scmi0_clk[]/scmi0_reset[] and "sandbox-scmi-agent@0" in test.dts.
+ *
+ * Agent #1 simulates 1 clock.
+ * See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts.
+ *
+ * All clocks are default disabled and reset levels down.
+ *
+ * This Driver exports sandbox_scmi_service_ct() for the test sequence to
+ * get the state of the simulated services (clock state, rate, ...) and
+ * check back-end device state reflects the request send through the
+ * various uclass devices, as clocks and reset controllers.
+ */
+
+#define SANDBOX_SCMI_AGENT_COUNT 2
+
+static struct sandbox_scmi_clk scmi0_clk[] = {
+ { .id = 7, .rate = 1000 },
+ { .id = 3, .rate = 333 },
+};
+
+static struct sandbox_scmi_reset scmi0_reset[] = {
+ { .id = 3 },
+};
+
+static struct sandbox_scmi_clk scmi1_clk[] = {
+ { .id = 1, .rate = 44 },
+};
+
+/* The list saves to simulted end devices references for test purpose */
+struct sandbox_scmi_agent *sandbox_scmi_agent_list[SANDBOX_SCMI_AGENT_COUNT];
+
+static struct sandbox_scmi_service sandbox_scmi_service_state = {
+ .agent = sandbox_scmi_agent_list,
+ .agent_count = SANDBOX_SCMI_AGENT_COUNT,
+};
+
+struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
+{
+ return &sandbox_scmi_service_state;
+}
+
+static void debug_print_agent_state(struct udevice *dev, char *str)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+
+ dev_dbg(dev, "Dump sandbox_scmi_agent %u: %s\n", agent->idx, str);
+ dev_dbg(dev, " scmi%u_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
+ agent->idx,
+ agent->clk_count,
+ agent->clk_count ? agent->clk[0].enabled : -1,
+ agent->clk_count ? agent->clk[0].rate : -1,
+ agent->clk_count > 1 ? agent->clk[1].enabled : -1,
+ agent->clk_count > 1 ? agent->clk[1].rate : -1,
+ agent->clk_count > 2 ? agent->clk[2].enabled : -1,
+ agent->clk_count > 2 ? agent->clk[2].rate : -1);
+ dev_dbg(dev, " scmi%u_reset (%zu): %d, %d, ...\n",
+ agent->idx,
+ agent->reset_count,
+ agent->reset_count ? agent->reset[0].asserted : -1,
+ agent->reset_count > 1 ? agent->reset[1].asserted : -1);
+};
+
+static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id)
+{
+ struct sandbox_scmi_clk *target = NULL;
+ size_t target_count = 0;
+ size_t n;
+
+ switch (agent_id) {
+ case 0:
+ target = scmi0_clk;
+ target_count = ARRAY_SIZE(scmi0_clk);
+ break;
+ case 1:
+ target = scmi1_clk;
+ target_count = ARRAY_SIZE(scmi1_clk);
+ break;
+ default:
+ return NULL;
+ }
+
+ for (n = 0; n < target_count; n++)
+ if (target[n].id == clock_id)
+ return target + n;
+
+ return NULL;
+}
+
+static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id,
+ uint reset_id)
+{
+ size_t n;
+
+ if (agent_id == 0) {
+ for (n = 0; n < ARRAY_SIZE(scmi0_reset); n++)
+ if (scmi0_reset[n].id == reset_id)
+ return scmi0_reset + n;
+ }
+
+ return NULL;
+}
+
+/*
+ * Sandbox SCMI agent ops
+ */
+
+static int sandbox_scmi_clock_rate_set(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_clk_rate_set_in *in = NULL;
+ struct scmi_clk_rate_set_out *out = NULL;
+ struct sandbox_scmi_clk *clk_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_clk_rate_set_in *)msg->in_msg;
+ out = (struct scmi_clk_rate_set_out *)msg->out_msg;
+
+ clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
+ if (!clk_state) {
+ dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
+
+ clk_state->rate = (ulong)rate;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_clock_rate_get(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_clk_rate_get_in *in = NULL;
+ struct scmi_clk_rate_get_out *out = NULL;
+ struct sandbox_scmi_clk *clk_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_clk_rate_get_in *)msg->in_msg;
+ out = (struct scmi_clk_rate_get_out *)msg->out_msg;
+
+ clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
+ if (!clk_state) {
+ dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ out->rate_msb = (u32)((u64)clk_state->rate >> 32);
+ out->rate_lsb = (u32)clk_state->rate;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_clk_state_in *in = NULL;
+ struct scmi_clk_state_out *out = NULL;
+ struct sandbox_scmi_clk *clk_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_clk_state_in *)msg->in_msg;
+ out = (struct scmi_clk_state_out *)msg->out_msg;
+
+ clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
+ if (!clk_state) {
+ dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else if (in->attributes > 1) {
+ out->status = SCMI_PROTOCOL_ERROR;
+ } else {
+ clk_state->enabled = in->attributes;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_rd_attr_in *in = NULL;
+ struct scmi_rd_attr_out *out = NULL;
+ struct sandbox_scmi_reset *reset_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_rd_attr_in *)msg->in_msg;
+ out = (struct scmi_rd_attr_out *)msg->out_msg;
+
+ reset_state = get_scmi_reset_state(agent->idx, in->domain_id);
+ if (!reset_state) {
+ dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ memset(out, 0, sizeof(*out));
+ snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_rd_reset_in *in = NULL;
+ struct scmi_rd_reset_out *out = NULL;
+ struct sandbox_scmi_reset *reset_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_rd_reset_in *)msg->in_msg;
+ out = (struct scmi_rd_reset_out *)msg->out_msg;
+
+ reset_state = get_scmi_reset_state(agent->idx, in->domain_id);
+ if (!reset_state) {
+ dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else if (in->reset_state > 1) {
+ dev_err(dev, "Invalid reset domain input attribute value\n");
+
+ out->status = SCMI_INVALID_PARAMETERS;
+ } else {
+ if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
+ if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
+ out->status = SCMI_NOT_SUPPORTED;
+ } else {
+ /* Ends deasserted whatever current state */
+ reset_state->asserted = false;
+ out->status = SCMI_SUCCESS;
+ }
+ } else {
+ reset_state->asserted = in->flags &
+ SCMI_RD_RESET_FLAG_ASSERT;
+
+ out->status = SCMI_SUCCESS;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_test_process_msg(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ switch (msg->protocol_id) {
+ case SCMI_PROTOCOL_ID_CLOCK:
+ switch (msg->message_id) {
+ case SCMI_CLOCK_RATE_SET:
+ return sandbox_scmi_clock_rate_set(dev, msg);
+ case SCMI_CLOCK_RATE_GET:
+ return sandbox_scmi_clock_rate_get(dev, msg);
+ case SCMI_CLOCK_CONFIG_SET:
+ return sandbox_scmi_clock_gate(dev, msg);
+ default:
+ break;
+ }
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ switch (msg->message_id) {
+ case SCMI_RESET_DOMAIN_ATTRIBUTES:
+ return sandbox_scmi_rd_attribs(dev, msg);
+ case SCMI_RESET_DOMAIN_RESET:
+ return sandbox_scmi_rd_reset(dev, msg);
+ default:
+ break;
+ }
+ break;
+ case SCMI_PROTOCOL_ID_BASE:
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ case SCMI_PROTOCOL_ID_SYSTEM:
+ case SCMI_PROTOCOL_ID_PERF:
+ case SCMI_PROTOCOL_ID_SENSOR:
+ *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
+ return 0;
+ default:
+ break;
+ }
+
+ dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
+ __func__, dev->name, msg->protocol_id, msg->message_id);
+
+ if (msg->out_msg_sz < sizeof(u32))
+ return -EINVAL;
+
+ /* Intentionnaly report unhandled IDs through the SCMI return code */
+ *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
+ return 0;
+}
+
+static int sandbox_scmi_test_remove(struct udevice *dev)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+
+ debug_print_agent_state(dev, "removed");
+
+ /* We only need to dereference the agent in the context */
+ sandbox_scmi_service_ctx()->agent[agent->idx] = NULL;
+
+ return 0;
+}
+
+static int sandbox_scmi_test_probe(struct udevice *dev)
+{
+ static const char basename[] = "sandbox-scmi-agent@";
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ const size_t basename_size = sizeof(basename) - 1;
+
+ if (strncmp(basename, dev->name, basename_size))
+ return -ENOENT;
+
+ switch (dev->name[basename_size]) {
+ case '0':
+ *agent = (struct sandbox_scmi_agent){
+ .idx = 0,
+ .clk = scmi0_clk,
+ .clk_count = ARRAY_SIZE(scmi0_clk),
+ .reset = scmi0_reset,
+ .reset_count = ARRAY_SIZE(scmi0_reset),
+ };
+ break;
+ case '1':
+ *agent = (struct sandbox_scmi_agent){
+ .idx = 1,
+ .clk = scmi1_clk,
+ .clk_count = ARRAY_SIZE(scmi1_clk),
+ };
+ break;
+ default:
+ dev_err(dev, "%s(): Unexpected agent ID %s\n",
+ __func__, dev->name + basename_size);
+ return -ENOENT;
+ }
+
+ debug_print_agent_state(dev, "probed");
+
+ /* Save reference for tests purpose */
+ sandbox_scmi_service_ctx()->agent[agent->idx] = agent;
+
+ return 0;
+};
+
+static const struct udevice_id sandbox_scmi_test_ids[] = {
+ { .compatible = "sandbox,scmi-agent" },
+ { }
+};
+
+struct scmi_agent_ops sandbox_scmi_test_ops = {
+ .process_msg = sandbox_scmi_test_process_msg,
+};
+
+U_BOOT_DRIVER(sandbox_scmi_agent) = {
+ .name = "sandbox-scmi_agent",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = sandbox_scmi_test_ids,
+ .priv_auto_alloc_size = sizeof(struct sandbox_scmi_agent),
+ .probe = sandbox_scmi_test_probe,
+ .remove = sandbox_scmi_test_remove,
+ .ops = &sandbox_scmi_test_ops,
+};
diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c
new file mode 100644
index 0000000000..c69967bf69
--- /dev/null
+++ b/drivers/firmware/scmi/sandbox-scmi_devices.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020, Linaro Limited
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <asm/scmi_test.h>
+#include <dm/device_compat.h>
+
+/*
+ * Simulate to some extent a SCMI exchange.
+ * This drivers gets SCMI resources and offers API function to the
+ * SCMI test sequence manipulate the resources, currently clock
+ * and reset controllers.
+ */
+
+#define SCMI_TEST_DEVICES_CLK_COUNT 3
+#define SCMI_TEST_DEVICES_RD_COUNT 1
+
+/*
+ * struct sandbox_scmi_device_priv - Storage for device handles used by test
+ * @clk: Array of clock instances used by tests
+ * @reset_clt: Array of the reset controller instances used by tests
+ * @devices: Resources exposed by sandbox_scmi_devices_ctx()
+ */
+struct sandbox_scmi_device_priv {
+ struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
+ struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
+ struct sandbox_scmi_devices devices;
+};
+
+struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev)
+{
+ struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
+
+ if (priv)
+ return &priv->devices;
+
+ return NULL;
+}
+
+static int sandbox_scmi_devices_remove(struct udevice *dev)
+{
+ struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev);
+ int ret = 0;
+ size_t n;
+
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
+ int ret2 = reset_free(devices->reset + n);
+
+ if (ret2 && !ret)
+ ret = ret2;
+ }
+
+ return ret;
+}
+
+static int sandbox_scmi_devices_probe(struct udevice *dev)
+{
+ struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
+ int ret;
+ size_t n;
+
+ priv->devices = (struct sandbox_scmi_devices){
+ .clk = priv->clk,
+ .clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
+ .reset = priv->reset_ctl,
+ .reset_count = SCMI_TEST_DEVICES_RD_COUNT,
+ };
+
+ for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
+ ret = clk_get_by_index(dev, n, priv->devices.clk + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on clk %zu\n", __func__, n);
+ return ret;
+ }
+ }
+
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
+ ret = reset_get_by_index(dev, n, priv->devices.reset + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on reset %zu\n", __func__, n);
+ goto err_reset;
+ }
+ }
+
+ return 0;
+
+err_reset:
+ for (; n > 0; n--)
+ reset_free(priv->devices.reset + n - 1);
+
+ return ret;
+}
+
+static const struct udevice_id sandbox_scmi_devices_ids[] = {
+ { .compatible = "sandbox,scmi-devices" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_scmi_devices) = {
+ .name = "sandbox-scmi_devices",
+ .id = UCLASS_MISC,
+ .of_match = sandbox_scmi_devices_ids,
+ .priv_auto_alloc_size = sizeof(struct sandbox_scmi_device_priv),
+ .remove = sandbox_scmi_devices_remove,
+ .probe = sandbox_scmi_devices_probe,
+};
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
new file mode 100644
index 0000000000..77160b1999
--- /dev/null
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
+
+#include <dm/device-internal.h>
+#include <linux/compat.h>
+
+/**
+ * struct error_code - Helper structure for SCMI error code conversion
+ * @scmi: SCMI error code
+ * @errno: Related standard error number
+ */
+struct error_code {
+ int scmi;
+ int errno;
+};
+
+static const struct error_code scmi_linux_errmap[] = {
+ { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
+ { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
+ { .scmi = SCMI_DENIED, .errno = -EACCES, },
+ { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
+ { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
+ { .scmi = SCMI_BUSY, .errno = -EBUSY, },
+ { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
+ { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
+ { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
+ { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
+};
+
+int scmi_to_linux_errno(s32 scmi_code)
+{
+ int n;
+
+ if (!scmi_code)
+ return 0;
+
+ for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
+ if (scmi_code == scmi_linux_errmap[n].scmi)
+ return scmi_linux_errmap[1].errno;
+
+ return -EPROTO;
+}
+
+/*
+ * SCMI agent devices binds devices of various uclasses depeding on
+ * the FDT description. scmi_bind_protocol() is a generic bind sequence
+ * called by the uclass at bind stage, that is uclass post_bind.
+ */
+static int scmi_bind_protocols(struct udevice *dev)
+{
+ int ret = 0;
+ ofnode node;
+
+ dev_for_each_subnode(node, dev) {
+ struct driver *drv = NULL;
+ u32 protocol_id;
+
+ if (!ofnode_is_available(node))
+ continue;
+
+ if (ofnode_read_u32(node, "reg", &protocol_id))
+ continue;
+
+ switch (protocol_id) {
+ case SCMI_PROTOCOL_ID_CLOCK:
+ if (IS_ENABLED(CONFIG_CLK_SCMI))
+ drv = DM_GET_DRIVER(scmi_clock);
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ if (IS_ENABLED(CONFIG_RESET_SCMI))
+ drv = DM_GET_DRIVER(scmi_reset_domain);
+ break;
+ default:
+ break;
+ }
+
+ if (!drv) {
+ dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
+ protocol_id);
+ continue;
+ }
+
+ ret = device_bind_ofnode(dev, drv, ofnode_get_name(node),
+ NULL, node, NULL);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
+{
+ return (const struct scmi_agent_ops *)dev->driver->ops;
+}
+
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ const struct scmi_agent_ops *ops = transport_dev_ops(dev);
+
+ if (ops->process_msg)
+ return ops->process_msg(dev, msg);
+
+ return -EPROTONOSUPPORT;
+}
+
+UCLASS_DRIVER(scmi_agent) = {
+ .id = UCLASS_SCMI_AGENT,
+ .name = "scmi_agent",
+ .post_bind = scmi_bind_protocols,
+};
diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
new file mode 100644
index 0000000000..85dbf9195e
--- /dev/null
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <dm/devres.h>
+#include <dm/device-internal.h>
+#include <linux/arm-smccc.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define SMCCC_RET_NOT_SUPPORTED ((unsigned long)-1)
+
+/**
+ * struct scmi_smccc_channel - Description of an SCMI SMCCC transport
+ * @func_id: SMCCC function ID used by the SCMI transport
+ * @smt: Shared memory buffer
+ */
+struct scmi_smccc_channel {
+ ulong func_id;
+ struct scmi_smt smt;
+};
+
+static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_smccc_channel *chan = dev_get_priv(dev);
+ struct arm_smccc_res res;
+ int ret;
+
+ ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
+ if (ret)
+ return ret;
+
+ arm_smccc_smc(chan->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+ ret = -ENXIO;
+ else
+ ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+
+ scmi_clear_smt_channel(&chan->smt);
+
+ return ret;
+}
+
+static int scmi_smccc_probe(struct udevice *dev)
+{
+ struct scmi_smccc_channel *chan = dev_get_priv(dev);
+ u32 func_id;
+ int ret;
+
+ if (dev_read_u32(dev, "arm,smc-id", &func_id)) {
+ dev_err(dev, "Missing property func-id\n");
+ return -EINVAL;
+ }
+
+ chan->func_id = func_id;
+
+ ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+ if (ret) {
+ dev_err(dev, "Failed to get smt resources: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id scmi_smccc_ids[] = {
+ { .compatible = "arm,scmi-smc" },
+ { }
+};
+
+static const struct scmi_agent_ops scmi_smccc_ops = {
+ .process_msg = scmi_smccc_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_smccc) = {
+ .name = "scmi-over-smccc",
+ .id = UCLASS_SCMI_AGENT,
+ .of_match = scmi_smccc_ids,
+ .priv_auto_alloc_size = sizeof(struct scmi_smccc_channel),
+ .probe = scmi_smccc_probe,
+ .ops = &scmi_smccc_ops,
+};
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
new file mode 100644
index 0000000000..ce8fe49939
--- /dev/null
+++ b/drivers/firmware/scmi/smt.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <asm/cache.h>
+#include <asm/system.h>
+#include <dm/ofnode.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#include "smt.h"
+
+/**
+ * Get shared memory configuration defined by the referred DT phandle
+ * Return with a errno compliant value.
+ */
+int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
+{
+ int ret;
+ struct ofnode_phandle_args args;
+ struct resource resource;
+ fdt32_t faddr;
+ phys_addr_t paddr;
+
+ ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);
+ if (ret)
+ return ret;
+
+ ret = ofnode_read_resource(args.node, 0, &resource);
+ if (ret)
+ return ret;
+
+ faddr = cpu_to_fdt32(resource.start);
+ paddr = ofnode_translate_address(args.node, &faddr);
+
+ smt->size = resource_size(&resource);
+ if (smt->size < sizeof(struct scmi_smt_header)) {
+ dev_err(dev, "Shared memory buffer too small\n");
+ return -EINVAL;
+ }
+
+ smt->buf = devm_ioremap(dev, paddr, smt->size);
+ if (!smt->buf)
+ return -ENOMEM;
+
+#ifdef CONFIG_ARM
+ if (dcache_status())
+ mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,
+ smt->size, DCACHE_OFF);
+#endif
+
+ return 0;
+}
+
+/**
+ * Write SCMI message @msg into a SMT shared buffer @smt.
+ * Return 0 on success and with a negative errno in case of error.
+ */
+int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ if ((!msg->in_msg && msg->in_msg_sz) ||
+ (!msg->out_msg && msg->out_msg_sz))
+ return -EINVAL;
+
+ if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+ dev_dbg(dev, "Channel busy\n");
+ return -EBUSY;
+ }
+
+ if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
+ smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
+ dev_dbg(dev, "Buffer too small\n");
+ return -ETOOSMALL;
+ }
+
+ /* Load message in shared memory */
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header);
+ hdr->msg_header = SMT_HEADER_TOKEN(0) |
+ SMT_HEADER_MESSAGE_TYPE(0) |
+ SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
+ SMT_HEADER_MESSAGE_ID(msg->message_id);
+
+ memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
+
+ return 0;
+}
+
+/**
+ * Read SCMI message from a SMT shared buffer @smt and copy it into @msg.
+ * Return 0 on success and with a negative errno in case of error.
+ */
+int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
+ dev_err(dev, "Channel unexpectedly busy\n");
+ return -EBUSY;
+ }
+
+ if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
+ dev_err(dev, "Channel error reported, reset channel\n");
+ return -ECOMM;
+ }
+
+ if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) {
+ dev_err(dev, "Buffer to small\n");
+ return -ETOOSMALL;
+ }
+
+ /* Get the data */
+ msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header);
+ memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
+
+ return 0;
+}
+
+/**
+ * Clear SMT flags in shared buffer to allow further message exchange
+ */
+void scmi_clear_smt_channel(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
diff --git a/drivers/firmware/scmi/smt.h b/drivers/firmware/scmi/smt.h
new file mode 100644
index 0000000000..a8c0987bd3
--- /dev/null
+++ b/drivers/firmware/scmi/smt.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (C) 2019-2020 Linaro Limited.
+ */
+#ifndef SCMI_SMT_H
+#define SCMI_SMT_H
+
+#include <asm/types.h>
+
+/**
+ * struct scmi_smt_header - Description of the shared memory message buffer
+ *
+ * SMT stands for Shared Memory based Transport.
+ * SMT uses 28 byte header prior message payload to handle the state of
+ * the communication channel realized by the shared memory area and
+ * to define SCMI protocol information the payload relates to.
+ */
+struct scmi_smt_header {
+ __le32 reserved;
+ __le32 channel_status;
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1)
+#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0)
+ __le32 reserved1[2];
+ __le32 flags;
+#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0)
+ __le32 length;
+ __le32 msg_header;
+ u8 msg_payload[0];
+};
+
+#define SMT_HEADER_TOKEN(token) (((token) << 18) & GENMASK(31, 18))
+#define SMT_HEADER_PROTOCOL_ID(proto) (((proto) << 10) & GENMASK(17, 10))
+#define SMT_HEADER_MESSAGE_TYPE(type) (((type) << 18) & GENMASK(9, 8))
+#define SMT_HEADER_MESSAGE_ID(id) ((id) & GENMASK(7, 0))
+
+/**
+ * struct scmi_smt - Description of a SMT memory buffer
+ * @buf: Shared memory base address
+ * @size: Shared memory byte size
+ */
+struct scmi_smt {
+ u8 *buf;
+ size_t size;
+};
+
+static inline bool scmi_smt_channel_is_free(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+}
+
+static inline bool scmi_smt_channel_reports_error(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
+
+static inline void scmi_smt_get_channel(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+}
+
+static inline void scmi_smt_put_channel(struct scmi_smt *smt)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ hdr->channel_status |= SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
+ hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
+}
+
+int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt);
+
+int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg);
+
+int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
+ struct scmi_msg *msg);
+
+void scmi_clear_smt_channel(struct scmi_smt *smt);
+
+#endif /* SCMI_SMT_H */
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index e311f55ef8..a2beb0079d 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -619,7 +619,7 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
return ret;
}
@@ -1591,7 +1591,7 @@ static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
return ret;
}
@@ -1639,7 +1639,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
(u32 *)&req, sizeof(req), sizeof(*resp));
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
- dev_err(dev, "Message alloc failed(%d)\n", ret);
+ dev_err(info->dev, "Message alloc failed(%d)\n", ret);
return ret;
}
@@ -1649,7 +1649,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
goto fail;
}
@@ -1745,7 +1745,7 @@ static int ti_sci_cmd_query_msmc(const struct ti_sci_handle *handle,
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "Mbox send fail %d\n", ret);
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
return ret;
}
@@ -2229,6 +2229,14 @@ static int ti_sci_cmd_proc_shutdown_no_wait(const struct ti_sci_handle *handle,
u8 proc_id)
{
int ret;
+ struct ti_sci_info *info;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ info = handle_to_ti_sci_info(handle);
/*
* Send the core boot status wait message waiting for either WFE or
@@ -2554,7 +2562,8 @@ static int ti_sci_cmd_rm_udmap_rx_flow_cfg(
(u32 *)&req, sizeof(req), sizeof(*resp));
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
- dev_err(dev, "RX_FL_CFG: Message alloc failed(%d)\n", ret);
+ dev_err(info->dev, "RX_FL_CFG: Message alloc failed(%d)\n",
+ ret);
return ret;
}
@@ -2583,7 +2592,7 @@ static int ti_sci_cmd_rm_udmap_rx_flow_cfg(
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
- dev_err(dev, "RX_FL_CFG: Mbox send fail %d\n", ret);
+ dev_err(info->dev, "RX_FL_CFG: Mbox send fail %d\n", ret);
goto fail;
}
diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c
index 5b103cfeaf..8ce140a2e1 100644
--- a/drivers/fpga/zynqmppl.c
+++ b/drivers/fpga/zynqmppl.c
@@ -231,11 +231,11 @@ static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
buf_hi = upper_32_bits(bin_buf);
if (xilfpga_old)
- ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
+ ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
buf_hi, (u32)(uintptr_t)bsizeptr,
bstype, ret_payload);
else
- ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
+ ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
buf_hi, (u32)bsize, 0, ret_payload);
if (ret)
@@ -277,7 +277,7 @@ static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize,
buf_lo = lower_32_bits((ulong)buf);
buf_hi = upper_32_bits((ulong)buf);
- ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
+ ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
buf_hi,
(u32)(uintptr_t)fpga_sec_info->userkey_addr,
flag, ret_payload);
@@ -295,7 +295,7 @@ static int zynqmp_pcap_info(xilinx_desc *desc)
int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
- ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_STATUS, 0, 0, 0,
+ ret = xilinx_pm_request(PM_FPGA_GET_STATUS, 0, 0, 0,
0, ret_payload);
if (!ret)
printf("PCAP status\t0x%x\n", ret_payload[1]);
@@ -305,7 +305,7 @@ static int zynqmp_pcap_info(xilinx_desc *desc)
struct xilinx_fpga_op zynqmp_op = {
.load = zynqmp_load,
-#if defined CONFIG_CMD_FPGA_LOAD_SECURE
+#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) && !defined(CONFIG_SPL_BUILD)
.loads = zynqmp_loads,
#endif
.info = zynqmp_pcap_info,
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 9c53299b6a..0c01413b58 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -6,6 +6,8 @@
#include <common.h>
#include <dm.h>
#include <log.h>
+#include <dm/devres.h>
+#include <dm/device_compat.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/uclass-internal.h>
@@ -1209,6 +1211,75 @@ int gpio_dev_request_index(struct udevice *dev, const char *nodename,
flags, 0, dev);
}
+static void devm_gpiod_release(struct udevice *dev, void *res)
+{
+ dm_gpio_free(dev, res);
+}
+
+static int devm_gpiod_match(struct udevice *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id,
+ unsigned int index, int flags)
+{
+ int rc;
+ struct gpio_desc *desc;
+ char *propname;
+ static const char suffix[] = "-gpios";
+
+ propname = malloc(strlen(id) + sizeof(suffix));
+ if (!propname) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ strcpy(propname, id);
+ strcat(propname, suffix);
+
+ desc = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc),
+ __GFP_ZERO);
+ if (unlikely(!desc)) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = gpio_request_by_name(dev, propname, index, desc, flags);
+
+end:
+ if (propname)
+ free(propname);
+
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, desc);
+
+ return desc;
+}
+
+struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev,
+ const char *id,
+ unsigned int index,
+ int flags)
+{
+ struct gpio_desc *desc = devm_gpiod_get_index(dev, id, index, flags);
+
+ if (IS_ERR(desc))
+ return NULL;
+
+ return desc;
+}
+
+void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_gpiod_release, devm_gpiod_match, desc);
+ WARN_ON(rc);
+}
+
static int gpio_post_bind(struct udevice *dev)
{
struct udevice *child;
diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c
index 5bff27f75b..473e364796 100644
--- a/drivers/gpio/stm32_gpio.c
+++ b/drivers/gpio/stm32_gpio.c
@@ -273,9 +273,12 @@ static const struct dm_gpio_ops gpio_stm32_ops = {
static int gpio_stm32_probe(struct udevice *dev)
{
struct stm32_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ofnode_phandle_args args;
+ const char *name;
struct clk clk;
fdt_addr_t addr;
- int ret;
+ int ret, i;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
@@ -283,11 +286,6 @@ static int gpio_stm32_probe(struct udevice *dev)
priv->regs = (struct stm32_gpio_regs *)addr;
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- struct ofnode_phandle_args args;
- const char *name;
- int i;
-
name = dev_read_string(dev, "st,bank-name");
if (!name)
return -EINVAL;
@@ -297,6 +295,9 @@ static int gpio_stm32_probe(struct udevice *dev)
ret = dev_read_phandle_with_args(dev, "gpio-ranges",
NULL, 3, i, &args);
+ if (!ret && args.args_count < 3)
+ return -EINVAL;
+
if (ret == -ENOENT) {
uc_priv->gpio_count = STM32_GPIOS_PER_BANK;
priv->gpio_range = GENMASK(STM32_GPIOS_PER_BANK - 1, 0);
@@ -310,6 +311,8 @@ static int gpio_stm32_probe(struct udevice *dev)
ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3,
++i, &args);
+ if (!ret && args.args_count < 3)
+ return -EINVAL;
}
dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n",
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index f7b2786448..bd248cbf52 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -3,6 +3,9 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
+ifdef CONFIG_ACPIGEN
+obj-$(CONFIG_DM_I2C) += acpi_i2c.o
+endif
obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
diff --git a/drivers/i2c/acpi_i2c.c b/drivers/i2c/acpi_i2c.c
new file mode 100644
index 0000000000..57d29683cb
--- /dev/null
+++ b/drivers/i2c/acpi_i2c.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_dp.h>
+#ifdef CONFIG_X86
+#include <asm/intel_pinctrl_defs.h>
+#endif
+#include <asm-generic/gpio.h>
+#include <dm/acpi.h>
+
+static bool acpi_i2c_add_gpios_to_crs(struct acpi_i2c_priv *priv)
+{
+ /*
+ * Return false if:
+ * 1. Request to explicitly disable export of GPIOs in CRS, or
+ * 2. Both reset and enable GPIOs are not provided.
+ */
+ if (priv->disable_gpio_export_in_crs ||
+ (!dm_gpio_is_valid(&priv->reset_gpio) &&
+ !dm_gpio_is_valid(&priv->enable_gpio)))
+ return false;
+
+ return true;
+}
+
+static int acpi_i2c_write_gpio(struct acpi_ctx *ctx, struct gpio_desc *gpio,
+ int *curindex)
+{
+ int ret;
+
+ if (!dm_gpio_is_valid(gpio))
+ return -ENOENT;
+
+ acpi_device_write_gpio_desc(ctx, gpio);
+ ret = *curindex;
+ (*curindex)++;
+
+ return ret;
+}
+
+int acpi_i2c_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ int reset_gpio_index = -1, enable_gpio_index = -1, irq_gpio_index = -1;
+ enum i2c_device_t type = dev_get_driver_data(dev);
+ struct acpi_i2c_priv *priv = dev_get_priv(dev);
+ struct acpi_dp *dsd = NULL;
+ char scope[ACPI_PATH_MAX];
+ char name[ACPI_NAME_MAX];
+ int tx_state_val;
+ int curindex = 0;
+ int ret;
+
+#ifdef CONFIG_X86
+ tx_state_val = PAD_CFG0_TX_STATE;
+#elif defined(CONFIG_SANDBOX)
+ tx_state_val = BIT(7); /* test value */
+#else
+#error "Not supported on this architecture"
+#endif
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+ ret = acpi_device_scope(dev, scope, sizeof(scope));
+ if (ret)
+ return log_msg_ret("scope", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, scope);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_string(ctx, "_HID", priv->hid);
+ if (type == I2C_DEVICE_HID_OVER_I2C)
+ acpigen_write_name_string(ctx, "_CID", "PNP0C50");
+ acpigen_write_name_integer(ctx, "_UID", priv->uid);
+ acpigen_write_name_string(ctx, "_DDN", priv->desc);
+ acpigen_write_sta(ctx, acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name(ctx, "_CRS");
+ acpigen_write_resourcetemplate_header(ctx);
+ acpi_device_write_i2c_dev(ctx, dev);
+
+ /* Use either Interrupt() or GpioInt() */
+ if (dm_gpio_is_valid(&priv->irq_gpio)) {
+ irq_gpio_index = acpi_i2c_write_gpio(ctx, &priv->irq_gpio,
+ &curindex);
+ } else {
+ ret = acpi_device_write_interrupt_irq(ctx, &priv->irq);
+ if (ret < 0)
+ return log_msg_ret("irq", ret);
+ }
+
+ if (acpi_i2c_add_gpios_to_crs(priv)) {
+ reset_gpio_index = acpi_i2c_write_gpio(ctx, &priv->reset_gpio,
+ &curindex);
+ enable_gpio_index = acpi_i2c_write_gpio(ctx, &priv->enable_gpio,
+ &curindex);
+ }
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ /* Wake capabilities */
+ if (priv->wake) {
+ acpigen_write_name_integer(ctx, "_S0W", 4);
+ acpigen_write_prw(ctx, priv->wake, 3);
+ }
+
+ /* DSD */
+ if (priv->probed || priv->property_count || priv->compat_string ||
+ reset_gpio_index >= 0 || enable_gpio_index >= 0 ||
+ irq_gpio_index >= 0) {
+ char path[ACPI_PATH_MAX];
+
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+
+ dsd = acpi_dp_new_table("_DSD");
+ if (priv->compat_string)
+ acpi_dp_add_string(dsd, "compatible",
+ priv->compat_string);
+ if (priv->probed)
+ acpi_dp_add_integer(dsd, "linux,probed", 1);
+ if (irq_gpio_index >= 0)
+ acpi_dp_add_gpio(dsd, "irq-gpios", path,
+ irq_gpio_index, 0,
+ priv->irq_gpio.flags &
+ GPIOD_ACTIVE_LOW ?
+ ACPI_GPIO_ACTIVE_LOW : 0);
+ if (reset_gpio_index >= 0)
+ acpi_dp_add_gpio(dsd, "reset-gpios", path,
+ reset_gpio_index, 0,
+ priv->reset_gpio.flags &
+ GPIOD_ACTIVE_LOW ?
+ ACPI_GPIO_ACTIVE_LOW : 0);
+ if (enable_gpio_index >= 0)
+ acpi_dp_add_gpio(dsd, "enable-gpios", path,
+ enable_gpio_index, 0,
+ priv->enable_gpio.flags &
+ GPIOD_ACTIVE_LOW ?
+ ACPI_GPIO_ACTIVE_LOW : 0);
+ /* Generic property list is not supported */
+ acpi_dp_write(ctx, dsd);
+ }
+
+ /* Power Resource */
+ if (priv->has_power_resource) {
+ ret = acpi_device_add_power_res(ctx, tx_state_val,
+ "\\_SB.GPC0", "\\_SB.SPC0",
+ &priv->reset_gpio, priv->reset_delay_ms,
+ priv->reset_off_delay_ms, &priv->enable_gpio,
+ priv->enable_delay_ms, priv->enable_off_delay_ms,
+ &priv->stop_gpio, priv->stop_delay_ms,
+ priv->stop_off_delay_ms);
+ if (ret)
+ return log_msg_ret("power", ret);
+ }
+ if (priv->hid_desc_reg_offset) {
+ ret = acpi_device_write_dsm_i2c_hid(ctx,
+ priv->hid_desc_reg_offset);
+ if (ret)
+ return log_msg_ret("dsm", ret);
+ }
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
+int acpi_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+ struct acpi_i2c_priv *priv = dev_get_priv(dev);
+
+ gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
+ GPIOD_IS_OUT);
+ gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable_gpio,
+ GPIOD_IS_OUT);
+ gpio_request_by_name(dev, "irq-gpios", 0, &priv->irq_gpio, GPIOD_IS_IN);
+ gpio_request_by_name(dev, "stop-gpios", 0, &priv->stop_gpio,
+ GPIOD_IS_OUT);
+ irq_get_by_index(dev, 0, &priv->irq);
+ priv->hid = dev_read_string(dev, "acpi,hid");
+ if (!priv->hid)
+ return log_msg_ret("hid", -EINVAL);
+ dev_read_u32(dev, "acpi,uid", &priv->uid);
+ priv->desc = dev_read_string(dev, "acpi,ddn");
+ dev_read_u32(dev, "acpi,wake", &priv->wake);
+ priv->probed = dev_read_bool(dev, "linux,probed");
+ priv->compat_string = dev_read_string(dev, "acpi,compatible");
+ priv->has_power_resource = dev_read_bool(dev,
+ "acpi,has-power-resource");
+ dev_read_u32(dev, "hid-descr-addr", &priv->hid_desc_reg_offset);
+ dev_read_u32(dev, "reset-delay-ms", &priv->reset_delay_ms);
+ dev_read_u32(dev, "reset-off-delay-ms", &priv->reset_off_delay_ms);
+ dev_read_u32(dev, "enable-delay-ms", &priv->enable_delay_ms);
+ dev_read_u32(dev, "enable-off-delay-ms", &priv->enable_off_delay_ms);
+ dev_read_u32(dev, "stop-delay-ms", &priv->stop_delay_ms);
+ dev_read_u32(dev, "stop-off-delay-ms", &priv->stop_off_delay_ms);
+
+ return 0;
+}
+
+/* Use name specified in priv or build one from I2C address */
+static int acpi_i2c_get_name(const struct udevice *dev, char *out_name)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+ struct acpi_i2c_priv *priv = dev_get_priv(dev);
+
+ snprintf(out_name, ACPI_NAME_MAX,
+ priv->hid_desc_reg_offset ? "H%03X" : "D%03X",
+ chip->chip_addr);
+
+ return 0;
+}
+
+struct acpi_ops acpi_i2c_ops = {
+ .fill_ssdt = acpi_i2c_fill_ssdt,
+ .get_name = acpi_i2c_get_name,
+};
diff --git a/drivers/i2c/acpi_i2c.h b/drivers/i2c/acpi_i2c.h
new file mode 100644
index 0000000000..1f4be29601
--- /dev/null
+++ b/drivers/i2c/acpi_i2c.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ACPI_I2C_H
+#define __ACPI_I2C_H
+
+#include <dm/acpi.h>
+
+extern struct acpi_ops acpi_i2c_ops;
+
+int acpi_i2c_ofdata_to_platdata(struct udevice *dev);
+
+#endif
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c
index 024c63c4ea..7144d39984 100644
--- a/drivers/i2c/i2c-cdns.c
+++ b/drivers/i2c/i2c-cdns.c
@@ -500,7 +500,7 @@ static const struct udevice_id cdns_i2c_of_match[] = {
};
U_BOOT_DRIVER(cdns_i2c) = {
- .name = "i2c-cdns",
+ .name = "i2c_cdns",
.id = UCLASS_I2C,
.of_match = cdns_i2c_of_match,
.ofdata_to_platdata = cdns_i2c_ofdata_to_platdata,
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 2373aa2ea4..5c4626b044 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -9,6 +9,8 @@
#include <i2c.h>
#include <log.h>
#include <malloc.h>
+#include <acpi/acpi_device.h>
+#include <dm/acpi.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
@@ -16,6 +18,7 @@
#include <asm/gpio.h>
#endif
#include <linux/delay.h>
+#include "acpi_i2c.h"
#define I2C_MAX_OFFSET_LEN 4
@@ -749,7 +752,21 @@ UCLASS_DRIVER(i2c_generic) = {
.name = "i2c_generic",
};
+static const struct udevice_id generic_chip_i2c_ids[] = {
+ { .compatible = "i2c-chip", .data = I2C_DEVICE_GENERIC },
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ { .compatible = "hid-over-i2c", .data = I2C_DEVICE_HID_OVER_I2C },
+#endif
+ { }
+};
+
U_BOOT_DRIVER(i2c_generic_chip_drv) = {
.name = "i2c_generic_chip_drv",
.id = UCLASS_I2C_GENERIC,
+ .of_match = generic_chip_i2c_ids,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .ofdata_to_platdata = acpi_i2c_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct acpi_i2c_priv),
+#endif
+ ACPI_OPS_PTR(&acpi_i2c_ops)
};
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index e3d980a9df..7609594bd0 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -941,7 +941,8 @@ static int mxc_i2c_probe(struct udevice *bus)
*/
ret = fdt_stringlist_search(fdt, node, "pinctrl-names", "gpio");
if (ret < 0) {
- debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n", bus->seq, i2c_bus->base);
+ debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n",
+ bus->seq, i2c_bus->base);
} else {
ret = gpio_request_by_name_nodev(offset_to_ofnode(node),
"scl-gpios", 0, &i2c_bus->scl_gpio,
@@ -952,7 +953,9 @@ static int mxc_i2c_probe(struct udevice *bus)
if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) ||
!dm_gpio_is_valid(&i2c_bus->scl_gpio) ||
ret || ret2) {
- dev_err(dev, "i2c bus %d at %lu, fail to request scl/sda gpio\n", bus->seq, i2c_bus->base);
+ dev_err(bus,
+ "i2c bus %d at %lu, fail to request scl/sda gpio\n",
+ bus->seq, i2c_bus->base);
return -EINVAL;
}
}
diff --git a/drivers/mailbox/k3-sec-proxy.c b/drivers/mailbox/k3-sec-proxy.c
index 3f9afaed32..27ccc6eab0 100644
--- a/drivers/mailbox/k3-sec-proxy.c
+++ b/drivers/mailbox/k3-sec-proxy.c
@@ -212,14 +212,16 @@ static int k3_sec_proxy_send(struct mbox_chan *chan, const void *data)
ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
if (ret) {
- dev_err(dev, "%s: Thread%d verification failed. ret = %d\n",
+ dev_err(chan->dev,
+ "%s: Thread%d verification failed. ret = %d\n",
__func__, spt->id, ret);
return ret;
}
/* Check the message size. */
if (msg->len > spm->desc->max_msg_size) {
- printf("%s: Thread %ld message length %zu > max msg size %d\n",
+ dev_err(chan->dev,
+ "%s: Thread %ld message length %zu > max msg size %d\n",
__func__, chan->id, msg->len, spm->desc->max_msg_size);
return -EINVAL;
}
diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c
index b8bf356b4a..81a4115986 100644
--- a/drivers/mailbox/stm32-ipcc.c
+++ b/drivers/mailbox/stm32-ipcc.c
@@ -101,9 +101,8 @@ static int stm32_ipcc_probe(struct udevice *dev)
{
struct stm32_ipcc *ipcc = dev_get_priv(dev);
fdt_addr_t addr;
- const fdt32_t *cell;
struct clk clk;
- int len, ret;
+ int ret;
debug("%s(dev=%p)\n", __func__, dev);
@@ -114,14 +113,12 @@ static int stm32_ipcc_probe(struct udevice *dev)
ipcc->reg_base = (void __iomem *)addr;
/* proc_id */
- cell = dev_read_prop(dev, "st,proc_id", &len);
- if (len < sizeof(fdt32_t)) {
+ ret = dev_read_u32_index(dev, "st,proc_id", 1, &ipcc->proc_id);
+ if (ret) {
dev_dbg(dev, "Missing st,proc_id\n");
return -EINVAL;
}
- ipcc->proc_id = fdtdec_get_number(cell, 1);
-
if (ipcc->proc_id >= STM32_MAX_PROCS) {
dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id);
return -EINVAL;
diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c
index 746377e557..9483ed9cef 100644
--- a/drivers/mailbox/zynqmp-ipi.c
+++ b/drivers/mailbox/zynqmp-ipi.c
@@ -133,7 +133,7 @@ struct mbox_ops zynqmp_ipi_mbox_ops = {
};
U_BOOT_DRIVER(zynqmp_ipi) = {
- .name = "zynqmp-ipi",
+ .name = "zynqmp_ipi",
.id = UCLASS_MAILBOX,
.of_match = zynqmp_ipi_ids,
.probe = zynqmp_ipi_probe,
diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 0c53caf448..f56ae63bc2 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -79,14 +79,20 @@ static int atmel_sdhci_probe(struct udevice *dev)
if (ret)
return ret;
- ret = clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
- if (ret)
- return ret;
+ clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
max_clk = clk_get_rate(&clk);
if (!max_clk)
return -EINVAL;
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ ret = mmc_of_parse(dev, &plat->cfg);
+ if (ret)
+ return ret;
+
host->max_clk = max_clk;
host->mmc = &plat->mmc;
host->mmc->dev = dev;
@@ -113,6 +119,7 @@ static int atmel_sdhci_bind(struct udevice *dev)
static const struct udevice_id atmel_sdhci_ids[] = {
{ .compatible = "atmel,sama5d2-sdhci" },
{ .compatible = "microchip,sam9x60-sdhci" },
+ { .compatible = "microchip,sama7g5-sdhci" },
{ }
};
diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c
index b793028ab5..ea8b385d7e 100644
--- a/drivers/mmc/bcm2835_sdhost.c
+++ b/drivers/mmc/bcm2835_sdhost.c
@@ -185,22 +185,22 @@ struct bcm2835_host {
static void bcm2835_dumpregs(struct bcm2835_host *host)
{
- dev_dbg(dev, "=========== REGISTER DUMP ===========\n");
- dev_dbg(dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD));
- dev_dbg(dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG));
- dev_dbg(dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT));
- dev_dbg(dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV));
- dev_dbg(dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0));
- dev_dbg(dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1));
- dev_dbg(dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2));
- dev_dbg(dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3));
- dev_dbg(dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS));
- dev_dbg(dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD));
- dev_dbg(dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM));
- dev_dbg(dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG));
- dev_dbg(dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT));
- dev_dbg(dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC));
- dev_dbg(dev, "===========================================\n");
+ dev_dbg(host->dev, "=========== REGISTER DUMP ===========\n");
+ dev_dbg(host->dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD));
+ dev_dbg(host->dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG));
+ dev_dbg(host->dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT));
+ dev_dbg(host->dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV));
+ dev_dbg(host->dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0));
+ dev_dbg(host->dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1));
+ dev_dbg(host->dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2));
+ dev_dbg(host->dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3));
+ dev_dbg(host->dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS));
+ dev_dbg(host->dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD));
+ dev_dbg(host->dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM));
+ dev_dbg(host->dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG));
+ dev_dbg(host->dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT));
+ dev_dbg(host->dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC));
+ dev_dbg(host->dev, "===========================================\n");
}
static void bcm2835_reset_internal(struct bcm2835_host *host)
@@ -738,7 +738,7 @@ static void bcm2835_add_host(struct bcm2835_host *host)
cfg->f_min = host->max_clk / SDCDIV_MAX_CDIV;
cfg->b_max = 65535;
- dev_dbg(dev, "f_max %d, f_min %d\n",
+ dev_dbg(host->dev, "f_max %d, f_min %d\n",
cfg->f_max, cfg->f_min);
/* host controller capabilities */
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index bd1fb09d1c..30fe7a0aa2 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -774,7 +774,8 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width)
writel(val, &host->base->sdc_cfg);
}
-static void msdc_set_mclk(struct msdc_host *host, enum bus_mode timing, u32 hz)
+static void msdc_set_mclk(struct udevice *dev,
+ struct msdc_host *host, enum bus_mode timing, u32 hz)
{
u32 mode;
u32 div;
@@ -897,7 +898,7 @@ static int msdc_ops_set_ios(struct udevice *dev)
clock = mmc->cfg->f_min;
if (host->mclk != clock || host->timing != mmc->selected_mode)
- msdc_set_mclk(host, mmc->selected_mode, clock);
+ msdc_set_mclk(dev, host, mmc->selected_mode, clock);
return 0;
}
@@ -957,7 +958,8 @@ static int get_delay_len(u32 delay, u32 start_bit)
return PAD_DELAY_MAX - start_bit;
}
-static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+static struct msdc_delay_phase get_best_delay(struct udevice *dev,
+ struct msdc_host *host, u32 delay)
{
int start = 0, len = 0;
int start_final = 0, len_final = 0;
@@ -1067,7 +1069,7 @@ static int hs400_tune_response(struct udevice *dev, u32 opcode)
}
}
- final_cmd_delay = get_best_delay(host, cmd_delay);
+ final_cmd_delay = get_best_delay(dev, host, cmd_delay);
clrsetbits_le32(tune_reg, PAD_CMD_TUNE_RX_DLY3,
final_cmd_delay.final_phase <<
PAD_CMD_TUNE_RX_DLY3_S);
@@ -1117,7 +1119,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode)
}
}
- final_rise_delay = get_best_delay(host, rise_delay);
+ final_rise_delay = get_best_delay(dev, host, rise_delay);
/* if rising edge has enough margin, do not scan falling edge */
if (final_rise_delay.maxlen >= 12 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
@@ -1139,7 +1141,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode)
}
}
- final_fall_delay = get_best_delay(host, fall_delay);
+ final_fall_delay = get_best_delay(dev, host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
@@ -1171,7 +1173,7 @@ skip_fall:
dev_err(dev, "Final internal delay: 0x%x\n", internal_delay);
- internal_delay_phase = get_best_delay(host, internal_delay);
+ internal_delay_phase = get_best_delay(dev, host, internal_delay);
clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
internal_delay_phase.final_phase <<
MSDC_PAD_TUNE_CMDRRDLY_S);
@@ -1214,7 +1216,7 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
}
}
- final_rise_delay = get_best_delay(host, rise_delay);
+ final_rise_delay = get_best_delay(dev, host, rise_delay);
if (final_rise_delay.maxlen >= 12 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
@@ -1237,7 +1239,7 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode)
}
}
- final_fall_delay = get_best_delay(host, fall_delay);
+ final_fall_delay = get_best_delay(dev, host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
@@ -1293,7 +1295,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode)
rise_delay |= (1 << i);
}
- final_rise_delay = get_best_delay(host, rise_delay);
+ final_rise_delay = get_best_delay(dev, host, rise_delay);
if (final_rise_delay.maxlen >= 12 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
@@ -1309,7 +1311,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode)
fall_delay |= (1 << i);
}
- final_fall_delay = get_best_delay(host, fall_delay);
+ final_fall_delay = get_best_delay(dev, host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index e9381b9493..775c17baac 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -191,7 +191,7 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
#if defined(CONFIG_ARCH_ZYNQMP)
const struct sdhci_ops arasan_ops = {
- .platform_execute_tuning = &arasan_sdhci_execute_tuning,
+ .platform_execute_tuning = &arasan_sdhci_execute_tuning,
.set_delay = &arasan_sdhci_set_tapdelay,
.set_control_reg = &arasan_sdhci_set_control_reg,
};
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 06b2ff972c..df4cbd52cf 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -233,7 +233,7 @@ endif
config NAND_ARASAN
bool "Configure Arasan Nand"
select SYS_NAND_SELF_INIT
- select DM_MTD
+ depends on DM_MTD
imply CMD_NAND
help
This enables Nand driver support for Arasan nand flash
diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c
index 6c1d64054c..0615e50378 100644
--- a/drivers/mtd/nand/raw/arasan_nfc.c
+++ b/drivers/mtd/nand/raw/arasan_nfc.c
@@ -1306,7 +1306,7 @@ static const struct udevice_id arasan_nand_dt_ids[] = {
};
U_BOOT_DRIVER(arasan_nand) = {
- .name = "arasan-nand",
+ .name = "arasan_nand",
.id = UCLASS_MTD,
.of_match = arasan_nand_dt_ids,
.probe = arasan_probe,
diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
index 5e95901e27..abc432c862 100644
--- a/drivers/mtd/nand/raw/atmel_nand.c
+++ b/drivers/mtd/nand/raw/atmel_nand.c
@@ -424,7 +424,8 @@ static int pmecc_err_location(struct mtd_info *mtd)
}
if (!timeout) {
- dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n");
+ dev_err(mtd->dev,
+ "Timeout to calculate PMECC error location\n");
return -1;
}
@@ -464,7 +465,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
*(buf + byte_pos) ^= (1 << bit_pos);
pos = sector_num * host->pmecc_sector_size + byte_pos;
- dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+ dev_dbg(mtd->dev,
+ "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, *(buf + byte_pos));
} else {
/* Bit flip in OOB area */
@@ -474,7 +476,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
ecc[tmp] ^= (1 << bit_pos);
pos = tmp + nand_chip->ecc.layout->eccpos[0];
- dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+ dev_dbg(mtd->dev,
+ "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, ecc[tmp]);
}
@@ -516,7 +519,7 @@ normal_check:
err_nbr = pmecc_err_location(mtd);
if (err_nbr == -1) {
- dev_err(host->dev, "PMECC: Too many errors\n");
+ dev_err(mtd->dev, "PMECC: Too many errors\n");
mtd->ecc_stats.failed++;
return -EBADMSG;
} else {
@@ -560,7 +563,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
}
if (!timeout) {
- dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n");
+ dev_err(mtd->dev, "Timeout to read PMECC page\n");
return -1;
}
@@ -600,7 +603,8 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
}
if (!timeout) {
- dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
+ dev_err(mtd->dev,
+ "Timeout to read PMECC status, fail to write PMECC in oob\n");
goto out;
}
@@ -713,7 +717,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
if (*cap == 0 && *sector_size == 0) {
/* Non-ONFI compliant */
- dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n");
+ dev_info(chip->mtd.dev,
+ "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n");
*cap = 2;
*sector_size = 512;
}
@@ -835,17 +840,20 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
* from ONFI.
*/
if (pmecc_choose_ecc(host, nand, &cap, &sector_size)) {
- dev_err(host->dev, "Required ECC %d bits in %d bytes not supported!\n",
+ dev_err(mtd->dev,
+ "Required ECC %d bits in %d bytes not supported!\n",
cap, sector_size);
return -EINVAL;
}
if (cap > host->pmecc_corr_cap)
- dev_info(host->dev, "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n",
- host->pmecc_corr_cap, cap);
+ dev_info(mtd->dev,
+ "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n",
+ host->pmecc_corr_cap, cap);
if (sector_size < host->pmecc_sector_size)
- dev_info(host->dev, "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n",
- host->pmecc_sector_size, sector_size);
+ dev_info(mtd->dev,
+ "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n",
+ host->pmecc_sector_size, sector_size);
#else /* CONFIG_SYS_NAND_ONFI_DETECTION */
host->pmecc_corr_cap = CONFIG_PMECC_CAP;
host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE;
@@ -877,7 +885,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
#if defined(NO_GALOIS_TABLE_IN_ROM)
pmecc_galois_table = create_lookup_table(host->pmecc_sector_size);
if (!pmecc_galois_table) {
- dev_err(host->dev, "out of memory\n");
+ dev_err(mtd->dev, "out of memory\n");
return -ENOMEM;
}
@@ -909,13 +917,14 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
host->pmecc_sector_number;
if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) {
- dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n",
- MTD_MAX_ECCPOS_ENTRIES_LARGE);
+ dev_err(mtd->dev,
+ "too large eccpos entries. max support ecc.bytes is %d\n",
+ MTD_MAX_ECCPOS_ENTRIES_LARGE);
return -EINVAL;
}
if (nand->ecc.bytes > mtd->oobsize - PMECC_OOB_RESERVED_BYTES) {
- dev_err(host->dev, "No room for ECC bytes\n");
+ dev_err(mtd->dev, "No room for ECC bytes\n");
return -EINVAL;
}
pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
@@ -926,7 +935,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
case 512:
case 1024:
/* TODO */
- dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n");
+ dev_err(mtd->dev,
+ "Unsupported page size for PMECC, use Software ECC\n");
default:
/* page size not handled by HW ECC */
/* switching back to soft ECC */
@@ -940,7 +950,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
/* Allocate data for PMECC computation */
if (pmecc_data_alloc(host)) {
- dev_err(host->dev, "Cannot allocate memory for PMECC computation!\n");
+ dev_err(mtd->dev,
+ "Cannot allocate memory for PMECC computation!\n");
return -ENOMEM;
}
@@ -951,7 +962,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
/* Check the PMECC ip version */
host->pmecc_version = pmecc_readl(host->pmerrloc, version);
- dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version);
+ dev_dbg(mtd->dev, "PMECC IP version is: %x\n", host->pmecc_version);
atmel_pmecc_core_init(mtd);
@@ -1114,8 +1125,8 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
/* it doesn't seems to be a freshly
* erased block.
* We can't correct so many errors */
- dev_warn(host->dev, "atmel_nand : multiple errors detected."
- " Unable to correct.\n");
+ dev_warn(mtd->dev,
+ "multiple errors detected. Unable to correct.\n");
return -EBADMSG;
}
@@ -1124,15 +1135,14 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
/* there's nothing much to do here.
* the bit error is on the ECC itself.
*/
- dev_warn(host->dev, "atmel_nand : one bit error on ECC code."
- " Nothing to correct\n");
+ dev_warn(mtd->dev,
+ "one bit error on ECC code. Nothing to correct\n");
return 0;
}
- dev_warn(host->dev, "atmel_nand : one bit error on data."
- " (word offset in the page :"
- " 0x%x bit offset : 0x%x)\n",
- ecc_word, ecc_bit);
+ dev_warn(mtd->dev,
+ "one bit error on data. (word offset in the page : 0x%x bit offset : 0x%x)\n",
+ ecc_word, ecc_bit);
/* correct the error */
if (nand_chip->options & NAND_BUSWIDTH_16) {
/* 16 bits words */
@@ -1141,7 +1151,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
/* 8 bits words */
dat[ecc_word] ^= (1 << ecc_bit);
}
- dev_warn(host->dev, "atmel_nand : error corrected\n");
+ dev_warn(mtd->dev, "error corrected\n");
return 1;
}
@@ -1511,7 +1521,6 @@ void board_nand_init(void)
int i;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
if (atmel_nand_chip_init(i, base_addr[i]))
- dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip",
- i);
+ log_err("atmel_nand: Fail to initialize #%d chip", i);
}
#endif /* CONFIG_SPL_BUILD */
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 48c0ca69de..7349a9bc99 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -956,7 +956,7 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
*/
req = DIV_ROUND_UP(ecc_level * 14, 8);
if (req >= sas) {
- dev_err(&host->pdev->dev,
+ dev_err(host->pdev,
"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
req, sas);
return NULL;
@@ -1012,8 +1012,8 @@ static struct nand_ecclayout *brcmstb_choose_ecc_layout(
layout = brcmnand_create_layout(ecc_level, host);
if (!layout) {
- dev_err(&host->pdev->dev,
- "no proper ecc_layout for this NAND cfg\n");
+ dev_err(host->pdev,
+ "no proper ecc_layout for this NAND cfg\n");
return NULL;
}
@@ -1056,17 +1056,9 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
NAND_CTRL_RDY |
NAND_STATUS_READY |
(wp ? 0 : NAND_STATUS_WP), 0);
-#ifndef __UBOOT__
- if (ret)
- dev_err_ratelimited(&host->pdev->dev,
- "nand #WP expected %s\n",
- wp ? "on" : "off");
-#else
if (ret)
- dev_err(&host->pdev->dev,
- "nand #WP expected %s\n",
- wp ? "on" : "off");
-#endif /* __UBOOT__ */
+ dev_err(host->pdev, "nand #WP expected %s\n",
+ wp ? "on" : "off");
}
}
@@ -2257,7 +2249,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, ofnode dn)
ret = ofnode_read_s32(dn, "reg", &host->cs);
#endif
if (ret) {
- dev_err(&pdev->dev, "can't get chip-select\n");
+ dev_err(pdev, "can't get chip-select\n");
return -ENXIO;
}
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index a30e82166b..5fb3081c83 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -512,7 +512,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
}
if (i == ntypes) {
- dev_err(&info->pdev->dev, "Error: timings not found\n");
+ dev_err(mtd->dev, "Error: timings not found\n");
return -EINVAL;
}
@@ -603,7 +603,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
ts = get_timer(0);
while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) {
if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) {
- dev_err(&info->pdev->dev,
+ dev_err(info->controller.active->mtd.dev,
"Timeout on RDDREQ while draining the FIFO\n");
return;
}
@@ -656,8 +656,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
DIV_ROUND_UP(info->step_spare_size, 4));
break;
default:
- dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
- info->state);
+ dev_err(info->controller.active->mtd.dev,
+ "%s: invalid state %d\n", __func__, info->state);
BUG();
}
@@ -1027,7 +1027,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
default:
exec_cmd = 0;
- dev_err(&info->pdev->dev, "non-supported command %x\n",
+ dev_err(mtd->dev, "non-supported command %x\n",
command);
break;
}
@@ -1087,7 +1087,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
break;
if (get_timer(ts) > CHIP_DELAY_TIMEOUT) {
- dev_err(&info->pdev->dev, "Wait timeout!!!\n");
+ dev_err(mtd->dev, "Wait timeout!!!\n");
return;
}
}
@@ -1180,7 +1180,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
break;
if (get_timer(ts) > CHIP_DELAY_TIMEOUT) {
- dev_err(&info->pdev->dev, "Wait timeout!!!\n");
+ dev_err(mtd->dev, "Wait timeout!!!\n");
return;
}
}
@@ -1426,7 +1426,7 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
break;
if (get_timer(ts) > CHIP_DELAY_TIMEOUT) {
- dev_err(&info->pdev->dev, "Ready timeout!!!\n");
+ dev_err(mtd->dev, "Ready timeout!!!\n");
return NAND_STATUS_FAIL;
}
}
@@ -1633,7 +1633,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
ecc->strength = 16;
} else {
- dev_err(&info->pdev->dev,
+ dev_err(info->controller.active->mtd.dev,
"ECC strength %d at page size %d is not supported\n",
strength, page_size);
return -ENODEV;
@@ -1659,8 +1659,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
return ret;
ret = pxa3xx_nand_sensing(host);
if (ret) {
- dev_info(&info->pdev->dev,
- "There is no chip on cs %d!\n",
+ dev_info(mtd->dev, "There is no chip on cs %d!\n",
info->cs);
return ret;
}
@@ -1676,7 +1675,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
if (!pdata->keep_config) {
ret = pxa3xx_nand_init_timings(host);
if (ret) {
- dev_err(&info->pdev->dev,
+ dev_err(mtd->dev,
"Failed to set timings: %d\n", ret);
return ret;
}
@@ -1720,7 +1719,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
chip->cmdfunc = nand_cmdfunc_extended;
} else {
- dev_err(&info->pdev->dev,
+ dev_err(mtd->dev,
"unsupported page size on this variant\n");
return -ENODEV;
}
@@ -1873,6 +1872,7 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info)
static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
{
+ struct mtd_info *mtd = &info->controller.active->mtd;
struct pxa3xx_nand_platform_data *pdata;
int ret, cs, probe_success;
@@ -1884,7 +1884,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
ret = alloc_nand_resource(info);
if (ret) {
- dev_err(&pdev->dev, "alloc nand resource failed\n");
+ dev_err(mtd->dev, "alloc nand resource failed\n");
return ret;
}
@@ -1901,7 +1901,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
info->cs = cs;
ret = pxa3xx_nand_scan(mtd);
if (ret) {
- dev_info(&pdev->dev, "failed to scan nand at cs %d\n",
+ dev_info(mtd->dev, "failed to scan nand at cs %d\n",
cs);
continue;
}
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 004b6f17a5..12fc065b32 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1226,7 +1226,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
+static int sunxi_nand_chip_set_timings(struct sunxi_nfc *nfc,
+ struct sunxi_nand_chip *chip,
const struct nand_sdr_timings *timings)
{
u32 min_clk_period = 0;
@@ -1349,7 +1350,8 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return 0;
}
-static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip)
+static int sunxi_nand_chip_init_timings(struct sunxi_nfc *nfc,
+ struct sunxi_nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(&chip->nand);
const struct nand_sdr_timings *timings;
@@ -1384,7 +1386,7 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip)
if (IS_ERR(timings))
return PTR_ERR(timings);
- return sunxi_nand_chip_set_timings(chip, timings);
+ return sunxi_nand_chip_set_timings(nfc, chip, timings);
}
static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
@@ -1423,7 +1425,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
}
if (i >= ARRAY_SIZE(strengths)) {
- dev_err(nfc->dev, "unsupported strength\n");
+ dev_err(mtd->dev, "unsupported strength\n");
ret = -ENOTSUPP;
goto err;
}
@@ -1619,7 +1621,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
nsels /= sizeof(u32);
if (!nsels || nsels > 8) {
- dev_err(dev, "invalid reg property size\n");
+ dev_err(nfc->dev, "invalid reg property size\n");
return -EINVAL;
}
@@ -1627,7 +1629,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
(nsels * sizeof(struct sunxi_nand_chip_sel)),
GFP_KERNEL);
if (!chip) {
- dev_err(dev, "could not allocate chip\n");
+ dev_err(nfc->dev, "could not allocate chip\n");
return -ENOMEM;
}
@@ -1641,14 +1643,14 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels);
if (ret) {
- dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret);
return ret;
}
ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb,
nsels);
if (ret) {
- dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret);
return ret;
}
@@ -1656,14 +1658,13 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
int tmp = cs[i];
if (tmp > NFC_MAX_CS) {
- dev_err(dev,
- "invalid reg value: %u (max CS = 7)\n",
- tmp);
+ dev_err(nfc->dev,
+ "invalid reg value: %u (max CS = 7)\n", tmp);
return -EINVAL;
}
if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
- dev_err(dev, "CS %d already assigned\n", tmp);
+ dev_err(nfc->dev, "CS %d already assigned\n", tmp);
return -EINVAL;
}
@@ -1688,15 +1689,15 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
timings = onfi_async_timing_mode_to_sdr_timings(0);
if (IS_ERR(timings)) {
ret = PTR_ERR(timings);
- dev_err(dev,
+ dev_err(nfc->dev,
"could not retrieve timings for ONFI mode 0: %d\n",
ret);
return ret;
}
- ret = sunxi_nand_chip_set_timings(chip, timings);
+ ret = sunxi_nand_chip_set_timings(nfc, chip, timings);
if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
+ dev_err(nfc->dev, "could not configure chip timings: %d\n", ret);
return ret;
}
@@ -1729,27 +1730,27 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
nand->options |= NAND_SUBPAGE_READ;
- ret = sunxi_nand_chip_init_timings(chip);
+ ret = sunxi_nand_chip_init_timings(nfc, chip);
if (ret) {
- dev_err(dev, "could not configure chip timings: %d\n", ret);
+ dev_err(nfc->dev, "could not configure chip timings: %d\n", ret);
return ret;
}
ret = sunxi_nand_ecc_init(mtd, &nand->ecc);
if (ret) {
- dev_err(dev, "ECC init failed: %d\n", ret);
+ dev_err(nfc->dev, "ECC init failed: %d\n", ret);
return ret;
}
ret = nand_scan_tail(mtd);
if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ dev_err(nfc->dev, "nand_scan_tail failed: %d\n", ret);
return ret;
}
ret = nand_register(devnum, mtd);
if (ret) {
- dev_err(dev, "failed to register mtd device: %d\n", ret);
+ dev_err(nfc->dev, "failed to register mtd device: %d\n", ret);
return ret;
}
@@ -1769,7 +1770,7 @@ static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc)
i++;
if (i > 8) {
- dev_err(dev, "too many NAND chips: %d (max = 8)\n", i);
+ dev_err(nfc->dev, "too many NAND chips: %d (max = 8)\n", i);
return -EINVAL;
}
@@ -1841,7 +1842,7 @@ void sunxi_nand_init(void)
ret = sunxi_nand_chips_init(node, nfc);
if (ret) {
- dev_err(dev, "failed to init nand chips\n");
+ dev_err(nfc->dev, "failed to init nand chips\n");
goto err;
}
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index 52c8a94778..4e6fdc607f 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -152,6 +152,8 @@ enum vf610_nfc_alt_buf {
struct vf610_nfc {
struct nand_chip chip;
+ /* NULL without CONFIG_NAND_VF610_NFC_DT */
+ struct udevice *dev;
void __iomem *regs;
uint buf_offset;
int write_sz;
@@ -631,11 +633,10 @@ struct vf610_nfc_config {
int flash_bbt;
};
-static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
+static int vf610_nfc_nand_init(struct vf610_nfc *nfc, int devnum)
{
- struct mtd_info *mtd;
- struct nand_chip *chip;
- struct vf610_nfc *nfc;
+ struct nand_chip *chip = &nfc->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
int err = 0;
struct vf610_nfc_config cfg = {
.hardware_ecc = 1,
@@ -647,16 +648,6 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
.flash_bbt = 1,
};
- nfc = calloc(1, sizeof(*nfc));
- if (!nfc) {
- printf(KERN_ERR "%s: Memory exhausted!\n", __func__);
- return -ENOMEM;
- }
-
- chip = &nfc->chip;
- nfc->regs = addr;
-
- mtd = nand_to_mtd(chip);
nand_set_controller_data(chip, nfc);
if (cfg.width == 16)
@@ -777,20 +768,23 @@ static const struct udevice_id vf610_nfc_dt_ids[] = {
static int vf610_nfc_dt_probe(struct udevice *dev)
{
struct resource res;
+ struct vf610_nfc *nfc = dev_get_priv(dev);
int ret;
ret = dev_read_resource(dev, 0, &res);
if (ret)
return ret;
- return vf610_nfc_nand_init(0, devm_ioremap(dev, res.start,
- resource_size(&res)));
+ nfc->regs = devm_ioremap(dev, res.start, resource_size(&res));
+ nfc->dev = dev;
+ return vf610_nfc_nand_init(nfc, 0);
}
U_BOOT_DRIVER(vf610_nfc_dt) = {
.name = "vf610-nfc-dt",
.id = UCLASS_MTD,
.of_match = vf610_nfc_dt_ids,
+ .priv_auto_alloc_size = sizeof(struct vf610_nfc),
.probe = vf610_nfc_dt_probe,
};
@@ -809,7 +803,17 @@ void board_nand_init(void)
#else
void board_nand_init(void)
{
- int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE);
+ int err;
+ struct vf610_nfc *nfc;
+
+ nfc = calloc(1, sizeof(*nfc));
+ if (!nfc) {
+ printf("%s: Out of memory\n", __func__);
+ return;
+ }
+
+ nfc->regs = (void __iomem *)CONFIG_SYS_NAND_BASE;
+ err = vf610_nfc_nand_init(nfc, 0);
if (err)
printf("VF610 NAND init failed (err %d)\n", err);
}
diff --git a/drivers/mtd/nand/raw/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c
index fa59455210..92db2aa19c 100644
--- a/drivers/mtd/nand/raw/zynq_nand.c
+++ b/drivers/mtd/nand/raw/zynq_nand.c
@@ -1282,7 +1282,7 @@ static const struct udevice_id zynq_nand_dt_ids[] = {
};
U_BOOT_DRIVER(zynq_nand) = {
- .name = "zynq-nand",
+ .name = "zynq_nand",
.id = UCLASS_MTD,
.of_match = zynq_nand_dt_ids,
.probe = zynq_nand_probe,
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 93371fdde0..8c7e07d463 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -984,13 +984,13 @@ static int spinand_detect(struct spinand_device *spinand)
ret = spinand_manufacturer_detect(spinand);
if (ret) {
- dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
- spinand->id.data);
+ dev_err(spinand->slave->dev, "unknown raw ID %*phN\n",
+ SPINAND_MAX_ID_LEN, spinand->id.data);
return ret;
}
if (nand->memorg.ntargets > 1 && !spinand->select_target) {
- dev_err(dev,
+ dev_err(spinand->slave->dev,
"SPI NANDs with more than one die must implement ->select_target()\n");
return -EINVAL;
}
@@ -1076,7 +1076,7 @@ static int spinand_init(struct spinand_device *spinand)
ret = spinand_manufacturer_init(spinand);
if (ret) {
- dev_err(dev,
+ dev_err(spinand->slave->dev,
"Failed to initialize the SPI NAND chip (err = %d)\n",
ret);
goto err_free_bufs;
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 0113e70037..e16b0e1462 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <log.h>
+#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <linux/bitops.h>
diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index fa26ea33c8..07c8c7b82b 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -55,9 +55,19 @@ static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
int ret;
ret = spi_nor_read_write_reg(nor, &op, val);
- if (ret < 0)
- dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
+ if (ret < 0) {
+ /*
+ * spi_slave does not have a struct udevice member without DM,
+ * so use the bus and cs instead.
+ */
+#if CONFIG_IS_ENABLED(DM_SPI)
+ dev_dbg(nor->spi->dev, "error %d reading %x\n", ret,
code);
+#else
+ log_debug("spi%u.%u: error %d reading %x\n",
+ nor->spi->bus, nor->spi->cs, ret, code);
+#endif
+ }
return ret;
}
@@ -512,7 +522,8 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
/* Check current Quad Enable bit value. */
ret = read_cr(nor);
if (ret < 0) {
- dev_dbg(dev, "error while reading configuration register\n");
+ dev_dbg(nor->dev,
+ "error while reading configuration register\n");
return -EINVAL;
}
@@ -524,7 +535,7 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
/* Keep the current value of the Status Register. */
ret = read_sr(nor);
if (ret < 0) {
- dev_dbg(dev, "error while reading status register\n");
+ dev_dbg(nor->dev, "error while reading status register\n");
return -EINVAL;
}
sr_cr[0] = ret;
@@ -785,7 +796,7 @@ int spi_nor_scan(struct spi_nor *nor)
}
if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
- dev_dbg(dev, "address width is too large: %u\n",
+ dev_dbg(nor->dev, "address width is too large: %u\n",
nor->addr_width);
return -EINVAL;
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 039f9fb058..a0d2d21a55 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -432,6 +432,8 @@ config PCNET
This driver supports AMD PCnet series fast ethernet family of
PCI chipsets/adapters.
+source "drivers/net/qe/Kconfig"
+
config RTL8139
bool "Realtek 8139 series Ethernet controller driver"
help
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1ecdc40b8f..03f01921ea 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_VSC9953) += vsc9953.o
obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
obj-$(CONFIG_FSL_PFE) += pfe_eth/
+obj-y += qe/
obj-$(CONFIG_SNI_AVE) += sni_ave.o
obj-y += ti/
obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
diff --git a/drivers/net/bcm6368-eth.c b/drivers/net/bcm6368-eth.c
index 648fafd3e0..38a2a30fe6 100644
--- a/drivers/net/bcm6368-eth.c
+++ b/drivers/net/bcm6368-eth.c
@@ -249,8 +249,7 @@ static int bcm6368_eth_adjust_link(struct udevice *dev)
/* link changed */
if (!up) {
- dev_info(&priv->pdev->dev, "link DOWN on %s\n",
- port->name);
+ dev_info(dev, "link DOWN on %s\n", port->name);
writeb_be(ETH_PORTOV_ENABLE_MASK,
priv->base + ETH_PORTOV_REG(i));
writeb_be(ETH_PTCTRL_RXDIS_MASK |
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 810a2b95b1..db1102562f 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -26,6 +26,7 @@
* supports a single RGMII PHY. This configuration also has SW control over
* all clock and reset signals to the HW block.
*/
+
#include <common.h>
#include <clk.h>
#include <cpu_func.h>
@@ -1893,8 +1894,7 @@ static phy_interface_t eqos_get_interface_stm32(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev);
- phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
- NULL);
+ phy_mode = dev_read_prop(dev, "phy-mode", NULL);
if (phy_mode)
interface = phy_get_interface_by_name(phy_mode);
@@ -1931,8 +1931,7 @@ static phy_interface_t eqos_get_interface_imx(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev);
- phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
- NULL);
+ phy_mode = dev_read_prop(dev, "phy-mode", NULL);
if (phy_mode)
interface = phy_get_interface_by_name(phy_mode);
diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c
index d2edd1751c..77f1a96a2e 100644
--- a/drivers/net/fsl_mdio.c
+++ b/drivers/net/fsl_mdio.c
@@ -11,6 +11,7 @@
#include <fsl_mdio.h>
#include <asm/io.h>
#include <linux/errno.h>
+#include <tsec.h>
#ifdef CONFIG_DM_MDIO
struct tsec_mdio_priv {
@@ -190,17 +191,30 @@ static const struct mdio_ops tsec_mdio_ops = {
.reset = tsec_mdio_reset,
};
+static struct fsl_pq_mdio_data etsec2_data = {
+ .mdio_regs_off = TSEC_MDIO_REGS_OFFSET,
+};
+
+static struct fsl_pq_mdio_data gianfar_data = {
+ .mdio_regs_off = 0x0,
+};
+
+static struct fsl_pq_mdio_data fman_data = {
+ .mdio_regs_off = 0x0,
+};
+
static const struct udevice_id tsec_mdio_ids[] = {
- { .compatible = "fsl,gianfar-tbi" },
- { .compatible = "fsl,gianfar-mdio" },
- { .compatible = "fsl,etsec2-tbi" },
- { .compatible = "fsl,etsec2-mdio" },
- { .compatible = "fsl,fman-mdio" },
+ { .compatible = "fsl,gianfar-tbi", .data = (ulong)&gianfar_data },
+ { .compatible = "fsl,gianfar-mdio", .data = (ulong)&gianfar_data },
+ { .compatible = "fsl,etsec2-tbi", .data = (ulong)&etsec2_data },
+ { .compatible = "fsl,etsec2-mdio", .data = (ulong)&etsec2_data },
+ { .compatible = "fsl,fman-mdio", .data = (ulong)&fman_data },
{}
};
static int tsec_mdio_probe(struct udevice *dev)
{
+ struct fsl_pq_mdio_data *data;
struct tsec_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL;
struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
NULL;
@@ -213,7 +227,9 @@ static int tsec_mdio_probe(struct udevice *dev)
printf("dev_get_priv(dev %p) = NULL\n", dev);
return -1;
}
- priv->regs = (void *)(uintptr_t)dev_read_addr(dev);
+
+ data = (struct fsl_pq_mdio_data *)dev_get_driver_data(dev);
+ priv->regs = dev_remap_addr(dev) + data->mdio_regs_off;
debug("%s priv %p @ regs %p, pdata %p\n", __func__,
priv, priv->regs, pdata);
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 5676a5b3ba..00bda24f1f 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -551,6 +551,10 @@ static int ftgmac100_probe(struct udevice *dev)
priv->max_speed = pdata->max_speed;
priv->phy_addr = 0;
+#ifdef CONFIG_PHY_ADDR
+ priv->phy_addr = CONFIG_PHY_ADDR;
+#endif
+
ret = clk_enable_bulk(&priv->clks);
if (ret)
goto out;
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index 4c7d06ca40..83f99e5d8a 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -625,9 +625,9 @@ static void mvneta_port_down(struct mvneta_port *pp)
count = 0;
do {
if (count++ >= MVNETA_RX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(pp->dev,
- "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n",
- val);
+ dev_warn(pp->phydev->dev,
+ "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n",
+ val);
break;
}
mdelay(1);
@@ -648,9 +648,9 @@ static void mvneta_port_down(struct mvneta_port *pp)
count = 0;
do {
if (count++ >= MVNETA_TX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(pp->dev,
- "TIMEOUT for TX stopped status=0x%08x\n",
- val);
+ dev_warn(pp->phydev->dev,
+ "TIMEOUT for TX stopped status=0x%08x\n",
+ val);
break;
}
mdelay(1);
@@ -664,9 +664,9 @@ static void mvneta_port_down(struct mvneta_port *pp)
count = 0;
do {
if (count++ >= MVNETA_TX_FIFO_EMPTY_TIMEOUT) {
- netdev_warn(pp->dev,
- "TX FIFO empty timeout status=0x08%x\n",
- val);
+ dev_warn(pp->phydev->dev,
+ "TX FIFO empty timeout status=0x08%x\n",
+ val);
break;
}
mdelay(1);
@@ -949,28 +949,32 @@ static void mvneta_rx_error(struct mvneta_port *pp,
u32 status = rx_desc->status;
if (!mvneta_rxq_desc_is_first_last(status)) {
- netdev_err(pp->dev,
- "bad rx status %08x (buffer oversize), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (buffer oversize), size=%d\n",
+ status, rx_desc->data_size);
return;
}
switch (status & MVNETA_RXD_ERR_CODE_MASK) {
case MVNETA_RXD_ERR_CRC:
- netdev_err(pp->dev, "bad rx status %08x (crc error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (crc error), size=%d\n", status,
+ rx_desc->data_size);
break;
case MVNETA_RXD_ERR_OVERRUN:
- netdev_err(pp->dev, "bad rx status %08x (overrun error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (overrun error), size=%d\n", status,
+ rx_desc->data_size);
break;
case MVNETA_RXD_ERR_LEN:
- netdev_err(pp->dev, "bad rx status %08x (max frame length error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (max frame length error), size=%d\n",
+ status, rx_desc->data_size);
break;
case MVNETA_RXD_ERR_RESOURCE:
- netdev_err(pp->dev, "bad rx status %08x (resource error), size=%d\n",
- status, rx_desc->data_size);
+ dev_err(pp->phydev->dev,
+ "bad rx status %08x (resource error), size=%d\n",
+ status, rx_desc->data_size);
break;
}
}
@@ -1127,8 +1131,8 @@ static int mvneta_setup_rxqs(struct mvneta_port *pp)
for (queue = 0; queue < rxq_number; queue++) {
int err = mvneta_rxq_init(pp, &pp->rxqs[queue]);
if (err) {
- netdev_err(pp->dev, "%s: can't create rxq=%d\n",
- __func__, queue);
+ dev_err(pp->phydev->dev, "%s: can't create rxq=%d\n",
+ __func__, queue);
mvneta_cleanup_rxqs(pp);
return err;
}
@@ -1145,8 +1149,8 @@ static int mvneta_setup_txqs(struct mvneta_port *pp)
for (queue = 0; queue < txq_number; queue++) {
int err = mvneta_txq_init(pp, &pp->txqs[queue]);
if (err) {
- netdev_err(pp->dev, "%s: can't create txq=%d\n",
- __func__, queue);
+ dev_err(pp->phydev->dev, "%s: can't create txq=%d\n",
+ __func__, queue);
mvneta_cleanup_txqs(pp);
return err;
}
@@ -1402,7 +1406,7 @@ static int mvneta_init(struct udevice *dev)
err = mvneta_init2(pp);
if (err < 0) {
- dev_err(&pdev->dev, "can't init eth hal\n");
+ dev_err(dev, "can't init eth hal\n");
return err;
}
@@ -1410,7 +1414,7 @@ static int mvneta_init(struct udevice *dev)
err = mvneta_port_power_up(pp, pp->phy_interface);
if (err < 0) {
- dev_err(&pdev->dev, "can't power up port\n");
+ dev_err(dev, "can't power up port\n");
return err;
}
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index a5747a25ab..8f790a8b44 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -2568,7 +2568,7 @@ static int mvpp2_bm_pool_create(struct udevice *dev,
if (!IS_ALIGNED((unsigned long)bm_pool->virt_addr,
MVPP2_BM_POOL_PTR_ALIGN)) {
- dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n",
+ dev_err(dev, "BM pool %d is not %d bytes aligned\n",
bm_pool->id, MVPP2_BM_POOL_PTR_ALIGN);
return -ENOMEM;
}
@@ -2659,7 +2659,7 @@ static int mvpp2_bm_pools_init(struct udevice *dev,
return 0;
err_unroll_pools:
- dev_err(&pdev->dev, "failed to create BM pool %d, size %d\n", i, size);
+ dev_err(dev, "failed to create BM pool %d, size %d\n", i, size);
for (i = i - 1; i >= 0; i--)
mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]);
return err;
@@ -2773,9 +2773,9 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port,
if (buf_num < 0 ||
(buf_num + bm_pool->buf_num > bm_pool->size)) {
- netdev_err(port->dev,
- "cannot allocate %d buffers for pool %d\n",
- buf_num, bm_pool->id);
+ dev_err(port->phy_dev->dev,
+ "cannot allocate %d buffers for pool %d\n", buf_num,
+ bm_pool->id);
return 0;
}
@@ -2803,7 +2803,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
int num;
if (new_pool->type != MVPP2_BM_FREE && new_pool->type != type) {
- netdev_err(port->dev, "mixing pool types is forbidden\n");
+ dev_err(port->phy_dev->dev, "mixing pool types is forbidden\n");
return NULL;
}
@@ -2834,8 +2834,9 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
/* Allocate buffers for this pool */
num = mvpp2_bm_bufs_add(port, new_pool, pkts_num);
if (num != pkts_num) {
- dev_err(dev, "pool %d: %d of %d allocated\n",
- new_pool->id, num, pkts_num);
+ dev_err(port->phy_dev->dev,
+ "pool %d: %d of %d allocated\n", new_pool->id,
+ num, pkts_num);
return NULL;
}
}
@@ -3344,8 +3345,7 @@ static int gop_port_init(struct mvpp2_port *port)
int num_of_act_lanes;
if (mac_num >= MVPP22_GOP_MAC_NUM) {
- netdev_err(NULL, "%s: illegal port number %d", __func__,
- mac_num);
+ log_err("illegal port number %d", mac_num);
return -1;
}
@@ -3399,8 +3399,8 @@ static int gop_port_init(struct mvpp2_port *port)
break;
default:
- netdev_err(NULL, "%s: Requested port mode (%d) not supported\n",
- __func__, port->phy_interface);
+ log_err("Requested port mode (%d) not supported\n",
+ port->phy_interface);
return -1;
}
@@ -3440,8 +3440,8 @@ static void gop_port_enable(struct mvpp2_port *port, int enable)
break;
default:
- netdev_err(NULL, "%s: Wrong port mode (%d)\n", __func__,
- port->phy_interface);
+ log_err("%s: Wrong port mode (%d)\n", __func__,
+ port->phy_interface);
return;
}
}
@@ -3811,9 +3811,9 @@ static void mvpp2_egress_disable(struct mvpp2_port *port)
delay = 0;
do {
if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(port->dev,
- "Tx stop timed out, status=0x%08x\n",
- reg_data);
+ dev_warn(port->phy_dev->dev,
+ "Tx stop timed out, status=0x%08x\n",
+ reg_data);
break;
}
mdelay(1);
@@ -4261,9 +4261,9 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq)
delay = 0;
do {
if (delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) {
- netdev_warn(port->dev,
- "port %d: cleaning queue %d timed out\n",
- port->id, txq->log_id);
+ dev_warn(port->phy_dev->dev,
+ "port %d: cleaning queue %d timed out\n",
+ port->id, txq->log_id);
break;
}
mdelay(1);
@@ -4430,16 +4430,19 @@ static void mvpp2_rx_error(struct mvpp2_port *port,
switch (status & MVPP2_RXD_ERR_CODE_MASK) {
case MVPP2_RXD_ERR_CRC:
- netdev_err(port->dev, "bad rx status %08x (crc error), size=%zu\n",
- status, sz);
+ dev_err(port->phy_dev->dev,
+ "bad rx status %08x (crc error), size=%zu\n", status,
+ sz);
break;
case MVPP2_RXD_ERR_OVERRUN:
- netdev_err(port->dev, "bad rx status %08x (overrun error), size=%zu\n",
- status, sz);
+ dev_err(port->phy_dev->dev,
+ "bad rx status %08x (overrun error), size=%zu\n",
+ status, sz);
break;
case MVPP2_RXD_ERR_RESOURCE:
- netdev_err(port->dev, "bad rx status %08x (resource error), size=%zu\n",
- status, sz);
+ dev_err(port->phy_dev->dev,
+ "bad rx status %08x (resource error), size=%zu\n",
+ status, sz);
break;
}
}
@@ -4507,8 +4510,8 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
*/
if (phy_dev &&
phy_dev->drv->uid == 0xffffffff) {/* Generic phy */
- netdev_warn(port->dev,
- "Marking phy as invalid, link will not be checked\n");
+ dev_warn(port->phy_dev->dev,
+ "Marking phy as invalid, link will not be checked\n");
/* set phy_addr to invalid value */
port->phyaddr = PHY_MAX_ADDR;
mvpp2_egress_enable(port);
@@ -4519,7 +4522,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
port->phy_dev = phy_dev;
if (!phy_dev) {
- netdev_err(port->dev, "cannot connect to phy\n");
+ dev_err(port->phy_dev->dev, "cannot connect to phy\n");
return;
}
phy_dev->supported &= PHY_GBIT_FEATURES;
@@ -4550,31 +4553,31 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port)
err = mvpp2_prs_mac_da_accept(port->priv, port->id, mac_bcast, true);
if (err) {
- netdev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n");
+ dev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n");
return err;
}
err = mvpp2_prs_mac_da_accept(port->priv, port->id,
port->dev_addr, true);
if (err) {
- netdev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n");
+ dev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n");
return err;
}
err = mvpp2_prs_def_flow(port);
if (err) {
- netdev_err(dev, "mvpp2_prs_def_flow failed\n");
+ dev_err(dev, "mvpp2_prs_def_flow failed\n");
return err;
}
/* Allocate the Rx/Tx queues */
err = mvpp2_setup_rxqs(port);
if (err) {
- netdev_err(port->dev, "cannot allocate Rx queues\n");
+ dev_err(port->phy_dev->dev, "cannot allocate Rx queues\n");
return err;
}
err = mvpp2_setup_txqs(port);
if (err) {
- netdev_err(port->dev, "cannot allocate Tx queues\n");
+ dev_err(port->phy_dev->dev, "cannot allocate Tx queues\n");
return err;
}
@@ -4725,7 +4728,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
int parent;
phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0);
if (phyaddr < 0) {
- dev_err(&pdev->dev, "could not find phy address\n");
+ dev_err(dev, "could not find phy address\n");
return -1;
}
parent = fdt_parent_offset(gd->fdt_blob, phy_node);
@@ -4742,13 +4745,13 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
if (phy_mode_str)
phy_mode = phy_get_interface_by_name(phy_mode_str);
if (phy_mode == -1) {
- dev_err(&pdev->dev, "incorrect phy mode\n");
+ dev_err(dev, "incorrect phy mode\n");
return -EINVAL;
}
id = fdtdec_get_int(gd->fdt_blob, port_node, "port-id", -1);
if (id == -1) {
- dev_err(&pdev->dev, "missing port-id value\n");
+ dev_err(dev, "missing port-id value\n");
return -EINVAL;
}
@@ -4807,7 +4810,7 @@ static int mvpp2_port_probe(struct udevice *dev,
err = mvpp2_port_init(dev, port);
if (err < 0) {
- dev_err(&pdev->dev, "failed to init port %d\n", port->id);
+ dev_err(dev, "failed to init port %d\n", port->id);
return err;
}
mvpp2_port_power_up(port);
@@ -4978,7 +4981,7 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv)
/* Checks for hardware constraints (U-Boot uses only one rxq) */
if ((rxq_number > priv->max_port_rxqs) ||
(txq_number > MVPP2_MAX_TXQ)) {
- dev_err(&pdev->dev, "invalid queue size parameter\n");
+ dev_err(dev, "invalid queue size parameter\n");
return -EINVAL;
}
@@ -5099,7 +5102,7 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp)
err = mvpp2_rx_refill(port, bm_pool, bm, dma_addr);
if (err) {
- netdev_err(port->dev, "failed to refill BM pools\n");
+ dev_err(port->phy_dev->dev, "failed to refill BM pools\n");
return 0;
}
@@ -5345,7 +5348,7 @@ static int mvpp2_probe(struct udevice *dev)
port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"gop-port-id", -1);
if (port->id == -1) {
- dev_err(&pdev->dev, "missing gop-port-id value\n");
+ dev_err(dev, "missing gop-port-id value\n");
return -EINVAL;
}
@@ -5364,7 +5367,7 @@ static int mvpp2_probe(struct udevice *dev)
/* Initialize network controller */
err = mvpp2_init(dev, priv);
if (err < 0) {
- dev_err(&pdev->dev, "failed to initialize controller\n");
+ dev_err(dev, "failed to initialize controller\n");
return err;
}
priv->num_ports = 0;
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 709979f48c..d1a643cf5a 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -157,6 +157,14 @@
#define INT_MEM_DATA_M GENMASK(7, 0)
#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
+/* Extended page GPIO register 13G */
+#define MSCC_CLKOUT_CNTL 13
+#define CLKOUT_ENABLE BIT(15)
+#define CLKOUT_FREQ_MASK GENMASK(14, 13)
+#define CLKOUT_FREQ_25M (0x0 << 13)
+#define CLKOUT_FREQ_50M (0x1 << 13)
+#define CLKOUT_FREQ_125M (0x2 << 13)
+
/* Extended page GPIO register 18G */
#define MSCC_PHY_PROC_CMD 18
#define PROC_CMD_NCOMPLETED BIT(15)
@@ -1168,6 +1176,9 @@ static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
rx_clk_out = RX_CLK_OUT_NORMAL;
break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
/* Set Reg23.12:11=2 */
mac_if = MAC_IF_SELECTION_RGMII;
@@ -1210,13 +1221,84 @@ static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
return 0;
}
+static int vsc8531_vsc8541_clkout_config(struct phy_device *phydev)
+{
+ struct ofnode_phandle_args phandle_args;
+ u32 clkout_rate = 0;
+ u16 reg_val;
+ int retval;
+
+ retval = dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL,
+ 0, 0, &phandle_args);
+ if (!retval)
+ clkout_rate = ofnode_read_u32_default(phandle_args.node,
+ "vsc8531,clk-out-frequency", 0);
+
+ switch (clkout_rate) {
+ case 0:
+ reg_val = 0;
+ break;
+ case 25000000:
+ reg_val = CLKOUT_FREQ_25M | CLKOUT_ENABLE;
+ break;
+ case 50000000:
+ reg_val = CLKOUT_FREQ_50M | CLKOUT_ENABLE;
+ break;
+ case 125000000:
+ reg_val = CLKOUT_FREQ_125M | CLKOUT_ENABLE;
+ break;
+ default:
+ printf("PHY 8530/31 invalid clkout rate %u\n",
+ clkout_rate);
+ return -EINVAL;
+ }
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_GPIO);
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_CLKOUT_CNTL, reg_val);
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_STD);
+
+ return 0;
+}
+
+static int vsc8531_vsc8541_clk_skew_config(struct phy_device *phydev)
+{
+ enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS;
+ enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS;
+ u16 reg_val;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ rx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ tx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXT2);
+ reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
+
+ /* Reg20E2 - Update RGMII RX_Clk Skews. */
+ reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
+ RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
+ /* Reg20E2 - Update RGMII TX_Clk Skews. */
+ reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
+ RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
+ phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_STD);
+
+ return 0;
+}
+
static int vsc8531_config(struct phy_device *phydev)
{
int retval = -EINVAL;
u16 reg_val;
u16 rmii_clk_out;
- enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
- enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
/* For VSC8530/31 and VSC8540/41 the init scripts are the same */
@@ -1226,6 +1308,9 @@ static int vsc8531_config(struct phy_device *phydev)
switch (phydev->interface) {
case PHY_INTERFACE_MODE_RMII:
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
retval = vsc8531_vsc8541_mac_config(phydev);
if (retval != 0)
return retval;
@@ -1242,19 +1327,12 @@ static int vsc8531_config(struct phy_device *phydev)
/* Default RMII Clk Output to 0=OFF/1=ON */
rmii_clk_out = 0;
+ retval = vsc8531_vsc8541_clk_skew_config(phydev);
+ if (retval != 0)
+ return retval;
+
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_EXT2);
- reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
-
- /* Reg20E2 - Update RGMII RX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
- RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
- /* Reg20E2 - Update RGMII TX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
- RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
-
- phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
-
reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
/* Reg27E2 - Update Clk Slew Rate. */
reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
@@ -1267,6 +1345,11 @@ static int vsc8531_config(struct phy_device *phydev)
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_STD);
+ /* Configure the clk output */
+ retval = vsc8531_vsc8541_clkout_config(phydev);
+ if (retval != 0)
+ return retval;
+
return genphy_config_aneg(phydev);
}
@@ -1275,8 +1358,6 @@ static int vsc8541_config(struct phy_device *phydev)
int retval = -EINVAL;
u16 reg_val;
u16 rmii_clk_out;
- enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
- enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
/* For VSC8530/31 and VSC8540/41 the init scripts are the same */
@@ -1304,17 +1385,12 @@ static int vsc8541_config(struct phy_device *phydev)
/* Default RMII Clk Output to 0=OFF/1=ON */
rmii_clk_out = 0;
+ retval = vsc8531_vsc8541_clk_skew_config(phydev);
+ if (retval != 0)
+ return retval;
+
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_EXT2);
- reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
- /* Reg20E2 - Update RGMII RX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
- RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
- /* Reg20E2 - Update RGMII TX_Clk Skews. */
- reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
- RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
- phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
-
reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
/* Reg27E2 - Update Clk Slew Rate. */
reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
@@ -1327,6 +1403,11 @@ static int vsc8541_config(struct phy_device *phydev)
phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
MSCC_PHY_PAGE_STD);
+ /* Configure the clk output */
+ retval = vsc8531_vsc8541_clkout_config(phydev);
+ if (retval != 0)
+ return retval;
+
return genphy_config_aneg(phydev);
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 67789897c2..9587e6b9fa 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -664,7 +664,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
dev = malloc(sizeof(*dev));
if (!dev) {
printf("Failed to allocate PHY device for %s:%d\n",
- bus->name, addr);
+ bus ? bus->name : "(null bus)", addr);
return NULL;
}
@@ -692,7 +692,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
return NULL;
}
- if (addr >= 0 && addr < PHY_MAX_ADDR)
+ if (addr >= 0 && addr < PHY_MAX_ADDR && phy_id != PHY_FIXED_ID)
bus->phymap[addr] = dev;
return dev;
diff --git a/drivers/net/qe/Kconfig b/drivers/net/qe/Kconfig
new file mode 100644
index 0000000000..dec88dea2a
--- /dev/null
+++ b/drivers/net/qe/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020 Heiko Schocher <hs@denx.de>
+
+config QE_UEC
+ bool "NXP QE UEC Ethernet controller"
+ depends on DM_ETH
+ help
+ This driver supports the NXP QE UEC ethernet controller
diff --git a/drivers/net/qe/Makefile b/drivers/net/qe/Makefile
new file mode 100644
index 0000000000..7d84757c17
--- /dev/null
+++ b/drivers/net/qe/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020 Heiko Schocher <hs@denx.de>
+
+obj-$(CONFIG_QE_UEC) += dm_qe_uec.o dm_qe_uec_phy.o uccf.o
diff --git a/drivers/net/qe/dm_qe_uec.c b/drivers/net/qe/dm_qe_uec.c
new file mode 100644
index 0000000000..3482b3ff17
--- /dev/null
+++ b/drivers/net/qe/dm_qe_uec.c
@@ -0,0 +1,1167 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * QE UEC ethernet controller driver
+ *
+ * based on drivers/qe/uec.c from NXP
+ *
+ * Copyright (C) 2020 Heiko Schocher <hs@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <memalign.h>
+#include <miiphy.h>
+#include <asm/io.h>
+
+#include "dm_qe_uec.h"
+
+#define QE_UEC_DRIVER_NAME "ucc_geth"
+
+/* Default UTBIPAR SMI address */
+#ifndef CONFIG_UTBIPAR_INIT_TBIPA
+#define CONFIG_UTBIPAR_INIT_TBIPA 0x1F
+#endif
+
+static int uec_mac_enable(struct uec_priv *uec, comm_dir_e mode)
+{
+ uec_t *uec_regs;
+ u32 maccfg1;
+
+ uec_regs = uec->uec_regs;
+ maccfg1 = in_be32(&uec_regs->maccfg1);
+
+ if (mode & COMM_DIR_TX) {
+ maccfg1 |= MACCFG1_ENABLE_TX;
+ out_be32(&uec_regs->maccfg1, maccfg1);
+ uec->mac_tx_enabled = 1;
+ }
+
+ if (mode & COMM_DIR_RX) {
+ maccfg1 |= MACCFG1_ENABLE_RX;
+ out_be32(&uec_regs->maccfg1, maccfg1);
+ uec->mac_rx_enabled = 1;
+ }
+
+ return 0;
+}
+
+static int uec_mac_disable(struct uec_priv *uec, comm_dir_e mode)
+{
+ uec_t *uec_regs;
+ u32 maccfg1;
+
+ uec_regs = uec->uec_regs;
+ maccfg1 = in_be32(&uec_regs->maccfg1);
+
+ if (mode & COMM_DIR_TX) {
+ maccfg1 &= ~MACCFG1_ENABLE_TX;
+ out_be32(&uec_regs->maccfg1, maccfg1);
+ uec->mac_tx_enabled = 0;
+ }
+
+ if (mode & COMM_DIR_RX) {
+ maccfg1 &= ~MACCFG1_ENABLE_RX;
+ out_be32(&uec_regs->maccfg1, maccfg1);
+ uec->mac_rx_enabled = 0;
+ }
+
+ return 0;
+}
+
+static int uec_restart_tx(struct uec_priv *uec)
+{
+ struct uec_inf *ui = uec->uec_info;
+ u32 cecr_subblock;
+
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(ui->uf_info.ucc_num);
+ qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+
+ uec->grace_stopped_tx = 0;
+
+ return 0;
+}
+
+static int uec_restart_rx(struct uec_priv *uec)
+{
+ struct uec_inf *ui = uec->uec_info;
+ u32 cecr_subblock;
+
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(ui->uf_info.ucc_num);
+ qe_issue_cmd(QE_RESTART_RX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+
+ uec->grace_stopped_rx = 0;
+
+ return 0;
+}
+
+static int uec_open(struct uec_priv *uec, comm_dir_e mode)
+{
+ struct ucc_fast_priv *uccf;
+
+ uccf = uec->uccf;
+
+ /* check if the UCC number is in range. */
+ if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) {
+ printf("%s: ucc_num out of range.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Enable MAC */
+ uec_mac_enable(uec, mode);
+
+ /* Enable UCC fast */
+ ucc_fast_enable(uccf, mode);
+
+ /* RISC microcode start */
+ if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx)
+ uec_restart_tx(uec);
+
+ if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx)
+ uec_restart_rx(uec);
+
+ return 0;
+}
+
+static int uec_set_mac_if_mode(struct uec_priv *uec)
+{
+ struct uec_inf *uec_info = uec->uec_info;
+ phy_interface_t enet_if_mode;
+ uec_t *uec_regs;
+ u32 upsmr;
+ u32 maccfg2;
+
+ uec_regs = uec->uec_regs;
+ enet_if_mode = uec_info->enet_interface_type;
+
+ maccfg2 = in_be32(&uec_regs->maccfg2);
+ maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
+
+ upsmr = in_be32(&uec->uccf->uf_regs->upsmr);
+ upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM);
+
+ switch (uec_info->speed) {
+ case SPEED_10:
+ maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
+ switch (enet_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ upsmr |= (UPSMR_RPM | UPSMR_R10M);
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ upsmr |= (UPSMR_R10M | UPSMR_RMM);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SPEED_100:
+ maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
+ switch (enet_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ upsmr |= UPSMR_RPM;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ upsmr |= UPSMR_RMM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SPEED_1000:
+ maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
+ switch (enet_if_mode) {
+ case PHY_INTERFACE_MODE_GMII:
+ break;
+ case PHY_INTERFACE_MODE_TBI:
+ upsmr |= UPSMR_TBIM;
+ break;
+ case PHY_INTERFACE_MODE_RTBI:
+ upsmr |= (UPSMR_RPM | UPSMR_TBIM);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII:
+ upsmr |= UPSMR_RPM;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ upsmr |= UPSMR_SGMM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ out_be32(&uec_regs->maccfg2, maccfg2);
+ out_be32(&uec->uccf->uf_regs->upsmr, upsmr);
+
+ return 0;
+}
+
+static int qe_uec_start(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct uec_priv *uec = priv->uec;
+ struct phy_device *phydev = priv->phydev;
+ struct uec_inf *uec_info = uec->uec_info;
+ int err;
+
+ if (!phydev)
+ return -ENODEV;
+
+ /* Setup MAC interface mode */
+ genphy_update_link(phydev);
+ genphy_parse_link(phydev);
+ uec_info->speed = phydev->speed;
+ uec_set_mac_if_mode(uec);
+
+ err = uec_open(uec, COMM_DIR_RX_AND_TX);
+ if (err) {
+ printf("%s: cannot enable UEC device\n", dev->name);
+ return -EINVAL;
+ }
+
+ return (phydev->link ? 0 : -EINVAL);
+}
+
+static int qe_uec_send(struct udevice *dev, void *packet, int length)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct uec_priv *uec = priv->uec;
+ struct ucc_fast_priv *uccf = uec->uccf;
+ struct buffer_descriptor *bd;
+ u16 status;
+ int i;
+ int result = 0;
+
+ uccf = uec->uccf;
+ bd = uec->tx_bd;
+
+ /* Find an empty TxBD */
+ for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) {
+ if (i > 0x100000) {
+ printf("%s: tx buffer not ready\n", dev->name);
+ return result;
+ }
+ }
+
+ /* Init TxBD */
+ BD_DATA_SET(bd, packet);
+ BD_LENGTH_SET(bd, length);
+ status = BD_STATUS(bd);
+ status &= BD_WRAP;
+ status |= (TX_BD_READY | TX_BD_LAST);
+ BD_STATUS_SET(bd, status);
+
+ /* Tell UCC to transmit the buffer */
+ ucc_fast_transmit_on_demand(uccf);
+
+ /* Wait for buffer to be transmitted */
+ for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) {
+ if (i > 0x100000) {
+ printf("%s: tx error\n", dev->name);
+ return result;
+ }
+ }
+
+ /* Ok, the buffer be transimitted */
+ BD_ADVANCE(bd, status, uec->p_tx_bd_ring);
+ uec->tx_bd = bd;
+ result = 1;
+
+ return result;
+}
+
+/*
+ * Receive frame:
+ * - wait for the next BD to get ready bit set
+ * - clean up the descriptor
+ * - move on and indicate to HW that the cleaned BD is available for Rx
+ */
+static int qe_uec_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct uec_priv *uec = priv->uec;
+ struct buffer_descriptor *bd;
+ u16 status;
+ u16 len = 0;
+ u8 *data;
+
+ *packetp = memalign(ARCH_DMA_MINALIGN, MAX_RXBUF_LEN);
+ if (*packetp == 0) {
+ printf("%s: error allocating packetp\n", __func__);
+ return -ENOMEM;
+ }
+
+ bd = uec->rx_bd;
+ status = BD_STATUS(bd);
+
+ while (!(status & RX_BD_EMPTY)) {
+ if (!(status & RX_BD_ERROR)) {
+ data = BD_DATA(bd);
+ len = BD_LENGTH(bd);
+ memcpy(*packetp, (char *)data, len);
+ } else {
+ printf("%s: Rx error\n", dev->name);
+ }
+ status &= BD_CLEAN;
+ BD_LENGTH_SET(bd, 0);
+ BD_STATUS_SET(bd, status | RX_BD_EMPTY);
+ BD_ADVANCE(bd, status, uec->p_rx_bd_ring);
+ status = BD_STATUS(bd);
+ }
+ uec->rx_bd = bd;
+
+ return len;
+}
+
+static int uec_graceful_stop_tx(struct uec_priv *uec)
+{
+ ucc_fast_t *uf_regs;
+ u32 cecr_subblock;
+ u32 ucce;
+
+ uf_regs = uec->uccf->uf_regs;
+
+ /* Clear the grace stop event */
+ out_be32(&uf_regs->ucce, UCCE_GRA);
+
+ /* Issue host command */
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+
+ /* Wait for command to complete */
+ do {
+ ucce = in_be32(&uf_regs->ucce);
+ } while (!(ucce & UCCE_GRA));
+
+ uec->grace_stopped_tx = 1;
+
+ return 0;
+}
+
+static int uec_graceful_stop_rx(struct uec_priv *uec)
+{
+ u32 cecr_subblock;
+ u8 ack;
+
+ if (!uec->p_rx_glbl_pram) {
+ printf("%s: No init rx global parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Clear acknowledge bit */
+ ack = uec->p_rx_glbl_pram->rxgstpack;
+ ack &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX;
+ uec->p_rx_glbl_pram->rxgstpack = ack;
+
+ /* Keep issuing cmd and checking ack bit until it is asserted */
+ do {
+ /* Issue host command */
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+ ack = uec->p_rx_glbl_pram->rxgstpack;
+ } while (!(ack & GRACEFUL_STOP_ACKNOWLEDGE_RX));
+
+ uec->grace_stopped_rx = 1;
+
+ return 0;
+}
+
+static int uec_stop(struct uec_priv *uec, comm_dir_e mode)
+{
+ /* check if the UCC number is in range. */
+ if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) {
+ printf("%s: ucc_num out of range.\n", __func__);
+ return -EINVAL;
+ }
+ /* Stop any transmissions */
+ if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx)
+ uec_graceful_stop_tx(uec);
+
+ /* Stop any receptions */
+ if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx)
+ uec_graceful_stop_rx(uec);
+
+ /* Disable the UCC fast */
+ ucc_fast_disable(uec->uccf, mode);
+
+ /* Disable the MAC */
+ uec_mac_disable(uec, mode);
+
+ return 0;
+}
+
+static void qe_uec_stop(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct uec_priv *uec = priv->uec;
+
+ uec_stop(uec, COMM_DIR_RX_AND_TX);
+}
+
+static int qe_uec_set_hwaddr(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct uec_priv *uec = priv->uec;
+ uec_t *uec_regs = uec->uec_regs;
+ uchar *mac = pdata->enetaddr;
+ u32 mac_addr1;
+ u32 mac_addr2;
+
+ /*
+ * if a station address of 0x12345678ABCD, perform a write to
+ * MACSTNADDR1 of 0xCDAB7856,
+ * MACSTNADDR2 of 0x34120000
+ */
+
+ mac_addr1 = (mac[5] << 24) | (mac[4] << 16) |
+ (mac[3] << 8) | (mac[2]);
+ out_be32(&uec_regs->macstnaddr1, mac_addr1);
+
+ mac_addr2 = ((mac[1] << 24) | (mac[0] << 16)) & 0xffff0000;
+ out_be32(&uec_regs->macstnaddr2, mac_addr2);
+
+ return 0;
+}
+
+static int qe_uec_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ if (packet)
+ free(packet);
+
+ return 0;
+}
+
+static const struct eth_ops qe_uec_eth_ops = {
+ .start = qe_uec_start,
+ .send = qe_uec_send,
+ .recv = qe_uec_recv,
+ .free_pkt = qe_uec_free_pkt,
+ .stop = qe_uec_stop,
+ .write_hwaddr = qe_uec_set_hwaddr,
+};
+
+static int uec_convert_threads_num(enum uec_num_of_threads threads_num,
+ int *threads_num_ret)
+{
+ int num_threads_numerica;
+
+ switch (threads_num) {
+ case UEC_NUM_OF_THREADS_1:
+ num_threads_numerica = 1;
+ break;
+ case UEC_NUM_OF_THREADS_2:
+ num_threads_numerica = 2;
+ break;
+ case UEC_NUM_OF_THREADS_4:
+ num_threads_numerica = 4;
+ break;
+ case UEC_NUM_OF_THREADS_6:
+ num_threads_numerica = 6;
+ break;
+ case UEC_NUM_OF_THREADS_8:
+ num_threads_numerica = 8;
+ break;
+ default:
+ printf("%s: Bad number of threads value.",
+ __func__);
+ return -EINVAL;
+ }
+
+ *threads_num_ret = num_threads_numerica;
+
+ return 0;
+}
+
+static void uec_init_tx_parameter(struct uec_priv *uec, int num_threads_tx)
+{
+ struct uec_inf *uec_info;
+ u32 end_bd;
+ u8 bmrx = 0;
+ int i;
+
+ uec_info = uec->uec_info;
+
+ /* Alloc global Tx parameter RAM page */
+ uec->tx_glbl_pram_offset =
+ qe_muram_alloc(sizeof(struct uec_tx_global_pram),
+ UEC_TX_GLOBAL_PRAM_ALIGNMENT);
+ uec->p_tx_glbl_pram = (struct uec_tx_global_pram *)
+ qe_muram_addr(uec->tx_glbl_pram_offset);
+
+ /* Zero the global Tx prameter RAM */
+ memset(uec->p_tx_glbl_pram, 0, sizeof(struct uec_tx_global_pram));
+
+ /* Init global Tx parameter RAM */
+
+ /* TEMODER, RMON statistics disable, one Tx queue */
+ out_be16(&uec->p_tx_glbl_pram->temoder, TEMODER_INIT_VALUE);
+
+ /* SQPTR */
+ uec->send_q_mem_reg_offset =
+ qe_muram_alloc(sizeof(struct uec_send_queue_qd),
+ UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
+ uec->p_send_q_mem_reg = (struct uec_send_queue_mem_region *)
+ qe_muram_addr(uec->send_q_mem_reg_offset);
+ out_be32(&uec->p_tx_glbl_pram->sqptr, uec->send_q_mem_reg_offset);
+
+ /* Setup the table with TxBDs ring */
+ end_bd = (u32)uec->p_tx_bd_ring + (uec_info->tx_bd_ring_len - 1)
+ * SIZEOFBD;
+ out_be32(&uec->p_send_q_mem_reg->sqqd[0].bd_ring_base,
+ (u32)(uec->p_tx_bd_ring));
+ out_be32(&uec->p_send_q_mem_reg->sqqd[0].last_bd_completed_address,
+ end_bd);
+
+ /* Scheduler Base Pointer, we have only one Tx queue, no need it */
+ out_be32(&uec->p_tx_glbl_pram->schedulerbasepointer, 0);
+
+ /* TxRMON Base Pointer, TxRMON disable, we don't need it */
+ out_be32(&uec->p_tx_glbl_pram->txrmonbaseptr, 0);
+
+ /* TSTATE, global snooping, big endian, the CSB bus selected */
+ bmrx = BMR_INIT_VALUE;
+ out_be32(&uec->p_tx_glbl_pram->tstate, ((u32)(bmrx) << BMR_SHIFT));
+
+ /* IPH_Offset */
+ for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++)
+ out_8(&uec->p_tx_glbl_pram->iphoffset[i], 0);
+
+ /* VTAG table */
+ for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++)
+ out_be32(&uec->p_tx_glbl_pram->vtagtable[i], 0);
+
+ /* TQPTR */
+ uec->thread_dat_tx_offset =
+ qe_muram_alloc(num_threads_tx *
+ sizeof(struct uec_thread_data_tx) +
+ 32 * (num_threads_tx == 1),
+ UEC_THREAD_DATA_ALIGNMENT);
+
+ uec->p_thread_data_tx = (struct uec_thread_data_tx *)
+ qe_muram_addr(uec->thread_dat_tx_offset);
+ out_be32(&uec->p_tx_glbl_pram->tqptr, uec->thread_dat_tx_offset);
+}
+
+static void uec_init_rx_parameter(struct uec_priv *uec, int num_threads_rx)
+{
+ u8 bmrx = 0;
+ int i;
+ struct uec_82xx_add_filtering_pram *p_af_pram;
+
+ /* Allocate global Rx parameter RAM page */
+ uec->rx_glbl_pram_offset =
+ qe_muram_alloc(sizeof(struct uec_rx_global_pram),
+ UEC_RX_GLOBAL_PRAM_ALIGNMENT);
+ uec->p_rx_glbl_pram = (struct uec_rx_global_pram *)
+ qe_muram_addr(uec->rx_glbl_pram_offset);
+
+ /* Zero Global Rx parameter RAM */
+ memset(uec->p_rx_glbl_pram, 0, sizeof(struct uec_rx_global_pram));
+
+ /* Init global Rx parameter RAM */
+ /*
+ * REMODER, Extended feature mode disable, VLAN disable,
+ * LossLess flow control disable, Receive firmware statisic disable,
+ * Extended address parsing mode disable, One Rx queues,
+ * Dynamic maximum/minimum frame length disable, IP checksum check
+ * disable, IP address alignment disable
+ */
+ out_be32(&uec->p_rx_glbl_pram->remoder, REMODER_INIT_VALUE);
+
+ /* RQPTR */
+ uec->thread_dat_rx_offset =
+ qe_muram_alloc(num_threads_rx *
+ sizeof(struct uec_thread_data_rx),
+ UEC_THREAD_DATA_ALIGNMENT);
+ uec->p_thread_data_rx = (struct uec_thread_data_rx *)
+ qe_muram_addr(uec->thread_dat_rx_offset);
+ out_be32(&uec->p_rx_glbl_pram->rqptr, uec->thread_dat_rx_offset);
+
+ /* Type_or_Len */
+ out_be16(&uec->p_rx_glbl_pram->typeorlen, 3072);
+
+ /* RxRMON base pointer, we don't need it */
+ out_be32(&uec->p_rx_glbl_pram->rxrmonbaseptr, 0);
+
+ /* IntCoalescingPTR, we don't need it, no interrupt */
+ out_be32(&uec->p_rx_glbl_pram->intcoalescingptr, 0);
+
+ /* RSTATE, global snooping, big endian, the CSB bus selected */
+ bmrx = BMR_INIT_VALUE;
+ out_8(&uec->p_rx_glbl_pram->rstate, bmrx);
+
+ /* MRBLR */
+ out_be16(&uec->p_rx_glbl_pram->mrblr, MAX_RXBUF_LEN);
+
+ /* RBDQPTR */
+ uec->rx_bd_qs_tbl_offset =
+ qe_muram_alloc(sizeof(struct uec_rx_bd_queues_entry) +
+ sizeof(struct uec_rx_pref_bds),
+ UEC_RX_BD_QUEUES_ALIGNMENT);
+ uec->p_rx_bd_qs_tbl = (struct uec_rx_bd_queues_entry *)
+ qe_muram_addr(uec->rx_bd_qs_tbl_offset);
+
+ /* Zero it */
+ memset(uec->p_rx_bd_qs_tbl, 0, sizeof(struct uec_rx_bd_queues_entry) +
+ sizeof(struct uec_rx_pref_bds));
+ out_be32(&uec->p_rx_glbl_pram->rbdqptr, uec->rx_bd_qs_tbl_offset);
+ out_be32(&uec->p_rx_bd_qs_tbl->externalbdbaseptr,
+ (u32)uec->p_rx_bd_ring);
+
+ /* MFLR */
+ out_be16(&uec->p_rx_glbl_pram->mflr, MAX_FRAME_LEN);
+ /* MINFLR */
+ out_be16(&uec->p_rx_glbl_pram->minflr, MIN_FRAME_LEN);
+ /* MAXD1 */
+ out_be16(&uec->p_rx_glbl_pram->maxd1, MAX_DMA1_LEN);
+ /* MAXD2 */
+ out_be16(&uec->p_rx_glbl_pram->maxd2, MAX_DMA2_LEN);
+ /* ECAM_PTR */
+ out_be32(&uec->p_rx_glbl_pram->ecamptr, 0);
+ /* L2QT */
+ out_be32(&uec->p_rx_glbl_pram->l2qt, 0);
+ /* L3QT */
+ for (i = 0; i < 8; i++)
+ out_be32(&uec->p_rx_glbl_pram->l3qt[i], 0);
+
+ /* VLAN_TYPE */
+ out_be16(&uec->p_rx_glbl_pram->vlantype, 0x8100);
+ /* TCI */
+ out_be16(&uec->p_rx_glbl_pram->vlantci, 0);
+
+ /* Clear PQ2 style address filtering hash table */
+ p_af_pram = (struct uec_82xx_add_filtering_pram *)
+ uec->p_rx_glbl_pram->addressfiltering;
+
+ p_af_pram->iaddr_h = 0;
+ p_af_pram->iaddr_l = 0;
+ p_af_pram->gaddr_h = 0;
+ p_af_pram->gaddr_l = 0;
+}
+
+static int uec_issue_init_enet_rxtx_cmd(struct uec_priv *uec,
+ int thread_tx, int thread_rx)
+{
+ struct uec_init_cmd_pram *p_init_enet_param;
+ u32 init_enet_param_offset;
+ struct uec_inf *uec_info;
+ struct ucc_fast_inf *uf_info;
+ int i;
+ int snum;
+ u32 off;
+ u32 entry_val;
+ u32 command;
+ u32 cecr_subblock;
+
+ uec_info = uec->uec_info;
+ uf_info = &uec_info->uf_info;
+
+ /* Allocate init enet command parameter */
+ uec->init_enet_param_offset =
+ qe_muram_alloc(sizeof(struct uec_init_cmd_pram), 4);
+ init_enet_param_offset = uec->init_enet_param_offset;
+ uec->p_init_enet_param = (struct uec_init_cmd_pram *)
+ qe_muram_addr(uec->init_enet_param_offset);
+
+ /* Zero init enet command struct */
+ memset((void *)uec->p_init_enet_param, 0,
+ sizeof(struct uec_init_cmd_pram));
+
+ /* Init the command struct */
+ p_init_enet_param = uec->p_init_enet_param;
+ p_init_enet_param->resinit0 = ENET_INIT_PARAM_MAGIC_RES_INIT0;
+ p_init_enet_param->resinit1 = ENET_INIT_PARAM_MAGIC_RES_INIT1;
+ p_init_enet_param->resinit2 = ENET_INIT_PARAM_MAGIC_RES_INIT2;
+ p_init_enet_param->resinit3 = ENET_INIT_PARAM_MAGIC_RES_INIT3;
+ p_init_enet_param->resinit4 = ENET_INIT_PARAM_MAGIC_RES_INIT4;
+ p_init_enet_param->largestexternallookupkeysize = 0;
+
+ p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_rx)
+ << ENET_INIT_PARAM_RGF_SHIFT;
+ p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_tx)
+ << ENET_INIT_PARAM_TGF_SHIFT;
+
+ /* Init Rx global parameter pointer */
+ p_init_enet_param->rgftgfrxglobal |= uec->rx_glbl_pram_offset |
+ (u32)uec_info->risc_rx;
+
+ /* Init Rx threads */
+ for (i = 0; i < (thread_rx + 1); i++) {
+ snum = qe_get_snum();
+ if (snum < 0) {
+ printf("%s can not get snum\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (i == 0) {
+ off = 0;
+ } else {
+ off = qe_muram_alloc(sizeof(struct uec_thread_rx_pram),
+ UEC_THREAD_RX_PRAM_ALIGNMENT);
+ }
+
+ entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) |
+ off | (u32)uec_info->risc_rx;
+ p_init_enet_param->rxthread[i] = entry_val;
+ }
+
+ /* Init Tx global parameter pointer */
+ p_init_enet_param->txglobal = uec->tx_glbl_pram_offset |
+ (u32)uec_info->risc_tx;
+
+ /* Init Tx threads */
+ for (i = 0; i < thread_tx; i++) {
+ snum = qe_get_snum();
+ if (snum < 0) {
+ printf("%s can not get snum\n", __func__);
+ return -ENOMEM;
+ }
+
+ off = qe_muram_alloc(sizeof(struct uec_thread_tx_pram),
+ UEC_THREAD_TX_PRAM_ALIGNMENT);
+
+ entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) |
+ off | (u32)uec_info->risc_tx;
+ p_init_enet_param->txthread[i] = entry_val;
+ }
+
+ __asm__ __volatile__("sync");
+
+ /* Issue QE command */
+ command = QE_INIT_TX_RX;
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
+ qe_issue_cmd(command, cecr_subblock, (u8)QE_CR_PROTOCOL_ETHERNET,
+ init_enet_param_offset);
+
+ return 0;
+}
+
+static int uec_startup(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct uec_priv *uec = priv->uec;
+ struct uec_inf *uec_info;
+ struct ucc_fast_inf *uf_info;
+ struct ucc_fast_priv *uccf;
+ ucc_fast_t *uf_regs;
+ uec_t *uec_regs;
+ int num_threads_tx;
+ int num_threads_rx;
+ u32 utbipar;
+ u32 length;
+ u32 align;
+ struct buffer_descriptor *bd;
+ u8 *buf;
+ int i;
+
+ uec_info = uec->uec_info;
+ uf_info = &uec_info->uf_info;
+
+ /* Check if Rx BD ring len is illegal */
+ if (uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN ||
+ uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT) {
+ printf("%s: Rx BD ring len must be multiple of 4, and > 8.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Check if Tx BD ring len is illegal */
+ if (uec_info->tx_bd_ring_len < UEC_TX_BD_RING_SIZE_MIN) {
+ printf("%s: Tx BD ring length must not be smaller than 2.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Check if MRBLR is illegal */
+ if (MAX_RXBUF_LEN == 0 || (MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT)) {
+ printf("%s: max rx buffer length must be mutliple of 128.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Both Rx and Tx are stopped */
+ uec->grace_stopped_rx = 1;
+ uec->grace_stopped_tx = 1;
+
+ /* Init UCC fast */
+ if (ucc_fast_init(uf_info, &uccf)) {
+ printf("%s: failed to init ucc fast\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* Save uccf */
+ uec->uccf = uccf;
+
+ /* Convert the Tx threads number */
+ if (uec_convert_threads_num(uec_info->num_threads_tx,
+ &num_threads_tx))
+ return -EINVAL;
+
+ /* Convert the Rx threads number */
+ if (uec_convert_threads_num(uec_info->num_threads_rx,
+ &num_threads_rx))
+ return -EINVAL;
+
+ uf_regs = uccf->uf_regs;
+
+ /* UEC register is following UCC fast registers */
+ uec_regs = (uec_t *)(&uf_regs->ucc_eth);
+
+ /* Save the UEC register pointer to UEC private struct */
+ uec->uec_regs = uec_regs;
+
+ /* Init UPSMR, enable hardware statistics (UCC) */
+ out_be32(&uec->uccf->uf_regs->upsmr, UPSMR_INIT_VALUE);
+
+ /* Init MACCFG1, flow control disable, disable Tx and Rx */
+ out_be32(&uec_regs->maccfg1, MACCFG1_INIT_VALUE);
+
+ /* Init MACCFG2, length check, MAC PAD and CRC enable */
+ out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE);
+
+ /* Setup UTBIPAR */
+ utbipar = in_be32(&uec_regs->utbipar);
+ utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
+
+ /* Initialize UTBIPAR address to CONFIG_UTBIPAR_INIT_TBIPA for ALL UEC.
+ * This frees up the remaining SMI addresses for use.
+ */
+ utbipar |= CONFIG_UTBIPAR_INIT_TBIPA << UTBIPAR_PHY_ADDRESS_SHIFT;
+ out_be32(&uec_regs->utbipar, utbipar);
+
+ /* Allocate Tx BDs */
+ length = ((uec_info->tx_bd_ring_len * SIZEOFBD) /
+ UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) *
+ UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+ if ((uec_info->tx_bd_ring_len * SIZEOFBD) %
+ UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ length += UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+
+ align = UEC_TX_BD_RING_ALIGNMENT;
+ uec->tx_bd_ring_offset = (u32)malloc((u32)(length + align));
+ if (uec->tx_bd_ring_offset != 0)
+ uec->p_tx_bd_ring = (u8 *)((uec->tx_bd_ring_offset + align)
+ & ~(align - 1));
+
+ /* Zero all of Tx BDs */
+ memset((void *)(uec->tx_bd_ring_offset), 0, length + align);
+
+ /* Allocate Rx BDs */
+ length = uec_info->rx_bd_ring_len * SIZEOFBD;
+ align = UEC_RX_BD_RING_ALIGNMENT;
+ uec->rx_bd_ring_offset = (u32)(malloc((u32)(length + align)));
+ if (uec->rx_bd_ring_offset != 0)
+ uec->p_rx_bd_ring = (u8 *)((uec->rx_bd_ring_offset + align)
+ & ~(align - 1));
+
+ /* Zero all of Rx BDs */
+ memset((void *)(uec->rx_bd_ring_offset), 0, length + align);
+
+ /* Allocate Rx buffer */
+ length = uec_info->rx_bd_ring_len * MAX_RXBUF_LEN;
+ align = UEC_RX_DATA_BUF_ALIGNMENT;
+ uec->rx_buf_offset = (u32)malloc(length + align);
+ if (uec->rx_buf_offset != 0)
+ uec->p_rx_buf = (u8 *)((uec->rx_buf_offset + align)
+ & ~(align - 1));
+
+ /* Zero all of the Rx buffer */
+ memset((void *)(uec->rx_buf_offset), 0, length + align);
+
+ /* Init TxBD ring */
+ bd = (struct buffer_descriptor *)uec->p_tx_bd_ring;
+ uec->tx_bd = bd;
+
+ for (i = 0; i < uec_info->tx_bd_ring_len; i++) {
+ BD_DATA_CLEAR(bd);
+ BD_STATUS_SET(bd, 0);
+ BD_LENGTH_SET(bd, 0);
+ bd++;
+ }
+ BD_STATUS_SET((--bd), TX_BD_WRAP);
+
+ /* Init RxBD ring */
+ bd = (struct buffer_descriptor *)uec->p_rx_bd_ring;
+ uec->rx_bd = bd;
+ buf = uec->p_rx_buf;
+ for (i = 0; i < uec_info->rx_bd_ring_len; i++) {
+ BD_DATA_SET(bd, buf);
+ BD_LENGTH_SET(bd, 0);
+ BD_STATUS_SET(bd, RX_BD_EMPTY);
+ buf += MAX_RXBUF_LEN;
+ bd++;
+ }
+ BD_STATUS_SET((--bd), RX_BD_WRAP | RX_BD_EMPTY);
+
+ /* Init global Tx parameter RAM */
+ uec_init_tx_parameter(uec, num_threads_tx);
+
+ /* Init global Rx parameter RAM */
+ uec_init_rx_parameter(uec, num_threads_rx);
+
+ /* Init ethernet Tx and Rx parameter command */
+ if (uec_issue_init_enet_rxtx_cmd(uec, num_threads_tx,
+ num_threads_rx)) {
+ printf("%s issue init enet cmd failed\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* Convert a string to a QE clock source enum
+ *
+ * This function takes a string, typically from a property in the device
+ * tree, and returns the corresponding "enum qe_clock" value.
+ */
+enum qe_clock qe_clock_source(const char *source)
+{
+ unsigned int i;
+
+ if (strcasecmp(source, "none") == 0)
+ return QE_CLK_NONE;
+
+ if (strncasecmp(source, "brg", 3) == 0) {
+ i = simple_strtoul(source + 3, NULL, 10);
+ if (i >= 1 && i <= 16)
+ return (QE_BRG1 - 1) + i;
+ else
+ return QE_CLK_DUMMY;
+ }
+
+ if (strncasecmp(source, "clk", 3) == 0) {
+ i = simple_strtoul(source + 3, NULL, 10);
+ if (i >= 1 && i <= 24)
+ return (QE_CLK1 - 1) + i;
+ else
+ return QE_CLK_DUMMY;
+ }
+
+ return QE_CLK_DUMMY;
+}
+
+static void qe_uec_set_eth_type(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct uec_priv *uec = priv->uec;
+ struct uec_inf *uec_info = uec->uec_info;
+ struct ucc_fast_inf *uf_info = &uec_info->uf_info;
+
+ switch (uec_info->enet_interface_type) {
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_TBI:
+ case PHY_INTERFACE_MODE_RTBI:
+ case PHY_INTERFACE_MODE_SGMII:
+ uf_info->eth_type = GIGA_ETH;
+ break;
+ default:
+ uf_info->eth_type = FAST_ETH;
+ break;
+ }
+}
+
+static int qe_uec_set_uec_info(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct uec_priv *uec = priv->uec;
+ struct uec_inf *uec_info;
+ struct ucc_fast_inf *uf_info;
+ const char *s;
+ int ret;
+ u32 val;
+
+ uec_info = (struct uec_inf *)malloc(sizeof(struct uec_inf));
+ if (!uec_info)
+ return -ENOMEM;
+
+ uf_info = &uec_info->uf_info;
+
+ ret = dev_read_u32(dev, "cell-index", &val);
+ if (ret) {
+ ret = dev_read_u32(dev, "device-id", &val);
+ if (ret) {
+ pr_err("no cell-index nor device-id found!");
+ goto out;
+ }
+ }
+
+ uf_info->ucc_num = val - 1;
+ if (uf_info->ucc_num < 0 || uf_info->ucc_num > 7) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = dev_read_string_index(dev, "rx-clock-name", 0, &s);
+ if (!ret) {
+ uf_info->rx_clock = qe_clock_source(s);
+ if (uf_info->rx_clock < QE_CLK_NONE ||
+ uf_info->rx_clock > QE_CLK24) {
+ pr_err("invalid rx-clock-name property\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ } else {
+ ret = dev_read_u32(dev, "rx-clock", &val);
+ if (ret) {
+ /*
+ * If both rx-clock-name and rx-clock are missing,
+ * we want to tell people to use rx-clock-name.
+ */
+ pr_err("missing rx-clock-name property\n");
+ goto out;
+ }
+ if (val < QE_CLK_NONE || val > QE_CLK24) {
+ pr_err("invalid rx-clock property\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ uf_info->rx_clock = val;
+ }
+
+ ret = dev_read_string_index(dev, "tx-clock-name", 0, &s);
+ if (!ret) {
+ uf_info->tx_clock = qe_clock_source(s);
+ if (uf_info->tx_clock < QE_CLK_NONE ||
+ uf_info->tx_clock > QE_CLK24) {
+ pr_err("invalid tx-clock-name property\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ } else {
+ ret = dev_read_u32(dev, "tx-clock", &val);
+ if (ret) {
+ pr_err("missing tx-clock-name property\n");
+ goto out;
+ }
+ if (val < QE_CLK_NONE || val > QE_CLK24) {
+ pr_err("invalid tx-clock property\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ uf_info->tx_clock = val;
+ }
+
+ uec_info->num_threads_tx = UEC_NUM_OF_THREADS_1;
+ uec_info->num_threads_rx = UEC_NUM_OF_THREADS_1;
+ uec_info->risc_tx = QE_RISC_ALLOCATION_RISC1_AND_RISC2;
+ uec_info->risc_rx = QE_RISC_ALLOCATION_RISC1_AND_RISC2;
+ uec_info->tx_bd_ring_len = 16;
+ uec_info->rx_bd_ring_len = 16;
+#if (MAX_QE_RISC == 4)
+ uec_info->risc_tx = QE_RISC_ALLOCATION_FOUR_RISCS;
+ uec_info->risc_rx = QE_RISC_ALLOCATION_FOUR_RISCS;
+#endif
+
+ uec_info->enet_interface_type = pdata->phy_interface;
+
+ uec->uec_info = uec_info;
+ qe_uec_set_eth_type(dev);
+
+ return 0;
+out:
+ free(uec_info);
+ return ret;
+}
+
+static int qe_uec_probe(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct uec_priv *uec;
+ int ret;
+
+ /* Allocate the UEC private struct */
+ uec = (struct uec_priv *)malloc(sizeof(struct uec_priv));
+ if (!uec)
+ return -ENOMEM;
+
+ memset(uec, 0, sizeof(struct uec_priv));
+ priv->uec = uec;
+ uec->uec_regs = (uec_t *)pdata->iobase;
+
+ /* setup uec info struct */
+ ret = qe_uec_set_uec_info(dev);
+ if (ret) {
+ free(uec);
+ return ret;
+ }
+
+ ret = uec_startup(dev);
+ if (ret) {
+ free(uec->uec_info);
+ free(uec);
+ return ret;
+ }
+
+ priv->phydev = dm_eth_phy_connect(dev);
+ return 0;
+}
+
+/*
+ * Remove the driver from an interface:
+ * - free up allocated memory
+ */
+static int qe_uec_remove(struct udevice *dev)
+{
+ struct qe_uec_priv *priv = dev_get_priv(dev);
+
+ free(priv->uec);
+ return 0;
+}
+
+static int qe_uec_ofdata_to_platdata(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ const char *phy_mode;
+
+ pdata->iobase = (phys_addr_t)devfdt_get_addr(dev);
+
+ pdata->phy_interface = -1;
+ phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+ "phy-connection-type", NULL);
+ if (phy_mode)
+ pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+ if (pdata->phy_interface == -1) {
+ debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id qe_uec_ids[] = {
+ { .compatible = QE_UEC_DRIVER_NAME },
+ { }
+};
+
+U_BOOT_DRIVER(eth_qe_uec) = {
+ .name = QE_UEC_DRIVER_NAME,
+ .id = UCLASS_ETH,
+ .of_match = qe_uec_ids,
+ .ofdata_to_platdata = qe_uec_ofdata_to_platdata,
+ .probe = qe_uec_probe,
+ .remove = qe_uec_remove,
+ .ops = &qe_uec_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct qe_uec_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/qe/dm_qe_uec.h b/drivers/net/qe/dm_qe_uec.h
new file mode 100644
index 0000000000..690093caa2
--- /dev/null
+++ b/drivers/net/qe/dm_qe_uec.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * QE UEC ethernet controller driver
+ *
+ * based on drivers/qe/uec.c from NXP
+ *
+ * Copyright (C) 2020 Heiko Schocher <hs@denx.de>
+ */
+
+#ifndef _DM_QE_UEC_H
+#define _DM_QE_UEC_H
+
+#define qe_uec_dbg(dev, fmt, args...) debug("%s:" fmt, dev->name, ##args)
+
+#include "uec.h"
+
+/* QE UEC private structure */
+struct qe_uec_priv {
+ struct uec_priv *uec;
+ struct phy_device *phydev;
+};
+#endif
diff --git a/drivers/net/qe/dm_qe_uec_phy.c b/drivers/net/qe/dm_qe_uec_phy.c
new file mode 100644
index 0000000000..02ce08edad
--- /dev/null
+++ b/drivers/net/qe/dm_qe_uec_phy.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * QE UEC ethernet phy controller driver
+ *
+ * based on phy parts of drivers/qe/uec.c and drivers/qe/uec_phy.c
+ * from NXP
+ *
+ * Copyright (C) 2020 Heiko Schocher <hs@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+
+#include "dm_qe_uec.h"
+
+struct qe_uec_mdio_priv {
+ struct ucc_mii_mng *base;
+};
+
+static int
+qe_uec_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+ struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
+ struct ucc_mii_mng *regs = priv->base;
+ u32 tmp_reg;
+ u16 value;
+
+ debug("%s: regs: %p addr: %x devad: %x reg: %x\n", __func__, regs,
+ addr, devad, reg);
+ /* Setting up the MII management Address Register */
+ tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
+ out_be32(&regs->miimadd, tmp_reg);
+
+ /* clear MII management command cycle */
+ out_be32(&regs->miimcom, 0);
+ sync();
+
+ /* Perform an MII management read cycle */
+ out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) &
+ (MIIMIND_NOT_VALID | MIIMIND_BUSY))
+ ;
+
+ /* Read MII management status */
+ value = (u16)in_be32(&regs->miimstat);
+ if (value == 0xffff)
+ return -EINVAL;
+
+ return value;
+};
+
+static int
+qe_uec_mdio_write(struct udevice *dev, int addr, int devad, int reg,
+ u16 value)
+{
+ struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
+ struct ucc_mii_mng *regs = priv->base;
+ u32 tmp_reg;
+
+ debug("%s: regs: %p addr: %x devad: %x reg: %x val: %x\n", __func__,
+ regs, addr, devad, reg, value);
+
+ /* Stop the MII management read cycle */
+ out_be32(&regs->miimcom, 0);
+ /* Setting up the MII management Address Register */
+ tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
+ out_be32(&regs->miimadd, tmp_reg);
+
+ /* Setting up the MII management Control Register with the value */
+ out_be32(&regs->miimcon, (u32)value);
+ sync();
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
+ ;
+
+ return 0;
+};
+
+static const struct mdio_ops qe_uec_mdio_ops = {
+ .read = qe_uec_mdio_read,
+ .write = qe_uec_mdio_write,
+};
+
+static int qe_uec_mdio_probe(struct udevice *dev)
+{
+ struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
+ fdt_size_t base;
+ ofnode node;
+ u32 num = 0;
+ int ret = -ENODEV;
+
+ priv->base = (struct ucc_mii_mng *)dev_read_addr(dev);
+ base = (fdt_size_t)priv->base;
+
+ /*
+ * idea from linux:
+ * drivers/net/ethernet/freescale/fsl_pq_mdio.c
+ *
+ * Find the UCC node that controls the given MDIO node
+ *
+ * For some reason, the QE MDIO nodes are not children of the UCC
+ * devices that control them. Therefore, we need to scan all UCC
+ * nodes looking for the one that encompases the given MDIO node.
+ * We do this by comparing physical addresses. The 'start' and
+ * 'end' addresses of the MDIO node are passed, and the correct
+ * UCC node will cover the entire address range.
+ */
+ node = ofnode_by_compatible(ofnode_null(), "ucc_geth");
+ while (ofnode_valid(node)) {
+ fdt_size_t size;
+ fdt_addr_t addr;
+
+ addr = ofnode_get_addr_index(node, 0);
+ ret = ofnode_get_addr_size_index(node, 0, &size);
+
+ if (addr == FDT_ADDR_T_NONE) {
+ node = ofnode_by_compatible(node, "ucc_geth");
+ continue;
+ }
+
+ /* check if priv->base in start end */
+ if (base > addr && base < (addr + size)) {
+ ret = ofnode_read_u32(node, "cell-index", &num);
+ if (ret)
+ ret = ofnode_read_u32(node, "device-id",
+ &num);
+ break;
+ }
+ node = ofnode_by_compatible(node, "ucc_geth");
+ }
+
+ if (ret) {
+ printf("%s: no cell-index nor device-id found!", __func__);
+ return ret;
+ }
+
+ /* Setup MII master clock source */
+ qe_set_mii_clk_src(num - 1);
+
+ return 0;
+}
+
+static const struct udevice_id qe_uec_mdio_ids[] = {
+ { .compatible = "fsl,ucc-mdio" },
+ { }
+};
+
+U_BOOT_DRIVER(mvmdio) = {
+ .name = "qe_uec_mdio",
+ .id = UCLASS_MDIO,
+ .of_match = qe_uec_mdio_ids,
+ .probe = qe_uec_mdio_probe,
+ .ops = &qe_uec_mdio_ops,
+ .priv_auto_alloc_size = sizeof(struct qe_uec_mdio_priv),
+};
diff --git a/drivers/net/qe/uccf.c b/drivers/net/qe/uccf.c
new file mode 100644
index 0000000000..306f1ea1db
--- /dev/null
+++ b/drivers/net/qe/uccf.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/immap_qe.h>
+#include "uccf.h"
+#include <fsl_qe.h>
+
+void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf)
+{
+ out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
+}
+
+u32 ucc_fast_get_qe_cr_subblock(int ucc_num)
+{
+ switch (ucc_num) {
+ case 0:
+ return QE_CR_SUBBLOCK_UCCFAST1;
+ case 1:
+ return QE_CR_SUBBLOCK_UCCFAST2;
+ case 2:
+ return QE_CR_SUBBLOCK_UCCFAST3;
+ case 3:
+ return QE_CR_SUBBLOCK_UCCFAST4;
+ case 4:
+ return QE_CR_SUBBLOCK_UCCFAST5;
+ case 5:
+ return QE_CR_SUBBLOCK_UCCFAST6;
+ case 6:
+ return QE_CR_SUBBLOCK_UCCFAST7;
+ case 7:
+ return QE_CR_SUBBLOCK_UCCFAST8;
+ default:
+ return QE_CR_SUBBLOCK_INVALID;
+ }
+}
+
+static void ucc_get_cmxucr_reg(int ucc_num, u32 **p_cmxucr,
+ u8 *reg_num, u8 *shift)
+{
+ switch (ucc_num) {
+ case 0: /* UCC1 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr1;
+ *reg_num = 1;
+ *shift = 16;
+ break;
+ case 2: /* UCC3 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr1;
+ *reg_num = 1;
+ *shift = 0;
+ break;
+ case 4: /* UCC5 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr2;
+ *reg_num = 2;
+ *shift = 16;
+ break;
+ case 6: /* UCC7 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr2;
+ *reg_num = 2;
+ *shift = 0;
+ break;
+ case 1: /* UCC2 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr3;
+ *reg_num = 3;
+ *shift = 16;
+ break;
+ case 3: /* UCC4 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr3;
+ *reg_num = 3;
+ *shift = 0;
+ break;
+ case 5: /* UCC6 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr4;
+ *reg_num = 4;
+ *shift = 16;
+ break;
+ case 7: /* UCC8 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr4;
+ *reg_num = 4;
+ *shift = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static int ucc_set_clk_src(int ucc_num, qe_clock_e clock, comm_dir_e mode)
+{
+ u32 *p_cmxucr = NULL;
+ u8 reg_num = 0;
+ u8 shift = 0;
+ u32 clk_bits;
+ u32 clk_mask;
+ int source = -1;
+
+ /* check if the UCC number is in range. */
+ if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0)
+ return -EINVAL;
+
+ if (!(mode == COMM_DIR_RX || mode == COMM_DIR_TX)) {
+ printf("%s: bad comm mode type passed\n", __func__);
+ return -EINVAL;
+ }
+
+ ucc_get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
+
+ switch (reg_num) {
+ case 1:
+ switch (clock) {
+ case QE_BRG1:
+ source = 1;
+ break;
+ case QE_BRG2:
+ source = 2;
+ break;
+ case QE_BRG7:
+ source = 3;
+ break;
+ case QE_BRG8:
+ source = 4;
+ break;
+ case QE_CLK9:
+ source = 5;
+ break;
+ case QE_CLK10:
+ source = 6;
+ break;
+ case QE_CLK11:
+ source = 7;
+ break;
+ case QE_CLK12:
+ source = 8;
+ break;
+ case QE_CLK15:
+ source = 9;
+ break;
+ case QE_CLK16:
+ source = 10;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG5:
+ source = 1;
+ break;
+ case QE_BRG6:
+ source = 2;
+ break;
+ case QE_BRG7:
+ source = 3;
+ break;
+ case QE_BRG8:
+ source = 4;
+ break;
+ case QE_CLK13:
+ source = 5;
+ break;
+ case QE_CLK14:
+ source = 6;
+ break;
+ case QE_CLK19:
+ source = 7;
+ break;
+ case QE_CLK20:
+ source = 8;
+ break;
+ case QE_CLK15:
+ source = 9;
+ break;
+ case QE_CLK16:
+ source = 10;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG9:
+ source = 1;
+ break;
+ case QE_BRG10:
+ source = 2;
+ break;
+ case QE_BRG15:
+ source = 3;
+ break;
+ case QE_BRG16:
+ source = 4;
+ break;
+ case QE_CLK3:
+ source = 5;
+ break;
+ case QE_CLK4:
+ source = 6;
+ break;
+ case QE_CLK17:
+ source = 7;
+ break;
+ case QE_CLK18:
+ source = 8;
+ break;
+ case QE_CLK7:
+ source = 9;
+ break;
+ case QE_CLK8:
+ source = 10;
+ break;
+ case QE_CLK16:
+ source = 11;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ case 4:
+ switch (clock) {
+ case QE_BRG13:
+ source = 1;
+ break;
+ case QE_BRG14:
+ source = 2;
+ break;
+ case QE_BRG15:
+ source = 3;
+ break;
+ case QE_BRG16:
+ source = 4;
+ break;
+ case QE_CLK5:
+ source = 5;
+ break;
+ case QE_CLK6:
+ source = 6;
+ break;
+ case QE_CLK21:
+ source = 7;
+ break;
+ case QE_CLK22:
+ source = 8;
+ break;
+ case QE_CLK7:
+ source = 9;
+ break;
+ case QE_CLK8:
+ source = 10;
+ break;
+ case QE_CLK16:
+ source = 11;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ default:
+ source = -1;
+ break;
+ }
+
+ if (source == -1) {
+ printf("%s: Bad combination of clock and UCC\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_bits = (u32)source;
+ clk_mask = QE_CMXUCR_TX_CLK_SRC_MASK;
+ if (mode == COMM_DIR_RX) {
+ clk_bits <<= 4; /* Rx field is 4 bits to left of Tx field */
+ clk_mask <<= 4; /* Rx field is 4 bits to left of Tx field */
+ }
+ clk_bits <<= shift;
+ clk_mask <<= shift;
+
+ out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clk_mask) | clk_bits);
+
+ return 0;
+}
+
+static uint ucc_get_reg_baseaddr(int ucc_num)
+{
+ uint base = 0;
+
+ /* check if the UCC number is in range */
+ if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
+ printf("%s: the UCC num not in ranges\n", __func__);
+ return 0;
+ }
+
+ switch (ucc_num) {
+ case 0:
+ base = 0x00002000;
+ break;
+ case 1:
+ base = 0x00003000;
+ break;
+ case 2:
+ base = 0x00002200;
+ break;
+ case 3:
+ base = 0x00003200;
+ break;
+ case 4:
+ base = 0x00002400;
+ break;
+ case 5:
+ base = 0x00003400;
+ break;
+ case 6:
+ base = 0x00002600;
+ break;
+ case 7:
+ base = 0x00003600;
+ break;
+ default:
+ break;
+ }
+
+ base = (uint)qe_immr + base;
+ return base;
+}
+
+void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode)
+{
+ ucc_fast_t *uf_regs;
+ u32 gumr;
+
+ uf_regs = uccf->uf_regs;
+
+ /* Enable reception and/or transmission on this UCC. */
+ gumr = in_be32(&uf_regs->gumr);
+ if (mode & COMM_DIR_TX) {
+ gumr |= UCC_FAST_GUMR_ENT;
+ uccf->enabled_tx = 1;
+ }
+ if (mode & COMM_DIR_RX) {
+ gumr |= UCC_FAST_GUMR_ENR;
+ uccf->enabled_rx = 1;
+ }
+ out_be32(&uf_regs->gumr, gumr);
+}
+
+void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode)
+{
+ ucc_fast_t *uf_regs;
+ u32 gumr;
+
+ uf_regs = uccf->uf_regs;
+
+ /* Disable reception and/or transmission on this UCC. */
+ gumr = in_be32(&uf_regs->gumr);
+ if (mode & COMM_DIR_TX) {
+ gumr &= ~UCC_FAST_GUMR_ENT;
+ uccf->enabled_tx = 0;
+ }
+ if (mode & COMM_DIR_RX) {
+ gumr &= ~UCC_FAST_GUMR_ENR;
+ uccf->enabled_rx = 0;
+ }
+ out_be32(&uf_regs->gumr, gumr);
+}
+
+int ucc_fast_init(struct ucc_fast_inf *uf_info,
+ struct ucc_fast_priv **uccf_ret)
+{
+ struct ucc_fast_priv *uccf;
+ ucc_fast_t *uf_regs;
+
+ if (!uf_info)
+ return -EINVAL;
+
+ if (uf_info->ucc_num < 0 || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
+ printf("%s: Illagal UCC number!\n", __func__);
+ return -EINVAL;
+ }
+
+ uccf = (struct ucc_fast_priv *)malloc(sizeof(struct ucc_fast_priv));
+ if (!uccf) {
+ printf("%s: No memory for UCC fast data structure!\n",
+ __func__);
+ return -ENOMEM;
+ }
+ memset(uccf, 0, sizeof(struct ucc_fast_priv));
+
+ /* Save fast UCC structure */
+ uccf->uf_info = uf_info;
+ uccf->uf_regs = (ucc_fast_t *)ucc_get_reg_baseaddr(uf_info->ucc_num);
+
+ if (!uccf->uf_regs) {
+ printf("%s: No memory map for UCC fast controller!\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ uccf->enabled_tx = 0;
+ uccf->enabled_rx = 0;
+
+ uf_regs = uccf->uf_regs;
+ uccf->p_ucce = (u32 *)&uf_regs->ucce;
+ uccf->p_uccm = (u32 *)&uf_regs->uccm;
+
+ /* Init GUEMR register, UCC both Rx and Tx is Fast protocol */
+ out_8(&uf_regs->guemr, UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_FAST_RX
+ | UCC_GUEMR_MODE_FAST_TX);
+
+ /* Set GUMR, disable UCC both Rx and Tx, Ethernet protocol */
+ out_be32(&uf_regs->gumr, UCC_FAST_GUMR_ETH);
+
+ /* Set the Giga ethernet VFIFO stuff */
+ if (uf_info->eth_type == GIGA_ETH) {
+ /* Allocate memory for Tx Virtual Fifo */
+ uccf->ucc_fast_tx_virtual_fifo_base_offset =
+ qe_muram_alloc(UCC_GETH_UTFS_GIGA_INIT,
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+
+ /* Allocate memory for Rx Virtual Fifo */
+ uccf->ucc_fast_rx_virtual_fifo_base_offset =
+ qe_muram_alloc(UCC_GETH_URFS_GIGA_INIT +
+ UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD,
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+
+ /* utfb, urfb are offsets from MURAM base */
+ out_be32(&uf_regs->utfb,
+ uccf->ucc_fast_tx_virtual_fifo_base_offset);
+ out_be32(&uf_regs->urfb,
+ uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+ /* Set Virtual Fifo registers */
+ out_be16(&uf_regs->urfs, UCC_GETH_URFS_GIGA_INIT);
+ out_be16(&uf_regs->urfet, UCC_GETH_URFET_GIGA_INIT);
+ out_be16(&uf_regs->urfset, UCC_GETH_URFSET_GIGA_INIT);
+ out_be16(&uf_regs->utfs, UCC_GETH_UTFS_GIGA_INIT);
+ out_be16(&uf_regs->utfet, UCC_GETH_UTFET_GIGA_INIT);
+ out_be16(&uf_regs->utftt, UCC_GETH_UTFTT_GIGA_INIT);
+ }
+
+ /* Set the Fast ethernet VFIFO stuff */
+ if (uf_info->eth_type == FAST_ETH) {
+ /* Allocate memory for Tx Virtual Fifo */
+ uccf->ucc_fast_tx_virtual_fifo_base_offset =
+ qe_muram_alloc(UCC_GETH_UTFS_INIT,
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+
+ /* Allocate memory for Rx Virtual Fifo */
+ uccf->ucc_fast_rx_virtual_fifo_base_offset =
+ qe_muram_alloc(UCC_GETH_URFS_INIT +
+ UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD,
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+
+ /* utfb, urfb are offsets from MURAM base */
+ out_be32(&uf_regs->utfb,
+ uccf->ucc_fast_tx_virtual_fifo_base_offset);
+ out_be32(&uf_regs->urfb,
+ uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+ /* Set Virtual Fifo registers */
+ out_be16(&uf_regs->urfs, UCC_GETH_URFS_INIT);
+ out_be16(&uf_regs->urfet, UCC_GETH_URFET_INIT);
+ out_be16(&uf_regs->urfset, UCC_GETH_URFSET_INIT);
+ out_be16(&uf_regs->utfs, UCC_GETH_UTFS_INIT);
+ out_be16(&uf_regs->utfet, UCC_GETH_UTFET_INIT);
+ out_be16(&uf_regs->utftt, UCC_GETH_UTFTT_INIT);
+ }
+
+ /* Rx clock routing */
+ if (uf_info->rx_clock != QE_CLK_NONE) {
+ if (ucc_set_clk_src(uf_info->ucc_num,
+ uf_info->rx_clock, COMM_DIR_RX)) {
+ printf("%s: Illegal value for parameter 'RxClock'.\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ /* Tx clock routing */
+ if (uf_info->tx_clock != QE_CLK_NONE) {
+ if (ucc_set_clk_src(uf_info->ucc_num,
+ uf_info->tx_clock, COMM_DIR_TX)) {
+ printf("%s: Illegal value for parameter 'TxClock'.\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ /* Clear interrupt mask register to disable all of interrupts */
+ out_be32(&uf_regs->uccm, 0x0);
+
+ /* Writing '1' to clear all of envents */
+ out_be32(&uf_regs->ucce, 0xffffffff);
+
+ *uccf_ret = uccf;
+ return 0;
+}
diff --git a/drivers/net/qe/uccf.h b/drivers/net/qe/uccf.h
new file mode 100644
index 0000000000..99f8458edf
--- /dev/null
+++ b/drivers/net/qe/uccf.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ */
+
+#ifndef __UCCF_H__
+#define __UCCF_H__
+
+#include "common.h"
+#include "linux/immap_qe.h"
+#include <fsl_qe.h>
+
+/* Fast or Giga ethernet */
+enum enet_type {
+ FAST_ETH,
+ GIGA_ETH,
+};
+
+/* General UCC Extended Mode Register */
+#define UCC_GUEMR_MODE_MASK_RX 0x02
+#define UCC_GUEMR_MODE_MASK_TX 0x01
+#define UCC_GUEMR_MODE_FAST_RX 0x02
+#define UCC_GUEMR_MODE_FAST_TX 0x01
+#define UCC_GUEMR_MODE_SLOW_RX 0x00
+#define UCC_GUEMR_MODE_SLOW_TX 0x00
+/* Bit 3 must be set 1 */
+#define UCC_GUEMR_SET_RESERVED3 0x10
+
+/* General UCC FAST Mode Register */
+#define UCC_FAST_GUMR_TCI 0x20000000
+#define UCC_FAST_GUMR_TRX 0x10000000
+#define UCC_FAST_GUMR_TTX 0x08000000
+#define UCC_FAST_GUMR_CDP 0x04000000
+#define UCC_FAST_GUMR_CTSP 0x02000000
+#define UCC_FAST_GUMR_CDS 0x01000000
+#define UCC_FAST_GUMR_CTSS 0x00800000
+#define UCC_FAST_GUMR_TXSY 0x00020000
+#define UCC_FAST_GUMR_RSYN 0x00010000
+#define UCC_FAST_GUMR_RTSM 0x00002000
+#define UCC_FAST_GUMR_REVD 0x00000400
+#define UCC_FAST_GUMR_ENR 0x00000020
+#define UCC_FAST_GUMR_ENT 0x00000010
+
+/* GUMR [MODE] bit maps */
+#define UCC_FAST_GUMR_HDLC 0x00000000
+#define UCC_FAST_GUMR_QMC 0x00000002
+#define UCC_FAST_GUMR_UART 0x00000004
+#define UCC_FAST_GUMR_BISYNC 0x00000008
+#define UCC_FAST_GUMR_ATM 0x0000000a
+#define UCC_FAST_GUMR_ETH 0x0000000c
+
+/* Transmit On Demand (UTORD) */
+#define UCC_SLOW_TOD 0x8000
+#define UCC_FAST_TOD 0x8000
+
+/* Fast Ethernet (10/100 Mbps) */
+/* Rx virtual FIFO size */
+#define UCC_GETH_URFS_INIT 512
+/* 1/2 urfs */
+#define UCC_GETH_URFET_INIT 256
+/* 3/4 urfs */
+#define UCC_GETH_URFSET_INIT 384
+/* Tx virtual FIFO size */
+#define UCC_GETH_UTFS_INIT 512
+/* 1/2 utfs */
+#define UCC_GETH_UTFET_INIT 256
+#define UCC_GETH_UTFTT_INIT 128
+
+/* Gigabit Ethernet (1000 Mbps) */
+/* Rx virtual FIFO size */
+#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/
+/* 1/2 urfs */
+#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/
+/* 3/4 urfs */
+#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/
+/* Tx virtual FIFO size */
+#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/
+/* 1/2 utfs */
+#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/
+#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/
+
+/* UCC fast alignment */
+#define UCC_FAST_RX_ALIGN 4
+#define UCC_FAST_MRBLR_ALIGNMENT 4
+#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8
+
+/* Sizes */
+#define UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD 8
+
+/* UCC fast structure. */
+struct ucc_fast_inf {
+ int ucc_num;
+ qe_clock_e rx_clock;
+ qe_clock_e tx_clock;
+ enum enet_type eth_type;
+};
+
+struct ucc_fast_priv {
+ struct ucc_fast_inf *uf_info;
+ ucc_fast_t *uf_regs; /* a pointer to memory map of UCC regs */
+ u32 *p_ucce; /* a pointer to the event register */
+ u32 *p_uccm; /* a pointer to the mask register */
+ int enabled_tx; /* whether UCC is enabled for Tx (ENT) */
+ int enabled_rx; /* whether UCC is enabled for Rx (ENR) */
+ u32 ucc_fast_tx_virtual_fifo_base_offset;
+ u32 ucc_fast_rx_virtual_fifo_base_offset;
+};
+
+void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf);
+u32 ucc_fast_get_qe_cr_subblock(int ucc_num);
+void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode);
+void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode);
+int ucc_fast_init(struct ucc_fast_inf *uf_info,
+ struct ucc_fast_priv **uccf_ret);
+
+#endif /* __UCCF_H__ */
diff --git a/drivers/net/qe/uec.h b/drivers/net/qe/uec.h
new file mode 100644
index 0000000000..7cd4b8737a
--- /dev/null
+++ b/drivers/net/qe/uec.h
@@ -0,0 +1,693 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2006-2010 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ */
+
+#ifndef __UEC_H__
+#define __UEC_H__
+
+#include "uccf.h"
+#include <fsl_qe.h>
+#include <phy.h>
+
+#define MAX_TX_THREADS 8
+#define MAX_RX_THREADS 8
+#define MAX_TX_QUEUES 8
+#define MAX_RX_QUEUES 8
+#define MAX_PREFETCHED_BDS 4
+#define MAX_IPH_OFFSET_ENTRY 8
+#define MAX_ENET_INIT_PARAM_ENTRIES_RX 9
+#define MAX_ENET_INIT_PARAM_ENTRIES_TX 8
+
+/* UEC UPSMR (Protocol Specific Mode Register)
+ */
+#define UPSMR_ECM 0x04000000 /* Enable CAM Miss */
+#define UPSMR_HSE 0x02000000 /* Hardware Statistics Enable */
+#define UPSMR_PRO 0x00400000 /* Promiscuous */
+#define UPSMR_CAP 0x00200000 /* CAM polarity */
+#define UPSMR_RSH 0x00100000 /* Receive Short Frames */
+#define UPSMR_RPM 0x00080000 /* Reduced Pin Mode interfaces */
+#define UPSMR_R10M 0x00040000 /* RGMII/RMII 10 Mode */
+#define UPSMR_RLPB 0x00020000 /* RMII Loopback Mode */
+#define UPSMR_TBIM 0x00010000 /* Ten-bit Interface Mode */
+#define UPSMR_RMM 0x00001000 /* RMII/RGMII Mode */
+#define UPSMR_CAM 0x00000400 /* CAM Address Matching */
+#define UPSMR_BRO 0x00000200 /* Broadcast Address */
+#define UPSMR_RES1 0x00002000 /* Reserved feild - must be 1 */
+#define UPSMR_SGMM 0x00000020 /* SGMII mode */
+
+#define UPSMR_INIT_VALUE (UPSMR_HSE | UPSMR_RES1)
+
+/* UEC MACCFG1 (MAC Configuration 1 Register)
+ */
+#define MACCFG1_FLOW_RX 0x00000020 /* Flow Control Rx */
+#define MACCFG1_FLOW_TX 0x00000010 /* Flow Control Tx */
+#define MACCFG1_ENABLE_SYNCHED_RX 0x00000008 /* Enable Rx Sync */
+#define MACCFG1_ENABLE_RX 0x00000004 /* Enable Rx */
+#define MACCFG1_ENABLE_SYNCHED_TX 0x00000002 /* Enable Tx Sync */
+#define MACCFG1_ENABLE_TX 0x00000001 /* Enable Tx */
+
+#define MACCFG1_INIT_VALUE (0)
+
+/* UEC MACCFG2 (MAC Configuration 2 Register)
+ */
+#define MACCFG2_PREL 0x00007000
+#define MACCFG2_PREL_SHIFT (31 - 19)
+#define MACCFG2_PREL_MASK 0x0000f000
+#define MACCFG2_SRP 0x00000080
+#define MACCFG2_STP 0x00000040
+#define MACCFG2_RESERVED_1 0x00000020 /* must be set */
+#define MACCFG2_LC 0x00000010 /* Length Check */
+#define MACCFG2_MPE 0x00000008
+#define MACCFG2_FDX 0x00000001 /* Full Duplex */
+#define MACCFG2_FDX_MASK 0x00000001
+#define MACCFG2_PAD_CRC 0x00000004
+#define MACCFG2_CRC_EN 0x00000002
+#define MACCFG2_PAD_AND_CRC_MODE_NONE 0x00000000
+#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY 0x00000002
+#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC 0x00000004
+#define MACCFG2_INTERFACE_MODE_NIBBLE 0x00000100
+#define MACCFG2_INTERFACE_MODE_BYTE 0x00000200
+#define MACCFG2_INTERFACE_MODE_MASK 0x00000300
+
+#define MACCFG2_INIT_VALUE (MACCFG2_PREL | MACCFG2_RESERVED_1 | \
+ MACCFG2_LC | MACCFG2_PAD_CRC | MACCFG2_FDX)
+
+/* UEC Event Register */
+#define UCCE_MPD 0x80000000
+#define UCCE_SCAR 0x40000000
+#define UCCE_GRA 0x20000000
+#define UCCE_CBPR 0x10000000
+#define UCCE_BSY 0x08000000
+#define UCCE_RXC 0x04000000
+#define UCCE_TXC 0x02000000
+#define UCCE_TXE 0x01000000
+#define UCCE_TXB7 0x00800000
+#define UCCE_TXB6 0x00400000
+#define UCCE_TXB5 0x00200000
+#define UCCE_TXB4 0x00100000
+#define UCCE_TXB3 0x00080000
+#define UCCE_TXB2 0x00040000
+#define UCCE_TXB1 0x00020000
+#define UCCE_TXB0 0x00010000
+#define UCCE_RXB7 0x00008000
+#define UCCE_RXB6 0x00004000
+#define UCCE_RXB5 0x00002000
+#define UCCE_RXB4 0x00001000
+#define UCCE_RXB3 0x00000800
+#define UCCE_RXB2 0x00000400
+#define UCCE_RXB1 0x00000200
+#define UCCE_RXB0 0x00000100
+#define UCCE_RXF7 0x00000080
+#define UCCE_RXF6 0x00000040
+#define UCCE_RXF5 0x00000020
+#define UCCE_RXF4 0x00000010
+#define UCCE_RXF3 0x00000008
+#define UCCE_RXF2 0x00000004
+#define UCCE_RXF1 0x00000002
+#define UCCE_RXF0 0x00000001
+
+#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 | \
+ UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0)
+#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 | \
+ UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0)
+#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 | \
+ UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0)
+#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY | \
+ UCCE_RXC | UCCE_TXC | UCCE_TXE)
+
+/* UEC TEMODR Register */
+#define TEMODER_SCHEDULER_ENABLE 0x2000
+#define TEMODER_IP_CHECKSUM_GENERATE 0x0400
+#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200
+#define TEMODER_RMON_STATISTICS 0x0100
+#define TEMODER_NUM_OF_QUEUES_SHIFT (15 - 15)
+
+#define TEMODER_INIT_VALUE 0xc000
+
+/* UEC REMODR Register */
+#define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000
+#define REMODER_RX_EXTENDED_FEATURES 0x80000000
+#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31 - 9)
+#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31 - 10)
+#define REMODER_RX_QOS_MODE_SHIFT (31 - 15)
+#define REMODER_RMON_STATISTICS 0x00001000
+#define REMODER_RX_EXTENDED_FILTERING 0x00000800
+#define REMODER_NUM_OF_QUEUES_SHIFT (31 - 23)
+#define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008
+#define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004
+#define REMODER_IP_CHECKSUM_CHECK 0x00000002
+#define REMODER_IP_ADDRESS_ALIGNMENT 0x00000001
+
+#define REMODER_INIT_VALUE 0
+
+/* BMRx - Bus Mode Register */
+#define BMR_GLB 0x20
+#define BMR_BO_BE 0x10
+#define BMR_DTB_SECONDARY_BUS 0x02
+#define BMR_BDB_SECONDARY_BUS 0x01
+
+#define BMR_SHIFT 24
+#define BMR_INIT_VALUE (BMR_GLB | BMR_BO_BE)
+
+/* UEC UCCS (Ethernet Status Register)
+ */
+#define UCCS_BPR 0x02
+#define UCCS_PAU 0x02
+#define UCCS_MPD 0x01
+
+/* UEC MIIMCFG (MII Management Configuration Register)
+ */
+#define MIIMCFG_RESET_MANAGEMENT 0x80000000
+#define MIIMCFG_NO_PREAMBLE 0x00000010
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31)
+#define MIIMCFG_CLOCK_DIVIDE_MASK 0x0000000f
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007
+
+#define MIIMCFG_MNGMNT_CLC_DIV_INIT_VALUE \
+ MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10
+
+/* UEC MIIMCOM (MII Management Command Register)
+ */
+#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */
+#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */
+
+/* UEC MIIMADD (MII Management Address Register)
+ */
+#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23)
+#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31)
+
+/* UEC MIIMCON (MII Management Control Register)
+ */
+#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31)
+#define MIIMCON_PHY_STATUS_SHIFT (31 - 31)
+
+/* UEC MIIMIND (MII Management Indicator Register)
+ */
+#define MIIMIND_NOT_VALID 0x00000004
+#define MIIMIND_SCAN 0x00000002
+#define MIIMIND_BUSY 0x00000001
+
+/* UEC UTBIPAR (Ten Bit Interface Physical Address Register)
+ */
+#define UTBIPAR_PHY_ADDRESS_SHIFT (31 - 31)
+#define UTBIPAR_PHY_ADDRESS_MASK 0x0000001f
+
+/* UEC UESCR (Ethernet Statistics Control Register)
+ */
+#define UESCR_AUTOZ 0x8000
+#define UESCR_CLRCNT 0x4000
+#define UESCR_MAXCOV_SHIFT (15 - 7)
+#define UESCR_SCOV_SHIFT (15 - 15)
+
+/****** Tx data struct collection ******/
+/* Tx thread data, each Tx thread has one this struct. */
+struct uec_thread_data_tx {
+ u8 res0[136];
+} __packed;
+
+/* Tx thread parameter, each Tx thread has one this struct. */
+struct uec_thread_tx_pram {
+ u8 res0[64];
+} __packed;
+
+/* Send queue queue-descriptor, each Tx queue has one this QD */
+struct uec_send_queue_qd {
+ u32 bd_ring_base; /* pointer to BD ring base address */
+ u8 res0[0x8];
+ u32 last_bd_completed_address; /* last entry in BD ring */
+ u8 res1[0x30];
+} __packed;
+
+/* Send queue memory region */
+struct uec_send_queue_mem_region {
+ struct uec_send_queue_qd sqqd[MAX_TX_QUEUES];
+} __packed;
+
+/* Scheduler struct */
+struct uec_scheduler {
+ u16 cpucount0; /* CPU packet counter */
+ u16 cpucount1; /* CPU packet counter */
+ u16 cecount0; /* QE packet counter */
+ u16 cecount1; /* QE packet counter */
+ u16 cpucount2; /* CPU packet counter */
+ u16 cpucount3; /* CPU packet counter */
+ u16 cecount2; /* QE packet counter */
+ u16 cecount3; /* QE packet counter */
+ u16 cpucount4; /* CPU packet counter */
+ u16 cpucount5; /* CPU packet counter */
+ u16 cecount4; /* QE packet counter */
+ u16 cecount5; /* QE packet counter */
+ u16 cpucount6; /* CPU packet counter */
+ u16 cpucount7; /* CPU packet counter */
+ u16 cecount6; /* QE packet counter */
+ u16 cecount7; /* QE packet counter */
+ u32 weightstatus[MAX_TX_QUEUES]; /* accumulated weight factor */
+ u32 rtsrshadow; /* temporary variable handled by QE */
+ u32 time; /* temporary variable handled by QE */
+ u32 ttl; /* temporary variable handled by QE */
+ u32 mblinterval; /* max burst length interval */
+ u16 nortsrbytetime; /* normalized value of byte time in tsr units */
+ u8 fracsiz;
+ u8 res0[1];
+ u8 strictpriorityq; /* Strict Priority Mask register */
+ u8 txasap; /* Transmit ASAP register */
+ u8 extrabw; /* Extra BandWidth register */
+ u8 oldwfqmask; /* temporary variable handled by QE */
+ u8 weightfactor[MAX_TX_QUEUES]; /**< weight factor for queues */
+ u32 minw; /* temporary variable handled by QE */
+ u8 res1[0x70 - 0x64];
+} __packed;
+
+/* Tx firmware counters */
+struct uec_tx_firmware_statistics_pram {
+ u32 sicoltx; /* single collision */
+ u32 mulcoltx; /* multiple collision */
+ u32 latecoltxfr; /* late collision */
+ u32 frabortduecol; /* frames aborted due to tx collision */
+ u32 frlostinmactxer; /* frames lost due to internal MAC error tx */
+ u32 carriersenseertx; /* carrier sense error */
+ u32 frtxok; /* frames transmitted OK */
+ u32 txfrexcessivedefer;
+ u32 txpkts256; /* total packets(including bad) 256~511 B */
+ u32 txpkts512; /* total packets(including bad) 512~1023B */
+ u32 txpkts1024; /* total packets(including bad) 1024~1518B */
+ u32 txpktsjumbo; /* total packets(including bad) >1024 */
+} __packed;
+
+/* Tx global parameter table */
+struct uec_tx_global_pram {
+ u16 temoder;
+ u8 res0[0x38 - 0x02];
+ u32 sqptr;
+ u32 schedulerbasepointer;
+ u32 txrmonbaseptr;
+ u32 tstate;
+ u8 iphoffset[MAX_IPH_OFFSET_ENTRY];
+ u32 vtagtable[0x8];
+ u32 tqptr;
+ u8 res2[0x80 - 0x74];
+} __packed;
+
+/****** Rx data struct collection ******/
+/* Rx thread data, each Rx thread has one this struct. */
+struct uec_thread_data_rx {
+ u8 res0[40];
+} __packed;
+
+/* Rx thread parameter, each Rx thread has one this struct. */
+struct uec_thread_rx_pram {
+ u8 res0[128];
+} __packed;
+
+/* Rx firmware counters */
+struct uec_rx_firmware_statistics_pram {
+ u32 frrxfcser; /* frames with crc error */
+ u32 fraligner; /* frames with alignment error */
+ u32 inrangelenrxer; /* in range length error */
+ u32 outrangelenrxer; /* out of range length error */
+ u32 frtoolong; /* frame too long */
+ u32 runt; /* runt */
+ u32 verylongevent; /* very long event */
+ u32 symbolerror; /* symbol error */
+ u32 dropbsy; /* drop because of BD not ready */
+ u8 res0[0x8];
+ u32 mismatchdrop; /* drop because of MAC filtering */
+ u32 underpkts; /* total frames less than 64 octets */
+ u32 pkts256; /* total frames(including bad)256~511 B */
+ u32 pkts512; /* total frames(including bad)512~1023 B */
+ u32 pkts1024; /* total frames(including bad)1024~1518 B */
+ u32 pktsjumbo; /* total frames(including bad) >1024 B */
+ u32 frlossinmacer;
+ u32 pausefr; /* pause frames */
+ u8 res1[0x4];
+ u32 removevlan;
+ u32 replacevlan;
+ u32 insertvlan;
+} __packed;
+
+/* Rx interrupt coalescing entry, each Rx queue has one this entry. */
+struct uec_rx_interrupt_coalescing_entry {
+ u32 maxvalue;
+ u32 counter;
+} __packed;
+
+struct uec_rx_interrupt_coalescing_table {
+ struct uec_rx_interrupt_coalescing_entry entry[MAX_RX_QUEUES];
+} __packed;
+
+/* RxBD queue entry, each Rx queue has one this entry. */
+struct uec_rx_bd_queues_entry {
+ u32 bdbaseptr; /* BD base pointer */
+ u32 bdptr; /* BD pointer */
+ u32 externalbdbaseptr; /* external BD base pointer */
+ u32 externalbdptr; /* external BD pointer */
+} __packed;
+
+/* Rx global parameter table */
+struct uec_rx_global_pram {
+ u32 remoder; /* ethernet mode reg. */
+ u32 rqptr; /* base pointer to the Rx Queues */
+ u32 res0[0x1];
+ u8 res1[0x20 - 0xc];
+ u16 typeorlen;
+ u8 res2[0x1];
+ u8 rxgstpack; /* ack on GRACEFUL STOP RX command */
+ u32 rxrmonbaseptr; /* Rx RMON statistics base */
+ u8 res3[0x30 - 0x28];
+ u32 intcoalescingptr; /* Interrupt coalescing table pointer */
+ u8 res4[0x36 - 0x34];
+ u8 rstate;
+ u8 res5[0x46 - 0x37];
+ u16 mrblr; /* max receive buffer length reg. */
+ u32 rbdqptr; /* RxBD parameter table description */
+ u16 mflr; /* max frame length reg. */
+ u16 minflr; /* min frame length reg. */
+ u16 maxd1; /* max dma1 length reg. */
+ u16 maxd2; /* max dma2 length reg. */
+ u32 ecamptr; /* external CAM address */
+ u32 l2qt; /* VLAN priority mapping table. */
+ u32 l3qt[0x8]; /* IP priority mapping table. */
+ u16 vlantype; /* vlan type */
+ u16 vlantci; /* default vlan tci */
+ u8 addressfiltering[64];/* address filtering data structure */
+ u32 exf_global_param; /* extended filtering global parameters */
+ u8 res6[0x100 - 0xc4]; /* Initialize to zero */
+} __packed;
+
+#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01
+
+/****** UEC common ******/
+/* UCC statistics - hardware counters */
+struct uec_hardware_statistics {
+ u32 tx64;
+ u32 tx127;
+ u32 tx255;
+ u32 rx64;
+ u32 rx127;
+ u32 rx255;
+ u32 txok;
+ u16 txcf;
+ u32 tmca;
+ u32 tbca;
+ u32 rxfok;
+ u32 rxbok;
+ u32 rbyt;
+ u32 rmca;
+ u32 rbca;
+} __packed;
+
+/* InitEnet command parameter */
+struct uec_init_cmd_pram {
+ u8 resinit0;
+ u8 resinit1;
+ u8 resinit2;
+ u8 resinit3;
+ u16 resinit4;
+ u8 res1[0x1];
+ u8 largestexternallookupkeysize;
+ u32 rgftgfrxglobal;
+ u32 rxthread[MAX_ENET_INIT_PARAM_ENTRIES_RX]; /* rx threads */
+ u8 res2[0x38 - 0x30];
+ u32 txglobal; /* tx global */
+ u32 txthread[MAX_ENET_INIT_PARAM_ENTRIES_TX]; /* tx threads */
+ u8 res3[0x1];
+} __packed;
+
+#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4)
+#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8)
+
+#define ENET_INIT_PARAM_RISC_MASK 0x0000003f
+#define ENET_INIT_PARAM_PTR_MASK 0x00ffffc0
+#define ENET_INIT_PARAM_SNUM_MASK 0xff000000
+#define ENET_INIT_PARAM_SNUM_SHIFT 24
+
+#define ENET_INIT_PARAM_MAGIC_RES_INIT0 0x06
+#define ENET_INIT_PARAM_MAGIC_RES_INIT1 0x30
+#define ENET_INIT_PARAM_MAGIC_RES_INIT2 0xff
+#define ENET_INIT_PARAM_MAGIC_RES_INIT3 0x00
+#define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x0400
+
+/* structure representing 82xx Address Filtering Enet Address in PRAM */
+struct uec_82xx_enet_addr {
+ u8 res1[0x2];
+ u16 h; /* address (MSB) */
+ u16 m; /* address */
+ u16 l; /* address (LSB) */
+} __packed;
+
+/* structure representing 82xx Address Filtering PRAM */
+struct uec_82xx_add_filtering_pram {
+ u32 iaddr_h; /* individual address filter, high */
+ u32 iaddr_l; /* individual address filter, low */
+ u32 gaddr_h; /* group address filter, high */
+ u32 gaddr_l; /* group address filter, low */
+ struct uec_82xx_enet_addr taddr;
+ struct uec_82xx_enet_addr paddr[4];
+ u8 res0[0x40 - 0x38];
+} __packed;
+
+/* Buffer Descriptor */
+struct buffer_descriptor {
+ u16 status;
+ u16 len;
+ u32 data;
+} __packed;
+
+#define SIZEOFBD sizeof(struct buffer_descriptor)
+
+/* Common BD flags */
+#define BD_WRAP 0x2000
+#define BD_INT 0x1000
+#define BD_LAST 0x0800
+#define BD_CLEAN 0x3000
+
+/* TxBD status flags */
+#define TX_BD_READY 0x8000
+#define TX_BD_PADCRC 0x4000
+#define TX_BD_WRAP BD_WRAP
+#define TX_BD_INT BD_INT
+#define TX_BD_LAST BD_LAST
+#define TX_BD_TXCRC 0x0400
+#define TX_BD_DEF 0x0200
+#define TX_BD_PP 0x0100
+#define TX_BD_LC 0x0080
+#define TX_BD_RL 0x0040
+#define TX_BD_RC 0x003C
+#define TX_BD_UNDERRUN 0x0002
+#define TX_BD_TRUNC 0x0001
+
+#define TX_BD_ERROR (TX_BD_UNDERRUN | TX_BD_TRUNC)
+
+/* RxBD status flags */
+#define RX_BD_EMPTY 0x8000
+#define RX_BD_OWNER 0x4000
+#define RX_BD_WRAP BD_WRAP
+#define RX_BD_INT BD_INT
+#define RX_BD_LAST BD_LAST
+#define RX_BD_FIRST 0x0400
+#define RX_BD_CMR 0x0200
+#define RX_BD_MISS 0x0100
+#define RX_BD_BCAST 0x0080
+#define RX_BD_MCAST 0x0040
+#define RX_BD_LG 0x0020
+#define RX_BD_NO 0x0010
+#define RX_BD_SHORT 0x0008
+#define RX_BD_CRCERR 0x0004
+#define RX_BD_OVERRUN 0x0002
+#define RX_BD_IPCH 0x0001
+
+#define RX_BD_ERROR (RX_BD_LG | RX_BD_NO | RX_BD_SHORT | \
+ RX_BD_CRCERR | RX_BD_OVERRUN)
+
+/* BD access macros */
+#define BD_STATUS(_bd) (in_be16(&((_bd)->status)))
+#define BD_STATUS_SET(_bd, _v) (out_be16(&((_bd)->status), _v))
+#define BD_LENGTH(_bd) (in_be16(&((_bd)->len)))
+#define BD_LENGTH_SET(_bd, _v) (out_be16(&((_bd)->len), _v))
+#define BD_DATA_CLEAR(_bd) (out_be32(&((_bd)->data), 0))
+#define BD_DATA(_bd) ((u8 *)(((_bd)->data)))
+#define BD_DATA_SET(_bd, _data) (out_be32(&((_bd)->data), (u32)_data))
+#define BD_ADVANCE(_bd, _status, _base) \
+ (((_status) & BD_WRAP) ? (_bd) = \
+ ((struct buffer_descriptor *)(_base)) : ++(_bd))
+
+/* Rx Prefetched BDs */
+struct uec_rx_pref_bds {
+ struct buffer_descriptor bd[MAX_PREFETCHED_BDS]; /* prefetched bd */
+} __packed;
+
+/* Alignments */
+#define UEC_RX_GLOBAL_PRAM_ALIGNMENT 64
+#define UEC_TX_GLOBAL_PRAM_ALIGNMENT 64
+#define UEC_THREAD_RX_PRAM_ALIGNMENT 128
+#define UEC_THREAD_TX_PRAM_ALIGNMENT 64
+#define UEC_THREAD_DATA_ALIGNMENT 256
+#define UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT 32
+#define UEC_SCHEDULER_ALIGNMENT 4
+#define UEC_TX_STATISTICS_ALIGNMENT 4
+#define UEC_RX_STATISTICS_ALIGNMENT 4
+#define UEC_RX_INTERRUPT_COALESCING_ALIGNMENT 4
+#define UEC_RX_BD_QUEUES_ALIGNMENT 8
+#define UEC_RX_PREFETCHED_BDS_ALIGNMENT 128
+#define UEC_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4
+#define UEC_RX_BD_RING_ALIGNMENT 32
+#define UEC_TX_BD_RING_ALIGNMENT 32
+#define UEC_MRBLR_ALIGNMENT 128
+#define UEC_RX_BD_RING_SIZE_ALIGNMENT 4
+#define UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT 32
+#define UEC_RX_DATA_BUF_ALIGNMENT 64
+
+#define UEC_VLAN_PRIORITY_MAX 8
+#define UEC_IP_PRIORITY_MAX 64
+#define UEC_TX_VTAG_TABLE_ENTRY_MAX 8
+#define UEC_RX_BD_RING_SIZE_MIN 8
+#define UEC_TX_BD_RING_SIZE_MIN 2
+
+/* TBI / MII Set Register */
+enum enet_tbi_mii_reg {
+ ENET_TBI_MII_CR = 0x00,
+ ENET_TBI_MII_SR = 0x01,
+ ENET_TBI_MII_ANA = 0x04,
+ ENET_TBI_MII_ANLPBPA = 0x05,
+ ENET_TBI_MII_ANEX = 0x06,
+ ENET_TBI_MII_ANNPT = 0x07,
+ ENET_TBI_MII_ANLPANP = 0x08,
+ ENET_TBI_MII_EXST = 0x0F,
+ ENET_TBI_MII_JD = 0x10,
+ ENET_TBI_MII_TBICON = 0x11
+};
+
+/* TBI MDIO register bit fields*/
+#define TBICON_CLK_SELECT 0x0020
+#define TBIANA_ASYMMETRIC_PAUSE 0x0100
+#define TBIANA_SYMMETRIC_PAUSE 0x0080
+#define TBIANA_HALF_DUPLEX 0x0040
+#define TBIANA_FULL_DUPLEX 0x0020
+#define TBICR_PHY_RESET 0x8000
+#define TBICR_ANEG_ENABLE 0x1000
+#define TBICR_RESTART_ANEG 0x0200
+#define TBICR_FULL_DUPLEX 0x0100
+#define TBICR_SPEED1_SET 0x0040
+
+#define TBIANA_SETTINGS ( \
+ TBIANA_ASYMMETRIC_PAUSE \
+ | TBIANA_SYMMETRIC_PAUSE \
+ | TBIANA_FULL_DUPLEX \
+ )
+
+#define TBICR_SETTINGS ( \
+ TBICR_PHY_RESET \
+ | TBICR_ANEG_ENABLE \
+ | TBICR_FULL_DUPLEX \
+ | TBICR_SPEED1_SET \
+ )
+
+/* UEC number of threads */
+enum uec_num_of_threads {
+ UEC_NUM_OF_THREADS_1 = 0x1, /* 1 */
+ UEC_NUM_OF_THREADS_2 = 0x2, /* 2 */
+ UEC_NUM_OF_THREADS_4 = 0x0, /* 4 */
+ UEC_NUM_OF_THREADS_6 = 0x3, /* 6 */
+ UEC_NUM_OF_THREADS_8 = 0x4 /* 8 */
+};
+
+/* UEC initialization info struct */
+#define STD_UEC_INFO(num) \
+{ \
+ .uf_info = { \
+ .ucc_num = CONFIG_SYS_UEC##num##_UCC_NUM,\
+ .rx_clock = CONFIG_SYS_UEC##num##_RX_CLK, \
+ .tx_clock = CONFIG_SYS_UEC##num##_TX_CLK, \
+ .eth_type = CONFIG_SYS_UEC##num##_ETH_TYPE,\
+ }, \
+ .num_threads_tx = UEC_NUM_OF_THREADS_1, \
+ .num_threads_rx = UEC_NUM_OF_THREADS_1, \
+ .risc_tx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, \
+ .risc_rx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, \
+ .tx_bd_ring_len = 16, \
+ .rx_bd_ring_len = 16, \
+ .phy_address = CONFIG_SYS_UEC##num##_PHY_ADDR, \
+ .enet_interface_type = CONFIG_SYS_UEC##num##_INTERFACE_TYPE, \
+ .speed = CONFIG_SYS_UEC##num##_INTERFACE_SPEED, \
+}
+
+struct uec_inf {
+ struct ucc_fast_inf uf_info;
+ enum uec_num_of_threads num_threads_tx;
+ enum uec_num_of_threads num_threads_rx;
+ unsigned int risc_tx;
+ unsigned int risc_rx;
+ u16 rx_bd_ring_len;
+ u16 tx_bd_ring_len;
+ u8 phy_address;
+ phy_interface_t enet_interface_type;
+ int speed;
+};
+
+/* UEC driver initialized info */
+#define MAX_RXBUF_LEN 1536
+#define MAX_FRAME_LEN 1518
+#define MIN_FRAME_LEN 64
+#define MAX_DMA1_LEN 1520
+#define MAX_DMA2_LEN 1520
+
+/* UEC driver private struct */
+struct uec_priv {
+ struct uec_inf *uec_info;
+ struct ucc_fast_priv *uccf;
+ struct eth_device *dev;
+ uec_t *uec_regs;
+ /* enet init command parameter */
+ struct uec_init_cmd_pram *p_init_enet_param;
+ u32 init_enet_param_offset;
+ /* Rx and Tx parameter */
+ struct uec_rx_global_pram *p_rx_glbl_pram;
+ u32 rx_glbl_pram_offset;
+ struct uec_tx_global_pram *p_tx_glbl_pram;
+ u32 tx_glbl_pram_offset;
+ struct uec_send_queue_mem_region *p_send_q_mem_reg;
+ u32 send_q_mem_reg_offset;
+ struct uec_thread_data_tx *p_thread_data_tx;
+ u32 thread_dat_tx_offset;
+ struct uec_thread_data_rx *p_thread_data_rx;
+ u32 thread_dat_rx_offset;
+ struct uec_rx_bd_queues_entry *p_rx_bd_qs_tbl;
+ u32 rx_bd_qs_tbl_offset;
+ /* BDs specific */
+ u8 *p_tx_bd_ring;
+ u32 tx_bd_ring_offset;
+ u8 *p_rx_bd_ring;
+ u32 rx_bd_ring_offset;
+ u8 *p_rx_buf;
+ u32 rx_buf_offset;
+ struct buffer_descriptor *tx_bd;
+ struct buffer_descriptor *rx_bd;
+ /* Status */
+ int mac_tx_enabled;
+ int mac_rx_enabled;
+ int grace_stopped_tx;
+ int grace_stopped_rx;
+ int the_first_run;
+#if !defined(COFIG_DM)
+ /* PHY specific */
+ struct uec_mii_info *mii_info;
+ int oldspeed;
+ int oldduplex;
+ int oldlink;
+#endif
+};
+
+int uec_initialize(struct bd_info *bis, struct uec_inf *uec_info);
+int uec_eth_init(struct bd_info *bis, struct uec_inf *uecs, int num);
+int uec_standard_init(struct bd_info *bis);
+#endif /* __UEC_H__ */
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c
index 886f53ee82..98883cd15b 100644
--- a/drivers/net/ravb.c
+++ b/drivers/net/ravb.c
@@ -438,8 +438,6 @@ static int ravb_config(struct udevice *dev)
writel(mask, eth->iobase + RAVB_REG_ECMR);
- phy->drv->writeext(phy, -1, 0x02, 0x08, (0x0f << 5) | 0x19);
-
return 0;
}
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 546cc6ccb6..1dae81c7bf 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -663,7 +663,8 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev)
return _sun8i_write_hwaddr(priv, pdata->enetaddr);
}
-static int sun8i_emac_board_setup(struct emac_eth_dev *priv)
+static int sun8i_emac_board_setup(struct udevice *dev,
+ struct emac_eth_dev *priv)
{
int ret;
@@ -833,7 +834,7 @@ static int sun8i_emac_eth_probe(struct udevice *dev)
priv->mac_reg = (void *)pdata->iobase;
- ret = sun8i_emac_board_setup(priv);
+ ret = sun8i_emac_board_setup(dev, priv);
if (ret)
return ret;
@@ -854,7 +855,7 @@ static const struct eth_ops sun8i_emac_eth_ops = {
.stop = sun8i_emac_eth_stop,
};
-static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv)
+static int sun8i_get_ephy_nodes(struct udevice *dev, struct emac_eth_dev *priv)
{
int emac_node, ephy_node, ret, ephy_handle;
@@ -986,7 +987,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
}
if (priv->variant == H3_EMAC) {
- ret = sun8i_get_ephy_nodes(priv);
+ ret = sun8i_get_ephy_nodes(dev, priv);
if (ret)
return ret;
}
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index df18ecc064..8e66ce2461 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -505,7 +505,8 @@ static int _sunxi_emac_eth_send(struct emac_eth_dev *priv, void *packet,
return 0;
}
-static int sunxi_emac_board_setup(struct emac_eth_dev *priv)
+static int sunxi_emac_board_setup(struct udevice *dev,
+ struct emac_eth_dev *priv)
{
struct sunxi_sramc_regs *sram =
(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
@@ -576,7 +577,7 @@ static int sunxi_emac_eth_probe(struct udevice *dev)
return ret;
}
- ret = sunxi_emac_board_setup(priv);
+ ret = sunxi_emac_board_setup(dev, priv);
if (ret)
return ret;
diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c
index d6fefe5306..1c11257839 100644
--- a/drivers/net/ti/cpsw.c
+++ b/drivers/net/ti/cpsw.c
@@ -856,8 +856,14 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave)
ret = phy_set_supported(phydev, slave->data->max_speed);
if (ret)
return ret;
+#if CONFIG_IS_ENABLED(DM_ETH)
dev_dbg(priv->dev, "Port %u speed forced to %uMbit\n",
slave->slave_num + 1, slave->data->max_speed);
+#else
+ log_debug("%s: Port %u speed forced to %uMbit\n",
+ priv->dev->name, slave->slave_num + 1,
+ slave->data->max_speed);
+#endif
}
phydev->advertising = phydev->supported;
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 5d12e4b775..c436b8317d 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -18,6 +18,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <miiphy.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -681,8 +682,15 @@ static int init_phy(struct tsec_private *priv)
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
tsec_configure_serdes(priv);
+#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_MDIO)
+ if (ofnode_valid(ofnode_find_subnode(priv->dev->node, "fixed-link")))
+ phydev = phy_connect(NULL, 0, priv->dev, priv->interface);
+ else
+ phydev = dm_eth_phy_connect(priv->dev);
+#else
phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
priv->interface);
+#endif
if (!phydev)
return 0;
@@ -793,43 +801,19 @@ int tsec_probe(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct tsec_private *priv = dev_get_priv(dev);
- struct tsec_mii_mng __iomem *ext_phyregs_mii;
struct ofnode_phandle_args phandle_args;
u32 tbiaddr = CONFIG_SYS_TBIPA_VALUE;
- struct fsl_pq_mdio_info mdio_info;
+ struct tsec_data *data;
const char *phy_mode;
fdt_addr_t reg;
ofnode parent;
int ret;
+ data = (struct tsec_data *)dev_get_driver_data(dev);
+
pdata->iobase = (phys_addr_t)dev_read_addr(dev);
priv->regs = dev_remap_addr(dev);
- if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
- &phandle_args)) {
- printf("phy-handle does not exist under tsec %s\n", dev->name);
- return -ENOENT;
- } else {
- int reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
-
- priv->phyaddr = reg;
- }
-
- parent = ofnode_get_parent(phandle_args.node);
- if (!ofnode_valid(parent)) {
- printf("No parent node for PHY?\n");
- return -ENOENT;
- }
-
- reg = ofnode_get_addr_index(parent, 0);
- if (reg == FDT_ADDR_T_NONE) {
- printf("No 'reg' property of MII for external PHY\n");
- return -ENOENT;
- }
-
- ext_phyregs_mii = map_physmem(reg + TSEC_MDIO_REGS_OFFSET, 0,
- MAP_NOCACHE);
-
ret = dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
&phandle_args);
if (ret == 0) {
@@ -847,7 +831,7 @@ int tsec_probe(struct udevice *dev)
return -ENOENT;
}
- priv->phyregs_sgmii = map_physmem(reg + TSEC_MDIO_REGS_OFFSET,
+ priv->phyregs_sgmii = map_physmem(reg + data->mdio_regs_off,
0, MAP_NOCACHE);
}
@@ -867,12 +851,6 @@ int tsec_probe(struct udevice *dev)
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
priv->flags |= TSEC_SGMII;
- mdio_info.regs = ext_phyregs_mii;
- mdio_info.name = (char *)dev->name;
- ret = fsl_pq_mdio_init(NULL, &mdio_info);
- if (ret)
- return ret;
-
/* Reset the MAC */
setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
@@ -905,8 +883,17 @@ static const struct eth_ops tsec_ops = {
.mcast = tsec_mcast_addr,
};
+static struct tsec_data etsec2_data = {
+ .mdio_regs_off = TSEC_MDIO_REGS_OFFSET,
+};
+
+static struct tsec_data gianfar_data = {
+ .mdio_regs_off = 0x0,
+};
+
static const struct udevice_id tsec_ids[] = {
- { .compatible = "fsl,etsec2" },
+ { .compatible = "fsl,etsec2", .data = (ulong)&etsec2_data },
+ { .compatible = "gianfar", .data = (ulong)&gianfar_data },
{ }
};
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c
index 99d4d85c52..8af3711204 100644
--- a/drivers/net/xilinx_axi_emac.c
+++ b/drivers/net/xilinx_axi_emac.c
@@ -101,10 +101,10 @@ struct axidma_priv {
/* BD descriptors */
struct axidma_bd {
- u32 next; /* Next descriptor pointer */
- u32 reserved1;
- u32 phys; /* Buffer address */
- u32 reserved2;
+ u32 next_desc; /* Next descriptor pointer */
+ u32 next_desc_msb;
+ u32 buf_addr; /* Buffer address */
+ u32 buf_addr_msb;
u32 reserved3;
u32 reserved4;
u32 cntrl; /* Control */
@@ -182,7 +182,7 @@ static inline int mdio_wait(struct axi_regs *regs)
static inline void axienet_dma_write(struct axidma_bd *bd, u32 *desc)
{
#if defined(CONFIG_PHYS_64BIT)
- writeq(bd, desc);
+ writeq((unsigned long)bd, desc);
#else
writel((u32)bd, desc);
#endif
@@ -492,15 +492,19 @@ static int axiemac_start(struct udevice *dev)
/* Setup the BD. */
memset(&rx_bd, 0, sizeof(rx_bd));
- rx_bd.next = (u32)&rx_bd;
- rx_bd.phys = (u32)&rxframe;
+ rx_bd.next_desc = lower_32_bits((unsigned long)&rx_bd);
+ rx_bd.buf_addr = lower_32_bits((unsigned long)&rxframe);
+#if defined(CONFIG_PHYS_64BIT)
+ rx_bd.next_desc_msb = upper_32_bits((unsigned long)&rx_bd);
+ rx_bd.buf_addr_msb = upper_32_bits((unsigned long)&rxframe);
+#endif
rx_bd.cntrl = sizeof(rxframe);
/* Flush the last BD so DMA core could see the updates */
- flush_cache((u32)&rx_bd, sizeof(rx_bd));
+ flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd));
/* It is necessary to flush rxframe because if you don't do it
* then cache can contain uninitialized data */
- flush_cache((u32)&rxframe, sizeof(rxframe));
+ flush_cache((phys_addr_t)&rxframe, sizeof(rxframe));
/* Start the hardware */
temp = readl(&priv->dmarx->control);
@@ -534,19 +538,23 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len)
len = PKTSIZE_ALIGN;
/* Flush packet to main memory to be trasfered by DMA */
- flush_cache((u32)ptr, len);
+ flush_cache((phys_addr_t)ptr, len);
/* Setup Tx BD */
memset(&tx_bd, 0, sizeof(tx_bd));
/* At the end of the ring, link the last BD back to the top */
- tx_bd.next = (u32)&tx_bd;
- tx_bd.phys = (u32)ptr;
+ tx_bd.next_desc = lower_32_bits((unsigned long)&tx_bd);
+ tx_bd.buf_addr = lower_32_bits((unsigned long)ptr);
+#if defined(CONFIG_PHYS_64BIT)
+ tx_bd.next_desc_msb = upper_32_bits((unsigned long)&tx_bd);
+ tx_bd.buf_addr_msb = upper_32_bits((unsigned long)ptr);
+#endif
/* Save len */
tx_bd.cntrl = len | XAXIDMA_BD_CTRL_TXSOF_MASK |
XAXIDMA_BD_CTRL_TXEOF_MASK;
/* Flush the last BD so DMA core could see the updates */
- flush_cache((u32)&tx_bd, sizeof(tx_bd));
+ flush_cache((phys_addr_t)&tx_bd, sizeof(tx_bd));
if (readl(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) {
u32 temp;
@@ -637,16 +645,20 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length)
/* Setup RxBD */
/* Clear the whole buffer and setup it again - all flags are cleared */
memset(&rx_bd, 0, sizeof(rx_bd));
- rx_bd.next = (u32)&rx_bd;
- rx_bd.phys = (u32)&rxframe;
+ rx_bd.next_desc = lower_32_bits((unsigned long)&rx_bd);
+ rx_bd.buf_addr = lower_32_bits((unsigned long)&rxframe);
+#if defined(CONFIG_PHYS_64BIT)
+ rx_bd.next_desc_msb = upper_32_bits((unsigned long)&rx_bd);
+ rx_bd.buf_addr_msb = upper_32_bits((unsigned long)&rxframe);
+#endif
rx_bd.cntrl = sizeof(rxframe);
/* Write bd to HW */
- flush_cache((u32)&rx_bd, sizeof(rx_bd));
+ flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd));
/* It is necessary to flush rxframe because if you don't do it
* then cache will contain previous packet */
- flush_cache((u32)&rxframe, sizeof(rxframe));
+ flush_cache((phys_addr_t)&rxframe, sizeof(rxframe));
/* Rx BD is ready - start again */
axienet_dma_write(&rx_bd, &priv->dmarx->tail);
@@ -738,7 +750,7 @@ static int axi_emac_ofdata_to_platdata(struct udevice *dev)
return -EINVAL;
}
/* RX channel offset is 0x30 */
- priv->dmarx = (struct axidma_reg *)((u32)priv->dmatx + 0x30);
+ priv->dmarx = (struct axidma_reg *)((phys_addr_t)priv->dmatx + 0x30);
priv->phyaddr = -1;
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index da4b6fba9f..8afec8bbfc 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -758,6 +758,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
if (!dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
&phandle_args)) {
+ fdt_addr_t addr;
+ ofnode parent;
+
debug("phy-handle does exist %s\n", dev->name);
priv->phyaddr = ofnode_read_u32_default(phandle_args.node,
"reg", -1);
@@ -765,6 +768,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
priv->max_speed = ofnode_read_u32_default(phandle_args.node,
"max-speed",
SPEED_1000);
+
+ parent = ofnode_get_parent(phandle_args.node);
+ addr = ofnode_get_addr(parent);
+ if (addr != FDT_ADDR_T_NONE) {
+ debug("MDIO bus not found %s\n", dev->name);
+ priv->mdiobase = (struct zynq_gem_regs *)addr;
+ }
}
phy_mode = dev_read_prop(dev, "phy-mode", NULL);
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index d8a6647a1d..eb07d25301 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -911,8 +911,8 @@ static void decode_regions(struct pci_controller *hose, ofnode parent_node,
ofnode node)
{
int pci_addr_cells, addr_cells, size_cells;
- struct bd_info *bd = gd->bd;
int cells_per_record;
+ struct bd_info *bd;
const u32 *prop;
int max_regions;
int len;
@@ -989,6 +989,7 @@ static void decode_regions(struct pci_controller *hose, ofnode parent_node,
}
/* Add a region for our local memory */
+ bd = gd->bd;
if (!bd)
return;
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 9c775107e9..d66aa07392 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -84,6 +84,13 @@ config BCM6368_USBH_PHY
help
Support for the Broadcom MIPS BCM6368 USBH PHY.
+config BCM_SR_PCIE_PHY
+ bool "Broadcom Stingray PCIe PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Broadcom Stingray PCIe PHY
+ If unsure, say N.
+
config PHY_DA8XX_USB
tristate "TI DA8xx USB PHY Driver"
depends on PHY && ARCH_DAVINCI
@@ -125,6 +132,12 @@ config STI_USB_PHY
used by USB2 and USB3 Host controllers available on
STiH407 SoC families.
+config PHY_QCOM_IPQ4019_USB
+ tristate "Qualcomm IPQ4019 USB PHY driver"
+ depends on PHY && ARCH_IPQ40XX
+ help
+ Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s.
+
config PHY_RCAR_GEN2
tristate "Renesas R-Car Gen2 USB PHY"
depends on PHY && RCAR_GEN2
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 74e8d931d3..8dabefd776 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -9,10 +9,12 @@ obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o
+obj-$(CONFIG_BCM_SR_PCIE_PHY) += phy-bcm-sr-pcie.o
obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o
obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o
obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o
obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o
+obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_PHY_RCAR_GEN3) += phy-rcar-gen3.o
obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index f050645044..7b9d3eefc5 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -272,13 +272,15 @@ static int sun4i_usb_phy_init(struct phy *phy)
ret = clk_enable(&usb_phy->clocks);
if (ret) {
- dev_err(dev, "failed to enable usb_%ldphy clock\n", phy->id);
+ dev_err(phy->dev, "failed to enable usb_%ldphy clock\n",
+ phy->id);
return ret;
}
ret = reset_deassert(&usb_phy->resets);
if (ret) {
- dev_err(dev, "failed to deassert usb_%ldreset reset\n", phy->id);
+ dev_err(phy->dev, "failed to deassert usb_%ldreset reset\n",
+ phy->id);
return ret;
}
@@ -338,13 +340,15 @@ static int sun4i_usb_phy_exit(struct phy *phy)
ret = clk_disable(&usb_phy->clocks);
if (ret) {
- dev_err(dev, "failed to disable usb_%ldphy clock\n", phy->id);
+ dev_err(phy->dev, "failed to disable usb_%ldphy clock\n",
+ phy->id);
return ret;
}
ret = reset_assert(&usb_phy->resets);
if (ret) {
- dev_err(dev, "failed to assert usb_%ldreset reset\n", phy->id);
+ dev_err(phy->dev, "failed to assert usb_%ldreset reset\n",
+ phy->id);
return ret;
}
diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c
index 27bff27ff7..5e8ce740cd 100644
--- a/drivers/phy/marvell/comphy_core.c
+++ b/drivers/phy/marvell/comphy_core.c
@@ -98,14 +98,14 @@ static int comphy_probe(struct udevice *dev)
chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node,
"max-lanes", 0);
if (chip_cfg->comphy_lanes_count <= 0) {
- dev_err(&dev->dev, "comphy max lanes is wrong\n");
+ dev_err(dev, "comphy max lanes is wrong\n");
return -EINVAL;
}
chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node,
"mux-bitcount", 0);
if (chip_cfg->comphy_mux_bitcount <= 0) {
- dev_err(&dev->dev, "comphy mux bit count is wrong\n");
+ dev_err(dev, "comphy mux bit count is wrong\n");
return -EINVAL;
}
@@ -124,7 +124,7 @@ static int comphy_probe(struct udevice *dev)
* compatible node is found
*/
if (!chip_cfg->ptr_comphy_chip_init) {
- dev_err(&dev->dev, "comphy: No compatible DT node found\n");
+ dev_err(dev, "comphy: No compatible DT node found\n");
return -ENODEV;
}
diff --git a/drivers/phy/phy-bcm-sr-pcie.c b/drivers/phy/phy-bcm-sr-pcie.c
new file mode 100644
index 0000000000..36c77c4b63
--- /dev/null
+++ b/drivers/phy/phy-bcm-sr-pcie.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Broadcom
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+/* we have up to 8 PAXB based RC. The 9th one is always PAXC */
+#define SR_NR_PCIE_PHYS 8
+
+#define PCIE_PIPEMUX_CFG_OFFSET 0x10c
+#define PCIE_PIPEMUX_SELECT_STRAP GENMASK(3, 0)
+
+#define CDRU_STRAP_DATA_LSW_OFFSET 0x5c
+#define PCIE_PIPEMUX_SHIFT 19
+#define PCIE_PIPEMUX_MASK GENMASK(3, 0)
+
+/**
+ * struct sr_pcie_phy_core - Stingray PCIe PHY core control
+ *
+ * @dev: pointer to device
+ * @base: base register of PCIe SS
+ * @cdru: CDRU base address
+ * @pipemux: pipemuex strap
+ */
+struct sr_pcie_phy_core {
+ struct udevice *dev;
+ void __iomem *base;
+ void __iomem *cdru;
+ u32 pipemux;
+};
+
+/*
+ * PCIe PIPEMUX lookup table
+ *
+ * Each array index represents a PIPEMUX strap setting
+ * The array element represents a bitmap where a set bit means the PCIe
+ * core and associated serdes has been enabled as RC and is available for use
+ */
+static const u8 pipemux_table[] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ 0x00,
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ 0x80,
+ /* PIPEMUX = 2, EP 4x4 */
+ 0x00,
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ 0x81,
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ 0xc3,
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ 0xff,
+ /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+ 0xcd,
+ /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+ 0xfd,
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+ 0xf0,
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+ 0xc0,
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+ 0x42,
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+ 0x3c,
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+ 0xfc,
+ /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+ 0x4c,
+};
+
+/*
+ * Return true if the strap setting is valid
+ */
+static bool pipemux_strap_is_valid(u32 pipemux)
+{
+ return !!(pipemux < ARRAY_SIZE(pipemux_table));
+}
+
+/*
+ * Read the PCIe PIPEMUX from strap
+ */
+static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
+{
+ u32 pipemux;
+
+ /*
+ * Read PIPEMUX configuration register to determine the pipemux setting
+ *
+ * In the case when the value indicates using HW strap, fall back to
+ * use HW strap
+ */
+ pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
+ pipemux &= PCIE_PIPEMUX_MASK;
+ if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
+ pipemux = readl(core->cdru + CDRU_STRAP_DATA_LSW_OFFSET);
+ pipemux >>= PCIE_PIPEMUX_SHIFT;
+ pipemux &= PCIE_PIPEMUX_MASK;
+ }
+
+ return pipemux;
+}
+
+static int sr_pcie_phy_init(struct phy *phy)
+{
+ struct sr_pcie_phy_core *core = dev_get_priv(phy->dev);
+ unsigned int core_idx = phy->id;
+
+ debug("%s %lx\n", __func__, phy->id);
+ /*
+ * Check whether this PHY is for root complex or not. If yes, return
+ * zero so the host driver can proceed to enumeration. If not, return
+ * an error and that will force the host driver to bail out
+ */
+ if (!!((pipemux_table[core->pipemux] >> core_idx) & 0x1))
+ return 0;
+
+ return -ENODEV;
+}
+
+static int sr_pcie_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ debug("%s %d\n", __func__, args->args[0]);
+ if (args->args_count && args->args[0] < SR_NR_PCIE_PHYS)
+ phy->id = args->args[0];
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct phy_ops sr_pcie_phy_ops = {
+ .of_xlate = sr_pcie_phy_xlate,
+ .init = sr_pcie_phy_init,
+};
+
+static int sr_pcie_phy_probe(struct udevice *dev)
+{
+ struct sr_pcie_phy_core *core = dev_get_priv(dev);
+
+ core->dev = dev;
+
+ core->base = (void __iomem *)devfdt_get_addr_name(dev, "reg_base");
+ core->cdru = (void __iomem *)devfdt_get_addr_name(dev, "cdru_base");
+ debug("ip base %p\n", core->base);
+ debug("cdru base %p\n", core->cdru);
+
+ /* read the PCIe PIPEMUX strap setting */
+ core->pipemux = pipemux_strap_read(core);
+ if (!pipemux_strap_is_valid(core->pipemux)) {
+ pr_err("invalid PCIe PIPEMUX strap %u\n", core->pipemux);
+ return -EIO;
+ }
+ debug("%s %#x\n", __func__, core->pipemux);
+
+ pr_info("Stingray PCIe PHY driver initialized\n");
+
+ return 0;
+}
+
+static const struct udevice_id sr_pcie_phy_match_table[] = {
+ { .compatible = "brcm,sr-pcie-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(sr_pcie_phy) = {
+ .name = "sr-pcie-phy",
+ .id = UCLASS_PHY,
+ .probe = sr_pcie_phy_probe,
+ .of_match = sr_pcie_phy_match_table,
+ .ops = &sr_pcie_phy_ops,
+ .platdata_auto_alloc_size = sizeof(struct sr_pcie_phy_core),
+ .priv_auto_alloc_size = sizeof(struct sr_pcie_phy_core),
+};
diff --git a/drivers/phy/phy-qcom-ipq4019-usb.c b/drivers/phy/phy-qcom-ipq4019-usb.c
new file mode 100644
index 0000000000..465f0d3a01
--- /dev/null
+++ b/drivers/phy/phy-qcom-ipq4019-usb.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ *
+ * Based on Linux driver
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <log.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+struct ipq4019_usb_phy {
+ phys_addr_t base;
+ struct reset_ctl por_rst;
+ struct reset_ctl srif_rst;
+};
+
+static int ipq4019_ss_phy_power_off(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ reset_assert(&phy->por_rst);
+ mdelay(10);
+
+ return 0;
+}
+
+static int ipq4019_ss_phy_power_on(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ ipq4019_ss_phy_power_off(_phy);
+
+ reset_deassert(&phy->por_rst);
+
+ return 0;
+}
+
+static struct phy_ops ipq4019_usb_ss_phy_ops = {
+ .power_on = ipq4019_ss_phy_power_on,
+ .power_off = ipq4019_ss_phy_power_off,
+};
+
+static int ipq4019_usb_ss_phy_probe(struct udevice *dev)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(dev);
+ int ret;
+
+ phy->base = dev_read_addr(dev);
+ if (phy->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = reset_get_by_name(dev, "por_rst", &phy->por_rst);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id ipq4019_usb_ss_phy_ids[] = {
+ { .compatible = "qcom,usb-ss-ipq4019-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(ipq4019_usb_ss_phy) = {
+ .name = "ipq4019-usb-ss-phy",
+ .id = UCLASS_PHY,
+ .of_match = ipq4019_usb_ss_phy_ids,
+ .ops = &ipq4019_usb_ss_phy_ops,
+ .probe = ipq4019_usb_ss_phy_probe,
+ .priv_auto_alloc_size = sizeof(struct ipq4019_usb_phy),
+};
+
+static int ipq4019_hs_phy_power_off(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ reset_assert(&phy->por_rst);
+ mdelay(10);
+
+ reset_assert(&phy->srif_rst);
+ mdelay(10);
+
+ return 0;
+}
+
+static int ipq4019_hs_phy_power_on(struct phy *_phy)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev);
+
+ ipq4019_hs_phy_power_off(_phy);
+
+ reset_deassert(&phy->srif_rst);
+ mdelay(10);
+
+ reset_deassert(&phy->por_rst);
+
+ return 0;
+}
+
+static struct phy_ops ipq4019_usb_hs_phy_ops = {
+ .power_on = ipq4019_hs_phy_power_on,
+ .power_off = ipq4019_hs_phy_power_off,
+};
+
+static int ipq4019_usb_hs_phy_probe(struct udevice *dev)
+{
+ struct ipq4019_usb_phy *phy = dev_get_priv(dev);
+ int ret;
+
+ phy->base = dev_read_addr(dev);
+ if (phy->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = reset_get_by_name(dev, "por_rst", &phy->por_rst);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "srif_rst", &phy->srif_rst);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id ipq4019_usb_hs_phy_ids[] = {
+ { .compatible = "qcom,usb-hs-ipq4019-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(ipq4019_usb_hs_phy) = {
+ .name = "ipq4019-usb-hs-phy",
+ .id = UCLASS_PHY,
+ .of_match = ipq4019_usb_hs_phy_ids,
+ .ops = &ipq4019_usb_hs_phy_ops,
+ .probe = ipq4019_usb_hs_phy_probe,
+ .priv_auto_alloc_size = sizeof(struct ipq4019_usb_phy),
+};
diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c
index c6d3048602..9d4296d649 100644
--- a/drivers/phy/phy-stm32-usbphyc.c
+++ b/drivers/phy/phy-stm32-usbphyc.c
@@ -311,7 +311,7 @@ static int stm32_usbphyc_of_xlate(struct phy *phy,
if ((phy->id == 0 && args->args_count != 1) ||
(phy->id == 1 && args->args_count != 2)) {
- dev_err(dev, "invalid number of cells for phy port%ld\n",
+ dev_err(phy->dev, "invalid number of cells for phy port%ld\n",
phy->id);
return -EINVAL;
}
diff --git a/drivers/phy/phy-ti-am654.c b/drivers/phy/phy-ti-am654.c
index 6907c1afb3..cc73760c8b 100644
--- a/drivers/phy/phy-ti-am654.c
+++ b/drivers/phy/phy-ti-am654.c
@@ -318,13 +318,13 @@ static int serdes_am654_of_xlate(struct phy *x,
struct serdes_am654 *phy = dev_get_priv(x->dev);
if (args->args_count != 2) {
- dev_err(phy->dev, "Invalid DT PHY argument count: %d\n",
+ dev_err(x->dev, "Invalid DT PHY argument count: %d\n",
args->args_count);
return -EINVAL;
}
if (args->args[0] != PHY_TYPE_PCIE) {
- dev_err(phy->dev, "Unrecognized PHY type: %d\n",
+ dev_err(x->dev, "Unrecognized PHY type: %d\n",
args->args[0]);
return -EINVAL;
}
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c
index db7f39cd0b..8f456f33d2 100644
--- a/drivers/phy/phy-uclass.c
+++ b/drivers/phy/phy-uclass.c
@@ -117,56 +117,91 @@ int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
int generic_phy_init(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!generic_phy_valid(phy))
return 0;
ops = phy_dev_ops(phy->dev);
+ if (!ops->init)
+ return 0;
+ ret = ops->init(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to init %s: %d.\n",
+ phy->dev->name, ret);
- return ops->init ? ops->init(phy) : 0;
+ return ret;
}
int generic_phy_reset(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!generic_phy_valid(phy))
return 0;
ops = phy_dev_ops(phy->dev);
+ if (!ops->reset)
+ return 0;
+ ret = ops->reset(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to reset %s: %d.\n",
+ phy->dev->name, ret);
- return ops->reset ? ops->reset(phy) : 0;
+ return ret;
}
int generic_phy_exit(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!generic_phy_valid(phy))
return 0;
ops = phy_dev_ops(phy->dev);
+ if (!ops->exit)
+ return 0;
+ ret = ops->exit(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n",
+ phy->dev->name, ret);
- return ops->exit ? ops->exit(phy) : 0;
+ return ret;
}
int generic_phy_power_on(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!generic_phy_valid(phy))
return 0;
ops = phy_dev_ops(phy->dev);
+ if (!ops->power_on)
+ return 0;
+ ret = ops->power_on(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n",
+ phy->dev->name, ret);
- return ops->power_on ? ops->power_on(phy) : 0;
+ return ret;
}
int generic_phy_power_off(struct phy *phy)
{
struct phy_ops const *ops;
+ int ret;
if (!generic_phy_valid(phy))
return 0;
ops = phy_dev_ops(phy->dev);
+ if (!ops->power_off)
+ return 0;
+ ret = ops->power_off(phy);
+ if (ret)
+ dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n",
+ phy->dev->name, ret);
- return ops->power_off ? ops->power_off(phy) : 0;
+ return ret;
}
int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c
index 83928cffe0..617943fd82 100644
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -98,7 +98,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
ret = reset_deassert(&priv->phy_rst);
if (ret) {
- dev_err(dev, "failed to assert phy reset\n");
+ dev_err(phy->dev, "failed to assert phy reset\n");
return ret;
}
@@ -119,7 +119,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
20 * 1000,
50);
if (ret) {
- dev_err(&priv->dev, "pll lock timeout!\n");
+ dev_err(phy->dev, "pll lock timeout!\n");
goto err_pll_lock;
}
@@ -133,7 +133,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
20 * 1000,
50);
if (ret) {
- dev_err(&priv->dev, "pll output enable timeout!\n");
+ dev_err(phy->dev, "pll output enable timeout!\n");
goto err_pll_lock;
}
@@ -149,7 +149,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
20 * 1000,
50);
if (ret) {
- dev_err(&priv->dev, "pll relock timeout!\n");
+ dev_err(phy->dev, "pll relock timeout!\n");
goto err_pll_lock;
}
@@ -173,7 +173,7 @@ static int rockchip_pcie_phy_power_off(struct phy *phy)
ret = reset_assert(&priv->phy_rst);
if (ret) {
- dev_err(dev, "failed to assert phy reset\n");
+ dev_err(phy->dev, "failed to assert phy reset\n");
return ret;
}
@@ -187,13 +187,13 @@ static int rockchip_pcie_phy_init(struct phy *phy)
ret = clk_enable(&priv->refclk);
if (ret) {
- dev_err(dev, "failed to enable refclk clock\n");
+ dev_err(phy->dev, "failed to enable refclk clock\n");
return ret;
}
ret = reset_assert(&priv->phy_rst);
if (ret) {
- dev_err(dev, "failed to assert phy reset\n");
+ dev_err(phy->dev, "failed to assert phy reset\n");
goto err_reset;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index c9c8e1c542..da00daa447 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -448,7 +448,7 @@ static void rockchip_tcphy_rx_usb3_cfg_lane(struct rockchip_tcphy *priv,
writel(0xfb, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane));
}
-static int rockchip_tcphy_init(struct rockchip_tcphy *priv)
+static int rockchip_tcphy_init(struct phy *phy, struct rockchip_tcphy *priv)
{
const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs;
u32 val;
@@ -559,9 +559,9 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
return 0;
if (priv->mode == MODE_DISCONNECT) {
- ret = rockchip_tcphy_init(priv);
+ ret = rockchip_tcphy_init(phy, priv);
if (ret) {
- dev_err(dev, "failed to init tcphy (ret=%d)\n", ret);
+ dev_err(phy->dev, "failed to init tcphy (ret=%d)\n", ret);
return ret;
}
}
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index cdbccfd285..048583f39b 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -205,6 +205,13 @@ config PINCTRL_QCA953X
the GPIO definitions and pin control functions for each available
multiplex function.
+config PINCTRL_QE
+ bool "QE based pinctrl driver, like on mpc83xx"
+ depends on DM
+ help
+ This option is to enable the QE pinctrl driver for QE based io
+ controller.
+
config PINCTRL_ROCKCHIP_RV1108
bool "Rockchip rv1108 pin control driver"
depends on DM
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 92cff1b100..507dd3a926 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_PINCTRL_MTK) += mediatek/
obj-$(CONFIG_PINCTRL_MSCC) += mscc/
obj-$(CONFIG_ARCH_MVEBU) += mvebu/
obj-$(CONFIG_ARCH_NEXELL) += nexell/
+obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o
obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o
diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c
index c22d534da9..41da814123 100644
--- a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c
+++ b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c
@@ -63,7 +63,7 @@ static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio)
int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
u32 pin_arr[MAX_PINS_PER_BANK];
- u32 function;
+ int function;
int i, len, pin_count = 0;
if (!dev_read_prop(config, "brcm,pins", &len) || !len ||
@@ -104,17 +104,11 @@ static const struct udevice_id bcm2835_pinctrl_id[] = {
{}
};
-int bcm283x_pinctl_probe(struct udevice *dev)
+int bcm283x_pinctl_ofdata_to_platdata(struct udevice *dev)
{
struct bcm283x_pinctrl_priv *priv;
- int ret;
- struct udevice *pdev;
priv = dev_get_priv(dev);
- if (!priv) {
- debug("%s: Failed to get private\n", __func__);
- return -EINVAL;
- }
priv->base_reg = dev_read_addr_ptr(dev);
if (!priv->base_reg) {
@@ -122,6 +116,14 @@ int bcm283x_pinctl_probe(struct udevice *dev)
return -EINVAL;
}
+ return 0;
+}
+
+int bcm283x_pinctl_probe(struct udevice *dev)
+{
+ int ret;
+ struct udevice *pdev;
+
/* Create GPIO device as well */
ret = device_bind(dev, lists_driver_lookup_name("gpio_bcm2835"),
"gpio_bcm2835", NULL, dev_of_offset(dev), &pdev);
@@ -147,10 +149,11 @@ U_BOOT_DRIVER(pinctrl_bcm283x) = {
.name = "bcm283x_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(bcm2835_pinctrl_id),
+ .ofdata_to_platdata = bcm283x_pinctl_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv),
.ops = &bcm283x_pinctrl_ops,
.probe = bcm283x_pinctl_probe,
-#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_BOARD)
+#if CONFIG_IS_ENABLED(OF_BOARD)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index fdb7920b55..bf85cc916a 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -169,6 +169,7 @@ static int atmel_pinctrl_probe(struct udevice *dev)
static const struct udevice_id atmel_pinctrl_match[] = {
{ .compatible = "atmel,sama5d2-pinctrl" },
+ { .compatible = "microchip,sama7g5-pinctrl" },
{}
};
diff --git a/drivers/pinctrl/pinctrl-qe-io.c b/drivers/pinctrl/pinctrl-qe-io.c
new file mode 100644
index 0000000000..85521eabd4
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-qe-io.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ */
+
+#include <common.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/immap_83xx.h>
+
+#if defined(CONFIG_PINCTRL)
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/pinctrl.h>
+#include <linux/ioport.h>
+
+/**
+ * struct qe_io_platdata
+ *
+ * @base: Base register address
+ * @num_par_io_ports number of io ports
+ */
+struct qe_io_platdata {
+ qepio83xx_t *base;
+ u32 num_io_ports;
+};
+#endif
+
+#define NUM_OF_PINS 32
+
+/** qe_cfg_iopin configure one io pin setting
+ *
+ * @par_io: pointer to parallel I/O base
+ * @port: io pin port
+ * @pin: io pin number which get configured
+ * @dir: direction of io pin 2 bits valid
+ * 00 = pin disabled
+ * 01 = output
+ * 10 = input
+ * 11 = pin is I/O
+ * @open_drain: is pin open drain
+ * @assign: pin assignment registers select the function of the pin
+ */
+static void qe_cfg_iopin(qepio83xx_t *par_io, u8 port, u8 pin, int dir,
+ int open_drain, int assign)
+{
+ u32 dbit_mask;
+ u32 dbit_dir;
+ u32 dbit_asgn;
+ u32 bit_mask;
+ u32 tmp_val;
+ int offset;
+
+ offset = (NUM_OF_PINS - (pin % (NUM_OF_PINS / 2) + 1) * 2);
+
+ /* Calculate pin location and 2bit mask and dir */
+ dbit_mask = (u32)(0x3 << offset);
+ dbit_dir = (u32)(dir << offset);
+
+ /* Setup the direction */
+ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+ in_be32(&par_io->ioport[port].dir2) :
+ in_be32(&par_io->ioport[port].dir1);
+
+ if (pin > (NUM_OF_PINS / 2) - 1) {
+ out_be32(&par_io->ioport[port].dir2, ~dbit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].dir2, dbit_dir | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].dir1, ~dbit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].dir1, dbit_dir | tmp_val);
+ }
+
+ /* Calculate pin location for 1bit mask */
+ bit_mask = (u32)(1 << (NUM_OF_PINS - (pin + 1)));
+
+ /* Setup the open drain */
+ tmp_val = in_be32(&par_io->ioport[port].podr);
+ if (open_drain)
+ out_be32(&par_io->ioport[port].podr, bit_mask | tmp_val);
+ else
+ out_be32(&par_io->ioport[port].podr, ~bit_mask & tmp_val);
+
+ /* Setup the assignment */
+ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+ in_be32(&par_io->ioport[port].ppar2) :
+ in_be32(&par_io->ioport[port].ppar1);
+ dbit_asgn = (u32)(assign << offset);
+
+ /* Clear and set 2 bits mask */
+ if (pin > (NUM_OF_PINS / 2) - 1) {
+ out_be32(&par_io->ioport[port].ppar2, ~dbit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].ppar2, dbit_asgn | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].ppar1, ~dbit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].ppar1, dbit_asgn | tmp_val);
+ }
+}
+
+#if !defined(CONFIG_PINCTRL)
+/** qe_config_iopin configure one io pin setting
+ *
+ * @port: io pin port
+ * @pin: io pin number which get configured
+ * @dir: direction of io pin 2 bits valid
+ * 00 = pin disabled
+ * 01 = output
+ * 10 = input
+ * 11 = pin is I/O
+ * @open_drain: is pin open drain
+ * @assign: pin assignment registers select the function of the pin
+ */
+void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
+{
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ qepio83xx_t *par_io = (qepio83xx_t *)&im->qepio;
+
+ qe_cfg_iopin(par_io, port, pin, dir, open_drain, assign);
+}
+#else
+static int qe_io_ofdata_to_platdata(struct udevice *dev)
+{
+ struct qe_io_platdata *plat = dev->platdata;
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->base = (qepio83xx_t *)addr;
+ if (dev_read_u32(dev, "num-ports", &plat->num_io_ports))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * par_io_of_config_node config
+ * @dev: pointer to pinctrl device
+ * @pio: ofnode of pinconfig property
+ */
+static int par_io_of_config_node(struct udevice *dev, ofnode pio)
+{
+ struct qe_io_platdata *plat = dev->platdata;
+ qepio83xx_t *par_io = plat->base;
+ const unsigned int *pio_map;
+ int pio_map_len;
+
+ pio_map = ofnode_get_property(pio, "pio-map", &pio_map_len);
+ if (!pio_map)
+ return -ENOENT;
+
+ pio_map_len /= sizeof(unsigned int);
+ if ((pio_map_len % 6) != 0) {
+ dev_err(dev, "%s: pio-map format wrong!\n", __func__);
+ return -EINVAL;
+ }
+
+ while (pio_map_len > 0) {
+ /*
+ * column pio_map[5] from linux (has_irq) not
+ * supported in u-boot yet.
+ */
+ qe_cfg_iopin(par_io, (u8)pio_map[0], (u8)pio_map[1],
+ (int)pio_map[2], (int)pio_map[3],
+ (int)pio_map[4]);
+ pio_map += 6;
+ pio_map_len -= 6;
+ }
+ return 0;
+}
+
+int par_io_of_config(struct udevice *dev)
+{
+ u32 phandle;
+ ofnode pio;
+ int err;
+
+ err = ofnode_read_u32(dev_ofnode(dev), "pio-handle", &phandle);
+ if (err) {
+ dev_err(dev, "%s: pio-handle not available\n", __func__);
+ return err;
+ }
+
+ pio = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(pio)) {
+ dev_err(dev, "%s: unable to find node\n", __func__);
+ return -EINVAL;
+ }
+
+ /* To Do: find pinctrl device and pass it */
+ return par_io_of_config_node(NULL, pio);
+}
+
+/*
+ * This is not nice!
+ * pinsettings should work with "pinctrl-" properties.
+ * Unfortunately on mpc83xx powerpc linux device trees
+ * devices handle this with "pio-handle" properties ...
+ *
+ * Even worser, old board code inits all par_io
+ * pins in one step, if U-Boot uses the device
+ * or not. So init all par_io definitions here too
+ * as linux does this also.
+ */
+static void config_qe_ioports(struct udevice *dev)
+{
+ ofnode ofn;
+
+ for (ofn = dev_read_first_subnode(dev); ofnode_valid(ofn);
+ ofn = dev_read_next_subnode(ofn)) {
+ /*
+ * ignore errors here, as may the subnode
+ * has no pio-handle
+ */
+ par_io_of_config_node(dev, ofn);
+ }
+}
+
+static int par_io_pinctrl_probe(struct udevice *dev)
+{
+ config_qe_ioports(dev);
+
+ return 0;
+}
+
+static int par_io_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+ return 0;
+}
+
+const struct pinctrl_ops par_io_pinctrl_ops = {
+ .set_state = par_io_pinctrl_set_state,
+};
+
+static const struct udevice_id par_io_pinctrl_match[] = {
+ { .compatible = "fsl,mpc8360-par_io"},
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(par_io_pinctrl) = {
+ .name = "par-io-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = of_match_ptr(par_io_pinctrl_match),
+ .probe = par_io_pinctrl_probe,
+ .ofdata_to_platdata = qe_io_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct qe_io_platdata),
+ .ops = &par_io_pinctrl_ops,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .flags = DM_FLAG_PRE_RELOC,
+#endif
+};
+#endif
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
index 71fa29a389..dbea99532c 100644
--- a/drivers/pinctrl/pinctrl_stm32.c
+++ b/drivers/pinctrl/pinctrl_stm32.c
@@ -1,3 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017-2020 STMicroelectronics - All Rights Reserved
+ */
+
#include <common.h>
#include <dm.h>
#include <hwspinlock.h>
@@ -13,8 +18,6 @@
#include <linux/err.h>
#include <linux/libfdt.h>
-DECLARE_GLOBAL_DATA_PTR;
-
#define MAX_PINS_ONE_IP 70
#define MODE_BITS_MASK 3
#define OSPEED_MASK 3
@@ -308,7 +311,8 @@ static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin)
return 0;
}
-static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node)
+static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn,
+ ofnode node)
{
gpio_fn &= 0x00FF;
gpio_ctl->af = 0;
@@ -329,16 +333,16 @@ static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node)
break;
}
- gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0);
+ gpio_ctl->speed = ofnode_read_u32_default(node, "slew-rate", 0);
- if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain"))
+ if (ofnode_read_bool(node, "drive-open-drain"))
gpio_ctl->otype = STM32_GPIO_OTYPE_OD;
else
gpio_ctl->otype = STM32_GPIO_OTYPE_PP;
- if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up"))
+ if (ofnode_read_bool(node, "bias-pull-up"))
gpio_ctl->pupd = STM32_GPIO_PUPD_UP;
- else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down"))
+ else if (ofnode_read_bool(node, "bias-pull-down"))
gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN;
else
gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
@@ -350,32 +354,37 @@ static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node)
return 0;
}
-static int stm32_pinctrl_config(int offset)
+static int stm32_pinctrl_config(ofnode node)
{
u32 pin_mux[MAX_PINS_ONE_IP];
int rv, len;
+ ofnode subnode;
/*
* check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
* usart1) of pin controller phandle "pinctrl-0"
* */
- fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
+ ofnode_for_each_subnode(subnode, node) {
struct stm32_gpio_dsc gpio_dsc;
struct stm32_gpio_ctl gpio_ctl;
int i;
- len = fdtdec_get_int_array_count(gd->fdt_blob, offset,
- "pinmux", pin_mux,
- ARRAY_SIZE(pin_mux));
+ rv = ofnode_read_size(subnode, "pinmux");
+ if (rv < 0)
+ return rv;
+ len = rv / sizeof(pin_mux[0]);
debug("%s: no of pinmux entries= %d\n", __func__, len);
- if (len < 0)
+ if (len > MAX_PINS_ONE_IP)
return -EINVAL;
+ rv = ofnode_read_u32_array(subnode, "pinmux", pin_mux, len);
+ if (rv < 0)
+ return rv;
for (i = 0; i < len; i++) {
struct gpio_desc desc;
debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
- prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), offset);
+ prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), subnode);
rv = uclass_get_device_by_seq(UCLASS_GPIO,
gpio_dsc.port,
&desc.dev);
@@ -424,19 +433,18 @@ static int stm32_pinctrl_bind(struct udevice *dev)
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
- return stm32_pinctrl_config(dev_of_offset(config));
+ return stm32_pinctrl_config(dev_ofnode(config));
}
#else /* PINCTRL_FULL */
static int stm32_pinctrl_set_state_simple(struct udevice *dev,
struct udevice *periph)
{
- const void *fdt = gd->fdt_blob;
const fdt32_t *list;
uint32_t phandle;
- int config_node;
+ ofnode config_node;
int size, i, ret;
- list = fdt_getprop(fdt, dev_of_offset(periph), "pinctrl-0", &size);
+ list = ofnode_get_property(dev_ofnode(periph), "pinctrl-0", &size);
if (!list)
return -EINVAL;
@@ -446,8 +454,8 @@ static int stm32_pinctrl_set_state_simple(struct udevice *dev,
for (i = 0; i < size; i++) {
phandle = fdt32_to_cpu(*list++);
- config_node = fdt_node_offset_by_phandle(fdt, phandle);
- if (config_node < 0) {
+ config_node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(config_node)) {
pr_err("prop pinctrl-0 index %d invalid phandle\n", i);
return -EINVAL;
}
diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig
index 8327bcabd6..e14294b6e7 100644
--- a/drivers/pinctrl/renesas/Kconfig
+++ b/drivers/pinctrl/renesas/Kconfig
@@ -57,6 +57,16 @@ config PINCTRL_PFC_R8A7794
the GPIO definitions and pin control functions for each available
multiplex function.
+config PINCTRL_PFC_R8A774A1
+ bool "Renesas RZ/G2 R8A774A1 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas RZ/G2M R8A774A1 SoCs.
+
+ The driver is controlled by a device tree node which contains both
+ the GPIO definitions and pin control functions for each available
+ multiplex function.
+
config PINCTRL_PFC_R8A7795
bool "Renesas RCar Gen3 R8A7795 pin control driver"
depends on PINCTRL_PFC
@@ -77,16 +87,6 @@ config PINCTRL_PFC_R8A7796
the GPIO definitions and pin control functions for each available
multiplex function.
-config PINCTRL_PFC_R8A774A1
- bool "Renesas RCar Gen3 R8A774A1 pin control driver"
- depends on PINCTRL_PFC
- help
- Support pin multiplexing control on Renesas RZG2M R8A774A1 SoCs.
-
- The driver is controlled by a device tree node which contains both
- the GPIO definitions and pin control functions for each available
- multiplex function.
-
config PINCTRL_PFC_R8A77965
bool "Renesas RCar Gen3 R8A77965 pin control driver"
depends on PINCTRL_PFC
diff --git a/drivers/qe/Kconfig b/drivers/qe/Kconfig
index 44c9f010bd..864b36b822 100644
--- a/drivers/qe/Kconfig
+++ b/drivers/qe/Kconfig
@@ -3,7 +3,7 @@
#
config QE
bool "Enable support for QUICC Engine"
- depends on PPC && !DM_ETH
+ depends on PPC
default y if ARCH_T1040 || ARCH_T1042 || ARCH_T1024 || ARCH_P1021 \
|| ARCH_P1025
help
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 61ca4760c8..1a829b5a4c 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -26,7 +26,7 @@
#define MPC85xx_DEVDISR_QE_DISABLE 0x1
-qe_map_t *qe_immr = NULL;
+qe_map_t *qe_immr;
#ifdef CONFIG_QE
static qe_snum_t snums[QE_NUM_OF_SNUM];
#endif
@@ -38,18 +38,16 @@ void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
u32 cecr;
if (cmd == QE_RESET) {
- out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
+ out_be32(&qe_immr->cp.cecr, (u32)(cmd | QE_CR_FLG));
} else {
out_be32(&qe_immr->cp.cecdr, cmd_data);
out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
- ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
+ ((u32)mcn << QE_CR_PROTOCOL_SHIFT) | cmd));
}
/* Wait for the QE_CR_FLG to clear */
do {
cecr = in_be32(&qe_immr->cp.cecr);
} while (cecr & QE_CR_FLG);
-
- return;
}
#ifdef CONFIG_QE
@@ -66,12 +64,13 @@ uint qe_muram_alloc(uint size, uint align)
if (off != 0)
gd->arch.mp_alloc_base += (align - off);
- if ((off = size & align_mask) != 0)
+ off = size & align_mask;
+ if (off != 0)
size += (align - off);
if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
gd->arch.mp_alloc_base = savebase;
- printf("%s: ran out of ram.\n", __FUNCTION__);
+ printf("%s: ran out of ram.\n", __func__);
}
retloc = gd->arch.mp_alloc_base;
@@ -93,10 +92,10 @@ void *qe_muram_addr(uint offset)
#ifdef CONFIG_QE
static void qe_sdma_init(void)
{
- volatile sdma_t *p;
- uint sdma_buffer_base;
+ sdma_t *p;
+ uint sdma_buffer_base;
- p = (volatile sdma_t *)&qe_immr->sdma;
+ p = (sdma_t *)&qe_immr->sdma;
/* All of DMA transaction in bus 1 */
out_be32(&p->sdaqr, 0);
@@ -212,7 +211,7 @@ void qe_init(uint qe_base)
qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
/* enable the microcode in IRAM */
- out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
+ out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
#endif
gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
@@ -235,10 +234,12 @@ void u_qe_init(void)
void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
if (src == BOOT_SOURCE_IFC_NOR)
- addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_IFC_BASE);
+ addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
+ CONFIG_SYS_FSL_IFC_BASE);
if (src == BOOT_SOURCE_QSPI_NOR)
- addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_QSPI_BASE);
+ addr = (void *)(CONFIG_SYS_QE_FW_ADDR +
+ CONFIG_SYS_FSL_QSPI_BASE);
if (src == BOOT_SOURCE_SD_MMC) {
int dev = CONFIG_SYS_MMC_ENV_DEV;
@@ -320,7 +321,7 @@ void u_qe_resume(void)
void qe_reset(void)
{
qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
- (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
}
#ifdef CONFIG_QE
@@ -329,24 +330,22 @@ void qe_assign_page(uint snum, uint para_ram_base)
u32 cecr;
out_be32(&qe_immr->cp.cecdr, para_ram_base);
- out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
+ out_be32(&qe_immr->cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
| QE_CR_FLG | QE_ASSIGN_PAGE);
/* Wait for the QE_CR_FLG to clear */
do {
cecr = in_be32(&qe_immr->cp.cecr);
- } while (cecr & QE_CR_FLG );
-
- return;
+ } while (cecr & QE_CR_FLG);
}
#endif
/*
* brg: 0~15 as BRG1~BRG16
- rate: baud rate
+ * rate: baud rate
* BRG input clock comes from the BRGCLK (internal clock generated from
- the QE clock, it is one-half of the QE clock), If need the clock source
- from CLKn pin, we have te change the function.
+ * the QE clock, it is one-half of the QE clock), If need the clock source
+ * from CLKn pin, we have te change the function.
*/
#define BRG_CLK (gd->arch.brg_clk)
@@ -354,12 +353,14 @@ void qe_assign_page(uint snum, uint para_ram_base)
#ifdef CONFIG_QE
int qe_set_brg(uint brg, uint rate)
{
- volatile uint *bp;
- u32 divisor;
- int div16 = 0;
+ uint *bp;
+ u32 divisor;
+ u32 val;
+ int div16 = 0;
if (brg >= QE_NUM_OF_BRGS)
return -EINVAL;
+
bp = (uint *)&qe_immr->brg.brgc1;
bp += brg;
@@ -369,33 +370,37 @@ int qe_set_brg(uint brg, uint rate)
divisor /= 16;
}
- *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
- __asm__ __volatile__("sync");
+ /* CHECK TODO */
+ /*
+ * was
+ * *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
+ * __asm__ __volatile__("sync");
+ */
- if (div16) {
- *bp |= QE_BRGC_DIV16;
- __asm__ __volatile__("sync");
- }
+ val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
+ if (div16)
+ val |= QE_BRGC_DIV16;
+
+ out_be32(bp, val);
return 0;
}
#endif
-/* Set ethernet MII clock master
-*/
+/* Set ethernet MII clock master */
int qe_set_mii_clk_src(int ucc_num)
{
u32 cmxgcr;
/* check if the UCC number is in range. */
- if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
- printf("%s: ucc num not in ranges\n", __FUNCTION__);
+ if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
+ printf("%s: ucc num not in ranges\n", __func__);
return -EINVAL;
}
cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
- cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
+ cmxgcr |= (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
return 0;
@@ -417,7 +422,7 @@ static int qe_firmware_uploaded;
* the actual uploading of the microcode.
*/
static void qe_upload_microcode(const void *base,
- const struct qe_microcode *ucode)
+ const struct qe_microcode *ucode)
{
const u32 *code = base + be32_to_cpu(ucode->code_offset);
unsigned int i;
@@ -494,7 +499,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
}
/* Validate some of the fields */
- if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
+ if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
printf("Invalid data\n");
return -EINVAL;
}
@@ -522,7 +527,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
* function isn't available unless you turn on JFFS support.
*/
crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
- if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
+ if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
printf("Firmware CRC is invalid\n");
return -EIO;
}
@@ -532,12 +537,12 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
*/
if (!firmware->split) {
out_be16(&qe_immr->cp.cercr,
- in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
+ in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
}
if (firmware->soc.model)
printf("Firmware '%s' for %u V%u.%u\n",
- firmware->id, be16_to_cpu(firmware->soc.model),
+ firmware->id, be16_to_cpu(firmware->soc.model),
firmware->soc.major, firmware->soc.minor);
else
printf("Firmware '%s'\n", firmware->id);
@@ -550,7 +555,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
qe_firmware_info.extended_modes = firmware->extended_modes;
memcpy(qe_firmware_info.vtraps, firmware->vtraps,
- sizeof(firmware->vtraps));
+ sizeof(firmware->vtraps));
qe_firmware_uploaded = 1;
/* Loop through each microcode. */
@@ -634,7 +639,7 @@ int u_qe_upload_firmware(const struct qe_firmware *firmware)
}
/* Validate some of the fields */
- if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
+ if (firmware->count < 1 || firmware->count > MAX_QE_RISC) {
printf("Invalid data\n");
return -EINVAL;
}
@@ -803,7 +808,7 @@ static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
if (argc > 3) {
ulong length = simple_strtoul(argv[3], NULL, 16);
- struct qe_firmware *firmware = (void *) addr;
+ struct qe_firmware *firmware = (void *)addr;
if (length != be32_to_cpu(firmware->header.length)) {
printf("Length mismatch\n");
@@ -811,7 +816,7 @@ static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
}
}
- return qe_upload_firmware((const struct qe_firmware *) addr);
+ return qe_upload_firmware((const struct qe_firmware *)addr);
}
return cmd_usage(cmdtp);
@@ -820,7 +825,6 @@ static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
U_BOOT_CMD(
qe, 4, 0, qe_cmd,
"QUICC Engine commands",
- "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
- "the QE,\n"
+ "fw <addr> [<length>] - Upload firmware binary at address <addr> to the QE,\n"
"\twith optional length <length> verification."
);
diff --git a/drivers/qe/uccf.c b/drivers/qe/uccf.c
index 9beb5d90ac..d5d734439c 100644
--- a/drivers/qe/uccf.c
+++ b/drivers/qe/uccf.c
@@ -14,7 +14,8 @@
#include "uccf.h"
#include <fsl_qe.h>
-void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf)
+#if !defined(CONFIG_DM_ETH)
+void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf)
{
out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
}
@@ -22,170 +23,271 @@ void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf)
u32 ucc_fast_get_qe_cr_subblock(int ucc_num)
{
switch (ucc_num) {
- case 0: return QE_CR_SUBBLOCK_UCCFAST1;
- case 1: return QE_CR_SUBBLOCK_UCCFAST2;
- case 2: return QE_CR_SUBBLOCK_UCCFAST3;
- case 3: return QE_CR_SUBBLOCK_UCCFAST4;
- case 4: return QE_CR_SUBBLOCK_UCCFAST5;
- case 5: return QE_CR_SUBBLOCK_UCCFAST6;
- case 6: return QE_CR_SUBBLOCK_UCCFAST7;
- case 7: return QE_CR_SUBBLOCK_UCCFAST8;
- default: return QE_CR_SUBBLOCK_INVALID;
+ case 0:
+ return QE_CR_SUBBLOCK_UCCFAST1;
+ case 1:
+ return QE_CR_SUBBLOCK_UCCFAST2;
+ case 2:
+ return QE_CR_SUBBLOCK_UCCFAST3;
+ case 3:
+ return QE_CR_SUBBLOCK_UCCFAST4;
+ case 4:
+ return QE_CR_SUBBLOCK_UCCFAST5;
+ case 5:
+ return QE_CR_SUBBLOCK_UCCFAST6;
+ case 6:
+ return QE_CR_SUBBLOCK_UCCFAST7;
+ case 7:
+ return QE_CR_SUBBLOCK_UCCFAST8;
+ default:
+ return QE_CR_SUBBLOCK_INVALID;
}
}
-static void ucc_get_cmxucr_reg(int ucc_num, volatile u32 **p_cmxucr,
- u8 *reg_num, u8 *shift)
+static void ucc_get_cmxucr_reg(int ucc_num, u32 **p_cmxucr,
+ u8 *reg_num, u8 *shift)
{
switch (ucc_num) {
- case 0: /* UCC1 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr1);
- *reg_num = 1;
- *shift = 16;
- break;
- case 2: /* UCC3 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr1);
- *reg_num = 1;
- *shift = 0;
- break;
- case 4: /* UCC5 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr2);
- *reg_num = 2;
- *shift = 16;
- break;
- case 6: /* UCC7 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr2);
- *reg_num = 2;
- *shift = 0;
- break;
- case 1: /* UCC2 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr3);
- *reg_num = 3;
- *shift = 16;
- break;
- case 3: /* UCC4 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr3);
- *reg_num = 3;
- *shift = 0;
- break;
- case 5: /* UCC6 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr4);
- *reg_num = 4;
- *shift = 16;
- break;
- case 7: /* UCC8 */
- *p_cmxucr = &(qe_immr->qmx.cmxucr4);
- *reg_num = 4;
- *shift = 0;
- break;
- default:
- break;
+ case 0: /* UCC1 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr1;
+ *reg_num = 1;
+ *shift = 16;
+ break;
+ case 2: /* UCC3 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr1;
+ *reg_num = 1;
+ *shift = 0;
+ break;
+ case 4: /* UCC5 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr2;
+ *reg_num = 2;
+ *shift = 16;
+ break;
+ case 6: /* UCC7 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr2;
+ *reg_num = 2;
+ *shift = 0;
+ break;
+ case 1: /* UCC2 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr3;
+ *reg_num = 3;
+ *shift = 16;
+ break;
+ case 3: /* UCC4 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr3;
+ *reg_num = 3;
+ *shift = 0;
+ break;
+ case 5: /* UCC6 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr4;
+ *reg_num = 4;
+ *shift = 16;
+ break;
+ case 7: /* UCC8 */
+ *p_cmxucr = &qe_immr->qmx.cmxucr4;
+ *reg_num = 4;
+ *shift = 0;
+ break;
+ default:
+ break;
}
}
static int ucc_set_clk_src(int ucc_num, qe_clock_e clock, comm_dir_e mode)
{
- volatile u32 *p_cmxucr = NULL;
- u8 reg_num = 0;
- u8 shift = 0;
- u32 clockBits;
- u32 clockMask;
- int source = -1;
+ u32 *p_cmxucr = NULL;
+ u8 reg_num = 0;
+ u8 shift = 0;
+ u32 clk_bits;
+ u32 clk_mask;
+ int source = -1;
/* check if the UCC number is in range. */
- if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+ if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0)
return -EINVAL;
- if (! ((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) {
- printf("%s: bad comm mode type passed\n", __FUNCTION__);
+ if (!(mode == COMM_DIR_RX || mode == COMM_DIR_TX)) {
+ printf("%s: bad comm mode type passed\n", __func__);
return -EINVAL;
}
ucc_get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
switch (reg_num) {
- case 1:
- switch (clock) {
- case QE_BRG1: source = 1; break;
- case QE_BRG2: source = 2; break;
- case QE_BRG7: source = 3; break;
- case QE_BRG8: source = 4; break;
- case QE_CLK9: source = 5; break;
- case QE_CLK10: source = 6; break;
- case QE_CLK11: source = 7; break;
- case QE_CLK12: source = 8; break;
- case QE_CLK15: source = 9; break;
- case QE_CLK16: source = 10; break;
- default: source = -1; break;
- }
- break;
- case 2:
- switch (clock) {
- case QE_BRG5: source = 1; break;
- case QE_BRG6: source = 2; break;
- case QE_BRG7: source = 3; break;
- case QE_BRG8: source = 4; break;
- case QE_CLK13: source = 5; break;
- case QE_CLK14: source = 6; break;
- case QE_CLK19: source = 7; break;
- case QE_CLK20: source = 8; break;
- case QE_CLK15: source = 9; break;
- case QE_CLK16: source = 10; break;
- default: source = -1; break;
- }
- break;
- case 3:
- switch (clock) {
- case QE_BRG9: source = 1; break;
- case QE_BRG10: source = 2; break;
- case QE_BRG15: source = 3; break;
- case QE_BRG16: source = 4; break;
- case QE_CLK3: source = 5; break;
- case QE_CLK4: source = 6; break;
- case QE_CLK17: source = 7; break;
- case QE_CLK18: source = 8; break;
- case QE_CLK7: source = 9; break;
- case QE_CLK8: source = 10; break;
- case QE_CLK16: source = 11; break;
- default: source = -1; break;
- }
- break;
- case 4:
- switch (clock) {
- case QE_BRG13: source = 1; break;
- case QE_BRG14: source = 2; break;
- case QE_BRG15: source = 3; break;
- case QE_BRG16: source = 4; break;
- case QE_CLK5: source = 5; break;
- case QE_CLK6: source = 6; break;
- case QE_CLK21: source = 7; break;
- case QE_CLK22: source = 8; break;
- case QE_CLK7: source = 9; break;
- case QE_CLK8: source = 10; break;
- case QE_CLK16: source = 11; break;
- default: source = -1; break;
- }
+ case 1:
+ switch (clock) {
+ case QE_BRG1:
+ source = 1;
+ break;
+ case QE_BRG2:
+ source = 2;
+ break;
+ case QE_BRG7:
+ source = 3;
+ break;
+ case QE_BRG8:
+ source = 4;
+ break;
+ case QE_CLK9:
+ source = 5;
+ break;
+ case QE_CLK10:
+ source = 6;
+ break;
+ case QE_CLK11:
+ source = 7;
+ break;
+ case QE_CLK12:
+ source = 8;
+ break;
+ case QE_CLK15:
+ source = 9;
+ break;
+ case QE_CLK16:
+ source = 10;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG5:
+ source = 1;
+ break;
+ case QE_BRG6:
+ source = 2;
+ break;
+ case QE_BRG7:
+ source = 3;
+ break;
+ case QE_BRG8:
+ source = 4;
+ break;
+ case QE_CLK13:
+ source = 5;
+ break;
+ case QE_CLK14:
+ source = 6;
+ break;
+ case QE_CLK19:
+ source = 7;
+ break;
+ case QE_CLK20:
+ source = 8;
+ break;
+ case QE_CLK15:
+ source = 9;
+ break;
+ case QE_CLK16:
+ source = 10;
break;
default:
source = -1;
break;
+ }
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG9:
+ source = 1;
+ break;
+ case QE_BRG10:
+ source = 2;
+ break;
+ case QE_BRG15:
+ source = 3;
+ break;
+ case QE_BRG16:
+ source = 4;
+ break;
+ case QE_CLK3:
+ source = 5;
+ break;
+ case QE_CLK4:
+ source = 6;
+ break;
+ case QE_CLK17:
+ source = 7;
+ break;
+ case QE_CLK18:
+ source = 8;
+ break;
+ case QE_CLK7:
+ source = 9;
+ break;
+ case QE_CLK8:
+ source = 10;
+ break;
+ case QE_CLK16:
+ source = 11;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ case 4:
+ switch (clock) {
+ case QE_BRG13:
+ source = 1;
+ break;
+ case QE_BRG14:
+ source = 2;
+ break;
+ case QE_BRG15:
+ source = 3;
+ break;
+ case QE_BRG16:
+ source = 4;
+ break;
+ case QE_CLK5:
+ source = 5;
+ break;
+ case QE_CLK6:
+ source = 6;
+ break;
+ case QE_CLK21:
+ source = 7;
+ break;
+ case QE_CLK22:
+ source = 8;
+ break;
+ case QE_CLK7:
+ source = 9;
+ break;
+ case QE_CLK8:
+ source = 10;
+ break;
+ case QE_CLK16:
+ source = 11;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ default:
+ source = -1;
+ break;
}
if (source == -1) {
- printf("%s: Bad combination of clock and UCC\n", __FUNCTION__);
+ printf("%s: Bad combination of clock and UCC\n", __func__);
return -ENOENT;
}
- clockBits = (u32) source;
- clockMask = QE_CMXUCR_TX_CLK_SRC_MASK;
+ clk_bits = (u32)source;
+ clk_mask = QE_CMXUCR_TX_CLK_SRC_MASK;
if (mode == COMM_DIR_RX) {
- clockBits <<= 4; /* Rx field is 4 bits to left of Tx field */
- clockMask <<= 4; /* Rx field is 4 bits to left of Tx field */
+ clk_bits <<= 4; /* Rx field is 4 bits to left of Tx field */
+ clk_mask <<= 4; /* Rx field is 4 bits to left of Tx field */
}
- clockBits <<= shift;
- clockMask <<= shift;
+ clk_bits <<= shift;
+ clk_mask <<= shift;
- out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clockMask) | clockBits);
+ out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clk_mask) | clk_bits);
return 0;
}
@@ -195,28 +297,45 @@ static uint ucc_get_reg_baseaddr(int ucc_num)
uint base = 0;
/* check if the UCC number is in range */
- if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
- printf("%s: the UCC num not in ranges\n", __FUNCTION__);
+ if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) {
+ printf("%s: the UCC num not in ranges\n", __func__);
return 0;
}
switch (ucc_num) {
- case 0: base = 0x00002000; break;
- case 1: base = 0x00003000; break;
- case 2: base = 0x00002200; break;
- case 3: base = 0x00003200; break;
- case 4: base = 0x00002400; break;
- case 5: base = 0x00003400; break;
- case 6: base = 0x00002600; break;
- case 7: base = 0x00003600; break;
- default: break;
+ case 0:
+ base = 0x00002000;
+ break;
+ case 1:
+ base = 0x00003000;
+ break;
+ case 2:
+ base = 0x00002200;
+ break;
+ case 3:
+ base = 0x00003200;
+ break;
+ case 4:
+ base = 0x00002400;
+ break;
+ case 5:
+ base = 0x00003400;
+ break;
+ case 6:
+ base = 0x00002600;
+ break;
+ case 7:
+ base = 0x00003600;
+ break;
+ default:
+ break;
}
base = (uint)qe_immr + base;
return base;
}
-void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode)
+void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode)
{
ucc_fast_t *uf_regs;
u32 gumr;
@@ -236,7 +355,7 @@ void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode)
out_be32(&uf_regs->gumr, gumr);
}
-void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode)
+void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode)
{
ucc_fast_t *uf_regs;
u32 gumr;
@@ -256,34 +375,35 @@ void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode)
out_be32(&uf_regs->gumr, gumr);
}
-int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
+int ucc_fast_init(struct ucc_fast_inf *uf_info,
+ struct ucc_fast_priv **uccf_ret)
{
- ucc_fast_private_t *uccf;
+ struct ucc_fast_priv *uccf;
ucc_fast_t *uf_regs;
if (!uf_info)
return -EINVAL;
- if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
- printf("%s: Illagal UCC number!\n", __FUNCTION__);
+ if (uf_info->ucc_num < 0 || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
+ printf("%s: Illagal UCC number!\n", __func__);
return -EINVAL;
}
- uccf = (ucc_fast_private_t *)malloc(sizeof(ucc_fast_private_t));
+ uccf = (struct ucc_fast_priv *)malloc(sizeof(struct ucc_fast_priv));
if (!uccf) {
printf("%s: No memory for UCC fast data structure!\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
- memset(uccf, 0, sizeof(ucc_fast_private_t));
+ memset(uccf, 0, sizeof(struct ucc_fast_priv));
/* Save fast UCC structure */
uccf->uf_info = uf_info;
uccf->uf_regs = (ucc_fast_t *)ucc_get_reg_baseaddr(uf_info->ucc_num);
- if (uccf->uf_regs == NULL) {
+ if (!uccf->uf_regs) {
printf("%s: No memory map for UCC fast controller!\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -291,8 +411,8 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
uccf->enabled_rx = 0;
uf_regs = uccf->uf_regs;
- uccf->p_ucce = (u32 *) &(uf_regs->ucce);
- uccf->p_uccm = (u32 *) &(uf_regs->uccm);
+ uccf->p_ucce = (u32 *)&uf_regs->ucce;
+ uccf->p_uccm = (u32 *)&uf_regs->uccm;
/* Init GUEMR register, UCC both Rx and Tx is Fast protocol */
out_8(&uf_regs->guemr, UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_FAST_RX
@@ -306,13 +426,13 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
/* Allocate memory for Tx Virtual Fifo */
uccf->ucc_fast_tx_virtual_fifo_base_offset =
qe_muram_alloc(UCC_GETH_UTFS_GIGA_INIT,
- UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
/* Allocate memory for Rx Virtual Fifo */
uccf->ucc_fast_rx_virtual_fifo_base_offset =
qe_muram_alloc(UCC_GETH_URFS_GIGA_INIT +
- UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD,
- UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+ UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD,
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
/* utfb, urfb are offsets from MURAM base */
out_be32(&uf_regs->utfb,
@@ -334,7 +454,7 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
/* Allocate memory for Tx Virtual Fifo */
uccf->ucc_fast_tx_virtual_fifo_base_offset =
qe_muram_alloc(UCC_GETH_UTFS_INIT,
- UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
/* Allocate memory for Rx Virtual Fifo */
uccf->ucc_fast_rx_virtual_fifo_base_offset =
@@ -360,9 +480,9 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
/* Rx clock routing */
if (uf_info->rx_clock != QE_CLK_NONE) {
if (ucc_set_clk_src(uf_info->ucc_num,
- uf_info->rx_clock, COMM_DIR_RX)) {
+ uf_info->rx_clock, COMM_DIR_RX)) {
printf("%s: Illegal value for parameter 'RxClock'.\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
}
@@ -370,9 +490,9 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
/* Tx clock routing */
if (uf_info->tx_clock != QE_CLK_NONE) {
if (ucc_set_clk_src(uf_info->ucc_num,
- uf_info->tx_clock, COMM_DIR_TX)) {
+ uf_info->tx_clock, COMM_DIR_TX)) {
printf("%s: Illegal value for parameter 'TxClock'.\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
}
@@ -386,3 +506,4 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret)
*uccf_ret = uccf;
return 0;
}
+#endif
diff --git a/drivers/qe/uccf.h b/drivers/qe/uccf.h
index 4098c66317..99f8458edf 100644
--- a/drivers/qe/uccf.h
+++ b/drivers/qe/uccf.h
@@ -13,25 +13,23 @@
#include "linux/immap_qe.h"
#include <fsl_qe.h>
-/* Fast or Giga ethernet
-*/
-typedef enum enet_type {
+/* Fast or Giga ethernet */
+enum enet_type {
FAST_ETH,
GIGA_ETH,
-} enet_type_e;
+};
-/* General UCC Extended Mode Register
-*/
+/* General UCC Extended Mode Register */
#define UCC_GUEMR_MODE_MASK_RX 0x02
#define UCC_GUEMR_MODE_MASK_TX 0x01
#define UCC_GUEMR_MODE_FAST_RX 0x02
#define UCC_GUEMR_MODE_FAST_TX 0x01
#define UCC_GUEMR_MODE_SLOW_RX 0x00
#define UCC_GUEMR_MODE_SLOW_TX 0x00
-#define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 must be set 1 */
+/* Bit 3 must be set 1 */
+#define UCC_GUEMR_SET_RESERVED3 0x10
-/* General UCC FAST Mode Register
-*/
+/* General UCC FAST Mode Register */
#define UCC_FAST_GUMR_TCI 0x20000000
#define UCC_FAST_GUMR_TRX 0x10000000
#define UCC_FAST_GUMR_TTX 0x08000000
@@ -46,8 +44,7 @@ typedef enum enet_type {
#define UCC_FAST_GUMR_ENR 0x00000020
#define UCC_FAST_GUMR_ENT 0x00000010
-/* GUMR [MODE] bit maps
-*/
+/* GUMR [MODE] bit maps */
#define UCC_FAST_GUMR_HDLC 0x00000000
#define UCC_FAST_GUMR_QMC 0x00000002
#define UCC_FAST_GUMR_UART 0x00000004
@@ -55,50 +52,54 @@ typedef enum enet_type {
#define UCC_FAST_GUMR_ATM 0x0000000a
#define UCC_FAST_GUMR_ETH 0x0000000c
-/* Transmit On Demand (UTORD)
-*/
+/* Transmit On Demand (UTORD) */
#define UCC_SLOW_TOD 0x8000
#define UCC_FAST_TOD 0x8000
-/* Fast Ethernet (10/100 Mbps)
-*/
-#define UCC_GETH_URFS_INIT 512 /* Rx virtual FIFO size */
-#define UCC_GETH_URFET_INIT 256 /* 1/2 urfs */
-#define UCC_GETH_URFSET_INIT 384 /* 3/4 urfs */
-#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size */
-#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */
+/* Fast Ethernet (10/100 Mbps) */
+/* Rx virtual FIFO size */
+#define UCC_GETH_URFS_INIT 512
+/* 1/2 urfs */
+#define UCC_GETH_URFET_INIT 256
+/* 3/4 urfs */
+#define UCC_GETH_URFSET_INIT 384
+/* Tx virtual FIFO size */
+#define UCC_GETH_UTFS_INIT 512
+/* 1/2 utfs */
+#define UCC_GETH_UTFET_INIT 256
#define UCC_GETH_UTFTT_INIT 128
-/* Gigabit Ethernet (1000 Mbps)
-*/
-#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual FIFO size */
-#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ /* 1/2 urfs */
-#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ /* 3/4 urfs */
-#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ /* Tx virtual FIFO size */
-#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ /* 1/2 utfs */
-#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ /* */
+/* Gigabit Ethernet (1000 Mbps) */
+/* Rx virtual FIFO size */
+#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/
+/* 1/2 urfs */
+#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/
+/* 3/4 urfs */
+#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/
+/* Tx virtual FIFO size */
+#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/
+/* 1/2 utfs */
+#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/
+#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/
-/* UCC fast alignment
-*/
+/* UCC fast alignment */
#define UCC_FAST_RX_ALIGN 4
#define UCC_FAST_MRBLR_ALIGNMENT 4
#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8
-/* Sizes
-*/
+/* Sizes */
#define UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD 8
-/* UCC fast structure.
-*/
-typedef struct ucc_fast_info {
+/* UCC fast structure. */
+struct ucc_fast_inf {
int ucc_num;
qe_clock_e rx_clock;
qe_clock_e tx_clock;
- enet_type_e eth_type;
-} ucc_fast_info_t;
+ enum enet_type eth_type;
+};
-typedef struct ucc_fast_private {
- ucc_fast_info_t *uf_info;
+struct ucc_fast_priv {
+ struct ucc_fast_inf *uf_info;
ucc_fast_t *uf_regs; /* a pointer to memory map of UCC regs */
u32 *p_ucce; /* a pointer to the event register */
u32 *p_uccm; /* a pointer to the mask register */
@@ -106,12 +107,13 @@ typedef struct ucc_fast_private {
int enabled_rx; /* whether UCC is enabled for Rx (ENR) */
u32 ucc_fast_tx_virtual_fifo_base_offset;
u32 ucc_fast_rx_virtual_fifo_base_offset;
-} ucc_fast_private_t;
+};
-void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf);
+void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf);
u32 ucc_fast_get_qe_cr_subblock(int ucc_num);
-void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode);
-void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode);
-int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret);
+void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode);
+void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode);
+int ucc_fast_init(struct ucc_fast_inf *uf_info,
+ struct ucc_fast_priv **uccf_ret);
#endif /* __UCCF_H__ */
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index 0143454387..5da971ddc0 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -20,12 +20,13 @@
#include <fsl_qe.h>
#include <phy.h>
+#if !defined(CONFIG_DM_ETH)
/* Default UTBIPAR SMI address */
#ifndef CONFIG_UTBIPAR_INIT_TBIPA
#define CONFIG_UTBIPAR_INIT_TBIPA 0x1F
#endif
-static uec_info_t uec_info[] = {
+static struct uec_inf uec_info[] = {
#ifdef CONFIG_UEC_ETH1
STD_UEC_INFO(1), /* UEC1 */
#endif
@@ -56,13 +57,13 @@ static uec_info_t uec_info[] = {
static struct eth_device *devlist[MAXCONTROLLERS];
-static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode)
+static int uec_mac_enable(struct uec_priv *uec, comm_dir_e mode)
{
uec_t *uec_regs;
u32 maccfg1;
if (!uec) {
- printf("%s: uec not initial\n", __FUNCTION__);
+ printf("%s: uec not initial\n", __func__);
return -EINVAL;
}
uec_regs = uec->uec_regs;
@@ -84,13 +85,13 @@ static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode)
return 0;
}
-static int uec_mac_disable(uec_private_t *uec, comm_dir_e mode)
+static int uec_mac_disable(struct uec_priv *uec, comm_dir_e mode)
{
uec_t *uec_regs;
u32 maccfg1;
if (!uec) {
- printf("%s: uec not initial\n", __FUNCTION__);
+ printf("%s: uec not initial\n", __func__);
return -EINVAL;
}
uec_regs = uec->uec_regs;
@@ -112,14 +113,14 @@ static int uec_mac_disable(uec_private_t *uec, comm_dir_e mode)
return 0;
}
-static int uec_graceful_stop_tx(uec_private_t *uec)
+static int uec_graceful_stop_tx(struct uec_priv *uec)
{
ucc_fast_t *uf_regs;
u32 cecr_subblock;
u32 ucce;
if (!uec || !uec->uccf) {
- printf("%s: No handle passed.\n", __FUNCTION__);
+ printf("%s: No handle passed.\n", __func__);
return -EINVAL;
}
@@ -132,30 +133,30 @@ static int uec_graceful_stop_tx(uec_private_t *uec)
cecr_subblock =
ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
/* Wait for command to complete */
do {
ucce = in_be32(&uf_regs->ucce);
- } while (! (ucce & UCCE_GRA));
+ } while (!(ucce & UCCE_GRA));
uec->grace_stopped_tx = 1;
return 0;
}
-static int uec_graceful_stop_rx(uec_private_t *uec)
+static int uec_graceful_stop_rx(struct uec_priv *uec)
{
u32 cecr_subblock;
u8 ack;
if (!uec) {
- printf("%s: No handle passed.\n", __FUNCTION__);
+ printf("%s: No handle passed.\n", __func__);
return -EINVAL;
}
if (!uec->p_rx_glbl_pram) {
- printf("%s: No init rx global parameter\n", __FUNCTION__);
+ printf("%s: No init rx global parameter\n", __func__);
return -EINVAL;
}
@@ -170,66 +171,66 @@ static int uec_graceful_stop_rx(uec_private_t *uec)
cecr_subblock =
ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
ack = uec->p_rx_glbl_pram->rxgstpack;
- } while (! (ack & GRACEFUL_STOP_ACKNOWLEDGE_RX ));
+ } while (!(ack & GRACEFUL_STOP_ACKNOWLEDGE_RX));
uec->grace_stopped_rx = 1;
return 0;
}
-static int uec_restart_tx(uec_private_t *uec)
+static int uec_restart_tx(struct uec_priv *uec)
{
u32 cecr_subblock;
if (!uec || !uec->uec_info) {
- printf("%s: No handle passed.\n", __FUNCTION__);
+ printf("%s: No handle passed.\n", __func__);
return -EINVAL;
}
cecr_subblock =
ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
uec->grace_stopped_tx = 0;
return 0;
}
-static int uec_restart_rx(uec_private_t *uec)
+static int uec_restart_rx(struct uec_priv *uec)
{
u32 cecr_subblock;
if (!uec || !uec->uec_info) {
- printf("%s: No handle passed.\n", __FUNCTION__);
+ printf("%s: No handle passed.\n", __func__);
return -EINVAL;
}
cecr_subblock =
ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
qe_issue_cmd(QE_RESTART_RX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_ETHERNET, 0);
+ (u8)QE_CR_PROTOCOL_ETHERNET, 0);
uec->grace_stopped_rx = 0;
return 0;
}
-static int uec_open(uec_private_t *uec, comm_dir_e mode)
+static int uec_open(struct uec_priv *uec, comm_dir_e mode)
{
- ucc_fast_private_t *uccf;
+ struct ucc_fast_priv *uccf;
if (!uec || !uec->uccf) {
- printf("%s: No handle passed.\n", __FUNCTION__);
+ printf("%s: No handle passed.\n", __func__);
return -EINVAL;
}
uccf = uec->uccf;
/* check if the UCC number is in range. */
if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) {
- printf("%s: ucc_num out of range.\n", __FUNCTION__);
+ printf("%s: ucc_num out of range.\n", __func__);
return -EINVAL;
}
@@ -240,36 +241,33 @@ static int uec_open(uec_private_t *uec, comm_dir_e mode)
ucc_fast_enable(uccf, mode);
/* RISC microcode start */
- if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx) {
+ if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx)
uec_restart_tx(uec);
- }
- if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx) {
+ if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx)
uec_restart_rx(uec);
- }
return 0;
}
-static int uec_stop(uec_private_t *uec, comm_dir_e mode)
+static int uec_stop(struct uec_priv *uec, comm_dir_e mode)
{
if (!uec || !uec->uccf) {
- printf("%s: No handle passed.\n", __FUNCTION__);
+ printf("%s: No handle passed.\n", __func__);
return -EINVAL;
}
/* check if the UCC number is in range. */
if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) {
- printf("%s: ucc_num out of range.\n", __FUNCTION__);
+ printf("%s: ucc_num out of range.\n", __func__);
return -EINVAL;
}
/* Stop any transmissions */
- if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx) {
+ if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx)
uec_graceful_stop_tx(uec);
- }
+
/* Stop any receptions */
- if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx) {
+ if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx)
uec_graceful_stop_rx(uec);
- }
/* Disable the UCC fast */
ucc_fast_disable(uec->uccf, mode);
@@ -280,13 +278,13 @@ static int uec_stop(uec_private_t *uec, comm_dir_e mode)
return 0;
}
-static int uec_set_mac_duplex(uec_private_t *uec, int duplex)
+static int uec_set_mac_duplex(struct uec_priv *uec, int duplex)
{
uec_t *uec_regs;
u32 maccfg2;
if (!uec) {
- printf("%s: uec not initial\n", __FUNCTION__);
+ printf("%s: uec not initial\n", __func__);
return -EINVAL;
}
uec_regs = uec->uec_regs;
@@ -306,8 +304,8 @@ static int uec_set_mac_duplex(uec_private_t *uec, int duplex)
return 0;
}
-static int uec_set_mac_if_mode(uec_private_t *uec,
- phy_interface_t if_mode, int speed)
+static int uec_set_mac_if_mode(struct uec_priv *uec,
+ phy_interface_t if_mode, int speed)
{
phy_interface_t enet_if_mode;
uec_t *uec_regs;
@@ -315,7 +313,7 @@ static int uec_set_mac_if_mode(uec_private_t *uec,
u32 maccfg2;
if (!uec) {
- printf("%s: uec not initial\n", __FUNCTION__);
+ printf("%s: uec not initial\n", __func__);
return -EINVAL;
}
@@ -329,66 +327,62 @@ static int uec_set_mac_if_mode(uec_private_t *uec,
upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM);
switch (speed) {
- case SPEED_10:
- maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
- switch (enet_if_mode) {
- case PHY_INTERFACE_MODE_MII:
- break;
- case PHY_INTERFACE_MODE_RGMII:
- upsmr |= (UPSMR_RPM | UPSMR_R10M);
- break;
- case PHY_INTERFACE_MODE_RMII:
- upsmr |= (UPSMR_R10M | UPSMR_RMM);
- break;
- default:
- return -EINVAL;
- break;
- }
+ case SPEED_10:
+ maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
+ switch (enet_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
break;
- case SPEED_100:
- maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
- switch (enet_if_mode) {
- case PHY_INTERFACE_MODE_MII:
- break;
- case PHY_INTERFACE_MODE_RGMII:
- upsmr |= UPSMR_RPM;
- break;
- case PHY_INTERFACE_MODE_RMII:
- upsmr |= UPSMR_RMM;
- break;
- default:
- return -EINVAL;
- break;
- }
+ case PHY_INTERFACE_MODE_RGMII:
+ upsmr |= (UPSMR_RPM | UPSMR_R10M);
break;
- case SPEED_1000:
- maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
- switch (enet_if_mode) {
- case PHY_INTERFACE_MODE_GMII:
- break;
- case PHY_INTERFACE_MODE_TBI:
- upsmr |= UPSMR_TBIM;
- break;
- case PHY_INTERFACE_MODE_RTBI:
- upsmr |= (UPSMR_RPM | UPSMR_TBIM);
- break;
- case PHY_INTERFACE_MODE_RGMII_RXID:
- case PHY_INTERFACE_MODE_RGMII_TXID:
- case PHY_INTERFACE_MODE_RGMII_ID:
- case PHY_INTERFACE_MODE_RGMII:
- upsmr |= UPSMR_RPM;
- break;
- case PHY_INTERFACE_MODE_SGMII:
- upsmr |= UPSMR_SGMM;
- break;
- default:
- return -EINVAL;
- break;
- }
+ case PHY_INTERFACE_MODE_RMII:
+ upsmr |= (UPSMR_R10M | UPSMR_RMM);
break;
default:
return -EINVAL;
+ }
+ break;
+ case SPEED_100:
+ maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
+ switch (enet_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ upsmr |= UPSMR_RPM;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ upsmr |= UPSMR_RMM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SPEED_1000:
+ maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
+ switch (enet_if_mode) {
+ case PHY_INTERFACE_MODE_GMII:
+ break;
+ case PHY_INTERFACE_MODE_TBI:
+ upsmr |= UPSMR_TBIM;
+ break;
+ case PHY_INTERFACE_MODE_RTBI:
+ upsmr |= (UPSMR_RPM | UPSMR_TBIM);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII:
+ upsmr |= UPSMR_RPM;
break;
+ case PHY_INTERFACE_MODE_SGMII:
+ upsmr |= UPSMR_SGMM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
}
out_be32(&uec_regs->maccfg2, maccfg2);
@@ -407,9 +401,10 @@ static int init_mii_management_configuration(uec_mii_t *uec_mii_regs)
out_be32(&uec_mii_regs->miimcfg, miimcfg);
/* Wait until the bus is free */
- while ((in_be32(&uec_mii_regs->miimcfg) & MIIMIND_BUSY) && timeout--);
+ while ((in_be32(&uec_mii_regs->miimcfg) & MIIMIND_BUSY) && timeout--)
+ ;
if (timeout <= 0) {
- printf("%s: The MII Bus is stuck!", __FUNCTION__);
+ printf("%s: The MII Bus is stuck!", __func__);
return -ETIMEDOUT;
}
@@ -418,13 +413,13 @@ static int init_mii_management_configuration(uec_mii_t *uec_mii_regs)
static int init_phy(struct eth_device *dev)
{
- uec_private_t *uec;
+ struct uec_priv *uec;
uec_mii_t *umii_regs;
struct uec_mii_info *mii_info;
struct phy_info *curphy;
int err;
- uec = (uec_private_t *)dev->priv;
+ uec = (struct uec_priv *)dev->priv;
umii_regs = uec->uec_mii_regs;
uec->oldlink = 0;
@@ -438,11 +433,10 @@ static int init_phy(struct eth_device *dev)
}
memset(mii_info, 0, sizeof(*mii_info));
- if (uec->uec_info->uf_info.eth_type == GIGA_ETH) {
+ if (uec->uec_info->uf_info.eth_type == GIGA_ETH)
mii_info->speed = SPEED_1000;
- } else {
+ else
mii_info->speed = SPEED_100;
- }
mii_info->duplex = DUPLEX_FULL;
mii_info->pause = 0;
@@ -498,15 +492,14 @@ bus_fail:
static void adjust_link(struct eth_device *dev)
{
- uec_private_t *uec = (uec_private_t *)dev->priv;
+ struct uec_priv *uec = (struct uec_priv *)dev->priv;
struct uec_mii_info *mii_info = uec->mii_info;
- extern void change_phy_interface_mode(struct eth_device *dev,
- phy_interface_t mode, int speed);
-
if (mii_info->link) {
- /* Now we make sure that we can be in full duplex mode.
- * If not, we operate in half-duplex mode. */
+ /*
+ * Now we make sure that we can be in full duplex mode.
+ * If not, we operate in half-duplex mode.
+ */
if (mii_info->duplex != uec->oldduplex) {
if (!(mii_info->duplex)) {
uec_set_mac_duplex(uec, DUPLEX_HALF);
@@ -526,16 +519,16 @@ static void adjust_link(struct eth_device *dev)
case SPEED_1000:
break;
case SPEED_100:
- printf ("switching to rgmii 100\n");
+ printf("switching to rgmii 100\n");
mode = PHY_INTERFACE_MODE_RGMII;
break;
case SPEED_10:
- printf ("switching to rgmii 10\n");
+ printf("switching to rgmii 10\n");
mode = PHY_INTERFACE_MODE_RGMII;
break;
default:
printf("%s: Ack,Speed(%d)is illegal\n",
- dev->name, mii_info->speed);
+ dev->name, mii_info->speed);
break;
}
}
@@ -566,12 +559,12 @@ static void adjust_link(struct eth_device *dev)
static void phy_change(struct eth_device *dev)
{
- uec_private_t *uec = (uec_private_t *)dev->priv;
+ struct uec_priv *uec = (struct uec_priv *)dev->priv;
#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
- /* QE9 and QE12 need to be set for enabling QE MII managment signals */
+ /* QE9 and QE12 need to be set for enabling QE MII management signals */
setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9);
setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
#endif
@@ -604,14 +597,14 @@ static int uec_miiphy_find_dev_by_name(const char *devname)
int i;
for (i = 0; i < MAXCONTROLLERS; i++) {
- if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0) {
+ if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0)
break;
- }
}
/* If device cannot be found, returns -1 */
if (i == MAXCONTROLLERS) {
- debug ("%s: device %s not found in devlist\n", __FUNCTION__, devname);
+ debug("%s: device %s not found in devlist\n", __func__,
+ devname);
i = -1;
}
@@ -629,13 +622,12 @@ static int uec_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
unsigned short value = 0;
int devindex = 0;
- if (bus->name == NULL) {
- debug("%s: NULL pointer given\n", __FUNCTION__);
+ if (!bus->name) {
+ debug("%s: NULL pointer given\n", __func__);
} else {
devindex = uec_miiphy_find_dev_by_name(bus->name);
- if (devindex >= 0) {
+ if (devindex >= 0)
value = uec_read_phy_reg(devlist[devindex], addr, reg);
- }
}
return value;
}
@@ -651,36 +643,37 @@ static int uec_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
{
int devindex = 0;
- if (bus->name == NULL) {
- debug("%s: NULL pointer given\n", __FUNCTION__);
+ if (!bus->name) {
+ debug("%s: NULL pointer given\n", __func__);
} else {
devindex = uec_miiphy_find_dev_by_name(bus->name);
- if (devindex >= 0) {
+ if (devindex >= 0)
uec_write_phy_reg(devlist[devindex], addr, reg, value);
- }
}
return 0;
}
#endif
-static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
+static int uec_set_mac_address(struct uec_priv *uec, u8 *mac_addr)
{
uec_t *uec_regs;
u32 mac_addr1;
u32 mac_addr2;
if (!uec) {
- printf("%s: uec not initial\n", __FUNCTION__);
+ printf("%s: uec not initial\n", __func__);
return -EINVAL;
}
uec_regs = uec->uec_regs;
- /* if a station address of 0x12345678ABCD, perform a write to
- MACSTNADDR1 of 0xCDAB7856,
- MACSTNADDR2 of 0x34120000 */
+ /*
+ * if a station address of 0x12345678ABCD, perform a write to
+ * MACSTNADDR1 of 0xCDAB7856,
+ * MACSTNADDR2 of 0x34120000
+ */
- mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \
+ mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) |
(mac_addr[3] << 8) | (mac_addr[2]);
out_be32(&uec_regs->macstnaddr1, mac_addr1);
@@ -690,31 +683,31 @@ static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
return 0;
}
-static int uec_convert_threads_num(uec_num_of_threads_e threads_num,
- int *threads_num_ret)
+static int uec_convert_threads_num(enum uec_num_of_threads threads_num,
+ int *threads_num_ret)
{
int num_threads_numerica;
switch (threads_num) {
- case UEC_NUM_OF_THREADS_1:
- num_threads_numerica = 1;
- break;
- case UEC_NUM_OF_THREADS_2:
- num_threads_numerica = 2;
- break;
- case UEC_NUM_OF_THREADS_4:
- num_threads_numerica = 4;
- break;
- case UEC_NUM_OF_THREADS_6:
- num_threads_numerica = 6;
- break;
- case UEC_NUM_OF_THREADS_8:
- num_threads_numerica = 8;
- break;
- default:
- printf("%s: Bad number of threads value.",
- __FUNCTION__);
- return -EINVAL;
+ case UEC_NUM_OF_THREADS_1:
+ num_threads_numerica = 1;
+ break;
+ case UEC_NUM_OF_THREADS_2:
+ num_threads_numerica = 2;
+ break;
+ case UEC_NUM_OF_THREADS_4:
+ num_threads_numerica = 4;
+ break;
+ case UEC_NUM_OF_THREADS_6:
+ num_threads_numerica = 6;
+ break;
+ case UEC_NUM_OF_THREADS_8:
+ num_threads_numerica = 8;
+ break;
+ default:
+ printf("%s: Bad number of threads value.",
+ __func__);
+ return -EINVAL;
}
*threads_num_ret = num_threads_numerica;
@@ -722,9 +715,9 @@ static int uec_convert_threads_num(uec_num_of_threads_e threads_num,
return 0;
}
-static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx)
+static void uec_init_tx_parameter(struct uec_priv *uec, int num_threads_tx)
{
- uec_info_t *uec_info;
+ struct uec_inf *uec_info;
u32 end_bd;
u8 bmrx = 0;
int i;
@@ -732,14 +725,14 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx)
uec_info = uec->uec_info;
/* Alloc global Tx parameter RAM page */
- uec->tx_glbl_pram_offset = qe_muram_alloc(
- sizeof(uec_tx_global_pram_t),
- UEC_TX_GLOBAL_PRAM_ALIGNMENT);
- uec->p_tx_glbl_pram = (uec_tx_global_pram_t *)
+ uec->tx_glbl_pram_offset =
+ qe_muram_alloc(sizeof(struct uec_tx_global_pram),
+ UEC_TX_GLOBAL_PRAM_ALIGNMENT);
+ uec->p_tx_glbl_pram = (struct uec_tx_global_pram *)
qe_muram_addr(uec->tx_glbl_pram_offset);
/* Zero the global Tx prameter RAM */
- memset(uec->p_tx_glbl_pram, 0, sizeof(uec_tx_global_pram_t));
+ memset(uec->p_tx_glbl_pram, 0, sizeof(struct uec_tx_global_pram));
/* Init global Tx parameter RAM */
@@ -747,10 +740,10 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx)
out_be16(&uec->p_tx_glbl_pram->temoder, TEMODER_INIT_VALUE);
/* SQPTR */
- uec->send_q_mem_reg_offset = qe_muram_alloc(
- sizeof(uec_send_queue_qd_t),
- UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
- uec->p_send_q_mem_reg = (uec_send_queue_mem_region_t *)
+ uec->send_q_mem_reg_offset =
+ qe_muram_alloc(sizeof(struct uec_send_queue_qd),
+ UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
+ uec->p_send_q_mem_reg = (struct uec_send_queue_mem_region *)
qe_muram_addr(uec->send_q_mem_reg_offset);
out_be32(&uec->p_tx_glbl_pram->sqptr, uec->send_q_mem_reg_offset);
@@ -758,9 +751,9 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx)
end_bd = (u32)uec->p_tx_bd_ring + (uec_info->tx_bd_ring_len - 1)
* SIZEOFBD;
out_be32(&uec->p_send_q_mem_reg->sqqd[0].bd_ring_base,
- (u32)(uec->p_tx_bd_ring));
+ (u32)(uec->p_tx_bd_ring));
out_be32(&uec->p_send_q_mem_reg->sqqd[0].last_bd_completed_address,
- end_bd);
+ end_bd);
/* Scheduler Base Pointer, we have only one Tx queue, no need it */
out_be32(&uec->p_tx_glbl_pram->schedulerbasepointer, 0);
@@ -773,54 +766,57 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx)
out_be32(&uec->p_tx_glbl_pram->tstate, ((u32)(bmrx) << BMR_SHIFT));
/* IPH_Offset */
- for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++) {
+ for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++)
out_8(&uec->p_tx_glbl_pram->iphoffset[i], 0);
- }
/* VTAG table */
- for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++) {
+ for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++)
out_be32(&uec->p_tx_glbl_pram->vtagtable[i], 0);
- }
/* TQPTR */
- uec->thread_dat_tx_offset = qe_muram_alloc(
- num_threads_tx * sizeof(uec_thread_data_tx_t) +
- 32 *(num_threads_tx == 1), UEC_THREAD_DATA_ALIGNMENT);
+ uec->thread_dat_tx_offset =
+ qe_muram_alloc(num_threads_tx *
+ sizeof(struct uec_thread_data_tx) +
+ 32 * (num_threads_tx == 1),
+ UEC_THREAD_DATA_ALIGNMENT);
- uec->p_thread_data_tx = (uec_thread_data_tx_t *)
+ uec->p_thread_data_tx = (struct uec_thread_data_tx *)
qe_muram_addr(uec->thread_dat_tx_offset);
out_be32(&uec->p_tx_glbl_pram->tqptr, uec->thread_dat_tx_offset);
}
-static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx)
+static void uec_init_rx_parameter(struct uec_priv *uec, int num_threads_rx)
{
u8 bmrx = 0;
int i;
- uec_82xx_address_filtering_pram_t *p_af_pram;
+ struct uec_82xx_add_filtering_pram *p_af_pram;
/* Allocate global Rx parameter RAM page */
- uec->rx_glbl_pram_offset = qe_muram_alloc(
- sizeof(uec_rx_global_pram_t), UEC_RX_GLOBAL_PRAM_ALIGNMENT);
- uec->p_rx_glbl_pram = (uec_rx_global_pram_t *)
+ uec->rx_glbl_pram_offset =
+ qe_muram_alloc(sizeof(struct uec_rx_global_pram),
+ UEC_RX_GLOBAL_PRAM_ALIGNMENT);
+ uec->p_rx_glbl_pram = (struct uec_rx_global_pram *)
qe_muram_addr(uec->rx_glbl_pram_offset);
/* Zero Global Rx parameter RAM */
- memset(uec->p_rx_glbl_pram, 0, sizeof(uec_rx_global_pram_t));
+ memset(uec->p_rx_glbl_pram, 0, sizeof(struct uec_rx_global_pram));
/* Init global Rx parameter RAM */
- /* REMODER, Extended feature mode disable, VLAN disable,
- LossLess flow control disable, Receive firmware statisic disable,
- Extended address parsing mode disable, One Rx queues,
- Dynamic maximum/minimum frame length disable, IP checksum check
- disable, IP address alignment disable
- */
+ /*
+ * REMODER, Extended feature mode disable, VLAN disable,
+ * LossLess flow control disable, Receive firmware statisic disable,
+ * Extended address parsing mode disable, One Rx queues,
+ * Dynamic maximum/minimum frame length disable, IP checksum check
+ * disable, IP address alignment disable
+ */
out_be32(&uec->p_rx_glbl_pram->remoder, REMODER_INIT_VALUE);
/* RQPTR */
- uec->thread_dat_rx_offset = qe_muram_alloc(
- num_threads_rx * sizeof(uec_thread_data_rx_t),
- UEC_THREAD_DATA_ALIGNMENT);
- uec->p_thread_data_rx = (uec_thread_data_rx_t *)
+ uec->thread_dat_rx_offset =
+ qe_muram_alloc(num_threads_rx *
+ sizeof(struct uec_thread_data_rx),
+ UEC_THREAD_DATA_ALIGNMENT);
+ uec->p_thread_data_rx = (struct uec_thread_data_rx *)
qe_muram_addr(uec->thread_dat_rx_offset);
out_be32(&uec->p_rx_glbl_pram->rqptr, uec->thread_dat_rx_offset);
@@ -841,16 +837,16 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx)
out_be16(&uec->p_rx_glbl_pram->mrblr, MAX_RXBUF_LEN);
/* RBDQPTR */
- uec->rx_bd_qs_tbl_offset = qe_muram_alloc(
- sizeof(uec_rx_bd_queues_entry_t) + \
- sizeof(uec_rx_prefetched_bds_t),
- UEC_RX_BD_QUEUES_ALIGNMENT);
- uec->p_rx_bd_qs_tbl = (uec_rx_bd_queues_entry_t *)
+ uec->rx_bd_qs_tbl_offset =
+ qe_muram_alloc(sizeof(struct uec_rx_bd_queues_entry) +
+ sizeof(struct uec_rx_pref_bds),
+ UEC_RX_BD_QUEUES_ALIGNMENT);
+ uec->p_rx_bd_qs_tbl = (struct uec_rx_bd_queues_entry *)
qe_muram_addr(uec->rx_bd_qs_tbl_offset);
/* Zero it */
- memset(uec->p_rx_bd_qs_tbl, 0, sizeof(uec_rx_bd_queues_entry_t) + \
- sizeof(uec_rx_prefetched_bds_t));
+ memset(uec->p_rx_bd_qs_tbl, 0, sizeof(struct uec_rx_bd_queues_entry) +
+ sizeof(struct uec_rx_pref_bds));
out_be32(&uec->p_rx_glbl_pram->rbdqptr, uec->rx_bd_qs_tbl_offset);
out_be32(&uec->p_rx_bd_qs_tbl->externalbdbaseptr,
(u32)uec->p_rx_bd_ring);
@@ -868,9 +864,8 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx)
/* L2QT */
out_be32(&uec->p_rx_glbl_pram->l2qt, 0);
/* L3QT */
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
out_be32(&uec->p_rx_glbl_pram->l3qt[i], 0);
- }
/* VLAN_TYPE */
out_be16(&uec->p_rx_glbl_pram->vlantype, 0x8100);
@@ -878,7 +873,7 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx)
out_be16(&uec->p_rx_glbl_pram->vlantci, 0);
/* Clear PQ2 style address filtering hash table */
- p_af_pram = (uec_82xx_address_filtering_pram_t *) \
+ p_af_pram = (struct uec_82xx_add_filtering_pram *)
uec->p_rx_glbl_pram->addressfiltering;
p_af_pram->iaddr_h = 0;
@@ -887,30 +882,33 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx)
p_af_pram->gaddr_l = 0;
}
-static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec,
- int thread_tx, int thread_rx)
+static int uec_issue_init_enet_rxtx_cmd(struct uec_priv *uec,
+ int thread_tx, int thread_rx)
{
- uec_init_cmd_pram_t *p_init_enet_param;
+ struct uec_init_cmd_pram *p_init_enet_param;
u32 init_enet_param_offset;
- uec_info_t *uec_info;
+ struct uec_inf *uec_info;
+ struct ucc_fast_inf *uf_info;
int i;
int snum;
- u32 init_enet_offset;
+ u32 off;
u32 entry_val;
u32 command;
u32 cecr_subblock;
uec_info = uec->uec_info;
+ uf_info = &uec_info->uf_info;
/* Allocate init enet command parameter */
- uec->init_enet_param_offset = qe_muram_alloc(
- sizeof(uec_init_cmd_pram_t), 4);
+ uec->init_enet_param_offset =
+ qe_muram_alloc(sizeof(struct uec_init_cmd_pram), 4);
init_enet_param_offset = uec->init_enet_param_offset;
- uec->p_init_enet_param = (uec_init_cmd_pram_t *)
+ uec->p_init_enet_param = (struct uec_init_cmd_pram *)
qe_muram_addr(uec->init_enet_param_offset);
/* Zero init enet command struct */
- memset((void *)uec->p_init_enet_param, 0, sizeof(uec_init_cmd_pram_t));
+ memset((void *)uec->p_init_enet_param, 0,
+ sizeof(struct uec_init_cmd_pram));
/* Init the command struct */
p_init_enet_param = uec->p_init_enet_param;
@@ -932,21 +930,21 @@ static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec,
/* Init Rx threads */
for (i = 0; i < (thread_rx + 1); i++) {
- if ((snum = qe_get_snum()) < 0) {
- printf("%s can not get snum\n", __FUNCTION__);
+ snum = qe_get_snum();
+ if (snum < 0) {
+ printf("%s can not get snum\n", __func__);
return -ENOMEM;
}
- if (i==0) {
- init_enet_offset = 0;
+ if (i == 0) {
+ off = 0;
} else {
- init_enet_offset = qe_muram_alloc(
- sizeof(uec_thread_rx_pram_t),
- UEC_THREAD_RX_PRAM_ALIGNMENT);
+ off = qe_muram_alloc(sizeof(struct uec_thread_rx_pram),
+ UEC_THREAD_RX_PRAM_ALIGNMENT);
}
entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) |
- init_enet_offset | (u32)uec_info->risc_rx;
+ off | (u32)uec_info->risc_rx;
p_init_enet_param->rxthread[i] = entry_val;
}
@@ -956,16 +954,17 @@ static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec,
/* Init Tx threads */
for (i = 0; i < thread_tx; i++) {
- if ((snum = qe_get_snum()) < 0) {
- printf("%s can not get snum\n", __FUNCTION__);
+ snum = qe_get_snum();
+ if (snum < 0) {
+ printf("%s can not get snum\n", __func__);
return -ENOMEM;
}
- init_enet_offset = qe_muram_alloc(sizeof(uec_thread_tx_pram_t),
- UEC_THREAD_TX_PRAM_ALIGNMENT);
+ off = qe_muram_alloc(sizeof(struct uec_thread_tx_pram),
+ UEC_THREAD_TX_PRAM_ALIGNMENT);
entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) |
- init_enet_offset | (u32)uec_info->risc_tx;
+ off | (u32)uec_info->risc_tx;
p_init_enet_param->txthread[i] = entry_val;
}
@@ -973,19 +972,18 @@ static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec,
/* Issue QE command */
command = QE_INIT_TX_RX;
- cecr_subblock = ucc_fast_get_qe_cr_subblock(
- uec->uec_info->uf_info.ucc_num);
- qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
- init_enet_param_offset);
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
+ qe_issue_cmd(command, cecr_subblock, (u8)QE_CR_PROTOCOL_ETHERNET,
+ init_enet_param_offset);
return 0;
}
-static int uec_startup(uec_private_t *uec)
+static int uec_startup(struct uec_priv *uec)
{
- uec_info_t *uec_info;
- ucc_fast_info_t *uf_info;
- ucc_fast_private_t *uccf;
+ struct uec_inf *uec_info;
+ struct ucc_fast_inf *uf_info;
+ struct ucc_fast_priv *uccf;
ucc_fast_t *uf_regs;
uec_t *uec_regs;
int num_threads_tx;
@@ -993,37 +991,37 @@ static int uec_startup(uec_private_t *uec)
u32 utbipar;
u32 length;
u32 align;
- qe_bd_t *bd;
+ struct buffer_descriptor *bd;
u8 *buf;
int i;
if (!uec || !uec->uec_info) {
- printf("%s: uec or uec_info not initial\n", __FUNCTION__);
+ printf("%s: uec or uec_info not initial\n", __func__);
return -EINVAL;
}
uec_info = uec->uec_info;
- uf_info = &(uec_info->uf_info);
+ uf_info = &uec_info->uf_info;
/* Check if Rx BD ring len is illegal */
- if ((uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN) || \
- (uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT)) {
+ if (uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN ||
+ (uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT)) {
printf("%s: Rx BD ring len must be multiple of 4, and > 8.\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
/* Check if Tx BD ring len is illegal */
if (uec_info->tx_bd_ring_len < UEC_TX_BD_RING_SIZE_MIN) {
printf("%s: Tx BD ring length must not be smaller than 2.\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
/* Check if MRBLR is illegal */
- if ((MAX_RXBUF_LEN == 0) || (MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT)) {
+ if (MAX_RXBUF_LEN == 0 || MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT) {
printf("%s: max rx buffer length must be mutliple of 128.\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
@@ -1033,7 +1031,7 @@ static int uec_startup(uec_private_t *uec)
/* Init UCC fast */
if (ucc_fast_init(uf_info, &uccf)) {
- printf("%s: failed to init ucc fast\n", __FUNCTION__);
+ printf("%s: failed to init ucc fast\n", __func__);
return -ENOMEM;
}
@@ -1042,13 +1040,13 @@ static int uec_startup(uec_private_t *uec)
/* Convert the Tx threads number */
if (uec_convert_threads_num(uec_info->num_threads_tx,
- &num_threads_tx)) {
+ &num_threads_tx)) {
return -EINVAL;
}
/* Convert the Rx threads number */
if (uec_convert_threads_num(uec_info->num_threads_rx,
- &num_threads_rx)) {
+ &num_threads_rx)) {
return -EINVAL;
}
@@ -1070,13 +1068,14 @@ static int uec_startup(uec_private_t *uec)
out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE);
/* Setup MAC interface mode */
- uec_set_mac_if_mode(uec, uec_info->enet_interface_type, uec_info->speed);
+ uec_set_mac_if_mode(uec, uec_info->enet_interface_type,
+ uec_info->speed);
/* Setup MII management base */
#ifndef CONFIG_eTSEC_MDIO_BUS
uec->uec_mii_regs = (uec_mii_t *)(&uec_regs->miimcfg);
#else
- uec->uec_mii_regs = (uec_mii_t *) CONFIG_MIIM_ADDRESS;
+ uec->uec_mii_regs = (uec_mii_t *)CONFIG_MIIM_ADDRESS;
#endif
/* Setup MII master clock source */
@@ -1093,16 +1092,16 @@ static int uec_startup(uec_private_t *uec)
out_be32(&uec_regs->utbipar, utbipar);
/* Configure the TBI for SGMII operation */
- if ((uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII) &&
- (uec->uec_info->speed == SPEED_1000)) {
+ if (uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII &&
+ uec->uec_info->speed == SPEED_1000) {
uec_write_phy_reg(uec->dev, uec_regs->utbipar,
- ENET_TBI_MII_ANA, TBIANA_SETTINGS);
+ ENET_TBI_MII_ANA, TBIANA_SETTINGS);
uec_write_phy_reg(uec->dev, uec_regs->utbipar,
- ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
+ ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
uec_write_phy_reg(uec->dev, uec_regs->utbipar,
- ENET_TBI_MII_CR, TBICR_SETTINGS);
+ ENET_TBI_MII_CR, TBICR_SETTINGS);
}
/* Allocate Tx BDs */
@@ -1149,29 +1148,29 @@ static int uec_startup(uec_private_t *uec)
memset((void *)(uec->rx_buf_offset), 0, length + align);
/* Init TxBD ring */
- bd = (qe_bd_t *)uec->p_tx_bd_ring;
- uec->txBd = bd;
+ bd = (struct buffer_descriptor *)uec->p_tx_bd_ring;
+ uec->tx_bd = bd;
for (i = 0; i < uec_info->tx_bd_ring_len; i++) {
BD_DATA_CLEAR(bd);
BD_STATUS_SET(bd, 0);
BD_LENGTH_SET(bd, 0);
- bd ++;
+ bd++;
}
- BD_STATUS_SET((--bd), TxBD_WRAP);
+ BD_STATUS_SET((--bd), TX_BD_WRAP);
/* Init RxBD ring */
- bd = (qe_bd_t *)uec->p_rx_bd_ring;
- uec->rxBd = bd;
+ bd = (struct buffer_descriptor *)uec->p_rx_bd_ring;
+ uec->rx_bd = bd;
buf = uec->p_rx_buf;
for (i = 0; i < uec_info->rx_bd_ring_len; i++) {
BD_DATA_SET(bd, buf);
BD_LENGTH_SET(bd, 0);
- BD_STATUS_SET(bd, RxBD_EMPTY);
+ BD_STATUS_SET(bd, RX_BD_EMPTY);
buf += MAX_RXBUF_LEN;
- bd ++;
+ bd++;
}
- BD_STATUS_SET((--bd), RxBD_WRAP | RxBD_EMPTY);
+ BD_STATUS_SET((--bd), RX_BD_WRAP | RX_BD_EMPTY);
/* Init global Tx parameter RAM */
uec_init_tx_parameter(uec, num_threads_tx);
@@ -1182,29 +1181,32 @@ static int uec_startup(uec_private_t *uec)
/* Init ethernet Tx and Rx parameter command */
if (uec_issue_init_enet_rxtx_cmd(uec, num_threads_tx,
num_threads_rx)) {
- printf("%s issue init enet cmd failed\n", __FUNCTION__);
+ printf("%s issue init enet cmd failed\n", __func__);
return -ENOMEM;
}
return 0;
}
-static int uec_init(struct eth_device* dev, struct bd_info *bd)
+static int uec_init(struct eth_device *dev, struct bd_info *bd)
{
- uec_private_t *uec;
+ struct uec_priv *uec;
int err, i;
struct phy_info *curphy;
#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
- uec = (uec_private_t *)dev->priv;
+ uec = (struct uec_priv *)dev->priv;
- if (uec->the_first_run == 0) {
+ if (!uec->the_first_run) {
#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
- /* QE9 and QE12 need to be set for enabling QE MII managment signals */
- setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9);
- setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
+ /*
+ * QE9 and QE12 need to be set for enabling QE MII
+ * management signals
+ */
+ setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9);
+ setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
#endif
err = init_phy(dev);
@@ -1230,7 +1232,7 @@ static int uec_init(struct eth_device* dev, struct bd_info *bd)
err = curphy->read_status(uec->mii_info);
if (!(((i-- > 0) && !uec->mii_info->link) || err))
break;
- udelay(100000);
+ mdelay(100);
} while (1);
#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
@@ -1248,12 +1250,11 @@ static int uec_init(struct eth_device* dev, struct bd_info *bd)
/* Set up the MAC address */
if (dev->enetaddr[0] & 0x01) {
printf("%s: MacAddress is multcast address\n",
- __FUNCTION__);
+ __func__);
return -1;
}
uec_set_mac_address(uec, dev->enetaddr);
-
err = uec_open(uec, COMM_DIR_RX_AND_TX);
if (err) {
printf("%s: cannot enable UEC device\n", dev->name);
@@ -1262,30 +1263,31 @@ static int uec_init(struct eth_device* dev, struct bd_info *bd)
phy_change(dev);
- return (uec->mii_info->link ? 0 : -1);
+ return uec->mii_info->link ? 0 : -1;
}
-static void uec_halt(struct eth_device* dev)
+static void uec_halt(struct eth_device *dev)
{
- uec_private_t *uec = (uec_private_t *)dev->priv;
+ struct uec_priv *uec = (struct uec_priv *)dev->priv;
+
uec_stop(uec, COMM_DIR_RX_AND_TX);
}
static int uec_send(struct eth_device *dev, void *buf, int len)
{
- uec_private_t *uec;
- ucc_fast_private_t *uccf;
- volatile qe_bd_t *bd;
+ struct uec_priv *uec;
+ struct ucc_fast_priv *uccf;
+ struct buffer_descriptor *bd;
u16 status;
int i;
int result = 0;
- uec = (uec_private_t *)dev->priv;
+ uec = (struct uec_priv *)dev->priv;
uccf = uec->uccf;
- bd = uec->txBd;
+ bd = uec->tx_bd;
/* Find an empty TxBD */
- for (i = 0; bd->status & TxBD_READY; i++) {
+ for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) {
if (i > 0x100000) {
printf("%s: tx buffer not ready\n", dev->name);
return result;
@@ -1295,16 +1297,16 @@ static int uec_send(struct eth_device *dev, void *buf, int len)
/* Init TxBD */
BD_DATA_SET(bd, buf);
BD_LENGTH_SET(bd, len);
- status = bd->status;
+ status = BD_STATUS(bd);
status &= BD_WRAP;
- status |= (TxBD_READY | TxBD_LAST);
+ status |= (TX_BD_READY | TX_BD_LAST);
BD_STATUS_SET(bd, status);
/* Tell UCC to transmit the buffer */
ucc_fast_transmit_on_demand(uccf);
/* Wait for buffer to be transmitted */
- for (i = 0; bd->status & TxBD_READY; i++) {
+ for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) {
if (i > 0x100000) {
printf("%s: tx error\n", dev->name);
return result;
@@ -1313,25 +1315,25 @@ static int uec_send(struct eth_device *dev, void *buf, int len)
/* Ok, the buffer be transimitted */
BD_ADVANCE(bd, status, uec->p_tx_bd_ring);
- uec->txBd = bd;
+ uec->tx_bd = bd;
result = 1;
return result;
}
-static int uec_recv(struct eth_device* dev)
+static int uec_recv(struct eth_device *dev)
{
- uec_private_t *uec = dev->priv;
- volatile qe_bd_t *bd;
+ struct uec_priv *uec = dev->priv;
+ struct buffer_descriptor *bd;
u16 status;
u16 len;
u8 *data;
- bd = uec->rxBd;
- status = bd->status;
+ bd = uec->rx_bd;
+ status = BD_STATUS(bd);
- while (!(status & RxBD_EMPTY)) {
- if (!(status & RxBD_ERROR)) {
+ while (!(status & RX_BD_EMPTY)) {
+ if (!(status & RX_BD_ERROR)) {
data = BD_DATA(bd);
len = BD_LENGTH(bd);
net_process_received_packet(data, len);
@@ -1340,20 +1342,20 @@ static int uec_recv(struct eth_device* dev)
}
status &= BD_CLEAN;
BD_LENGTH_SET(bd, 0);
- BD_STATUS_SET(bd, status | RxBD_EMPTY);
+ BD_STATUS_SET(bd, status | RX_BD_EMPTY);
BD_ADVANCE(bd, status, uec->p_rx_bd_ring);
- status = bd->status;
+ status = BD_STATUS(bd);
}
- uec->rxBd = bd;
+ uec->rx_bd = bd;
return 1;
}
-int uec_initialize(struct bd_info *bis, uec_info_t *uec_info)
+int uec_initialize(struct bd_info *bis, struct uec_inf *uec_info)
{
struct eth_device *dev;
int i;
- uec_private_t *uec;
+ struct uec_priv *uec;
int err;
dev = (struct eth_device *)malloc(sizeof(struct eth_device));
@@ -1362,11 +1364,11 @@ int uec_initialize(struct bd_info *bis, uec_info_t *uec_info)
memset(dev, 0, sizeof(struct eth_device));
/* Allocate the UEC private struct */
- uec = (uec_private_t *)malloc(sizeof(uec_private_t));
- if (!uec) {
+ uec = (struct uec_priv *)malloc(sizeof(struct uec_priv));
+ if (!uec)
return -ENOMEM;
- }
- memset(uec, 0, sizeof(uec_private_t));
+
+ memset(uec, 0, sizeof(struct uec_priv));
/* Adjust uec_info */
#if (MAX_QE_RISC == 4)
@@ -1395,13 +1397,14 @@ int uec_initialize(struct bd_info *bis, uec_info_t *uec_info)
err = uec_startup(uec);
if (err) {
- printf("%s: Cannot configure net device, aborting.",dev->name);
+ printf("%s: Cannot configure net device, aborting.", dev->name);
return err;
}
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
int retval;
struct mii_dev *mdiodev = mdio_alloc();
+
if (!mdiodev)
return -ENOMEM;
strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
@@ -1416,7 +1419,7 @@ int uec_initialize(struct bd_info *bis, uec_info_t *uec_info)
return 1;
}
-int uec_eth_init(struct bd_info *bis, uec_info_t *uecs, int num)
+int uec_eth_init(struct bd_info *bis, struct uec_inf *uecs, int num)
{
int i;
@@ -1430,3 +1433,4 @@ int uec_standard_init(struct bd_info *bis)
{
return uec_eth_init(bis, uec_info, ARRAY_SIZE(uec_info));
}
+#endif
diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h
index 6de2ac44f8..83461c024c 100644
--- a/drivers/qe/uec.h
+++ b/drivers/qe/uec.h
@@ -76,8 +76,7 @@
#define MACCFG2_INIT_VALUE (MACCFG2_PREL | MACCFG2_RESERVED_1 | \
MACCFG2_LC | MACCFG2_PAD_CRC | MACCFG2_FDX)
-/* UEC Event Register
-*/
+/* UEC Event Register */
#define UCCE_MPD 0x80000000
#define UCCE_SCAR 0x40000000
#define UCCE_GRA 0x20000000
@@ -120,26 +119,24 @@
#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY | \
UCCE_RXC | UCCE_TXC | UCCE_TXE)
-/* UEC TEMODR Register
-*/
+/* UEC TEMODR Register */
#define TEMODER_SCHEDULER_ENABLE 0x2000
#define TEMODER_IP_CHECKSUM_GENERATE 0x0400
#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200
#define TEMODER_RMON_STATISTICS 0x0100
-#define TEMODER_NUM_OF_QUEUES_SHIFT (15-15)
+#define TEMODER_NUM_OF_QUEUES_SHIFT (15 - 15)
#define TEMODER_INIT_VALUE 0xc000
-/* UEC REMODR Register
-*/
+/* UEC REMODR Register */
#define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000
#define REMODER_RX_EXTENDED_FEATURES 0x80000000
-#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31-9 )
-#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31-10)
-#define REMODER_RX_QOS_MODE_SHIFT (31-15)
+#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31 - 9)
+#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31 - 10)
+#define REMODER_RX_QOS_MODE_SHIFT (31 - 15)
#define REMODER_RMON_STATISTICS 0x00001000
#define REMODER_RX_EXTENDED_FILTERING 0x00000800
-#define REMODER_NUM_OF_QUEUES_SHIFT (31-23)
+#define REMODER_NUM_OF_QUEUES_SHIFT (31 - 23)
#define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008
#define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004
#define REMODER_IP_CHECKSUM_CHECK 0x00000002
@@ -213,35 +210,31 @@
#define UESCR_SCOV_SHIFT (15 - 15)
/****** Tx data struct collection ******/
-/* Tx thread data, each Tx thread has one this struct.
-*/
-typedef struct uec_thread_data_tx {
+/* Tx thread data, each Tx thread has one this struct. */
+struct uec_thread_data_tx {
u8 res0[136];
-} __attribute__ ((packed)) uec_thread_data_tx_t;
+} __packed;
-/* Tx thread parameter, each Tx thread has one this struct.
-*/
-typedef struct uec_thread_tx_pram {
+/* Tx thread parameter, each Tx thread has one this struct. */
+struct uec_thread_tx_pram {
u8 res0[64];
-} __attribute__ ((packed)) uec_thread_tx_pram_t;
+} __packed;
-/* Send queue queue-descriptor, each Tx queue has one this QD
-*/
-typedef struct uec_send_queue_qd {
+/* Send queue queue-descriptor, each Tx queue has one this QD */
+struct uec_send_queue_qd {
u32 bd_ring_base; /* pointer to BD ring base address */
u8 res0[0x8];
u32 last_bd_completed_address; /* last entry in BD ring */
u8 res1[0x30];
-} __attribute__ ((packed)) uec_send_queue_qd_t;
+} __packed;
/* Send queue memory region */
-typedef struct uec_send_queue_mem_region {
- uec_send_queue_qd_t sqqd[MAX_TX_QUEUES];
-} __attribute__ ((packed)) uec_send_queue_mem_region_t;
+struct uec_send_queue_mem_region {
+ struct uec_send_queue_qd sqqd[MAX_TX_QUEUES];
+} __packed;
-/* Scheduler struct
-*/
-typedef struct uec_scheduler {
+/* Scheduler struct */
+struct uec_scheduler {
u16 cpucount0; /* CPU packet counter */
u16 cpucount1; /* CPU packet counter */
u16 cecount0; /* QE packet counter */
@@ -272,12 +265,11 @@ typedef struct uec_scheduler {
u8 oldwfqmask; /* temporary variable handled by QE */
u8 weightfactor[MAX_TX_QUEUES]; /**< weight factor for queues */
u32 minw; /* temporary variable handled by QE */
- u8 res1[0x70-0x64];
-} __attribute__ ((packed)) uec_scheduler_t;
+ u8 res1[0x70 - 0x64];
+} __packed;
-/* Tx firmware counters
-*/
-typedef struct uec_tx_firmware_statistics_pram {
+/* Tx firmware counters */
+struct uec_tx_firmware_statistics_pram {
u32 sicoltx; /* single collision */
u32 mulcoltx; /* multiple collision */
u32 latecoltxfr; /* late collision */
@@ -290,13 +282,12 @@ typedef struct uec_tx_firmware_statistics_pram {
u32 txpkts512; /* total packets(including bad) 512~1023B */
u32 txpkts1024; /* total packets(including bad) 1024~1518B */
u32 txpktsjumbo; /* total packets(including bad) >1024 */
-} __attribute__ ((packed)) uec_tx_firmware_statistics_pram_t;
+} __packed;
-/* Tx global parameter table
-*/
-typedef struct uec_tx_global_pram {
+/* Tx global parameter table */
+struct uec_tx_global_pram {
u16 temoder;
- u8 res0[0x38-0x02];
+ u8 res0[0x38 - 0x02];
u32 sqptr;
u32 schedulerbasepointer;
u32 txrmonbaseptr;
@@ -304,26 +295,22 @@ typedef struct uec_tx_global_pram {
u8 iphoffset[MAX_IPH_OFFSET_ENTRY];
u32 vtagtable[0x8];
u32 tqptr;
- u8 res2[0x80-0x74];
-} __attribute__ ((packed)) uec_tx_global_pram_t;
-
+ u8 res2[0x80 - 0x74];
+} __packed;
/****** Rx data struct collection ******/
-/* Rx thread data, each Rx thread has one this struct.
-*/
-typedef struct uec_thread_data_rx {
+/* Rx thread data, each Rx thread has one this struct. */
+struct uec_thread_data_rx {
u8 res0[40];
-} __attribute__ ((packed)) uec_thread_data_rx_t;
+} __packed;
-/* Rx thread parameter, each Rx thread has one this struct.
-*/
-typedef struct uec_thread_rx_pram {
+/* Rx thread parameter, each Rx thread has one this struct. */
+struct uec_thread_rx_pram {
u8 res0[128];
-} __attribute__ ((packed)) uec_thread_rx_pram_t;
+} __packed;
-/* Rx firmware counters
-*/
-typedef struct uec_rx_firmware_statistics_pram {
+/* Rx firmware counters */
+struct uec_rx_firmware_statistics_pram {
u32 frrxfcser; /* frames with crc error */
u32 fraligner; /* frames with alignment error */
u32 inrangelenrxer; /* in range length error */
@@ -346,44 +333,41 @@ typedef struct uec_rx_firmware_statistics_pram {
u32 removevlan;
u32 replacevlan;
u32 insertvlan;
-} __attribute__ ((packed)) uec_rx_firmware_statistics_pram_t;
+} __packed;
-/* Rx interrupt coalescing entry, each Rx queue has one this entry.
-*/
-typedef struct uec_rx_interrupt_coalescing_entry {
+/* Rx interrupt coalescing entry, each Rx queue has one this entry. */
+struct uec_rx_interrupt_coalescing_entry {
u32 maxvalue;
u32 counter;
-} __attribute__ ((packed)) uec_rx_interrupt_coalescing_entry_t;
+} __packed;
-typedef struct uec_rx_interrupt_coalescing_table {
- uec_rx_interrupt_coalescing_entry_t entry[MAX_RX_QUEUES];
-} __attribute__ ((packed)) uec_rx_interrupt_coalescing_table_t;
+struct uec_rx_interrupt_coalescing_table {
+ struct uec_rx_interrupt_coalescing_entry entry[MAX_RX_QUEUES];
+} __packed;
-/* RxBD queue entry, each Rx queue has one this entry.
-*/
-typedef struct uec_rx_bd_queues_entry {
+/* RxBD queue entry, each Rx queue has one this entry. */
+struct uec_rx_bd_queues_entry {
u32 bdbaseptr; /* BD base pointer */
u32 bdptr; /* BD pointer */
u32 externalbdbaseptr; /* external BD base pointer */
u32 externalbdptr; /* external BD pointer */
-} __attribute__ ((packed)) uec_rx_bd_queues_entry_t;
+} __packed;
-/* Rx global paramter table
-*/
-typedef struct uec_rx_global_pram {
+/* Rx global parameter table */
+struct uec_rx_global_pram {
u32 remoder; /* ethernet mode reg. */
u32 rqptr; /* base pointer to the Rx Queues */
u32 res0[0x1];
- u8 res1[0x20-0xC];
+ u8 res1[0x20 - 0xc];
u16 typeorlen;
u8 res2[0x1];
u8 rxgstpack; /* ack on GRACEFUL STOP RX command */
u32 rxrmonbaseptr; /* Rx RMON statistics base */
- u8 res3[0x30-0x28];
+ u8 res3[0x30 - 0x28];
u32 intcoalescingptr; /* Interrupt coalescing table pointer */
- u8 res4[0x36-0x34];
+ u8 res4[0x36 - 0x34];
u8 rstate;
- u8 res5[0x46-0x37];
+ u8 res5[0x46 - 0x37];
u16 mrblr; /* max receive buffer length reg. */
u32 rbdqptr; /* RxBD parameter table description */
u16 mflr; /* max frame length reg. */
@@ -396,17 +380,15 @@ typedef struct uec_rx_global_pram {
u16 vlantype; /* vlan type */
u16 vlantci; /* default vlan tci */
u8 addressfiltering[64];/* address filtering data structure */
- u32 exfGlobalParam; /* extended filtering global parameters */
- u8 res6[0x100-0xC4]; /* Initialize to zero */
-} __attribute__ ((packed)) uec_rx_global_pram_t;
+ u32 exf_global_param; /* extended filtering global parameters */
+ u8 res6[0x100 - 0xc4]; /* Initialize to zero */
+} __packed;
#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01
-
/****** UEC common ******/
-/* UCC statistics - hardware counters
-*/
-typedef struct uec_hardware_statistics {
+/* UCC statistics - hardware counters */
+struct uec_hardware_statistics {
u32 tx64;
u32 tx127;
u32 tx255;
@@ -422,11 +404,10 @@ typedef struct uec_hardware_statistics {
u32 rbyt;
u32 rmca;
u32 rbca;
-} __attribute__ ((packed)) uec_hardware_statistics_t;
+} __packed;
-/* InitEnet command parameter
-*/
-typedef struct uec_init_cmd_pram {
+/* InitEnet command parameter */
+struct uec_init_cmd_pram {
u8 resinit0;
u8 resinit1;
u8 resinit2;
@@ -440,7 +421,7 @@ typedef struct uec_init_cmd_pram {
u32 txglobal; /* tx global */
u32 txthread[MAX_ENET_INIT_PARAM_ENTRIES_TX]; /* tx threads */
u8 res3[0x1];
-} __attribute__ ((packed)) uec_init_cmd_pram_t;
+} __packed;
#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4)
#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8)
@@ -456,105 +437,96 @@ typedef struct uec_init_cmd_pram {
#define ENET_INIT_PARAM_MAGIC_RES_INIT3 0x00
#define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x0400
-/* structure representing 82xx Address Filtering Enet Address in PRAM
-*/
-typedef struct uec_82xx_enet_address {
+/* structure representing 82xx Address Filtering Enet Address in PRAM */
+struct uec_82xx_enet_addr {
u8 res1[0x2];
u16 h; /* address (MSB) */
u16 m; /* address */
u16 l; /* address (LSB) */
-} __attribute__ ((packed)) uec_82xx_enet_address_t;
+} __packed;
-/* structure representing 82xx Address Filtering PRAM
-*/
-typedef struct uec_82xx_address_filtering_pram {
+/* structure representing 82xx Address Filtering PRAM */
+struct uec_82xx_add_filtering_pram {
u32 iaddr_h; /* individual address filter, high */
u32 iaddr_l; /* individual address filter, low */
u32 gaddr_h; /* group address filter, high */
u32 gaddr_l; /* group address filter, low */
- uec_82xx_enet_address_t taddr;
- uec_82xx_enet_address_t paddr[4];
- u8 res0[0x40-0x38];
-} __attribute__ ((packed)) uec_82xx_address_filtering_pram_t;
-
-/* Buffer Descriptor
-*/
-typedef struct buffer_descriptor {
+ struct uec_82xx_enet_addr taddr;
+ struct uec_82xx_enet_addr paddr[4];
+ u8 res0[0x40 - 0x38];
+} __packed;
+
+/* Buffer Descriptor */
+struct buffer_descriptor {
u16 status;
u16 len;
u32 data;
-} __attribute__ ((packed)) qe_bd_t, *p_bd_t;
+} __packed;
-#define SIZEOFBD sizeof(qe_bd_t)
+#define SIZEOFBD sizeof(struct buffer_descriptor)
-/* Common BD flags
-*/
+/* Common BD flags */
#define BD_WRAP 0x2000
#define BD_INT 0x1000
#define BD_LAST 0x0800
#define BD_CLEAN 0x3000
-/* TxBD status flags
-*/
-#define TxBD_READY 0x8000
-#define TxBD_PADCRC 0x4000
-#define TxBD_WRAP BD_WRAP
-#define TxBD_INT BD_INT
-#define TxBD_LAST BD_LAST
-#define TxBD_TXCRC 0x0400
-#define TxBD_DEF 0x0200
-#define TxBD_PP 0x0100
-#define TxBD_LC 0x0080
-#define TxBD_RL 0x0040
-#define TxBD_RC 0x003C
-#define TxBD_UNDERRUN 0x0002
-#define TxBD_TRUNC 0x0001
-
-#define TxBD_ERROR (TxBD_UNDERRUN | TxBD_TRUNC)
-
-/* RxBD status flags
-*/
-#define RxBD_EMPTY 0x8000
-#define RxBD_OWNER 0x4000
-#define RxBD_WRAP BD_WRAP
-#define RxBD_INT BD_INT
-#define RxBD_LAST BD_LAST
-#define RxBD_FIRST 0x0400
-#define RxBD_CMR 0x0200
-#define RxBD_MISS 0x0100
-#define RxBD_BCAST 0x0080
-#define RxBD_MCAST 0x0040
-#define RxBD_LG 0x0020
-#define RxBD_NO 0x0010
-#define RxBD_SHORT 0x0008
-#define RxBD_CRCERR 0x0004
-#define RxBD_OVERRUN 0x0002
-#define RxBD_IPCH 0x0001
-
-#define RxBD_ERROR (RxBD_LG | RxBD_NO | RxBD_SHORT | \
- RxBD_CRCERR | RxBD_OVERRUN)
-
-/* BD access macros
-*/
-#define BD_STATUS(_bd) (((p_bd_t)(_bd))->status)
-#define BD_STATUS_SET(_bd, _val) (((p_bd_t)(_bd))->status = _val)
-#define BD_LENGTH(_bd) (((p_bd_t)(_bd))->len)
-#define BD_LENGTH_SET(_bd, _val) (((p_bd_t)(_bd))->len = _val)
-#define BD_DATA_CLEAR(_bd) (((p_bd_t)(_bd))->data = 0)
-#define BD_IS_DATA(_bd) (((p_bd_t)(_bd))->data)
-#define BD_DATA(_bd) ((u8 *)(((p_bd_t)(_bd))->data))
-#define BD_DATA_SET(_bd, _data) (((p_bd_t)(_bd))->data = (u32)(_data))
-#define BD_ADVANCE(_bd,_status,_base) \
- (((_status) & BD_WRAP) ? (_bd) = ((p_bd_t)(_base)) : ++(_bd))
-
-/* Rx Prefetched BDs
-*/
-typedef struct uec_rx_prefetched_bds {
- qe_bd_t bd[MAX_PREFETCHED_BDS]; /* prefetched bd */
-} __attribute__ ((packed)) uec_rx_prefetched_bds_t;
-
-/* Alignments
- */
+/* TxBD status flags */
+#define TX_BD_READY 0x8000
+#define TX_BD_PADCRC 0x4000
+#define TX_BD_WRAP BD_WRAP
+#define TX_BD_INT BD_INT
+#define TX_BD_LAST BD_LAST
+#define TX_BD_TXCRC 0x0400
+#define TX_BD_DEF 0x0200
+#define TX_BD_PP 0x0100
+#define TX_BD_LC 0x0080
+#define TX_BD_RL 0x0040
+#define TX_BD_RC 0x003C
+#define TX_BD_UNDERRUN 0x0002
+#define TX_BD_TRUNC 0x0001
+
+#define TX_BD_ERROR (TX_BD_UNDERRUN | TX_BD_TRUNC)
+
+/* RxBD status flags */
+#define RX_BD_EMPTY 0x8000
+#define RX_BD_OWNER 0x4000
+#define RX_BD_WRAP BD_WRAP
+#define RX_BD_INT BD_INT
+#define RX_BD_LAST BD_LAST
+#define RX_BD_FIRST 0x0400
+#define RX_BD_CMR 0x0200
+#define RX_BD_MISS 0x0100
+#define RX_BD_BCAST 0x0080
+#define RX_BD_MCAST 0x0040
+#define RX_BD_LG 0x0020
+#define RX_BD_NO 0x0010
+#define RX_BD_SHORT 0x0008
+#define RX_BD_CRCERR 0x0004
+#define RX_BD_OVERRUN 0x0002
+#define RX_BD_IPCH 0x0001
+
+#define RX_BD_ERROR (RX_BD_LG | RX_BD_NO | RX_BD_SHORT | \
+ RX_BD_CRCERR | RX_BD_OVERRUN)
+
+/* BD access macros */
+#define BD_STATUS(_bd) (in_be16(&((_bd)->status)))
+#define BD_STATUS_SET(_bd, _v) (out_be16(&((_bd)->status), _v))
+#define BD_LENGTH(_bd) (in_be16(&((_bd)->len)))
+#define BD_LENGTH_SET(_bd, _v) (out_be16(&((_bd)->len), _v))
+#define BD_DATA_CLEAR(_bd) (out_be32(&((_bd)->data), 0))
+#define BD_DATA(_bd) ((u8 *)(((_bd)->data)))
+#define BD_DATA_SET(_bd, _data) (out_be32(&((_bd)->data), (u32)_data))
+#define BD_ADVANCE(_bd, _status, _base) \
+ (((_status) & BD_WRAP) ? (_bd) = \
+ ((struct buffer_descriptor *)(_base)) : ++(_bd))
+
+/* Rx Prefetched BDs */
+struct uec_rx_pref_bds {
+ struct buffer_descriptor bd[MAX_PREFETCHED_BDS]; /* prefetched bd */
+} __packed;
+
+/* Alignments */
#define UEC_RX_GLOBAL_PRAM_ALIGNMENT 64
#define UEC_TX_GLOBAL_PRAM_ALIGNMENT 64
#define UEC_THREAD_RX_PRAM_ALIGNMENT 128
@@ -581,25 +553,8 @@ typedef struct uec_rx_prefetched_bds {
#define UEC_RX_BD_RING_SIZE_MIN 8
#define UEC_TX_BD_RING_SIZE_MIN 2
-/* Ethernet speed
-*/
-typedef enum enet_speed {
- ENET_SPEED_10BT, /* 10 Base T */
- ENET_SPEED_100BT, /* 100 Base T */
- ENET_SPEED_1000BT /* 1000 Base T */
-} enet_speed_e;
-
-/* Ethernet Address Type.
-*/
-typedef enum enet_addr_type {
- ENET_ADDR_TYPE_INDIVIDUAL,
- ENET_ADDR_TYPE_GROUP,
- ENET_ADDR_TYPE_BROADCAST
-} enet_addr_type_e;
-
-/* TBI / MII Set Register
-*/
-typedef enum enet_tbi_mii_reg {
+/* TBI / MII Set Register */
+enum enet_tbi_mii_reg {
ENET_TBI_MII_CR = 0x00,
ENET_TBI_MII_SR = 0x01,
ENET_TBI_MII_ANA = 0x04,
@@ -610,7 +565,7 @@ typedef enum enet_tbi_mii_reg {
ENET_TBI_MII_EXST = 0x0F,
ENET_TBI_MII_JD = 0x10,
ENET_TBI_MII_TBICON = 0x11
-} enet_tbi_mii_reg_e;
+};
/* TBI MDIO register bit fields*/
#define TBICON_CLK_SELECT 0x0020
@@ -637,18 +592,16 @@ typedef enum enet_tbi_mii_reg {
| TBICR_SPEED1_SET \
)
-/* UEC number of threads
-*/
-typedef enum uec_num_of_threads {
+/* UEC number of threads */
+enum uec_num_of_threads {
UEC_NUM_OF_THREADS_1 = 0x1, /* 1 */
UEC_NUM_OF_THREADS_2 = 0x2, /* 2 */
UEC_NUM_OF_THREADS_4 = 0x0, /* 4 */
UEC_NUM_OF_THREADS_6 = 0x3, /* 6 */
UEC_NUM_OF_THREADS_8 = 0x4 /* 8 */
-} uec_num_of_threads_e;
+};
-/* UEC initialization info struct
-*/
+/* UEC initialization info struct */
#define STD_UEC_INFO(num) \
{ \
.uf_info = { \
@@ -668,10 +621,10 @@ typedef enum uec_num_of_threads {
.speed = CONFIG_SYS_UEC##num##_INTERFACE_SPEED, \
}
-typedef struct uec_info {
- ucc_fast_info_t uf_info;
- uec_num_of_threads_e num_threads_tx;
- uec_num_of_threads_e num_threads_rx;
+struct uec_inf {
+ struct ucc_fast_inf uf_info;
+ enum uec_num_of_threads num_threads_tx;
+ enum uec_num_of_threads num_threads_rx;
unsigned int risc_tx;
unsigned int risc_rx;
u16 rx_bd_ring_len;
@@ -679,39 +632,37 @@ typedef struct uec_info {
u8 phy_address;
phy_interface_t enet_interface_type;
int speed;
-} uec_info_t;
+};
-/* UEC driver initialized info
-*/
+/* UEC driver initialized info */
#define MAX_RXBUF_LEN 1536
#define MAX_FRAME_LEN 1518
#define MIN_FRAME_LEN 64
#define MAX_DMA1_LEN 1520
#define MAX_DMA2_LEN 1520
-/* UEC driver private struct
-*/
-typedef struct uec_private {
- uec_info_t *uec_info;
- ucc_fast_private_t *uccf;
+/* UEC driver private struct */
+struct uec_priv {
+ struct uec_inf *uec_info;
+ struct ucc_fast_priv *uccf;
struct eth_device *dev;
uec_t *uec_regs;
uec_mii_t *uec_mii_regs;
/* enet init command parameter */
- uec_init_cmd_pram_t *p_init_enet_param;
+ struct uec_init_cmd_pram *p_init_enet_param;
u32 init_enet_param_offset;
- /* Rx and Tx paramter */
- uec_rx_global_pram_t *p_rx_glbl_pram;
+ /* Rx and Tx parameter */
+ struct uec_rx_global_pram *p_rx_glbl_pram;
u32 rx_glbl_pram_offset;
- uec_tx_global_pram_t *p_tx_glbl_pram;
+ struct uec_tx_global_pram *p_tx_glbl_pram;
u32 tx_glbl_pram_offset;
- uec_send_queue_mem_region_t *p_send_q_mem_reg;
+ struct uec_send_queue_mem_region *p_send_q_mem_reg;
u32 send_q_mem_reg_offset;
- uec_thread_data_tx_t *p_thread_data_tx;
+ struct uec_thread_data_tx *p_thread_data_tx;
u32 thread_dat_tx_offset;
- uec_thread_data_rx_t *p_thread_data_rx;
+ struct uec_thread_data_rx *p_thread_data_rx;
u32 thread_dat_rx_offset;
- uec_rx_bd_queues_entry_t *p_rx_bd_qs_tbl;
+ struct uec_rx_bd_queues_entry *p_rx_bd_qs_tbl;
u32 rx_bd_qs_tbl_offset;
/* BDs specific */
u8 *p_tx_bd_ring;
@@ -720,8 +671,8 @@ typedef struct uec_private {
u32 rx_bd_ring_offset;
u8 *p_rx_buf;
u32 rx_buf_offset;
- volatile qe_bd_t *txBd;
- volatile qe_bd_t *rxBd;
+ struct buffer_descriptor *tx_bd;
+ struct buffer_descriptor *rx_bd;
/* Status */
int mac_tx_enabled;
int mac_rx_enabled;
@@ -733,9 +684,9 @@ typedef struct uec_private {
int oldspeed;
int oldduplex;
int oldlink;
-} uec_private_t;
+};
-int uec_initialize(struct bd_info *bis, uec_info_t *uec_info);
-int uec_eth_init(struct bd_info *bis, uec_info_t *uecs, int num);
+int uec_initialize(struct bd_info *bis, struct uec_inf *uec_info);
+int uec_eth_init(struct bd_info *bis, struct uec_inf *uecs, int num);
int uec_standard_init(struct bd_info *bis);
#endif /* __UEC_H__ */
diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c
index 69c22dd5e2..9d429c832f 100644
--- a/drivers/qe/uec_phy.c
+++ b/drivers/qe/uec_phy.c
@@ -23,17 +23,19 @@
#include <fsl_qe.h>
#include <phy.h>
+#if !defined(CONFIG_DM_ETH)
+
#define ugphy_printk(format, arg...) \
printf(format "\n", ## arg)
#define ugphy_dbg(format, arg...) \
- ugphy_printk(format , ## arg)
+ ugphy_printk(format, ## arg)
#define ugphy_err(format, arg...) \
- ugphy_printk(format , ## arg)
+ ugphy_printk(format, ## arg)
#define ugphy_info(format, arg...) \
- ugphy_printk(format , ## arg)
+ ugphy_printk(format, ## arg)
#define ugphy_warn(format, arg...) \
- ugphy_printk(format , ## arg)
+ ugphy_printk(format, ## arg)
#ifdef UEC_VERBOSE_DEBUG
#define ugphy_vdbg ugphy_dbg
@@ -41,13 +43,13 @@
#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
#endif /* UEC_VERBOSE_DEBUG */
-/*--------------------------------------------------------------------+
+/*
+ * --------------------------------------------------------------------
* Fixed PHY (PHY-less) support for Ethernet Ports.
*
* Copied from arch/powerpc/cpu/ppc4xx/4xx_enet.c
- *--------------------------------------------------------------------*/
-
-/*
+ *--------------------------------------------------------------------
+ *
* Some boards do not have a PHY for each ethernet port. These ports are known
* as Fixed PHY (or PHY-less) ports. For such ports, set the appropriate
* CONFIG_SYS_UECx_PHY_ADDR equal to CONFIG_FIXED_PHY_ADDR (an unused address)
@@ -90,54 +92,58 @@ static const struct fixed_phy_port fixed_phy_port[] = {
CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
};
-/*--------------------------------------------------------------------+
+/*
+ * -------------------------------------------------------------------
* BitBang MII support for ethernet ports
*
* Based from MPC8560ADS implementation
- *--------------------------------------------------------------------*/
-/*
+ *--------------------------------------------------------------------
+ *
* Example board header file to define bitbang ethernet ports:
*
* #define CONFIG_SYS_BITBANG_PHY_PORT(name) name,
* #define CONFIG_SYS_BITBANG_PHY_PORTS CONFIG_SYS_BITBANG_PHY_PORT("UEC0")
-*/
+ */
#ifndef CONFIG_SYS_BITBANG_PHY_PORTS
#define CONFIG_SYS_BITBANG_PHY_PORTS /* default is an empty array */
#endif
#if defined(CONFIG_BITBANGMII)
-static const char *bitbang_phy_port[] = {
+static const char * const bitbang_phy_port[] = {
CONFIG_SYS_BITBANG_PHY_PORTS /* defined in board configuration file */
};
#endif /* CONFIG_BITBANGMII */
-static void config_genmii_advert (struct uec_mii_info *mii_info);
-static void genmii_setup_forced (struct uec_mii_info *mii_info);
-static void genmii_restart_aneg (struct uec_mii_info *mii_info);
-static int gbit_config_aneg (struct uec_mii_info *mii_info);
-static int genmii_config_aneg (struct uec_mii_info *mii_info);
-static int genmii_update_link (struct uec_mii_info *mii_info);
-static int genmii_read_status (struct uec_mii_info *mii_info);
-u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum);
-void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val);
-
-/* Write value to the PHY for this device to the register at regnum, */
-/* waiting until the write is done before it returns. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int value)
-{
- uec_private_t *ugeth = (uec_private_t *) dev->priv;
+static void config_genmii_advert(struct uec_mii_info *mii_info);
+static void genmii_setup_forced(struct uec_mii_info *mii_info);
+static void genmii_restart_aneg(struct uec_mii_info *mii_info);
+static int gbit_config_aneg(struct uec_mii_info *mii_info);
+static int genmii_config_aneg(struct uec_mii_info *mii_info);
+static int genmii_update_link(struct uec_mii_info *mii_info);
+static int genmii_read_status(struct uec_mii_info *mii_info);
+static u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum);
+static void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum,
+ u16 val);
+
+/*
+ * Write value to the PHY for this device to the register at regnum,
+ * waiting until the write is done before it returns. All PHY
+ * configuration has to be done through the TSEC1 MIIM regs
+ */
+void uec_write_phy_reg(struct eth_device *dev, int mii_id, int regnum,
+ int value)
+{
+ struct uec_priv *ugeth = (struct uec_priv *)dev->priv;
uec_mii_t *ug_regs;
- enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+ enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg)regnum;
u32 tmp_reg;
-
#if defined(CONFIG_BITBANGMII)
u32 i = 0;
for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
if (strncmp(dev->name, bitbang_phy_port[i],
- sizeof(dev->name)) == 0) {
+ sizeof(dev->name)) == 0) {
(void)bb_miiphy_write(NULL, mii_id, regnum, value);
return;
}
@@ -148,46 +154,48 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu
/* Stop the MII management read cycle */
out_be32 (&ug_regs->miimcom, 0);
- /* Setting up the MII Mangement Address Register */
- tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+ /* Setting up the MII Management Address Register */
+ tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
out_be32 (&ug_regs->miimadd, tmp_reg);
- /* Setting up the MII Mangement Control Register with the value */
- out_be32 (&ug_regs->miimcon, (u32) value);
+ /* Setting up the MII Management Control Register with the value */
+ out_be32 (&ug_regs->miimcon, (u32)value);
sync();
/* Wait till MII management write is complete */
- while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
+ while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY)
+ ;
}
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value. Clears miimcom first. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
+/*
+ * Reads from register regnum in the PHY for device dev,
+ * returning the value. Clears miimcom first. All PHY
+ * configuration has to be done through the TSEC1 MIIM regs
+ */
+int uec_read_phy_reg(struct eth_device *dev, int mii_id, int regnum)
{
- uec_private_t *ugeth = (uec_private_t *) dev->priv;
+ struct uec_priv *ugeth = (struct uec_priv *)dev->priv;
uec_mii_t *ug_regs;
- enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+ enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg)regnum;
u32 tmp_reg;
u16 value;
-
#if defined(CONFIG_BITBANGMII)
u32 i = 0;
for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
if (strncmp(dev->name, bitbang_phy_port[i],
- sizeof(dev->name)) == 0) {
+ sizeof(dev->name)) == 0) {
(void)bb_miiphy_read(NULL, mii_id, regnum, &value);
- return (value);
+ return value;
}
}
#endif /* CONFIG_BITBANGMII */
ug_regs = ugeth->uec_mii_regs;
- /* Setting up the MII Mangement Address Register */
- tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+ /* Setting up the MII Management Address Register */
+ tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
out_be32 (&ug_regs->miimadd, tmp_reg);
/* clear MII management command cycle */
@@ -199,37 +207,38 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
/* Wait till MII management write is complete */
while ((in_be32 (&ug_regs->miimind)) &
- (MIIMIND_NOT_VALID | MIIMIND_BUSY));
+ (MIIMIND_NOT_VALID | MIIMIND_BUSY))
+ ;
/* Read MII management status */
- value = (u16) in_be32 (&ug_regs->miimstat);
+ value = (u16)in_be32 (&ug_regs->miimstat);
if (value == 0xffff)
ugphy_vdbg
("read wrong value : mii_id %d,mii_reg %d, base %08x",
- mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
+ mii_id, mii_reg, (u32)&ug_regs->miimcfg);
- return (value);
+ return value;
}
-void mii_clear_phy_interrupt (struct uec_mii_info *mii_info)
+void mii_clear_phy_interrupt(struct uec_mii_info *mii_info)
{
if (mii_info->phyinfo->ack_interrupt)
- mii_info->phyinfo->ack_interrupt (mii_info);
+ mii_info->phyinfo->ack_interrupt(mii_info);
}
-void mii_configure_phy_interrupt (struct uec_mii_info *mii_info,
- u32 interrupts)
+void mii_configure_phy_interrupt(struct uec_mii_info *mii_info,
+ u32 interrupts)
{
mii_info->interrupts = interrupts;
if (mii_info->phyinfo->config_intr)
- mii_info->phyinfo->config_intr (mii_info);
+ mii_info->phyinfo->config_intr(mii_info);
}
/* Writes MII_ADVERTISE with the appropriate values, after
* sanitizing advertise to make sure only supported features
* are advertised
*/
-static void config_genmii_advert (struct uec_mii_info *mii_info)
+static void config_genmii_advert(struct uec_mii_info *mii_info)
{
u32 advertise;
u16 adv;
@@ -252,7 +261,7 @@ static void config_genmii_advert (struct uec_mii_info *mii_info)
uec_phy_write(mii_info, MII_ADVERTISE, adv);
}
-static void genmii_setup_forced (struct uec_mii_info *mii_info)
+static void genmii_setup_forced(struct uec_mii_info *mii_info)
{
u16 ctrl;
u32 features = mii_info->phyinfo->features;
@@ -283,7 +292,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info)
| SUPPORTED_10baseT_Full))
break;
default: /* Unsupported speed! */
- ugphy_err ("%s: Bad speed!", mii_info->dev->name);
+ ugphy_err("%s: Bad speed!", mii_info->dev->name);
break;
}
@@ -291,7 +300,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info)
}
/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg (struct uec_mii_info *mii_info)
+static void genmii_restart_aneg(struct uec_mii_info *mii_info)
{
u16 ctl;
@@ -300,14 +309,14 @@ static void genmii_restart_aneg (struct uec_mii_info *mii_info)
uec_phy_write(mii_info, MII_BMCR, ctl);
}
-static int gbit_config_aneg (struct uec_mii_info *mii_info)
+static int gbit_config_aneg(struct uec_mii_info *mii_info)
{
u16 adv;
u32 advertise;
if (mii_info->autoneg) {
/* Configure the ADVERTISE register */
- config_genmii_advert (mii_info);
+ config_genmii_advert(mii_info);
advertise = mii_info->advertising;
adv = uec_phy_read(mii_info, MII_CTRL1000);
@@ -320,18 +329,21 @@ static int gbit_config_aneg (struct uec_mii_info *mii_info)
uec_phy_write(mii_info, MII_CTRL1000, adv);
/* Start/Restart aneg */
- genmii_restart_aneg (mii_info);
- } else
- genmii_setup_forced (mii_info);
+ genmii_restart_aneg(mii_info);
+ } else {
+ genmii_setup_forced(mii_info);
+ }
return 0;
}
-static int marvell_config_aneg (struct uec_mii_info *mii_info)
+static int marvell_config_aneg(struct uec_mii_info *mii_info)
{
- /* The Marvell PHY has an errata which requires
+ /*
+ * The Marvell PHY has an errata which requires
* that certain registers get written in order
- * to restart autonegotiation */
+ * to restart autonegotiation
+ */
uec_phy_write(mii_info, MII_BMCR, BMCR_RESET);
uec_phy_write(mii_info, 0x1d, 0x1f);
@@ -340,16 +352,18 @@ static int marvell_config_aneg (struct uec_mii_info *mii_info)
uec_phy_write(mii_info, 0x1e, 0);
uec_phy_write(mii_info, 0x1e, 0x100);
- gbit_config_aneg (mii_info);
+ gbit_config_aneg(mii_info);
return 0;
}
-static int genmii_config_aneg (struct uec_mii_info *mii_info)
+static int genmii_config_aneg(struct uec_mii_info *mii_info)
{
if (mii_info->autoneg) {
- /* Speed up the common case, if link is already up, speed and
- duplex match, skip auto neg as it already matches */
+ /*
+ * Speed up the common case, if link is already up, speed and
+ * duplex match, skip auto neg as it already matches
+ */
if (!genmii_read_status(mii_info) && mii_info->link)
if (mii_info->duplex == DUPLEX_FULL &&
mii_info->speed == SPEED_100)
@@ -357,15 +371,16 @@ static int genmii_config_aneg (struct uec_mii_info *mii_info)
ADVERTISED_100baseT_Full)
return 0;
- config_genmii_advert (mii_info);
- genmii_restart_aneg (mii_info);
- } else
- genmii_setup_forced (mii_info);
+ config_genmii_advert(mii_info);
+ genmii_restart_aneg(mii_info);
+ } else {
+ genmii_setup_forced(mii_info);
+ }
return 0;
}
-static int genmii_update_link (struct uec_mii_info *mii_info)
+static int genmii_update_link(struct uec_mii_info *mii_info)
{
u16 status;
@@ -377,8 +392,8 @@ static int genmii_update_link (struct uec_mii_info *mii_info)
* (ie - we're capable and it's not done)
*/
status = uec_phy_read(mii_info, MII_BMSR);
- if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE)
- && !(status & BMSR_ANEGCOMPLETE)) {
+ if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE) &&
+ !(status & BMSR_ANEGCOMPLETE)) {
int i = 0;
while (!(status & BMSR_ANEGCOMPLETE)) {
@@ -405,14 +420,13 @@ static int genmii_update_link (struct uec_mii_info *mii_info)
return 0;
}
-static int genmii_read_status (struct uec_mii_info *mii_info)
+static int genmii_read_status(struct uec_mii_info *mii_info)
{
u16 status;
int err;
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link (mii_info);
+ /* Update the link, but return if there was an error */
+ err = genmii_update_link(mii_info);
if (err)
return err;
@@ -449,13 +463,13 @@ static int genmii_read_status (struct uec_mii_info *mii_info)
static int bcm_init(struct uec_mii_info *mii_info)
{
struct eth_device *edev = mii_info->dev;
- uec_private_t *uec = edev->priv;
+ struct uec_priv *uec = edev->priv;
gbit_config_aneg(mii_info);
- if ((uec->uec_info->enet_interface_type ==
- PHY_INTERFACE_MODE_RGMII_RXID) &&
- (uec->uec_info->speed == SPEED_1000)) {
+ if (uec->uec_info->enet_interface_type ==
+ PHY_INTERFACE_MODE_RGMII_RXID &&
+ uec->uec_info->speed == SPEED_1000) {
u16 val;
int cnt = 50;
@@ -476,18 +490,18 @@ static int bcm_init(struct uec_mii_info *mii_info)
uec_phy_write(mii_info, 0x18, val);
}
- return 0;
+ return 0;
}
static int uec_marvell_init(struct uec_mii_info *mii_info)
{
struct eth_device *edev = mii_info->dev;
- uec_private_t *uec = edev->priv;
+ struct uec_priv *uec = edev->priv;
phy_interface_t iface = uec->uec_info->enet_interface_type;
int speed = uec->uec_info->speed;
- if ((speed == SPEED_1000) &&
- (iface == PHY_INTERFACE_MODE_RGMII_ID ||
+ if (speed == SPEED_1000 &&
+ (iface == PHY_INTERFACE_MODE_RGMII_ID ||
iface == PHY_INTERFACE_MODE_RGMII_RXID ||
iface == PHY_INTERFACE_MODE_RGMII_TXID)) {
int temp;
@@ -515,20 +529,21 @@ static int uec_marvell_init(struct uec_mii_info *mii_info)
return 0;
}
-static int marvell_read_status (struct uec_mii_info *mii_info)
+static int marvell_read_status(struct uec_mii_info *mii_info)
{
u16 status;
int err;
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link (mii_info);
+ /* Update the link, but return if there was an error */
+ err = genmii_update_link(mii_info);
if (err)
return err;
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
+ /*
+ * If the link is up, read the speed and duplex
+ * If we aren't autonegotiating, assume speeds
+ * are as set
+ */
if (mii_info->autoneg && mii_info->link) {
int speed;
@@ -559,7 +574,7 @@ static int marvell_read_status (struct uec_mii_info *mii_info)
return 0;
}
-static int marvell_ack_interrupt (struct uec_mii_info *mii_info)
+static int marvell_ack_interrupt(struct uec_mii_info *mii_info)
{
/* Clear the interrupts by reading the reg */
uec_phy_read(mii_info, MII_M1011_IEVENT);
@@ -567,18 +582,18 @@ static int marvell_ack_interrupt (struct uec_mii_info *mii_info)
return 0;
}
-static int marvell_config_intr (struct uec_mii_info *mii_info)
+static int marvell_config_intr(struct uec_mii_info *mii_info)
{
if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
uec_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
else
uec_phy_write(mii_info, MII_M1011_IMASK,
- MII_M1011_IMASK_CLEAR);
+ MII_M1011_IMASK_CLEAR);
return 0;
}
-static int dm9161_init (struct uec_mii_info *mii_info)
+static int dm9161_init(struct uec_mii_info *mii_info)
{
/* Reset the PHY */
uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) |
@@ -589,29 +604,31 @@ static int dm9161_init (struct uec_mii_info *mii_info)
uec_phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
- config_genmii_advert (mii_info);
+ config_genmii_advert(mii_info);
/* Start/restart aneg */
- genmii_config_aneg (mii_info);
+ genmii_config_aneg(mii_info);
return 0;
}
-static int dm9161_config_aneg (struct uec_mii_info *mii_info)
+static int dm9161_config_aneg(struct uec_mii_info *mii_info)
{
return 0;
}
-static int dm9161_read_status (struct uec_mii_info *mii_info)
+static int dm9161_read_status(struct uec_mii_info *mii_info)
{
u16 status;
int err;
/* Update the link, but return if there was an error */
- err = genmii_update_link (mii_info);
+ err = genmii_update_link(mii_info);
if (err)
return err;
- /* If the link is up, read the speed and duplex
- If we aren't autonegotiating assume speeds are as set */
+ /*
+ * If the link is up, read the speed and duplex
+ * If we aren't autonegotiating assume speeds are as set
+ */
if (mii_info->autoneg && mii_info->link) {
status = uec_phy_read(mii_info, MII_DM9161_SCSR);
if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
@@ -628,7 +645,7 @@ static int dm9161_read_status (struct uec_mii_info *mii_info)
return 0;
}
-static int dm9161_ack_interrupt (struct uec_mii_info *mii_info)
+static int dm9161_ack_interrupt(struct uec_mii_info *mii_info)
{
/* Clear the interrupt by reading the reg */
uec_phy_read(mii_info, MII_DM9161_INTR);
@@ -636,7 +653,7 @@ static int dm9161_ack_interrupt (struct uec_mii_info *mii_info)
return 0;
}
-static int dm9161_config_intr (struct uec_mii_info *mii_info)
+static int dm9161_config_intr(struct uec_mii_info *mii_info)
{
if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
@@ -646,23 +663,23 @@ static int dm9161_config_intr (struct uec_mii_info *mii_info)
return 0;
}
-static void dm9161_close (struct uec_mii_info *mii_info)
+static void dm9161_close(struct uec_mii_info *mii_info)
{
}
-static int fixed_phy_aneg (struct uec_mii_info *mii_info)
+static int fixed_phy_aneg(struct uec_mii_info *mii_info)
{
mii_info->autoneg = 0; /* Turn off auto negotiation for fixed phy */
return 0;
}
-static int fixed_phy_read_status (struct uec_mii_info *mii_info)
+static int fixed_phy_read_status(struct uec_mii_info *mii_info)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
if (strncmp(mii_info->dev->name, fixed_phy_port[i].name,
- strlen(mii_info->dev->name)) == 0) {
+ strlen(mii_info->dev->name)) == 0) {
mii_info->speed = fixed_phy_port[i].speed;
mii_info->duplex = fixed_phy_port[i].duplex;
mii_info->link = 1; /* Link is always UP */
@@ -673,25 +690,26 @@ static int fixed_phy_read_status (struct uec_mii_info *mii_info)
return 0;
}
-static int smsc_config_aneg (struct uec_mii_info *mii_info)
+static int smsc_config_aneg(struct uec_mii_info *mii_info)
{
return 0;
}
-static int smsc_read_status (struct uec_mii_info *mii_info)
+static int smsc_read_status(struct uec_mii_info *mii_info)
{
u16 status;
int err;
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link (mii_info);
+ /* Update the link, but return if there was an error */
+ err = genmii_update_link(mii_info);
if (err)
return err;
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
+ /*
+ * If the link is up, read the speed and duplex
+ * If we aren't autonegotiating, assume speeds
+ * are as set
+ */
if (mii_info->autoneg && mii_info->link) {
int val;
@@ -699,22 +717,22 @@ static int smsc_read_status (struct uec_mii_info *mii_info)
val = (status & 0x1c) >> 2;
switch (val) {
- case 1:
- mii_info->duplex = DUPLEX_HALF;
- mii_info->speed = SPEED_10;
- break;
- case 5:
- mii_info->duplex = DUPLEX_FULL;
- mii_info->speed = SPEED_10;
- break;
- case 2:
- mii_info->duplex = DUPLEX_HALF;
- mii_info->speed = SPEED_100;
- break;
- case 6:
- mii_info->duplex = DUPLEX_FULL;
- mii_info->speed = SPEED_100;
- break;
+ case 1:
+ mii_info->duplex = DUPLEX_HALF;
+ mii_info->speed = SPEED_10;
+ break;
+ case 5:
+ mii_info->duplex = DUPLEX_FULL;
+ mii_info->speed = SPEED_10;
+ break;
+ case 2:
+ mii_info->duplex = DUPLEX_HALF;
+ mii_info->speed = SPEED_100;
+ break;
+ case 6:
+ mii_info->duplex = DUPLEX_FULL;
+ mii_info->speed = SPEED_100;
+ break;
}
mii_info->pause = 0;
}
@@ -803,25 +821,25 @@ static struct phy_info *phy_info[] = {
NULL
};
-u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum)
+static u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum)
{
- return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum);
+ return mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
}
-void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val)
+static void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val)
{
- mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val);
+ mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
}
/* Use the PHY ID registers to determine what type of PHY is attached
* to device dev. return a struct phy_info structure describing that PHY
*/
-struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info)
+struct phy_info *uec_get_phy_info(struct uec_mii_info *mii_info)
{
u16 phy_reg;
u32 phy_ID;
int i;
- struct phy_info *theInfo = NULL;
+ struct phy_info *info = NULL;
/* Grab the bits from PHYIR1, and put them in the upper half */
phy_reg = uec_phy_read(mii_info, MII_PHYSID1);
@@ -836,30 +854,29 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info)
for (i = 0; phy_info[i]; i++)
if (phy_info[i]->phy_id ==
(phy_ID & phy_info[i]->phy_id_mask)) {
- theInfo = phy_info[i];
+ info = phy_info[i];
break;
}
/* This shouldn't happen, as we have generic PHY support */
- if (theInfo == NULL) {
- ugphy_info ("UEC: PHY id %x is not supported!", phy_ID);
+ if (!info) {
+ ugphy_info("UEC: PHY id %x is not supported!", phy_ID);
return NULL;
- } else {
- ugphy_info ("UEC: PHY is %s (%x)", theInfo->name, phy_ID);
}
+ ugphy_info("UEC: PHY is %s (%x)", info->name, phy_ID);
- return theInfo;
+ return info;
}
void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type,
- int speed)
+ int speed)
{
- uec_private_t *uec = (uec_private_t *) dev->priv;
+ struct uec_priv *uec = (struct uec_priv *)dev->priv;
struct uec_mii_info *mii_info;
u16 status;
if (!uec->mii_info) {
- printf ("%s: the PHY not initialized\n", __FUNCTION__);
+ printf("%s: the PHY not initialized\n", __func__);
return;
}
mii_info = uec->mii_info;
@@ -903,10 +920,11 @@ void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type,
/* now the B2 will correctly report autoneg completion status */
}
-void change_phy_interface_mode (struct eth_device *dev,
- phy_interface_t type, int speed)
+void change_phy_interface_mode(struct eth_device *dev,
+ phy_interface_t type, int speed)
{
#ifdef CONFIG_PHY_MODE_NEED_CHANGE
- marvell_phy_interface_mode (dev, type, speed);
+ marvell_phy_interface_mode(dev, type, speed);
#endif
}
+#endif
diff --git a/drivers/qe/uec_phy.h b/drivers/qe/uec_phy.h
index 83a7ccd981..7fd0e2c544 100644
--- a/drivers/qe/uec_phy.h
+++ b/drivers/qe/uec_phy.h
@@ -11,6 +11,8 @@
#ifndef __UEC_PHY_H__
#define __UEC_PHY_H__
+#include <linux/bitops.h>
+
#define MII_end ((u32)-2)
#define MII_read ((u32)-1)
@@ -93,8 +95,8 @@
#define MII_DM9161_INTR_LINK_CHANGE 0x0004
#define MII_DM9161_INTR_INIT 0x0000
#define MII_DM9161_INTR_STOP \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+ (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK | \
+ MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
/* DM9161 10BT Configuration/Status */
#define MII_DM9161_10BTCSR 0x12
@@ -125,35 +127,6 @@
#define DUPLEX_HALF 0x00
#define DUPLEX_FULL 0x01
-/* Indicates what features are supported by the interface. */
-#define SUPPORTED_10baseT_Half (1 << 0)
-#define SUPPORTED_10baseT_Full (1 << 1)
-#define SUPPORTED_100baseT_Half (1 << 2)
-#define SUPPORTED_100baseT_Full (1 << 3)
-#define SUPPORTED_1000baseT_Half (1 << 4)
-#define SUPPORTED_1000baseT_Full (1 << 5)
-#define SUPPORTED_Autoneg (1 << 6)
-#define SUPPORTED_TP (1 << 7)
-#define SUPPORTED_AUI (1 << 8)
-#define SUPPORTED_MII (1 << 9)
-#define SUPPORTED_FIBRE (1 << 10)
-#define SUPPORTED_BNC (1 << 11)
-#define SUPPORTED_10000baseT_Full (1 << 12)
-
-#define ADVERTISED_10baseT_Half (1 << 0)
-#define ADVERTISED_10baseT_Full (1 << 1)
-#define ADVERTISED_100baseT_Half (1 << 2)
-#define ADVERTISED_100baseT_Full (1 << 3)
-#define ADVERTISED_1000baseT_Half (1 << 4)
-#define ADVERTISED_1000baseT_Full (1 << 5)
-#define ADVERTISED_Autoneg (1 << 6)
-#define ADVERTISED_TP (1 << 7)
-#define ADVERTISED_AUI (1 << 8)
-#define ADVERTISED_MII (1 << 9)
-#define ADVERTISED_FIBRE (1 << 10)
-#define ADVERTISED_BNC (1 << 11)
-#define ADVERTISED_10000baseT_Full (1 << 12)
-
/* Taken from mii_if_info and sungem_phy.h */
struct uec_mii_info {
/* Information about the PHY type */
@@ -184,9 +157,9 @@ struct uec_mii_info {
void *priv;
/* Provided by ethernet driver */
- int (*mdio_read) (struct eth_device * dev, int mii_id, int reg);
- void (*mdio_write) (struct eth_device * dev, int mii_id, int reg,
- int val);
+ int (*mdio_read)(struct eth_device *dev, int mii_id, int reg);
+ void (*mdio_write)(struct eth_device *dev, int mii_id, int reg,
+ int val);
};
/* struct phy_info: a structure which defines attributes for a PHY
@@ -208,32 +181,34 @@ struct phy_info {
u32 features;
/* Called to initialize the PHY */
- int (*init) (struct uec_mii_info * mii_info);
+ int (*init)(struct uec_mii_info *mii_info);
/* Called to suspend the PHY for power */
- int (*suspend) (struct uec_mii_info * mii_info);
+ int (*suspend)(struct uec_mii_info *mii_info);
/* Reconfigures autonegotiation (or disables it) */
- int (*config_aneg) (struct uec_mii_info * mii_info);
+ int (*config_aneg)(struct uec_mii_info *mii_info);
/* Determines the negotiated speed and duplex */
- int (*read_status) (struct uec_mii_info * mii_info);
+ int (*read_status)(struct uec_mii_info *mii_info);
/* Clears any pending interrupts */
- int (*ack_interrupt) (struct uec_mii_info * mii_info);
+ int (*ack_interrupt)(struct uec_mii_info *mii_info);
/* Enables or disables interrupts */
- int (*config_intr) (struct uec_mii_info * mii_info);
+ int (*config_intr)(struct uec_mii_info *mii_info);
/* Clears up any memory if needed */
- void (*close) (struct uec_mii_info * mii_info);
+ void (*close)(struct uec_mii_info *mii_info);
};
-struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info);
-void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum,
- int value);
-int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum);
-void mii_clear_phy_interrupt (struct uec_mii_info *mii_info);
-void mii_configure_phy_interrupt (struct uec_mii_info *mii_info,
- u32 interrupts);
+struct phy_info *uec_get_phy_info(struct uec_mii_info *mii_info);
+void uec_write_phy_reg(struct eth_device *dev, int mii_id, int regnum,
+ int value);
+int uec_read_phy_reg(struct eth_device *dev, int mii_id, int regnum);
+void mii_clear_phy_interrupt(struct uec_mii_info *mii_info);
+void mii_configure_phy_interrupt(struct uec_mii_info *mii_info,
+ u32 interrupts);
+void change_phy_interface_mode(struct eth_device *dev,
+ phy_interface_t type, int speed);
#endif /* __UEC_PHY_H__ */
diff --git a/drivers/ram/sifive/fu540_ddr.c b/drivers/ram/sifive/fu540_ddr.c
index 5ff88692a8..60d4945f84 100644
--- a/drivers/ram/sifive/fu540_ddr.c
+++ b/drivers/ram/sifive/fu540_ddr.c
@@ -11,7 +11,6 @@
#include <fdtdec.h>
#include <init.h>
#include <ram.h>
-#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <clk.h>
@@ -339,17 +338,12 @@ static int fu540_ddr_probe(struct udevice *dev)
priv->info.size = gd->ram_size;
#if defined(CONFIG_SPL_BUILD)
- struct regmap *map;
int ret;
u32 clock = 0;
debug("FU540 DDR probe\n");
priv->dev = dev;
- ret = regmap_init_mem(dev_ofnode(dev), &map);
- if (ret)
- return ret;
-
ret = clk_get_by_index(dev, 0, &priv->ddr_clk);
if (ret) {
debug("clk get failed %d\n", ret);
@@ -369,9 +363,14 @@ static int fu540_ddr_probe(struct udevice *dev)
}
ret = clk_enable(&priv->ddr_clk);
- priv->ctl = regmap_get_range(map, 0);
- priv->phy = regmap_get_range(map, 1);
- priv->physical_filter_ctrl = regmap_get_range(map, 2);
+ if (ret < 0) {
+ debug("Could not enable DDR clock\n");
+ return ret;
+ }
+
+ priv->ctl = (struct fu540_ddrctl *)dev_read_addr_index(dev, 0);
+ priv->phy = (struct fu540_ddrphy *)dev_read_addr_index(dev, 1);
+ priv->physical_filter_ctrl = (u32 *)dev_read_addr_index(dev, 2);
return fu540_ddr_setup(dev);
#endif
diff --git a/drivers/remoteproc/k3_system_controller.c b/drivers/remoteproc/k3_system_controller.c
index 54209fccb3..702d98d1a8 100644
--- a/drivers/remoteproc/k3_system_controller.c
+++ b/drivers/remoteproc/k3_system_controller.c
@@ -100,7 +100,7 @@ void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw,
fw->buffer_size = size;
}
-static int k3_sysctrler_load_response(u32 *buf)
+static int k3_sysctrler_load_response(struct udevice *dev, u32 *buf)
{
struct k3_sysctrler_load_msg *fw;
@@ -129,7 +129,8 @@ static int k3_sysctrler_load_response(u32 *buf)
return 0;
}
-static int k3_sysctrler_boot_notification_response(u32 *buf)
+static int k3_sysctrler_boot_notification_response(struct udevice *dev,
+ u32 *buf)
{
struct k3_sysctrler_boot_notification_msg *boot;
@@ -193,7 +194,7 @@ static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size)
}
/* Process the response */
- ret = k3_sysctrler_load_response(msg.buf);
+ ret = k3_sysctrler_load_response(dev, msg.buf);
if (ret)
return ret;
@@ -230,7 +231,7 @@ static int k3_sysctrler_start(struct udevice *dev)
}
/* Process the response */
- ret = k3_sysctrler_boot_notification_response(msg.buf);
+ ret = k3_sysctrler_boot_notification_response(dev, msg.buf);
if (ret)
return ret;
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
index c464ecebb7..b185a6cafb 100644
--- a/drivers/remoteproc/rproc-elf-loader.c
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -158,22 +158,6 @@ int rproc_elf64_sanity_check(ulong addr, ulong size)
return 0;
}
-/* Basic function to verify ELF image format */
-int rproc_elf_sanity_check(ulong addr, ulong size)
-{
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
-
- if (!addr) {
- dev_err(dev, "Invalid firmware address\n");
- return -EFAULT;
- }
-
- if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
- return rproc_elf64_sanity_check(addr, size);
- else
- return rproc_elf32_sanity_check(addr, size);
-}
-
int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index 1a7f1f8a00..9332a63d21 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -2,8 +2,9 @@
/*
* Texas Instruments' K3 R5 Remoteproc driver
*
- * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
+ * Suman Anna <s-anna@ti.com>
*/
#include <common.h>
@@ -37,6 +38,8 @@
#define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000
#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000
#define PROC_BOOT_CFG_FLAG_GEN_IGN_BOOTVECTOR 0x10000000
+/* Available from J7200 SoCs onwards */
+#define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000
/* R5 TI-SCI Processor Control Flags */
#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
@@ -55,6 +58,16 @@ enum cluster_mode {
};
/**
+ * struct k3_r5f_ip_data - internal data structure used for IP variations
+ * @tcm_is_double: flag to denote the larger unified TCMs in certain modes
+ * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC
+ */
+struct k3_r5f_ip_data {
+ bool tcm_is_double;
+ bool tcm_ecc_autoinit;
+};
+
+/**
* struct k3_r5_mem - internal memory structure
* @cpu_addr: MPU virtual address of the memory region
* @bus_addr: Bus address used to access the memory region
@@ -74,6 +87,7 @@ struct k3_r5f_mem {
* @cluster: pointer to the parent cluster.
* @reset: reset control handle
* @tsp: TI-SCI processor control handle
+ * @ipdata: cached pointer to R5F IP specific feature data
* @mem: Array of available internal memories
* @num_mem: Number of available memories
* @atcm_enable: flag to control ATCM enablement
@@ -86,6 +100,7 @@ struct k3_r5f_core {
struct k3_r5f_cluster *cluster;
struct reset_ctl reset;
struct ti_sci_proc tsp;
+ struct k3_r5f_ip_data *ipdata;
struct k3_r5f_mem *mem;
int num_mems;
u32 atcm_enable;
@@ -150,7 +165,7 @@ static int k3_r5f_lockstep_release(struct k3_r5f_cluster *cluster)
{
int ret, c;
- dev_dbg(dev, "%s\n", __func__);
+ debug("%s\n", __func__);
for (c = NR_CORES - 1; c >= 0; c--) {
ret = ti_sci_proc_power_domain_on(&cluster->cores[c]->tsp);
@@ -186,7 +201,7 @@ static int k3_r5f_split_release(struct k3_r5f_core *core)
{
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
ret = ti_sci_proc_power_domain_on(&core->tsp);
if (ret) {
@@ -231,25 +246,29 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core)
struct k3_r5f_cluster *cluster = core->cluster;
if (core->in_use) {
- dev_err(dev, "Invalid op: Trying to load/start on already running core %d\n",
+ dev_err(core->dev,
+ "Invalid op: Trying to load/start on already running core %d\n",
core->tsp.proc_id);
return -EINVAL;
}
if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !cluster->cores[1]) {
- printf("Secondary core is not probed in this cluster\n");
+ dev_err(core->dev,
+ "Secondary core is not probed in this cluster\n");
return -EAGAIN;
}
if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !is_primary_core(core)) {
- dev_err(dev, "Invalid op: Trying to start secondary core %d in lockstep mode\n",
+ dev_err(core->dev,
+ "Invalid op: Trying to start secondary core %d in lockstep mode\n",
core->tsp.proc_id);
return -EINVAL;
}
if (cluster->mode == CLUSTER_MODE_SPLIT && !is_primary_core(core)) {
if (!core->cluster->cores[0]->in_use) {
- dev_err(dev, "Invalid seq: Enable primary core before loading secondary core\n");
+ dev_err(core->dev,
+ "Invalid seq: Enable primary core before loading secondary core\n");
return -EINVAL;
}
}
@@ -257,6 +276,18 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core)
return 0;
}
+/* Zero out TCMs so that ECC can be effective on all TCM addresses */
+void k3_r5f_init_tcm_memories(struct k3_r5f_core *core, bool auto_inited)
+{
+ if (core->ipdata->tcm_ecc_autoinit && auto_inited)
+ return;
+
+ if (core->atcm_enable)
+ memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size);
+ if (core->btcm_enable)
+ memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size);
+}
+
/**
* k3_r5f_load() - Load up the Remote processor image
* @dev: rproc device pointer
@@ -268,7 +299,9 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core)
static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size)
{
struct k3_r5f_core *core = dev_get_priv(dev);
- u32 boot_vector;
+ u64 boot_vector;
+ u32 ctrl, sts, cfg = 0;
+ bool mem_auto_init;
int ret;
dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
@@ -281,6 +314,12 @@ static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size)
if (ret)
return ret;
+ ret = ti_sci_proc_get_status(&core->tsp, &boot_vector, &cfg, &ctrl,
+ &sts);
+ if (ret)
+ return ret;
+ mem_auto_init = !(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS);
+
ret = k3_r5f_prepare(dev);
if (ret) {
dev_err(dev, "R5f prepare failed for core %d\n",
@@ -288,11 +327,7 @@ static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size)
goto proc_release;
}
- /* Zero out TCMs so that ECC can be effective on all TCM addresses */
- if (core->atcm_enable)
- memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size);
- if (core->btcm_enable)
- memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size);
+ k3_r5f_init_tcm_memories(core, mem_auto_init);
ret = rproc_elf_load_image(dev, addr, size);
if (ret < 0) {
@@ -302,7 +337,7 @@ static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size)
boot_vector = rproc_elf_get_boot_addr(dev, addr);
- dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector);
+ dev_dbg(dev, "%s: Boot vector = 0x%llx\n", __func__, boot_vector);
ret = ti_sci_proc_set_config(&core->tsp, boot_vector, 0, 0);
@@ -401,7 +436,7 @@ static int k3_r5f_split_reset(struct k3_r5f_core *core)
{
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
if (reset_assert(&core->reset))
ret = -EINVAL;
@@ -416,7 +451,7 @@ static int k3_r5f_lockstep_reset(struct k3_r5f_cluster *cluster)
{
int ret = 0, c;
- dev_dbg(dev, "%s\n", __func__);
+ debug("%s\n", __func__);
for (c = 0; c < NR_CORES; c++)
if (reset_assert(&cluster->cores[c]->reset))
@@ -548,7 +583,7 @@ static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
u64 boot_vec = 0;
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
ret = ti_sci_proc_request(&core->tsp);
if (ret < 0)
@@ -641,7 +676,7 @@ static int k3_r5f_of_to_priv(struct k3_r5f_core *core)
{
int ret;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(core->dev, "%s\n", __func__);
core->atcm_enable = dev_read_u32_default(core->dev, "atcm-enable", 0);
core->btcm_enable = dev_read_u32_default(core->dev, "btcm-enable", 1);
@@ -657,6 +692,8 @@ static int k3_r5f_of_to_priv(struct k3_r5f_core *core)
return ret;
}
+ core->ipdata = (struct k3_r5f_ip_data *)dev_get_driver_data(core->dev);
+
return 0;
}
@@ -702,6 +739,38 @@ static int k3_r5f_core_of_get_memories(struct k3_r5f_core *core)
return 0;
}
+/*
+ * Each R5F core within a typical R5FSS instance has a total of 64 KB of TCMs,
+ * split equally into two 32 KB banks between ATCM and BTCM. The TCMs from both
+ * cores are usable in Split-mode, but only the Core0 TCMs can be used in
+ * LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by
+ * leveraging the Core1 TCMs as well in certain modes where they would have
+ * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by
+ * making a Core1 TCM visible immediately after the corresponding Core0 TCM.
+ * The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the
+ * dts representation reflects this increased size on supported SoCs. The Core0
+ * TCM sizes therefore have to be adjusted to only half the original size in
+ * Split mode.
+ */
+static void k3_r5f_core_adjust_tcm_sizes(struct k3_r5f_core *core)
+{
+ struct k3_r5f_cluster *cluster = core->cluster;
+
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
+ return;
+
+ if (!core->ipdata->tcm_is_double)
+ return;
+
+ if (core == cluster->cores[0]) {
+ core->mem[0].size /= 2;
+ core->mem[1].size /= 2;
+
+ dev_dbg(core->dev, "adjusted TCM sizes, ATCM = 0x%zx BTCM = 0x%zx\n",
+ core->mem[0].size, core->mem[1].size);
+ }
+}
+
/**
* k3_r5f_probe() - Basic probe
* @dev: corresponding k3 remote processor device
@@ -755,6 +824,8 @@ static int k3_r5f_probe(struct udevice *dev)
return ret;
}
+ k3_r5f_core_adjust_tcm_sizes(core);
+
dev_dbg(dev, "Remoteproc successfully probed\n");
return 0;
@@ -771,9 +842,20 @@ static int k3_r5f_remove(struct udevice *dev)
return 0;
}
+static const struct k3_r5f_ip_data k3_data = {
+ .tcm_is_double = false,
+ .tcm_ecc_autoinit = false,
+};
+
+static const struct k3_r5f_ip_data j7200_data = {
+ .tcm_is_double = true,
+ .tcm_ecc_autoinit = true,
+};
+
static const struct udevice_id k3_r5f_rproc_ids[] = {
- { .compatible = "ti,am654-r5f"},
- { .compatible = "ti,j721e-r5f"},
+ { .compatible = "ti,am654-r5f", .data = (ulong)&k3_data, },
+ { .compatible = "ti,j721e-r5f", .data = (ulong)&k3_data, },
+ { .compatible = "ti,j7200-r5f", .data = (ulong)&j7200_data, },
{}
};
@@ -810,6 +892,7 @@ static int k3_r5f_cluster_probe(struct udevice *dev)
static const struct udevice_id k3_r5fss_ids[] = {
{ .compatible = "ti,am654-r5fss"},
{ .compatible = "ti,j721e-r5fss"},
+ { .compatible = "ti,j7200-r5fss"},
{}
};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 253902ff57..b60e11f98b 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -148,6 +148,14 @@ config RESET_IMX7
help
Support for reset controller on i.MX7/8 SoCs.
+config RESET_IPQ419
+ bool "Reset driver for Qualcomm IPQ40xx SoCs"
+ depends on DM_RESET && ARCH_IPQ40XX
+ default y
+ help
+ Support for reset controller on Qualcomm
+ IPQ40xx SoCs.
+
config RESET_SIFIVE
bool "Reset Driver for SiFive SoC's"
depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_FU540
@@ -173,4 +181,12 @@ config RESET_RASPBERRYPI
relevant. This driver provides a reset controller capable of
interfacing with RPi4's co-processor and model these firmware
initialization routines as reset lines.
+
+config RESET_SCMI
+ bool "Enable SCMI reset domain driver"
+ select SCMI_FIRMWARE
+ help
+ Enable this option if you want to support reset controller
+ devices exposed by a SCMI agent based on SCMI reset domain
+ protocol communication with a SCMI server.
endmenu
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 3c7f066ae3..10a7973f82 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -23,6 +23,8 @@ obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
+obj-$(CONFIG_RESET_IPQ419) += reset-ipq4019.o
obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o
obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o
obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
+obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
diff --git a/drivers/reset/reset-ipq4019.c b/drivers/reset/reset-ipq4019.c
new file mode 100644
index 0000000000..f216db4ce5
--- /dev/null
+++ b/drivers/reset/reset-ipq4019.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ *
+ * Based on Linux driver
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <dt-bindings/reset/qcom,ipq4019-reset.h>
+#include <reset-uclass.h>
+#include <linux/bitops.h>
+#include <malloc.h>
+
+struct ipq4019_reset_priv {
+ phys_addr_t base;
+};
+
+struct qcom_reset_map {
+ unsigned int reg;
+ u8 bit;
+};
+
+static const struct qcom_reset_map gcc_ipq4019_resets[] = {
+ [WIFI0_CPU_INIT_RESET] = { 0x1f008, 5 },
+ [WIFI0_RADIO_SRIF_RESET] = { 0x1f008, 4 },
+ [WIFI0_RADIO_WARM_RESET] = { 0x1f008, 3 },
+ [WIFI0_RADIO_COLD_RESET] = { 0x1f008, 2 },
+ [WIFI0_CORE_WARM_RESET] = { 0x1f008, 1 },
+ [WIFI0_CORE_COLD_RESET] = { 0x1f008, 0 },
+ [WIFI1_CPU_INIT_RESET] = { 0x20008, 5 },
+ [WIFI1_RADIO_SRIF_RESET] = { 0x20008, 4 },
+ [WIFI1_RADIO_WARM_RESET] = { 0x20008, 3 },
+ [WIFI1_RADIO_COLD_RESET] = { 0x20008, 2 },
+ [WIFI1_CORE_WARM_RESET] = { 0x20008, 1 },
+ [WIFI1_CORE_COLD_RESET] = { 0x20008, 0 },
+ [USB3_UNIPHY_PHY_ARES] = { 0x1e038, 5 },
+ [USB3_HSPHY_POR_ARES] = { 0x1e038, 4 },
+ [USB3_HSPHY_S_ARES] = { 0x1e038, 2 },
+ [USB2_HSPHY_POR_ARES] = { 0x1e01c, 4 },
+ [USB2_HSPHY_S_ARES] = { 0x1e01c, 2 },
+ [PCIE_PHY_AHB_ARES] = { 0x1d010, 11 },
+ [PCIE_AHB_ARES] = { 0x1d010, 10 },
+ [PCIE_PWR_ARES] = { 0x1d010, 9 },
+ [PCIE_PIPE_STICKY_ARES] = { 0x1d010, 8 },
+ [PCIE_AXI_M_STICKY_ARES] = { 0x1d010, 7 },
+ [PCIE_PHY_ARES] = { 0x1d010, 6 },
+ [PCIE_PARF_XPU_ARES] = { 0x1d010, 5 },
+ [PCIE_AXI_S_XPU_ARES] = { 0x1d010, 4 },
+ [PCIE_AXI_M_VMIDMT_ARES] = { 0x1d010, 3 },
+ [PCIE_PIPE_ARES] = { 0x1d010, 2 },
+ [PCIE_AXI_S_ARES] = { 0x1d010, 1 },
+ [PCIE_AXI_M_ARES] = { 0x1d010, 0 },
+ [ESS_RESET] = { 0x12008, 0},
+ [GCC_BLSP1_BCR] = {0x01000, 0},
+ [GCC_BLSP1_QUP1_BCR] = {0x02000, 0},
+ [GCC_BLSP1_UART1_BCR] = {0x02038, 0},
+ [GCC_BLSP1_QUP2_BCR] = {0x03008, 0},
+ [GCC_BLSP1_UART2_BCR] = {0x03028, 0},
+ [GCC_BIMC_BCR] = {0x04000, 0},
+ [GCC_TLMM_BCR] = {0x05000, 0},
+ [GCC_IMEM_BCR] = {0x0E000, 0},
+ [GCC_ESS_BCR] = {0x12008, 0},
+ [GCC_PRNG_BCR] = {0x13000, 0},
+ [GCC_BOOT_ROM_BCR] = {0x13008, 0},
+ [GCC_CRYPTO_BCR] = {0x16000, 0},
+ [GCC_SDCC1_BCR] = {0x18000, 0},
+ [GCC_SEC_CTRL_BCR] = {0x1A000, 0},
+ [GCC_AUDIO_BCR] = {0x1B008, 0},
+ [GCC_QPIC_BCR] = {0x1C000, 0},
+ [GCC_PCIE_BCR] = {0x1D000, 0},
+ [GCC_USB2_BCR] = {0x1E008, 0},
+ [GCC_USB2_PHY_BCR] = {0x1E018, 0},
+ [GCC_USB3_BCR] = {0x1E024, 0},
+ [GCC_USB3_PHY_BCR] = {0x1E034, 0},
+ [GCC_SYSTEM_NOC_BCR] = {0x21000, 0},
+ [GCC_PCNOC_BCR] = {0x2102C, 0},
+ [GCC_DCD_BCR] = {0x21038, 0},
+ [GCC_SNOC_BUS_TIMEOUT0_BCR] = {0x21064, 0},
+ [GCC_SNOC_BUS_TIMEOUT1_BCR] = {0x2106C, 0},
+ [GCC_SNOC_BUS_TIMEOUT2_BCR] = {0x21074, 0},
+ [GCC_SNOC_BUS_TIMEOUT3_BCR] = {0x2107C, 0},
+ [GCC_PCNOC_BUS_TIMEOUT0_BCR] = {0x21084, 0},
+ [GCC_PCNOC_BUS_TIMEOUT1_BCR] = {0x2108C, 0},
+ [GCC_PCNOC_BUS_TIMEOUT2_BCR] = {0x21094, 0},
+ [GCC_PCNOC_BUS_TIMEOUT3_BCR] = {0x2109C, 0},
+ [GCC_PCNOC_BUS_TIMEOUT4_BCR] = {0x210A4, 0},
+ [GCC_PCNOC_BUS_TIMEOUT5_BCR] = {0x210AC, 0},
+ [GCC_PCNOC_BUS_TIMEOUT6_BCR] = {0x210B4, 0},
+ [GCC_PCNOC_BUS_TIMEOUT7_BCR] = {0x210BC, 0},
+ [GCC_PCNOC_BUS_TIMEOUT8_BCR] = {0x210C4, 0},
+ [GCC_PCNOC_BUS_TIMEOUT9_BCR] = {0x210CC, 0},
+ [GCC_TCSR_BCR] = {0x22000, 0},
+ [GCC_MPM_BCR] = {0x24000, 0},
+ [GCC_SPDM_BCR] = {0x25000, 0},
+};
+
+static int ipq4019_reset_assert(struct reset_ctl *rst)
+{
+ struct ipq4019_reset_priv *priv = dev_get_priv(rst->dev);
+ const struct qcom_reset_map *reset_map = gcc_ipq4019_resets;
+ const struct qcom_reset_map *map;
+ u32 value;
+
+ map = &reset_map[rst->id];
+
+ value = readl(priv->base + map->reg);
+ value |= BIT(map->bit);
+ writel(value, priv->base + map->reg);
+
+ return 0;
+}
+
+static int ipq4019_reset_deassert(struct reset_ctl *rst)
+{
+ struct ipq4019_reset_priv *priv = dev_get_priv(rst->dev);
+ const struct qcom_reset_map *reset_map = gcc_ipq4019_resets;
+ const struct qcom_reset_map *map;
+ u32 value;
+
+ map = &reset_map[rst->id];
+
+ value = readl(priv->base + map->reg);
+ value &= ~BIT(map->bit);
+ writel(value, priv->base + map->reg);
+
+ return 0;
+}
+
+static int ipq4019_reset_free(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static int ipq4019_reset_request(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static const struct reset_ops ipq4019_reset_ops = {
+ .request = ipq4019_reset_request,
+ .rfree = ipq4019_reset_free,
+ .rst_assert = ipq4019_reset_assert,
+ .rst_deassert = ipq4019_reset_deassert,
+};
+
+static const struct udevice_id ipq4019_reset_ids[] = {
+ { .compatible = "qcom,gcc-reset-ipq4019" },
+ { }
+};
+
+static int ipq4019_reset_probe(struct udevice *dev)
+{
+ struct ipq4019_reset_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(ipq4019_reset) = {
+ .name = "ipq4019_reset",
+ .id = UCLASS_RESET,
+ .of_match = ipq4019_reset_ids,
+ .ops = &ipq4019_reset_ops,
+ .probe = ipq4019_reset_probe,
+ .priv_auto_alloc_size = sizeof(struct ipq4019_reset_priv),
+};
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
new file mode 100644
index 0000000000..1bff8075ee
--- /dev/null
+++ b/drivers/reset/reset-scmi.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2020 Linaro Limited
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset-uclass.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+
+static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
+{
+ struct scmi_rd_reset_in in = {
+ .domain_id = rst->id,
+ .flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0,
+ .reset_state = 0,
+ };
+ struct scmi_rd_reset_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ SCMI_RESET_DOMAIN_RESET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(rst->dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_reset_assert(struct reset_ctl *rst)
+{
+ return scmi_reset_set_level(rst, true);
+}
+
+static int scmi_reset_deassert(struct reset_ctl *rst)
+{
+ return scmi_reset_set_level(rst, false);
+}
+
+static int scmi_reset_request(struct reset_ctl *rst)
+{
+ struct scmi_rd_attr_in in = {
+ .domain_id = rst->id,
+ };
+ struct scmi_rd_attr_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ SCMI_RESET_DOMAIN_ATTRIBUTES,
+ in, out);
+ int ret;
+
+ /*
+ * We don't really care about the attribute, just check
+ * the reset domain exists.
+ */
+ ret = devm_scmi_process_msg(rst->dev->parent, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_reset_rfree(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static const struct reset_ops scmi_reset_domain_ops = {
+ .request = scmi_reset_request,
+ .rfree = scmi_reset_rfree,
+ .rst_assert = scmi_reset_assert,
+ .rst_deassert = scmi_reset_deassert,
+};
+
+U_BOOT_DRIVER(scmi_reset_domain) = {
+ .name = "scmi_reset_domain",
+ .id = UCLASS_RESET,
+ .ops = &scmi_reset_domain_ops,
+};
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index 5e38ce5c06..e7e407ca35 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -11,6 +11,7 @@
#include <reset.h>
#include <reset-uclass.h>
#include <dm/devres.h>
+#include <dm/lists.h>
static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
{
@@ -100,13 +101,14 @@ int reset_get_by_index_nodev(ofnode node, int index,
index > 0, reset_ctl);
}
-int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+static int __reset_get_bulk(struct udevice *dev, ofnode node,
+ struct reset_ctl_bulk *bulk)
{
int i, ret, err, count;
-
+
bulk->count = 0;
- count = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
+ count = ofnode_count_phandle_with_args(node, "resets", "#reset-cells");
if (count < 1)
return count;
@@ -116,7 +118,7 @@ int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
return -ENOMEM;
for (i = 0; i < count; i++) {
- ret = reset_get_by_index(dev, i, &bulk->resets[i]);
+ ret = reset_get_by_index_nodev(node, i, &bulk->resets[i]);
if (ret < 0)
goto bulk_get_err;
@@ -134,6 +136,11 @@ bulk_get_err:
return ret;
}
+int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
+{
+ return __reset_get_bulk(dev, dev_ofnode(dev), bulk);
+}
+
int reset_get_by_name(struct udevice *dev, const char *name,
struct reset_ctl *reset_ctl)
{
@@ -246,6 +253,109 @@ int reset_release_all(struct reset_ctl *reset_ctl, int count)
return 0;
}
+static void devm_reset_release(struct udevice *dev, void *res)
+{
+ reset_free(res);
+}
+
+struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev,
+ int index)
+{
+ int rc;
+ struct reset_ctl *reset_ctl;
+
+ reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl),
+ __GFP_ZERO);
+ if (unlikely(!reset_ctl))
+ return ERR_PTR(-ENOMEM);
+
+ rc = reset_get_by_index(dev, index, reset_ctl);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, reset_ctl);
+ return reset_ctl;
+}
+
+struct reset_ctl *devm_reset_control_get(struct udevice *dev, const char *id)
+{
+ int rc;
+ struct reset_ctl *reset_ctl;
+
+ reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl),
+ __GFP_ZERO);
+ if (unlikely(!reset_ctl))
+ return ERR_PTR(-ENOMEM);
+
+ rc = reset_get_by_name(dev, id, reset_ctl);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, reset_ctl);
+ return reset_ctl;
+}
+
+struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev,
+ const char *id)
+{
+ struct reset_ctl *r = devm_reset_control_get(dev, id);
+
+ if (IS_ERR(r))
+ return NULL;
+
+ return r;
+}
+
+static void devm_reset_bulk_release(struct udevice *dev, void *res)
+{
+ struct reset_ctl_bulk *bulk = res;
+
+ reset_release_all(bulk->resets, bulk->count);
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev,
+ ofnode node)
+{
+ int rc;
+ struct reset_ctl_bulk *bulk;
+
+ bulk = devres_alloc(devm_reset_bulk_release,
+ sizeof(struct reset_ctl_bulk),
+ __GFP_ZERO);
+ if (unlikely(!bulk))
+ return ERR_PTR(-ENOMEM);
+
+ rc = __reset_get_bulk(dev, node, bulk);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, bulk);
+ return bulk;
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev,
+ ofnode node)
+{
+ struct reset_ctl_bulk *bulk;
+
+ bulk = devm_reset_bulk_get_by_node(dev, node);
+
+ if (IS_ERR(bulk))
+ return NULL;
+
+ return bulk;
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev)
+{
+ return devm_reset_bulk_get_by_node(dev, dev_ofnode(dev));
+}
+
+struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev)
+{
+ return devm_reset_bulk_get_optional_by_node(dev, dev_ofnode(dev));
+}
+
UCLASS_DRIVER(reset) = {
.id = UCLASS_RESET,
.name = "reset",
diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c
index 9bc4a7e0de..10e02f1036 100644
--- a/drivers/reset/sandbox-reset-test.c
+++ b/drivers/reset/sandbox-reset-test.c
@@ -10,66 +10,105 @@
#include <reset.h>
#include <asm/io.h>
#include <asm/reset.h>
+#include <linux/err.h>
struct sandbox_reset_test {
struct reset_ctl ctl;
struct reset_ctl_bulk bulk;
+
+ struct reset_ctl *ctlp;
+ struct reset_ctl_bulk *bulkp;
};
int sandbox_reset_test_get(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ sbrt->ctlp = &sbrt->ctl;
return reset_get_by_name(dev, "test", &sbrt->ctl);
}
+int sandbox_reset_test_get_devm(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ struct reset_ctl *r;
+
+ r = devm_reset_control_get(dev, "not-a-valid-reset-ctl");
+ if (!IS_ERR(r))
+ return -EINVAL;
+
+ r = devm_reset_control_get_optional(dev, "not-a-valid-reset-ctl");
+ if (r)
+ return -EINVAL;
+
+ sbrt->ctlp = devm_reset_control_get(dev, "test");
+ if (IS_ERR(sbrt->ctlp))
+ return PTR_ERR(sbrt->ctlp);
+
+ return 0;
+}
+
int sandbox_reset_test_get_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ sbrt->bulkp = &sbrt->bulk;
return reset_get_bulk(dev, &sbrt->bulk);
}
+int sandbox_reset_test_get_bulk_devm(struct udevice *dev)
+{
+ struct sandbox_reset_test *sbrt = dev_get_priv(dev);
+ struct reset_ctl_bulk *r;
+
+ r = devm_reset_bulk_get_optional(dev);
+ if (IS_ERR(r))
+ return PTR_ERR(r);
+
+ sbrt->bulkp = r;
+ return 0;
+}
+
int sandbox_reset_test_assert(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_assert(&sbrt->ctl);
+ return reset_assert(sbrt->ctlp);
}
int sandbox_reset_test_assert_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_assert_bulk(&sbrt->bulk);
+ return reset_assert_bulk(sbrt->bulkp);
}
int sandbox_reset_test_deassert(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_deassert(&sbrt->ctl);
+ return reset_deassert(sbrt->ctlp);
}
int sandbox_reset_test_deassert_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_deassert_bulk(&sbrt->bulk);
+ return reset_deassert_bulk(sbrt->bulkp);
}
int sandbox_reset_test_free(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_free(&sbrt->ctl);
+ return reset_free(sbrt->ctlp);
}
int sandbox_reset_test_release_bulk(struct udevice *dev)
{
struct sandbox_reset_test *sbrt = dev_get_priv(dev);
- return reset_release_bulk(&sbrt->bulk);
+ return reset_release_bulk(sbrt->bulkp);
}
static const struct udevice_id sandbox_reset_test_ids[] = {
diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c
index 7a6f7f676c..08008d875a 100644
--- a/drivers/reset/sandbox-reset.c
+++ b/drivers/reset/sandbox-reset.c
@@ -15,6 +15,7 @@
struct sandbox_reset_signal {
bool asserted;
+ bool requested;
};
struct sandbox_reset {
@@ -23,18 +24,24 @@ struct sandbox_reset {
static int sandbox_reset_request(struct reset_ctl *reset_ctl)
{
+ struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev);
+
debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
if (reset_ctl->id >= SANDBOX_RESET_SIGNALS)
return -EINVAL;
+ sbr->signals[reset_ctl->id].requested = true;
return 0;
}
static int sandbox_reset_free(struct reset_ctl *reset_ctl)
{
+ struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev);
+
debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
+ sbr->signals[reset_ctl->id].requested = false;
return 0;
}
@@ -107,3 +114,15 @@ int sandbox_reset_query(struct udevice *dev, unsigned long id)
return sbr->signals[id].asserted;
}
+
+int sandbox_reset_is_requested(struct udevice *dev, unsigned long id)
+{
+ struct sandbox_reset *sbr = dev_get_priv(dev);
+
+ debug("%s(dev=%p, id=%ld)\n", __func__, dev, id);
+
+ if (id >= SANDBOX_RESET_SIGNALS)
+ return -EINVAL;
+
+ return sbr->signals[id].requested;
+}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index e344677f91..b4805a2e4e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -734,7 +734,7 @@ config UNIPHIER_SERIAL
config XILINX_UARTLITE
bool "Xilinx Uarlite support"
- depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || 4xx)
+ depends on DM_SERIAL
help
If you have a Xilinx based board and want to use the uartlite
serial ports, say Y to this option. If unsure, say N.
@@ -802,7 +802,7 @@ config STM32_SERIAL
config ZYNQ_SERIAL
bool "Cadence (Xilinx Zynq) UART support"
- depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_ZYNQMP_R5)
+ depends on DM_SERIAL
help
This driver supports the Cadence UART. It is found e.g. in Xilinx
Zynq/ZynqMP.
diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c
index 5116d13751..236ab860ad 100644
--- a/drivers/serial/serial_xuartlite.c
+++ b/drivers/serial/serial_xuartlite.c
@@ -23,6 +23,8 @@
#define ULITE_CONTROL_RST_TX 0x01
#define ULITE_CONTROL_RST_RX 0x02
+static bool little_endian;
+
struct uartlite {
unsigned int rx_fifo;
unsigned int tx_fifo;
@@ -34,15 +36,31 @@ struct uartlite_platdata {
struct uartlite *regs;
};
+static u32 uart_in32(void __iomem *addr)
+{
+ if (little_endian)
+ return in_le32(addr);
+ else
+ return in_be32(addr);
+}
+
+static void uart_out32(void __iomem *addr, u32 val)
+{
+ if (little_endian)
+ out_le32(addr, val);
+ else
+ out_be32(addr, val);
+}
+
static int uartlite_serial_putc(struct udevice *dev, const char ch)
{
struct uartlite_platdata *plat = dev_get_platdata(dev);
struct uartlite *regs = plat->regs;
- if (in_be32(&regs->status) & SR_TX_FIFO_FULL)
+ if (uart_in32(&regs->status) & SR_TX_FIFO_FULL)
return -EAGAIN;
- out_be32(&regs->tx_fifo, ch & 0xff);
+ uart_out32(&regs->tx_fifo, ch & 0xff);
return 0;
}
@@ -52,10 +70,10 @@ static int uartlite_serial_getc(struct udevice *dev)
struct uartlite_platdata *plat = dev_get_platdata(dev);
struct uartlite *regs = plat->regs;
- if (!(in_be32(&regs->status) & SR_RX_FIFO_VALID_DATA))
+ if (!(uart_in32(&regs->status) & SR_RX_FIFO_VALID_DATA))
return -EAGAIN;
- return in_be32(&regs->rx_fifo) & 0xff;
+ return uart_in32(&regs->rx_fifo) & 0xff;
}
static int uartlite_serial_pending(struct udevice *dev, bool input)
@@ -64,19 +82,26 @@ static int uartlite_serial_pending(struct udevice *dev, bool input)
struct uartlite *regs = plat->regs;
if (input)
- return in_be32(&regs->status) & SR_RX_FIFO_VALID_DATA;
+ return uart_in32(&regs->status) & SR_RX_FIFO_VALID_DATA;
- return !(in_be32(&regs->status) & SR_TX_FIFO_EMPTY);
+ return !(uart_in32(&regs->status) & SR_TX_FIFO_EMPTY);
}
static int uartlite_serial_probe(struct udevice *dev)
{
struct uartlite_platdata *plat = dev_get_platdata(dev);
struct uartlite *regs = plat->regs;
-
- out_be32(&regs->control, 0);
- out_be32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
- in_be32(&regs->control);
+ int ret;
+
+ uart_out32(&regs->control, 0);
+ uart_out32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+ ret = uart_in32(&regs->status);
+ /* Endianness detection */
+ if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) {
+ little_endian = true;
+ uart_out32(&regs->control, ULITE_CONTROL_RST_RX |
+ ULITE_CONTROL_RST_TX);
+ }
return 0;
}
@@ -119,20 +144,27 @@ U_BOOT_DRIVER(serial_uartlite) = {
static inline void _debug_uart_init(void)
{
struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE;
-
- out_be32(&regs->control, 0);
- out_be32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
- in_be32(&regs->control);
+ int ret;
+
+ uart_out32(&regs->control, 0);
+ uart_out32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+ uart_in32(&regs->status);
+ /* Endianness detection */
+ if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) {
+ little_endian = true;
+ uart_out32(&regs->control, ULITE_CONTROL_RST_RX |
+ ULITE_CONTROL_RST_TX);
+ }
}
static inline void _debug_uart_putc(int ch)
{
struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE;
- while (in_be32(&regs->status) & SR_TX_FIFO_FULL)
+ while (uart_in32(&regs->status) & SR_TX_FIFO_FULL)
;
- out_be32(&regs->tx_fifo, ch & 0xff);
+ uart_out32(&regs->tx_fifo, ch & 0xff);
}
DEBUG_UART_FUNCS
diff --git a/drivers/smem/Kconfig b/drivers/smem/Kconfig
index 7169d0f205..73d51b3a7a 100644
--- a/drivers/smem/Kconfig
+++ b/drivers/smem/Kconfig
@@ -15,7 +15,7 @@ config SANDBOX_SMEM
config MSM_SMEM
bool "Qualcomm Shared Memory Manager (SMEM)"
depends on DM
- depends on ARCH_SNAPDRAGON
+ depends on ARCH_SNAPDRAGON || ARCH_IPQ40XX
help
Enable support for the Qualcomm Shared Memory Manager.
The driver provides an interface to items in a heap shared among all
diff --git a/drivers/smem/msm_smem.c b/drivers/smem/msm_smem.c
index 2557269bc5..597d425d11 100644
--- a/drivers/smem/msm_smem.c
+++ b/drivers/smem/msm_smem.c
@@ -879,7 +879,7 @@ static int qcom_smem_probe(struct udevice *dev)
header = smem->regions[0].virt_base;
if (le32_to_cpu(header->initialized) != 1 ||
le32_to_cpu(header->reserved)) {
- dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
+ dev_err(dev, "SMEM is not initialized by SBL\n");
return -EINVAL;
}
diff --git a/drivers/sound/max98357a.c b/drivers/sound/max98357a.c
index 841bc6ef68..827262d235 100644
--- a/drivers/sound/max98357a.c
+++ b/drivers/sound/max98357a.c
@@ -81,7 +81,7 @@ static int max98357a_acpi_fill_ssdt(const struct udevice *dev,
dp = acpi_dp_new_table("_DSD");
acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0,
priv->sdmode_gpio.flags & GPIOD_ACTIVE_LOW ?
- ACPI_IRQ_ACTIVE_LOW : ACPI_IRQ_ACTIVE_HIGH);
+ ACPI_GPIO_ACTIVE_LOW : ACPI_GPIO_ACTIVE_HIGH);
acpi_dp_add_integer(dp, "sdmode-delay",
dev_read_u32_default(dev, "sdmode-delay", 0));
acpi_dp_write(ctx, dp);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 3fc2d0674a..5df97c80fa 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -407,7 +407,6 @@ config XILINX_SPI
config ZYNQ_SPI
bool "Zynq SPI driver"
- depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL
help
Enable the Zynq SPI driver. This driver can be used to
access the SPI NOR flash on platforms embedding this Zynq
@@ -415,7 +414,6 @@ config ZYNQ_SPI
config ZYNQ_QSPI
bool "Zynq QSPI driver"
- depends on ARCH_ZYNQ
imply SPI_FLASH_BAR
help
Enable the Zynq Quad-SPI (QSPI) driver. This driver can be
@@ -425,7 +423,6 @@ config ZYNQ_QSPI
config ZYNQMP_GQSPI
bool "Configure ZynqMP Generic QSPI"
- depends on ARCH_ZYNQMP || ARCH_VERSAL
help
This option is used to enable ZynqMP QSPI controller driver which
is used to communicate with qspi flash devices.
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index fbf9575851..56cb217486 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -22,82 +22,14 @@
#include <malloc.h>
#include <asm/io.h>
#include <linux/bitops.h>
+#include <omap3_spi.h>
DECLARE_GLOBAL_DATA_PTR;
-#define OMAP4_MCSPI_REG_OFFSET 0x100
-
struct omap2_mcspi_platform_config {
unsigned int regs_offset;
};
-/* per-register bitmasks */
-#define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
-#define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2)
-#define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE BIT(0)
-#define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1)
-
-#define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0)
-
-#define OMAP3_MCSPI_MODULCTRL_SINGLE BIT(0)
-#define OMAP3_MCSPI_MODULCTRL_MS BIT(2)
-#define OMAP3_MCSPI_MODULCTRL_STEST BIT(3)
-
-#define OMAP3_MCSPI_CHCONF_PHA BIT(0)
-#define OMAP3_MCSPI_CHCONF_POL BIT(1)
-#define OMAP3_MCSPI_CHCONF_CLKD_MASK GENMASK(5, 2)
-#define OMAP3_MCSPI_CHCONF_EPOL BIT(6)
-#define OMAP3_MCSPI_CHCONF_WL_MASK GENMASK(11, 7)
-#define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY BIT(12)
-#define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY BIT(13)
-#define OMAP3_MCSPI_CHCONF_TRM_MASK GENMASK(13, 12)
-#define OMAP3_MCSPI_CHCONF_DMAW BIT(14)
-#define OMAP3_MCSPI_CHCONF_DMAR BIT(15)
-#define OMAP3_MCSPI_CHCONF_DPE0 BIT(16)
-#define OMAP3_MCSPI_CHCONF_DPE1 BIT(17)
-#define OMAP3_MCSPI_CHCONF_IS BIT(18)
-#define OMAP3_MCSPI_CHCONF_TURBO BIT(19)
-#define OMAP3_MCSPI_CHCONF_FORCE BIT(20)
-
-#define OMAP3_MCSPI_CHSTAT_RXS BIT(0)
-#define OMAP3_MCSPI_CHSTAT_TXS BIT(1)
-#define OMAP3_MCSPI_CHSTAT_EOT BIT(2)
-
-#define OMAP3_MCSPI_CHCTRL_EN BIT(0)
-#define OMAP3_MCSPI_CHCTRL_DIS (0 << 0)
-
-#define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0)
-#define MCSPI_PINDIR_D0_IN_D1_OUT 0
-#define MCSPI_PINDIR_D0_OUT_D1_IN 1
-
-#define OMAP3_MCSPI_MAX_FREQ 48000000
-#define SPI_WAIT_TIMEOUT 10
-
-/* OMAP3 McSPI registers */
-struct mcspi_channel {
- unsigned int chconf; /* 0x2C, 0x40, 0x54, 0x68 */
- unsigned int chstat; /* 0x30, 0x44, 0x58, 0x6C */
- unsigned int chctrl; /* 0x34, 0x48, 0x5C, 0x70 */
- unsigned int tx; /* 0x38, 0x4C, 0x60, 0x74 */
- unsigned int rx; /* 0x3C, 0x50, 0x64, 0x78 */
-};
-
-struct mcspi {
- unsigned char res1[0x10];
- unsigned int sysconfig; /* 0x10 */
- unsigned int sysstatus; /* 0x14 */
- unsigned int irqstatus; /* 0x18 */
- unsigned int irqenable; /* 0x1C */
- unsigned int wakeupenable; /* 0x20 */
- unsigned int syst; /* 0x24 */
- unsigned int modulctrl; /* 0x28 */
- struct mcspi_channel channel[4];
- /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */
- /* channel1: 0x40 - 0x50, bus 0 & 1 */
- /* channel2: 0x54 - 0x64, bus 0 & 1 */
- /* channel3: 0x68 - 0x78, bus 0 */
-};
-
struct omap3_spi_priv {
struct mcspi *regs;
unsigned int cs;
@@ -482,17 +414,10 @@ static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen)
static int omap3_spi_probe(struct udevice *dev)
{
struct omap3_spi_priv *priv = dev_get_priv(dev);
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(dev);
-
- struct omap2_mcspi_platform_config* data =
- (struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
+ struct omap3_spi_plat *plat = dev_get_platdata(dev);
- priv->regs = (struct mcspi *)(dev_read_addr(dev) + data->regs_offset);
- if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in"))
- priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
- else
- priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
+ priv->regs = plat->regs;
+ priv->pin_dir = plat->pin_dir;
priv->wordlen = SPI_DEFAULT_WORDLEN;
spi_reset(priv->regs);
@@ -544,6 +469,7 @@ static const struct dm_spi_ops omap3_spi_ops = {
*/
};
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
static struct omap2_mcspi_platform_config omap2_pdata = {
.regs_offset = 0,
};
@@ -552,16 +478,37 @@ static struct omap2_mcspi_platform_config omap4_pdata = {
.regs_offset = OMAP4_MCSPI_REG_OFFSET,
};
+static int omap3_spi_ofdata_to_platdata(struct udevice *dev)
+{
+ struct omap2_mcspi_platform_config *data =
+ (struct omap2_mcspi_platform_config *)dev_get_driver_data(dev);
+ struct omap3_spi_plat *plat = dev_get_platdata(dev);
+
+ plat->regs = (struct mcspi *)(dev_read_addr(dev) + data->regs_offset);
+
+ if (dev_read_bool(dev, "ti,pindir-d0-out-d1-in"))
+ plat->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
+ else
+ plat->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
+
+ return 0;
+}
+
static const struct udevice_id omap3_spi_ids[] = {
{ .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata },
{ .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata },
{ }
};
-
+#endif
U_BOOT_DRIVER(omap3_spi) = {
.name = "omap3_spi",
.id = UCLASS_SPI,
+ .flags = DM_FLAG_PRE_RELOC,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
.of_match = omap3_spi_ids,
+ .ofdata_to_platdata = omap3_spi_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct omap3_spi_plat),
+#endif
.probe = omap3_spi_probe,
.ops = &omap3_spi_ops,
.priv_auto_alloc_size = sizeof(struct omap3_spi_priv),
diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
index cd2e17bfd1..0844a5a0a6 100644
--- a/drivers/spi/spi-sunxi.c
+++ b/drivers/spi/spi-sunxi.c
@@ -489,19 +489,19 @@ static int sun4i_spi_probe(struct udevice *bus)
ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
if (ret) {
- dev_err(dev, "failed to get ahb clock\n");
+ dev_err(bus, "failed to get ahb clock\n");
return ret;
}
ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
if (ret) {
- dev_err(dev, "failed to get mod clock\n");
+ dev_err(bus, "failed to get mod clock\n");
return ret;
}
ret = reset_get_by_index(bus, 0, &priv->reset);
if (ret && ret != -ENOENT) {
- dev_err(dev, "failed to get reset\n");
+ dev_err(bus, "failed to get reset\n");
return ret;
}
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index cffd9cf0b0..55a8eed890 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -497,7 +497,7 @@ UCLASS_DRIVER(spi) = {
.id = UCLASS_SPI,
.name = "spi",
.flags = DM_UC_FLAG_SEQ_ALIAS,
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
.post_bind = dm_scan_fdt_dev,
#endif
.post_probe = spi_post_probe,
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c
index a72986be90..e0e6687037 100644
--- a/drivers/spi/zynqmp_gqspi.c
+++ b/drivers/spi/zynqmp_gqspi.c
@@ -346,20 +346,20 @@ static int zynqmp_qspi_probe(struct udevice *bus)
ret = clk_get_by_index(bus, 0, &clk);
if (ret < 0) {
- dev_err(dev, "failed to get clock\n");
+ dev_err(bus, "failed to get clock\n");
return ret;
}
clock = clk_get_rate(&clk);
if (IS_ERR_VALUE(clock)) {
- dev_err(dev, "failed to get rate\n");
+ dev_err(bus, "failed to get rate\n");
return clock;
}
debug("%s: CLK %ld\n", __func__, clock);
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
- dev_err(dev, "failed to enable clock\n");
+ dev_err(bus, "failed to enable clock\n");
return ret;
}
plat->frequency = clock;
diff --git a/drivers/sysreset/sysreset-ti-sci.c b/drivers/sysreset/sysreset-ti-sci.c
index 3877b9bc12..7707c72bb5 100644
--- a/drivers/sysreset/sysreset-ti-sci.c
+++ b/drivers/sysreset/sysreset-ti-sci.c
@@ -51,8 +51,7 @@ static int ti_sci_sysreset_request(struct udevice *dev, enum sysreset_t type)
ret = cops->reboot_device(sci);
if (ret)
- dev_err(rst->dev, "%s: reboot_device failed (%d)\n",
- __func__, ret);
+ dev_err(dev, "%s: reboot_device failed (%d)\n", __func__, ret);
return ret;
}
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 637024445c..f8fa4aa71f 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -146,8 +146,8 @@ config RISCV_TIMER
bool "RISC-V timer support"
depends on TIMER && RISCV
help
- Select this to enable support for the timer as defined
- by the RISC-V privileged architecture spec.
+ Select this to enable support for a generic RISC-V S-Mode timer
+ driver.
config ROCKCHIP_TIMER
bool "Rockchip timer support"
@@ -213,4 +213,11 @@ config MTK_TIMER
Select this to enable support for the timer found on
MediaTek devices.
+config MCHP_PIT64B_TIMER
+ bool "Microchip 64-bit periodic interval timer support"
+ depends on TIMER
+ help
+ Select this to enable support for Microchip 64-bit periodic
+ interval timer.
+
endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index c22ffebcde..3a4d74b996 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_STI_TIMER) += sti-timer.o
obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
+obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o
diff --git a/drivers/timer/mchp-pit64b-timer.c b/drivers/timer/mchp-pit64b-timer.c
new file mode 100644
index 0000000000..ead8c9b84a
--- /dev/null
+++ b/drivers/timer/mchp-pit64b-timer.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * 64-bit Periodic Interval Timer driver
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+
+#define MCHP_PIT64B_CR 0x00 /* Control Register */
+#define MCHP_PIT64B_CR_START BIT(0)
+#define MCHP_PIT64B_CR_SWRST BIT(8)
+#define MCHP_PIT64B_MR 0x04 /* Mode Register */
+#define MCHP_PIT64B_MR_CONT BIT(0)
+#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
+#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
+#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
+#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
+
+struct mchp_pit64b_priv {
+ void __iomem *base;
+};
+
+static int mchp_pit64b_get_count(struct udevice *dev, u64 *count)
+{
+ struct mchp_pit64b_priv *priv = dev_get_priv(dev);
+
+ u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR);
+ u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR);
+
+ *count = ((u64)msb << 32) | lsb;
+
+ return 0;
+}
+
+static int mchp_pit64b_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mchp_pit64b_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ ulong rate;
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate) {
+ clk_disable(&clk);
+ return -ENOTSUPP;
+ }
+
+ /* Reset the timer in case it was used by previous bootloaders. */
+ writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR);
+
+ /*
+ * Use highest prescaller (for a peripheral clock running at 200MHz
+ * this will lead to the timer running at 12.5MHz) and continuous mode.
+ */
+ writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR);
+ uc_priv->clock_rate = rate / 16;
+
+ /*
+ * Simulate free running counter by setting max values to period
+ * registers.
+ */
+ writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR);
+ writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR);
+
+ /* Start the timer. */
+ writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR);
+
+ return 0;
+}
+
+static const struct timer_ops mchp_pit64b_ops = {
+ .get_count = mchp_pit64b_get_count,
+};
+
+static const struct udevice_id mchp_pit64b_ids[] = {
+ { .compatible = "microchip,sam9x60-pit64b", },
+ { .compatible = "microchip,sama7g5-pit64b", },
+ { }
+};
+
+U_BOOT_DRIVER(mchp_pit64b) = {
+ .name = "mchp-pit64b",
+ .id = UCLASS_TIMER,
+ .of_match = mchp_pit64b_ids,
+ .priv_auto_alloc_size = sizeof(struct mchp_pit64b_priv),
+ .probe = mchp_pit64b_probe,
+ .ops = &mchp_pit64b_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c
index 9f9f070e0b..449fcfcfd5 100644
--- a/drivers/timer/riscv_timer.c
+++ b/drivers/timer/riscv_timer.c
@@ -1,36 +1,37 @@
// SPDX-License-Identifier: GPL-2.0+
/*
+ * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
+ * Copyright (C) 2012 Regents of the University of California
*
- * RISC-V privileged architecture defined generic timer driver
+ * RISC-V architecturally-defined generic timer driver
*
- * This driver relies on RISC-V platform codes to provide the essential API
- * riscv_get_time() which is supposed to return the timer counter as defined
- * by the RISC-V privileged architecture spec.
- *
- * This driver can be used in both M-mode and S-mode U-Boot.
+ * This driver provides generic timer support for S-mode U-Boot.
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <timer.h>
-#include <asm/io.h>
-
-/**
- * riscv_get_time() - get the timer counter
- *
- * Platform codes should provide this API in order to make this driver function.
- *
- * @time: the 64-bit timer count as defined by the RISC-V privileged
- * architecture spec.
- * @return: 0 on success, -ve on error.
- */
-extern int riscv_get_time(u64 *time);
+#include <asm/csr.h>
static int riscv_timer_get_count(struct udevice *dev, u64 *count)
{
- return riscv_get_time(count);
+ if (IS_ENABLED(CONFIG_64BIT)) {
+ *count = csr_read(CSR_TIME);
+ } else {
+ u32 hi, lo;
+
+ do {
+ hi = csr_read(CSR_TIMEH);
+ lo = csr_read(CSR_TIME);
+ } while (hi != csr_read(CSR_TIMEH));
+
+ *count = ((u64)hi << 32) | lo;
+ }
+
+ return 0;
}
static int riscv_timer_probe(struct udevice *dev)
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index 5228486082..6a503c2f15 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -40,7 +40,9 @@ static int sandbox_timer_probe(struct udevice *dev)
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- if (!uc_priv->clock_rate)
+ if (dev_read_bool(dev, "sandbox,timebase-frequency-fallback"))
+ return timer_timebase_fallback(dev);
+ else if (!uc_priv->clock_rate)
uc_priv->clock_rate = SANDBOX_TIMER_RATE;
return 0;
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 14dde950a1..e9802c8b43 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -4,6 +4,7 @@
*/
#include <common.h>
+#include <cpu.h>
#include <dm.h>
#include <init.h>
#include <dm/lists.h>
@@ -79,6 +80,36 @@ static int timer_post_probe(struct udevice *dev)
return 0;
}
+/*
+ * TODO: should be CONFIG_IS_ENABLED(CPU), but the SPL config has _SUPPORT on
+ * the end...
+ */
+#if defined(CONFIG_CPU) || defined(CONFIG_SPL_CPU_SUPPORT)
+int timer_timebase_fallback(struct udevice *dev)
+{
+ struct udevice *cpu;
+ struct cpu_platdata *cpu_plat;
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Did we get our clock rate from the device tree? */
+ if (uc_priv->clock_rate)
+ return 0;
+
+ /* Fall back to timebase-frequency */
+ dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n");
+ cpu = cpu_get_current_dev();
+ if (!cpu)
+ return -ENODEV;
+
+ cpu_plat = dev_get_parent_platdata(cpu);
+ if (!cpu_plat)
+ return -ENODEV;
+
+ uc_priv->clock_rate = cpu_plat->timebase_freq;
+ return 0;
+}
+#endif
+
u64 timer_conv_64(u32 count)
{
/* increment tbh if tbl has rolled over */
diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index 1942c07c60..64831a4223 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -14,11 +14,14 @@
#include <log.h>
#include <spl.h>
#include <tpm-v2.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/iomap.h>
#include <asm/arch/pm.h>
#include <linux/delay.h>
+#include <dm/acpi.h>
enum {
TIMEOUT_INIT_MS = 30000, /* Very long timeout for TPM init */
@@ -581,6 +584,53 @@ static int cr50_i2c_cleanup(struct udevice *dev)
return 0;
}
+static int cr50_acpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ char scope[ACPI_PATH_MAX];
+ char name[ACPI_NAME_MAX];
+ const char *hid;
+ int ret;
+
+ ret = acpi_device_scope(dev, scope, sizeof(scope));
+ if (ret)
+ return log_msg_ret("scope", ret);
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+
+ hid = dev_read_string(dev, "acpi,hid");
+ if (!hid)
+ return log_msg_ret("hid", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, scope);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_string(ctx, "_HID", hid);
+ acpigen_write_name_integer(ctx, "_UID",
+ dev_read_u32_default(dev, "acpi,uid", 0));
+ acpigen_write_name_string(ctx, "_DDN",
+ dev_read_string(dev, "acpi,ddn"));
+ acpigen_write_sta(ctx, acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name(ctx, "_CRS");
+ acpigen_write_resourcetemplate_header(ctx);
+ ret = acpi_device_write_i2c_dev(ctx, dev);
+ if (ret < 0)
+ return log_msg_ret("i2c", ret);
+ ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev,
+ "ready-gpios");
+ if (ret < 0)
+ return log_msg_ret("irq_gpio", ret);
+
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
enum {
TPM_TIMEOUT_MS = 5,
SHORT_TIMEOUT_MS = 750,
@@ -653,6 +703,10 @@ static int cr50_i2c_probe(struct udevice *dev)
return 0;
}
+struct acpi_ops cr50_acpi_ops = {
+ .fill_ssdt = cr50_acpi_fill_ssdt,
+};
+
static const struct tpm_ops cr50_i2c_ops = {
.open = cr50_i2c_open,
.get_desc = cr50_i2c_get_desc,
@@ -675,5 +729,6 @@ U_BOOT_DRIVER(cr50_i2c) = {
.probe = cr50_i2c_probe,
.remove = cr50_i2c_cleanup,
.priv_auto_alloc_size = sizeof(struct cr50_priv),
+ ACPI_OPS_PTR(&cr50_acpi_ops)
.flags = DM_FLAG_OS_PREPARE,
};
diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c
index a08c694559..acff79ae1c 100644
--- a/drivers/usb/cdns3/ep0.c
+++ b/drivers/usb/cdns3/ep0.c
@@ -11,8 +11,9 @@
*/
#include <cpu_func.h>
-#include <asm/cache.h>
+#include <dm.h>
#include <dm/device_compat.h>
+#include <asm/cache.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/usb/composite.h>
@@ -810,7 +811,7 @@ int cdns3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
- dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name);
+ dev_dbg(priv_ep->cdns3_dev->dev, "Wedge for %s\n", ep->name);
cdns3_gadget_ep_set_halt(ep, 1);
priv_ep->flags |= EP_WEDGE;
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index 8f81d17ec8..83dbb5a103 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -2399,8 +2399,7 @@ static void cdns3_gadget_udc_set_speed(struct usb_gadget *gadget,
case USB_SPEED_SUPER:
break;
default:
- dev_err(cdns->dev, "invalid speed parameter %d\n",
- speed);
+ dev_err(priv_dev->dev, "invalid speed parameter %d\n", speed);
}
priv_dev->gadget.speed = speed;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 8682556589..2e003530a1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -592,7 +592,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize gadget\n");
+ dev_err(dwc->dev, "failed to initialize gadget\n");
return ret;
}
break;
@@ -600,7 +600,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize host\n");
+ dev_err(dwc->dev, "failed to initialize host\n");
return ret;
}
break;
@@ -608,18 +608,19 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize host\n");
+ dev_err(dwc->dev, "failed to initialize host\n");
return ret;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize gadget\n");
+ dev_err(dwc->dev, "failed to initialize gadget\n");
return ret;
}
break;
default:
- dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
+ dev_err(dwc->dev,
+ "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
@@ -768,7 +769,7 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
ret = dwc3_core_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize core\n");
+ dev_err(dwc->dev, "failed to initialize core\n");
goto err0;
}
@@ -974,7 +975,7 @@ int dwc3_init(struct dwc3 *dwc)
ret = dwc3_core_init(dwc);
if (ret) {
- dev_err(dev, "failed to initialize core\n");
+ dev_err(dwc->dev, "failed to initialize core\n");
goto core_fail;
}
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 551f682024..36fa16ad4e 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -10,7 +10,6 @@
#include <common.h>
#include <cpu_func.h>
#include <log.h>
-#include <asm-generic/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
@@ -449,6 +448,7 @@ static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "ti,am654-dwc3" },
{ .compatible = "rockchip,rk3328-dwc3" },
{ .compatible = "rockchip,rk3399-dwc3" },
+ { .compatible = "qcom,dwc3" },
{ }
};
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 385bed3e34..75ac993bc6 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -14,6 +14,7 @@
*/
#include <common.h>
#include <cpu_func.h>
+#include <dm.h>
#include <dm/device_compat.h>
#include <linux/bug.h>
#include <linux/kernel.h>
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2aec874e1d..4e68fb0a82 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -17,6 +17,7 @@
#include <cpu_func.h>
#include <log.h>
#include <malloc.h>
+#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <linux/bug.h>
@@ -633,7 +634,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
strlcat(dep->name, "-int", sizeof(dep->name));
break;
default:
- dev_err(dwc->dev, "invalid endpoint transfer type\n");
+ dev_err(dep->dwc->dev, "invalid endpoint transfer type\n");
}
spin_lock_irqsave(&dwc->lock, flags);
@@ -708,10 +709,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
{
struct dwc3_trb *trb;
- dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
- dep->name, req, (unsigned long long) dma,
- length, last ? " last" : "",
- chain ? " chain" : "");
+ dev_vdbg(dep->dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+ dep->name, req, (unsigned long long)dma,
+ length, last ? " last" : "", chain ? " chain" : "");
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
@@ -1074,21 +1074,22 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
spin_lock_irqsave(&dwc->lock, flags);
if (!dep->endpoint.desc) {
- dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
- request, ep->name);
+ dev_dbg(dep->dwc->dev,
+ "trying to queue request %p to disabled %s\n", request,
+ ep->name);
ret = -ESHUTDOWN;
goto out;
}
if (req->dep != dep) {
- WARN(true, "request %p belongs to '%s'\n",
- request, req->dep->name);
+ WARN(true, "request %p belongs to '%s'\n", request,
+ req->dep->name);
ret = -EINVAL;
goto out;
}
- dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
- request, ep->name, request->length);
+ dev_vdbg(dep->dwc->dev, "queing request %p to %s length %d\n",
+ request, ep->name, request->length);
ret = __dwc3_gadget_ep_queue(dep, req);
diff --git a/drivers/usb/dwc3/ti_usb_phy.c b/drivers/usb/dwc3/ti_usb_phy.c
index f8ab06482c..f476810763 100644
--- a/drivers/usb/dwc3/ti_usb_phy.c
+++ b/drivers/usb/dwc3/ti_usb_phy.c
@@ -129,7 +129,7 @@ static struct usb3_dpll_params *ti_usb3_get_dpll_params(struct ti_usb_phy *phy)
return &dpll_map->params;
}
- dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+ log_err("No DPLL configuration for %lu Hz SYS CLK\n", rate);
return NULL;
}
@@ -269,7 +269,7 @@ int ti_usb_phy_uboot_init(struct ti_usb_phy_device *dev)
phy = devm_kzalloc(NULL, sizeof(*phy), GFP_KERNEL);
if (!phy) {
- dev_err(NULL, "unable to alloc mem for TI USB3 PHY\n");
+ log_err("unable to alloc mem for TI USB3 PHY\n");
return -ENOMEM;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1c374a7bd8..4eb7b34e24 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -200,8 +200,7 @@ config USB_EHCI_TEGRA
config USB_EHCI_ZYNQ
bool "Support for Xilinx Zynq on-chip EHCI USB controller"
- depends on ARCH_ZYNQ
- default y
+ default y if ARCH_ZYNQ
---help---
Enable support for Zynq on-chip EHCI USB controller
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index cefe9d83b1..f1d13b1c1d 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -114,7 +114,8 @@ static void init_fslspclksel(struct dwc2_core_regs *regs)
* @param regs Programming view of DWC_otg controller.
* @param num Tx FIFO to flush.
*/
-static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
+static void dwc_otg_flush_tx_fifo(struct udevice *dev,
+ struct dwc2_core_regs *regs, const int num)
{
int ret;
@@ -134,7 +135,8 @@ static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
*
* @param regs Programming view of DWC_otg controller.
*/
-static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
+static void dwc_otg_flush_rx_fifo(struct udevice *dev,
+ struct dwc2_core_regs *regs)
{
int ret;
@@ -152,7 +154,8 @@ static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
-static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
+static void dwc_otg_core_reset(struct udevice *dev,
+ struct dwc2_core_regs *regs)
{
int ret;
@@ -284,8 +287,8 @@ static void dwc_otg_core_host_init(struct udevice *dev,
clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
/* Make sure the FIFOs are flushed. */
- dwc_otg_flush_tx_fifo(regs, 0x10); /* All Tx FIFOs */
- dwc_otg_flush_rx_fifo(regs);
+ dwc_otg_flush_tx_fifo(dev, regs, 0x10); /* All Tx FIFOs */
+ dwc_otg_flush_rx_fifo(dev, regs);
/* Flush out any leftover queued requests. */
num_channels = readl(&regs->ghwcfg2);
@@ -306,7 +309,7 @@ static void dwc_otg_core_host_init(struct udevice *dev,
ret = wait_for_bit_le32(&regs->hc_regs[i].hcchar,
DWC2_HCCHAR_CHEN, false, 1000, false);
if (ret)
- dev_info("%s: Timeout!\n", __func__);
+ dev_info(dev, "%s: Timeout!\n", __func__);
}
/* Turn on the vbus power. */
@@ -330,8 +333,9 @@ static void dwc_otg_core_host_init(struct udevice *dev,
*
* @param regs Programming view of the DWC_otg controller
*/
-static void dwc_otg_core_init(struct dwc2_priv *priv)
+static void dwc_otg_core_init(struct udevice *dev)
{
+ struct dwc2_priv *priv = dev_get_priv(dev);
struct dwc2_core_regs *regs = priv->regs;
uint32_t ahbcfg = 0;
uint32_t usbcfg = 0;
@@ -360,7 +364,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv)
writel(usbcfg, &regs->gusbcfg);
/* Reset the Controller */
- dwc_otg_core_reset(regs);
+ dwc_otg_core_reset(dev, regs);
/*
* This programming sequence needs to happen in FS mode before
@@ -372,7 +376,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv)
setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_PHYSEL);
/* Reset after a PHY select */
- dwc_otg_core_reset(regs);
+ dwc_otg_core_reset(dev, regs);
/*
* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
@@ -419,7 +423,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv)
writel(usbcfg, &regs->gusbcfg);
/* Reset after setting the PHY parameters */
- dwc_otg_core_reset(regs);
+ dwc_otg_core_reset(dev, regs);
#endif
usbcfg = readl(&regs->gusbcfg);
@@ -1128,7 +1132,12 @@ int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
for (;;) {
if (get_timer(0) > timeout) {
- dev_err(dev, "Timeout poll on interrupt endpoint\n");
+#if CONFIG_IS_ENABLED(DM_USB)
+ dev_err(dev->dev,
+ "Timeout poll on interrupt endpoint\n");
+#else
+ log_err("Timeout poll on interrupt endpoint\n");
+#endif
return -ETIMEDOUT;
}
ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
@@ -1194,7 +1203,7 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv)
priv->ext_vbus = 0;
#endif
- dwc_otg_core_init(priv);
+ dwc_otg_core_init(dev);
dwc_otg_core_host_init(dev, regs);
clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
@@ -1320,12 +1329,10 @@ static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev,
static int dwc2_usb_ofdata_to_platdata(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
- fdt_addr_t addr;
- addr = dev_read_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
+ priv->regs = dev_read_addr_ptr(dev);
+ if (!priv->regs)
return -EINVAL;
- priv->regs = (struct dwc2_core_regs *)addr;
priv->oc_disable = dev_read_bool(dev, "disable-over-current");
priv->hnp_srp_disable = dev_read_bool(dev, "hnp-srp-disable");
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f79f06320b..8933f60843 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1762,13 +1762,13 @@ int ehci_setup_phy(struct udevice *dev, struct phy *phy, int index)
} else {
ret = generic_phy_init(phy);
if (ret) {
- dev_err(dev, "failed to init usb phy\n");
+ dev_dbg(dev, "failed to init usb phy\n");
return ret;
}
ret = generic_phy_power_on(phy);
if (ret) {
- dev_err(dev, "failed to power on usb phy\n");
+ dev_dbg(dev, "failed to power on usb phy\n");
return generic_phy_exit(phy);
}
}
@@ -1786,13 +1786,13 @@ int ehci_shutdown_phy(struct udevice *dev, struct phy *phy)
if (generic_phy_valid(phy)) {
ret = generic_phy_power_off(phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
ret = generic_phy_exit(phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c
index b84bf8ac0f..ed5e500b2c 100644
--- a/drivers/usb/host/ohci-generic.c
+++ b/drivers/usb/host/ohci-generic.c
@@ -41,13 +41,13 @@ static int ohci_setup_phy(struct udevice *dev, int index)
} else {
ret = generic_phy_init(&priv->phy);
if (ret) {
- dev_err(dev, "failed to init usb phy\n");
+ dev_dbg(dev, "failed to init usb phy\n");
return ret;
}
ret = generic_phy_power_on(&priv->phy);
if (ret) {
- dev_err(dev, "failed to power on usb phy\n");
+ dev_dbg(dev, "failed to power on usb phy\n");
return generic_phy_exit(&priv->phy);
}
}
@@ -63,13 +63,13 @@ static int ohci_shutdown_phy(struct udevice *dev)
if (generic_phy_valid(&priv->phy)) {
ret = generic_phy_power_off(&priv->phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
ret = generic_phy_exit(&priv->phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(dev, "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 1da0524aa0..0b49614995 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -236,8 +236,7 @@ static void xhci_link_segments(struct xhci_segment *prev,
*/
val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
val &= ~TRB_TYPE_BITMASK;
- val |= (TRB_LINK << TRB_TYPE_SHIFT);
-
+ val |= TRB_TYPE(TRB_LINK);
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
}
@@ -826,25 +825,22 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
/* Step 4 - ring already allocated */
/* Step 5 */
- ep0_ctx->ep_info2 = cpu_to_le32(CTRL_EP << EP_TYPE_SHIFT);
+ ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP));
debug("SPEED = %d\n", speed);
switch (speed) {
case USB_SPEED_SUPER:
- ep0_ctx->ep_info2 |= cpu_to_le32(((512 & MAX_PACKET_MASK) <<
- MAX_PACKET_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512));
debug("Setting Packet size = 512bytes\n");
break;
case USB_SPEED_HIGH:
/* USB core guesses at a 64-byte max packet first for FS devices */
case USB_SPEED_FULL:
- ep0_ctx->ep_info2 |= cpu_to_le32(((64 & MAX_PACKET_MASK) <<
- MAX_PACKET_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64));
debug("Setting Packet size = 64bytes\n");
break;
case USB_SPEED_LOW:
- ep0_ctx->ep_info2 |= cpu_to_le32(((8 & MAX_PACKET_MASK) <<
- MAX_PACKET_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8));
debug("Setting Packet size = 8bytes\n");
break;
default:
@@ -853,9 +849,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
}
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
- ep0_ctx->ep_info2 |=
- cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) |
- ((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT));
+ ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
trb_64 = virt_to_phys(virt_dev->eps[0].ring->first_seg->trbs);
ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 8ff71854fc..f3f181dae0 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -258,6 +258,7 @@ static int xhci_mtk_probe(struct udevice *dev)
if (ret)
goto ssusb_init_err;
+ mtk->ctrl.quirks = XHCI_MTK_HOST;
hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd +
HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase)));
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index 8fc51df3d1..5379dba566 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -146,6 +146,7 @@ static int xhci_rcar_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id xhci_rcar_ids[] = {
+ { .compatible = "renesas,rcar-gen3-xhci" },
{ .compatible = "renesas,xhci-r8a7795" },
{ .compatible = "renesas,xhci-r8a7796" },
{ .compatible = "renesas,xhci-r8a77965" },
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 092ed6eaf1..b118207d93 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -298,55 +298,57 @@ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id,
xhci_writel(&ctrl->dba->doorbell[0], DB_VALUE_HOST);
}
-/**
- * The TD size is the number of bytes remaining in the TD (including this TRB),
- * right shifted by 10.
- * It must fit in bits 21:17, so it can't be bigger than 31.
+/*
+ * For xHCI 1.0 host controllers, TD size is the number of max packet sized
+ * packets remaining in the TD (*not* including this TRB).
*
- * @param remainder remaining packets to be sent
- * @return remainder if remainder is less than max else max
- */
-static u32 xhci_td_remainder(unsigned int remainder)
-{
- u32 max = (1 << (21 - 17 + 1)) - 1;
-
- if ((remainder >> 10) >= max)
- return max << 17;
- else
- return (remainder >> 10) << 17;
-}
-
-/**
- * Finds out the remanining packets to be sent
+ * Total TD packet count = total_packet_count =
+ * DIV_ROUND_UP(TD size in bytes / wMaxPacketSize)
+ *
+ * Packets transferred up to and including this TRB = packets_transferred =
+ * rounddown(total bytes transferred including this TRB / wMaxPacketSize)
+ *
+ * TD size = total_packet_count - packets_transferred
+ *
+ * For xHCI 0.96 and older, TD size field should be the remaining bytes
+ * including this TRB, right shifted by 10
*
- * @param running_total total size sent so far
+ * For all hosts it must fit in bits 21:17, so it can't be bigger than 31.
+ * This is taken care of in the TRB_TD_SIZE() macro
+ *
+ * The last TRB in a TD must have the TD size set to zero.
+ *
+ * @param ctrl host controller data structure
+ * @param transferred total size sent so far
* @param trb_buff_len length of the TRB Buffer
- * @param total_packet_count total packet count
- * @param maxpacketsize max packet size of current pipe
- * @param num_trbs_left number of TRBs left to be processed
- * @return 0 if running_total or trb_buff_len is 0, else remainder
+ * @param td_total_len total packet count
+ * @param maxp max packet size of current pipe
+ * @param more_trbs_coming indicate last trb in TD
+ * @return remainder
*/
-static u32 xhci_v1_0_td_remainder(int running_total,
- int trb_buff_len,
- unsigned int total_packet_count,
- int maxpacketsize,
- unsigned int num_trbs_left)
+static u32 xhci_td_remainder(struct xhci_ctrl *ctrl, int transferred,
+ int trb_buff_len, unsigned int td_total_len,
+ int maxp, bool more_trbs_coming)
{
- int packets_transferred;
+ u32 total_packet_count;
+
+ /* MTK xHCI 0.96 contains some features from 1.0 */
+ if (ctrl->hci_version < 0x100 && !(ctrl->quirks & XHCI_MTK_HOST))
+ return ((td_total_len - transferred) >> 10);
/* One TRB with a zero-length data packet. */
- if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0))
+ if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
+ trb_buff_len == td_total_len)
return 0;
- /*
- * All the TRB queueing functions don't count the current TRB in
- * running_total.
- */
- packets_transferred = (running_total + trb_buff_len) / maxpacketsize;
+ /* for MTK xHCI 0.96, TD size include this TRB, but not in 1.x */
+ if ((ctrl->quirks & XHCI_MTK_HOST) && (ctrl->hci_version < 0x100))
+ trb_buff_len = 0;
+
+ total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
- if ((total_packet_count - packets_transferred) > 31)
- return 31 << 17;
- return (total_packet_count - packets_transferred) << 17;
+ /* Queueing functions don't count the current TRB into transferred */
+ return (total_packet_count - ((transferred + trb_buff_len) / maxp));
}
/**
@@ -572,7 +574,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
union xhci_trb *event;
int running_total, trb_buff_len;
- unsigned int total_packet_count;
+ bool more_trbs_coming = true;
int maxpacketsize;
u64 addr;
int ret;
@@ -636,8 +638,6 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
running_total = 0;
maxpacketsize = usb_maxpacket(udev, pipe);
- total_packet_count = DIV_ROUND_UP(length, maxpacketsize);
-
/* How much data is in the first TRB? */
/*
* How much data is (potentially) left before the 64KB boundary?
@@ -672,34 +672,30 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
- if (num_trbs > 1)
+ if (num_trbs > 1) {
field |= TRB_CHAIN;
- else
+ } else {
field |= TRB_IOC;
+ more_trbs_coming = false;
+ }
/* Only set interrupt on short packet for IN endpoints */
if (usb_pipein(pipe))
field |= TRB_ISP;
/* Set the TRB length, TD size, and interrupter fields. */
- if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) < 0x100)
- remainder = xhci_td_remainder(length - running_total);
- else
- remainder = xhci_v1_0_td_remainder(running_total,
- trb_buff_len,
- total_packet_count,
- maxpacketsize,
- num_trbs - 1);
+ remainder = xhci_td_remainder(ctrl, running_total, trb_buff_len,
+ length, maxpacketsize,
+ more_trbs_coming);
- length_field = ((trb_buff_len & TRB_LEN_MASK) |
- remainder |
- ((0 & TRB_INTR_TARGET_MASK) <<
- TRB_INTR_TARGET_SHIFT));
+ length_field = (TRB_LEN(trb_buff_len) |
+ TRB_TD_SIZE(remainder) |
+ TRB_INTR_TARGET(0));
trb_fields[0] = lower_32_bits(addr);
trb_fields[1] = upper_32_bits(addr);
trb_fields[2] = length_field;
- trb_fields[3] = field | (TRB_NORMAL << TRB_TYPE_SHIFT);
+ trb_fields[3] = field | TRB_TYPE(TRB_NORMAL);
queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
@@ -764,6 +760,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
struct xhci_ring *ep_ring;
union xhci_trb *event;
+ u32 remainder;
debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
req->request, req->request,
@@ -825,17 +822,17 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
/* Queue setup TRB - see section 6.4.1.2.1 */
/* FIXME better way to translate setup_packet into two u32 fields? */
field = 0;
- field |= TRB_IDT | (TRB_SETUP << TRB_TYPE_SHIFT);
+ field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
if (start_cycle == 0)
field |= 0x1;
/* xHCI 1.0 6.4.1.2.1: Transfer Type field */
- if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) >= 0x100) {
+ if (ctrl->hci_version >= 0x100 || ctrl->quirks & XHCI_MTK_HOST) {
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
- field |= (TRB_DATA_IN << TRB_TX_TYPE_SHIFT);
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
else
- field |= (TRB_DATA_OUT << TRB_TX_TYPE_SHIFT);
+ field |= TRB_TX_TYPE(TRB_DATA_OUT);
}
}
@@ -851,8 +848,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
trb_fields[1] = le16_to_cpu(req->index) |
le16_to_cpu(req->length) << 16;
/* TRB_LEN | (TRB_INTR_TARGET) */
- trb_fields[2] = (8 | ((0 & TRB_INTR_TARGET_MASK) <<
- TRB_INTR_TARGET_SHIFT));
+ trb_fields[2] = (TRB_LEN(8) | TRB_INTR_TARGET(0));
/* Immediate data in pointer */
trb_fields[3] = field;
queue_trb(ctrl, ep_ring, true, trb_fields);
@@ -862,16 +858,18 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
/* If there's data, queue data TRBs */
/* Only set interrupt on short packet for IN endpoints */
if (usb_pipein(pipe))
- field = TRB_ISP | (TRB_DATA << TRB_TYPE_SHIFT);
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
else
- field = (TRB_DATA << TRB_TYPE_SHIFT);
+ field = TRB_TYPE(TRB_DATA);
- length_field = (length & TRB_LEN_MASK) | xhci_td_remainder(length) |
- ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT);
+ remainder = xhci_td_remainder(ctrl, 0, length, length,
+ usb_maxpacket(udev, pipe), true);
+ length_field = TRB_LEN(length) | TRB_TD_SIZE(remainder) |
+ TRB_INTR_TARGET(0);
debug("length_field = %d, length = %d,"
"xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n",
- length_field, (length & TRB_LEN_MASK),
- xhci_td_remainder(length), 0);
+ length_field, TRB_LEN(length),
+ TRB_TD_SIZE(remainder), 0);
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
@@ -901,11 +899,10 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
trb_fields[0] = 0;
trb_fields[1] = 0;
- trb_fields[2] = ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT);
+ trb_fields[2] = TRB_INTR_TARGET(0);
/* Event on completion */
trb_fields[3] = field | TRB_IOC |
- (TRB_STATUS << TRB_TYPE_SHIFT) |
- ep_ring->cycle_state;
+ TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
queue_trb(ctrl, ep_ring, false, trb_fields);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 126dabc11b..3547a9bad1 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -33,6 +33,7 @@
#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/iopoll.h>
#include <usb/xhci.h>
#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
@@ -143,23 +144,19 @@ struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev)
* @param usec time to wait till
* @return 0 if handshake is success else < 0 on failure
*/
-static int handshake(uint32_t volatile *ptr, uint32_t mask,
- uint32_t done, int usec)
+static int
+handshake(uint32_t volatile *ptr, uint32_t mask, uint32_t done, int usec)
{
uint32_t result;
+ int ret;
+
+ ret = readx_poll_sleep_timeout(xhci_readl, ptr, result,
+ (result & mask) == done || result == U32_MAX,
+ 1, usec);
+ if (result == U32_MAX) /* card removed */
+ return -ENODEV;
- do {
- result = xhci_readl(ptr);
- if (result == ~(uint32_t)0)
- return -ENODEV;
- result &= mask;
- if (result == done)
- return 0;
- usec--;
- udelay(1);
- } while (usec > 0);
-
- return -ETIMEDOUT;
+ return ret;
}
/**
@@ -618,8 +615,7 @@ static int xhci_set_configuration(struct usb_device *udev)
cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
EP_INTERVAL(interval) | EP_MULT(mult));
- ep_ctx[ep_index]->ep_info2 =
- cpu_to_le32(ep_type << EP_TYPE_SHIFT);
+ ep_ctx[ep_index]->ep_info2 = cpu_to_le32(EP_TYPE(ep_type));
ep_ctx[ep_index]->ep_info2 |=
cpu_to_le32(MAX_PACKET
(get_unaligned(&endpt_desc->wMaxPacketSize)));
@@ -650,7 +646,7 @@ static int xhci_set_configuration(struct usb_device *udev)
* are put into reserved DWs in Slot and Endpoint Contexts
* for synchronous endpoints.
*/
- if (IS_ENABLED(CONFIG_USB_XHCI_MTK)) {
+ if (ctrl->quirks & XHCI_MTK_HOST) {
ep_ctx[ep_index]->reserved[0] =
cpu_to_le32(EP_BPKTS(1) | EP_BBM(1));
}
@@ -832,8 +828,7 @@ int xhci_check_maxpacket(struct usb_device *udev)
ctrl->devs[slot_id]->out_ctx, ep_index);
in_ctx = ctrl->devs[slot_id]->in_ctx;
ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
- ep_ctx->ep_info2 &= cpu_to_le32(~((0xffff & MAX_PACKET_MASK)
- << MAX_PACKET_SHIFT));
+ ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET(MAX_PACKET_MASK));
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
/*
@@ -1257,8 +1252,7 @@ static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
return -ENOMEM;
reg = xhci_readl(&hccr->cr_hcsparams1);
- descriptor.hub.bNbrPorts = ((reg & HCS_MAX_PORTS_MASK) >>
- HCS_MAX_PORTS_SHIFT);
+ descriptor.hub.bNbrPorts = HCS_MAX_PORTS(reg);
printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
/* Port Indicators */
@@ -1283,6 +1277,7 @@ static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
reg = HC_VERSION(xhci_readl(&hccr->cr_capbase));
printf("USB XHCI %x.%02x\n", reg >> 8, reg & 0xff);
+ ctrl->hci_version = reg;
return 0;
}
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 53c336fc3f..187db7794b 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -257,7 +257,7 @@ static int sunxi_musb_enable(struct musb *musb)
ret = generic_phy_power_on(&glue->phy);
if (ret) {
- pr_err("failed to power on USB PHY\n");
+ pr_debug("failed to power on USB PHY\n");
return ret;
}
}
@@ -281,7 +281,7 @@ static void sunxi_musb_disable(struct musb *musb)
if (is_host_enabled(musb)) {
ret = generic_phy_power_off(&glue->phy);
if (ret) {
- pr_err("failed to power off USB PHY\n");
+ pr_debug("failed to power off USB PHY\n");
return;
}
}
@@ -301,21 +301,21 @@ static int sunxi_musb_init(struct musb *musb)
ret = clk_enable(&glue->clk);
if (ret) {
- dev_err(dev, "failed to enable clock\n");
+ dev_err(musb->controller, "failed to enable clock\n");
return ret;
}
if (reset_valid(&glue->rst)) {
ret = reset_deassert(&glue->rst);
if (ret) {
- dev_err(dev, "failed to deassert reset\n");
+ dev_err(musb->controller, "failed to deassert reset\n");
goto err_clk;
}
}
ret = generic_phy_init(&glue->phy);
if (ret) {
- dev_err(dev, "failed to init USB PHY\n");
+ dev_dbg(musb->controller, "failed to init USB PHY\n");
goto err_rst;
}
@@ -352,7 +352,8 @@ static int sunxi_musb_exit(struct musb *musb)
if (generic_phy_valid(&glue->phy)) {
ret = generic_phy_exit(&glue->phy);
if (ret) {
- dev_err(dev, "failed to power off usb phy\n");
+ dev_dbg(musb->controller,
+ "failed to power off usb phy\n");
return ret;
}
}
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index badade353e..3f07f4eb29 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -1983,8 +1983,6 @@ static void *video_logo(void)
static int cfb_fb_is_in_dram(void)
{
struct bd_info *bd = gd->bd;
-#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || \
-defined(CONFIG_SANDBOX) || defined(CONFIG_X86)
ulong start, end;
int i;
@@ -1995,11 +1993,7 @@ defined(CONFIG_SANDBOX) || defined(CONFIG_X86)
(ulong)video_fb_address < end)
return 1;
}
-#else
- if ((ulong)video_fb_address >= bd->bi_memstart &&
- (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize)
- return 1;
-#endif
+
return 0;
}
diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c
index b7bfbb5e50..2743836fb4 100644
--- a/drivers/video/dw_mipi_dsi.c
+++ b/drivers/video/dw_mipi_dsi.c
@@ -314,7 +314,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
val, !(val & GEN_CMD_FULL),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "failed to get available command FIFO\n");
+ dev_err(dsi->dsi_host.dev,
+ "failed to get available command FIFO\n");
return ret;
}
@@ -325,7 +326,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
val, (val & mask) == mask,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "failed to write command FIFO\n");
+ dev_err(dsi->dsi_host.dev, "failed to write command FIFO\n");
return ret;
}
@@ -357,7 +358,7 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
val, !(val & GEN_PLD_W_FULL),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev,
+ dev_err(dsi->dsi_host.dev,
"failed to get available write payload FIFO\n");
return ret;
}
@@ -380,7 +381,7 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
val, !(val & GEN_RD_CMD_BUSY),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "Timeout during read operation\n");
+ dev_err(dsi->dsi_host.dev, "Timeout during read operation\n");
return ret;
}
@@ -390,7 +391,8 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
val, !(val & GEN_PLD_R_EMPTY),
CMD_PKT_STATUS_TIMEOUT_US);
if (ret) {
- dev_err(dsi->dev, "Read payload FIFO is empty\n");
+ dev_err(dsi->dsi_host.dev,
+ "Read payload FIFO is empty\n");
return ret;
}
@@ -411,7 +413,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
ret = mipi_dsi_create_packet(&packet, msg);
if (ret) {
- dev_err(dsi->dev, "failed to create packet: %d\n", ret);
+ dev_err(host->dev, "failed to create packet: %d\n", ret);
return ret;
}
@@ -702,13 +704,15 @@ static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi)
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val,
val & PHY_LOCK, PHY_STATUS_TIMEOUT_US);
if (ret)
- dev_warn(dsi->dev, "failed to wait phy lock state\n");
+ dev_warn(dsi->dsi_host.dev,
+ "failed to wait phy lock state\n");
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
val, val & PHY_STOP_STATE_CLK_LANE,
PHY_STATUS_TIMEOUT_US);
if (ret)
- dev_warn(dsi->dev, "failed to wait phy clk lane stop state\n");
+ dev_warn(dsi->dsi_host.dev,
+ "failed to wait phy clk lane stop state\n");
}
static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
@@ -729,7 +733,7 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi,
ret = phy_ops->get_lane_mbps(dsi->device, timings, device->lanes,
device->format, &dsi->lane_mbps);
if (ret)
- dev_warn(dsi->dev, "Phy get_lane_mbps() failed\n");
+ dev_warn(dsi->dsi_host.dev, "Phy get_lane_mbps() failed\n");
dw_mipi_dsi_init_pll(dsi);
dw_mipi_dsi_dpi_config(dsi, timings);
@@ -748,7 +752,7 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi,
ret = phy_ops->init(dsi->device);
if (ret)
- dev_warn(dsi->dev, "Phy init() failed\n");
+ dev_warn(dsi->dsi_host.dev, "Phy init() failed\n");
dw_mipi_dsi_dphy_enable(dsi);
diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c
index 283151398b..9d5abacc2b 100644
--- a/drivers/video/stm32/stm32_dsi.c
+++ b/drivers/video/stm32/stm32_dsi.c
@@ -359,8 +359,7 @@ static int stm32_dsi_attach(struct udevice *dev)
ret = panel_get_display_timing(priv->panel, &timings);
if (ret) {
- ret = fdtdec_decode_display_timing(gd->fdt_blob,
- dev_of_offset(priv->panel),
+ ret = ofnode_decode_display_timing(dev_ofnode(priv->panel),
0, &timings);
if (ret) {
dev_err(dev, "decode display timing error %d\n", ret);
diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c
index 2f3427a32e..7fff735930 100644
--- a/drivers/video/stm32/stm32_ltdc.c
+++ b/drivers/video/stm32/stm32_ltdc.c
@@ -366,8 +366,7 @@ static int stm32_ltdc_probe(struct udevice *dev)
ret = panel_get_display_timing(panel, &timings);
if (ret) {
- ret = fdtdec_decode_display_timing(gd->fdt_blob,
- dev_of_offset(panel),
+ ret = ofnode_decode_display_timing(dev_ofnode(panel),
0, &timings);
if (ret) {
dev_err(dev, "decode display timing error %d\n", ret);