summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig23
-rw-r--r--drivers/clk/Makefile4
-rw-r--r--drivers/clk/analogbits/Kconfig4
-rw-r--r--drivers/clk/analogbits/Makefile3
-rw-r--r--drivers/clk/analogbits/wrpll-cln28hpc.c (renamed from drivers/clk/sifive/wrpll-cln28hpc.c)168
-rw-r--r--drivers/clk/clk-divider.c155
-rw-r--r--drivers/clk/clk-fixed-factor.c80
-rw-r--r--drivers/clk/clk-mux.c172
-rw-r--r--drivers/clk/clk-uclass.c62
-rw-r--r--drivers/clk/clk.c57
-rw-r--r--drivers/clk/clk_fixed_factor.c3
-rw-r--r--drivers/clk/clk_fixed_rate.c8
-rw-r--r--drivers/clk/clk_sandbox_ccf.c185
-rw-r--r--drivers/clk/clk_stm32mp1.c9
-rw-r--r--drivers/clk/imx/Kconfig16
-rw-r--r--drivers/clk/imx/Makefile2
-rw-r--r--drivers/clk/imx/clk-gate2.c103
-rw-r--r--drivers/clk/imx/clk-imx6q.c179
-rw-r--r--drivers/clk/imx/clk-pfd.c90
-rw-r--r--drivers/clk/imx/clk-pllv3.c82
-rw-r--r--drivers/clk/imx/clk.h69
-rw-r--r--drivers/clk/rockchip/clk_rk3188.c3
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c88
-rw-r--r--drivers/clk/sifive/Kconfig10
-rw-r--r--drivers/clk/sifive/Makefile4
-rw-r--r--drivers/clk/sifive/analogbits-wrpll-cln28hpc.h101
-rw-r--r--drivers/clk/sifive/fu540-prci.c123
-rw-r--r--drivers/clk/sifive/gemgxl-mgmt.c60
-rw-r--r--drivers/core/device.c17
-rw-r--r--drivers/core/of_addr.c4
-rw-r--r--drivers/core/ofnode.c10
-rw-r--r--drivers/core/read.c5
-rw-r--r--drivers/firmware/ti_sci.c291
-rw-r--r--drivers/firmware/ti_sci.h50
-rw-r--r--drivers/gpio/mxc_gpio.c2
-rw-r--r--drivers/gpio/mxs_gpio.c148
-rw-r--r--drivers/misc/imx8/scu_api.c28
-rw-r--r--drivers/mmc/am654_sdhci.c114
-rw-r--r--drivers/mmc/mmc_spi.c4
-rw-r--r--drivers/mmc/rockchip_sdhci.c8
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.c2
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.h73
-rw-r--r--drivers/mtd/nand/raw/mxs_nand_dt.c2
-rw-r--r--drivers/mtd/nand/raw/mxs_nand_spl.c2
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c4
-rw-r--r--drivers/net/Kconfig39
-rw-r--r--drivers/net/Makefile3
-rw-r--r--drivers/net/designware.c28
-rw-r--r--drivers/net/fec_mxc.c1
-rw-r--r--drivers/net/fsl_enetc.c597
-rw-r--r--drivers/net/fsl_enetc.h229
-rw-r--r--drivers/net/fsl_enetc_mdio.c149
-rw-r--r--drivers/net/macb.c208
-rw-r--r--drivers/net/macb.h870
-rw-r--r--drivers/net/mdio_mux_sandbox.c97
-rw-r--r--drivers/net/mdio_sandbox.c16
-rw-r--r--drivers/net/phy/aquantia.c28
-rw-r--r--drivers/net/phy/phy.c11
-rw-r--r--drivers/net/sun8i_emac.c29
-rw-r--r--drivers/net/ti/davinci_emac.c77
-rw-r--r--drivers/net/tsec.c59
-rw-r--r--drivers/pinctrl/nxp/Kconfig10
-rw-r--r--drivers/pinctrl/nxp/Makefile1
-rw-r--r--drivers/pinctrl/nxp/pinctrl-mxs.c190
-rw-r--r--drivers/pinctrl/nxp/pinctrl-mxs.h61
-rw-r--r--drivers/power/domain/ti-sci-power-domain.c31
-rw-r--r--drivers/power/pmic/bd71837.c32
-rw-r--r--drivers/power/regulator/Kconfig17
-rw-r--r--drivers/power/regulator/Makefile1
-rw-r--r--drivers/power/regulator/bd71837.c468
-rw-r--r--drivers/pwm/Kconfig5
-rw-r--r--drivers/pwm/pwm-imx.c110
-rw-r--r--drivers/ram/Kconfig1
-rw-r--r--drivers/ram/rockchip/Kconfig33
-rw-r--r--drivers/ram/rockchip/Makefile3
-rw-r--r--drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc1570
-rw-r--r--drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc1570
-rw-r--r--drivers/ram/rockchip/sdram_debug.c147
-rw-r--r--drivers/ram/rockchip/sdram_rk322x.c29
-rw-r--r--drivers/ram/rockchip/sdram_rk3399.c2208
-rw-r--r--drivers/remoteproc/Kconfig30
-rw-r--r--drivers/remoteproc/Makefile5
-rw-r--r--drivers/remoteproc/rproc-elf-loader.c106
-rw-r--r--drivers/remoteproc/sandbox_testproc.c19
-rw-r--r--drivers/remoteproc/stm32_copro.c257
-rw-r--r--drivers/remoteproc/ti_k3_arm64_rproc.c (renamed from drivers/remoteproc/k3_rproc.c)136
-rw-r--r--drivers/remoteproc/ti_sci_proc.h121
-rw-r--r--drivers/rtc/Kconfig6
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/stm32_rtc.c323
-rw-r--r--drivers/serial/serial_mxc.c4
-rw-r--r--drivers/spi/Kconfig21
-rw-r--r--drivers/spi/Makefile3
-rw-r--r--drivers/spi/fsl_qspi.c18
-rw-r--r--drivers/spi/mtk_qspi.c359
-rw-r--r--drivers/spi/mtk_snfi_spi.c318
-rw-r--r--drivers/spi/mxs_spi.c400
-rw-r--r--drivers/spi/spi-mem.c8
-rw-r--r--drivers/spi/spi-sifive.c370
-rw-r--r--drivers/spi/stm32_qspi.c1
-rw-r--r--drivers/thermal/Kconfig9
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/imx_scu_thermal.c203
-rw-r--r--drivers/timer/timer-uclass.c4
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/host/dwc3-of-simple.c1
-rw-r--r--drivers/usb/host/xhci-dwc3.c20
-rw-r--r--drivers/usb/host/xhci-rockchip.c2
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/bcm2835.c4
-rw-r--r--drivers/video/display-uclass.c15
-rw-r--r--drivers/video/dw_hdmi.c13
-rw-r--r--drivers/video/fsl_dcu_fb.c213
-rw-r--r--drivers/video/meson/meson_dw_hdmi.c10
-rw-r--r--drivers/video/mxsfb.c74
-rw-r--r--drivers/video/rockchip/rk3288_hdmi.c2
-rw-r--r--drivers/video/rockchip/rk_hdmi.c3
-rw-r--r--drivers/video/simple_panel.c1
-rw-r--r--drivers/video/sunxi/sunxi_dw_hdmi.c3
-rw-r--r--drivers/watchdog/Kconfig9
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/imx_watchdog.c119
122 files changed, 12890 insertions, 1882 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 96969b9e30e..5e92446c18c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -46,6 +46,20 @@ config CLK_BOSTON
help
Enable this to support the clocks
+config SPL_CLK_CCF
+ bool "SPL Common Clock Framework [CCF] support "
+ depends on SPL_CLK_IMX6Q
+ help
+ Enable this option if you want to (re-)use the Linux kernel's Common
+ Clock Framework [CCF] code in U-Boot's SPL.
+
+config CLK_CCF
+ bool "Common Clock Framework [CCF] support "
+ depends on CLK_IMX6Q || SANDBOX_CLK_CCF
+ help
+ Enable this option if you want to (re-)use the Linux kernel's Common
+ Clock Framework [CCF] code in U-Boot's clock driver.
+
config CLK_STM32F
bool "Enable clock driver support for STM32F family"
depends on CLK && (STM32F7 || STM32F4)
@@ -98,6 +112,7 @@ config CLK_STM32MP1
Enable the STM32 clock (RCC) driver. Enable support for
manipulating STM32MP1's on-SoC clocks.
+source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/at91/Kconfig"
source "drivers/clk/exynos/Kconfig"
source "drivers/clk/imx/Kconfig"
@@ -124,4 +139,12 @@ config CLK_MPC83XX
help
Support for the clock driver of the MPC83xx series of SoCs.
+config SANDBOX_CLK_CCF
+ bool "Sandbox Common Clock Framework [CCF] support "
+ depends on SANDBOX
+ select CLK_CCF
+ help
+ Enable this option if you want to test the Linux kernel's Common
+ Clock Framework [CCF] code in U-Boot's Sandbox clock driver.
+
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 719b9b8e024..b7fec605c6c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -7,7 +7,10 @@
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o
obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o
+obj-y += analogbits/
obj-y += imx/
obj-y += tegra/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
@@ -36,5 +39,6 @@ obj-$(CONFIG_ICS8N3QV01) += ics8n3qv01.o
obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
obj-$(CONFIG_SANDBOX) += clk_sandbox.o
obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
+obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
obj-$(CONFIG_STM32H7) += clk_stm32h7.o
obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
diff --git a/drivers/clk/analogbits/Kconfig b/drivers/clk/analogbits/Kconfig
new file mode 100644
index 00000000000..1d25e6f1249
--- /dev/null
+++ b/drivers/clk/analogbits/Kconfig
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CLK_ANALOGBITS_WRPLL_CLN28HPC
+ bool
diff --git a/drivers/clk/analogbits/Makefile b/drivers/clk/analogbits/Makefile
new file mode 100644
index 00000000000..ec1bb4092b8
--- /dev/null
+++ b/drivers/clk/analogbits/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
diff --git a/drivers/clk/sifive/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c
index d3778496935..776ead319ae 100644
--- a/drivers/clk/sifive/wrpll-cln28hpc.c
+++ b/drivers/clk/analogbits/wrpll-cln28hpc.c
@@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- *
- * Copyright (C) 2018 SiFive, Inc.
+ * Copyright (C) 2018-2019 SiFive, Inc.
* Wesley Terpstra
* Paul Walmsley
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* This library supports configuration parsing and reprogramming of
* the CLN28HPC variant of the Analog Bits Wide Range PLL. The
* intention is for this library to be reusable for any device that
@@ -29,14 +18,14 @@
* References:
* - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01
* - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset"
+ * https://static.dev.sifive.com/FU540-C000-v1.0.pdf
*/
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/log2.h>
#include <linux/math64.h>
-
-#include "analogbits-wrpll-cln28hpc.h"
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
#define MIN_INPUT_FREQ 7000000
@@ -85,40 +74,38 @@
* range selection.
*
* Return: The RANGE value to be presented to the PLL configuration inputs,
- * or -1 upon error.
+ * or a negative return code upon error.
*/
static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
{
- u8 range;
-
if (post_divr_freq < MIN_POST_DIVR_FREQ ||
post_divr_freq > MAX_POST_DIVR_FREQ) {
WARN(1, "%s: post-divider reference freq out of range: %lu",
__func__, post_divr_freq);
- return -1;
+ return -ERANGE;
}
- if (post_divr_freq < 11000000)
- range = 1;
- else if (post_divr_freq < 18000000)
- range = 2;
- else if (post_divr_freq < 30000000)
- range = 3;
- else if (post_divr_freq < 50000000)
- range = 4;
- else if (post_divr_freq < 80000000)
- range = 5;
- else if (post_divr_freq < 130000000)
- range = 6;
- else
- range = 7;
-
- return range;
+ switch (post_divr_freq) {
+ case 0 ... 10999999:
+ return 1;
+ case 11000000 ... 17999999:
+ return 2;
+ case 18000000 ... 29999999:
+ return 3;
+ case 30000000 ... 49999999:
+ return 4;
+ case 50000000 ... 79999999:
+ return 5;
+ case 80000000 ... 129999999:
+ return 6;
+ }
+
+ return 7;
}
/**
* __wrpll_calc_fbdiv() - return feedback fixed divide value
- * @c: ptr to a struct analogbits_wrpll_cfg record to read from
+ * @c: ptr to a struct wrpll_cfg record to read from
*
* The internal feedback path includes a fixed by-two divider; the
* external feedback path does not. Return the appropriate divider
@@ -133,7 +120,7 @@ static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
* Return: 2 if internal feedback is enabled or 1 if external feedback
* is enabled.
*/
-static u8 __wrpll_calc_fbdiv(struct analogbits_wrpll_cfg *c)
+static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c)
{
return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1;
}
@@ -173,7 +160,7 @@ static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate)
*vco_rate = MIN_VCO_FREQ;
} else {
divq = ilog2(s);
- *vco_rate = target_rate << divq;
+ *vco_rate = (u64)target_rate << divq;
}
wcd_out:
@@ -182,7 +169,7 @@ wcd_out:
/**
* __wrpll_update_parent_rate() - update PLL data when parent rate changes
- * @c: ptr to a struct analogbits_wrpll_cfg record to write PLL data to
+ * @c: ptr to a struct wrpll_cfg record to write PLL data to
* @parent_rate: PLL input refclk rate (pre-R-divider)
*
* Pre-compute some data used by the PLL configuration algorithm when
@@ -190,46 +177,40 @@ wcd_out:
* computation when the parent rate remains constant - expected to be
* the common case.
*
- * Returns: 0 upon success or -1 if the reference clock rate is out of range.
+ * Returns: 0 upon success or -ERANGE if the reference clock rate is
+ * out of range.
*/
-static int __wrpll_update_parent_rate(struct analogbits_wrpll_cfg *c,
+static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
unsigned long parent_rate)
{
u8 max_r_for_parent;
if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ)
- return -1;
+ return -ERANGE;
- c->_parent_rate = parent_rate;
+ c->parent_rate = parent_rate;
max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ);
- c->_max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
+ c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
- /* Round up */
- c->_init_r = div_u64(parent_rate + MAX_POST_DIVR_FREQ - 1,
- MAX_POST_DIVR_FREQ);
+ c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ);
return 0;
}
-/*
- * Public functions
- */
-
/**
- * analogbits_wrpll_configure() - compute PLL configuration for a target rate
- * @c: ptr to a struct analogbits_wrpll_cfg record to write into
+ * wrpll_configure() - compute PLL configuration for a target rate
+ * @c: ptr to a struct wrpll_cfg record to write into
* @target_rate: target PLL output clock rate (post-Q-divider)
* @parent_rate: PLL input refclk rate (pre-R-divider)
*
- * Given a pointer to a PLL context @c, a desired PLL target output
- * rate @target_rate, and a reference clock input rate @parent_rate,
- * compute the appropriate PLL signal configuration values. PLL
- * reprogramming is not glitchless, so the caller should switch any
- * downstream logic to a different clock source or clock-gate it
- * before presenting these values to the PLL configuration signals.
+ * Compute the appropriate PLL signal configuration values and store
+ * in PLL context @c. PLL reprogramming is not glitchless, so the
+ * caller should switch any downstream logic to a different clock
+ * source or clock-gate it before presenting these values to the PLL
+ * configuration signals.
*
* The caller must pass this function a pre-initialized struct
- * analogbits_wrpll_cfg record: either initialized to zero (with the
+ * wrpll_cfg record: either initialized to zero (with the
* exception of the .name and .flags fields) or read from the PLL.
*
* Context: Any context. Caller must protect the memory pointed to by @c
@@ -237,41 +218,26 @@ static int __wrpll_update_parent_rate(struct analogbits_wrpll_cfg *c,
*
* Return: 0 upon success; anything else upon failure.
*/
-int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
- u32 target_rate,
- unsigned long parent_rate)
+int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
+ unsigned long parent_rate)
{
unsigned long ratio;
u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre;
- u32 best_f, f, post_divr_freq, fbcfg;
+ u32 best_f, f, post_divr_freq;
u8 fbdiv, divq, best_r, r;
-
- if (!c)
- return -1;
+ int range;
if (c->flags == 0) {
WARN(1, "%s called with uninitialized PLL config", __func__);
- return -1;
- }
-
- fbcfg = WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK;
- if ((c->flags & fbcfg) == fbcfg) {
- WARN(1, "%s called with invalid PLL config", __func__);
- return -1;
- }
-
- if (c->flags == WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
- WARN(1, "%s: external feedback mode not currently supported",
- __func__);
- return -1;
+ return -EINVAL;
}
/* Initialize rounding data if it hasn't been initialized already */
- if (parent_rate != c->_parent_rate) {
+ if (parent_rate != c->parent_rate) {
if (__wrpll_update_parent_rate(c, parent_rate)) {
pr_err("%s: PLL input rate is out of range\n",
__func__);
- return -1;
+ return -ERANGE;
}
}
@@ -282,11 +248,12 @@ int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
c->flags |= WRPLL_FLAGS_BYPASS_MASK;
return 0;
}
+
c->flags &= ~WRPLL_FLAGS_BYPASS_MASK;
/* Calculate the Q shift and target VCO rate */
divq = __wrpll_calc_divq(target_rate, &target_vco_rate);
- if (divq == 0)
+ if (!divq)
return -1;
c->divq = divq;
@@ -302,8 +269,7 @@ int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
* Consider all values for R which land within
* [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R
*/
- for (r = c->_init_r; r <= c->_max_r; ++r) {
- /* What is the best F we can pick in this case? */
+ for (r = c->init_r; r <= c->max_r; ++r) {
f_pre_div = ratio * r;
f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT;
f >>= (fbdiv - 1);
@@ -335,46 +301,54 @@ int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
post_divr_freq = div_u64(parent_rate, best_r);
/* Pick the best PLL jitter filter */
- c->range = __wrpll_calc_filter_range(post_divr_freq);
+ range = __wrpll_calc_filter_range(post_divr_freq);
+ if (range < 0)
+ return range;
+ c->range = range;
return 0;
}
/**
- * analogbits_wrpll_calc_output_rate() - calculate the PLL's target output rate
- * @c: ptr to a struct analogbits_wrpll_cfg record to read from
+ * wrpll_calc_output_rate() - calculate the PLL's target output rate
+ * @c: ptr to a struct wrpll_cfg record to read from
* @parent_rate: PLL refclk rate
*
* Given a pointer to the PLL's current input configuration @c and the
* PLL's input reference clock rate @parent_rate (before the R
* pre-divider), calculate the PLL's output clock rate (after the Q
- * post-divider)
+ * post-divider).
*
* Context: Any context. Caller must protect the memory pointed to by @c
* from simultaneous modification.
*
- * Return: the PLL's output clock rate, in Hz.
+ * Return: the PLL's output clock rate, in Hz. The return value from
+ * this function is intended to be convenient to pass directly
+ * to the Linux clock framework; thus there is no explicit
+ * error return value.
*/
-unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
- unsigned long parent_rate)
+unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
+ unsigned long parent_rate)
{
u8 fbdiv;
u64 n;
- WARN(c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK,
- "external feedback mode not yet supported");
+ if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
+ WARN(1, "external feedback mode not yet supported");
+ return ULONG_MAX;
+ }
fbdiv = __wrpll_calc_fbdiv(c);
n = parent_rate * fbdiv * (c->divf + 1);
- n = div_u64(n, (c->divr + 1));
+ n = div_u64(n, c->divr + 1);
n >>= c->divq;
return n;
}
/**
- * analogbits_wrpll_calc_max_lock_us() - return the time for the PLL to lock
- * @c: ptr to a struct analogbits_wrpll_cfg record to read from
+ * wrpll_calc_max_lock_us() - return the time for the PLL to lock
+ * @c: ptr to a struct wrpll_cfg record to read from
*
* Return the minimum amount of time (in microseconds) that the caller
* must wait after reprogramming the PLL to ensure that it is locked
@@ -384,7 +358,7 @@ unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
* Return: the minimum amount of time the caller must wait for the PLL
* to lock (in microseconds)
*/
-unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c)
+unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
{
return MAX_LOCK_US;
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
new file mode 100644
index 00000000000..6921c76a48f
--- /dev/null
+++ b/drivers/clk/clk-divider.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <linux/clk-provider.h>
+#include <div64.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_CCF_DIVIDER "ccf_clk_divider"
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->val == val)
+ return clkt->div;
+ return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags, u8 width)
+{
+ if (flags & CLK_DIVIDER_ONE_BASED)
+ return val;
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
+ return 1 << val;
+ if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+ return val ? val : clk_div_mask(width) + 1;
+ if (table)
+ return _get_table_div(table, val);
+ return val + 1;
+}
+
+unsigned long divider_recalc_rate(struct clk *hw, unsigned long parent_rate,
+ unsigned int val,
+ const struct clk_div_table *table,
+ unsigned long flags, unsigned long width)
+{
+ unsigned int div;
+
+ div = _get_div(table, val, flags, width);
+ if (!div) {
+ WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
+ "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
+ clk_hw_get_name(hw));
+ return parent_rate;
+ }
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, div);
+}
+
+static ulong clk_divider_recalc_rate(struct clk *clk)
+{
+ struct clk_divider *divider =
+ to_clk_divider(dev_get_clk_ptr(clk->dev));
+ unsigned long parent_rate = clk_get_parent_rate(clk);
+ unsigned int val;
+
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+ val = divider->io_divider_val;
+#else
+ val = readl(divider->reg);
+#endif
+ val >>= divider->shift;
+ val &= clk_div_mask(divider->width);
+
+ return divider_recalc_rate(clk, parent_rate, val, divider->table,
+ divider->flags, divider->width);
+}
+
+const struct clk_ops clk_divider_ops = {
+ .get_rate = clk_divider_recalc_rate,
+};
+
+static struct clk *_register_divider(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_divider_flags, const struct clk_div_table *table)
+{
+ struct clk_divider *div;
+ struct clk *clk;
+ int ret;
+
+ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+ if (width + shift > 16) {
+ pr_warn("divider value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ /* allocate the divider */
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ /* struct clk_divider assignments */
+ div->reg = reg;
+ div->shift = shift;
+ div->width = width;
+ div->flags = clk_divider_flags;
+ div->table = table;
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+ div->io_divider_val = *(u32 *)reg;
+#endif
+
+ /* register the clock */
+ clk = &div->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name);
+ if (ret) {
+ kfree(div);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_divider_flags)
+{
+ struct clk *clk;
+
+ clk = _register_divider(dev, name, parent_name, flags, reg, shift,
+ width, clk_divider_flags, NULL);
+ if (IS_ERR(clk))
+ return ERR_CAST(clk);
+ return clk;
+}
+
+U_BOOT_DRIVER(ccf_clk_divider) = {
+ .name = UBOOT_DM_CLK_CCF_DIVIDER,
+ .id = UCLASS_CLK,
+ .ops = &clk_divider_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
new file mode 100644
index 00000000000..711b0588bc3
--- /dev/null
+++ b/drivers/clk/clk-fixed-factor.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ */
+#include <common.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <div64.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_FIXED_FACTOR "ccf_clk_fixed_factor"
+
+static ulong clk_factor_recalc_rate(struct clk *clk)
+{
+ struct clk_fixed_factor *fix =
+ to_clk_fixed_factor(dev_get_clk_ptr(clk->dev));
+ unsigned long parent_rate = clk_get_parent_rate(clk);
+ unsigned long long int rate;
+
+ rate = (unsigned long long int)parent_rate * fix->mult;
+ do_div(rate, fix->div);
+ return (ulong)rate;
+}
+
+const struct clk_ops ccf_clk_fixed_factor_ops = {
+ .get_rate = clk_factor_recalc_rate,
+};
+
+struct clk *clk_hw_register_fixed_factor(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags,
+ unsigned int mult, unsigned int div)
+{
+ struct clk_fixed_factor *fix;
+ struct clk *clk;
+ int ret;
+
+ fix = kzalloc(sizeof(*fix), GFP_KERNEL);
+ if (!fix)
+ return ERR_PTR(-ENOMEM);
+
+ /* struct clk_fixed_factor assignments */
+ fix->mult = mult;
+ fix->div = div;
+ clk = &fix->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_IMX_FIXED_FACTOR, name,
+ parent_name);
+ if (ret) {
+ kfree(fix);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ unsigned int mult, unsigned int div)
+{
+ struct clk *clk;
+
+ clk = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult,
+ div);
+ if (IS_ERR(clk))
+ return ERR_CAST(clk);
+ return clk;
+}
+
+U_BOOT_DRIVER(imx_clk_fixed_factor) = {
+ .name = UBOOT_DM_CLK_IMX_FIXED_FACTOR,
+ .id = UCLASS_CLK,
+ .ops = &ccf_clk_fixed_factor_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
new file mode 100644
index 00000000000..3c075aa09ec
--- /dev/null
+++ b/drivers/clk/clk-mux.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * Simple multiplexer clock implementation
+ */
+
+/*
+ * U-Boot CCF porting node:
+ *
+ * The Linux kernel - as of tag: 5.0-rc3 is using also the imx_clk_fixup_mux()
+ * version of CCF mux. It is used on e.g. imx6q to provide fixes (like
+ * imx_cscmr1_fixup) for broken HW.
+ *
+ * At least for IMX6Q (but NOT IMX6QP) it is important when we set the parent
+ * clock.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_CCF_MUX "ccf_clk_mux"
+
+int clk_mux_val_to_index(struct clk *clk, u32 *table, unsigned int flags,
+ unsigned int val)
+{
+ struct clk_mux *mux = to_clk_mux(clk);
+ int num_parents = mux->num_parents;
+
+ if (table) {
+ int i;
+
+ for (i = 0; i < num_parents; i++)
+ if (table[i] == val)
+ return i;
+ return -EINVAL;
+ }
+
+ if (val && (flags & CLK_MUX_INDEX_BIT))
+ val = ffs(val) - 1;
+
+ if (val && (flags & CLK_MUX_INDEX_ONE))
+ val--;
+
+ if (val >= num_parents)
+ return -EINVAL;
+
+ return val;
+}
+
+static u8 clk_mux_get_parent(struct clk *clk)
+{
+ struct clk_mux *mux = to_clk_mux(clk);
+ u32 val;
+
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+ val = mux->io_mux_val;
+#else
+ val = readl(mux->reg);
+#endif
+ val >>= mux->shift;
+ val &= mux->mask;
+
+ return clk_mux_val_to_index(clk, mux->table, mux->flags, val);
+}
+
+const struct clk_ops clk_mux_ops = {
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
+ const char * const *parent_names, u8 num_parents,
+ unsigned long flags,
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table)
+{
+ struct clk_mux *mux;
+ struct clk *clk;
+ u8 width = 0;
+ int ret;
+
+ if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
+ width = fls(mask) - ffs(mask) + 1;
+ if (width + shift > 16) {
+ pr_err("mux value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ /* allocate the mux */
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ /* U-boot specific assignments */
+ mux->parent_names = parent_names;
+ mux->num_parents = num_parents;
+
+ /* struct clk_mux assignments */
+ mux->reg = reg;
+ mux->shift = shift;
+ mux->mask = mask;
+ mux->flags = clk_mux_flags;
+ mux->table = table;
+#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
+ mux->io_mux_val = *(u32 *)reg;
+#endif
+
+ clk = &mux->clk;
+
+ /*
+ * Read the current mux setup - so we assign correct parent.
+ *
+ * Changing parent would require changing internals of udevice struct
+ * for the corresponding clock (to do that define .set_parent() method.
+ */
+ ret = clk_register(clk, UBOOT_DM_CLK_CCF_MUX, name,
+ parent_names[clk_mux_get_parent(clk)]);
+ if (ret) {
+ kfree(mux);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+struct clk *clk_register_mux_table(struct device *dev, const char *name,
+ const char * const *parent_names, u8 num_parents,
+ unsigned long flags,
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table)
+{
+ struct clk *clk;
+
+ clk = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags,
+ table);
+ if (IS_ERR(clk))
+ return ERR_CAST(clk);
+ return clk;
+}
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+ const char * const *parent_names, u8 num_parents,
+ unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags)
+{
+ u32 mask = BIT(width) - 1;
+
+ return clk_register_mux_table(dev, name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags,
+ NULL);
+}
+
+U_BOOT_DRIVER(ccf_clk_mux) = {
+ .name = UBOOT_DM_CLK_CCF_MUX,
+ .id = UCLASS_CLK,
+ .ops = &clk_mux_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 79b3b0494c6..85dfe712f5a 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -13,6 +13,7 @@
#include <dm/read.h>
#include <dt-structs.h>
#include <errno.h>
+#include <linux/clk-provider.h>
static inline const struct clk_ops *clk_dev_ops(struct udevice *dev)
{
@@ -51,6 +52,8 @@ static int clk_of_xlate_default(struct clk *clk,
else
clk->id = 0;
+ clk->data = 0;
+
return 0;
}
@@ -379,6 +382,43 @@ ulong clk_get_rate(struct clk *clk)
return ops->get_rate(clk);
}
+struct clk *clk_get_parent(struct clk *clk)
+{
+ struct udevice *pdev;
+ struct clk *pclk;
+
+ debug("%s(clk=%p)\n", __func__, clk);
+
+ pdev = dev_get_parent(clk->dev);
+ pclk = dev_get_clk_ptr(pdev);
+ if (!pclk)
+ return ERR_PTR(-ENODEV);
+
+ return pclk;
+}
+
+long long clk_get_parent_rate(struct clk *clk)
+{
+ const struct clk_ops *ops;
+ struct clk *pclk;
+
+ debug("%s(clk=%p)\n", __func__, clk);
+
+ pclk = clk_get_parent(clk);
+ if (IS_ERR(pclk))
+ return -ENODEV;
+
+ ops = clk_dev_ops(pclk->dev);
+ if (!ops->get_rate)
+ return -ENOSYS;
+
+ /* Read the 'rate' if not already set or if proper flag set*/
+ if (!pclk->rate || pclk->flags & CLK_GET_RATE_NOCACHE)
+ pclk->rate = clk_get_rate(pclk);
+
+ return pclk->rate;
+}
+
ulong clk_set_rate(struct clk *clk, ulong rate)
{
const struct clk_ops *ops = clk_dev_ops(clk->dev);
@@ -453,6 +493,28 @@ int clk_disable_bulk(struct clk_bulk *bulk)
return 0;
}
+int clk_get_by_id(ulong id, struct clk **clkp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_CLK, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(dev, uc) {
+ struct clk *clk = dev_get_clk_ptr(dev);
+
+ if (clk && clk->id == id) {
+ *clkp = clk;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
UCLASS_DRIVER(clk) = {
.id = UCLASS_CLK,
.name = "clk",
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 00000000000..7d748c9fc73
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <clk.h>
+
+int clk_register(struct clk *clk, const char *drv_name,
+ const char *name, const char *parent_name)
+{
+ struct udevice *parent;
+ struct driver *drv;
+ int ret;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent);
+ if (ret)
+ printf("%s: UCLASS parent: 0x%p\n", __func__, parent);
+
+ debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, parent->name,
+ parent);
+
+ drv = lists_driver_lookup_name(drv_name);
+ if (!drv) {
+ printf("%s: %s is not a valid driver name\n",
+ __func__, drv_name);
+ return -ENOENT;
+ }
+
+ ret = device_bind(parent, drv, name, NULL, -1, &clk->dev);
+ if (ret) {
+ printf("%s: CLK: %s driver bind error [%d]!\n", __func__, name,
+ ret);
+ return ret;
+ }
+
+ /* Store back pointer to clk from udevice */
+ clk->dev->uclass_priv = clk;
+
+ return 0;
+}
+
+ulong clk_generic_get_rate(struct clk *clk)
+{
+ return clk_get_parent_rate(clk);
+}
+
+const char *clk_hw_get_name(const struct clk *hw)
+{
+ return hw->dev->name;
+}
diff --git a/drivers/clk/clk_fixed_factor.c b/drivers/clk/clk_fixed_factor.c
index 5fa20a84dbb..dcdb6ddf5cf 100644
--- a/drivers/clk/clk_fixed_factor.c
+++ b/drivers/clk/clk_fixed_factor.c
@@ -24,9 +24,6 @@ static ulong clk_fixed_factor_get_rate(struct clk *clk)
uint64_t rate;
struct clk_fixed_factor *ff = to_clk_fixed_factor(clk->dev);
- if (clk->id != 0)
- return -EINVAL;
-
rate = clk_get_rate(&ff->parent);
if (IS_ERR_VALUE(rate))
return rate;
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index d8d9f86c864..1fdf8c4e540 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -8,6 +8,7 @@
#include <dm.h>
struct clk_fixed_rate {
+ struct clk clk;
unsigned long fixed_rate;
};
@@ -15,9 +16,6 @@ struct clk_fixed_rate {
static ulong clk_fixed_rate_get_rate(struct clk *clk)
{
- if (clk->id != 0)
- return -EINVAL;
-
return to_clk_fixed_rate(clk->dev)->fixed_rate;
}
@@ -27,10 +25,14 @@ const struct clk_ops clk_fixed_rate_ops = {
static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
{
+ struct clk *clk = &to_clk_fixed_rate(dev)->clk;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
to_clk_fixed_rate(dev)->fixed_rate =
dev_read_u32_default(dev, "clock-frequency", 0);
#endif
+ /* Make fixed rate clock accessible from higher level struct clk */
+ dev->uclass_priv = clk;
+ clk->dev = dev;
return 0;
}
diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c
new file mode 100644
index 00000000000..edeb0f2cf3e
--- /dev/null
+++ b/drivers/clk/clk_sandbox_ccf.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Common Clock Framework [CCF] driver for Sandbox
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <asm/clk.h>
+#include <clk-uclass.h>
+#include <linux/clk-provider.h>
+#include <sandbox-clk.h>
+
+/*
+ * Sandbox implementation of CCF primitives necessary for clk-uclass testing
+ *
+ * --- Sandbox PLLv3 ---
+ */
+struct clk_pllv3 {
+ struct clk clk;
+ u32 div_mask;
+ u32 div_shift;
+};
+
+static ulong clk_pllv3_get_rate(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_parent_rate(clk);
+
+ return parent_rate * 24;
+}
+
+static const struct clk_ops clk_pllv3_generic_ops = {
+ .get_rate = clk_pllv3_get_rate,
+};
+
+struct clk *sandbox_clk_pllv3(enum sandbox_pllv3_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 div_mask)
+{
+ struct clk_pllv3 *pll;
+ struct clk *clk;
+ char *drv_name = "sandbox_clk_pllv3";
+ int ret;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->div_mask = div_mask;
+ clk = &pll->clk;
+
+ ret = clk_register(clk, drv_name, name, parent_name);
+ if (ret) {
+ kfree(pll);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(sandbox_clk_pll_generic) = {
+ .name = "sandbox_clk_pllv3",
+ .id = UCLASS_CLK,
+ .ops = &clk_pllv3_generic_ops,
+};
+
+/* --- Sandbox PLLv3 --- */
+/* --- Sandbox Gate --- */
+struct clk_gate2 {
+ struct clk clk;
+ bool state;
+};
+
+#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
+
+static int clk_gate2_enable(struct clk *clk)
+{
+ struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+
+ gate->state = 1;
+ return 0;
+}
+
+static int clk_gate2_disable(struct clk *clk)
+{
+ struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+
+ gate->state = 0;
+ return 0;
+}
+
+static const struct clk_ops clk_gate2_ops = {
+ .enable = clk_gate2_enable,
+ .disable = clk_gate2_disable,
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *sandbox_clk_register_gate2(struct device *dev, const char *name,
+ const char *parent_name,
+ unsigned long flags, void __iomem *reg,
+ u8 bit_idx, u8 cgr_val,
+ u8 clk_gate2_flags)
+{
+ struct clk_gate2 *gate;
+ struct clk *clk;
+ int ret;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->state = 0;
+ clk = &gate->clk;
+
+ ret = clk_register(clk, "sandbox_clk_gate2", name, parent_name);
+ if (ret) {
+ kfree(gate);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(sandbox_clk_gate2) = {
+ .name = "sandbox_clk_gate2",
+ .id = UCLASS_CLK,
+ .ops = &clk_gate2_ops,
+};
+
+/* --- Sandbox Gate --- */
+/* The CCF core driver itself */
+static const struct udevice_id sandbox_clk_ccf_test_ids[] = {
+ { .compatible = "sandbox,clk-ccf" },
+ { }
+};
+
+static const char *const usdhc_sels[] = { "pll3_60m", "pll3_80m", };
+
+static int sandbox_clk_ccf_probe(struct udevice *dev)
+{
+ void *base = NULL;
+ u32 reg;
+
+ clk_dm(SANDBOX_CLK_PLL3,
+ sandbox_clk_pllv3(SANDBOX_PLLV3_USB, "pll3_usb_otg", "osc",
+ base + 0x10, 0x3));
+
+ clk_dm(SANDBOX_CLK_PLL3_60M,
+ sandbox_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8));
+
+ clk_dm(SANDBOX_CLK_PLL3_80M,
+ sandbox_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6));
+
+ /* The HW adds +1 to the divider value (2+1) is the divider */
+ reg = (2 << 19);
+ clk_dm(SANDBOX_CLK_ECSPI_ROOT,
+ sandbox_clk_divider("ecspi_root", "pll3_60m", &reg, 19, 6));
+
+ clk_dm(SANDBOX_CLK_ECSPI1,
+ sandbox_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
+
+ /* Select 'pll3_60m' */
+ reg = 0;
+ clk_dm(SANDBOX_CLK_USDHC1_SEL,
+ sandbox_clk_mux("usdhc1_sel", &reg, 16, 1, usdhc_sels,
+ ARRAY_SIZE(usdhc_sels)));
+
+ /* Select 'pll3_80m' */
+ reg = BIT(17);
+ clk_dm(SANDBOX_CLK_USDHC2_SEL,
+ sandbox_clk_mux("usdhc2_sel", &reg, 17, 1, usdhc_sels,
+ ARRAY_SIZE(usdhc_sels)));
+
+ return 0;
+}
+
+U_BOOT_DRIVER(sandbox_clk_ccf) = {
+ .name = "sandbox_clk_ccf",
+ .id = UCLASS_CLK,
+ .probe = sandbox_clk_ccf_probe,
+ .of_match = sandbox_clk_ccf_test_ids,
+};
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index 6ffa05b8fd7..5806d48696f 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -300,6 +300,7 @@ enum stm32mp1_parent_sel {
_DSI_SEL,
_ADC12_SEL,
_SPI1_SEL,
+ _RTC_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
};
@@ -534,6 +535,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
STM32MP1_CLK_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB2ENSETR, 5, ADC12, _HCLK2),
@@ -569,6 +571,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
+
+ STM32MP1_CLK(RCC_BDCR, 20, RTC, _RTC_SEL),
};
static const u8 i2c12_parents[] = {_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER};
@@ -594,6 +598,7 @@ static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P};
static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q};
static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER,
_PLL3_R};
+static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE};
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents),
@@ -619,6 +624,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents),
STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents),
STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents),
+ STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT,
+ (RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT),
+ rtc_parents),
};
#ifdef STM32MP1_CLOCK_TREE_INIT
@@ -734,6 +742,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = {
[_DSI_SEL] = "DSI",
[_ADC12_SEL] = "ADC12",
[_SPI1_SEL] = "SPI1",
+ [_RTC_SEL] = "RTC",
};
static const struct stm32mp1_clk_data stm32mp1_data = {
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index a6fb58d6cf6..3e6a980c8c3 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -1,3 +1,19 @@
+config SPL_CLK_IMX6Q
+ bool "SPL clock support for i.MX6Q"
+ depends on ARCH_MX6 && SPL
+ select SPL_CLK
+ select SPL_CLK_CCF
+ help
+ This enables SPL DM/DTS support for clock driver in i.MX6Q platforms.
+
+config CLK_IMX6Q
+ bool "Clock support for i.MX6Q"
+ depends on ARCH_MX6
+ select CLK
+ select CLK_CCF
+ help
+ This enables DM/DTS support for clock driver in i.MX6Q platforms.
+
config CLK_IMX8
bool "Clock support for i.MX8"
depends on ARCH_IMX8
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index eb379c188ae..105a58ca907 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_IMX6Q) += clk-imx6q.o
obj-$(CONFIG_CLK_IMX8) += clk-imx8.o
ifdef CONFIG_CLK_IMX8
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
new file mode 100644
index 00000000000..571be320883
--- /dev/null
+++ b/drivers/clk/imx/clk-gate2.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Gated clock implementation
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_GATE2 "imx_clk_gate2"
+
+struct clk_gate2 {
+ struct clk clk;
+ void __iomem *reg;
+ u8 bit_idx;
+ u8 cgr_val;
+ u8 flags;
+};
+
+#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
+
+static int clk_gate2_enable(struct clk *clk)
+{
+ struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+ u32 reg;
+
+ reg = readl(gate->reg);
+ reg &= ~(3 << gate->bit_idx);
+ reg |= gate->cgr_val << gate->bit_idx;
+ writel(reg, gate->reg);
+
+ return 0;
+}
+
+static int clk_gate2_disable(struct clk *clk)
+{
+ struct clk_gate2 *gate = to_clk_gate2(dev_get_clk_ptr(clk->dev));
+ u32 reg;
+
+ reg = readl(gate->reg);
+ reg &= ~(3 << gate->bit_idx);
+ writel(reg, gate->reg);
+
+ return 0;
+}
+
+static const struct clk_ops clk_gate2_ops = {
+ .enable = clk_gate2_enable,
+ .disable = clk_gate2_disable,
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *clk_register_gate2(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx, u8 cgr_val,
+ u8 clk_gate2_flags)
+{
+ struct clk_gate2 *gate;
+ struct clk *clk;
+ int ret;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->cgr_val = cgr_val;
+ gate->flags = clk_gate2_flags;
+
+ clk = &gate->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE2, name, parent_name);
+ if (ret) {
+ kfree(gate);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(clk_gate2) = {
+ .name = UBOOT_DM_CLK_IMX_GATE2,
+ .id = UCLASS_CLK,
+ .ops = &clk_gate2_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
new file mode 100644
index 00000000000..92e9337d446
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <dt-bindings/clock/imx6qdl-clock.h>
+
+#include "clk.h"
+
+static int imx6q_check_id(ulong id)
+{
+ if (id < IMX6QDL_CLK_DUMMY || id >= IMX6QDL_CLK_END) {
+ printf("%s: Invalid clk ID #%lu\n", __func__, id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static ulong imx6q_clk_get_rate(struct clk *clk)
+{
+ struct clk *c;
+ int ret;
+
+ debug("%s(#%lu)\n", __func__, clk->id);
+
+ ret = imx6q_check_id(clk->id);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ return clk_get_rate(c);
+}
+
+static ulong imx6q_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
+
+ return rate;
+}
+
+static int __imx6q_clk_enable(struct clk *clk, bool enable)
+{
+ struct clk *c;
+ int ret = 0;
+
+ debug("%s(#%lu) en: %d\n", __func__, clk->id, enable);
+
+ ret = imx6q_check_id(clk->id);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ if (enable)
+ ret = clk_enable(c);
+ else
+ ret = clk_disable(c);
+
+ return ret;
+}
+
+static int imx6q_clk_disable(struct clk *clk)
+{
+ return __imx6q_clk_enable(clk, 0);
+}
+
+static int imx6q_clk_enable(struct clk *clk)
+{
+ return __imx6q_clk_enable(clk, 1);
+}
+
+static struct clk_ops imx6q_clk_ops = {
+ .set_rate = imx6q_clk_set_rate,
+ .get_rate = imx6q_clk_get_rate,
+ .enable = imx6q_clk_enable,
+ .disable = imx6q_clk_disable,
+};
+
+static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+
+static int imx6q_clk_probe(struct udevice *dev)
+{
+ void *base;
+
+ /* Anatop clocks */
+ base = (void *)ANATOP_BASE_ADDR;
+
+ clk_dm(IMX6QDL_CLK_PLL2,
+ imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc",
+ base + 0x30, 0x1));
+ clk_dm(IMX6QDL_CLK_PLL3_USB_OTG,
+ imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc",
+ base + 0x10, 0x3));
+ clk_dm(IMX6QDL_CLK_PLL3_60M,
+ imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8));
+ clk_dm(IMX6QDL_CLK_PLL2_PFD0_352M,
+ imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0));
+ clk_dm(IMX6QDL_CLK_PLL2_PFD2_396M,
+ imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2));
+
+ /* CCM clocks */
+ base = dev_read_addr_ptr(dev);
+ if (base == (void *)FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ clk_dm(IMX6QDL_CLK_USDHC1_SEL,
+ imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
+ usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+ clk_dm(IMX6QDL_CLK_USDHC2_SEL,
+ imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
+ usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+ clk_dm(IMX6QDL_CLK_USDHC3_SEL,
+ imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1,
+ usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+ clk_dm(IMX6QDL_CLK_USDHC4_SEL,
+ imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1,
+ usdhc_sels, ARRAY_SIZE(usdhc_sels)));
+
+ clk_dm(IMX6QDL_CLK_USDHC1_PODF,
+ imx_clk_divider("usdhc1_podf", "usdhc1_sel",
+ base + 0x24, 11, 3));
+ clk_dm(IMX6QDL_CLK_USDHC2_PODF,
+ imx_clk_divider("usdhc2_podf", "usdhc2_sel",
+ base + 0x24, 16, 3));
+ clk_dm(IMX6QDL_CLK_USDHC3_PODF,
+ imx_clk_divider("usdhc3_podf", "usdhc3_sel",
+ base + 0x24, 19, 3));
+ clk_dm(IMX6QDL_CLK_USDHC4_PODF,
+ imx_clk_divider("usdhc4_podf", "usdhc4_sel",
+ base + 0x24, 22, 3));
+
+ clk_dm(IMX6QDL_CLK_ECSPI_ROOT,
+ imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6));
+
+ clk_dm(IMX6QDL_CLK_ECSPI1,
+ imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
+ clk_dm(IMX6QDL_CLK_ECSPI2,
+ imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2));
+ clk_dm(IMX6QDL_CLK_ECSPI3,
+ imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4));
+ clk_dm(IMX6QDL_CLK_ECSPI4,
+ imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6));
+ clk_dm(IMX6QDL_CLK_USDHC1,
+ imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
+ clk_dm(IMX6QDL_CLK_USDHC2,
+ imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
+ clk_dm(IMX6QDL_CLK_USDHC3,
+ imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6));
+ clk_dm(IMX6QDL_CLK_USDHC4,
+ imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8));
+
+ return 0;
+}
+
+static const struct udevice_id imx6q_clk_ids[] = {
+ { .compatible = "fsl,imx6q-ccm" },
+ { },
+};
+
+U_BOOT_DRIVER(imx6q_clk) = {
+ .name = "clk_imx6q",
+ .id = UCLASS_CLK,
+ .of_match = imx6q_clk_ids,
+ .ops = &imx6q_clk_ops,
+ .probe = imx6q_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
new file mode 100644
index 00000000000..188b2b3b90a
--- /dev/null
+++ b/drivers/clk/imx/clk-pfd.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <linux/clk-provider.h>
+#include <div64.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_PFD "imx_clk_pfd"
+
+struct clk_pfd {
+ struct clk clk;
+ void __iomem *reg;
+ u8 idx;
+};
+
+#define to_clk_pfd(_clk) container_of(_clk, struct clk_pfd, clk)
+
+#define SET 0x4
+#define CLR 0x8
+#define OTG 0xc
+
+static unsigned long clk_pfd_recalc_rate(struct clk *clk)
+{
+ struct clk_pfd *pfd =
+ to_clk_pfd(dev_get_clk_ptr(clk->dev));
+ unsigned long parent_rate = clk_get_parent_rate(clk);
+ u64 tmp = parent_rate;
+ u8 frac = (readl(pfd->reg) >> (pfd->idx * 8)) & 0x3f;
+
+ tmp *= 18;
+ do_div(tmp, frac);
+
+ return tmp;
+}
+
+static const struct clk_ops clk_pfd_ops = {
+ .get_rate = clk_pfd_recalc_rate,
+};
+
+struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+ void __iomem *reg, u8 idx)
+{
+ struct clk_pfd *pfd;
+ struct clk *clk;
+ int ret;
+
+ pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
+ if (!pfd)
+ return ERR_PTR(-ENOMEM);
+
+ pfd->reg = reg;
+ pfd->idx = idx;
+
+ /* register the clock */
+ clk = &pfd->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_IMX_PFD, name, parent_name);
+ if (ret) {
+ kfree(pfd);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(clk_pfd) = {
+ .name = UBOOT_DM_CLK_IMX_PFD,
+ .id = UCLASS_CLK,
+ .ops = &clk_pfd_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
new file mode 100644
index 00000000000..fbb7b24d5e2
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <clk.h>
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_PLLV3 "imx_clk_pllv3"
+
+struct clk_pllv3 {
+ struct clk clk;
+ void __iomem *base;
+ u32 div_mask;
+ u32 div_shift;
+};
+
+#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
+
+static ulong clk_pllv3_get_rate(struct clk *clk)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
+ unsigned long parent_rate = clk_get_parent_rate(clk);
+
+ u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
+
+ return (div == 1) ? parent_rate * 22 : parent_rate * 20;
+}
+
+static const struct clk_ops clk_pllv3_generic_ops = {
+ .get_rate = clk_pllv3_get_rate,
+};
+
+struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 div_mask)
+{
+ struct clk_pllv3 *pll;
+ struct clk *clk;
+ char *drv_name;
+ int ret;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ switch (type) {
+ case IMX_PLLV3_GENERIC:
+ case IMX_PLLV3_USB:
+ drv_name = UBOOT_DM_CLK_IMX_PLLV3;
+ break;
+ default:
+ kfree(pll);
+ return ERR_PTR(-ENOTSUPP);
+ }
+
+ pll->base = base;
+ pll->div_mask = div_mask;
+ clk = &pll->clk;
+
+ ret = clk_register(clk, drv_name, name, parent_name);
+ if (ret) {
+ kfree(pll);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(clk_pllv3_generic) = {
+ .name = UBOOT_DM_CLK_IMX_PLLV3,
+ .id = UCLASS_CLK,
+ .ops = &clk_pllv3_generic_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
new file mode 100644
index 00000000000..e6d51830e88
--- /dev/null
+++ b/drivers/clk/imx/clk.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+#ifndef __MACH_IMX_CLK_H
+#define __MACH_IMX_CLK_H
+
+#include <linux/clk-provider.h>
+
+enum imx_pllv3_type {
+ IMX_PLLV3_GENERIC,
+ IMX_PLLV3_SYS,
+ IMX_PLLV3_USB,
+ IMX_PLLV3_USB_VF610,
+ IMX_PLLV3_AV,
+ IMX_PLLV3_ENET,
+ IMX_PLLV3_ENET_IMX7,
+ IMX_PLLV3_SYS_VF610,
+ IMX_PLLV3_DDR_IMX7,
+};
+
+struct clk *clk_register_gate2(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx, u8 cgr_val,
+ u8 clk_gate_flags);
+
+struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+ const char *parent_name, void __iomem *base,
+ u32 div_mask);
+
+static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ shift, 0x3, 0);
+}
+
+static inline struct clk *imx_clk_fixed_factor(const char *name,
+ const char *parent, unsigned int mult, unsigned int div)
+{
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, mult, div);
+}
+
+static inline struct clk *imx_clk_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width)
+{
+ return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+ reg, shift, width, 0);
+}
+
+struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+ void __iomem *reg, u8 idx);
+
+struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char * const *parents,
+ int num_parents, void (*fixup)(u32 *val));
+
+static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char * const *parents,
+ int num_parents)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, reg, shift,
+ width, 0);
+}
+
+#endif /* __MACH_IMX_CLK_H */
diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c
index 9bb9959c9d3..dda686cfb3a 100644
--- a/drivers/clk/rockchip/clk_rk3188.c
+++ b/drivers/clk/rockchip/clk_rk3188.c
@@ -562,6 +562,9 @@ static int rk3188_clk_probe(struct udevice *dev)
#endif
rkclk_init(priv->cru, priv->grf, priv->has_bwadj);
+
+ /* Init CPU frequency */
+ rkclk_configure_cpu(priv->cru, priv->grf, APLL_HZ, priv->has_bwadj);
#endif
return 0;
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index aa6a8ad1c9c..d9950c159bd 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -38,8 +38,8 @@ struct pll_div {
};
#define RATE_TO_DIV(input_rate, output_rate) \
- ((input_rate) / (output_rate) - 1);
-#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+ ((input_rate) / (output_rate) - 1)
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
.refdiv = _refdiv,\
@@ -53,15 +53,15 @@ static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2, 2);
static const struct pll_div ppll_init_cfg = PLL_DIVISORS(PPLL_HZ, 2, 2, 1);
#endif
-static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600*MHz, 3, 1, 1);
-static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
+static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600 * MHz, 3, 1, 1);
+static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600 * MHz, 1, 2, 1);
static const struct pll_div *apll_l_cfgs[] = {
[APLL_L_1600_MHZ] = &apll_l_1600_cfg,
[APLL_L_600_MHZ] = &apll_l_600_cfg,
};
-static const struct pll_div apll_b_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
+static const struct pll_div apll_b_600_cfg = PLL_DIVISORS(600 * MHz, 1, 2, 1);
static const struct pll_div *apll_b_cfgs[] = {
[APLL_B_600_MHZ] = &apll_b_600_cfg,
};
@@ -393,7 +393,7 @@ static int pll_para_config(u32 freq_hz, struct pll_div *div)
fref_khz = ref_khz / refdiv;
fbdiv = vco_khz / fref_khz;
- if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv))
+ if (fbdiv >= max_fbdiv || fbdiv <= min_fbdiv)
continue;
diff_khz = vco_khz - fbdiv * fref_khz;
if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
@@ -409,7 +409,7 @@ static int pll_para_config(u32 freq_hz, struct pll_div *div)
div->fbdiv = fbdiv;
}
- if (best_diff_khz > 4 * (MHz/KHz)) {
+ if (best_diff_khz > 4 * (MHz / KHz)) {
printf("%s: Failed to match output frequency %u, "
"difference is %u Hz,exceed 4MHZ\n", __func__, freq_hz,
best_diff_khz * KHz);
@@ -489,28 +489,21 @@ void rk3399_configure_cpu_b(struct rk3399_cru *cru,
}
#define I2C_CLK_REG_MASK(bus) \
- (I2C_DIV_CON_MASK << \
- CLK_I2C ##bus## _DIV_CON_SHIFT | \
- CLK_I2C_PLL_SEL_MASK << \
- CLK_I2C ##bus## _PLL_SEL_SHIFT)
+ (I2C_DIV_CON_MASK << CLK_I2C ##bus## _DIV_CON_SHIFT | \
+ CLK_I2C_PLL_SEL_MASK << CLK_I2C ##bus## _PLL_SEL_SHIFT)
#define I2C_CLK_REG_VALUE(bus, clk_div) \
- ((clk_div - 1) << \
- CLK_I2C ##bus## _DIV_CON_SHIFT | \
- CLK_I2C_PLL_SEL_GPLL << \
- CLK_I2C ##bus## _PLL_SEL_SHIFT)
+ ((clk_div - 1) << CLK_I2C ##bus## _DIV_CON_SHIFT | \
+ CLK_I2C_PLL_SEL_GPLL << CLK_I2C ##bus## _PLL_SEL_SHIFT)
#define I2C_CLK_DIV_VALUE(con, bus) \
- (con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & \
- I2C_DIV_CON_MASK;
+ ((con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & I2C_DIV_CON_MASK)
#define I2C_PMUCLK_REG_MASK(bus) \
- (I2C_DIV_CON_MASK << \
- CLK_I2C ##bus## _DIV_CON_SHIFT)
+ (I2C_DIV_CON_MASK << CLK_I2C ##bus## _DIV_CON_SHIFT)
#define I2C_PMUCLK_REG_VALUE(bus, clk_div) \
- ((clk_div - 1) << \
- CLK_I2C ##bus## _DIV_CON_SHIFT)
+ ((clk_div - 1) << CLK_I2C ##bus## _DIV_CON_SHIFT)
static ulong rk3399_i2c_get_clk(struct rk3399_cru *cru, ulong clk_id)
{
@@ -597,9 +590,9 @@ static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
*/
struct spi_clkreg {
- uint8_t reg; /* CLKSEL_CON[reg] register in CRU */
- uint8_t div_shift;
- uint8_t sel_shift;
+ u8 reg; /* CLKSEL_CON[reg] register in CRU */
+ u8 div_shift;
+ u8 sel_shift;
};
/*
@@ -678,7 +671,7 @@ static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
{
struct pll_div vpll_config = {0};
- int aclk_vop = 198*MHz;
+ int aclk_vop = 198 * MHz;
void *aclkreg_addr, *dclkreg_addr;
u32 div;
@@ -710,7 +703,7 @@ static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
rkclk_set_pll(&cru->vpll_con[0], &vpll_config);
rk_clrsetreg(dclkreg_addr,
- DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_PLL_SEL_MASK|
+ DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
DCLK_VOP_DIV_CON_MASK,
DCLK_VOP_DCLK_SEL_DIVOUT << DCLK_VOP_DCLK_SEL_SHIFT |
DCLK_VOP_PLL_SEL_VPLL << DCLK_VOP_PLL_SEL_SHIFT |
@@ -750,7 +743,7 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
ulong clk_id, ulong set_rate)
{
int src_clk_div;
- int aclk_emmc = 198*MHz;
+ int aclk_emmc = 198 * MHz;
switch (clk_id) {
case HCLK_SDMMC:
@@ -776,7 +769,7 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
break;
case SCLK_EMMC:
/* Select aclk_emmc source from GPLL */
- src_clk_div = DIV_ROUND_UP(GPLL_HZ , aclk_emmc);
+ src_clk_div = DIV_ROUND_UP(GPLL_HZ, aclk_emmc);
assert(src_clk_div - 1 < 32);
rk_clrsetreg(&cru->clksel_con[21],
@@ -834,23 +827,31 @@ static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
/* clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
switch (set_rate) {
- case 200*MHz:
+ case 50 * MHz:
+ dpll_cfg = (struct pll_div)
+ {.refdiv = 1, .fbdiv = 12, .postdiv1 = 3, .postdiv2 = 2};
+ break;
+ case 200 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
break;
- case 300*MHz:
+ case 300 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
break;
- case 666*MHz:
+ case 400 * MHz:
+ dpll_cfg = (struct pll_div)
+ {.refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1};
+ break;
+ case 666 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
break;
- case 800*MHz:
+ case 800 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
break;
- case 933*MHz:
+ case 933 * MHz:
dpll_cfg = (struct pll_div)
{.refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1};
break;
@@ -916,7 +917,6 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
case SCLK_UART2:
case SCLK_UART3:
return 24000000;
- break;
case PCLK_HDMI_CTRL:
break;
case DCLK_VOP0:
@@ -1014,7 +1014,8 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
return ret;
}
-static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk, struct clk *parent)
+static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk,
+ struct clk *parent)
{
struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
const char *clock_output_name;
@@ -1024,7 +1025,7 @@ static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk, struct clk *pa
* If the requested parent is in the same clock-controller and
* the id is SCLK_MAC ("clk_gmac"), switch to the internal clock.
*/
- if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC)) {
+ if (parent->dev == clk->dev && parent->id == SCLK_MAC) {
debug("%s: switching RGMII to SCLK_MAC\n", __func__);
rk_clrreg(&priv->cru->clksel_con[19], BIT(4));
return 0;
@@ -1049,7 +1050,8 @@ static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk, struct clk *pa
return -EINVAL;
}
-static int __maybe_unused rk3399_clk_set_parent(struct clk *clk, struct clk *parent)
+static int __maybe_unused rk3399_clk_set_parent(struct clk *clk,
+ struct clk *parent)
{
switch (clk->id) {
case SCLK_RMII_SRC:
@@ -1078,6 +1080,18 @@ static int rk3399_clk_enable(struct clk *clk)
case PCLK_GMAC:
/* Required to successfully probe the Designware GMAC driver */
return 0;
+
+ case SCLK_USB3OTG0_REF:
+ case SCLK_USB3OTG1_REF:
+ case SCLK_USB3OTG0_SUSPEND:
+ case SCLK_USB3OTG1_SUSPEND:
+ case ACLK_USB3OTG0:
+ case ACLK_USB3OTG1:
+ case ACLK_USB3_RKSOC_AXI_PERF:
+ case ACLK_USB3:
+ case ACLK_USB3_GRF:
+ /* Required to successfully probe the Designware USB3 driver */
+ return 0;
}
debug("%s: unsupported clk %ld\n", __func__, clk->id);
diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
index 644881b9487..c4d0a1f9b1f 100644
--- a/drivers/clk/sifive/Kconfig
+++ b/drivers/clk/sifive/Kconfig
@@ -1,8 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-config CLK_ANALOGBITS_WRPLL_CLN28HPC
- bool
-
config CLK_SIFIVE
bool "SiFive SoC driver support"
depends on CLK
@@ -17,10 +14,3 @@ config CLK_SIFIVE_FU540_PRCI
Supports the Power Reset Clock interface (PRCI) IP block found in
FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
enable this driver.
-
-config CLK_SIFIVE_GEMGXL_MGMT
- bool "GEMGXL management for SiFive FU540 SoCs"
- depends on CLK_SIFIVE
- help
- Supports the GEMGXL management IP block found in FU540 SoCs to
- control GEM TX clock operation mode for 10/100/1000 Mbps.
diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
index f8263e79b70..b224279afbe 100644
--- a/drivers/clk/sifive/Makefile
+++ b/drivers/clk/sifive/Makefile
@@ -1,7 +1,3 @@
# SPDX-License-Identifier: GPL-2.0+
-obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
-
obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
-
-obj-$(CONFIG_CLK_SIFIVE_GEMGXL_MGMT) += gemgxl-mgmt.o
diff --git a/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h b/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h
deleted file mode 100644
index 4432e247491..00000000000
--- a/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- *
- * Copyright (C) 2018 SiFive, Inc.
- * Wesley Terpstra
- * Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
-#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H
-
-#include <linux/types.h>
-
-/* DIVQ_VALUES: number of valid DIVQ values */
-#define DIVQ_VALUES 6
-
-/*
- * Bit definitions for struct analogbits_wrpll_cfg.flags
- *
- * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be
- * programmed to enter bypass
- * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset
- * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal
- * feedback mode
- * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external
- * feedback mode (not yet supported by this driver)
- *
- * The flags WRPLL_FLAGS_INT_FEEDBACK_FLAG and WRPLL_FLAGS_EXT_FEEDBACK_FLAG are
- * mutually exclusive. If both bits are set, or both are zero, the struct
- * analogbits_wrpll_cfg record is uninitialized or corrupt.
- */
-#define WRPLL_FLAGS_BYPASS_SHIFT 0
-#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT)
-#define WRPLL_FLAGS_RESET_SHIFT 1
-#define WRPLL_FLAGS_RESET_MASK BIT(WRPLL_FLAGS_RESET_SHIFT)
-#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT 2
-#define WRPLL_FLAGS_INT_FEEDBACK_MASK BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT)
-#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT 3
-#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT)
-
-/**
- * struct analogbits_wrpll_cfg - WRPLL configuration values
- * @divr: reference divider value (6 bits), as presented to the PLL signals.
- * @divf: feedback divider value (9 bits), as presented to the PLL signals.
- * @divq: output divider value (3 bits), as presented to the PLL signals.
- * @flags: PLL configuration flags. See above for more information.
- * @range: PLL loop filter range. See below for more information.
- * @_output_rate_cache: cached output rates, swept across DIVQ.
- * @_parent_rate: PLL refclk rate for which values are valid
- * @_max_r: maximum possible R divider value, given @parent_rate
- * @_init_r: initial R divider value to start the search from
- *
- * @divr, @divq, @divq, @range represent what the PLL expects to see
- * on its input signals. Thus @divr and @divf are the actual divisors
- * minus one. @divq is a power-of-two divider; for example, 1 =
- * divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value.
- *
- * When initially passing a struct analogbits_wrpll_cfg record, the
- * record should be zero-initialized with the exception of the @flags
- * field. The only flag bits that need to be set are either
- * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK.
- *
- * Field names beginning with an underscore should be considered
- * private to the wrpll-cln28hpc.c code.
- */
-struct analogbits_wrpll_cfg {
- u8 divr;
- u8 divq;
- u8 range;
- u8 flags;
- u16 divf;
- u32 _output_rate_cache[DIVQ_VALUES];
- unsigned long _parent_rate;
- u8 _max_r;
- u8 _init_r;
-};
-
-/*
- * Function prototypes
- */
-
-int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c,
- u32 target_rate,
- unsigned long parent_rate);
-
-unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c);
-
-unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c,
- unsigned long parent_rate);
-
-#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */
diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
index 2d47ebc6b1e..ce0769f2d13 100644
--- a/drivers/clk/sifive/fu540-prci.c
+++ b/drivers/clk/sifive/fu540-prci.c
@@ -37,9 +37,8 @@
#include <errno.h>
#include <linux/math64.h>
-#include <dt-bindings/clk/sifive-fu540-prci.h>
-
-#include "analogbits-wrpll-cln28hpc.h"
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+#include <dt-bindings/clock/sifive-fu540-prci.h>
/*
* EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
@@ -159,30 +158,32 @@
* PRCI per-device instance data
*/
struct __prci_data {
- void *base;
- struct clk parent;
+ void *va;
+ struct clk parent_hfclk;
+ struct clk parent_rtcclk;
};
/**
* struct __prci_wrpll_data - WRPLL configuration and integration data
* @c: WRPLL current configuration record
- * @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
- * @no_bypass: fn ptr to code to not bypass the WRPLL (if applicable; else NULL)
+ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
*
- * @bypass and @no_bypass are used for WRPLL instances that contain a separate
- * external glitchless clock mux downstream from the PLL. The WRPLL internal
- * bypass mux is not glitchless.
+ * @enable_bypass and @disable_bypass are used for WRPLL instances
+ * that contain a separate external glitchless clock mux downstream
+ * from the PLL. The WRPLL internal bypass mux is not glitchless.
*/
struct __prci_wrpll_data {
- struct analogbits_wrpll_cfg c;
- void (*bypass)(struct __prci_data *pd);
- void (*no_bypass)(struct __prci_data *pd);
+ struct wrpll_cfg c;
+ void (*enable_bypass)(struct __prci_data *pd);
+ void (*disable_bypass)(struct __prci_data *pd);
u8 cfg0_offs;
};
struct __prci_clock;
+/* struct __prci_clock_ops - clock operations */
struct __prci_clock_ops {
int (*set_rate)(struct __prci_clock *pc,
unsigned long rate,
@@ -198,8 +199,7 @@ struct __prci_clock_ops {
* struct __prci_clock - describes a clock device managed by PRCI
* @name: user-readable clock name string - should match the manual
* @parent_name: parent name for this clock
- * @ops: struct clk_ops for the Linux clock framework to use for control
- * @hw: Linux-private clock data
+ * @ops: struct __prci_clock_ops for control
* @pwd: WRPLL-specific data, associated with this clock (if not NULL)
* @pd: PRCI-specific data associated with this clock (if not NULL)
*
@@ -233,19 +233,19 @@ struct __prci_clock {
*/
static u32 __prci_readl(struct __prci_data *pd, u32 offs)
{
- return readl(pd->base + offs);
+ return readl(pd->va + offs);
}
static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
{
- return writel(v, pd->base + offs);
+ writel(v, pd->va + offs);
}
/* WRPLL-related private functions */
/**
* __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
- * @c: ptr to a struct analogbits_wrpll_cfg record to write config into
+ * @c: ptr to a struct wrpll_cfg record to write config into
* @r: value read from the PRCI PLL configuration register
*
* Given a value @r read from an FU540 PRCI PLL configuration register,
@@ -257,7 +257,7 @@ static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
*
* Context: Any context.
*/
-static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
+static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
{
u32 v;
@@ -280,15 +280,13 @@ static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
WRPLL_FLAGS_EXT_FEEDBACK_MASK);
- if (r & PRCI_COREPLLCFG0_FSE_MASK)
- c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
- else
- c->flags |= WRPLL_FLAGS_EXT_FEEDBACK_MASK;
+ /* external feedback mode not supported */
+ c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
}
/**
* __prci_wrpll_pack() - pack PLL configuration parameters into a register value
- * @c: pointer to a struct analogbits_wrpll_cfg record containing the PLL's cfg
+ * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
*
* Using a set of WRPLL configuration values pointed to by @c,
* assemble a PRCI PLL configuration register value, and return it to
@@ -301,7 +299,7 @@ static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r)
* Returns: a value suitable for writing into a PRCI PLL configuration
* register
*/
-static u32 __prci_wrpll_pack(struct analogbits_wrpll_cfg *c)
+static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
{
u32 r = 0;
@@ -309,8 +307,9 @@ static u32 __prci_wrpll_pack(struct analogbits_wrpll_cfg *c)
r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
- if (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK)
- r |= PRCI_COREPLLCFG0_FSE_MASK;
+
+ /* external feedback mode not supported */
+ r |= PRCI_COREPLLCFG0_FSE_MASK;
return r;
}
@@ -349,11 +348,11 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd,
*/
static void __prci_wrpll_write_cfg(struct __prci_data *pd,
struct __prci_wrpll_data *pwd,
- struct analogbits_wrpll_cfg *c)
+ struct wrpll_cfg *c)
{
__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
- memcpy(&pwd->c, c, sizeof(struct analogbits_wrpll_cfg));
+ memcpy(&pwd->c, c, sizeof(*c));
}
/* Core clock mux control */
@@ -404,7 +403,7 @@ static unsigned long sifive_fu540_prci_wrpll_recalc_rate(
{
struct __prci_wrpll_data *pwd = pc->pwd;
- return analogbits_wrpll_calc_output_rate(&pwd->c, parent_rate);
+ return wrpll_calc_output_rate(&pwd->c, parent_rate);
}
static unsigned long sifive_fu540_prci_wrpll_round_rate(
@@ -413,13 +412,13 @@ static unsigned long sifive_fu540_prci_wrpll_round_rate(
unsigned long *parent_rate)
{
struct __prci_wrpll_data *pwd = pc->pwd;
- struct analogbits_wrpll_cfg c;
+ struct wrpll_cfg c;
memcpy(&c, &pwd->c, sizeof(c));
- analogbits_wrpll_configure_for_rate(&c, rate, *parent_rate);
+ wrpll_configure_for_rate(&c, rate, *parent_rate);
- return analogbits_wrpll_calc_output_rate(&c, *parent_rate);
+ return wrpll_calc_output_rate(&c, *parent_rate);
}
static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
@@ -430,19 +429,19 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
struct __prci_data *pd = pc->pd;
int r;
- r = analogbits_wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+ r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
if (r)
- return -ERANGE;
+ return r;
- if (pwd->bypass)
- pwd->bypass(pd);
+ if (pwd->enable_bypass)
+ pwd->enable_bypass(pd);
__prci_wrpll_write_cfg(pd, pwd, &pwd->c);
- udelay(analogbits_wrpll_calc_max_lock_us(&pwd->c));
+ udelay(wrpll_calc_max_lock_us(&pwd->c));
- if (pwd->no_bypass)
- pwd->no_bypass(pd);
+ if (pwd->disable_bypass)
+ pwd->disable_bypass(pd);
return 0;
}
@@ -484,8 +483,8 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
static struct __prci_wrpll_data __prci_corepll_data = {
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
- .bypass = __prci_coreclksel_use_hfclk,
- .no_bypass = __prci_coreclksel_use_corepll,
+ .enable_bypass = __prci_coreclksel_use_hfclk,
+ .disable_bypass = __prci_coreclksel_use_corepll,
};
static struct __prci_wrpll_data __prci_ddrpll_data = {
@@ -526,6 +525,27 @@ static struct __prci_clock __prci_init_clocks[] = {
},
};
+static ulong sifive_fu540_prci_parent_rate(struct __prci_clock *pc)
+{
+ ulong parent_rate;
+ struct __prci_clock *p;
+
+ if (strcmp(pc->parent_name, "corepll") == 0) {
+ p = &__prci_init_clocks[PRCI_CLK_COREPLL];
+ if (!p->pd || !p->ops->recalc_rate)
+ return -ENXIO;
+
+ return p->ops->recalc_rate(p, sifive_fu540_prci_parent_rate(p));
+ }
+
+ if (strcmp(pc->parent_name, "rtcclk") == 0)
+ parent_rate = clk_get_rate(&pc->pd->parent_rtcclk);
+ else
+ parent_rate = clk_get_rate(&pc->pd->parent_hfclk);
+
+ return parent_rate;
+}
+
static ulong sifive_fu540_prci_get_rate(struct clk *clk)
{
struct __prci_clock *pc;
@@ -537,7 +557,7 @@ static ulong sifive_fu540_prci_get_rate(struct clk *clk)
if (!pc->pd || !pc->ops->recalc_rate)
return -ENXIO;
- return pc->ops->recalc_rate(pc, clk_get_rate(&pc->pd->parent));
+ return pc->ops->recalc_rate(pc, sifive_fu540_prci_parent_rate(pc));
}
static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
@@ -552,7 +572,7 @@ static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
if (!pc->pd || !pc->ops->set_rate)
return -ENXIO;
- err = pc->ops->set_rate(pc, rate, clk_get_rate(&pc->pd->parent));
+ err = pc->ops->set_rate(pc, rate, sifive_fu540_prci_parent_rate(pc));
if (err)
return err;
@@ -565,11 +585,15 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
struct __prci_clock *pc;
struct __prci_data *pd = dev_get_priv(dev);
- pd->base = (void *)dev_read_addr(dev);
- if (IS_ERR(pd->base))
- return PTR_ERR(pd->base);
+ pd->va = (void *)dev_read_addr(dev);
+ if (IS_ERR(pd->va))
+ return PTR_ERR(pd->va);
+
+ err = clk_get_by_index(dev, 0, &pd->parent_hfclk);
+ if (err)
+ return err;
- err = clk_get_by_index(dev, 0, &pd->parent);
+ err = clk_get_by_index(dev, 1, &pd->parent_rtcclk);
if (err)
return err;
@@ -589,8 +613,7 @@ static struct clk_ops sifive_fu540_prci_ops = {
};
static const struct udevice_id sifive_fu540_prci_ids[] = {
- { .compatible = "sifive,fu540-c000-prci0" },
- { .compatible = "sifive,aloeprci0" },
+ { .compatible = "sifive,fu540-c000-prci" },
{ }
};
diff --git a/drivers/clk/sifive/gemgxl-mgmt.c b/drivers/clk/sifive/gemgxl-mgmt.c
deleted file mode 100644
index eb37416b5e0..00000000000
--- a/drivers/clk/sifive/gemgxl-mgmt.c
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2019, Bin Meng <bmeng.cn@gmail.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <asm/io.h>
-
-struct gemgxl_mgmt_regs {
- __u32 tx_clk_sel;
-};
-
-struct gemgxl_mgmt_platdata {
- struct gemgxl_mgmt_regs *regs;
-};
-
-static int gemgxl_mgmt_ofdata_to_platdata(struct udevice *dev)
-{
- struct gemgxl_mgmt_platdata *plat = dev_get_platdata(dev);
-
- plat->regs = (struct gemgxl_mgmt_regs *)dev_read_addr(dev);
-
- return 0;
-}
-
-static ulong gemgxl_mgmt_set_rate(struct clk *clk, ulong rate)
-{
- struct gemgxl_mgmt_platdata *plat = dev_get_platdata(clk->dev);
-
- /*
- * GEMGXL TX clock operation mode:
- *
- * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
- * and output clock on GMII output signal GTX_CLK
- * 1 = MII mode. Use MII input signal TX_CLK in TX logic
- */
- writel(rate != 125000000, &plat->regs->tx_clk_sel);
-
- return 0;
-}
-
-const struct clk_ops gemgxl_mgmt_ops = {
- .set_rate = gemgxl_mgmt_set_rate,
-};
-
-static const struct udevice_id gemgxl_mgmt_match[] = {
- { .compatible = "sifive,cadencegemgxlmgmt0", },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(sifive_gemgxl_mgmt) = {
- .name = "sifive-gemgxl-mgmt",
- .id = UCLASS_CLK,
- .of_match = gemgxl_mgmt_match,
- .ofdata_to_platdata = gemgxl_mgmt_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct gemgxl_mgmt_platdata),
- .ops = &gemgxl_mgmt_ops,
-};
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 0d15e5062b6..474c1642ee5 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -388,7 +388,8 @@ int device_probe(struct udevice *dev)
if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
pinctrl_select_state(dev, "default");
- if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
+ if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
+ device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
if (!power_domain_get(dev, &pd))
power_domain_on(&pd);
}
@@ -409,10 +410,16 @@ int device_probe(struct udevice *dev)
goto fail;
}
- /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
- ret = clk_set_defaults(dev);
- if (ret)
- goto fail;
+ /* Only handle devices that have a valid ofnode */
+ if (dev_of_valid(dev)) {
+ /*
+ * Process 'assigned-{clocks/clock-parents/clock-rates}'
+ * properties
+ */
+ ret = clk_set_defaults(dev);
+ if (ret)
+ goto fail;
+ }
if (drv->probe) {
ret = drv->probe(dev);
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index 1bfaaeec00a..4e256d99260 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -318,6 +318,10 @@ u64 of_translate_address(const struct device_node *dev, const __be32 *in_addr)
return __of_translate_address(dev, in_addr, "ranges");
}
+u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "dma-ranges");
+}
static int __of_address_to_resource(const struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index c72c6e26737..2ac73af9343 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -770,6 +770,14 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
}
+u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
+{
+ if (ofnode_is_np(node))
+ return of_translate_dma_address(ofnode_to_np(node), in_addr);
+ else
+ return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+}
+
int ofnode_device_is_compatible(ofnode node, const char *compat)
{
if (ofnode_is_np(node))
@@ -876,5 +884,5 @@ int ofnode_set_enabled(ofnode node, bool value)
if (value)
return ofnode_write_string(node, "status", "okay");
else
- return ofnode_write_string(node, "status", "disable");
+ return ofnode_write_string(node, "status", "disabled");
}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 6bda077a34b..1a044b05e88 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -265,6 +265,11 @@ u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr)
return ofnode_translate_address(dev_ofnode(dev), in_addr);
}
+u64 dev_translate_dma_address(struct udevice *dev, const fdt32_t *in_addr)
+{
+ return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
+}
+
int dev_read_alias_highest_id(const char *stem)
{
if (of_live_active())
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 303aa6a6311..1fd29f2cdf5 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -87,11 +87,18 @@ struct ti_sci_info {
struct mbox_chan chan_notify;
struct ti_sci_xfer xfer;
struct list_head list;
+ struct list_head dev_list;
bool is_secure;
u8 host_id;
u8 seq;
};
+struct ti_sci_exclusive_dev {
+ u32 id;
+ u32 count;
+ struct list_head list;
+};
+
#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
/**
@@ -101,7 +108,8 @@ struct ti_sci_info {
* @msg_flags: Flag to set for the message
* @buf: Buffer to be send to mailbox channel
* @tx_message_size: transmit message size
- * @rx_message_size: receive message size
+ * @rx_message_size: receive message size. may be set to zero for send-only
+ * transactions.
*
* Helper function which is used by various command functions that are
* exposed to clients of this driver for allocating a message traffic event.
@@ -121,7 +129,8 @@ static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info,
/* Ensure we have sane transfer sizes */
if (rx_message_size > info->desc->max_msg_size ||
tx_message_size > info->desc->max_msg_size ||
- rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr))
+ (rx_message_size > 0 && rx_message_size < sizeof(*hdr)) ||
+ tx_message_size < sizeof(*hdr))
return ERR_PTR(-ERANGE);
info->seq = ~info->seq;
@@ -219,7 +228,9 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
xfer->tx_message.buf = (u32 *)secure_buf;
xfer->tx_message.len += sizeof(secure_hdr);
- xfer->rx_len += sizeof(secure_hdr);
+
+ if (xfer->rx_len)
+ xfer->rx_len += sizeof(secure_hdr);
}
/* Send the message */
@@ -230,7 +241,11 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
return ret;
}
- return ti_sci_get_response(info, xfer, &info->chan_rx);
+ /* Get response if requested */
+ if (xfer->rx_len)
+ ret = ti_sci_get_response(info, xfer, &info->chan_rx);
+
+ return ret;
}
/**
@@ -419,6 +434,47 @@ static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle,
addr, size);
}
+static struct ti_sci_exclusive_dev
+*ti_sci_get_exclusive_dev(struct list_head *dev_list, u32 id)
+{
+ struct ti_sci_exclusive_dev *dev;
+
+ list_for_each_entry(dev, dev_list, list)
+ if (dev->id == id)
+ return dev;
+
+ return NULL;
+}
+
+static void ti_sci_add_exclusive_dev(struct ti_sci_info *info, u32 id)
+{
+ struct ti_sci_exclusive_dev *dev;
+
+ dev = ti_sci_get_exclusive_dev(&info->dev_list, id);
+ if (dev) {
+ dev->count++;
+ return;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev->id = id;
+ dev->count = 1;
+ INIT_LIST_HEAD(&dev->list);
+ list_add_tail(&dev->list, &info->dev_list);
+}
+
+static void ti_sci_delete_exclusive_dev(struct ti_sci_info *info, u32 id)
+{
+ struct ti_sci_exclusive_dev *dev;
+
+ dev = ti_sci_get_exclusive_dev(&info->dev_list, id);
+ if (!dev)
+ return;
+
+ if (dev->count > 0)
+ dev->count--;
+}
+
/**
* ti_sci_set_device_state() - Set device state helper
* @handle: pointer to TI SCI handle
@@ -466,6 +522,54 @@ static int ti_sci_set_device_state(const struct ti_sci_handle *handle,
if (!ti_sci_is_response_ack(resp))
return -ENODEV;
+ if (state == MSG_DEVICE_SW_STATE_AUTO_OFF)
+ ti_sci_delete_exclusive_dev(info, id);
+ else if (flags & MSG_FLAG_DEVICE_EXCLUSIVE)
+ ti_sci_add_exclusive_dev(info, id);
+
+ return ret;
+}
+
+/**
+ * ti_sci_set_device_state_no_wait() - Set device state helper without
+ * requesting or waiting for a response.
+ * @handle: pointer to TI SCI handle
+ * @id: Device identifier
+ * @flags: flags to setup for the device
+ * @state: State to move the device to
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_set_device_state_no_wait(const struct ti_sci_handle *handle,
+ u32 id, u32 flags, u8 state)
+{
+ struct ti_sci_msg_req_set_device_state req;
+ struct ti_sci_info *info;
+ struct ti_sci_xfer *xfer;
+ int ret = 0;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ info = handle_to_ti_sci_info(handle);
+
+ xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE,
+ flags | TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+ (u32 *)&req, sizeof(req), 0);
+ if (IS_ERR(xfer)) {
+ ret = PTR_ERR(xfer);
+ dev_err(info->dev, "Message alloc failed(%d)\n", ret);
+ return ret;
+ }
+ req.id = id;
+ req.state = state;
+
+ ret = ti_sci_do_xfer(info, xfer);
+ if (ret)
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
+
return ret;
}
@@ -547,8 +651,14 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
*/
static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id)
{
- return ti_sci_set_device_state(handle, id,
- MSG_FLAG_DEVICE_EXCLUSIVE,
+ return ti_sci_set_device_state(handle, id, 0,
+ MSG_DEVICE_SW_STATE_ON);
+}
+
+static int ti_sci_cmd_get_device_exclusive(const struct ti_sci_handle *handle,
+ u32 id)
+{
+ return ti_sci_set_device_state(handle, id, MSG_FLAG_DEVICE_EXCLUSIVE,
MSG_DEVICE_SW_STATE_ON);
}
@@ -566,7 +676,14 @@ static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id)
static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id)
{
return ti_sci_set_device_state(handle, id,
- MSG_FLAG_DEVICE_EXCLUSIVE,
+ 0,
+ MSG_DEVICE_SW_STATE_RETENTION);
+}
+
+static int ti_sci_cmd_idle_device_exclusive(const struct ti_sci_handle *handle,
+ u32 id)
+{
+ return ti_sci_set_device_state(handle, id, MSG_FLAG_DEVICE_EXCLUSIVE,
MSG_DEVICE_SW_STATE_RETENTION);
}
@@ -583,8 +700,27 @@ static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id)
*/
static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id)
{
- return ti_sci_set_device_state(handle, id,
- 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
+ return ti_sci_set_device_state(handle, id, 0,
+ MSG_DEVICE_SW_STATE_AUTO_OFF);
+}
+
+static
+int ti_sci_cmd_release_exclusive_devices(const struct ti_sci_handle *handle)
+{
+ struct ti_sci_exclusive_dev *dev, *tmp;
+ struct ti_sci_info *info;
+ int i, cnt;
+
+ info = handle_to_ti_sci_info(handle);
+
+ list_for_each_entry_safe(dev, tmp, &info->dev_list, list) {
+ cnt = dev->count;
+ debug("%s: id = %d, cnt = %d\n", __func__, dev->id, cnt);
+ for (i = 0; i < cnt; i++)
+ ti_sci_cmd_put_device(handle, dev->id);
+ }
+
+ return 0;
}
/**
@@ -2027,6 +2163,137 @@ static int ti_sci_cmd_get_proc_boot_status(const struct ti_sci_handle *handle,
}
/**
+ * ti_sci_proc_wait_boot_status_no_wait() - Helper function to wait for a
+ * processor boot status without requesting or
+ * waiting for a response.
+ * @proc_id: Processor ID this request is for
+ * @num_wait_iterations: Total number of iterations we will check before
+ * we will timeout and give up
+ * @num_match_iterations: How many iterations should we have continued
+ * status to account for status bits glitching.
+ * This is to make sure that match occurs for
+ * consecutive checks. This implies that the
+ * worst case should consider that the stable
+ * time should at the worst be num_wait_iterations
+ * num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us: Specifies how long to wait (in micro seconds)
+ * between each status checks. This is the minimum
+ * duration, and overhead of register reads and
+ * checks are on top of this and can vary based on
+ * varied conditions.
+ * @delay_before_iterations_us: Specifies how long to wait (in micro seconds)
+ * before the very first check in the first
+ * iteration of status check loop. This is the
+ * minimum duration, and overhead of register
+ * reads and checks are.
+ * @status_flags_1_set_all_wait:If non-zero, Specifies that all bits of the
+ * status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait:If non-zero, Specifies that at least one of the
+ * bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait:If non-zero, Specifies that all bits of the
+ * status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait:If non-zero, Specifies that at least one of the
+ * bits matching this field requested MUST be 0.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static int
+ti_sci_proc_wait_boot_status_no_wait(const struct ti_sci_handle *handle,
+ u8 proc_id,
+ u8 num_wait_iterations,
+ u8 num_match_iterations,
+ u8 delay_per_iteration_us,
+ u8 delay_before_iterations_us,
+ u32 status_flags_1_set_all_wait,
+ u32 status_flags_1_set_any_wait,
+ u32 status_flags_1_clr_all_wait,
+ u32 status_flags_1_clr_any_wait)
+{
+ struct ti_sci_msg_req_wait_proc_boot_status req;
+ struct ti_sci_info *info;
+ struct ti_sci_xfer *xfer;
+ int ret = 0;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ info = handle_to_ti_sci_info(handle);
+
+ xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_WAIT_PROC_BOOT_STATUS,
+ TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
+ (u32 *)&req, sizeof(req), 0);
+ if (IS_ERR(xfer)) {
+ ret = PTR_ERR(xfer);
+ dev_err(info->dev, "Message alloc failed(%d)\n", ret);
+ return ret;
+ }
+ req.processor_id = proc_id;
+ req.num_wait_iterations = num_wait_iterations;
+ req.num_match_iterations = num_match_iterations;
+ req.delay_per_iteration_us = delay_per_iteration_us;
+ req.delay_before_iterations_us = delay_before_iterations_us;
+ req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
+ req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
+ req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
+ req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
+
+ ret = ti_sci_do_xfer(info, xfer);
+ if (ret)
+ dev_err(info->dev, "Mbox send fail %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * ti_sci_cmd_proc_shutdown_no_wait() - Command to shutdown a core without
+ * requesting or waiting for a response. Note that this API call
+ * should be followed by placing the respective processor into
+ * either WFE or WFI mode.
+ * @handle: Pointer to TI SCI handle
+ * @proc_id: Processor ID this request is for
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+static int ti_sci_cmd_proc_shutdown_no_wait(const struct ti_sci_handle *handle,
+ u8 proc_id)
+{
+ int ret;
+
+ /*
+ * Send the core boot status wait message waiting for either WFE or
+ * WFI without requesting or waiting for a TISCI response with the
+ * maximum wait time to give us the best chance to get to the WFE/WFI
+ * command that should follow the invocation of this API before the
+ * DMSC-internal processing of this command times out. Note that
+ * waiting for the R5 WFE/WFI flags will also work on an ARMV8 type
+ * core as the related flag bit positions are the same.
+ */
+ ret = ti_sci_proc_wait_boot_status_no_wait(handle, proc_id,
+ U8_MAX, 100, U8_MAX, U8_MAX,
+ 0, PROC_BOOT_STATUS_FLAG_R5_WFE | PROC_BOOT_STATUS_FLAG_R5_WFI,
+ 0, 0);
+ if (ret) {
+ dev_err(info->dev, "Sending core %u wait message fail %d\n",
+ proc_id, ret);
+ return ret;
+ }
+
+ /*
+ * Release a processor managed by TISCI without requesting or waiting
+ * for a response.
+ */
+ ret = ti_sci_set_device_state_no_wait(handle, proc_id, 0,
+ MSG_DEVICE_SW_STATE_AUTO_OFF);
+ if (ret)
+ dev_err(info->dev, "Sending core %u shutdown message fail %d\n",
+ proc_id, ret);
+
+ return ret;
+}
+
+/**
* ti_sci_cmd_ring_config() - configure RA ring
* @handle: pointer to TI SCI handle
* @valid_params: Bitfield defining validity of ring configuration parameters.
@@ -2632,7 +2899,9 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
bops->board_config_pm = ti_sci_cmd_set_board_config_pm;
dops->get_device = ti_sci_cmd_get_device;
+ dops->get_device_exclusive = ti_sci_cmd_get_device_exclusive;
dops->idle_device = ti_sci_cmd_idle_device;
+ dops->idle_device_exclusive = ti_sci_cmd_idle_device_exclusive;
dops->put_device = ti_sci_cmd_put_device;
dops->is_valid = ti_sci_cmd_dev_is_valid;
dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt;
@@ -2642,6 +2911,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
dops->is_transitioning = ti_sci_cmd_dev_is_trans;
dops->set_device_resets = ti_sci_cmd_set_device_resets;
dops->get_device_resets = ti_sci_cmd_get_device_resets;
+ dops->release_exclusive_devices = ti_sci_cmd_release_exclusive_devices;
cops->get_clock = ti_sci_cmd_get_clock;
cops->idle_clock = ti_sci_cmd_idle_clock;
@@ -2672,6 +2942,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
pops->set_proc_boot_ctrl = ti_sci_cmd_set_proc_boot_ctrl;
pops->proc_auth_boot_image = ti_sci_cmd_proc_auth_boot_image;
pops->get_proc_boot_status = ti_sci_cmd_get_proc_boot_status;
+ pops->proc_shutdown_no_wait = ti_sci_cmd_proc_shutdown_no_wait;
rops->config = ti_sci_cmd_ring_config;
rops->get_config = ti_sci_cmd_ring_get_config;
@@ -2835,6 +3106,8 @@ static int ti_sci_probe(struct udevice *dev)
ret = ti_sci_cmd_get_revision(&info->handle);
+ INIT_LIST_HEAD(&info->dev_list);
+
return ret;
}
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index a484b1fa408..69ff74d6a95 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -50,6 +50,7 @@
#define TISCI_MSG_SET_PROC_BOOT_CTRL 0xc101
#define TISCI_MSG_PROC_AUTH_BOOT_IMIAGE 0xc120
#define TISCI_MSG_GET_PROC_BOOT_STATUS 0xc400
+#define TISCI_MSG_WAIT_PROC_BOOT_STATUS 0xc401
/* Resource Management Requests */
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500
@@ -773,6 +774,55 @@ struct ti_sci_msg_resp_get_proc_boot_status {
} __packed;
/**
+ * struct ti_sci_msg_req_wait_proc_boot_status - Wait for a processor
+ * boot status
+ * @hdr: Generic Header
+ * @processor_id: ID of processor
+ * @num_wait_iterations: Total number of iterations we will check before
+ * we will timeout and give up
+ * @num_match_iterations: How many iterations should we have continued
+ * status to account for status bits glitching.
+ * This is to make sure that match occurs for
+ * consecutive checks. This implies that the
+ * worst case should consider that the stable
+ * time should at the worst be num_wait_iterations
+ * num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us: Specifies how long to wait (in micro seconds)
+ * between each status checks. This is the minimum
+ * duration, and overhead of register reads and
+ * checks are on top of this and can vary based on
+ * varied conditions.
+ * @delay_before_iterations_us: Specifies how long to wait (in micro seconds)
+ * before the very first check in the first
+ * iteration of status check loop. This is the
+ * minimum duration, and overhead of register
+ * reads and checks are.
+ * @status_flags_1_set_all_wait:If non-zero, Specifies that all bits of the
+ * status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait:If non-zero, Specifies that at least one of the
+ * bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait:If non-zero, Specifies that all bits of the
+ * status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait:If non-zero, Specifies that at least one of the
+ * bits matching this field requested MUST be 0.
+ *
+ * Request type is TISCI_MSG_WAIT_PROC_BOOT_STATUS, response is appropriate
+ * message, or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_wait_proc_boot_status {
+ struct ti_sci_msg_hdr hdr;
+ u8 processor_id;
+ u8 num_wait_iterations;
+ u8 num_match_iterations;
+ u8 delay_per_iteration_us;
+ u8 delay_before_iterations_us;
+ u32 status_flags_1_set_all_wait;
+ u32 status_flags_1_set_any_wait;
+ u32 status_flags_1_clr_all_wait;
+ u32 status_flags_1_clr_any_wait;
+} __packed;
+
+/**
* struct ti_sci_msg_rm_ring_cfg_req - Configure a Navigator Subsystem ring
*
* Configures the non-real-time registers of a Navigator Subsystem ring.
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 8bd30c75b2f..64ab7a303f1 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -31,7 +31,7 @@ struct mxc_bank_info {
};
#ifndef CONFIG_DM_GPIO
-#define GPIO_TO_PORT(n) (n / 32)
+#define GPIO_TO_PORT(n) ((n) / 32)
/* GPIO port description */
static unsigned long gpio_ports[] = {
diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c
index c2c8a25886a..b2451fdda8a 100644
--- a/drivers/gpio/mxs_gpio.c
+++ b/drivers/gpio/mxs_gpio.c
@@ -51,6 +51,7 @@ void mxs_gpio_init(void)
}
}
+#if !CONFIG_IS_ENABLED(DM_GPIO)
int gpio_get_value(unsigned gpio)
{
uint32_t bank = PAD_BANK(gpio);
@@ -127,3 +128,150 @@ int name_to_gpio(const char *name)
return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
}
+#else /* CONFIG_DM_GPIO */
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/arch/gpio.h>
+#define MXS_MAX_GPIO_PER_BANK 32
+
+DECLARE_GLOBAL_DATA_PTR;
+/*
+ * According to i.MX28 Reference Manual:
+ * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010'
+ * The i.MX28 has following number of GPIOs available:
+ * Bank 0: 0-28 -> 29 PINS
+ * Bank 1: 0-31 -> 32 PINS
+ * Bank 2: 0-27 -> 28 PINS
+ * Bank 3: 0-30 -> 31 PINS
+ * Bank 4: 0-20 -> 21 PINS
+ */
+
+struct mxs_gpio_priv {
+ unsigned int bank;
+};
+
+static int mxs_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DIN(priv->bank));
+
+ return (readl(&reg->reg) >> offset) & 1;
+}
+
+static int mxs_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOUT(priv->bank));
+ if (value)
+ writel(BIT(offset), &reg->reg_set);
+ else
+ writel(BIT(offset), &reg->reg_clr);
+
+ return 0;
+}
+
+static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOE(priv->bank));
+
+ writel(BIT(offset), &reg->reg_clr);
+
+ return 0;
+}
+
+static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOE(priv->bank));
+
+ mxs_gpio_set_value(dev, offset, value);
+
+ writel(BIT(offset), &reg->reg_set);
+
+ return 0;
+}
+
+static int mxs_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct mxs_register_32 *reg =
+ (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
+ PINCTRL_DOE(priv->bank));
+ bool is_output = !!(readl(&reg->reg) >> offset);
+
+ return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops gpio_mxs_ops = {
+ .direction_input = mxs_gpio_direction_input,
+ .direction_output = mxs_gpio_direction_output,
+ .get_value = mxs_gpio_get_value,
+ .set_value = mxs_gpio_set_value,
+ .get_function = mxs_gpio_get_function,
+};
+
+static int mxs_gpio_probe(struct udevice *dev)
+{
+ struct mxs_gpio_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct fdtdec_phandle_args args;
+ int node = dev_of_offset(dev);
+ char name[16], *str;
+ fdt_addr_t addr;
+ int ret;
+
+ addr = devfdt_get_addr(dev);
+ if (addr == FDT_ADDR_T_NONE) {
+ printf("%s: No 'reg' property defined!\n", __func__);
+ return -EINVAL;
+ }
+
+ priv->bank = (unsigned int)addr;
+
+ snprintf(name, sizeof(name), "GPIO%d_", priv->bank);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+
+ uc_priv->bank_name = str;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
+ NULL, 3, 0, &args);
+ if (ret)
+ printf("%s: 'gpio-ranges' not defined - using default!\n",
+ __func__);
+
+ uc_priv->gpio_count = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK;
+
+ debug("%s: %s: %d pins\n", __func__, uc_priv->bank_name,
+ uc_priv->gpio_count);
+
+ return 0;
+}
+
+static const struct udevice_id mxs_gpio_ids[] = {
+ { .compatible = "fsl,imx23-gpio" },
+ { .compatible = "fsl,imx28-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_mxs) = {
+ .name = "gpio_mxs",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_mxs_ops,
+ .probe = mxs_gpio_probe,
+ .priv_auto_alloc_size = sizeof(struct mxs_gpio_priv),
+ .of_match = mxs_gpio_ids,
+};
+#endif /* CONFIG_DM_GPIO */
diff --git a/drivers/misc/imx8/scu_api.c b/drivers/misc/imx8/scu_api.c
index d9c4d5d7840..031bc0048b6 100644
--- a/drivers/misc/imx8/scu_api.c
+++ b/drivers/misc/imx8/scu_api.c
@@ -273,6 +273,34 @@ int sc_misc_otp_fuse_read(sc_ipc_t ipc, u32 word, u32 *val)
return 0;
}
+int sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp,
+ s16 *celsius, s8 *tenths)
+{
+ struct udevice *dev = gd->arch.scu_dev;
+ int size = sizeof(struct sc_rpc_msg_s);
+ struct sc_rpc_msg_s msg;
+ int ret;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (u8)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (u8)MISC_FUNC_GET_TEMP;
+ RPC_U16(&msg, 0U) = (u16)resource;
+ RPC_U8(&msg, 2U) = (u8)temp;
+ RPC_SIZE(&msg) = 2U;
+
+ ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size);
+ if (ret < 0)
+ return ret;
+
+ if (celsius)
+ *celsius = RPC_I16(&msg, 0U);
+
+ if (tenths)
+ *tenths = RPC_I8(&msg, 2U);
+
+ return 0;
+}
+
/* RM */
sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr)
{
diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
index fb0fb580706..1793a3f99a5 100644
--- a/drivers/mmc/am654_sdhci.c
+++ b/drivers/mmc/am654_sdhci.c
@@ -72,6 +72,8 @@ struct am654_sdhci_plat {
u32 otap_del_sel;
u32 trm_icp;
u32 drv_strength;
+ u32 flags;
+#define DLL_PRESENT (1 << 0)
bool dll_on;
};
@@ -162,6 +164,10 @@ const struct sdhci_ops am654_sdhci_ops = {
.set_control_reg = &am654_sdhci_set_control_reg,
};
+const struct sdhci_ops j721e_4bit_sdhci_ops = {
+ .set_control_reg = &am654_sdhci_set_control_reg,
+};
+
int am654_sdhci_init(struct am654_sdhci_plat *plat)
{
u32 ctl_cfg_2 = 0;
@@ -172,24 +178,28 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat)
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
- regmap_read(plat->base, PHY_STAT1, &val);
- if (~val & CALDONE_MASK) {
- /* Calibrate IO lines */
- regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK, PDB_MASK);
- ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
- val & CALDONE_MASK, 1, 20);
- if (ret)
- return ret;
- }
+ if (plat->flags & DLL_PRESENT) {
+ regmap_read(plat->base, PHY_STAT1, &val);
+ if (~val & CALDONE_MASK) {
+ /* Calibrate IO lines */
+ regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK,
+ PDB_MASK);
+ ret = regmap_read_poll_timeout(plat->base, PHY_STAT1,
+ val, val & CALDONE_MASK,
+ 1, 20);
+ if (ret)
+ return ret;
+ }
- /* Configure DLL TRIM */
- mask = DLL_TRIM_ICP_MASK;
- val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
+ /* Configure DLL TRIM */
+ mask = DLL_TRIM_ICP_MASK;
+ val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
- /* Configure DLL driver strength */
- mask |= DR_TY_MASK;
- val |= plat->drv_strength << DR_TY_SHIFT;
- regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
+ /* Configure DLL driver strength */
+ mask |= DR_TY_MASK;
+ val |= plat->drv_strength << DR_TY_SHIFT;
+ regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
+ }
/* Enable pins by setting IO mux to 0 */
regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
@@ -245,7 +255,7 @@ static int am654_sdhci_probe(struct udevice *dev)
AM654_SDHCI_MIN_FREQ);
if (ret)
return ret;
- host->ops = &am654_sdhci_ops;
+ host->ops = (struct sdhci_ops *)dev_get_driver_data(dev);
host->mmc->priv = host;
upriv->mmc = host->mmc;
@@ -268,37 +278,44 @@ static int am654_sdhci_ofdata_to_platdata(struct udevice *dev)
host->ioaddr = (void *)dev_read_addr(dev);
plat->non_removable = dev_read_bool(dev, "non-removable");
- ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
- if (ret)
- return ret;
+ if (device_is_compatible(dev, "ti,am654-sdhci-5.1") ||
+ device_is_compatible(dev, "ti,j721e-sdhci-8bit"))
+ plat->flags |= DLL_PRESENT;
ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel);
if (ret)
return ret;
- ret = dev_read_u32(dev, "ti,driver-strength-ohm", &drv_strength);
- if (ret)
- return ret;
+ if (plat->flags & DLL_PRESENT) {
+ ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
+ if (ret)
+ return ret;
+
+ ret = dev_read_u32(dev, "ti,driver-strength-ohm",
+ &drv_strength);
+ if (ret)
+ return ret;
- switch (drv_strength) {
- case 50:
- plat->drv_strength = DRIVER_STRENGTH_50_OHM;
- break;
- case 33:
- plat->drv_strength = DRIVER_STRENGTH_33_OHM;
- break;
- case 66:
- plat->drv_strength = DRIVER_STRENGTH_66_OHM;
- break;
- case 100:
- plat->drv_strength = DRIVER_STRENGTH_100_OHM;
- break;
- case 40:
- plat->drv_strength = DRIVER_STRENGTH_40_OHM;
- break;
- default:
- dev_err(dev, "Invalid driver strength\n");
- return -EINVAL;
+ switch (drv_strength) {
+ case 50:
+ plat->drv_strength = DRIVER_STRENGTH_50_OHM;
+ break;
+ case 33:
+ plat->drv_strength = DRIVER_STRENGTH_33_OHM;
+ break;
+ case 66:
+ plat->drv_strength = DRIVER_STRENGTH_66_OHM;
+ break;
+ case 100:
+ plat->drv_strength = DRIVER_STRENGTH_100_OHM;
+ break;
+ case 40:
+ plat->drv_strength = DRIVER_STRENGTH_40_OHM;
+ break;
+ default:
+ dev_err(dev, "Invalid driver strength\n");
+ return -EINVAL;
+ }
}
ret = mmc_of_parse(dev, cfg);
@@ -316,7 +333,18 @@ static int am654_sdhci_bind(struct udevice *dev)
}
static const struct udevice_id am654_sdhci_ids[] = {
- { .compatible = "ti,am654-sdhci-5.1" },
+ {
+ .compatible = "ti,am654-sdhci-5.1",
+ .data = (ulong)&am654_sdhci_ops,
+ },
+ {
+ .compatible = "ti,j721e-sdhci-8bit",
+ .data = (ulong)&am654_sdhci_ops,
+ },
+ {
+ .compatible = "ti,j721e-sdhci-4bit",
+ .data = (ulong)&j721e_4bit_sdhci_ops,
+ },
{ }
};
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
index f3d687ae806..350812a04ba 100644
--- a/drivers/mmc/mmc_spi.c
+++ b/drivers/mmc/mmc_spi.c
@@ -84,7 +84,7 @@ static int mmc_spi_sendcmd(struct udevice *dev,
cmdo[4] = cmdarg >> 8;
cmdo[5] = cmdarg;
cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
- ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0);
+ ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, SPI_XFER_BEGIN);
if (ret)
return ret;
@@ -360,6 +360,8 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
}
done:
+ dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END);
+
dm_spi_release_bus(dev);
return ret;
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index cb623d589b4..dd3d5574dbc 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -68,15 +68,15 @@ static int arasan_sdhci_probe(struct udevice *dev)
if (host->bus_width == 8)
host->host_caps |= MMC_MODE_8BIT;
- ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
-
host->mmc = &plat->mmc;
- if (ret)
- return ret;
host->mmc->priv = &prv->host;
host->mmc->dev = dev;
upriv->mmc = host->mmc;
+ ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
+ if (ret)
+ return ret;
+
return sdhci_probe(dev);
}
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index b93d77a3951..a41b9620d0a 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -25,7 +25,7 @@
#include <asm/mach-imx/regs-bch.h>
#include <asm/mach-imx/regs-gpmi.h>
#include <asm/arch/sys_proto.h>
-#include "mxs_nand.h"
+#include <mxs_nand.h>
#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
diff --git a/drivers/mtd/nand/raw/mxs_nand.h b/drivers/mtd/nand/raw/mxs_nand.h
deleted file mode 100644
index 4bd65cded94..00000000000
--- a/drivers/mtd/nand/raw/mxs_nand.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * NXP GPMI NAND flash driver
- *
- * Copyright (C) 2018 Toradex
- * Authors:
- * Stefan Agner <stefan.agner@toradex.com>
- */
-
-#include <linux/mtd/mtd.h>
-#include <asm/cache.h>
-#include <nand.h>
-#include <asm/mach-imx/dma.h>
-
-/**
- * @gf_len: The length of Galois Field. (e.g., 13 or 14)
- * @ecc_strength: A number that describes the strength of the ECC
- * algorithm.
- * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note
- * the first chunk in the page includes both data and
- * metadata, so it's a bit larger than this value.
- * @ecc_chunk_count: The number of ECC chunks in the page,
- * @block_mark_byte_offset: The byte offset in the ECC-based page view at
- * which the underlying physical block mark appears.
- * @block_mark_bit_offset: The bit offset into the ECC-based page view at
- * which the underlying physical block mark appears.
- */
-struct bch_geometry {
- unsigned int gf_len;
- unsigned int ecc_strength;
- unsigned int ecc_chunk_size;
- unsigned int ecc_chunk_count;
- unsigned int block_mark_byte_offset;
- unsigned int block_mark_bit_offset;
-};
-
-struct mxs_nand_info {
- struct nand_chip chip;
- struct udevice *dev;
- unsigned int max_ecc_strength_supported;
- bool use_minimum_ecc;
- int cur_chip;
-
- uint32_t cmd_queue_len;
- uint32_t data_buf_size;
- struct bch_geometry bch_geometry;
-
- uint8_t *cmd_buf;
- uint8_t *data_buf;
- uint8_t *oob_buf;
-
- uint8_t marking_block_bad;
- uint8_t raw_oob_mode;
-
- struct mxs_gpmi_regs *gpmi_regs;
- struct mxs_bch_regs *bch_regs;
-
- /* Functions with altered behaviour */
- int (*hooked_read_oob)(struct mtd_info *mtd,
- loff_t from, struct mtd_oob_ops *ops);
- int (*hooked_write_oob)(struct mtd_info *mtd,
- loff_t to, struct mtd_oob_ops *ops);
- int (*hooked_block_markbad)(struct mtd_info *mtd,
- loff_t ofs);
-
- /* DMA descriptors */
- struct mxs_dma_desc **desc;
- uint32_t desc_index;
-};
-
-int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info);
-int mxs_nand_init_spl(struct nand_chip *nand);
-int mxs_nand_setup_ecc(struct mtd_info *mtd);
diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c
index 44dec5dedf9..8ad7d618c64 100644
--- a/drivers/mtd/nand/raw/mxs_nand_dt.c
+++ b/drivers/mtd/nand/raw/mxs_nand_dt.c
@@ -15,7 +15,7 @@
#include <linux/ioport.h>
#include <linux/printk.h>
-#include "mxs_nand.h"
+#include <mxs_nand.h>
struct mxs_nand_dt_data {
unsigned int max_ecc_strength_supported;
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index ee7d9cb9571..975a91a37d2 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -6,7 +6,7 @@
#include <common.h>
#include <nand.h>
#include <malloc.h>
-#include "mxs_nand.h"
+#include <mxs_nand.h>
static struct mtd_info *mtd;
static struct nand_chip nand_chip;
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index ec929760eee..a3920ba520e 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -163,11 +163,15 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { INFO6("mt25qu512a", 0x20bb20, 0x104400, 64 * 1024, 1024,
+ SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+ { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_4B_OPCODES) },
+ { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, USE_FSR | SPI_NOR_4B_OPCODES) },
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
/* Spansion/Cypress -- single (large) sector size only, at least
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 635f8d72c2d..0a1d228a883 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -24,6 +24,18 @@ config DM_MDIO
This is currently implemented in net/mdio-uclass.c
Look in include/miiphy.h for details.
+config DM_MDIO_MUX
+ bool "Enable Driver Model for MDIO MUX devices"
+ depends on DM_MDIO
+ help
+ Enable driver model for MDIO MUX devices
+
+ Adds UCLASS_MDIO_MUX DM class supporting MDIO MUXes. Useful for
+ systems that support DM_MDIO and integrate one or multiple muxes on
+ the MDIO bus.
+ This is currently implemented in net/mdio-mux-uclass.c
+ Look in include/miiphy.h for details.
+
config MDIO_SANDBOX
depends on DM_MDIO && SANDBOX
default y
@@ -34,6 +46,16 @@ config MDIO_SANDBOX
This driver is used in for testing in test/dm/mdio.c
+config MDIO_MUX_SANDBOX
+ depends on DM_MDIO_MUX && MDIO_SANDBOX
+ default y
+ bool "Sandbox: Mocked MDIO-MUX driver"
+ help
+ This driver implements dummy select/deselect ops mimicking a MUX on
+ the MDIO bux. It uses mdio_sandbox driver as parent MDIO.
+
+ This driver is used for testing in test/dm/mdio.c
+
menuconfig NETDEVICES
bool "Network device support"
depends on NET
@@ -213,7 +235,7 @@ config FEC_MXC_MDIO_BASE
config FEC_MXC
bool "FEC Ethernet controller"
- depends on MX5 || MX6 || MX7 || IMX8 || VF610
+ depends on MX28 || MX5 || MX6 || MX7 || IMX8 || VF610
help
This driver supports the 10/100 Fast Ethernet controller for
NXP i.MX processors.
@@ -566,4 +588,19 @@ config HIGMACV300_ETH
This driver supports HIGMACV300 Ethernet controller found on
HiSilicon SoCs.
+config FSL_ENETC
+ bool "NXP ENETC Ethernet controller"
+ depends on DM_PCI && DM_ETH && DM_MDIO
+ help
+ This driver supports the NXP ENETC Ethernet controller found on some
+ of the NXP SoCs.
+
+config MDIO_MUX_I2CREG
+ bool "MDIO MUX accessed as a register over I2C"
+ depends on DM_MDIO_MUX && DM_I2C
+ help
+ This driver is used for MDIO muxes driven by writing to a register of
+ an I2C chip. The board it was developed for uses a mux controlled by
+ on-board FPGA which in turn is accessed as a chip over I2C.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 40038427dbd..71c0889355c 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,6 +37,8 @@ obj-$(CONFIG_LAN91C96) += lan91c96.o
obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
+obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o
+obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
obj-$(CONFIG_MVGBE) += mvgbe.o
@@ -78,3 +80,4 @@ obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
obj-y += mscc_eswitch/
obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
+obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 2c5d9560c58..c4fe40b19aa 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -480,18 +480,16 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
- int mask = 0xffffffff, ret;
+ int phy_addr = -1, ret;
#ifdef CONFIG_PHY_ADDR
- mask = 1 << CONFIG_PHY_ADDR;
+ phy_addr = CONFIG_PHY_ADDR;
#endif
- phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+ phydev = phy_connect(priv->bus, phy_addr, dev, priv->interface);
if (!phydev)
return -ENODEV;
- phy_connect_dev(phydev, dev);
-
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
@@ -677,10 +675,10 @@ int designware_eth_probe(struct udevice *dev)
struct dw_eth_dev *priv = dev_get_priv(dev);
u32 iobase = pdata->iobase;
ulong ioaddr;
- int ret;
+ int ret, err;
struct reset_ctl_bulk reset_bulk;
#ifdef CONFIG_CLK
- int i, err, clock_nb;
+ int i, clock_nb;
priv->clock_count = 0;
clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
@@ -753,13 +751,23 @@ int designware_eth_probe(struct udevice *dev)
priv->interface = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
- dw_mdio_init(dev->name, dev);
+ ret = dw_mdio_init(dev->name, dev);
+ if (ret) {
+ err = ret;
+ goto mdio_err;
+ }
priv->bus = miiphy_get_dev_by_name(dev->name);
ret = dw_phy_init(priv, dev);
debug("%s, ret=%d\n", __func__, ret);
+ if (!ret)
+ return 0;
- return ret;
+ /* continue here for cleanup if no PHY found */
+ err = ret;
+ mdio_unregister(priv->bus);
+ mdio_free(priv->bus);
+mdio_err:
#ifdef CONFIG_CLK
clk_err:
@@ -767,8 +775,8 @@ clk_err:
if (ret)
pr_err("failed to disable all clocks\n");
- return err;
#endif
+ return err;
}
static int designware_eth_remove(struct udevice *dev)
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index d7c080943a5..96e3ad9a1a2 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -1485,6 +1485,7 @@ static int fecmxc_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id fecmxc_ids[] = {
+ { .compatible = "fsl,imx28-fec" },
{ .compatible = "fsl,imx6q-fec" },
{ .compatible = "fsl,imx6sl-fec" },
{ .compatible = "fsl,imx6sx-fec" },
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
new file mode 100644
index 00000000000..e7c5062c39a
--- /dev/null
+++ b/drivers/net/fsl_enetc.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ENETC ethernet controller driver
+ * Copyright 2017-2019 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <memalign.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <miiphy.h>
+
+#include "fsl_enetc.h"
+
+/*
+ * Bind the device:
+ * - set a more explicit name on the interface
+ */
+static int enetc_bind(struct udevice *dev)
+{
+ char name[16];
+ static int eth_num_devices;
+
+ /*
+ * prefer using PCI function numbers to number interfaces, but these
+ * are only available if dts nodes are present. For PCI they are
+ * optional, handle that case too. Just in case some nodes are present
+ * and some are not, use different naming scheme - enetc-N based on
+ * PCI function # and enetc#N based on interface count
+ */
+ if (ofnode_valid(dev->node))
+ sprintf(name, "enetc-%u", PCI_FUNC(pci_get_devfn(dev)));
+ else
+ sprintf(name, "enetc#%u", eth_num_devices++);
+ device_set_name(dev, name);
+
+ return 0;
+}
+
+/* MDIO wrappers, we're using these to drive internal MDIO to get to serdes */
+static int enetc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct enetc_mdio_priv priv;
+
+ priv.regs_base = bus->priv;
+ return enetc_mdio_read_priv(&priv, addr, devad, reg);
+}
+
+static int enetc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct enetc_mdio_priv priv;
+
+ priv.regs_base = bus->priv;
+ return enetc_mdio_write_priv(&priv, addr, devad, reg, val);
+}
+
+/* only interfaces that can pin out through serdes have internal MDIO */
+static bool enetc_has_imdio(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ return !!(priv->imdio.priv);
+}
+
+/* set up serdes for SGMII */
+static int enetc_init_sgmii(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ bool is2500 = false;
+ u16 reg;
+
+ if (!enetc_has_imdio(dev))
+ return 0;
+
+ if (priv->if_type == PHY_INTERFACE_MODE_SGMII_2500)
+ is2500 = true;
+
+ /*
+ * Set to SGMII mode, for 1Gbps enable AN, for 2.5Gbps set fixed speed.
+ * Although fixed speed is 1Gbps, we could be running at 2.5Gbps based
+ * on PLL configuration. Setting 1G for 2.5G here is counter intuitive
+ * but intentional.
+ */
+ reg = ENETC_PCS_IF_MODE_SGMII;
+ reg |= is2500 ? ENETC_PCS_IF_MODE_SPEED_1G : ENETC_PCS_IF_MODE_SGMII_AN;
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_IF_MODE, reg);
+
+ /* Dev ability - SGMII */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SGMII);
+
+ /* Adjust link timer for SGMII */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
+
+ reg = ENETC_PCS_CR_DEF_VAL;
+ reg |= is2500 ? ENETC_PCS_CR_RST : ENETC_PCS_CR_RESET_AN;
+ /* restart PCS AN */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, MDIO_DEVAD_NONE,
+ ENETC_PCS_CR, reg);
+
+ return 0;
+}
+
+/* set up MAC for RGMII */
+static int enetc_init_rgmii(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ u32 if_mode;
+
+ /* enable RGMII AN */
+ if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
+ if_mode |= ENETC_PM_IF_MODE_AN_ENA;
+ enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+
+ return 0;
+}
+
+/* set up MAC and serdes for SXGMII */
+static int enetc_init_sxgmii(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ u32 if_mode;
+
+ /* set ifmode to (US)XGMII */
+ if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
+ if_mode &= ~ENETC_PM_IF_IFMODE_MASK;
+ enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+
+ if (!enetc_has_imdio(dev))
+ return 0;
+
+ /* Dev ability - SXGMII */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII);
+
+ /* Restart PCS AN */
+ enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL,
+ ENETC_PCS_CR,
+ ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN);
+
+ return 0;
+}
+
+/* Apply protocol specific configuration to MAC, serdes as needed */
+static void enetc_start_pcs(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ const char *if_str;
+
+ priv->if_type = PHY_INTERFACE_MODE_NONE;
+
+ /* check internal mdio capability, not all ports need it */
+ if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) {
+ /*
+ * set up internal MDIO, this is part of ETH PCI function and is
+ * used to access serdes / internal SoC PHYs.
+ * We don't currently register it as a MDIO bus as it goes away
+ * when the interface is removed, so it can't practically be
+ * used in the console.
+ */
+ priv->imdio.read = enetc_mdio_read;
+ priv->imdio.write = enetc_mdio_write;
+ priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE;
+ strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN);
+ }
+
+ if (!ofnode_valid(dev->node)) {
+ enetc_dbg(dev, "no enetc ofnode found, skipping PCS set-up\n");
+ return;
+ }
+
+ if_str = ofnode_read_string(dev->node, "phy-mode");
+ if (if_str)
+ priv->if_type = phy_get_interface_by_name(if_str);
+ else
+ enetc_dbg(dev,
+ "phy-mode property not found, defaulting to SGMII\n");
+ if (priv->if_type < 0)
+ priv->if_type = PHY_INTERFACE_MODE_NONE;
+
+ switch (priv->if_type) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_SGMII_2500:
+ enetc_init_sgmii(dev);
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ enetc_init_rgmii(dev);
+ break;
+ case PHY_INTERFACE_MODE_XGMII:
+ enetc_init_sxgmii(dev);
+ break;
+ };
+}
+
+/* Configure the actual/external ethernet PHY, if one is found */
+static void enetc_start_phy(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct udevice *miidev;
+ struct phy_device *phy;
+ u32 phandle, phy_id;
+ ofnode phy_node;
+ int supported;
+
+ if (!ofnode_valid(dev->node)) {
+ enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n");
+ return;
+ }
+
+ if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) {
+ enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n");
+ return;
+ }
+
+ phy_node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(phy_node)) {
+ enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n");
+ return;
+ }
+ enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node));
+
+ if (ofnode_read_u32(phy_node, "reg", &phy_id)) {
+ enetc_dbg(dev,
+ "missing reg in PHY node, skipping PHY set-up\n");
+ return;
+ }
+
+ if (uclass_get_device_by_ofnode(UCLASS_MDIO,
+ ofnode_get_parent(phy_node),
+ &miidev)) {
+ enetc_dbg(dev, "can't find MDIO bus for node %s\n",
+ ofnode_get_name(ofnode_get_parent(phy_node)));
+ return;
+ }
+
+ phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type);
+ if (!phy) {
+ enetc_dbg(dev, "dm_mdio_phy_connect returned null\n");
+ return;
+ }
+
+ supported = GENMASK(6, 0); /* speeds up to 1G & AN */
+ phy->advertising = phy->supported & supported;
+ phy_config(phy);
+ phy_startup(phy);
+}
+
+/*
+ * Probe ENETC driver:
+ * - initialize port and station interface BARs
+ */
+static int enetc_probe(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ if (ofnode_valid(dev->node) && !ofnode_is_available(dev->node)) {
+ enetc_dbg(dev, "interface disabled\n");
+ return -ENODEV;
+ }
+
+ priv->enetc_txbd = memalign(ENETC_BD_ALIGN,
+ sizeof(struct enetc_tx_bd) * ENETC_BD_CNT);
+ priv->enetc_rxbd = memalign(ENETC_BD_ALIGN,
+ sizeof(union enetc_rx_bd) * ENETC_BD_CNT);
+
+ if (!priv->enetc_txbd || !priv->enetc_rxbd) {
+ /* free should be able to handle NULL, just free all pointers */
+ free(priv->enetc_txbd);
+ free(priv->enetc_rxbd);
+
+ return -ENOMEM;
+ }
+
+ /* initialize register */
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ if (!priv->regs_base) {
+ enetc_dbg(dev, "failed to map BAR0\n");
+ return -EINVAL;
+ }
+ priv->port_regs = priv->regs_base + ENETC_PORT_REGS_OFF;
+
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+
+ return 0;
+}
+
+/*
+ * Remove the driver from an interface:
+ * - free up allocated memory
+ */
+static int enetc_remove(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ free(priv->enetc_txbd);
+ free(priv->enetc_rxbd);
+
+ return 0;
+}
+
+/* ENETC Port MAC address registers, accepts big-endian format */
+static void enetc_set_primary_mac_addr(struct enetc_priv *priv, const u8 *addr)
+{
+ u16 lower = *(const u16 *)(addr + 4);
+ u32 upper = *(const u32 *)addr;
+
+ enetc_write_port(priv, ENETC_PSIPMAR0, upper);
+ enetc_write_port(priv, ENETC_PSIPMAR1, lower);
+}
+
+/* Configure port parameters (# of rings, frame size, enable port) */
+static void enetc_enable_si_port(struct enetc_priv *priv)
+{
+ u32 val;
+
+ /* set Rx/Tx BDR count */
+ val = ENETC_PSICFGR_SET_TXBDR(ENETC_TX_BDR_CNT);
+ val |= ENETC_PSICFGR_SET_RXBDR(ENETC_RX_BDR_CNT);
+ enetc_write_port(priv, ENETC_PSICFGR(0), val);
+ /* set Rx max frame size */
+ enetc_write_port(priv, ENETC_PM_MAXFRM, ENETC_RX_MAXFRM_SIZE);
+ /* enable MAC port */
+ enetc_write_port(priv, ENETC_PM_CC, ENETC_PM_CC_RX_TX_EN);
+ /* enable port */
+ enetc_write_port(priv, ENETC_PMR, ENETC_PMR_SI0_EN);
+ /* set SI cache policy */
+ enetc_write(priv, ENETC_SICAR0,
+ ENETC_SICAR_RD_CFG | ENETC_SICAR_WR_CFG);
+ /* enable SI */
+ enetc_write(priv, ENETC_SIMR, ENETC_SIMR_EN);
+}
+
+/* returns DMA address for a given buffer index */
+static inline u64 enetc_rxb_address(struct udevice *dev, int i)
+{
+ return cpu_to_le64(dm_pci_virt_to_mem(dev, net_rx_packets[i]));
+}
+
+/*
+ * Setup a single Tx BD Ring (ID = 0):
+ * - set Tx buffer descriptor address
+ * - set the BD count
+ * - initialize the producer and consumer index
+ */
+static void enetc_setup_tx_bdr(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *tx_bdr = &priv->tx_bdr;
+ u64 tx_bd_add = (u64)priv->enetc_txbd;
+
+ /* used later to advance to the next Tx BD */
+ tx_bdr->bd_count = ENETC_BD_CNT;
+ tx_bdr->next_prod_idx = 0;
+ tx_bdr->next_cons_idx = 0;
+ tx_bdr->cons_idx = priv->regs_base +
+ ENETC_BDR(TX, ENETC_TX_BDR_ID, ENETC_TBCIR);
+ tx_bdr->prod_idx = priv->regs_base +
+ ENETC_BDR(TX, ENETC_TX_BDR_ID, ENETC_TBPIR);
+
+ /* set Tx BD address */
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBBAR0,
+ lower_32_bits(tx_bd_add));
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBBAR1,
+ upper_32_bits(tx_bd_add));
+ /* set Tx 8 BD count */
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBLENR,
+ tx_bdr->bd_count);
+
+ /* reset both producer/consumer indexes */
+ enetc_write_reg(tx_bdr->cons_idx, tx_bdr->next_cons_idx);
+ enetc_write_reg(tx_bdr->prod_idx, tx_bdr->next_prod_idx);
+
+ /* enable TX ring */
+ enetc_bdr_write(priv, TX, ENETC_TX_BDR_ID, ENETC_TBMR, ENETC_TBMR_EN);
+}
+
+/*
+ * Setup a single Rx BD Ring (ID = 0):
+ * - set Rx buffer descriptors address (one descriptor per buffer)
+ * - set buffer size as max frame size
+ * - enable Rx ring
+ * - reset consumer and producer indexes
+ * - set buffer for each descriptor
+ */
+static void enetc_setup_rx_bdr(struct udevice *dev)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *rx_bdr = &priv->rx_bdr;
+ u64 rx_bd_add = (u64)priv->enetc_rxbd;
+ int i;
+
+ /* used later to advance to the next BD produced by ENETC HW */
+ rx_bdr->bd_count = ENETC_BD_CNT;
+ rx_bdr->next_prod_idx = 0;
+ rx_bdr->next_cons_idx = 0;
+ rx_bdr->cons_idx = priv->regs_base +
+ ENETC_BDR(RX, ENETC_RX_BDR_ID, ENETC_RBCIR);
+ rx_bdr->prod_idx = priv->regs_base +
+ ENETC_BDR(RX, ENETC_RX_BDR_ID, ENETC_RBPIR);
+
+ /* set Rx BD address */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBBAR0,
+ lower_32_bits(rx_bd_add));
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBBAR1,
+ upper_32_bits(rx_bd_add));
+ /* set Rx BD count (multiple of 8) */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBLENR,
+ rx_bdr->bd_count);
+ /* set Rx buffer size */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBBSR, PKTSIZE_ALIGN);
+
+ /* fill Rx BD */
+ memset(priv->enetc_rxbd, 0,
+ rx_bdr->bd_count * sizeof(union enetc_rx_bd));
+ for (i = 0; i < rx_bdr->bd_count; i++) {
+ priv->enetc_rxbd[i].w.addr = enetc_rxb_address(dev, i);
+ /* each RX buffer must be aligned to 64B */
+ WARN_ON(priv->enetc_rxbd[i].w.addr & (ARCH_DMA_MINALIGN - 1));
+ }
+
+ /* reset producer (ENETC owned) and consumer (SW owned) index */
+ enetc_write_reg(rx_bdr->cons_idx, rx_bdr->next_cons_idx);
+ enetc_write_reg(rx_bdr->prod_idx, rx_bdr->next_prod_idx);
+
+ /* enable Rx ring */
+ enetc_bdr_write(priv, RX, ENETC_RX_BDR_ID, ENETC_RBMR, ENETC_RBMR_EN);
+}
+
+/*
+ * Start ENETC interface:
+ * - perform FLR
+ * - enable access to port and SI registers
+ * - set mac address
+ * - setup TX/RX buffer descriptors
+ * - enable Tx/Rx rings
+ */
+static int enetc_start(struct udevice *dev)
+{
+ struct eth_pdata *plat = dev_get_platdata(dev);
+ struct enetc_priv *priv = dev_get_priv(dev);
+
+ /* reset and enable the PCI device */
+ dm_pci_flr(dev);
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ if (!is_valid_ethaddr(plat->enetaddr)) {
+ enetc_dbg(dev, "invalid MAC address, generate random ...\n");
+ net_random_ethaddr(plat->enetaddr);
+ }
+ enetc_set_primary_mac_addr(priv, plat->enetaddr);
+
+ enetc_enable_si_port(priv);
+
+ /* setup Tx/Rx buffer descriptors */
+ enetc_setup_tx_bdr(dev);
+ enetc_setup_rx_bdr(dev);
+
+ enetc_start_pcs(dev);
+ enetc_start_phy(dev);
+
+ return 0;
+}
+
+/*
+ * Stop the network interface:
+ * - just quiesce it, we can wipe all configuration as _start starts from
+ * scratch each time
+ */
+static void enetc_stop(struct udevice *dev)
+{
+ /* FLR is sufficient to quiesce the device */
+ dm_pci_flr(dev);
+}
+
+/*
+ * ENETC transmit packet:
+ * - check if Tx BD ring is full
+ * - set buffer/packet address (dma address)
+ * - set final fragment flag
+ * - try while producer index equals consumer index or timeout
+ */
+static int enetc_send(struct udevice *dev, void *packet, int length)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *txr = &priv->tx_bdr;
+ void *nv_packet = (void *)packet;
+ int tries = ENETC_POLL_TRIES;
+ u32 pi, ci;
+
+ pi = txr->next_prod_idx;
+ ci = enetc_read_reg(txr->cons_idx) & ENETC_BDR_IDX_MASK;
+ /* Tx ring is full when */
+ if (((pi + 1) % txr->bd_count) == ci) {
+ enetc_dbg(dev, "Tx BDR full\n");
+ return -ETIMEDOUT;
+ }
+ enetc_dbg(dev, "TxBD[%d]send: pkt_len=%d, buff @0x%x%08x\n", pi, length,
+ upper_32_bits((u64)nv_packet), lower_32_bits((u64)nv_packet));
+
+ /* prepare Tx BD */
+ memset(&priv->enetc_txbd[pi], 0x0, sizeof(struct enetc_tx_bd));
+ priv->enetc_txbd[pi].addr =
+ cpu_to_le64(dm_pci_virt_to_mem(dev, nv_packet));
+ priv->enetc_txbd[pi].buf_len = cpu_to_le16(length);
+ priv->enetc_txbd[pi].frm_len = cpu_to_le16(length);
+ priv->enetc_txbd[pi].flags = cpu_to_le16(ENETC_TXBD_FLAGS_F);
+ dmb();
+ /* send frame: increment producer index */
+ pi = (pi + 1) % txr->bd_count;
+ txr->next_prod_idx = pi;
+ enetc_write_reg(txr->prod_idx, pi);
+ while ((--tries >= 0) &&
+ (pi != (enetc_read_reg(txr->cons_idx) & ENETC_BDR_IDX_MASK)))
+ udelay(10);
+
+ return tries > 0 ? 0 : -ETIMEDOUT;
+}
+
+/*
+ * 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 enetc_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct enetc_priv *priv = dev_get_priv(dev);
+ struct bd_ring *rxr = &priv->rx_bdr;
+ int tries = ENETC_POLL_TRIES;
+ int pi = rxr->next_prod_idx;
+ int ci = rxr->next_cons_idx;
+ u32 status;
+ int len;
+ u8 rdy;
+
+ do {
+ dmb();
+ status = le32_to_cpu(priv->enetc_rxbd[pi].r.lstatus);
+ /* check if current BD is ready to be consumed */
+ rdy = ENETC_RXBD_STATUS_R(status);
+ } while (--tries >= 0 && !rdy);
+
+ if (!rdy)
+ return -EAGAIN;
+
+ dmb();
+ len = le16_to_cpu(priv->enetc_rxbd[pi].r.buf_len);
+ *packetp = (uchar *)enetc_rxb_address(dev, pi);
+ enetc_dbg(dev, "RxBD[%d]: len=%d err=%d pkt=0x%x%08x\n", pi, len,
+ ENETC_RXBD_STATUS_ERRORS(status),
+ upper_32_bits((u64)*packetp), lower_32_bits((u64)*packetp));
+
+ /* BD clean up and advance to next in ring */
+ memset(&priv->enetc_rxbd[pi], 0, sizeof(union enetc_rx_bd));
+ priv->enetc_rxbd[pi].w.addr = enetc_rxb_address(dev, pi);
+ rxr->next_prod_idx = (pi + 1) % rxr->bd_count;
+ ci = (ci + 1) % rxr->bd_count;
+ rxr->next_cons_idx = ci;
+ dmb();
+ /* free up the slot in the ring for HW */
+ enetc_write_reg(rxr->cons_idx, ci);
+
+ return len;
+}
+
+static const struct eth_ops enetc_ops = {
+ .start = enetc_start,
+ .send = enetc_send,
+ .recv = enetc_recv,
+ .stop = enetc_stop,
+};
+
+U_BOOT_DRIVER(eth_enetc) = {
+ .name = "enetc_eth",
+ .id = UCLASS_ETH,
+ .bind = enetc_bind,
+ .probe = enetc_probe,
+ .remove = enetc_remove,
+ .ops = &enetc_ops,
+ .priv_auto_alloc_size = sizeof(struct enetc_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static struct pci_device_id enetc_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_ETH) },
+ {}
+};
+
+U_BOOT_PCI_DEVICE(eth_enetc, enetc_ids);
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
new file mode 100644
index 00000000000..0bb4cdff479
--- /dev/null
+++ b/drivers/net/fsl_enetc.h
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * ENETC ethernet controller driver
+ * Copyright 2017-2019 NXP
+ */
+
+#ifndef _ENETC_H
+#define _ENETC_H
+
+#define enetc_dbg(dev, fmt, args...) debug("%s:" fmt, dev->name, ##args)
+
+/* PCI function IDs */
+#define PCI_DEVICE_ID_ENETC_ETH 0xE100
+#define PCI_DEVICE_ID_ENETC_MDIO 0xEE01
+
+/* ENETC Ethernet controller registers */
+/* Station interface register offsets */
+#define ENETC_SIMR 0x000
+#define ENETC_SIMR_EN BIT(31)
+#define ENETC_SICAR0 0x040
+/* write cache cfg: snoop, no allocate, data & BD coherent */
+#define ENETC_SICAR_WR_CFG 0x6767
+/* read cache cfg: coherent copy, look up, don't alloc in cache */
+#define ENETC_SICAR_RD_CFG 0x27270000
+#define ENETC_SIROCT 0x300
+#define ENETC_SIRFRM 0x308
+#define ENETC_SITOCT 0x320
+#define ENETC_SITFRM 0x328
+
+/* Rx/Tx Buffer Descriptor Ring registers */
+enum enetc_bdr_type {TX, RX};
+#define ENETC_BDR(type, n, off) (0x8000 + (type) * 0x100 + (n) * 0x200 + (off))
+#define ENETC_BDR_IDX_MASK 0xffff
+
+/* Rx BDR reg offsets */
+#define ENETC_RBMR 0x00
+#define ENETC_RBMR_EN BIT(31)
+#define ENETC_RBBSR 0x08
+/* initial consumer index for Rx BDR */
+#define ENETC_RBCIR 0x0c
+#define ENETC_RBBAR0 0x10
+#define ENETC_RBBAR1 0x14
+#define ENETC_RBPIR 0x18
+#define ENETC_RBLENR 0x20
+
+/* Tx BDR reg offsets */
+#define ENETC_TBMR 0x00
+#define ENETC_TBMR_EN BIT(31)
+#define ENETC_TBBAR0 0x10
+#define ENETC_TBBAR1 0x14
+#define ENETC_TBPIR 0x18
+#define ENETC_TBCIR 0x1c
+#define ENETC_TBLENR 0x20
+
+/* Port registers offset */
+#define ENETC_PORT_REGS_OFF 0x10000
+
+/* Port registers */
+#define ENETC_PMR 0x0000
+#define ENETC_PMR_SI0_EN BIT(16)
+#define ENETC_PSIPMMR 0x0018
+#define ENETC_PSIPMAR0 0x0100
+#define ENETC_PSIPMAR1 0x0104
+#define ENETC_PCAPR0 0x0900
+#define ENETC_PCAPRO_MDIO BIT(11)
+#define ENETC_PSICFGR(n) (0x0940 + (n) * 0x10)
+#define ENETC_PSICFGR_SET_TXBDR(val) ((val) & 0xff)
+#define ENETC_PSICFGR_SET_RXBDR(val) (((val) & 0xff) << 16)
+/* MAC configuration */
+#define ENETC_PM_CC 0x8008
+#define ENETC_PM_CC_DEFAULT 0x0810
+#define ENETC_PM_CC_RX_TX_EN 0x8813
+#define ENETC_PM_MAXFRM 0x8014
+#define ENETC_RX_MAXFRM_SIZE PKTSIZE_ALIGN
+#define ENETC_PM_IMDIO_BASE 0x8030
+#define ENETC_PM_IF_MODE 0x8300
+#define ENETC_PM_IF_MODE_RG BIT(2)
+#define ENETC_PM_IF_MODE_AN_ENA BIT(15)
+#define ENETC_PM_IF_IFMODE_MASK GENMASK(1, 0)
+
+/* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */
+#define ENETC_BD_CNT CONFIG_SYS_RX_ETH_BUFFER
+#define ENETC_BD_ALIGN 128
+
+/* single pair of Rx/Tx rings */
+#define ENETC_RX_BDR_CNT 1
+#define ENETC_TX_BDR_CNT 1
+#define ENETC_RX_BDR_ID 0
+#define ENETC_TX_BDR_ID 0
+
+/* Tx buffer descriptor */
+struct enetc_tx_bd {
+ __le64 addr;
+ __le16 buf_len;
+ __le16 frm_len;
+ __le16 err_csum;
+ __le16 flags;
+};
+
+#define ENETC_TXBD_FLAGS_F BIT(15)
+#define ENETC_POLL_TRIES 32000
+
+/* Rx buffer descriptor */
+union enetc_rx_bd {
+ /* SW provided BD format */
+ struct {
+ __le64 addr;
+ u8 reserved[8];
+ } w;
+
+ /* ENETC returned BD format */
+ struct {
+ __le16 inet_csum;
+ __le16 parse_summary;
+ __le32 rss_hash;
+ __le16 buf_len;
+ __le16 vlan_opt;
+ union {
+ struct {
+ __le16 flags;
+ __le16 error;
+ };
+ __le32 lstatus;
+ };
+ } r;
+};
+
+#define ENETC_RXBD_STATUS_R(status) (((status) >> 30) & 0x1)
+#define ENETC_RXBD_STATUS_F(status) (((status) >> 31) & 0x1)
+#define ENETC_RXBD_STATUS_ERRORS(status) (((status) >> 16) & 0xff)
+#define ENETC_RXBD_STATUS(flags) ((flags) << 16)
+
+/* Tx/Rx ring info */
+struct bd_ring {
+ void *cons_idx;
+ void *prod_idx;
+ /* next BD index to use */
+ int next_prod_idx;
+ int next_cons_idx;
+ int bd_count;
+};
+
+/* ENETC private structure */
+struct enetc_priv {
+ struct enetc_tx_bd *enetc_txbd;
+ union enetc_rx_bd *enetc_rxbd;
+
+ void *regs_base; /* base ENETC registers */
+ void *port_regs; /* base ENETC port registers */
+
+ /* Rx/Tx buffer descriptor rings info */
+ struct bd_ring tx_bdr;
+ struct bd_ring rx_bdr;
+
+ int if_type;
+ struct mii_dev imdio;
+};
+
+/* register accessors */
+#define enetc_read_reg(x) readl((x))
+#define enetc_write_reg(x, val) writel((val), (x))
+#define enetc_read(priv, off) enetc_read_reg((priv)->regs_base + (off))
+#define enetc_write(priv, off, v) \
+ enetc_write_reg((priv)->regs_base + (off), v)
+
+/* port register accessors */
+#define enetc_port_regs(priv, off) ((priv)->port_regs + (off))
+#define enetc_read_port(priv, off) \
+ enetc_read_reg(enetc_port_regs((priv), (off)))
+#define enetc_write_port(priv, off, v) \
+ enetc_write_reg(enetc_port_regs((priv), (off)), v)
+
+/* BDR register accessors, see ENETC_BDR() */
+#define enetc_bdr_read(priv, t, n, off) \
+ enetc_read(priv, ENETC_BDR(t, n, off))
+#define enetc_bdr_write(priv, t, n, off, val) \
+ enetc_write(priv, ENETC_BDR(t, n, off), val)
+
+/* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */
+#define ENETC_PCS_PHY_ADDR 0
+
+/* PCS registers */
+#define ENETC_PCS_CR 0x00
+#define ENETC_PCS_CR_RESET_AN 0x1200
+#define ENETC_PCS_CR_DEF_VAL 0x0140
+#define ENETC_PCS_CR_RST BIT(15)
+#define ENETC_PCS_DEV_ABILITY 0x04
+#define ENETC_PCS_DEV_ABILITY_SGMII 0x4001
+#define ENETC_PCS_DEV_ABILITY_SXGMII 0x5001
+#define ENETC_PCS_LINK_TIMER1 0x12
+#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0
+#define ENETC_PCS_LINK_TIMER2 0x13
+#define ENETC_PCS_LINK_TIMER2_VAL 0x0003
+#define ENETC_PCS_IF_MODE 0x14
+#define ENETC_PCS_IF_MODE_SGMII BIT(0)
+#define ENETC_PCS_IF_MODE_SGMII_AN BIT(1)
+#define ENETC_PCS_IF_MODE_SPEED_1G BIT(3)
+
+/* PCS replicator block for USXGMII */
+#define ENETC_PCS_DEVAD_REPL 0x1f
+
+/* ENETC external MDIO registers */
+#define ENETC_MDIO_BASE 0x1c00
+#define ENETC_MDIO_CFG 0x00
+#define ENETC_EMDIO_CFG_C22 0x00809508
+#define ENETC_EMDIO_CFG_C45 0x00809548
+#define ENETC_EMDIO_CFG_RD_ER BIT(1)
+#define ENETC_EMDIO_CFG_BSY BIT(0)
+#define ENETC_MDIO_CTL 0x04
+#define ENETC_MDIO_CTL_READ BIT(15)
+#define ENETC_MDIO_DATA 0x08
+#define ENETC_MDIO_STAT 0x0c
+
+#define ENETC_MDIO_READ_ERR 0xffff
+
+struct enetc_mdio_priv {
+ void *regs_base;
+};
+
+/*
+ * these functions are implemented by ENETC_MDIO and are re-used by ENETC driver
+ * to drive serdes / internal SoC PHYs
+ */
+int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg);
+int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg, u16 val);
+
+#endif /* _ENETC_H */
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
new file mode 100644
index 00000000000..60d21537b80
--- /dev/null
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ENETC ethernet controller driver
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <miiphy.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <miiphy.h>
+
+#include "fsl_enetc.h"
+
+static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
+{
+ while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY)
+ cpu_relax();
+}
+
+int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg)
+{
+ if (devad == MDIO_DEVAD_NONE)
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
+ else
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
+ enetc_mdio_wait_bsy(priv);
+
+ if (devad == MDIO_DEVAD_NONE) {
+ enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
+ (addr << 5) | reg);
+ } else {
+ enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
+ enetc_mdio_wait_bsy(priv);
+
+ enetc_write(priv, ENETC_MDIO_STAT, reg);
+ enetc_mdio_wait_bsy(priv);
+
+ enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
+ (addr << 5) | devad);
+ }
+
+ enetc_mdio_wait_bsy(priv);
+ if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
+ return ENETC_MDIO_READ_ERR;
+
+ return enetc_read(priv, ENETC_MDIO_DATA);
+}
+
+int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
+ int reg, u16 val)
+{
+ if (devad == MDIO_DEVAD_NONE)
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
+ else
+ enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
+ enetc_mdio_wait_bsy(priv);
+
+ if (devad != MDIO_DEVAD_NONE) {
+ enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
+ enetc_write(priv, ENETC_MDIO_STAT, reg);
+ } else {
+ enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
+ }
+ enetc_mdio_wait_bsy(priv);
+
+ enetc_write(priv, ENETC_MDIO_DATA, val);
+ enetc_mdio_wait_bsy(priv);
+
+ return 0;
+}
+
+/* DM wrappers */
+static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+ struct enetc_mdio_priv *priv = dev_get_priv(dev);
+
+ return enetc_mdio_read_priv(priv, addr, devad, reg);
+}
+
+static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
+ int reg, u16 val)
+{
+ struct enetc_mdio_priv *priv = dev_get_priv(dev);
+
+ return enetc_mdio_write_priv(priv, addr, devad, reg, val);
+}
+
+static const struct mdio_ops enetc_mdio_ops = {
+ .read = dm_enetc_mdio_read,
+ .write = dm_enetc_mdio_write,
+};
+
+static int enetc_mdio_bind(struct udevice *dev)
+{
+ char name[16];
+ static int eth_num_devices;
+
+ /*
+ * prefer using PCI function numbers to number interfaces, but these
+ * are only available if dts nodes are present. For PCI they are
+ * optional, handle that case too. Just in case some nodes are present
+ * and some are not, use different naming scheme - enetc-N based on
+ * PCI function # and enetc#N based on interface count
+ */
+ if (ofnode_valid(dev->node))
+ sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
+ else
+ sprintf(name, "emdio#%u", eth_num_devices++);
+ device_set_name(dev, name);
+
+ return 0;
+}
+
+static int enetc_mdio_probe(struct udevice *dev)
+{
+ struct enetc_mdio_priv *priv = dev_get_priv(dev);
+
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ if (!priv->regs_base) {
+ enetc_dbg(dev, "failed to map BAR0\n");
+ return -EINVAL;
+ }
+
+ priv->regs_base += ENETC_MDIO_BASE;
+
+ dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(enetc_mdio) = {
+ .name = "enetc_mdio",
+ .id = UCLASS_MDIO,
+ .bind = enetc_mdio_bind,
+ .probe = enetc_mdio_probe,
+ .ops = &enetc_mdio_ops,
+ .priv_auto_alloc_size = sizeof(struct enetc_mdio_priv),
+};
+
+static struct pci_device_id enetc_mdio_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
+};
+
+U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index a7eddd647d0..c99cf663a41 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -45,9 +45,17 @@
DECLARE_GLOBAL_DATA_PTR;
-#define MACB_RX_BUFFER_SIZE 4096
-#define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128)
+/*
+ * These buffer sizes must be power of 2 and divisible
+ * by RX_BUFFER_MULTIPLE
+ */
+#define MACB_RX_BUFFER_SIZE 128
+#define GEM_RX_BUFFER_SIZE 2048
+#define RX_BUFFER_MULTIPLE 64
+
+#define MACB_RX_RING_SIZE 32
#define MACB_TX_RING_SIZE 16
+
#define MACB_TX_TIMEOUT 1000
#define MACB_AUTONEG_TIMEOUT 5000000
@@ -77,31 +85,16 @@ struct macb_dma_desc {
#define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE))
#define MACB_TX_DUMMY_DMA_DESC_SIZE (DMA_DESC_BYTES(1))
-#define RXADDR_USED 0x00000001
-#define RXADDR_WRAP 0x00000002
-
#define RXBUF_FRMLEN_MASK 0x00000fff
-#define RXBUF_FRAME_START 0x00004000
-#define RXBUF_FRAME_END 0x00008000
-#define RXBUF_TYPEID_MATCH 0x00400000
-#define RXBUF_ADDR4_MATCH 0x00800000
-#define RXBUF_ADDR3_MATCH 0x01000000
-#define RXBUF_ADDR2_MATCH 0x02000000
-#define RXBUF_ADDR1_MATCH 0x04000000
-#define RXBUF_BROADCAST 0x80000000
-
#define TXBUF_FRMLEN_MASK 0x000007ff
-#define TXBUF_FRAME_END 0x00008000
-#define TXBUF_NOCRC 0x00010000
-#define TXBUF_EXHAUSTED 0x08000000
-#define TXBUF_UNDERRUN 0x10000000
-#define TXBUF_MAXRETRY 0x20000000
-#define TXBUF_WRAP 0x40000000
-#define TXBUF_USED 0x80000000
struct macb_device {
void *regs;
+ bool is_big_endian;
+
+ const struct macb_config *config;
+
unsigned int rx_tail;
unsigned int tx_head;
unsigned int tx_tail;
@@ -112,6 +105,7 @@ struct macb_device {
void *tx_buffer;
struct macb_dma_desc *rx_ring;
struct macb_dma_desc *tx_ring;
+ size_t rx_buffer_size;
unsigned long rx_buffer_dma;
unsigned long rx_ring_dma;
@@ -137,6 +131,13 @@ struct macb_device {
phy_interface_t phy_interface;
#endif
};
+
+struct macb_config {
+ unsigned int dma_burst_length;
+
+ int (*clk_init)(struct udevice *dev, ulong rate);
+};
+
#ifndef CONFIG_DM_ETH
#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
#endif
@@ -316,9 +317,9 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet,
paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
ctrl = length & TXBUF_FRMLEN_MASK;
- ctrl |= TXBUF_FRAME_END;
+ ctrl |= MACB_BIT(TX_LAST);
if (tx_head == (MACB_TX_RING_SIZE - 1)) {
- ctrl |= TXBUF_WRAP;
+ ctrl |= MACB_BIT(TX_WRAP);
macb->tx_head = 0;
} else {
macb->tx_head++;
@@ -340,7 +341,7 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet,
barrier();
macb_invalidate_ring_desc(macb, TX);
ctrl = macb->tx_ring[tx_head].ctrl;
- if (ctrl & TXBUF_USED)
+ if (ctrl & MACB_BIT(TX_USED))
break;
udelay(1);
}
@@ -348,9 +349,9 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet,
dma_unmap_single(packet, length, paddr);
if (i <= MACB_TX_TIMEOUT) {
- if (ctrl & TXBUF_UNDERRUN)
+ if (ctrl & MACB_BIT(TX_UNDERRUN))
printf("%s: TX underrun\n", name);
- if (ctrl & TXBUF_EXHAUSTED)
+ if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
printf("%s: TX buffers exhausted in mid frame\n", name);
} else {
printf("%s: TX timeout\n", name);
@@ -369,14 +370,14 @@ static void reclaim_rx_buffers(struct macb_device *macb,
macb_invalidate_ring_desc(macb, RX);
while (i > new_tail) {
- macb->rx_ring[i].addr &= ~RXADDR_USED;
+ macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
i++;
if (i > MACB_RX_RING_SIZE)
i = 0;
}
while (i < new_tail) {
- macb->rx_ring[i].addr &= ~RXADDR_USED;
+ macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
i++;
}
@@ -396,26 +397,27 @@ static int _macb_recv(struct macb_device *macb, uchar **packetp)
for (;;) {
macb_invalidate_ring_desc(macb, RX);
- if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED))
+ if (!(macb->rx_ring[next_rx_tail].addr & MACB_BIT(RX_USED)))
return -EAGAIN;
status = macb->rx_ring[next_rx_tail].ctrl;
- if (status & RXBUF_FRAME_START) {
+ if (status & MACB_BIT(RX_SOF)) {
if (next_rx_tail != macb->rx_tail)
reclaim_rx_buffers(macb, next_rx_tail);
macb->wrapped = false;
}
- if (status & RXBUF_FRAME_END) {
- buffer = macb->rx_buffer + 128 * macb->rx_tail;
+ if (status & MACB_BIT(RX_EOF)) {
+ buffer = macb->rx_buffer +
+ macb->rx_buffer_size * macb->rx_tail;
length = status & RXBUF_FRMLEN_MASK;
macb_invalidate_rx_buffer(macb);
if (macb->wrapped) {
unsigned int headlen, taillen;
- headlen = 128 * (MACB_RX_RING_SIZE
- - macb->rx_tail);
+ headlen = macb->rx_buffer_size *
+ (MACB_RX_RING_SIZE - macb->rx_tail);
taillen = length - headlen;
memcpy((void *)net_rx_packets[0],
buffer, headlen);
@@ -495,21 +497,38 @@ static int macb_phy_find(struct macb_device *macb, const char *name)
* when operation failed.
*/
#ifdef CONFIG_DM_ETH
+static int macb_sifive_clk_init(struct udevice *dev, ulong rate)
+{
+ fdt_addr_t addr;
+ void *gemgxl_regs;
+
+ addr = dev_read_addr_index(dev, 1);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ gemgxl_regs = (void __iomem *)addr;
+ if (!gemgxl_regs)
+ return -ENODEV;
+
+ /*
+ * SiFive GEMGXL TX clock operation mode:
+ *
+ * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
+ * and output clock on GMII output signal GTX_CLK
+ * 1 = MII mode. Use MII input signal TX_CLK in TX logic
+ */
+ writel(rate != 125000000, gemgxl_regs);
+ return 0;
+}
+
int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed)
{
#ifdef CONFIG_CLK
+ struct macb_device *macb = dev_get_priv(dev);
struct clk tx_clk;
ulong rate;
int ret;
- /*
- * "tx_clk" is an optional clock source for MACB.
- * Ignore if it does not exist in DT.
- */
- ret = clk_get_by_name(dev, "tx_clk", &tx_clk);
- if (ret)
- return 0;
-
switch (speed) {
case _10BASET:
rate = 2500000; /* 2.5 MHz */
@@ -525,6 +544,17 @@ int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed)
return 0;
}
+ if (macb->config->clk_init)
+ return macb->config->clk_init(dev, rate);
+
+ /*
+ * "tx_clk" is an optional clock source for MACB.
+ * Ignore if it does not exist in DT.
+ */
+ ret = clk_get_by_name(dev, "tx_clk", &tx_clk);
+ if (ret)
+ return 0;
+
if (tx_clk.dev) {
ret = clk_set_rate(&tx_clk, rate);
if (ret)
@@ -699,7 +729,7 @@ static int gmac_init_multi_queues(struct macb_device *macb)
if (queue_mask & (1 << i))
num_queues++;
- macb->dummy_desc->ctrl = TXBUF_USED;
+ macb->dummy_desc->ctrl = MACB_BIT(TX_USED);
macb->dummy_desc->addr = 0;
flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma +
ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN));
@@ -710,6 +740,31 @@ static int gmac_init_multi_queues(struct macb_device *macb)
return 0;
}
+static void gmac_configure_dma(struct macb_device *macb)
+{
+ u32 buffer_size;
+ u32 dmacfg;
+
+ buffer_size = macb->rx_buffer_size / RX_BUFFER_MULTIPLE;
+ dmacfg = gem_readl(macb, DMACFG) & ~GEM_BF(RXBS, -1L);
+ dmacfg |= GEM_BF(RXBS, buffer_size);
+
+ if (macb->config->dma_burst_length)
+ dmacfg = GEM_BFINS(FBLDO,
+ macb->config->dma_burst_length, dmacfg);
+
+ dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
+ dmacfg &= ~GEM_BIT(ENDIA_PKT);
+
+ if (macb->is_big_endian)
+ dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
+ else
+ dmacfg &= ~GEM_BIT(ENDIA_DESC);
+
+ dmacfg &= ~GEM_BIT(ADDR64);
+ gem_writel(macb, DMACFG, dmacfg);
+}
+
#ifdef CONFIG_DM_ETH
static int _macb_init(struct udevice *dev, const char *name)
#else
@@ -732,10 +787,10 @@ static int _macb_init(struct macb_device *macb, const char *name)
paddr = macb->rx_buffer_dma;
for (i = 0; i < MACB_RX_RING_SIZE; i++) {
if (i == (MACB_RX_RING_SIZE - 1))
- paddr |= RXADDR_WRAP;
+ paddr |= MACB_BIT(RX_WRAP);
macb->rx_ring[i].addr = paddr;
macb->rx_ring[i].ctrl = 0;
- paddr += 128;
+ paddr += macb->rx_buffer_size;
}
macb_flush_ring_desc(macb, RX);
macb_flush_rx_buffer(macb);
@@ -743,9 +798,10 @@ static int _macb_init(struct macb_device *macb, const char *name)
for (i = 0; i < MACB_TX_RING_SIZE; i++) {
macb->tx_ring[i].addr = 0;
if (i == (MACB_TX_RING_SIZE - 1))
- macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+ macb->tx_ring[i].ctrl = MACB_BIT(TX_USED) |
+ MACB_BIT(TX_WRAP);
else
- macb->tx_ring[i].ctrl = TXBUF_USED;
+ macb->tx_ring[i].ctrl = MACB_BIT(TX_USED);
}
macb_flush_ring_desc(macb, TX);
@@ -762,6 +818,8 @@ static int _macb_init(struct macb_device *macb, const char *name)
macb_writel(macb, TBQP, macb->tx_ring_dma);
if (macb_is_gem(macb)) {
+ /* Initialize DMA properties */
+ gmac_configure_dma(macb);
/* Check the multi queue and initialize the queue for tx */
gmac_init_multi_queues(macb);
@@ -774,14 +832,21 @@ static int _macb_init(struct macb_device *macb, const char *name)
#ifdef CONFIG_DM_ETH
if ((macb->phy_interface == PHY_INTERFACE_MODE_RMII) ||
(macb->phy_interface == PHY_INTERFACE_MODE_RGMII))
- gem_writel(macb, UR, GEM_BIT(RGMII));
+ gem_writel(macb, USRIO, GEM_BIT(RGMII));
else
- gem_writel(macb, UR, 0);
+ gem_writel(macb, USRIO, 0);
+
+ if (macb->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+ unsigned int ncfgr = macb_readl(macb, NCFGR);
+
+ ncfgr |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
+ macb_writel(macb, NCFGR, ncfgr);
+ }
#else
#if defined(CONFIG_RGMII) || defined(CONFIG_RMII)
- gem_writel(macb, UR, GEM_BIT(RGMII));
+ gem_writel(macb, USRIO, GEM_BIT(RGMII));
#else
- gem_writel(macb, UR, 0);
+ gem_writel(macb, USRIO, 0);
#endif
#endif
} else {
@@ -903,8 +968,12 @@ static u32 gem_mdc_clk_div(int id, struct macb_device *macb)
config = GEM_BF(CLK, GEM_CLK_DIV48);
else if (macb_hz < 160000000)
config = GEM_BF(CLK, GEM_CLK_DIV64);
- else
+ else if (macb_hz < 240000000)
config = GEM_BF(CLK, GEM_CLK_DIV96);
+ else if (macb_hz < 320000000)
+ config = GEM_BF(CLK, GEM_CLK_DIV128);
+ else
+ config = GEM_BF(CLK, GEM_CLK_DIV224);
return config;
}
@@ -932,8 +1001,14 @@ static void _macb_eth_initialize(struct macb_device *macb)
int id = 0; /* This is not used by functions we call */
u32 ncfgr;
+ if (macb_is_gem(macb))
+ macb->rx_buffer_size = GEM_RX_BUFFER_SIZE;
+ else
+ macb->rx_buffer_size = MACB_RX_BUFFER_SIZE;
+
/* TODO: we need check the rx/tx_ring_dma is dcache line aligned */
- macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE,
+ macb->rx_buffer = dma_alloc_coherent(macb->rx_buffer_size *
+ MACB_RX_RING_SIZE,
&macb->rx_buffer_dma);
macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE,
&macb->rx_ring_dma);
@@ -1142,12 +1217,17 @@ static int macb_enable_clk(struct udevice *dev)
}
#endif
+static const struct macb_config default_gem_config = {
+ .dma_burst_length = 16,
+ .clk_init = NULL,
+};
+
static int macb_eth_probe(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct macb_device *macb = dev_get_priv(dev);
const char *phy_mode;
- __maybe_unused int ret;
+ int ret;
phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
NULL);
@@ -1160,6 +1240,12 @@ static int macb_eth_probe(struct udevice *dev)
macb->regs = (void *)pdata->iobase;
+ macb->is_big_endian = (cpu_to_be32(0x12345678) == 0x12345678);
+
+ macb->config = (struct macb_config *)dev_get_driver_data(dev);
+ if (!macb->config)
+ macb->config = &default_gem_config;
+
#ifdef CONFIG_CLK
ret = macb_enable_clk(dev);
if (ret)
@@ -1220,13 +1306,25 @@ static int macb_eth_ofdata_to_platdata(struct udevice *dev)
return macb_late_eth_ofdata_to_platdata(dev);
}
+static const struct macb_config sama5d4_config = {
+ .dma_burst_length = 4,
+ .clk_init = NULL,
+};
+
+static const struct macb_config sifive_config = {
+ .dma_burst_length = 16,
+ .clk_init = macb_sifive_clk_init,
+};
+
static const struct udevice_id macb_eth_ids[] = {
{ .compatible = "cdns,macb" },
{ .compatible = "cdns,at91sam9260-macb" },
{ .compatible = "atmel,sama5d2-gem" },
{ .compatible = "atmel,sama5d3-gem" },
- { .compatible = "atmel,sama5d4-gem" },
+ { .compatible = "atmel,sama5d4-gem", .data = (ulong)&sama5d4_config },
{ .compatible = "cdns,zynq-gem" },
+ { .compatible = "sifive,fu540-c000-gem",
+ .data = (ulong)&sifive_config },
{ }
};
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 3cc27f8560a..9b16383eba4 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -5,221 +5,410 @@
#ifndef __DRIVERS_MACB_H__
#define __DRIVERS_MACB_H__
+#define MACB_GREGS_NBR 16
+#define MACB_GREGS_VERSION 2
+#define MACB_MAX_QUEUES 8
+
/* MACB register offsets */
-#define MACB_NCR 0x0000
-#define MACB_NCFGR 0x0004
-#define MACB_NSR 0x0008
-#define GEM_UR 0x000c
-#define MACB_DMACFG 0x0010
-#define MACB_TSR 0x0014
-#define MACB_RBQP 0x0018
-#define MACB_TBQP 0x001c
-#define MACB_RSR 0x0020
-#define MACB_ISR 0x0024
-#define MACB_IER 0x0028
-#define MACB_IDR 0x002c
-#define MACB_IMR 0x0030
-#define MACB_MAN 0x0034
-#define MACB_PTR 0x0038
-#define MACB_PFR 0x003c
-#define MACB_FTO 0x0040
-#define MACB_SCF 0x0044
-#define MACB_MCF 0x0048
-#define MACB_FRO 0x004c
-#define MACB_FCSE 0x0050
-#define MACB_ALE 0x0054
-#define MACB_DTF 0x0058
-#define MACB_LCOL 0x005c
-#define MACB_EXCOL 0x0060
-#define MACB_TUND 0x0064
-#define MACB_CSE 0x0068
-#define MACB_RRE 0x006c
-#define MACB_ROVR 0x0070
-#define MACB_RSE 0x0074
-#define MACB_ELE 0x0078
-#define MACB_RJA 0x007c
-#define MACB_USF 0x0080
-#define MACB_STE 0x0084
-#define MACB_RLE 0x0088
-#define MACB_TPF 0x008c
-#define MACB_HRB 0x0090
-#define MACB_HRT 0x0094
-#define MACB_SA1B 0x0098
-#define MACB_SA1T 0x009c
-#define MACB_SA2B 0x00a0
-#define MACB_SA2T 0x00a4
-#define MACB_SA3B 0x00a8
-#define MACB_SA3T 0x00ac
-#define MACB_SA4B 0x00b0
-#define MACB_SA4T 0x00b4
-#define MACB_TID 0x00b8
-#define MACB_TPQ 0x00bc
-#define MACB_USRIO 0x00c0
-#define MACB_WOL 0x00c4
-#define MACB_MID 0x00fc
-
-/* GEM specific register offsets */
-#define GEM_DCFG1 0x0280
-#define GEM_DCFG6 0x0294
-
-#define MACB_MAX_QUEUES 8
-
-/* GEM specific multi queues register offset */
-/* hw_q can be 0~7 */
-#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
+#define MACB_NCR 0x0000 /* Network Control */
+#define MACB_NCFGR 0x0004 /* Network Config */
+#define MACB_NSR 0x0008 /* Network Status */
+#define MACB_TAR 0x000c /* AT91RM9200 only */
+#define MACB_TCR 0x0010 /* AT91RM9200 only */
+#define MACB_TSR 0x0014 /* Transmit Status */
+#define MACB_RBQP 0x0018 /* RX Q Base Address */
+#define MACB_TBQP 0x001c /* TX Q Base Address */
+#define MACB_RSR 0x0020 /* Receive Status */
+#define MACB_ISR 0x0024 /* Interrupt Status */
+#define MACB_IER 0x0028 /* Interrupt Enable */
+#define MACB_IDR 0x002c /* Interrupt Disable */
+#define MACB_IMR 0x0030 /* Interrupt Mask */
+#define MACB_MAN 0x0034 /* PHY Maintenance */
+#define MACB_PTR 0x0038
+#define MACB_PFR 0x003c
+#define MACB_FTO 0x0040
+#define MACB_SCF 0x0044
+#define MACB_MCF 0x0048
+#define MACB_FRO 0x004c
+#define MACB_FCSE 0x0050
+#define MACB_ALE 0x0054
+#define MACB_DTF 0x0058
+#define MACB_LCOL 0x005c
+#define MACB_EXCOL 0x0060
+#define MACB_TUND 0x0064
+#define MACB_CSE 0x0068
+#define MACB_RRE 0x006c
+#define MACB_ROVR 0x0070
+#define MACB_RSE 0x0074
+#define MACB_ELE 0x0078
+#define MACB_RJA 0x007c
+#define MACB_USF 0x0080
+#define MACB_STE 0x0084
+#define MACB_RLE 0x0088
+#define MACB_TPF 0x008c
+#define MACB_HRB 0x0090
+#define MACB_HRT 0x0094
+#define MACB_SA1B 0x0098
+#define MACB_SA1T 0x009c
+#define MACB_SA2B 0x00a0
+#define MACB_SA2T 0x00a4
+#define MACB_SA3B 0x00a8
+#define MACB_SA3T 0x00ac
+#define MACB_SA4B 0x00b0
+#define MACB_SA4T 0x00b4
+#define MACB_TID 0x00b8
+#define MACB_TPQ 0x00bc
+#define MACB_USRIO 0x00c0
+#define MACB_WOL 0x00c4
+#define MACB_MID 0x00fc
+#define MACB_TBQPH 0x04C8
+#define MACB_RBQPH 0x04D4
+
+/* GEM register offsets. */
+#define GEM_NCFGR 0x0004 /* Network Config */
+#define GEM_USRIO 0x000c /* User IO */
+#define GEM_DMACFG 0x0010 /* DMA Configuration */
+#define GEM_JML 0x0048 /* Jumbo Max Length */
+#define GEM_HRB 0x0080 /* Hash Bottom */
+#define GEM_HRT 0x0084 /* Hash Top */
+#define GEM_SA1B 0x0088 /* Specific1 Bottom */
+#define GEM_SA1T 0x008C /* Specific1 Top */
+#define GEM_SA2B 0x0090 /* Specific2 Bottom */
+#define GEM_SA2T 0x0094 /* Specific2 Top */
+#define GEM_SA3B 0x0098 /* Specific3 Bottom */
+#define GEM_SA3T 0x009C /* Specific3 Top */
+#define GEM_SA4B 0x00A0 /* Specific4 Bottom */
+#define GEM_SA4T 0x00A4 /* Specific4 Top */
+#define GEM_EFTSH 0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */
+#define GEM_EFRSH 0x00ec /* PTP Event Frame Received Seconds Register 47:32 */
+#define GEM_PEFTSH 0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */
+#define GEM_PEFRSH 0x00f4 /* PTP Peer Event Frame Received Seconds Register 47:32 */
+#define GEM_OTX 0x0100 /* Octets transmitted */
+#define GEM_OCTTXL 0x0100 /* Octets transmitted [31:0] */
+#define GEM_OCTTXH 0x0104 /* Octets transmitted [47:32] */
+#define GEM_TXCNT 0x0108 /* Frames Transmitted counter */
+#define GEM_TXBCCNT 0x010c /* Broadcast Frames counter */
+#define GEM_TXMCCNT 0x0110 /* Multicast Frames counter */
+#define GEM_TXPAUSECNT 0x0114 /* Pause Frames Transmitted Counter */
+#define GEM_TX64CNT 0x0118 /* 64 byte Frames TX counter */
+#define GEM_TX65CNT 0x011c /* 65-127 byte Frames TX counter */
+#define GEM_TX128CNT 0x0120 /* 128-255 byte Frames TX counter */
+#define GEM_TX256CNT 0x0124 /* 256-511 byte Frames TX counter */
+#define GEM_TX512CNT 0x0128 /* 512-1023 byte Frames TX counter */
+#define GEM_TX1024CNT 0x012c /* 1024-1518 byte Frames TX counter */
+#define GEM_TX1519CNT 0x0130 /* 1519+ byte Frames TX counter */
+#define GEM_TXURUNCNT 0x0134 /* TX under run error counter */
+#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame Counter */
+#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision Frame Counter */
+#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision Frame Counter */
+#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame Counter */
+#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission Frame Counter */
+#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error Counter */
+#define GEM_ORX 0x0150 /* Octets received */
+#define GEM_OCTRXL 0x0150 /* Octets received [31:0] */
+#define GEM_OCTRXH 0x0154 /* Octets received [47:32] */
+#define GEM_RXCNT 0x0158 /* Frames Received Counter */
+#define GEM_RXBROADCNT 0x015c /* Broadcast Frames Received Counter */
+#define GEM_RXMULTICNT 0x0160 /* Multicast Frames Received Counter */
+#define GEM_RXPAUSECNT 0x0164 /* Pause Frames Received Counter */
+#define GEM_RX64CNT 0x0168 /* 64 byte Frames RX Counter */
+#define GEM_RX65CNT 0x016c /* 65-127 byte Frames RX Counter */
+#define GEM_RX128CNT 0x0170 /* 128-255 byte Frames RX Counter */
+#define GEM_RX256CNT 0x0174 /* 256-511 byte Frames RX Counter */
+#define GEM_RX512CNT 0x0178 /* 512-1023 byte Frames RX Counter */
+#define GEM_RX1024CNT 0x017c /* 1024-1518 byte Frames RX Counter */
+#define GEM_RX1519CNT 0x0180 /* 1519+ byte Frames RX Counter */
+#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames Received Counter */
+#define GEM_RXOVRCNT 0x0188 /* Oversize Frames Received Counter */
+#define GEM_RXJABCNT 0x018c /* Jabbers Received Counter */
+#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence Error Counter */
+#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error Counter */
+#define GEM_RXSYMBCNT 0x0198 /* Symbol Error Counter */
+#define GEM_RXALIGNCNT 0x019c /* Alignment Error Counter */
+#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error Counter */
+#define GEM_RXORCNT 0x01a4 /* Receive Overrun Counter */
+#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */
+#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */
+#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */
+#define GEM_TISUBN 0x01bc /* 1588 Timer Increment Sub-ns */
+#define GEM_TSH 0x01c0 /* 1588 Timer Seconds High */
+#define GEM_TSL 0x01d0 /* 1588 Timer Seconds Low */
+#define GEM_TN 0x01d4 /* 1588 Timer Nanoseconds */
+#define GEM_TA 0x01d8 /* 1588 Timer Adjust */
+#define GEM_TI 0x01dc /* 1588 Timer Increment */
+#define GEM_EFTSL 0x01e0 /* PTP Event Frame Tx Seconds Low */
+#define GEM_EFTN 0x01e4 /* PTP Event Frame Tx Nanoseconds */
+#define GEM_EFRSL 0x01e8 /* PTP Event Frame Rx Seconds Low */
+#define GEM_EFRN 0x01ec /* PTP Event Frame Rx Nanoseconds */
+#define GEM_PEFTSL 0x01f0 /* PTP Peer Event Frame Tx Secs Low */
+#define GEM_PEFTN 0x01f4 /* PTP Peer Event Frame Tx Ns */
+#define GEM_PEFRSL 0x01f8 /* PTP Peer Event Frame Rx Sec Low */
+#define GEM_PEFRN 0x01fc /* PTP Peer Event Frame Rx Ns */
+#define GEM_DCFG1 0x0280 /* Design Config 1 */
+#define GEM_DCFG2 0x0284 /* Design Config 2 */
+#define GEM_DCFG3 0x0288 /* Design Config 3 */
+#define GEM_DCFG4 0x028c /* Design Config 4 */
+#define GEM_DCFG5 0x0290 /* Design Config 5 */
+#define GEM_DCFG6 0x0294 /* Design Config 6 */
+#define GEM_DCFG7 0x0298 /* Design Config 7 */
+#define GEM_DCFG8 0x029C /* Design Config 8 */
+#define GEM_DCFG10 0x02A4 /* Design Config 10 */
+
+#define GEM_TXBDCTRL 0x04cc /* TX Buffer Descriptor control register */
+#define GEM_RXBDCTRL 0x04d0 /* RX Buffer Descriptor control register */
+
+/* Screener Type 2 match registers */
+#define GEM_SCRT2 0x540
+
+/* EtherType registers */
+#define GEM_ETHT 0x06E0
+
+/* Type 2 compare registers */
+#define GEM_T2CMPW0 0x0700
+#define GEM_T2CMPW1 0x0704
+#define T2CMP_OFST(t2idx) (t2idx * 2)
+
+/* type 2 compare registers
+ * each location requires 3 compare regs
+ */
+#define GEM_IP4SRC_CMP(idx) (idx * 3)
+#define GEM_IP4DST_CMP(idx) (idx * 3 + 1)
+#define GEM_PORT_CMP(idx) (idx * 3 + 2)
+
+/* Which screening type 2 EtherType register will be used (0 - 7) */
+#define SCRT2_ETHT 0
+
+#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2))
+#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
+#define GEM_TBQPH(hw_q) (0x04C8)
+#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2))
+#define GEM_RBQS(hw_q) (0x04A0 + ((hw_q) << 2))
+#define GEM_RBQPH(hw_q) (0x04D4)
+#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2))
+#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
+#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
/* Bitfields in NCR */
-#define MACB_LB_OFFSET 0
-#define MACB_LB_SIZE 1
-#define MACB_LLB_OFFSET 1
-#define MACB_LLB_SIZE 1
-#define MACB_RE_OFFSET 2
-#define MACB_RE_SIZE 1
-#define MACB_TE_OFFSET 3
-#define MACB_TE_SIZE 1
-#define MACB_MPE_OFFSET 4
-#define MACB_MPE_SIZE 1
-#define MACB_CLRSTAT_OFFSET 5
-#define MACB_CLRSTAT_SIZE 1
-#define MACB_INCSTAT_OFFSET 6
-#define MACB_INCSTAT_SIZE 1
-#define MACB_WESTAT_OFFSET 7
-#define MACB_WESTAT_SIZE 1
-#define MACB_BP_OFFSET 8
-#define MACB_BP_SIZE 1
-#define MACB_TSTART_OFFSET 9
-#define MACB_TSTART_SIZE 1
-#define MACB_THALT_OFFSET 10
-#define MACB_THALT_SIZE 1
-#define MACB_NCR_TPF_OFFSET 11
-#define MACB_NCR_TPF_SIZE 1
-#define MACB_TZQ_OFFSET 12
-#define MACB_TZQ_SIZE 1
+#define MACB_LB_OFFSET 0 /* reserved */
+#define MACB_LB_SIZE 1
+#define MACB_LLB_OFFSET 1 /* Loop back local */
+#define MACB_LLB_SIZE 1
+#define MACB_RE_OFFSET 2 /* Receive enable */
+#define MACB_RE_SIZE 1
+#define MACB_TE_OFFSET 3 /* Transmit enable */
+#define MACB_TE_SIZE 1
+#define MACB_MPE_OFFSET 4 /* Management port enable */
+#define MACB_MPE_SIZE 1
+#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */
+#define MACB_CLRSTAT_SIZE 1
+#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */
+#define MACB_INCSTAT_SIZE 1
+#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */
+#define MACB_WESTAT_SIZE 1
+#define MACB_BP_OFFSET 8 /* Back pressure */
+#define MACB_BP_SIZE 1
+#define MACB_TSTART_OFFSET 9 /* Start transmission */
+#define MACB_TSTART_SIZE 1
+#define MACB_THALT_OFFSET 10 /* Transmit halt */
+#define MACB_THALT_SIZE 1
+#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */
+#define MACB_NCR_TPF_SIZE 1
+#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */
+#define MACB_TZQ_SIZE 1
+#define MACB_SRTSM_OFFSET 15
+#define MACB_OSSMODE_OFFSET 24 /* Enable One Step Synchro Mode */
+#define MACB_OSSMODE_SIZE 1
/* Bitfields in NCFGR */
-#define MACB_SPD_OFFSET 0
-#define MACB_SPD_SIZE 1
-#define MACB_FD_OFFSET 1
-#define MACB_FD_SIZE 1
-#define MACB_BIT_RATE_OFFSET 2
-#define MACB_BIT_RATE_SIZE 1
-#define MACB_JFRAME_OFFSET 3
-#define MACB_JFRAME_SIZE 1
-#define MACB_CAF_OFFSET 4
-#define MACB_CAF_SIZE 1
-#define MACB_NBC_OFFSET 5
-#define MACB_NBC_SIZE 1
-#define MACB_NCFGR_MTI_OFFSET 6
-#define MACB_NCFGR_MTI_SIZE 1
-#define MACB_UNI_OFFSET 7
-#define MACB_UNI_SIZE 1
-#define MACB_BIG_OFFSET 8
-#define MACB_BIG_SIZE 1
-#define MACB_EAE_OFFSET 9
-#define MACB_EAE_SIZE 1
-#define MACB_CLK_OFFSET 10
-#define MACB_CLK_SIZE 2
-#define MACB_RTY_OFFSET 12
-#define MACB_RTY_SIZE 1
-#define MACB_PAE_OFFSET 13
-#define MACB_PAE_SIZE 1
-#define MACB_RBOF_OFFSET 14
-#define MACB_RBOF_SIZE 2
-#define MACB_RLCE_OFFSET 16
-#define MACB_RLCE_SIZE 1
-#define MACB_DRFCS_OFFSET 17
-#define MACB_DRFCS_SIZE 1
-#define MACB_EFRHD_OFFSET 18
-#define MACB_EFRHD_SIZE 1
-#define MACB_IRXFCS_OFFSET 19
-#define MACB_IRXFCS_SIZE 1
-
-#define GEM_GBE_OFFSET 10
-#define GEM_GBE_SIZE 1
-#define GEM_CLK_OFFSET 18
-#define GEM_CLK_SIZE 3
-#define GEM_DBW_OFFSET 21
-#define GEM_DBW_SIZE 2
+#define MACB_SPD_OFFSET 0 /* Speed */
+#define MACB_SPD_SIZE 1
+#define MACB_FD_OFFSET 1 /* Full duplex */
+#define MACB_FD_SIZE 1
+#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */
+#define MACB_BIT_RATE_SIZE 1
+#define MACB_JFRAME_OFFSET 3 /* reserved */
+#define MACB_JFRAME_SIZE 1
+#define MACB_CAF_OFFSET 4 /* Copy all frames */
+#define MACB_CAF_SIZE 1
+#define MACB_NBC_OFFSET 5 /* No broadcast */
+#define MACB_NBC_SIZE 1
+#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */
+#define MACB_NCFGR_MTI_SIZE 1
+#define MACB_UNI_OFFSET 7 /* Unicast hash enable */
+#define MACB_UNI_SIZE 1
+#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */
+#define MACB_BIG_SIZE 1
+#define MACB_EAE_OFFSET 9 /* External address match enable */
+#define MACB_EAE_SIZE 1
+#define MACB_CLK_OFFSET 10
+#define MACB_CLK_SIZE 2
+#define MACB_RTY_OFFSET 12 /* Retry test */
+#define MACB_RTY_SIZE 1
+#define MACB_PAE_OFFSET 13 /* Pause enable */
+#define MACB_PAE_SIZE 1
+#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */
+#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */
+#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */
+#define MACB_RBOF_SIZE 2
+#define MACB_RLCE_OFFSET 16 /* Length field error frame discard */
+#define MACB_RLCE_SIZE 1
+#define MACB_DRFCS_OFFSET 17 /* FCS remove */
+#define MACB_DRFCS_SIZE 1
+#define MACB_EFRHD_OFFSET 18
+#define MACB_EFRHD_SIZE 1
+#define MACB_IRXFCS_OFFSET 19
+#define MACB_IRXFCS_SIZE 1
+
+/* GEM specific NCFGR bitfields. */
+#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */
+#define GEM_GBE_SIZE 1
+#define GEM_PCSSEL_OFFSET 11
+#define GEM_PCSSEL_SIZE 1
+#define GEM_CLK_OFFSET 18 /* MDC clock division */
+#define GEM_CLK_SIZE 3
+#define GEM_DBW_OFFSET 21 /* Data bus width */
+#define GEM_DBW_SIZE 2
+#define GEM_RXCOEN_OFFSET 24
+#define GEM_RXCOEN_SIZE 1
+#define GEM_SGMIIEN_OFFSET 27
+#define GEM_SGMIIEN_SIZE 1
+
+
+/* Constants for data bus width. */
+#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */
+#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus width */
+#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus width */
+
+/* Bitfields in DMACFG. */
+#define GEM_FBLDO_OFFSET 0 /* fixed burst length for DMA */
+#define GEM_FBLDO_SIZE 5
+#define GEM_ENDIA_DESC_OFFSET 6 /* endian swap mode for management descriptor access */
+#define GEM_ENDIA_DESC_SIZE 1
+#define GEM_ENDIA_PKT_OFFSET 7 /* endian swap mode for packet data access */
+#define GEM_ENDIA_PKT_SIZE 1
+#define GEM_RXBMS_OFFSET 8 /* RX packet buffer memory size select */
+#define GEM_RXBMS_SIZE 2
+#define GEM_TXPBMS_OFFSET 10 /* TX packet buffer memory size select */
+#define GEM_TXPBMS_SIZE 1
+#define GEM_TXCOEN_OFFSET 11 /* TX IP/TCP/UDP checksum gen offload */
+#define GEM_TXCOEN_SIZE 1
+#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size */
+#define GEM_RXBS_SIZE 8
+#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */
+#define GEM_DDRP_SIZE 1
+#define GEM_RXEXT_OFFSET 28 /* RX extended Buffer Descriptor mode */
+#define GEM_RXEXT_SIZE 1
+#define GEM_TXEXT_OFFSET 29 /* TX extended Buffer Descriptor mode */
+#define GEM_TXEXT_SIZE 1
+#define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */
+#define GEM_ADDR64_SIZE 1
+
/* Bitfields in NSR */
-#define MACB_NSR_LINK_OFFSET 0
-#define MACB_NSR_LINK_SIZE 1
-#define MACB_MDIO_OFFSET 1
-#define MACB_MDIO_SIZE 1
-#define MACB_IDLE_OFFSET 2
-#define MACB_IDLE_SIZE 1
-
-/* Bitfields in UR */
-#define GEM_RGMII_OFFSET 0
-#define GEM_RGMII_SIZE 1
+#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */
+#define MACB_NSR_LINK_SIZE 1
+#define MACB_MDIO_OFFSET 1 /* status of the mdio_in pin */
+#define MACB_MDIO_SIZE 1
+#define MACB_IDLE_OFFSET 2 /* The PHY management logic is idle */
+#define MACB_IDLE_SIZE 1
/* Bitfields in TSR */
-#define MACB_UBR_OFFSET 0
-#define MACB_UBR_SIZE 1
-#define MACB_COL_OFFSET 1
-#define MACB_COL_SIZE 1
-#define MACB_TSR_RLE_OFFSET 2
-#define MACB_TSR_RLE_SIZE 1
-#define MACB_TGO_OFFSET 3
-#define MACB_TGO_SIZE 1
-#define MACB_BEX_OFFSET 4
-#define MACB_BEX_SIZE 1
-#define MACB_COMP_OFFSET 5
-#define MACB_COMP_SIZE 1
-#define MACB_UND_OFFSET 6
-#define MACB_UND_SIZE 1
+#define MACB_UBR_OFFSET 0 /* Used bit read */
+#define MACB_UBR_SIZE 1
+#define MACB_COL_OFFSET 1 /* Collision occurred */
+#define MACB_COL_SIZE 1
+#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */
+#define MACB_TSR_RLE_SIZE 1
+#define MACB_TGO_OFFSET 3 /* Transmit go */
+#define MACB_TGO_SIZE 1
+#define MACB_BEX_OFFSET 4 /* TX frame corruption due to AHB error */
+#define MACB_BEX_SIZE 1
+#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */
+#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */
+#define MACB_COMP_OFFSET 5 /* Trnasmit complete */
+#define MACB_COMP_SIZE 1
+#define MACB_UND_OFFSET 6 /* Trnasmit under run */
+#define MACB_UND_SIZE 1
/* Bitfields in RSR */
-#define MACB_BNA_OFFSET 0
-#define MACB_BNA_SIZE 1
-#define MACB_REC_OFFSET 1
-#define MACB_REC_SIZE 1
-#define MACB_OVR_OFFSET 2
-#define MACB_OVR_SIZE 1
+#define MACB_BNA_OFFSET 0 /* Buffer not available */
+#define MACB_BNA_SIZE 1
+#define MACB_REC_OFFSET 1 /* Frame received */
+#define MACB_REC_SIZE 1
+#define MACB_OVR_OFFSET 2 /* Receive overrun */
+#define MACB_OVR_SIZE 1
/* Bitfields in ISR/IER/IDR/IMR */
-#define MACB_MFD_OFFSET 0
-#define MACB_MFD_SIZE 1
-#define MACB_RCOMP_OFFSET 1
-#define MACB_RCOMP_SIZE 1
-#define MACB_RXUBR_OFFSET 2
-#define MACB_RXUBR_SIZE 1
-#define MACB_TXUBR_OFFSET 3
-#define MACB_TXUBR_SIZE 1
-#define MACB_ISR_TUND_OFFSET 4
-#define MACB_ISR_TUND_SIZE 1
-#define MACB_ISR_RLE_OFFSET 5
-#define MACB_ISR_RLE_SIZE 1
-#define MACB_TXERR_OFFSET 6
-#define MACB_TXERR_SIZE 1
-#define MACB_TCOMP_OFFSET 7
-#define MACB_TCOMP_SIZE 1
-#define MACB_ISR_LINK_OFFSET 9
-#define MACB_ISR_LINK_SIZE 1
-#define MACB_ISR_ROVR_OFFSET 10
-#define MACB_ISR_ROVR_SIZE 1
-#define MACB_HRESP_OFFSET 11
-#define MACB_HRESP_SIZE 1
-#define MACB_PFR_OFFSET 12
-#define MACB_PFR_SIZE 1
-#define MACB_PTZ_OFFSET 13
-#define MACB_PTZ_SIZE 1
+#define MACB_MFD_OFFSET 0 /* Management frame sent */
+#define MACB_MFD_SIZE 1
+#define MACB_RCOMP_OFFSET 1 /* Receive complete */
+#define MACB_RCOMP_SIZE 1
+#define MACB_RXUBR_OFFSET 2 /* RX used bit read */
+#define MACB_RXUBR_SIZE 1
+#define MACB_TXUBR_OFFSET 3 /* TX used bit read */
+#define MACB_TXUBR_SIZE 1
+#define MACB_ISR_TUND_OFFSET 4 /* Enable TX buffer under run interrupt */
+#define MACB_ISR_TUND_SIZE 1
+#define MACB_ISR_RLE_OFFSET 5 /* EN retry exceeded/late coll interrupt */
+#define MACB_ISR_RLE_SIZE 1
+#define MACB_TXERR_OFFSET 6 /* EN TX frame corrupt from error interrupt */
+#define MACB_TXERR_SIZE 1
+#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete interrupt */
+#define MACB_TCOMP_SIZE 1
+#define MACB_ISR_LINK_OFFSET 9 /* Enable link change interrupt */
+#define MACB_ISR_LINK_SIZE 1
+#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun interrupt */
+#define MACB_ISR_ROVR_SIZE 1
+#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK interrupt */
+#define MACB_HRESP_SIZE 1
+#define MACB_PFR_OFFSET 12 /* Enable pause frame w/ quantum interrupt */
+#define MACB_PFR_SIZE 1
+#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */
+#define MACB_PTZ_SIZE 1
+#define MACB_WOL_OFFSET 14 /* Enable wake-on-lan interrupt */
+#define MACB_WOL_SIZE 1
+#define MACB_DRQFR_OFFSET 18 /* PTP Delay Request Frame Received */
+#define MACB_DRQFR_SIZE 1
+#define MACB_SFR_OFFSET 19 /* PTP Sync Frame Received */
+#define MACB_SFR_SIZE 1
+#define MACB_DRQFT_OFFSET 20 /* PTP Delay Request Frame Transmitted */
+#define MACB_DRQFT_SIZE 1
+#define MACB_SFT_OFFSET 21 /* PTP Sync Frame Transmitted */
+#define MACB_SFT_SIZE 1
+#define MACB_PDRQFR_OFFSET 22 /* PDelay Request Frame Received */
+#define MACB_PDRQFR_SIZE 1
+#define MACB_PDRSFR_OFFSET 23 /* PDelay Response Frame Received */
+#define MACB_PDRSFR_SIZE 1
+#define MACB_PDRQFT_OFFSET 24 /* PDelay Request Frame Transmitted */
+#define MACB_PDRQFT_SIZE 1
+#define MACB_PDRSFT_OFFSET 25 /* PDelay Response Frame Transmitted */
+#define MACB_PDRSFT_SIZE 1
+#define MACB_SRI_OFFSET 26 /* TSU Seconds Register Increment */
+#define MACB_SRI_SIZE 1
+
+/* Timer increment fields */
+#define MACB_TI_CNS_OFFSET 0
+#define MACB_TI_CNS_SIZE 8
+#define MACB_TI_ACNS_OFFSET 8
+#define MACB_TI_ACNS_SIZE 8
+#define MACB_TI_NIT_OFFSET 16
+#define MACB_TI_NIT_SIZE 8
/* Bitfields in MAN */
-#define MACB_DATA_OFFSET 0
-#define MACB_DATA_SIZE 16
-#define MACB_CODE_OFFSET 16
-#define MACB_CODE_SIZE 2
-#define MACB_REGA_OFFSET 18
-#define MACB_REGA_SIZE 5
-#define MACB_PHYA_OFFSET 23
-#define MACB_PHYA_SIZE 5
-#define MACB_RW_OFFSET 28
-#define MACB_RW_SIZE 2
-#define MACB_SOF_OFFSET 30
-#define MACB_SOF_SIZE 2
-
-/* Bitfields in USRIO */
+#define MACB_DATA_OFFSET 0 /* data */
+#define MACB_DATA_SIZE 16
+#define MACB_CODE_OFFSET 16 /* Must be written to 10 */
+#define MACB_CODE_SIZE 2
+#define MACB_REGA_OFFSET 18 /* Register address */
+#define MACB_REGA_SIZE 5
+#define MACB_PHYA_OFFSET 23 /* PHY address */
+#define MACB_PHYA_SIZE 5
+#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 is write. */
+#define MACB_RW_SIZE 2
+#define MACB_SOF_OFFSET 30 /* Must be written to 1 for Clause 22 */
+#define MACB_SOF_SIZE 2
+
+/* Bitfields in USRIO (AVR32) */
#define MACB_MII_OFFSET 0
#define MACB_MII_SIZE 1
#define MACB_EAM_OFFSET 1
@@ -232,6 +421,8 @@
/* Bitfields in USRIO (AT91) */
#define MACB_RMII_OFFSET 0
#define MACB_RMII_SIZE 1
+#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
+#define GEM_RGMII_SIZE 1
#define MACB_CLKEN_OFFSET 1
#define MACB_CLKEN_SIZE 1
@@ -249,17 +440,166 @@
/* Bitfields in MID */
#define MACB_IDNUM_OFFSET 16
-#define MACB_IDNUM_SIZE 16
+#define MACB_IDNUM_SIZE 12
+#define MACB_REV_OFFSET 0
+#define MACB_REV_SIZE 16
-/* Bitfields in DCFG1 */
+/* Bitfields in DCFG1. */
+#define GEM_IRQCOR_OFFSET 23
+#define GEM_IRQCOR_SIZE 1
#define GEM_DBWDEF_OFFSET 25
#define GEM_DBWDEF_SIZE 3
-/* constants for data bus width */
-#define GEM_DBW32 0
-#define GEM_DBW64 1
-#define GEM_DBW128 2
+/* Bitfields in DCFG2. */
+#define GEM_RX_PKT_BUFF_OFFSET 20
+#define GEM_RX_PKT_BUFF_SIZE 1
+#define GEM_TX_PKT_BUFF_OFFSET 21
+#define GEM_TX_PKT_BUFF_SIZE 1
+
+
+/* Bitfields in DCFG5. */
+#define GEM_TSU_OFFSET 8
+#define GEM_TSU_SIZE 1
+
+/* Bitfields in DCFG6. */
+#define GEM_PBUF_LSO_OFFSET 27
+#define GEM_PBUF_LSO_SIZE 1
+#define GEM_DAW64_OFFSET 23
+#define GEM_DAW64_SIZE 1
+
+/* Bitfields in DCFG8. */
+#define GEM_T1SCR_OFFSET 24
+#define GEM_T1SCR_SIZE 8
+#define GEM_T2SCR_OFFSET 16
+#define GEM_T2SCR_SIZE 8
+#define GEM_SCR2ETH_OFFSET 8
+#define GEM_SCR2ETH_SIZE 8
+#define GEM_SCR2CMP_OFFSET 0
+#define GEM_SCR2CMP_SIZE 8
+
+/* Bitfields in DCFG10 */
+#define GEM_TXBD_RDBUFF_OFFSET 12
+#define GEM_TXBD_RDBUFF_SIZE 4
+#define GEM_RXBD_RDBUFF_OFFSET 8
+#define GEM_RXBD_RDBUFF_SIZE 4
+
+/* Bitfields in TISUBN */
+#define GEM_SUBNSINCR_OFFSET 0
+#define GEM_SUBNSINCR_SIZE 16
+
+/* Bitfields in TI */
+#define GEM_NSINCR_OFFSET 0
+#define GEM_NSINCR_SIZE 8
+
+/* Bitfields in TSH */
+#define GEM_TSH_OFFSET 0 /* TSU timer value (s). MSB [47:32] of seconds timer count */
+#define GEM_TSH_SIZE 16
+
+/* Bitfields in TSL */
+#define GEM_TSL_OFFSET 0 /* TSU timer value (s). LSB [31:0] of seconds timer count */
+#define GEM_TSL_SIZE 32
+/* Bitfields in TN */
+#define GEM_TN_OFFSET 0 /* TSU timer value (ns) */
+#define GEM_TN_SIZE 30
+
+/* Bitfields in TXBDCTRL */
+#define GEM_TXTSMODE_OFFSET 4 /* TX Descriptor Timestamp Insertion mode */
+#define GEM_TXTSMODE_SIZE 2
+
+/* Bitfields in RXBDCTRL */
+#define GEM_RXTSMODE_OFFSET 4 /* RX Descriptor Timestamp Insertion mode */
+#define GEM_RXTSMODE_SIZE 2
+
+/* Bitfields in SCRT2 */
+#define GEM_QUEUE_OFFSET 0 /* Queue Number */
+#define GEM_QUEUE_SIZE 4
+#define GEM_VLANPR_OFFSET 4 /* VLAN Priority */
+#define GEM_VLANPR_SIZE 3
+#define GEM_VLANEN_OFFSET 8 /* VLAN Enable */
+#define GEM_VLANEN_SIZE 1
+#define GEM_ETHT2IDX_OFFSET 9 /* Index to screener type 2 EtherType register */
+#define GEM_ETHT2IDX_SIZE 3
+#define GEM_ETHTEN_OFFSET 12 /* EtherType Enable */
+#define GEM_ETHTEN_SIZE 1
+#define GEM_CMPA_OFFSET 13 /* Compare A - Index to screener type 2 Compare register */
+#define GEM_CMPA_SIZE 5
+#define GEM_CMPAEN_OFFSET 18 /* Compare A Enable */
+#define GEM_CMPAEN_SIZE 1
+#define GEM_CMPB_OFFSET 19 /* Compare B - Index to screener type 2 Compare register */
+#define GEM_CMPB_SIZE 5
+#define GEM_CMPBEN_OFFSET 24 /* Compare B Enable */
+#define GEM_CMPBEN_SIZE 1
+#define GEM_CMPC_OFFSET 25 /* Compare C - Index to screener type 2 Compare register */
+#define GEM_CMPC_SIZE 5
+#define GEM_CMPCEN_OFFSET 30 /* Compare C Enable */
+#define GEM_CMPCEN_SIZE 1
+
+/* Bitfields in ETHT */
+#define GEM_ETHTCMP_OFFSET 0 /* EtherType compare value */
+#define GEM_ETHTCMP_SIZE 16
+
+/* Bitfields in T2CMPW0 */
+#define GEM_T2CMP_OFFSET 16 /* 0xFFFF0000 compare value */
+#define GEM_T2CMP_SIZE 16
+#define GEM_T2MASK_OFFSET 0 /* 0x0000FFFF compare value or mask */
+#define GEM_T2MASK_SIZE 16
+
+/* Bitfields in T2CMPW1 */
+#define GEM_T2DISMSK_OFFSET 9 /* disable mask */
+#define GEM_T2DISMSK_SIZE 1
+#define GEM_T2CMPOFST_OFFSET 7 /* compare offset */
+#define GEM_T2CMPOFST_SIZE 2
+#define GEM_T2OFST_OFFSET 0 /* offset value */
+#define GEM_T2OFST_SIZE 7
+
+/* Offset for screener type 2 compare values (T2CMPOFST).
+ * Note the offset is applied after the specified point,
+ * e.g. GEM_T2COMPOFST_ETYPE denotes the EtherType field, so an offset
+ * of 12 bytes from this would be the source IP address in an IP header
+ */
+#define GEM_T2COMPOFST_SOF 0
+#define GEM_T2COMPOFST_ETYPE 1
+#define GEM_T2COMPOFST_IPHDR 2
+#define GEM_T2COMPOFST_TCPUDP 3
+
+/* offset from EtherType to IP address */
+#define ETYPE_SRCIP_OFFSET 12
+#define ETYPE_DSTIP_OFFSET 16
+
+/* offset from IP header to port */
+#define IPHDR_SRCPORT_OFFSET 0
+#define IPHDR_DSTPORT_OFFSET 2
+
+/* Transmit DMA buffer descriptor Word 1 */
+#define GEM_DMA_TXVALID_OFFSET 23 /* timestamp has been captured in the Buffer Descriptor */
+#define GEM_DMA_TXVALID_SIZE 1
+
+/* Receive DMA buffer descriptor Word 0 */
+#define GEM_DMA_RXVALID_OFFSET 2 /* indicates a valid timestamp in the Buffer Descriptor */
+#define GEM_DMA_RXVALID_SIZE 1
+
+/* DMA buffer descriptor Word 2 (32 bit addressing) or Word 4 (64 bit addressing) */
+#define GEM_DMA_SECL_OFFSET 30 /* Timestamp seconds[1:0] */
+#define GEM_DMA_SECL_SIZE 2
+#define GEM_DMA_NSEC_OFFSET 0 /* Timestamp nanosecs [29:0] */
+#define GEM_DMA_NSEC_SIZE 30
+
+/* DMA buffer descriptor Word 3 (32 bit addressing) or Word 5 (64 bit addressing) */
+
+/* New hardware supports 12 bit precision of timestamp in DMA buffer descriptor.
+ * Old hardware supports only 6 bit precision but it is enough for PTP.
+ * Less accuracy is used always instead of checking hardware version.
+ */
+#define GEM_DMA_SECH_OFFSET 0 /* Timestamp seconds[5:2] */
+#define GEM_DMA_SECH_SIZE 4
+#define GEM_DMA_SEC_WIDTH (GEM_DMA_SECH_SIZE + GEM_DMA_SECL_SIZE)
+#define GEM_DMA_SEC_TOP (1 << GEM_DMA_SEC_WIDTH)
+#define GEM_DMA_SEC_MASK (GEM_DMA_SEC_TOP - 1)
+
+/* Bitfields in ADJ */
+#define GEM_ADDSUB_OFFSET 31
+#define GEM_ADDSUB_SIZE 1
/* Constants for CLK */
#define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1
@@ -273,6 +613,8 @@
#define GEM_CLK_DIV48 3
#define GEM_CLK_DIV64 4
#define GEM_CLK_DIV96 5
+#define GEM_CLK_DIV128 6
+#define GEM_CLK_DIV224 7
/* Constants for MAN register */
#define MACB_MAN_SOF 1
@@ -280,19 +622,38 @@
#define MACB_MAN_READ 2
#define MACB_MAN_CODE 2
+/* Capability mask bits */
+#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001
+#define MACB_CAPS_USRIO_HAS_CLKEN 0x00000002
+#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII 0x00000004
+#define MACB_CAPS_NO_GIGABIT_HALF 0x00000008
+#define MACB_CAPS_USRIO_DISABLED 0x00000010
+#define MACB_CAPS_JUMBO 0x00000020
+#define MACB_CAPS_GEM_HAS_PTP 0x00000040
+#define MACB_CAPS_BD_RD_PREFETCH 0x00000080
+#define MACB_CAPS_NEEDS_RSTONUBR 0x00000100
+#define MACB_CAPS_FIFO_MODE 0x10000000
+#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000
+#define MACB_CAPS_SG_DISABLED 0x40000000
+#define MACB_CAPS_MACB_IS_GEM 0x80000000
+
+/* LSO settings */
+#define MACB_LSO_UFO_ENABLE 0x01
+#define MACB_LSO_TSO_ENABLE 0x02
+
/* Bit manipulation macros */
#define MACB_BIT(name) \
(1 << MACB_##name##_OFFSET)
-#define MACB_BF(name, value) \
+#define MACB_BF(name,value) \
(((value) & ((1 << MACB_##name##_SIZE) - 1)) \
<< MACB_##name##_OFFSET)
-#define MACB_BFEXT(name, value)\
+#define MACB_BFEXT(name,value)\
(((value) >> MACB_##name##_OFFSET) \
& ((1 << MACB_##name##_SIZE) - 1))
-#define MACB_BFINS(name, value, old) \
+#define MACB_BFINS(name,value,old) \
(((old) & ~(((1 << MACB_##name##_SIZE) - 1) \
<< MACB_##name##_OFFSET)) \
- | MACB_BF(name, value))
+ | MACB_BF(name,value))
#define GEM_BIT(name) \
(1 << GEM_##name##_OFFSET)
@@ -316,6 +677,95 @@
readl((port)->regs + GEM_##reg)
#define gem_writel(port, reg, value) \
writel((value), (port)->regs + GEM_##reg)
+
+/* DMA descriptor bitfields */
+#define MACB_RX_USED_OFFSET 0
+#define MACB_RX_USED_SIZE 1
+#define MACB_RX_WRAP_OFFSET 1
+#define MACB_RX_WRAP_SIZE 1
+#define MACB_RX_WADDR_OFFSET 2
+#define MACB_RX_WADDR_SIZE 30
+
+#define MACB_RX_FRMLEN_OFFSET 0
+#define MACB_RX_FRMLEN_SIZE 12
+#define MACB_RX_OFFSET_OFFSET 12
+#define MACB_RX_OFFSET_SIZE 2
+#define MACB_RX_SOF_OFFSET 14
+#define MACB_RX_SOF_SIZE 1
+#define MACB_RX_EOF_OFFSET 15
+#define MACB_RX_EOF_SIZE 1
+#define MACB_RX_CFI_OFFSET 16
+#define MACB_RX_CFI_SIZE 1
+#define MACB_RX_VLAN_PRI_OFFSET 17
+#define MACB_RX_VLAN_PRI_SIZE 3
+#define MACB_RX_PRI_TAG_OFFSET 20
+#define MACB_RX_PRI_TAG_SIZE 1
+#define MACB_RX_VLAN_TAG_OFFSET 21
+#define MACB_RX_VLAN_TAG_SIZE 1
+#define MACB_RX_TYPEID_MATCH_OFFSET 22
+#define MACB_RX_TYPEID_MATCH_SIZE 1
+#define MACB_RX_SA4_MATCH_OFFSET 23
+#define MACB_RX_SA4_MATCH_SIZE 1
+#define MACB_RX_SA3_MATCH_OFFSET 24
+#define MACB_RX_SA3_MATCH_SIZE 1
+#define MACB_RX_SA2_MATCH_OFFSET 25
+#define MACB_RX_SA2_MATCH_SIZE 1
+#define MACB_RX_SA1_MATCH_OFFSET 26
+#define MACB_RX_SA1_MATCH_SIZE 1
+#define MACB_RX_EXT_MATCH_OFFSET 28
+#define MACB_RX_EXT_MATCH_SIZE 1
+#define MACB_RX_UHASH_MATCH_OFFSET 29
+#define MACB_RX_UHASH_MATCH_SIZE 1
+#define MACB_RX_MHASH_MATCH_OFFSET 30
+#define MACB_RX_MHASH_MATCH_SIZE 1
+#define MACB_RX_BROADCAST_OFFSET 31
+#define MACB_RX_BROADCAST_SIZE 1
+
+#define MACB_RX_FRMLEN_MASK 0xFFF
+#define MACB_RX_JFRMLEN_MASK 0x3FFF
+
+/* RX checksum offload disabled: bit 24 clear in NCFGR */
+#define GEM_RX_TYPEID_MATCH_OFFSET 22
+#define GEM_RX_TYPEID_MATCH_SIZE 2
+
+/* RX checksum offload enabled: bit 24 set in NCFGR */
+#define GEM_RX_CSUM_OFFSET 22
+#define GEM_RX_CSUM_SIZE 2
+
+#define MACB_TX_FRMLEN_OFFSET 0
+#define MACB_TX_FRMLEN_SIZE 11
+#define MACB_TX_LAST_OFFSET 15
+#define MACB_TX_LAST_SIZE 1
+#define MACB_TX_NOCRC_OFFSET 16
+#define MACB_TX_NOCRC_SIZE 1
+#define MACB_MSS_MFS_OFFSET 16
+#define MACB_MSS_MFS_SIZE 14
+#define MACB_TX_LSO_OFFSET 17
+#define MACB_TX_LSO_SIZE 2
+#define MACB_TX_TCP_SEQ_SRC_OFFSET 19
+#define MACB_TX_TCP_SEQ_SRC_SIZE 1
+#define MACB_TX_BUF_EXHAUSTED_OFFSET 27
+#define MACB_TX_BUF_EXHAUSTED_SIZE 1
+#define MACB_TX_UNDERRUN_OFFSET 28
+#define MACB_TX_UNDERRUN_SIZE 1
+#define MACB_TX_ERROR_OFFSET 29
+#define MACB_TX_ERROR_SIZE 1
+#define MACB_TX_WRAP_OFFSET 30
+#define MACB_TX_WRAP_SIZE 1
+#define MACB_TX_USED_OFFSET 31
+#define MACB_TX_USED_SIZE 1
+
+#define GEM_TX_FRMLEN_OFFSET 0
+#define GEM_TX_FRMLEN_SIZE 14
+
+/* Buffer descriptor constants */
+#define GEM_RX_CSUM_NONE 0
+#define GEM_RX_CSUM_IP_ONLY 1
+#define GEM_RX_CSUM_IP_TCP 2
+#define GEM_RX_CSUM_IP_UDP 3
+
+/* limit RX checksum offload to TCP and UDP packets */
+#define GEM_RX_CSUM_CHECKED_MASK 2
#define gem_writel_queue_TBQP(port, value, queue_num) \
writel((value), (port)->regs + GEM_TBQP(queue_num))
diff --git a/drivers/net/mdio_mux_sandbox.c b/drivers/net/mdio_mux_sandbox.c
new file mode 100644
index 00000000000..3dba4d18a15
--- /dev/null
+++ b/drivers/net/mdio_mux_sandbox.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Alex Marginean, NXP
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <miiphy.h>
+
+/* macros copied over from mdio_sandbox.c */
+#define SANDBOX_PHY_ADDR 5
+#define SANDBOX_PHY_REG_CNT 2
+
+struct mdio_mux_sandbox_priv {
+ int enabled;
+ int sel;
+};
+
+static int mdio_mux_sandbox_mark_selection(struct udevice *dev, int sel)
+{
+ struct udevice *mdio;
+ struct mdio_ops *ops;
+ int err;
+
+ /*
+ * find the sandbox parent mdio and write a register on the PHY there
+ * so the mux test can verify selection.
+ */
+ err = uclass_get_device_by_name(UCLASS_MDIO, "mdio-test", &mdio);
+ if (err)
+ return err;
+ ops = mdio_get_ops(mdio);
+ return ops->write(mdio, SANDBOX_PHY_ADDR, MDIO_DEVAD_NONE,
+ SANDBOX_PHY_REG_CNT - 1, (u16)sel);
+}
+
+static int mdio_mux_sandbox_select(struct udevice *dev, int cur, int sel)
+{
+ struct mdio_mux_sandbox_priv *priv = dev_get_priv(dev);
+
+ if (!priv->enabled)
+ return -ENODEV;
+
+ if (cur != priv->sel)
+ return -EINVAL;
+
+ priv->sel = sel;
+ mdio_mux_sandbox_mark_selection(dev, priv->sel);
+
+ return 0;
+}
+
+static int mdio_mux_sandbox_deselect(struct udevice *dev, int sel)
+{
+ struct mdio_mux_sandbox_priv *priv = dev_get_priv(dev);
+
+ if (!priv->enabled)
+ return -ENODEV;
+
+ if (sel != priv->sel)
+ return -EINVAL;
+
+ priv->sel = -1;
+ mdio_mux_sandbox_mark_selection(dev, priv->sel);
+
+ return 0;
+}
+
+static const struct mdio_mux_ops mdio_mux_sandbox_ops = {
+ .select = mdio_mux_sandbox_select,
+ .deselect = mdio_mux_sandbox_deselect,
+};
+
+static int mdio_mux_sandbox_probe(struct udevice *dev)
+{
+ struct mdio_mux_sandbox_priv *priv = dev_get_priv(dev);
+
+ priv->enabled = 1;
+ priv->sel = -1;
+
+ return 0;
+}
+
+static const struct udevice_id mdio_mux_sandbox_ids[] = {
+ { .compatible = "sandbox,mdio-mux" },
+ { }
+};
+
+U_BOOT_DRIVER(mdio_mux_sandbox) = {
+ .name = "mdio_mux_sandbox",
+ .id = UCLASS_MDIO_MUX,
+ .of_match = mdio_mux_sandbox_ids,
+ .probe = mdio_mux_sandbox_probe,
+ .ops = &mdio_mux_sandbox_ops,
+ .priv_auto_alloc_size = sizeof(struct mdio_mux_sandbox_priv),
+};
diff --git a/drivers/net/mdio_sandbox.c b/drivers/net/mdio_sandbox.c
index 07515e078c2..df053f53814 100644
--- a/drivers/net/mdio_sandbox.c
+++ b/drivers/net/mdio_sandbox.c
@@ -9,11 +9,11 @@
#include <miiphy.h>
#define SANDBOX_PHY_ADDR 5
-#define SANDBOX_PHY_REG 0
+#define SANDBOX_PHY_REG_CNT 2
struct mdio_sandbox_priv {
int enabled;
- u16 reg;
+ u16 reg[SANDBOX_PHY_REG_CNT];
};
static int mdio_sandbox_read(struct udevice *dev, int addr, int devad, int reg)
@@ -27,10 +27,10 @@ static int mdio_sandbox_read(struct udevice *dev, int addr, int devad, int reg)
return -ENODEV;
if (devad != MDIO_DEVAD_NONE)
return -ENODEV;
- if (reg != SANDBOX_PHY_REG)
+ if (reg < 0 || reg > SANDBOX_PHY_REG_CNT)
return -ENODEV;
- return priv->reg;
+ return priv->reg[reg];
}
static int mdio_sandbox_write(struct udevice *dev, int addr, int devad, int reg,
@@ -45,10 +45,10 @@ static int mdio_sandbox_write(struct udevice *dev, int addr, int devad, int reg,
return -ENODEV;
if (devad != MDIO_DEVAD_NONE)
return -ENODEV;
- if (reg != SANDBOX_PHY_REG)
+ if (reg < 0 || reg > SANDBOX_PHY_REG_CNT)
return -ENODEV;
- priv->reg = val;
+ priv->reg[reg] = val;
return 0;
}
@@ -56,8 +56,10 @@ static int mdio_sandbox_write(struct udevice *dev, int addr, int devad, int reg,
static int mdio_sandbox_reset(struct udevice *dev)
{
struct mdio_sandbox_priv *priv = dev_get_priv(dev);
+ int i;
- priv->reg = 0;
+ for (i = 0; i < SANDBOX_PHY_REG_CNT; i++)
+ priv->reg[i] = 0;
return 0;
}
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index 5c3298d612c..465ec2d3423 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -461,6 +461,19 @@ struct phy_driver aqr107_driver = {
.shutdown = &gen10g_shutdown,
};
+struct phy_driver aqr112_driver = {
+ .name = "Aquantia AQR112",
+ .uid = 0x3a1b660,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS |
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
struct phy_driver aqr405_driver = {
.name = "Aquantia AQR405",
.uid = 0x3a1b4b2,
@@ -474,6 +487,19 @@ struct phy_driver aqr405_driver = {
.shutdown = &gen10g_shutdown,
};
+struct phy_driver aqr412_driver = {
+ .name = "Aquantia AQR412",
+ .uid = 0x3a1b710,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS |
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
int phy_aquantia_init(void)
{
phy_register(&aq1202_driver);
@@ -481,7 +507,9 @@ int phy_aquantia_init(void)
phy_register(&aqr105_driver);
phy_register(&aqr106_driver);
phy_register(&aqr107_driver);
+ phy_register(&aqr112_driver);
phy_register(&aqr405_driver);
+ phy_register(&aqr412_driver);
return 0;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c1c1af9abdb..ae37dd6c1e3 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -727,12 +727,23 @@ static struct phy_device *create_phy_by_mask(struct mii_dev *bus,
while (phy_mask) {
int addr = ffs(phy_mask) - 1;
int r = get_phy_id(bus, addr, devad, &phy_id);
+
+ /*
+ * If the PHY ID is flat 0 we ignore it. There are C45 PHYs
+ * that return all 0s for C22 reads (like Aquantia AQR112) and
+ * there are C22 PHYs that return all 0s for C45 reads (like
+ * Atheros AR8035).
+ */
+ if (r == 0 && phy_id == 0)
+ goto next;
+
/* If the PHY ID is mostly f's, we didn't find anything */
if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) {
is_c45 = (devad == MDIO_DEVAD_NONE) ? false : true;
return phy_device_create(bus, addr, phy_id, is_c45,
interface);
}
+next:
phy_mask &= ~(1 << addr);
}
return NULL;
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index c0a440886e2..0629b16e57c 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -846,31 +846,44 @@ static const struct eth_ops sun8i_emac_eth_ops = {
static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv)
{
- int node, ret;
+ int emac_node, ephy_node, ret, ephy_handle;
+
+ emac_node = fdt_path_offset(gd->fdt_blob,
+ "/soc/ethernet@1c30000");
+ if (emac_node < 0) {
+ debug("failed to get emac node\n");
+ return emac_node;
+ }
+ ephy_handle = fdtdec_lookup_phandle(gd->fdt_blob,
+ emac_node, "phy-handle");
/* look for mdio-mux node for internal PHY node */
- node = fdt_path_offset(gd->fdt_blob,
- "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1");
- if (node < 0) {
+ ephy_node = fdt_path_offset(gd->fdt_blob,
+ "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1");
+ if (ephy_node < 0) {
debug("failed to get mdio-mux with internal PHY\n");
- return node;
+ return ephy_node;
}
- ret = fdt_node_check_compatible(gd->fdt_blob, node,
+ /* This is not the phy we are looking for */
+ if (ephy_node != ephy_handle)
+ return 0;
+
+ ret = fdt_node_check_compatible(gd->fdt_blob, ephy_node,
"allwinner,sun8i-h3-mdio-internal");
if (ret < 0) {
debug("failed to find mdio-internal node\n");
return ret;
}
- ret = clk_get_by_index_nodev(offset_to_ofnode(node), 0,
+ ret = clk_get_by_index_nodev(offset_to_ofnode(ephy_node), 0,
&priv->ephy_clk);
if (ret) {
dev_err(dev, "failed to get EPHY TX clock\n");
return ret;
}
- ret = reset_get_by_index_nodev(offset_to_ofnode(node), 0,
+ ret = reset_get_by_index_nodev(offset_to_ofnode(ephy_node), 0,
&priv->ephy_rst);
if (ret) {
dev_err(dev, "failed to get EPHY TX reset\n");
diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c
index 9d539849739..2bd9c51079d 100644
--- a/drivers/net/ti/davinci_emac.c
+++ b/drivers/net/ti/davinci_emac.c
@@ -26,7 +26,6 @@
#include <net.h>
#include <miiphy.h>
#include <malloc.h>
-#include <netdev.h>
#include <linux/compiler.h>
#include <asm/arch/emac_defs.h>
#include <asm/io.h>
@@ -107,8 +106,9 @@ static u_int8_t num_phy;
phy_t phy[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT];
-static int davinci_eth_set_mac_addr(struct eth_device *dev)
+static int davinci_emac_write_hwaddr(struct udevice *dev)
{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
unsigned long mac_hi;
unsigned long mac_lo;
@@ -118,12 +118,12 @@ static int davinci_eth_set_mac_addr(struct eth_device *dev)
* Using channel 0 only - other channels are disabled
* */
writel(0, &adap_emac->MACINDEX);
- mac_hi = (dev->enetaddr[3] << 24) |
- (dev->enetaddr[2] << 16) |
- (dev->enetaddr[1] << 8) |
- (dev->enetaddr[0]);
- mac_lo = (dev->enetaddr[5] << 8) |
- (dev->enetaddr[4]);
+ mac_hi = (pdata->enetaddr[3] << 24) |
+ (pdata->enetaddr[2] << 16) |
+ (pdata->enetaddr[1] << 8) |
+ (pdata->enetaddr[0]);
+ mac_lo = (pdata->enetaddr[5] << 8) |
+ (pdata->enetaddr[4]);
writel(mac_hi, &adap_emac->MACADDRHI);
#if defined(DAVINCI_EMAC_VERSION2)
@@ -411,7 +411,7 @@ static void __attribute__((unused)) davinci_eth_gigabit_enable(int phy_addr)
}
/* Eth device open */
-static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
+static int davinci_emac_start(struct udevice *dev)
{
dv_reg_p addr;
u_int32_t clkdiv, cnt, mac_control;
@@ -447,7 +447,7 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
writel(1, &adap_emac->TXCONTROL);
writel(1, &adap_emac->RXCONTROL);
- davinci_eth_set_mac_addr(dev);
+ davinci_emac_write_hwaddr(dev);
/* Set DMA 8 TX / 8 RX Head pointers to 0 */
addr = &adap_emac->TX0HDP;
@@ -588,7 +588,7 @@ static void davinci_eth_ch_teardown(int ch)
}
/* Eth device close */
-static void davinci_eth_close(struct eth_device *dev)
+static void davinci_emac_stop(struct udevice *dev)
{
debug_emac("+ emac_close\n");
@@ -619,8 +619,8 @@ static int tx_send_loop = 0;
* This function sends a single packet on the network and returns
* positive number (number of bytes transmitted) or negative for error
*/
-static int davinci_eth_send_packet (struct eth_device *dev,
- void *packet, int length)
+static int davinci_emac_send(struct udevice *dev,
+ void *packet, int length)
{
int ret_status = -1;
int index;
@@ -672,7 +672,7 @@ static int davinci_eth_send_packet (struct eth_device *dev,
/*
* This function handles receipt of a packet from the network
*/
-static int davinci_eth_rcv_packet (struct eth_device *dev)
+static int davinci_emac_recv(struct udevice *dev, int flags, uchar **packetp)
{
volatile emac_desc *rx_curr_desc;
volatile emac_desc *curr_desc;
@@ -682,6 +682,7 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
rx_curr_desc = emac_rx_active_head;
if (!rx_curr_desc)
return 0;
+ *packetp = rx_curr_desc->buffer;
status = rx_curr_desc->pkt_flag_len;
if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) {
if (status & EMAC_CPPI_RX_ERROR_FRAME) {
@@ -693,7 +694,6 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
rx_curr_desc->buff_off_len & 0xffff;
invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN));
- net_process_received_packet(rx_curr_desc->buffer, len);
ret = len;
}
@@ -742,6 +742,7 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
}
return (ret);
}
+
return (0);
}
@@ -750,30 +751,12 @@ static int davinci_eth_rcv_packet (struct eth_device *dev)
* EMAC modules power or pin multiplexors, that is done by board_init()
* much earlier in bootup process. Returns 1 on success, 0 otherwise.
*/
-int davinci_emac_initialize(void)
+static int davinci_emac_probe(struct udevice *dev)
{
u_int32_t phy_id;
u_int16_t tmp;
int i;
int ret;
- struct eth_device *dev;
-
- dev = malloc(sizeof *dev);
-
- if (dev == NULL)
- return -1;
-
- memset(dev, 0, sizeof *dev);
- strcpy(dev->name, "DaVinci-EMAC");
-
- dev->iobase = 0;
- dev->init = davinci_eth_open;
- dev->halt = davinci_eth_close;
- dev->send = davinci_eth_send_packet;
- dev->recv = davinci_eth_rcv_packet;
- dev->write_hwaddr = davinci_eth_set_mac_addr;
-
- eth_register(dev);
davinci_eth_mdio_enable();
@@ -854,5 +837,29 @@ int davinci_emac_initialize(void)
phy[i].auto_negotiate(i);
}
#endif
- return(1);
+ return 0;
}
+
+static const struct eth_ops davinci_emac_ops = {
+ .start = davinci_emac_start,
+ .send = davinci_emac_send,
+ .recv = davinci_emac_recv,
+ .stop = davinci_emac_stop,
+ .write_hwaddr = davinci_emac_write_hwaddr,
+};
+
+static const struct udevice_id davinci_emac_ids[] = {
+ { .compatible = "ti,davinci-dm6467-emac" },
+ { .compatible = "ti,am3517-emac", },
+ { .compatible = "ti,dm816-emac", },
+ { }
+};
+
+U_BOOT_DRIVER(davinci_emac) = {
+ .name = "davinci_emac",
+ .id = UCLASS_ETH,
+ .of_match = davinci_emac_ids,
+ .probe = davinci_emac_probe,
+ .ops = &davinci_emac_ops,
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 06a9b4fb03c..f85cdcb97eb 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -259,8 +259,8 @@ static int tsec_send(struct udevice *dev, void *packet, int length)
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
- u16 status;
int result = 0;
+ u16 status;
int i;
/* Find an empty buffer descriptor */
@@ -268,7 +268,7 @@ static int tsec_send(struct udevice *dev, void *packet, int length)
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
i++) {
if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx buffers full\n", dev->name);
+ printf("%s: tsec: tx buffers full\n", dev->name);
return result;
}
}
@@ -287,7 +287,7 @@ static int tsec_send(struct udevice *dev, void *packet, int length)
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
i++) {
if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx error\n", dev->name);
+ printf("%s: tsec: tx error\n", dev->name);
return result;
}
}
@@ -560,6 +560,8 @@ static int tsec_init(struct udevice *dev)
struct tsec_private *priv = (struct tsec_private *)dev->priv;
#ifdef CONFIG_DM_ETH
struct eth_pdata *pdata = dev_get_platdata(dev);
+#else
+ struct eth_device *pdata = dev;
#endif
struct tsec __iomem *regs = priv->regs;
u32 tempval;
@@ -580,21 +582,12 @@ static int tsec_init(struct udevice *dev)
* order (BE), MACnADDR1 is set to 0xCDAB7856 and
* MACnADDR2 is set to 0x34120000.
*/
-#ifndef CONFIG_DM_ETH
- tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
- (dev->enetaddr[3] << 8) | dev->enetaddr[2];
-#else
tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
(pdata->enetaddr[3] << 8) | pdata->enetaddr[2];
-#endif
out_be32(&regs->macstnaddr1, tempval);
-#ifndef CONFIG_DM_ETH
- tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
-#else
tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
-#endif
out_be32(&regs->macstnaddr2, tempval);
@@ -708,9 +701,9 @@ static int init_phy(struct tsec_private *priv)
*/
static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
{
+ struct tsec_private *priv;
struct eth_device *dev;
int i;
- struct tsec_private *priv;
dev = (struct eth_device *)malloc(sizeof(*dev));
@@ -794,12 +787,14 @@ int tsec_standard_init(bd_t *bis)
#else /* CONFIG_DM_ETH */
int tsec_probe(struct udevice *dev)
{
- struct tsec_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
- struct fsl_pq_mdio_info mdio_info;
+ struct tsec_private *priv = dev_get_priv(dev);
struct ofnode_phandle_args phandle_args;
- ofnode parent;
+ u32 tbiaddr = CONFIG_SYS_TBIPA_VALUE;
+ struct fsl_pq_mdio_info mdio_info;
const char *phy_mode;
+ fdt_addr_t reg;
+ ofnode parent;
int ret;
pdata->iobase = (phys_addr_t)dev_read_addr(dev);
@@ -807,7 +802,7 @@ int tsec_probe(struct udevice *dev)
if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
&phandle_args)) {
- debug("phy-handle does not exist under tsec %s\n", dev->name);
+ 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);
@@ -816,29 +811,27 @@ int tsec_probe(struct udevice *dev)
}
parent = ofnode_get_parent(phandle_args.node);
- if (ofnode_valid(parent)) {
- int reg = ofnode_get_addr_index(parent, 0);
-
- priv->phyregs_sgmii = (struct tsec_mii_mng *)reg;
- } else {
- debug("No parent node for PHY?\n");
+ if (!ofnode_valid(parent)) {
+ printf("No parent node for PHY?\n");
return -ENOENT;
}
- if (dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
- &phandle_args)) {
- priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
- } else {
- int reg = ofnode_read_u32_default(phandle_args.node, "reg",
- CONFIG_SYS_TBIPA_VALUE);
- priv->tbiaddr = reg;
- }
+ reg = ofnode_get_addr_index(parent, 0);
+ priv->phyregs_sgmii = (struct tsec_mii_mng *)
+ (reg + TSEC_MDIO_REGS_OFFSET);
+
+ ret = dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0,
+ &phandle_args);
+ if (ret == 0)
+ ofnode_read_u32(phandle_args.node, "reg", &tbiaddr);
+
+ priv->tbiaddr = tbiaddr;
phy_mode = dev_read_prop(dev, "phy-connection-type", NULL);
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
- debug("Invalid PHY interface '%s'\n", phy_mode);
+ printf("Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
priv->interface = pdata->phy_interface;
@@ -887,7 +880,7 @@ static const struct eth_ops tsec_ops = {
};
static const struct udevice_id tsec_ids[] = {
- { .compatible = "fsl,tsec" },
+ { .compatible = "fsl,etsec2" },
{ }
};
diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig
index 61f93be42d2..f2e67ca2319 100644
--- a/drivers/pinctrl/nxp/Kconfig
+++ b/drivers/pinctrl/nxp/Kconfig
@@ -89,6 +89,16 @@ config PINCTRL_IMX8M
only parses the 'fsl,pins' property and configure related
registers.
+config PINCTRL_MXS
+ bool "NXP MXS pinctrl driver"
+ depends on ARCH_MX28 && PINCTRL_FULL
+ help
+ Say Y here to enable the i.MX mxs pinctrl driver
+
+ This option provides a simple pinctrl driver for i.MX mxs SoC
+ familiy, e.g. i.MX28. This feature depends on device tree
+ configuration.
+
config PINCTRL_VYBRID
bool "Vybrid (vf610) pinctrl driver"
depends on ARCH_VF610 && PINCTRL_FULL
diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile
index b340d9448aa..b86448aac9a 100644
--- a/drivers/pinctrl/nxp/Makefile
+++ b/drivers/pinctrl/nxp/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o
obj-$(CONFIG_PINCTRL_IMX8) += pinctrl-imx8.o
obj-$(CONFIG_PINCTRL_IMX8M) += pinctrl-imx8m.o
+obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_VYBRID) += pinctrl-vf610.o
diff --git a/drivers/pinctrl/nxp/pinctrl-mxs.c b/drivers/pinctrl/nxp/pinctrl-mxs.c
new file mode 100644
index 00000000000..6f6ca84674a
--- /dev/null
+++ b/drivers/pinctrl/nxp/pinctrl-mxs.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <dm/read.h>
+#include "pinctrl-mxs.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct mxs_pinctrl_priv {
+ void __iomem *base;
+ const struct mxs_regs *regs;
+};
+
+static unsigned long mxs_dt_node_to_map(struct udevice *conf)
+{
+ unsigned long config = 0;
+ int ret;
+ u32 val;
+
+ ret = dev_read_u32(conf, "fsl,drive-strength", &val);
+ if (!ret)
+ config = val | MA_PRESENT;
+
+ ret = dev_read_u32(conf, "fsl,voltage", &val);
+ if (!ret)
+ config |= val << VOL_SHIFT | VOL_PRESENT;
+
+ ret = dev_read_u32(conf, "fsl,pull-up", &val);
+ if (!ret)
+ config |= val << PULL_SHIFT | PULL_PRESENT;
+
+ return config;
+}
+
+static int mxs_pinctrl_set_mux(struct udevice *dev, u32 val, int bank, int pin)
+{
+ struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
+ int muxsel = MUXID_TO_MUXSEL(val), shift;
+ void __iomem *reg;
+
+ reg = iomux->base + iomux->regs->muxsel;
+ reg += bank * 0x20 + pin / 16 * 0x10;
+ shift = pin % 16 * 2;
+
+ mxs_pinctrl_rmwl(muxsel, 0x3, shift, reg);
+ debug(" mux %d,", muxsel);
+
+ return 0;
+}
+
+static int mxs_pinctrl_set_state(struct udevice *dev, struct udevice *conf)
+{
+ struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
+ u32 *pin_data, val, ma, vol, pull;
+ int npins, size, i, ret;
+ unsigned long config;
+
+ debug("\n%s: set state: %s\n", __func__, conf->name);
+
+ size = dev_read_size(conf, "fsl,pinmux-ids");
+ if (size < 0)
+ return size;
+
+ if (!size || size % sizeof(int)) {
+ dev_err(dev, "Invalid fsl,pinmux-ids property in %s\n",
+ conf->name);
+ return -EINVAL;
+ }
+
+ npins = size / sizeof(int);
+
+ pin_data = devm_kzalloc(dev, size, 0);
+ if (!pin_data)
+ return -ENOMEM;
+
+ ret = dev_read_u32_array(conf, "fsl,pinmux-ids", pin_data, npins);
+ if (ret) {
+ dev_err(dev, "Error reading pin data.\n");
+ devm_kfree(dev, pin_data);
+ return -EINVAL;
+ }
+
+ config = mxs_dt_node_to_map(conf);
+
+ ma = CONFIG_TO_MA(config);
+ vol = CONFIG_TO_VOL(config);
+ pull = CONFIG_TO_PULL(config);
+
+ for (i = 0; i < npins; i++) {
+ int pinid, bank, pin, shift;
+ void __iomem *reg;
+
+ val = pin_data[i];
+
+ pinid = MUXID_TO_PINID(val);
+ bank = PINID_TO_BANK(pinid);
+ pin = PINID_TO_PIN(pinid);
+
+ debug("(val: 0x%x) pin %d,", val, pinid);
+ /* Setup pinmux */
+ mxs_pinctrl_set_mux(dev, val, bank, pin);
+
+ debug(" ma: %d, vol: %d, pull: %d\n", ma, vol, pull);
+
+ /* drive */
+ reg = iomux->base + iomux->regs->drive;
+ reg += bank * 0x40 + pin / 8 * 0x10;
+
+ /* mA */
+ if (config & MA_PRESENT) {
+ shift = pin % 8 * 4;
+ mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
+ }
+
+ /* vol */
+ if (config & VOL_PRESENT) {
+ shift = pin % 8 * 4 + 2;
+ if (vol)
+ writel(1 << shift, reg + SET);
+ else
+ writel(1 << shift, reg + CLR);
+ }
+
+ /* pull */
+ if (config & PULL_PRESENT) {
+ reg = iomux->base + iomux->regs->pull;
+ reg += bank * 0x10;
+ shift = pin;
+ if (pull)
+ writel(1 << shift, reg + SET);
+ else
+ writel(1 << shift, reg + CLR);
+ }
+ }
+
+ devm_kfree(dev, pin_data);
+ return 0;
+}
+
+static struct pinctrl_ops mxs_pinctrl_ops = {
+ .set_state = mxs_pinctrl_set_state,
+};
+
+static int mxs_pinctrl_probe(struct udevice *dev)
+{
+ struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
+
+ iomux->base = dev_read_addr_ptr(dev);
+ iomux->regs = (struct mxs_regs *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static const struct mxs_regs imx23_regs = {
+ .muxsel = 0x100,
+ .drive = 0x200,
+ .pull = 0x400,
+};
+
+static const struct mxs_regs imx28_regs = {
+ .muxsel = 0x100,
+ .drive = 0x300,
+ .pull = 0x600,
+};
+
+static const struct udevice_id mxs_pinctrl_match[] = {
+ { .compatible = "fsl,imx23-pinctrl", .data = (ulong)&imx23_regs },
+ { .compatible = "fsl,imx28-pinctrl", .data = (ulong)&imx28_regs },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mxs_pinctrl) = {
+ .name = "mxs-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = of_match_ptr(mxs_pinctrl_match),
+ .probe = mxs_pinctrl_probe,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .bind = dm_scan_fdt_dev,
+#endif
+ .priv_auto_alloc_size = sizeof(struct mxs_pinctrl_priv),
+ .ops = &mxs_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/nxp/pinctrl-mxs.h b/drivers/pinctrl/nxp/pinctrl-mxs.h
new file mode 100644
index 00000000000..a398e43cbeb
--- /dev/null
+++ b/drivers/pinctrl/nxp/pinctrl-mxs.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __PINCTRL_MXS_H
+#define __PINCTRL_MXS_H
+
+#include <dm/pinctrl.h>
+
+#define SET 0x4
+#define CLR 0x8
+#define TOG 0xc
+
+#define MXS_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
+#define PINID(bank, pin) ((bank) * 32 + (pin))
+
+/*
+ * pinmux-id bit field definitions
+ *
+ * bank: 15..12 (4)
+ * pin: 11..4 (8)
+ * muxsel: 3..0 (4)
+ */
+#define MUXID_TO_PINID(m) PINID((m) >> 12 & 0xf, (m) >> 4 & 0xff)
+#define MUXID_TO_MUXSEL(m) ((m) & 0xf)
+
+#define PINID_TO_BANK(p) ((p) >> 5)
+#define PINID_TO_PIN(p) ((p) % 32)
+
+/*
+ * pin config bit field definitions
+ *
+ * pull-up: 6..5 (2)
+ * voltage: 4..3 (2)
+ * mA: 2..0 (3)
+ *
+ * MSB of each field is presence bit for the config.
+ */
+#define PULL_PRESENT (1 << 6)
+#define PULL_SHIFT 5
+#define VOL_PRESENT (1 << 4)
+#define VOL_SHIFT 3
+#define MA_PRESENT (1 << 2)
+#define MA_SHIFT 0
+#define CONFIG_TO_PULL(c) ((c) >> PULL_SHIFT & 0x1)
+#define CONFIG_TO_VOL(c) ((c) >> VOL_SHIFT & 0x1)
+#define CONFIG_TO_MA(c) ((c) >> MA_SHIFT & 0x3)
+
+struct mxs_regs {
+ u16 muxsel;
+ u16 drive;
+ u16 pull;
+};
+
+static inline void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift,
+ void __iomem *reg)
+{
+ clrsetbits_le32(reg, mask << shift, value << shift);
+}
+#endif /* __PINCTRL_MXS_H */
diff --git a/drivers/power/domain/ti-sci-power-domain.c b/drivers/power/domain/ti-sci-power-domain.c
index aafde62cbf0..b9cd37b6129 100644
--- a/drivers/power/domain/ti-sci-power-domain.c
+++ b/drivers/power/domain/ti-sci-power-domain.c
@@ -13,6 +13,7 @@
#include <errno.h>
#include <power-domain-uclass.h>
#include <linux/soc/ti/ti_sci_protocol.h>
+#include <dt-bindings/soc/ti,sci_pm_domain.h>
/**
* struct ti_sci_power_domain_data - pm domain controller information structure
@@ -56,11 +57,16 @@ static int ti_sci_power_domain_on(struct power_domain *pd)
struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
const struct ti_sci_handle *sci = data->sci;
const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
+ u8 flags = (uintptr_t)pd->priv;
int ret;
debug("%s(pd=%p)\n", __func__, pd);
- ret = dops->get_device(sci, pd->id);
+ if (flags & TI_SCI_PD_EXCLUSIVE)
+ ret = dops->get_device_exclusive(sci, pd->id);
+ else
+ ret = dops->get_device(sci, pd->id);
+
if (ret)
dev_err(power_domain->dev, "%s: get_device failed (%d)\n",
__func__, ret);
@@ -85,6 +91,28 @@ static int ti_sci_power_domain_off(struct power_domain *pd)
return ret;
}
+static int ti_sci_power_domain_of_xlate(struct power_domain *pd,
+ struct ofnode_phandle_args *args)
+{
+ u8 flags;
+
+ debug("%s(power_domain=%p)\n", __func__, pd);
+
+ if (args->args_count < 1) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ pd->id = args->args[0];
+ /* By default request for device exclusive */
+ flags = TI_SCI_PD_EXCLUSIVE;
+ if (args->args_count == 2)
+ flags = args->args[1] & TI_SCI_PD_EXCLUSIVE;
+ pd->priv = (void *)(uintptr_t)flags;
+
+ return 0;
+}
+
static const struct udevice_id ti_sci_power_domain_of_match[] = {
{ .compatible = "ti,sci-pm-domain" },
{ /* sentinel */ }
@@ -95,6 +123,7 @@ static struct power_domain_ops ti_sci_power_domain_ops = {
.free = ti_sci_power_domain_free,
.on = ti_sci_power_domain_on,
.off = ti_sci_power_domain_off,
+ .of_xlate = ti_sci_power_domain_of_xlate,
};
U_BOOT_DRIVER(ti_sci_pm_domains) = {
diff --git a/drivers/power/pmic/bd71837.c b/drivers/power/pmic/bd71837.c
index 24d9f7fab73..e292d42a8c6 100644
--- a/drivers/power/pmic/bd71837.c
+++ b/drivers/power/pmic/bd71837.c
@@ -3,6 +3,8 @@
* Copyright 2018 NXP
*/
+#define DEBUG
+
#include <common.h>
#include <errno.h>
#include <dm.h>
@@ -15,15 +17,15 @@ DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
/* buck */
- { .prefix = "b", .driver = BD71837_REGULATOR_DRIVER},
+ { .prefix = "b", .driver = BD718XX_REGULATOR_DRIVER},
/* ldo */
- { .prefix = "l", .driver = BD71837_REGULATOR_DRIVER},
+ { .prefix = "l", .driver = BD718XX_REGULATOR_DRIVER},
{ },
};
static int bd71837_reg_count(struct udevice *dev)
{
- return BD71837_REG_NUM;
+ return BD718XX_MAX_REGISTER - 1;
}
static int bd71837_write(struct udevice *dev, uint reg, const uint8_t *buff,
@@ -54,7 +56,7 @@ static int bd71837_bind(struct udevice *dev)
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
- debug("%s: %s regulators subnode not found!", __func__,
+ debug("%s: %s regulators subnode not found!\n", __func__,
dev->name);
return -ENXIO;
}
@@ -69,6 +71,24 @@ static int bd71837_bind(struct udevice *dev)
return 0;
}
+static int bd718x7_probe(struct udevice *dev)
+{
+ int ret;
+ uint8_t mask = BD718XX_REGLOCK_PWRSEQ | BD718XX_REGLOCK_VREG;
+
+ /* Unlock the PMIC regulator control before probing the children */
+ ret = pmic_clrsetbits(dev, BD718XX_REGLOCK, mask, 0);
+ if (ret) {
+ debug("%s: %s Failed to unlock regulator control\n", __func__,
+ dev->name);
+ return ret;
+ }
+ debug("%s: '%s' - BD718x7 PMIC registers unlocked\n", __func__,
+ dev->name);
+
+ return 0;
+}
+
static struct dm_pmic_ops bd71837_ops = {
.reg_count = bd71837_reg_count,
.read = bd71837_read,
@@ -76,7 +96,8 @@ static struct dm_pmic_ops bd71837_ops = {
};
static const struct udevice_id bd71837_ids[] = {
- { .compatible = "rohm,bd71837", .data = 0x4b, },
+ { .compatible = "rohm,bd71837", .data = ROHM_CHIP_TYPE_BD71837, },
+ { .compatible = "rohm,bd71847", .data = ROHM_CHIP_TYPE_BD71847, },
{ }
};
@@ -85,5 +106,6 @@ U_BOOT_DRIVER(pmic_bd71837) = {
.id = UCLASS_PMIC,
.of_match = bd71837_ids,
.bind = bd71837_bind,
+ .probe = bd718x7_probe,
.ops = &bd71837_ops,
};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 337e9e7471c..9aa00fad42f 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -43,6 +43,23 @@ config REGULATOR_AS3722
but does not yet support change voltages. Currently this must be
done using direct register writes to the PMIC.
+config DM_REGULATOR_BD71837
+ bool "Enable Driver Model for ROHM BD71837/BD71847 regulators"
+ depends on DM_REGULATOR && DM_PMIC_BD71837
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for regulators on ROHM BD71837 and BD71847 PMICs.
+ BD71837 contains 8 bucks and 7 LDOS. BD71847 is reduced version
+ containing 6 bucks and 6 LDOs. The driver implements get/set api for
+ value and enable.
+
+config SPL_DM_REGULATOR_BD71837
+ bool "Enable Driver Model for ROHM BD71837/BD71847 regulators in SPL"
+ depends on DM_REGULATOR_BD71837
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for regulators on ROHM BD71837 and BD71847 in SPL.
+
config DM_REGULATOR_PFUZE100
bool "Enable Driver Model for REGULATOR PFUZE100"
depends on DM_REGULATOR && DM_PMIC_PFUZE100
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index e728b73aee3..6a3d4bbee4c 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_BD71837) += bd71837.o
obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o
diff --git a/drivers/power/regulator/bd71837.c b/drivers/power/regulator/bd71837.c
new file mode 100644
index 00000000000..575429aa2d3
--- /dev/null
+++ b/drivers/power/regulator/bd71837.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 ROHM Semiconductors
+ *
+ * ROHM BD71837 regulator driver
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power/bd71837.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define HW_STATE_CONTROL 0
+#define DEBUG
+
+/**
+ * struct bd71837_vrange - describe linear range of voltages
+ *
+ * @min_volt: smallest voltage in range
+ * @step: how much voltage changes at each selector step
+ * @min_sel: smallest selector in the range
+ * @max_sel: maximum selector in the range
+ * @rangeval: register value used to select this range if selectible
+ * ranges are supported
+ */
+struct bd71837_vrange {
+ unsigned int min_volt;
+ unsigned int step;
+ u8 min_sel;
+ u8 max_sel;
+ u8 rangeval;
+};
+
+/**
+ * struct bd71837_platdata - describe regulator control registers
+ *
+ * @name: name of the regulator. Used for matching the dt-entry
+ * @enable_reg: register address used to enable/disable regulator
+ * @enablemask: register mask used to enable/disable regulator
+ * @volt_reg: register address used to configure regulator voltage
+ * @volt_mask: register mask used to configure regulator voltage
+ * @ranges: pointer to ranges of regulator voltages and matching register
+ * values
+ * @numranges: number of voltage ranges pointed by ranges
+ * @rangemask: mask for selecting used ranges if multiple ranges are supported
+ * @sel_mask: bit to toggle in order to transfer the register control to SW
+ * @dvs: whether the voltage can be changed when regulator is enabled
+ */
+struct bd71837_platdata {
+ const char *name;
+ u8 enable_reg;
+ u8 enablemask;
+ u8 volt_reg;
+ u8 volt_mask;
+ struct bd71837_vrange *ranges;
+ unsigned int numranges;
+ u8 rangemask;
+ u8 sel_mask;
+ bool dvs;
+};
+
+#define BD_RANGE(_min, _vstep, _sel_low, _sel_hi, _range_sel) \
+{ \
+ .min_volt = (_min), .step = (_vstep), .min_sel = (_sel_low), \
+ .max_sel = (_sel_hi), .rangeval = (_range_sel) \
+}
+
+#define BD_DATA(_name, enreg, enmask, vreg, vmask, _range, rmask, _dvs, sel) \
+{ \
+ .name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
+ .volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
+ .numranges = ARRAY_SIZE(_range), .rangemask = (rmask), .dvs = (_dvs), \
+ .sel_mask = (sel) \
+}
+
+static struct bd71837_vrange dvs_buck_vranges[] = {
+ BD_RANGE(700000, 10000, 0, 0x3c, 0),
+ BD_RANGE(1300000, 0, 0x3d, 0x3f, 0),
+};
+
+static struct bd71837_vrange bd71847_buck3_vranges[] = {
+ BD_RANGE(700000, 100000, 0x00, 0x03, 0),
+ BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
+ BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
+ BD_RANGE(550000, 50000, 0x0, 0x7, 0x40),
+ BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
+ BD_RANGE(1025000, 50000, 0x4, 0x5, 0x80),
+ BD_RANGE(1175000, 150000, 0x6, 0x7, 0x80),
+};
+
+static struct bd71837_vrange bd71847_buck4_vranges[] = {
+ BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+ BD_RANGE(2600000, 100000, 0x00, 0x03, 40),
+};
+
+static struct bd71837_vrange bd71837_buck5_vranges[] = {
+ BD_RANGE(700000, 100000, 0, 0x3, 0),
+ BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
+ BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
+ BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
+ BD_RANGE(1025000, 50000, 0x04, 0x05, 0x80),
+ BD_RANGE(1175000, 150000, 0x06, 0x07, 0x80),
+};
+
+static struct bd71837_vrange bd71837_buck6_vranges[] = {
+ BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+};
+
+static struct bd71837_vrange nodvs_buck3_vranges[] = {
+ BD_RANGE(1605000, 90000, 0, 1, 0),
+ BD_RANGE(1755000, 45000, 2, 4, 0),
+ BD_RANGE(1905000, 45000, 5, 7, 0),
+};
+
+static struct bd71837_vrange nodvs_buck4_vranges[] = {
+ BD_RANGE(800000, 10000, 0x00, 0x3C, 0),
+};
+
+static struct bd71837_vrange ldo1_vranges[] = {
+ BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
+ BD_RANGE(1600000, 100000, 0x00, 0x03, 0x20),
+};
+
+static struct bd71837_vrange ldo2_vranges[] = {
+ BD_RANGE(900000, 0, 0, 0, 0),
+ BD_RANGE(800000, 0, 1, 1, 0),
+};
+
+static struct bd71837_vrange ldo3_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+static struct bd71837_vrange ldo4_vranges[] = {
+ BD_RANGE(900000, 100000, 0x00, 0x09, 0),
+};
+
+static struct bd71837_vrange bd71837_ldo5_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+static struct bd71837_vrange bd71847_ldo5_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+ BD_RANGE(800000, 100000, 0x00, 0x0f, 0x20),
+};
+
+static struct bd71837_vrange ldo6_vranges[] = {
+ BD_RANGE(900000, 100000, 0x00, 0x09, 0),
+};
+
+static struct bd71837_vrange ldo7_vranges[] = {
+ BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
+};
+
+/*
+ * We use enable mask 'HW_STATE_CONTROL' to indicate that this regulator
+ * must not be enabled or disabled by SW. The typical use-case for BD71837
+ * is powering NXP i.MX8. In this use-case we (for now) only allow control
+ * for BUCK3 and BUCK4 which are not boot critical.
+ */
+static struct bd71837_platdata bd71837_reg_data[] = {
+/* Bucks 1-4 which support dynamic voltage scaling */
+ BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK3", BD71837_BUCK3_CTRL, BD718XX_BUCK_EN,
+ BD71837_BUCK3_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK4", BD71837_BUCK4_CTRL, BD718XX_BUCK_EN,
+ BD71837_BUCK4_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+/* Bucks 5-8 which do not support dynamic voltage scaling */
+ BD_DATA("BUCK5", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
+ bd71837_buck5_vranges, 0x80, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK6", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
+ bd71837_buck6_vranges, 0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK7", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
+ nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK8", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
+ nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
+/* LDOs */
+ BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
+ BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
+ BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
+ BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
+ BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
+ BD71837_LDO5_MASK, bd71837_ldo5_vranges, 0, false,
+ BD718XX_LDO_SEL),
+ BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
+ BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO7", BD71837_LDO7_VOLT, HW_STATE_CONTROL, BD71837_LDO7_VOLT,
+ BD71837_LDO7_MASK, ldo7_vranges, 0, false, BD718XX_LDO_SEL),
+};
+
+static struct bd71837_platdata bd71847_reg_data[] = {
+/* Bucks 1 and 2 which support dynamic voltage scaling */
+ BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
+ BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
+ true, BD718XX_BUCK_SEL),
+/* Bucks 3-6 which do not support dynamic voltage scaling */
+ BD_DATA("BUCK3", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
+ bd71847_buck3_vranges, 0xc0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK4", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
+ bd71847_buck4_vranges, 0x40, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK5", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
+ nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
+ BD_DATA("BUCK6", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
+ BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
+ nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
+/* LDOs */
+ BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
+ BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
+ BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
+ BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
+ BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
+ BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
+ BD71847_LDO5_MASK, bd71847_ldo5_vranges, 0x20, false,
+ BD718XX_LDO_SEL),
+ BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
+ BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
+};
+
+static int vrange_find_value(struct bd71837_vrange *r, unsigned int sel,
+ unsigned int *val)
+{
+ if (!val || sel < r->min_sel || sel > r->max_sel)
+ return -EINVAL;
+
+ *val = r->min_volt + r->step * (sel - r->min_sel);
+ return 0;
+}
+
+static int vrange_find_selector(struct bd71837_vrange *r, int val,
+ unsigned int *sel)
+{
+ int ret = -EINVAL;
+ int num_vals = r->max_sel - r->min_sel + 1;
+
+ if (val >= r->min_volt &&
+ val <= r->min_volt + r->step * (num_vals - 1)) {
+ if (r->step) {
+ *sel = r->min_sel + ((val - r->min_volt) / r->step);
+ ret = 0;
+ } else {
+ *sel = r->min_sel;
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int bd71837_get_enable(struct udevice *dev)
+{
+ int val;
+ struct bd71837_platdata *plat = dev_get_platdata(dev);
+
+ /*
+ * boot critical regulators on bd71837 must not be controlled by sw
+ * due to the 'feature' which leaves power rails down if bd71837 is
+ * reseted to snvs state. hence we can't get the state here.
+ *
+ * if we are alive it means we probably are on run state and
+ * if the regulator can't be controlled we can assume it is
+ * enabled.
+ */
+ if (plat->enablemask == HW_STATE_CONTROL)
+ return 1;
+
+ val = pmic_reg_read(dev->parent, plat->enable_reg);
+ if (val < 0)
+ return val;
+
+ return (val & plat->enablemask);
+}
+
+static int bd71837_set_enable(struct udevice *dev, bool enable)
+{
+ int val = 0;
+ struct bd71837_platdata *plat = dev_get_platdata(dev);
+
+ /*
+ * boot critical regulators on bd71837 must not be controlled by sw
+ * due to the 'feature' which leaves power rails down if bd71837 is
+ * reseted to snvs state. Hence we can't set the state here.
+ */
+ if (plat->enablemask == HW_STATE_CONTROL)
+ return -EINVAL;
+
+ if (enable)
+ val = plat->enablemask;
+
+ return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
+ val);
+}
+
+static int bd71837_set_value(struct udevice *dev, int uvolt)
+{
+ unsigned int sel;
+ unsigned int range;
+ int i;
+ int found = 0;
+ struct bd71837_platdata *plat = dev_get_platdata(dev);
+
+ /*
+ * An under/overshooting may occur if voltage is changed for other
+ * regulators but buck 1,2,3 or 4 when regulator is enabled. Prevent
+ * change to protect the HW
+ */
+ if (!plat->dvs)
+ if (bd71837_get_enable(dev)) {
+ pr_err("Only DVS bucks can be changed when enabled\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < plat->numranges; i++) {
+ struct bd71837_vrange *r = &plat->ranges[i];
+
+ found = !vrange_find_selector(r, uvolt, &sel);
+ if (found) {
+ unsigned int tmp;
+
+ /*
+ * We require exactly the requested value to be
+ * supported - this can be changed later if needed
+ */
+ range = r->rangeval;
+ found = !vrange_find_value(r, sel, &tmp);
+ if (found && tmp == uvolt)
+ break;
+ found = 0;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ sel <<= ffs(plat->volt_mask) - 1;
+
+ if (plat->rangemask)
+ sel |= range;
+
+ return pmic_clrsetbits(dev->parent, plat->volt_reg, plat->volt_mask |
+ plat->rangemask, sel);
+}
+
+static int bd71837_get_value(struct udevice *dev)
+{
+ unsigned int reg, range;
+ unsigned int tmp;
+ struct bd71837_platdata *plat = dev_get_platdata(dev);
+ int i;
+
+ reg = pmic_reg_read(dev->parent, plat->volt_reg);
+ if (((int)reg) < 0)
+ return reg;
+
+ range = reg & plat->rangemask;
+
+ reg &= plat->volt_mask;
+ reg >>= ffs(plat->volt_mask) - 1;
+
+ for (i = 0; i < plat->numranges; i++) {
+ struct bd71837_vrange *r = &plat->ranges[i];
+
+ if (plat->rangemask && ((plat->rangemask & range) !=
+ r->rangeval))
+ continue;
+
+ if (!vrange_find_value(r, reg, &tmp))
+ return tmp;
+ }
+
+ pr_err("Unknown voltage value read from pmic\n");
+
+ return -EINVAL;
+}
+
+static int bd71837_regulator_probe(struct udevice *dev)
+{
+ struct bd71837_platdata *plat = dev_get_platdata(dev);
+ int i, ret;
+ struct dm_regulator_uclass_platdata *uc_pdata;
+ int type;
+ struct bd71837_platdata *init_data;
+ int data_amnt;
+
+ type = dev_get_driver_data(dev_get_parent(dev));
+
+ switch (type) {
+ case ROHM_CHIP_TYPE_BD71837:
+ init_data = bd71837_reg_data;
+ data_amnt = ARRAY_SIZE(bd71837_reg_data);
+ break;
+ case ROHM_CHIP_TYPE_BD71847:
+ init_data = bd71847_reg_data;
+ data_amnt = ARRAY_SIZE(bd71847_reg_data);
+ break;
+ default:
+ debug("Unknown PMIC type\n");
+ init_data = NULL;
+ data_amnt = 0;
+ break;
+ }
+
+ for (i = 0; i < data_amnt; i++) {
+ if (!strcmp(dev->name, init_data[i].name)) {
+ *plat = init_data[i];
+ if (plat->enablemask != HW_STATE_CONTROL) {
+ /*
+ * Take the regulator under SW control. Ensure
+ * the initial state matches dt flags and then
+ * write the SEL bit
+ */
+ uc_pdata = dev_get_uclass_platdata(dev);
+ ret = bd71837_set_enable(dev,
+ !!(uc_pdata->boot_on ||
+ uc_pdata->always_on));
+ if (ret)
+ return ret;
+
+ return pmic_clrsetbits(dev->parent,
+ plat->enable_reg,
+ plat->sel_mask,
+ plat->sel_mask);
+ }
+ return 0;
+ }
+ }
+
+ pr_err("Unknown regulator '%s'\n", dev->name);
+
+ return -ENOENT;
+}
+
+static const struct dm_regulator_ops bd71837_regulator_ops = {
+ .get_value = bd71837_get_value,
+ .set_value = bd71837_set_value,
+ .get_enable = bd71837_get_enable,
+ .set_enable = bd71837_set_enable,
+};
+
+U_BOOT_DRIVER(bd71837_regulator) = {
+ .name = BD718XX_REGULATOR_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &bd71837_regulator_ops,
+ .probe = bd71837_regulator_probe,
+ .platdata_auto_alloc_size = sizeof(struct bd71837_platdata),
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 2984b797663..1f36fc78fa7 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,11 @@ config PWM_EXYNOS
used. It provides 5 channels which can be independently
programmed. Channel 4 (the last) is normally used as a timer.
+config PWM_IMX
+ bool "Enable support for i.MX27 and later PWM"
+ help
+ This PWM is found i.MX27 and later i.MX SoCs.
+
config PWM_ROCKCHIP
bool "Enable support for the Rockchip PWM"
depends on DM_PWM
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 83c1bfa8206..8d8f3e6f9f9 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <div64.h>
+#include <dm.h>
#include <pwm.h>
#include <asm/arch/imx-regs.h>
#include <asm/io.h>
@@ -24,18 +25,12 @@ int pwm_init(int pwm_id, int div, int invert)
return 0;
}
-int pwm_config(int pwm_id, int duty_ns, int period_ns)
+int pwm_config_internal(struct pwm_regs *pwm, unsigned long period_cycles,
+ unsigned long duty_cycles, unsigned long prescale)
{
- struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
- unsigned long period_cycles, duty_cycles, prescale;
u32 cr;
- if (!pwm)
- return -1;
-
- pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
- &prescale);
-
+ writel(0, &pwm->ir);
cr = PWMCR_PRESCALER(prescale) |
PWMCR_DOZEEN | PWMCR_WAITEN |
PWMCR_DBGEN | PWMCR_CLKSRC_IPG_HIGH;
@@ -48,6 +43,20 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns)
return 0;
}
+int pwm_config(int pwm_id, int duty_ns, int period_ns)
+{
+ struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
+ unsigned long period_cycles, duty_cycles, prescale;
+
+ if (!pwm)
+ return -1;
+
+ pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
+ &prescale);
+
+ return pwm_config_internal(pwm, period_cycles, duty_cycles, prescale);
+}
+
int pwm_enable(int pwm_id)
{
struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
@@ -68,3 +77,86 @@ void pwm_disable(int pwm_id)
clrbits_le32(&pwm->cr, PWMCR_EN);
}
+
+#if defined(CONFIG_DM_PWM)
+struct imx_pwm_priv {
+ struct pwm_regs *regs;
+ bool invert;
+};
+
+static int imx_pwm_set_invert(struct udevice *dev, uint channel,
+ bool polarity)
+{
+ struct imx_pwm_priv *priv = dev_get_priv(dev);
+
+ debug("%s: polarity=%u\n", __func__, polarity);
+ priv->invert = polarity;
+
+ return 0;
+}
+
+static int imx_pwm_set_config(struct udevice *dev, uint channel,
+ uint period_ns, uint duty_ns)
+{
+ struct imx_pwm_priv *priv = dev_get_priv(dev);
+ struct pwm_regs *regs = priv->regs;
+ unsigned long period_cycles, duty_cycles, prescale;
+
+ debug("%s: Config '%s' channel: %d\n", __func__, dev->name, channel);
+
+ pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles,
+ &prescale);
+
+ return pwm_config_internal(regs, period_cycles, duty_cycles, prescale);
+};
+
+static int imx_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+ struct imx_pwm_priv *priv = dev_get_priv(dev);
+ struct pwm_regs *regs = priv->regs;
+
+ debug("%s: Enable '%s' state: %d\n", __func__, dev->name, enable);
+
+ if (enable)
+ setbits_le32(&regs->cr, PWMCR_EN);
+ else
+ clrbits_le32(&regs->cr, PWMCR_EN);
+
+ return 0;
+};
+
+static int imx_pwm_ofdata_to_platdata(struct udevice *dev)
+{
+ struct imx_pwm_priv *priv = dev_get_priv(dev);
+
+ priv->regs = (struct pwm_regs *)devfdt_get_addr(dev);
+
+ return 0;
+}
+
+static int imx_pwm_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct pwm_ops imx_pwm_ops = {
+ .set_invert = imx_pwm_set_invert,
+ .set_config = imx_pwm_set_config,
+ .set_enable = imx_pwm_set_enable,
+};
+
+static const struct udevice_id imx_pwm_ids[] = {
+ { .compatible = "fsl,imx27-pwm" },
+ { }
+};
+
+U_BOOT_DRIVER(imx_pwm) = {
+ .name = "imx_pwm",
+ .id = UCLASS_PWM,
+ .of_match = imx_pwm_ids,
+ .ops = &imx_pwm_ops,
+ .ofdata_to_platdata = imx_pwm_ofdata_to_platdata,
+ .probe = imx_pwm_probe,
+ .priv_auto_alloc_size = sizeof(struct imx_pwm_priv),
+};
+#endif
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index fbf7d7b20fb..568d8f2c6a9 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -54,4 +54,5 @@ config K3_AM654_DDRSS
config add support for the initialization of the external
SDRAM devices connected to DDR subsystem.
+source "drivers/ram/rockchip/Kconfig"
source "drivers/ram/stm32mp1/Kconfig"
diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig
new file mode 100644
index 00000000000..4f274e01b35
--- /dev/null
+++ b/drivers/ram/rockchip/Kconfig
@@ -0,0 +1,33 @@
+config RAM_ROCKCHIP
+ bool "Ram drivers support for Rockchip SoCs"
+ depends on RAM && ARCH_ROCKCHIP
+ default y
+ help
+ This enables support for ram drivers Rockchip SoCs.
+
+if RAM_ROCKCHIP
+
+config RAM_ROCKCHIP_DEBUG
+ bool "Rockchip ram drivers debugging"
+ help
+ This enables debugging ram driver API's for the platforms
+ based on Rockchip SoCs.
+
+ This is an option for developers to understand the ram drivers
+ initialization, configurations and etc.
+
+config RAM_RK3399
+ bool "Ram driver for Rockchip RK3399"
+ default ROCKCHIP_RK3399
+ help
+ This enables ram drivers support for the platforms based on
+ Rockchip RK3399 SoC.
+
+config RAM_RK3399_LPDDR4
+ bool "LPDDR4 support for Rockchip RK3399"
+ depends on RAM_RK3399
+ help
+ This enables LPDDR4 sdram code support for the platforms based
+ on Rockchip RK3399 SoC.
+
+endif # RAM_ROCKCHIP
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index 5df196066da..feb1f82d007 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -3,10 +3,11 @@
# Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
#
+obj-$(CONFIG_RAM_ROCKCHIP_DEBUG) += sdram_debug.o
obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o
obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o
obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o
obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o
-obj-$(CONFIG_ROCKCHIP_RK3399) = sdram_rk3399.o
+obj-$(CONFIG_RAM_RK3399) += sdram_rk3399.o
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
new file mode 100644
index 00000000000..c50a03d9dd2
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-400.inc
@@ -0,0 +1,1570 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd.
+ * (C) Copyright 2019 Amarula Solutions
+ */
+
+{
+ {
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ },
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ }
+ },
+ {
+ .ddr_freq = 400 * MHz,
+ .dramtype = LPDDR4,
+ .num_channels = 2,
+ .stride = 13,
+ .odt = 1,
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_CTL_00_DATA */
+ 0x00000000, /* DENALI_CTL_01_DATA */
+ 0x00000000, /* DENALI_CTL_02_DATA */
+ 0x00000000, /* DENALI_CTL_03_DATA */
+ 0x00000000, /* DENALI_CTL_04_DATA */
+ 0x00013880, /* DENALI_CTL_05_DATA */
+ 0x000c3500, /* DENALI_CTL_06_DATA */
+ 0x00000005, /* DENALI_CTL_07_DATA */
+ 0x00000320, /* DENALI_CTL_08_DATA */
+ 0x00027100, /* DENALI_CTL_09_DATA */
+ 0x00186a00, /* DENALI_CTL_10_DATA */
+ 0x00000005, /* DENALI_CTL_11_DATA */
+ 0x00000640, /* DENALI_CTL_12_DATA */
+ 0x00002710, /* DENALI_CTL_13_DATA */
+ 0x000186a0, /* DENALI_CTL_14_DATA */
+ 0x00000005, /* DENALI_CTL_15_DATA */
+ 0x01000064, /* DENALI_CTL_16_DATA */
+ 0x00000000, /* DENALI_CTL_17_DATA */
+ 0x02020101, /* DENALI_CTL_18_DATA */
+ 0x00000102, /* DENALI_CTL_19_DATA */
+ 0x00000050, /* DENALI_CTL_20_DATA */
+ 0x000000c8, /* DENALI_CTL_21_DATA */
+ 0x00000000, /* DENALI_CTL_22_DATA */
+ 0x06140000, /* DENALI_CTL_23_DATA */
+ 0x00081c00, /* DENALI_CTL_24_DATA */
+ 0x0400040c, /* DENALI_CTL_25_DATA */
+ 0x19042008, /* DENALI_CTL_26_DATA */
+ 0x10080a11, /* DENALI_CTL_27_DATA */
+ 0x22310800, /* DENALI_CTL_28_DATA */
+ 0x00200f0a, /* DENALI_CTL_29_DATA */
+ 0x0a030704, /* DENALI_CTL_30_DATA */
+ 0x08000204, /* DENALI_CTL_31_DATA */
+ 0x00000a0a, /* DENALI_CTL_32_DATA */
+ 0x04006db0, /* DENALI_CTL_33_DATA */
+ 0x0a0a0804, /* DENALI_CTL_34_DATA */
+ 0x0600db60, /* DENALI_CTL_35_DATA */
+ 0x0a0a0806, /* DENALI_CTL_36_DATA */
+ 0x04000db6, /* DENALI_CTL_37_DATA */
+ 0x02030404, /* DENALI_CTL_38_DATA */
+ 0x0f0a0800, /* DENALI_CTL_39_DATA */
+ 0x08040411, /* DENALI_CTL_40_DATA */
+ 0x1400640a, /* DENALI_CTL_41_DATA */
+ 0x02010a0a, /* DENALI_CTL_42_DATA */
+ 0x00010001, /* DENALI_CTL_43_DATA */
+ 0x04082012, /* DENALI_CTL_44_DATA */
+ 0x00041109, /* DENALI_CTL_45_DATA */
+ 0x00000000, /* DENALI_CTL_46_DATA */
+ 0x03010000, /* DENALI_CTL_47_DATA */
+ 0x06100034, /* DENALI_CTL_48_DATA */
+ 0x0c280068, /* DENALI_CTL_49_DATA */
+ 0x00bb0007, /* DENALI_CTL_50_DATA */
+ 0x00000000, /* DENALI_CTL_51_DATA */
+ 0x00060003, /* DENALI_CTL_52_DATA */
+ 0x000a0003, /* DENALI_CTL_53_DATA */
+ 0x000a0014, /* DENALI_CTL_54_DATA */
+ 0x01000000, /* DENALI_CTL_55_DATA */
+ 0x030a0000, /* DENALI_CTL_56_DATA */
+ 0x0c000002, /* DENALI_CTL_57_DATA */
+ 0x00000103, /* DENALI_CTL_58_DATA */
+ 0x0003030a, /* DENALI_CTL_59_DATA */
+ 0x00060037, /* DENALI_CTL_60_DATA */
+ 0x0003006e, /* DENALI_CTL_61_DATA */
+ 0x05050007, /* DENALI_CTL_62_DATA */
+ 0x03020605, /* DENALI_CTL_63_DATA */
+ 0x06050301, /* DENALI_CTL_64_DATA */
+ 0x06020c05, /* DENALI_CTL_65_DATA */
+ 0x05050302, /* DENALI_CTL_66_DATA */
+ 0x03020305, /* DENALI_CTL_67_DATA */
+ 0x00000301, /* DENALI_CTL_68_DATA */
+ 0x00000301, /* DENALI_CTL_69_DATA */
+ 0x00000001, /* DENALI_CTL_70_DATA */
+ 0x00000000, /* DENALI_CTL_71_DATA */
+ 0x00000000, /* DENALI_CTL_72_DATA */
+ 0x01000000, /* DENALI_CTL_73_DATA */
+ 0x80104002, /* DENALI_CTL_74_DATA */
+ 0x00040003, /* DENALI_CTL_75_DATA */
+ 0x00040005, /* DENALI_CTL_76_DATA */
+ 0x00030000, /* DENALI_CTL_77_DATA */
+ 0x00050004, /* DENALI_CTL_78_DATA */
+ 0x00000004, /* DENALI_CTL_79_DATA */
+ 0x00040003, /* DENALI_CTL_80_DATA */
+ 0x00040005, /* DENALI_CTL_81_DATA */
+ 0x18400000, /* DENALI_CTL_82_DATA */
+ 0x00000c20, /* DENALI_CTL_83_DATA */
+ 0x185030a0, /* DENALI_CTL_84_DATA */
+ 0x02ec0000, /* DENALI_CTL_85_DATA */
+ 0x00000176, /* DENALI_CTL_86_DATA */
+ 0x00000000, /* DENALI_CTL_87_DATA */
+ 0x00000000, /* DENALI_CTL_88_DATA */
+ 0x00000000, /* DENALI_CTL_89_DATA */
+ 0x00000000, /* DENALI_CTL_90_DATA */
+ 0x00000000, /* DENALI_CTL_91_DATA */
+ 0x06030300, /* DENALI_CTL_92_DATA */
+ 0x00030303, /* DENALI_CTL_93_DATA */
+ 0x02030200, /* DENALI_CTL_94_DATA */
+ 0x00040703, /* DENALI_CTL_95_DATA */
+ 0x03020302, /* DENALI_CTL_96_DATA */
+ 0x02000407, /* DENALI_CTL_97_DATA */
+ 0x07030203, /* DENALI_CTL_98_DATA */
+ 0x00030f04, /* DENALI_CTL_99_DATA */
+ 0x00070004, /* DENALI_CTL_100_DATA */
+ 0x00000000, /* DENALI_CTL_101_DATA */
+ 0x00000000, /* DENALI_CTL_102_DATA */
+ 0x00000000, /* DENALI_CTL_103_DATA */
+ 0x00000000, /* DENALI_CTL_104_DATA */
+ 0x00000000, /* DENALI_CTL_105_DATA */
+ 0x00000000, /* DENALI_CTL_106_DATA */
+ 0x00000000, /* DENALI_CTL_107_DATA */
+ 0x00010000, /* DENALI_CTL_108_DATA */
+ 0x20040020, /* DENALI_CTL_109_DATA */
+ 0x00200400, /* DENALI_CTL_110_DATA */
+ 0x01000400, /* DENALI_CTL_111_DATA */
+ 0x00000b80, /* DENALI_CTL_112_DATA */
+ 0x00000000, /* DENALI_CTL_113_DATA */
+ 0x00000001, /* DENALI_CTL_114_DATA */
+ 0x00000002, /* DENALI_CTL_115_DATA */
+ 0x0000000e, /* DENALI_CTL_116_DATA */
+ 0x00000000, /* DENALI_CTL_117_DATA */
+ 0x00000000, /* DENALI_CTL_118_DATA */
+ 0x00000000, /* DENALI_CTL_119_DATA */
+ 0x00000000, /* DENALI_CTL_120_DATA */
+ 0x00000000, /* DENALI_CTL_121_DATA */
+ 0x00500000, /* DENALI_CTL_122_DATA */
+ 0x00640028, /* DENALI_CTL_123_DATA */
+ 0x00640404, /* DENALI_CTL_124_DATA */
+ 0x005000a0, /* DENALI_CTL_125_DATA */
+ 0x060600c8, /* DENALI_CTL_126_DATA */
+ 0x000a00c8, /* DENALI_CTL_127_DATA */
+ 0x000d0005, /* DENALI_CTL_128_DATA */
+ 0x000d0404, /* DENALI_CTL_129_DATA */
+ 0x00000000, /* DENALI_CTL_130_DATA */
+ 0x00000000, /* DENALI_CTL_131_DATA */
+ 0x00000000, /* DENALI_CTL_132_DATA */
+ 0x001400a3, /* DENALI_CTL_133_DATA */
+ 0x00e30009, /* DENALI_CTL_134_DATA */
+ 0x00120024, /* DENALI_CTL_135_DATA */
+ 0x00040063, /* DENALI_CTL_136_DATA */
+ 0x00000000, /* DENALI_CTL_137_DATA */
+ 0x00310031, /* DENALI_CTL_138_DATA */
+ 0x00000031, /* DENALI_CTL_139_DATA */
+ 0x004d0000, /* DENALI_CTL_140_DATA */
+ 0x004d004d, /* DENALI_CTL_141_DATA */
+ 0x004d0000, /* DENALI_CTL_142_DATA */
+ 0x004d004d, /* DENALI_CTL_143_DATA */
+ 0x00010101, /* DENALI_CTL_144_DATA */
+ 0x00000000, /* DENALI_CTL_145_DATA */
+ 0x00000000, /* DENALI_CTL_146_DATA */
+ 0x001400a3, /* DENALI_CTL_147_DATA */
+ 0x00e30009, /* DENALI_CTL_148_DATA */
+ 0x00120024, /* DENALI_CTL_149_DATA */
+ 0x00040063, /* DENALI_CTL_150_DATA */
+ 0x00000000, /* DENALI_CTL_151_DATA */
+ 0x00310031, /* DENALI_CTL_152_DATA */
+ 0x00000031, /* DENALI_CTL_153_DATA */
+ 0x004d0000, /* DENALI_CTL_154_DATA */
+ 0x004d004d, /* DENALI_CTL_155_DATA */
+ 0x004d0000, /* DENALI_CTL_156_DATA */
+ 0x004d004d, /* DENALI_CTL_157_DATA */
+ 0x00010101, /* DENALI_CTL_158_DATA */
+ 0x00000000, /* DENALI_CTL_159_DATA */
+ 0x00000000, /* DENALI_CTL_160_DATA */
+ 0x00000000, /* DENALI_CTL_161_DATA */
+ 0x00000001, /* DENALI_CTL_162_DATA */
+ 0x00000000, /* DENALI_CTL_163_DATA */
+ 0x18151100, /* DENALI_CTL_164_DATA */
+ 0x0000000c, /* DENALI_CTL_165_DATA */
+ 0x00000000, /* DENALI_CTL_166_DATA */
+ 0x00000000, /* DENALI_CTL_167_DATA */
+ 0x00000000, /* DENALI_CTL_168_DATA */
+ 0x00000000, /* DENALI_CTL_169_DATA */
+ 0x00000000, /* DENALI_CTL_170_DATA */
+ 0x00000000, /* DENALI_CTL_171_DATA */
+ 0x00000000, /* DENALI_CTL_172_DATA */
+ 0x00000000, /* DENALI_CTL_173_DATA */
+ 0x00000000, /* DENALI_CTL_174_DATA */
+ 0x00000000, /* DENALI_CTL_175_DATA */
+ 0x00000000, /* DENALI_CTL_176_DATA */
+ 0x00000000, /* DENALI_CTL_177_DATA */
+ 0x00000000, /* DENALI_CTL_178_DATA */
+ 0x00020003, /* DENALI_CTL_179_DATA */
+ 0x00400100, /* DENALI_CTL_180_DATA */
+ 0x000c0190, /* DENALI_CTL_181_DATA */
+ 0x01000200, /* DENALI_CTL_182_DATA */
+ 0x03200040, /* DENALI_CTL_183_DATA */
+ 0x00020018, /* DENALI_CTL_184_DATA */
+ 0x00400100, /* DENALI_CTL_185_DATA */
+ 0x00080032, /* DENALI_CTL_186_DATA */
+ 0x00140000, /* DENALI_CTL_187_DATA */
+ 0x00030028, /* DENALI_CTL_188_DATA */
+ 0x01010100, /* DENALI_CTL_189_DATA */
+ 0x02000202, /* DENALI_CTL_190_DATA */
+ 0x0b000002, /* DENALI_CTL_191_DATA */
+ 0x01000f0f, /* DENALI_CTL_192_DATA */
+ 0x00000000, /* DENALI_CTL_193_DATA */
+ 0x00000000, /* DENALI_CTL_194_DATA */
+ 0x00010003, /* DENALI_CTL_195_DATA */
+ 0x00000c03, /* DENALI_CTL_196_DATA */
+ 0x00040101, /* DENALI_CTL_197_DATA */
+ 0x04010100, /* DENALI_CTL_198_DATA */
+ 0x01000000, /* DENALI_CTL_199_DATA */
+ 0x02010000, /* DENALI_CTL_200_DATA */
+ 0x00000001, /* DENALI_CTL_201_DATA */
+ 0x00000000, /* DENALI_CTL_202_DATA */
+ 0x00000000, /* DENALI_CTL_203_DATA */
+ 0x00000000, /* DENALI_CTL_204_DATA */
+ 0x00000000, /* DENALI_CTL_205_DATA */
+ 0x00000000, /* DENALI_CTL_206_DATA */
+ 0x00000000, /* DENALI_CTL_207_DATA */
+ 0x00000000, /* DENALI_CTL_208_DATA */
+ 0x00000000, /* DENALI_CTL_209_DATA */
+ 0x00000000, /* DENALI_CTL_210_DATA */
+ 0x00010000, /* DENALI_CTL_211_DATA */
+ 0x00000001, /* DENALI_CTL_212_DATA */
+ 0x01010001, /* DENALI_CTL_213_DATA */
+ 0x05040001, /* DENALI_CTL_214_DATA */
+ 0x040a0703, /* DENALI_CTL_215_DATA */
+ 0x02080808, /* DENALI_CTL_216_DATA */
+ 0x020e000a, /* DENALI_CTL_217_DATA */
+ 0x020f010b, /* DENALI_CTL_218_DATA */
+ 0x000d0008, /* DENALI_CTL_219_DATA */
+ 0x00080b0a, /* DENALI_CTL_220_DATA */
+ 0x03000200, /* DENALI_CTL_221_DATA */
+ 0x00000100, /* DENALI_CTL_222_DATA */
+ 0x00000000, /* DENALI_CTL_223_DATA */
+ 0x00000000, /* DENALI_CTL_224_DATA */
+ 0x0d000001, /* DENALI_CTL_225_DATA */
+ 0x00000028, /* DENALI_CTL_226_DATA */
+ 0x00010000, /* DENALI_CTL_227_DATA */
+ 0x00000003, /* DENALI_CTL_228_DATA */
+ 0x00000000, /* DENALI_CTL_229_DATA */
+ 0x00000000, /* DENALI_CTL_230_DATA */
+ 0x00000000, /* DENALI_CTL_231_DATA */
+ 0x00000000, /* DENALI_CTL_232_DATA */
+ 0x00000000, /* DENALI_CTL_233_DATA */
+ 0x00000000, /* DENALI_CTL_234_DATA */
+ 0x00000000, /* DENALI_CTL_235_DATA */
+ 0x00000000, /* DENALI_CTL_236_DATA */
+ 0x00010100, /* DENALI_CTL_237_DATA */
+ 0x01000000, /* DENALI_CTL_238_DATA */
+ 0x00000001, /* DENALI_CTL_239_DATA */
+ 0x00000303, /* DENALI_CTL_240_DATA */
+ 0x00000000, /* DENALI_CTL_241_DATA */
+ 0x00000000, /* DENALI_CTL_242_DATA */
+ 0x00000000, /* DENALI_CTL_243_DATA */
+ 0x00000000, /* DENALI_CTL_244_DATA */
+ 0x00000000, /* DENALI_CTL_245_DATA */
+ 0x00000000, /* DENALI_CTL_246_DATA */
+ 0x00000000, /* DENALI_CTL_247_DATA */
+ 0x00000000, /* DENALI_CTL_248_DATA */
+ 0x00000000, /* DENALI_CTL_249_DATA */
+ 0x00000000, /* DENALI_CTL_250_DATA */
+ 0x00000000, /* DENALI_CTL_251_DATA */
+ 0x00000000, /* DENALI_CTL_252_DATA */
+ 0x00000000, /* DENALI_CTL_253_DATA */
+ 0x00000000, /* DENALI_CTL_254_DATA */
+ 0x00000000, /* DENALI_CTL_255_DATA */
+ 0x000556aa, /* DENALI_CTL_256_DATA */
+ 0x000aaaaa, /* DENALI_CTL_257_DATA */
+ 0x000aa955, /* DENALI_CTL_258_DATA */
+ 0x00055555, /* DENALI_CTL_259_DATA */
+ 0x000b3133, /* DENALI_CTL_260_DATA */
+ 0x0004cd33, /* DENALI_CTL_261_DATA */
+ 0x0004cecc, /* DENALI_CTL_262_DATA */
+ 0x000b32cc, /* DENALI_CTL_263_DATA */
+ 0x00010300, /* DENALI_CTL_264_DATA */
+ 0x03000100, /* DENALI_CTL_265_DATA */
+ 0x00000000, /* DENALI_CTL_266_DATA */
+ 0x00000000, /* DENALI_CTL_267_DATA */
+ 0x00000000, /* DENALI_CTL_268_DATA */
+ 0x00000000, /* DENALI_CTL_269_DATA */
+ 0x00000000, /* DENALI_CTL_270_DATA */
+ 0x00000000, /* DENALI_CTL_271_DATA */
+ 0x00000000, /* DENALI_CTL_272_DATA */
+ 0x00000000, /* DENALI_CTL_273_DATA */
+ 0x00ffff00, /* DENALI_CTL_274_DATA */
+ 0x1a160000, /* DENALI_CTL_275_DATA */
+ 0x08000012, /* DENALI_CTL_276_DATA */
+ 0x00000c20, /* DENALI_CTL_277_DATA */
+ 0x00000200, /* DENALI_CTL_278_DATA */
+ 0x00000200, /* DENALI_CTL_279_DATA */
+ 0x00000200, /* DENALI_CTL_280_DATA */
+ 0x00000200, /* DENALI_CTL_281_DATA */
+ 0x00000c20, /* DENALI_CTL_282_DATA */
+ 0x00007940, /* DENALI_CTL_283_DATA */
+ 0x18500409, /* DENALI_CTL_284_DATA */
+ 0x00000200, /* DENALI_CTL_285_DATA */
+ 0x00000200, /* DENALI_CTL_286_DATA */
+ 0x00000200, /* DENALI_CTL_287_DATA */
+ 0x00000200, /* DENALI_CTL_288_DATA */
+ 0x00001850, /* DENALI_CTL_289_DATA */
+ 0x0000f320, /* DENALI_CTL_290_DATA */
+ 0x0176060c, /* DENALI_CTL_291_DATA */
+ 0x00000200, /* DENALI_CTL_292_DATA */
+ 0x00000200, /* DENALI_CTL_293_DATA */
+ 0x00000200, /* DENALI_CTL_294_DATA */
+ 0x00000200, /* DENALI_CTL_295_DATA */
+ 0x00000176, /* DENALI_CTL_296_DATA */
+ 0x00000e9c, /* DENALI_CTL_297_DATA */
+ 0x02020205, /* DENALI_CTL_298_DATA */
+ 0x03030202, /* DENALI_CTL_299_DATA */
+ 0x00000018, /* DENALI_CTL_300_DATA */
+ 0x00000000, /* DENALI_CTL_301_DATA */
+ 0x00000000, /* DENALI_CTL_302_DATA */
+ 0x00001403, /* DENALI_CTL_303_DATA */
+ 0x00000000, /* DENALI_CTL_304_DATA */
+ 0x00000000, /* DENALI_CTL_305_DATA */
+ 0x00000000, /* DENALI_CTL_306_DATA */
+ 0x00030000, /* DENALI_CTL_307_DATA */
+ 0x000a001c, /* DENALI_CTL_308_DATA */
+ 0x000e0020, /* DENALI_CTL_309_DATA */
+ 0x00060018, /* DENALI_CTL_310_DATA */
+ 0x00000000, /* DENALI_CTL_311_DATA */
+ 0x00000000, /* DENALI_CTL_312_DATA */
+ 0x02000000, /* DENALI_CTL_313_DATA */
+ 0x00090305, /* DENALI_CTL_314_DATA */
+ 0x00050101, /* DENALI_CTL_315_DATA */
+ 0x00000000, /* DENALI_CTL_316_DATA */
+ 0x00000000, /* DENALI_CTL_317_DATA */
+ 0x00000000, /* DENALI_CTL_318_DATA */
+ 0x00000000, /* DENALI_CTL_319_DATA */
+ 0x00000000, /* DENALI_CTL_320_DATA */
+ 0x00000000, /* DENALI_CTL_321_DATA */
+ 0x00000000, /* DENALI_CTL_322_DATA */
+ 0x00000000, /* DENALI_CTL_323_DATA */
+ 0x01000001, /* DENALI_CTL_324_DATA */
+ 0x01010101, /* DENALI_CTL_325_DATA */
+ 0x01000101, /* DENALI_CTL_326_DATA */
+ 0x01000100, /* DENALI_CTL_327_DATA */
+ 0x00010001, /* DENALI_CTL_328_DATA */
+ 0x00010002, /* DENALI_CTL_329_DATA */
+ 0x00020100, /* DENALI_CTL_330_DATA */
+ 0x00000002 /* DENALI_CTL_331_DATA */
+ }
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_PI_00_DATA */
+ 0x00000000, /* DENALI_PI_01_DATA */
+ 0x000002ec, /* DENALI_PI_02_DATA */
+ 0x00000176, /* DENALI_PI_03_DATA */
+ 0x000030a0, /* DENALI_PI_04_DATA */
+ 0x00001850, /* DENALI_PI_05_DATA */
+ 0x00001840, /* DENALI_PI_06_DATA */
+ 0x01760c20, /* DENALI_PI_07_DATA */
+ 0x00000200, /* DENALI_PI_08_DATA */
+ 0x00000200, /* DENALI_PI_09_DATA */
+ 0x00000200, /* DENALI_PI_10_DATA */
+ 0x00000200, /* DENALI_PI_11_DATA */
+ 0x00001850, /* DENALI_PI_12_DATA */
+ 0x00000200, /* DENALI_PI_13_DATA */
+ 0x00000200, /* DENALI_PI_14_DATA */
+ 0x00000200, /* DENALI_PI_15_DATA */
+ 0x00000200, /* DENALI_PI_16_DATA */
+ 0x00000c20, /* DENALI_PI_17_DATA */
+ 0x00000200, /* DENALI_PI_18_DATA */
+ 0x00000200, /* DENALI_PI_19_DATA */
+ 0x00000200, /* DENALI_PI_20_DATA */
+ 0x00000200, /* DENALI_PI_21_DATA */
+ 0x00010000, /* DENALI_PI_22_DATA */
+ 0x00000007, /* DENALI_PI_23_DATA */
+ 0x01000001, /* DENALI_PI_24_DATA */
+ 0x00000000, /* DENALI_PI_25_DATA */
+ 0x3fffffff, /* DENALI_PI_26_DATA */
+ 0x00000000, /* DENALI_PI_27_DATA */
+ 0x00000000, /* DENALI_PI_28_DATA */
+ 0x00000000, /* DENALI_PI_29_DATA */
+ 0x00000000, /* DENALI_PI_30_DATA */
+ 0x00000000, /* DENALI_PI_31_DATA */
+ 0x00000000, /* DENALI_PI_32_DATA */
+ 0x00000000, /* DENALI_PI_33_DATA */
+ 0x00000000, /* DENALI_PI_34_DATA */
+ 0x00000000, /* DENALI_PI_35_DATA */
+ 0x00000000, /* DENALI_PI_36_DATA */
+ 0x00000000, /* DENALI_PI_37_DATA */
+ 0x00000000, /* DENALI_PI_38_DATA */
+ 0x00000000, /* DENALI_PI_39_DATA */
+ 0x00000000, /* DENALI_PI_40_DATA */
+ 0x0f000101, /* DENALI_PI_41_DATA */
+ 0x082b3223, /* DENALI_PI_42_DATA */
+ 0x080c0004, /* DENALI_PI_43_DATA */
+ 0x00061c00, /* DENALI_PI_44_DATA */
+ 0x00000214, /* DENALI_PI_45_DATA */
+ 0x00bb0007, /* DENALI_PI_46_DATA */
+ 0x0c280068, /* DENALI_PI_47_DATA */
+ 0x06100034, /* DENALI_PI_48_DATA */
+ 0x00000500, /* DENALI_PI_49_DATA */
+ 0x00000000, /* DENALI_PI_50_DATA */
+ 0x00000000, /* DENALI_PI_51_DATA */
+ 0x00000000, /* DENALI_PI_52_DATA */
+ 0x00000000, /* DENALI_PI_53_DATA */
+ 0x00000000, /* DENALI_PI_54_DATA */
+ 0x00000000, /* DENALI_PI_55_DATA */
+ 0x00000000, /* DENALI_PI_56_DATA */
+ 0x00000000, /* DENALI_PI_57_DATA */
+ 0x04040100, /* DENALI_PI_58_DATA */
+ 0x0a000004, /* DENALI_PI_59_DATA */
+ 0x00000128, /* DENALI_PI_60_DATA */
+ 0x00000000, /* DENALI_PI_61_DATA */
+ 0x0003000f, /* DENALI_PI_62_DATA */
+ 0x00000018, /* DENALI_PI_63_DATA */
+ 0x00000000, /* DENALI_PI_64_DATA */
+ 0x00000000, /* DENALI_PI_65_DATA */
+ 0x00060002, /* DENALI_PI_66_DATA */
+ 0x00010001, /* DENALI_PI_67_DATA */
+ 0x00000101, /* DENALI_PI_68_DATA */
+ 0x00020001, /* DENALI_PI_69_DATA */
+ 0x00080004, /* DENALI_PI_70_DATA */
+ 0x00000000, /* DENALI_PI_71_DATA */
+ 0x05030000, /* DENALI_PI_72_DATA */
+ 0x070a0404, /* DENALI_PI_73_DATA */
+ 0x00000000, /* DENALI_PI_74_DATA */
+ 0x00000000, /* DENALI_PI_75_DATA */
+ 0x00000000, /* DENALI_PI_76_DATA */
+ 0x000f0f00, /* DENALI_PI_77_DATA */
+ 0x0000001e, /* DENALI_PI_78_DATA */
+ 0x00000000, /* DENALI_PI_79_DATA */
+ 0x01010300, /* DENALI_PI_80_DATA */
+ 0x00000000, /* DENALI_PI_81_DATA */
+ 0x00000000, /* DENALI_PI_82_DATA */
+ 0x01000000, /* DENALI_PI_83_DATA */
+ 0x00000101, /* DENALI_PI_84_DATA */
+ 0x55555a5a, /* DENALI_PI_85_DATA */
+ 0x55555a5a, /* DENALI_PI_86_DATA */
+ 0x55555a5a, /* DENALI_PI_87_DATA */
+ 0x55555a5a, /* DENALI_PI_88_DATA */
+ 0x0c050001, /* DENALI_PI_89_DATA */
+ 0x06020009, /* DENALI_PI_90_DATA */
+ 0x00010004, /* DENALI_PI_91_DATA */
+ 0x00000203, /* DENALI_PI_92_DATA */
+ 0x00030000, /* DENALI_PI_93_DATA */
+ 0x170f0000, /* DENALI_PI_94_DATA */
+ 0x00060018, /* DENALI_PI_95_DATA */
+ 0x000e0020, /* DENALI_PI_96_DATA */
+ 0x000a001c, /* DENALI_PI_97_DATA */
+ 0x00000000, /* DENALI_PI_98_DATA */
+ 0x00000000, /* DENALI_PI_99_DATA */
+ 0x00000100, /* DENALI_PI_100_DATA */
+ 0x140a0000, /* DENALI_PI_101_DATA */
+ 0x000d010a, /* DENALI_PI_102_DATA */
+ 0x0100c802, /* DENALI_PI_103_DATA */
+ 0x010a0064, /* DENALI_PI_104_DATA */
+ 0x000e0100, /* DENALI_PI_105_DATA */
+ 0x0100000e, /* DENALI_PI_106_DATA */
+ 0x00c900c9, /* DENALI_PI_107_DATA */
+ 0x00650100, /* DENALI_PI_108_DATA */
+ 0x1e1a0065, /* DENALI_PI_109_DATA */
+ 0x10010204, /* DENALI_PI_110_DATA */
+ 0x06070605, /* DENALI_PI_111_DATA */
+ 0x20000202, /* DENALI_PI_112_DATA */
+ 0x00201000, /* DENALI_PI_113_DATA */
+ 0x00201000, /* DENALI_PI_114_DATA */
+ 0x04041000, /* DENALI_PI_115_DATA */
+ 0x10020100, /* DENALI_PI_116_DATA */
+ 0x0003010c, /* DENALI_PI_117_DATA */
+ 0x004b004a, /* DENALI_PI_118_DATA */
+ 0x1a0f0000, /* DENALI_PI_119_DATA */
+ 0x0102041e, /* DENALI_PI_120_DATA */
+ 0x34000000, /* DENALI_PI_121_DATA */
+ 0x00000000, /* DENALI_PI_122_DATA */
+ 0x00000000, /* DENALI_PI_123_DATA */
+ 0x00010000, /* DENALI_PI_124_DATA */
+ 0x00000400, /* DENALI_PI_125_DATA */
+ 0x00310000, /* DENALI_PI_126_DATA */
+ 0x004d4d00, /* DENALI_PI_127_DATA */
+ 0x00120024, /* DENALI_PI_128_DATA */
+ 0x4d000031, /* DENALI_PI_129_DATA */
+ 0x0000144d, /* DENALI_PI_130_DATA */
+ 0x00310009, /* DENALI_PI_131_DATA */
+ 0x004d4d00, /* DENALI_PI_132_DATA */
+ 0x00000004, /* DENALI_PI_133_DATA */
+ 0x4d000031, /* DENALI_PI_134_DATA */
+ 0x0000244d, /* DENALI_PI_135_DATA */
+ 0x00310012, /* DENALI_PI_136_DATA */
+ 0x004d4d00, /* DENALI_PI_137_DATA */
+ 0x00090014, /* DENALI_PI_138_DATA */
+ 0x4d000031, /* DENALI_PI_139_DATA */
+ 0x0004004d, /* DENALI_PI_140_DATA */
+ 0x00310000, /* DENALI_PI_141_DATA */
+ 0x004d4d00, /* DENALI_PI_142_DATA */
+ 0x00120024, /* DENALI_PI_143_DATA */
+ 0x4d000031, /* DENALI_PI_144_DATA */
+ 0x0000144d, /* DENALI_PI_145_DATA */
+ 0x00310009, /* DENALI_PI_146_DATA */
+ 0x004d4d00, /* DENALI_PI_147_DATA */
+ 0x00000004, /* DENALI_PI_148_DATA */
+ 0x4d000031, /* DENALI_PI_149_DATA */
+ 0x0000244d, /* DENALI_PI_150_DATA */
+ 0x00310012, /* DENALI_PI_151_DATA */
+ 0x004d4d00, /* DENALI_PI_152_DATA */
+ 0x00090014, /* DENALI_PI_153_DATA */
+ 0x4d000031, /* DENALI_PI_154_DATA */
+ 0x0200004d, /* DENALI_PI_155_DATA */
+ 0x00c8000d, /* DENALI_PI_156_DATA */
+ 0x08080064, /* DENALI_PI_157_DATA */
+ 0x040a0404, /* DENALI_PI_158_DATA */
+ 0x03000d92, /* DENALI_PI_159_DATA */
+ 0x010a2001, /* DENALI_PI_160_DATA */
+ 0x0f11080a, /* DENALI_PI_161_DATA */
+ 0x0000110a, /* DENALI_PI_162_DATA */
+ 0x2200d92e, /* DENALI_PI_163_DATA */
+ 0x080c2003, /* DENALI_PI_164_DATA */
+ 0x0809080a, /* DENALI_PI_165_DATA */
+ 0x00000a0a, /* DENALI_PI_166_DATA */
+ 0x11006c97, /* DENALI_PI_167_DATA */
+ 0x040a2002, /* DENALI_PI_168_DATA */
+ 0x0200020a, /* DENALI_PI_169_DATA */
+ 0x02000200, /* DENALI_PI_170_DATA */
+ 0x02000200, /* DENALI_PI_171_DATA */
+ 0x02000200, /* DENALI_PI_172_DATA */
+ 0x02000200, /* DENALI_PI_173_DATA */
+ 0x00000000, /* DENALI_PI_174_DATA */
+ 0x00000000, /* DENALI_PI_175_DATA */
+ 0x00000000, /* DENALI_PI_176_DATA */
+ 0x00000000, /* DENALI_PI_177_DATA */
+ 0x00000000, /* DENALI_PI_178_DATA */
+ 0x00000000, /* DENALI_PI_179_DATA */
+ 0x00000000, /* DENALI_PI_180_DATA */
+ 0x00000000, /* DENALI_PI_181_DATA */
+ 0x00000000, /* DENALI_PI_182_DATA */
+ 0x00000000, /* DENALI_PI_183_DATA */
+ 0x00000000, /* DENALI_PI_184_DATA */
+ 0x00000000, /* DENALI_PI_185_DATA */
+ 0x01000400, /* DENALI_PI_186_DATA */
+ 0x00017600, /* DENALI_PI_187_DATA */
+ 0x00000e9c, /* DENALI_PI_188_DATA */
+ 0x00001850, /* DENALI_PI_189_DATA */
+ 0x0000f320, /* DENALI_PI_190_DATA */
+ 0x00000c20, /* DENALI_PI_191_DATA */
+ 0x00007940, /* DENALI_PI_192_DATA */
+ 0x08000000, /* DENALI_PI_193_DATA */
+ 0x00000100, /* DENALI_PI_194_DATA */
+ 0x00000000, /* DENALI_PI_195_DATA */
+ 0x00000000, /* DENALI_PI_196_DATA */
+ 0x00000000, /* DENALI_PI_197_DATA */
+ 0x00000000, /* DENALI_PI_198_DATA */
+ 0x00000002 /* DENALI_PI_199_DATA */
+ }
+ },
+ {
+ {
+ 0x76543210, /* DENALI_PHY_00_DATA */
+ 0x0004f008, /* DENALI_PHY_01_DATA */
+ 0x00020119, /* DENALI_PHY_02_DATA */
+ 0x00000000, /* DENALI_PHY_03_DATA */
+ 0x00000000, /* DENALI_PHY_04_DATA */
+ 0x00010000, /* DENALI_PHY_05_DATA */
+ 0x01665555, /* DENALI_PHY_06_DATA */
+ 0x03665555, /* DENALI_PHY_07_DATA */
+ 0x00010f00, /* DENALI_PHY_08_DATA */
+ 0x04000100, /* DENALI_PHY_09_DATA */
+ 0x00000001, /* DENALI_PHY_10_DATA */
+ 0x00170180, /* DENALI_PHY_11_DATA */
+ 0x00cc0201, /* DENALI_PHY_12_DATA */
+ 0x00030066, /* DENALI_PHY_13_DATA */
+ 0x00000000, /* DENALI_PHY_14_DATA */
+ 0x00000000, /* DENALI_PHY_15_DATA */
+ 0x00000000, /* DENALI_PHY_16_DATA */
+ 0x00000000, /* DENALI_PHY_17_DATA */
+ 0x00000000, /* DENALI_PHY_18_DATA */
+ 0x00000000, /* DENALI_PHY_19_DATA */
+ 0x00000000, /* DENALI_PHY_20_DATA */
+ 0x00000000, /* DENALI_PHY_21_DATA */
+ 0x04080000, /* DENALI_PHY_22_DATA */
+ 0x04080400, /* DENALI_PHY_23_DATA */
+ 0x30000000, /* DENALI_PHY_24_DATA */
+ 0x0c00c007, /* DENALI_PHY_25_DATA */
+ 0x00000100, /* DENALI_PHY_26_DATA */
+ 0x00000000, /* DENALI_PHY_27_DATA */
+ 0xfd02fe01, /* DENALI_PHY_28_DATA */
+ 0xf708fb04, /* DENALI_PHY_29_DATA */
+ 0xdf20ef10, /* DENALI_PHY_30_DATA */
+ 0x7f80bf40, /* DENALI_PHY_31_DATA */
+ 0x0001aaaa, /* DENALI_PHY_32_DATA */
+ 0x00000000, /* DENALI_PHY_33_DATA */
+ 0x00000000, /* DENALI_PHY_34_DATA */
+ 0x00000000, /* DENALI_PHY_35_DATA */
+ 0x00000000, /* DENALI_PHY_36_DATA */
+ 0x00000000, /* DENALI_PHY_37_DATA */
+ 0x00000000, /* DENALI_PHY_38_DATA */
+ 0x00000000, /* DENALI_PHY_39_DATA */
+ 0x00000000, /* DENALI_PHY_40_DATA */
+ 0x00000000, /* DENALI_PHY_41_DATA */
+ 0x00000000, /* DENALI_PHY_42_DATA */
+ 0x00000000, /* DENALI_PHY_43_DATA */
+ 0x00000000, /* DENALI_PHY_44_DATA */
+ 0x00000000, /* DENALI_PHY_45_DATA */
+ 0x00000000, /* DENALI_PHY_46_DATA */
+ 0x00000000, /* DENALI_PHY_47_DATA */
+ 0x00000000, /* DENALI_PHY_48_DATA */
+ 0x00000000, /* DENALI_PHY_49_DATA */
+ 0x00000000, /* DENALI_PHY_50_DATA */
+ 0x00000000, /* DENALI_PHY_51_DATA */
+ 0x00200000, /* DENALI_PHY_52_DATA */
+ 0x00000000, /* DENALI_PHY_53_DATA */
+ 0x00000000, /* DENALI_PHY_54_DATA */
+ 0x00000000, /* DENALI_PHY_55_DATA */
+ 0x00000000, /* DENALI_PHY_56_DATA */
+ 0x00000000, /* DENALI_PHY_57_DATA */
+ 0x00000000, /* DENALI_PHY_58_DATA */
+ 0x02800280, /* DENALI_PHY_59_DATA */
+ 0x02800280, /* DENALI_PHY_60_DATA */
+ 0x02800280, /* DENALI_PHY_61_DATA */
+ 0x02800280, /* DENALI_PHY_62_DATA */
+ 0x00000280, /* DENALI_PHY_63_DATA */
+ 0x00000000, /* DENALI_PHY_64_DATA */
+ 0x00000000, /* DENALI_PHY_65_DATA */
+ 0x00000000, /* DENALI_PHY_66_DATA */
+ 0x00000000, /* DENALI_PHY_67_DATA */
+ 0x00800000, /* DENALI_PHY_68_DATA */
+ 0x00800080, /* DENALI_PHY_69_DATA */
+ 0x00800080, /* DENALI_PHY_70_DATA */
+ 0x00800080, /* DENALI_PHY_71_DATA */
+ 0x00800080, /* DENALI_PHY_72_DATA */
+ 0x00800080, /* DENALI_PHY_73_DATA */
+ 0x00800080, /* DENALI_PHY_74_DATA */
+ 0x00800080, /* DENALI_PHY_75_DATA */
+ 0x00800080, /* DENALI_PHY_76_DATA */
+ 0x01190080, /* DENALI_PHY_77_DATA */
+ 0x00000001, /* DENALI_PHY_78_DATA */
+ 0x00000000, /* DENALI_PHY_79_DATA */
+ 0x00000000, /* DENALI_PHY_80_DATA */
+ 0x00000200, /* DENALI_PHY_81_DATA */
+ 0x00000000, /* DENALI_PHY_82_DATA */
+ 0x51315152, /* DENALI_PHY_83_DATA */
+ 0xc0003150, /* DENALI_PHY_84_DATA */
+ 0x010000c0, /* DENALI_PHY_85_DATA */
+ 0x00100000, /* DENALI_PHY_86_DATA */
+ 0x07044204, /* DENALI_PHY_87_DATA */
+ 0x000f0c18, /* DENALI_PHY_88_DATA */
+ 0x01000140, /* DENALI_PHY_89_DATA */
+ 0x00000c10, /* DENALI_PHY_90_DATA */
+ 0x00000000, /* DENALI_PHY_91_DATA */
+ 0x00000000, /* DENALI_PHY_92_DATA */
+ 0x00000000, /* DENALI_PHY_93_DATA */
+ 0x00000000, /* DENALI_PHY_94_DATA */
+ 0x00000000, /* DENALI_PHY_95_DATA */
+ 0x00000000, /* DENALI_PHY_96_DATA */
+ 0x00000000, /* DENALI_PHY_97_DATA */
+ 0x00000000, /* DENALI_PHY_98_DATA */
+ 0x00000000, /* DENALI_PHY_99_DATA */
+ 0x00000000, /* DENALI_PHY_100_DATA */
+ 0x00000000, /* DENALI_PHY_101_DATA */
+ 0x00000000, /* DENALI_PHY_102_DATA */
+ 0x00000000, /* DENALI_PHY_103_DATA */
+ 0x00000000, /* DENALI_PHY_104_DATA */
+ 0x00000000, /* DENALI_PHY_105_DATA */
+ 0x00000000, /* DENALI_PHY_106_DATA */
+ 0x00000000, /* DENALI_PHY_107_DATA */
+ 0x00000000, /* DENALI_PHY_108_DATA */
+ 0x00000000, /* DENALI_PHY_109_DATA */
+ 0x00000000, /* DENALI_PHY_110_DATA */
+ 0x00000000, /* DENALI_PHY_111_DATA */
+ 0x00000000, /* DENALI_PHY_112_DATA */
+ 0x00000000, /* DENALI_PHY_113_DATA */
+ 0x00000000, /* DENALI_PHY_114_DATA */
+ 0x00000000, /* DENALI_PHY_115_DATA */
+ 0x00000000, /* DENALI_PHY_116_DATA */
+ 0x00000000, /* DENALI_PHY_117_DATA */
+ 0x00000000, /* DENALI_PHY_118_DATA */
+ 0x00000000, /* DENALI_PHY_119_DATA */
+ 0x00000000, /* DENALI_PHY_120_DATA */
+ 0x00000000, /* DENALI_PHY_121_DATA */
+ 0x00000000, /* DENALI_PHY_122_DATA */
+ 0x00000000, /* DENALI_PHY_123_DATA */
+ 0x00000000, /* DENALI_PHY_124_DATA */
+ 0x00000000, /* DENALI_PHY_125_DATA */
+ 0x00000000, /* DENALI_PHY_126_DATA */
+ 0x00000000, /* DENALI_PHY_127_DATA */
+ 0x76543210, /* DENALI_PHY_128_DATA */
+ 0x0004f008, /* DENALI_PHY_129_DATA */
+ 0x00020119, /* DENALI_PHY_130_DATA */
+ 0x00000000, /* DENALI_PHY_131_DATA */
+ 0x00000000, /* DENALI_PHY_132_DATA */
+ 0x00010000, /* DENALI_PHY_133_DATA */
+ 0x01665555, /* DENALI_PHY_134_DATA */
+ 0x03665555, /* DENALI_PHY_135_DATA */
+ 0x00010f00, /* DENALI_PHY_136_DATA */
+ 0x04000100, /* DENALI_PHY_137_DATA */
+ 0x00000001, /* DENALI_PHY_138_DATA */
+ 0x00170180, /* DENALI_PHY_139_DATA */
+ 0x00cc0201, /* DENALI_PHY_140_DATA */
+ 0x00030066, /* DENALI_PHY_141_DATA */
+ 0x00000000, /* DENALI_PHY_142_DATA */
+ 0x00000000, /* DENALI_PHY_143_DATA */
+ 0x00000000, /* DENALI_PHY_144_DATA */
+ 0x00000000, /* DENALI_PHY_145_DATA */
+ 0x00000000, /* DENALI_PHY_146_DATA */
+ 0x00000000, /* DENALI_PHY_147_DATA */
+ 0x00000000, /* DENALI_PHY_148_DATA */
+ 0x00000000, /* DENALI_PHY_149_DATA */
+ 0x04080000, /* DENALI_PHY_150_DATA */
+ 0x04080400, /* DENALI_PHY_151_DATA */
+ 0x30000000, /* DENALI_PHY_152_DATA */
+ 0x0c00c007, /* DENALI_PHY_153_DATA */
+ 0x00000100, /* DENALI_PHY_154_DATA */
+ 0x00000000, /* DENALI_PHY_155_DATA */
+ 0xfd02fe01, /* DENALI_PHY_156_DATA */
+ 0xf708fb04, /* DENALI_PHY_157_DATA */
+ 0xdf20ef10, /* DENALI_PHY_158_DATA */
+ 0x7f80bf40, /* DENALI_PHY_159_DATA */
+ 0x0000aaaa, /* DENALI_PHY_160_DATA */
+ 0x00000000, /* DENALI_PHY_161_DATA */
+ 0x00000000, /* DENALI_PHY_162_DATA */
+ 0x00000000, /* DENALI_PHY_163_DATA */
+ 0x00000000, /* DENALI_PHY_164_DATA */
+ 0x00000000, /* DENALI_PHY_165_DATA */
+ 0x00000000, /* DENALI_PHY_166_DATA */
+ 0x00000000, /* DENALI_PHY_167_DATA */
+ 0x00000000, /* DENALI_PHY_168_DATA */
+ 0x00000000, /* DENALI_PHY_169_DATA */
+ 0x00000000, /* DENALI_PHY_170_DATA */
+ 0x00000000, /* DENALI_PHY_171_DATA */
+ 0x00000000, /* DENALI_PHY_172_DATA */
+ 0x00000000, /* DENALI_PHY_173_DATA */
+ 0x00000000, /* DENALI_PHY_174_DATA */
+ 0x00000000, /* DENALI_PHY_175_DATA */
+ 0x00000000, /* DENALI_PHY_176_DATA */
+ 0x00000000, /* DENALI_PHY_177_DATA */
+ 0x00000000, /* DENALI_PHY_178_DATA */
+ 0x00000000, /* DENALI_PHY_179_DATA */
+ 0x00200000, /* DENALI_PHY_180_DATA */
+ 0x00000000, /* DENALI_PHY_181_DATA */
+ 0x00000000, /* DENALI_PHY_182_DATA */
+ 0x00000000, /* DENALI_PHY_183_DATA */
+ 0x00000000, /* DENALI_PHY_184_DATA */
+ 0x00000000, /* DENALI_PHY_185_DATA */
+ 0x00000000, /* DENALI_PHY_186_DATA */
+ 0x02800280, /* DENALI_PHY_187_DATA */
+ 0x02800280, /* DENALI_PHY_188_DATA */
+ 0x02800280, /* DENALI_PHY_189_DATA */
+ 0x02800280, /* DENALI_PHY_190_DATA */
+ 0x00000280, /* DENALI_PHY_191_DATA */
+ 0x00000000, /* DENALI_PHY_192_DATA */
+ 0x00000000, /* DENALI_PHY_193_DATA */
+ 0x00000000, /* DENALI_PHY_194_DATA */
+ 0x00000000, /* DENALI_PHY_195_DATA */
+ 0x00800000, /* DENALI_PHY_196_DATA */
+ 0x00800080, /* DENALI_PHY_197_DATA */
+ 0x00800080, /* DENALI_PHY_198_DATA */
+ 0x00800080, /* DENALI_PHY_199_DATA */
+ 0x00800080, /* DENALI_PHY_200_DATA */
+ 0x00800080, /* DENALI_PHY_201_DATA */
+ 0x00800080, /* DENALI_PHY_202_DATA */
+ 0x00800080, /* DENALI_PHY_203_DATA */
+ 0x00800080, /* DENALI_PHY_204_DATA */
+ 0x01190080, /* DENALI_PHY_205_DATA */
+ 0x00000001, /* DENALI_PHY_206_DATA */
+ 0x00000000, /* DENALI_PHY_207_DATA */
+ 0x00000000, /* DENALI_PHY_208_DATA */
+ 0x00000200, /* DENALI_PHY_209_DATA */
+ 0x00000000, /* DENALI_PHY_210_DATA */
+ 0x51315152, /* DENALI_PHY_211_DATA */
+ 0xc0003150, /* DENALI_PHY_212_DATA */
+ 0x010000c0, /* DENALI_PHY_213_DATA */
+ 0x00100000, /* DENALI_PHY_214_DATA */
+ 0x07044204, /* DENALI_PHY_215_DATA */
+ 0x000f0c18, /* DENALI_PHY_216_DATA */
+ 0x01000140, /* DENALI_PHY_217_DATA */
+ 0x00000c10, /* DENALI_PHY_218_DATA */
+ 0x00000000, /* DENALI_PHY_219_DATA */
+ 0x00000000, /* DENALI_PHY_220_DATA */
+ 0x00000000, /* DENALI_PHY_221_DATA */
+ 0x00000000, /* DENALI_PHY_222_DATA */
+ 0x00000000, /* DENALI_PHY_223_DATA */
+ 0x00000000, /* DENALI_PHY_224_DATA */
+ 0x00000000, /* DENALI_PHY_225_DATA */
+ 0x00000000, /* DENALI_PHY_226_DATA */
+ 0x00000000, /* DENALI_PHY_227_DATA */
+ 0x00000000, /* DENALI_PHY_228_DATA */
+ 0x00000000, /* DENALI_PHY_229_DATA */
+ 0x00000000, /* DENALI_PHY_230_DATA */
+ 0x00000000, /* DENALI_PHY_231_DATA */
+ 0x00000000, /* DENALI_PHY_232_DATA */
+ 0x00000000, /* DENALI_PHY_233_DATA */
+ 0x00000000, /* DENALI_PHY_234_DATA */
+ 0x00000000, /* DENALI_PHY_235_DATA */
+ 0x00000000, /* DENALI_PHY_236_DATA */
+ 0x00000000, /* DENALI_PHY_237_DATA */
+ 0x00000000, /* DENALI_PHY_238_DATA */
+ 0x00000000, /* DENALI_PHY_239_DATA */
+ 0x00000000, /* DENALI_PHY_240_DATA */
+ 0x00000000, /* DENALI_PHY_241_DATA */
+ 0x00000000, /* DENALI_PHY_242_DATA */
+ 0x00000000, /* DENALI_PHY_243_DATA */
+ 0x00000000, /* DENALI_PHY_244_DATA */
+ 0x00000000, /* DENALI_PHY_245_DATA */
+ 0x00000000, /* DENALI_PHY_246_DATA */
+ 0x00000000, /* DENALI_PHY_247_DATA */
+ 0x00000000, /* DENALI_PHY_248_DATA */
+ 0x00000000, /* DENALI_PHY_249_DATA */
+ 0x00000000, /* DENALI_PHY_250_DATA */
+ 0x00000000, /* DENALI_PHY_251_DATA */
+ 0x00000000, /* DENALI_PHY_252_DATA */
+ 0x00000000, /* DENALI_PHY_253_DATA */
+ 0x00000000, /* DENALI_PHY_254_DATA */
+ 0x00000000, /* DENALI_PHY_255_DATA */
+ 0x76543210, /* DENALI_PHY_256_DATA */
+ 0x0004f008, /* DENALI_PHY_257_DATA */
+ 0x00020119, /* DENALI_PHY_258_DATA */
+ 0x00000000, /* DENALI_PHY_259_DATA */
+ 0x00000000, /* DENALI_PHY_260_DATA */
+ 0x00010000, /* DENALI_PHY_261_DATA */
+ 0x01665555, /* DENALI_PHY_262_DATA */
+ 0x03665555, /* DENALI_PHY_263_DATA */
+ 0x00010f00, /* DENALI_PHY_264_DATA */
+ 0x04000100, /* DENALI_PHY_265_DATA */
+ 0x00000001, /* DENALI_PHY_266_DATA */
+ 0x00170180, /* DENALI_PHY_267_DATA */
+ 0x00cc0201, /* DENALI_PHY_268_DATA */
+ 0x00030066, /* DENALI_PHY_269_DATA */
+ 0x00000000, /* DENALI_PHY_270_DATA */
+ 0x00000000, /* DENALI_PHY_271_DATA */
+ 0x00000000, /* DENALI_PHY_272_DATA */
+ 0x00000000, /* DENALI_PHY_273_DATA */
+ 0x00000000, /* DENALI_PHY_274_DATA */
+ 0x00000000, /* DENALI_PHY_275_DATA */
+ 0x00000000, /* DENALI_PHY_276_DATA */
+ 0x00000000, /* DENALI_PHY_277_DATA */
+ 0x04080000, /* DENALI_PHY_278_DATA */
+ 0x04080400, /* DENALI_PHY_279_DATA */
+ 0x30000000, /* DENALI_PHY_280_DATA */
+ 0x0c00c007, /* DENALI_PHY_281_DATA */
+ 0x00000100, /* DENALI_PHY_282_DATA */
+ 0x00000000, /* DENALI_PHY_283_DATA */
+ 0xfd02fe01, /* DENALI_PHY_284_DATA */
+ 0xf708fb04, /* DENALI_PHY_285_DATA */
+ 0xdf20ef10, /* DENALI_PHY_286_DATA */
+ 0x7f80bf40, /* DENALI_PHY_287_DATA */
+ 0x0001aaaa, /* DENALI_PHY_288_DATA */
+ 0x00000000, /* DENALI_PHY_289_DATA */
+ 0x00000000, /* DENALI_PHY_290_DATA */
+ 0x00000000, /* DENALI_PHY_291_DATA */
+ 0x00000000, /* DENALI_PHY_292_DATA */
+ 0x00000000, /* DENALI_PHY_293_DATA */
+ 0x00000000, /* DENALI_PHY_294_DATA */
+ 0x00000000, /* DENALI_PHY_295_DATA */
+ 0x00000000, /* DENALI_PHY_296_DATA */
+ 0x00000000, /* DENALI_PHY_297_DATA */
+ 0x00000000, /* DENALI_PHY_298_DATA */
+ 0x00000000, /* DENALI_PHY_299_DATA */
+ 0x00000000, /* DENALI_PHY_300_DATA */
+ 0x00000000, /* DENALI_PHY_301_DATA */
+ 0x00000000, /* DENALI_PHY_302_DATA */
+ 0x00000000, /* DENALI_PHY_303_DATA */
+ 0x00000000, /* DENALI_PHY_304_DATA */
+ 0x00000000, /* DENALI_PHY_305_DATA */
+ 0x00000000, /* DENALI_PHY_306_DATA */
+ 0x00000000, /* DENALI_PHY_307_DATA */
+ 0x00200000, /* DENALI_PHY_308_DATA */
+ 0x00000000, /* DENALI_PHY_309_DATA */
+ 0x00000000, /* DENALI_PHY_310_DATA */
+ 0x00000000, /* DENALI_PHY_311_DATA */
+ 0x00000000, /* DENALI_PHY_312_DATA */
+ 0x00000000, /* DENALI_PHY_313_DATA */
+ 0x00000000, /* DENALI_PHY_314_DATA */
+ 0x02800280, /* DENALI_PHY_315_DATA */
+ 0x02800280, /* DENALI_PHY_316_DATA */
+ 0x02800280, /* DENALI_PHY_317_DATA */
+ 0x02800280, /* DENALI_PHY_318_DATA */
+ 0x00000280, /* DENALI_PHY_319_DATA */
+ 0x00000000, /* DENALI_PHY_320_DATA */
+ 0x00000000, /* DENALI_PHY_321_DATA */
+ 0x00000000, /* DENALI_PHY_322_DATA */
+ 0x00000000, /* DENALI_PHY_323_DATA */
+ 0x00800000, /* DENALI_PHY_324_DATA */
+ 0x00800080, /* DENALI_PHY_325_DATA */
+ 0x00800080, /* DENALI_PHY_326_DATA */
+ 0x00800080, /* DENALI_PHY_327_DATA */
+ 0x00800080, /* DENALI_PHY_328_DATA */
+ 0x00800080, /* DENALI_PHY_329_DATA */
+ 0x00800080, /* DENALI_PHY_330_DATA */
+ 0x00800080, /* DENALI_PHY_331_DATA */
+ 0x00800080, /* DENALI_PHY_332_DATA */
+ 0x01190080, /* DENALI_PHY_333_DATA */
+ 0x00000001, /* DENALI_PHY_334_DATA */
+ 0x00000000, /* DENALI_PHY_335_DATA */
+ 0x00000000, /* DENALI_PHY_336_DATA */
+ 0x00000200, /* DENALI_PHY_337_DATA */
+ 0x00000000, /* DENALI_PHY_338_DATA */
+ 0x51315152, /* DENALI_PHY_339_DATA */
+ 0xc0003150, /* DENALI_PHY_340_DATA */
+ 0x010000c0, /* DENALI_PHY_341_DATA */
+ 0x00100000, /* DENALI_PHY_342_DATA */
+ 0x07044204, /* DENALI_PHY_343_DATA */
+ 0x000f0c18, /* DENALI_PHY_344_DATA */
+ 0x01000140, /* DENALI_PHY_345_DATA */
+ 0x00000c10, /* DENALI_PHY_346_DATA */
+ 0x00000000, /* DENALI_PHY_347_DATA */
+ 0x00000000, /* DENALI_PHY_348_DATA */
+ 0x00000000, /* DENALI_PHY_349_DATA */
+ 0x00000000, /* DENALI_PHY_350_DATA */
+ 0x00000000, /* DENALI_PHY_351_DATA */
+ 0x00000000, /* DENALI_PHY_352_DATA */
+ 0x00000000, /* DENALI_PHY_353_DATA */
+ 0x00000000, /* DENALI_PHY_354_DATA */
+ 0x00000000, /* DENALI_PHY_355_DATA */
+ 0x00000000, /* DENALI_PHY_356_DATA */
+ 0x00000000, /* DENALI_PHY_357_DATA */
+ 0x00000000, /* DENALI_PHY_358_DATA */
+ 0x00000000, /* DENALI_PHY_359_DATA */
+ 0x00000000, /* DENALI_PHY_360_DATA */
+ 0x00000000, /* DENALI_PHY_361_DATA */
+ 0x00000000, /* DENALI_PHY_362_DATA */
+ 0x00000000, /* DENALI_PHY_363_DATA */
+ 0x00000000, /* DENALI_PHY_364_DATA */
+ 0x00000000, /* DENALI_PHY_365_DATA */
+ 0x00000000, /* DENALI_PHY_366_DATA */
+ 0x00000000, /* DENALI_PHY_367_DATA */
+ 0x00000000, /* DENALI_PHY_368_DATA */
+ 0x00000000, /* DENALI_PHY_369_DATA */
+ 0x00000000, /* DENALI_PHY_370_DATA */
+ 0x00000000, /* DENALI_PHY_371_DATA */
+ 0x00000000, /* DENALI_PHY_372_DATA */
+ 0x00000000, /* DENALI_PHY_373_DATA */
+ 0x00000000, /* DENALI_PHY_374_DATA */
+ 0x00000000, /* DENALI_PHY_375_DATA */
+ 0x00000000, /* DENALI_PHY_376_DATA */
+ 0x00000000, /* DENALI_PHY_377_DATA */
+ 0x00000000, /* DENALI_PHY_378_DATA */
+ 0x00000000, /* DENALI_PHY_379_DATA */
+ 0x00000000, /* DENALI_PHY_380_DATA */
+ 0x00000000, /* DENALI_PHY_381_DATA */
+ 0x00000000, /* DENALI_PHY_382_DATA */
+ 0x00000000, /* DENALI_PHY_383_DATA */
+ 0x76543210, /* DENALI_PHY_384_DATA */
+ 0x0004f008, /* DENALI_PHY_385_DATA */
+ 0x00020119, /* DENALI_PHY_386_DATA */
+ 0x00000000, /* DENALI_PHY_387_DATA */
+ 0x00000000, /* DENALI_PHY_388_DATA */
+ 0x00010000, /* DENALI_PHY_389_DATA */
+ 0x01665555, /* DENALI_PHY_390_DATA */
+ 0x03665555, /* DENALI_PHY_391_DATA */
+ 0x00010f00, /* DENALI_PHY_392_DATA */
+ 0x04000100, /* DENALI_PHY_393_DATA */
+ 0x00000001, /* DENALI_PHY_394_DATA */
+ 0x00170180, /* DENALI_PHY_395_DATA */
+ 0x00cc0201, /* DENALI_PHY_396_DATA */
+ 0x00030066, /* DENALI_PHY_397_DATA */
+ 0x00000000, /* DENALI_PHY_398_DATA */
+ 0x00000000, /* DENALI_PHY_399_DATA */
+ 0x00000000, /* DENALI_PHY_400_DATA */
+ 0x00000000, /* DENALI_PHY_401_DATA */
+ 0x00000000, /* DENALI_PHY_402_DATA */
+ 0x00000000, /* DENALI_PHY_403_DATA */
+ 0x00000000, /* DENALI_PHY_404_DATA */
+ 0x00000000, /* DENALI_PHY_405_DATA */
+ 0x04080000, /* DENALI_PHY_406_DATA */
+ 0x04080400, /* DENALI_PHY_407_DATA */
+ 0x30000000, /* DENALI_PHY_408_DATA */
+ 0x0c00c007, /* DENALI_PHY_409_DATA */
+ 0x00000100, /* DENALI_PHY_410_DATA */
+ 0x00000000, /* DENALI_PHY_411_DATA */
+ 0xfd02fe01, /* DENALI_PHY_412_DATA */
+ 0xf708fb04, /* DENALI_PHY_413_DATA */
+ 0xdf20ef10, /* DENALI_PHY_414_DATA */
+ 0x7f80bf40, /* DENALI_PHY_415_DATA */
+ 0x0000aaaa, /* DENALI_PHY_416_DATA */
+ 0x00000000, /* DENALI_PHY_417_DATA */
+ 0x00000000, /* DENALI_PHY_418_DATA */
+ 0x00000000, /* DENALI_PHY_419_DATA */
+ 0x00000000, /* DENALI_PHY_420_DATA */
+ 0x00000000, /* DENALI_PHY_421_DATA */
+ 0x00000000, /* DENALI_PHY_422_DATA */
+ 0x00000000, /* DENALI_PHY_423_DATA */
+ 0x00000000, /* DENALI_PHY_424_DATA */
+ 0x00000000, /* DENALI_PHY_425_DATA */
+ 0x00000000, /* DENALI_PHY_426_DATA */
+ 0x00000000, /* DENALI_PHY_427_DATA */
+ 0x00000000, /* DENALI_PHY_428_DATA */
+ 0x00000000, /* DENALI_PHY_429_DATA */
+ 0x00000000, /* DENALI_PHY_430_DATA */
+ 0x00000000, /* DENALI_PHY_431_DATA */
+ 0x00000000, /* DENALI_PHY_432_DATA */
+ 0x00000000, /* DENALI_PHY_433_DATA */
+ 0x00000000, /* DENALI_PHY_434_DATA */
+ 0x00000000, /* DENALI_PHY_435_DATA */
+ 0x00200000, /* DENALI_PHY_436_DATA */
+ 0x00000000, /* DENALI_PHY_437_DATA */
+ 0x00000000, /* DENALI_PHY_438_DATA */
+ 0x00000000, /* DENALI_PHY_439_DATA */
+ 0x00000000, /* DENALI_PHY_440_DATA */
+ 0x00000000, /* DENALI_PHY_441_DATA */
+ 0x00000000, /* DENALI_PHY_442_DATA */
+ 0x02800280, /* DENALI_PHY_443_DATA */
+ 0x02800280, /* DENALI_PHY_444_DATA */
+ 0x02800280, /* DENALI_PHY_445_DATA */
+ 0x02800280, /* DENALI_PHY_446_DATA */
+ 0x00000280, /* DENALI_PHY_447_DATA */
+ 0x00000000, /* DENALI_PHY_448_DATA */
+ 0x00000000, /* DENALI_PHY_449_DATA */
+ 0x00000000, /* DENALI_PHY_450_DATA */
+ 0x00000000, /* DENALI_PHY_451_DATA */
+ 0x00800000, /* DENALI_PHY_452_DATA */
+ 0x00800080, /* DENALI_PHY_453_DATA */
+ 0x00800080, /* DENALI_PHY_454_DATA */
+ 0x00800080, /* DENALI_PHY_455_DATA */
+ 0x00800080, /* DENALI_PHY_456_DATA */
+ 0x00800080, /* DENALI_PHY_457_DATA */
+ 0x00800080, /* DENALI_PHY_458_DATA */
+ 0x00800080, /* DENALI_PHY_459_DATA */
+ 0x00800080, /* DENALI_PHY_460_DATA */
+ 0x01190080, /* DENALI_PHY_461_DATA */
+ 0x00000001, /* DENALI_PHY_462_DATA */
+ 0x00000000, /* DENALI_PHY_463_DATA */
+ 0x00000000, /* DENALI_PHY_464_DATA */
+ 0x00000200, /* DENALI_PHY_465_DATA */
+ 0x00000000, /* DENALI_PHY_466_DATA */
+ 0x51315152, /* DENALI_PHY_467_DATA */
+ 0xc0003150, /* DENALI_PHY_468_DATA */
+ 0x010000c0, /* DENALI_PHY_469_DATA */
+ 0x00100000, /* DENALI_PHY_470_DATA */
+ 0x07044204, /* DENALI_PHY_471_DATA */
+ 0x000f0c18, /* DENALI_PHY_472_DATA */
+ 0x01000140, /* DENALI_PHY_473_DATA */
+ 0x00000c10, /* DENALI_PHY_474_DATA */
+ 0x00000000, /* DENALI_PHY_475_DATA */
+ 0x00000000, /* DENALI_PHY_476_DATA */
+ 0x00000000, /* DENALI_PHY_477_DATA */
+ 0x00000000, /* DENALI_PHY_478_DATA */
+ 0x00000000, /* DENALI_PHY_479_DATA */
+ 0x00000000, /* DENALI_PHY_480_DATA */
+ 0x00000000, /* DENALI_PHY_481_DATA */
+ 0x00000000, /* DENALI_PHY_482_DATA */
+ 0x00000000, /* DENALI_PHY_483_DATA */
+ 0x00000000, /* DENALI_PHY_484_DATA */
+ 0x00000000, /* DENALI_PHY_485_DATA */
+ 0x00000000, /* DENALI_PHY_486_DATA */
+ 0x00000000, /* DENALI_PHY_487_DATA */
+ 0x00000000, /* DENALI_PHY_488_DATA */
+ 0x00000000, /* DENALI_PHY_489_DATA */
+ 0x00000000, /* DENALI_PHY_490_DATA */
+ 0x00000000, /* DENALI_PHY_491_DATA */
+ 0x00000000, /* DENALI_PHY_492_DATA */
+ 0x00000000, /* DENALI_PHY_493_DATA */
+ 0x00000000, /* DENALI_PHY_494_DATA */
+ 0x00000000, /* DENALI_PHY_495_DATA */
+ 0x00000000, /* DENALI_PHY_496_DATA */
+ 0x00000000, /* DENALI_PHY_497_DATA */
+ 0x00000000, /* DENALI_PHY_498_DATA */
+ 0x00000000, /* DENALI_PHY_499_DATA */
+ 0x00000000, /* DENALI_PHY_500_DATA */
+ 0x00000000, /* DENALI_PHY_501_DATA */
+ 0x00000000, /* DENALI_PHY_502_DATA */
+ 0x00000000, /* DENALI_PHY_503_DATA */
+ 0x00000000, /* DENALI_PHY_504_DATA */
+ 0x00000000, /* DENALI_PHY_505_DATA */
+ 0x00000000, /* DENALI_PHY_506_DATA */
+ 0x00000000, /* DENALI_PHY_507_DATA */
+ 0x00000000, /* DENALI_PHY_508_DATA */
+ 0x00000000, /* DENALI_PHY_509_DATA */
+ 0x00000000, /* DENALI_PHY_510_DATA */
+ 0x00000000, /* DENALI_PHY_511_DATA */
+ 0x00000000, /* DENALI_PHY_512_DATA */
+ 0x00000000, /* DENALI_PHY_513_DATA */
+ 0x00000000, /* DENALI_PHY_514_DATA */
+ 0x00000000, /* DENALI_PHY_515_DATA */
+ 0x00000000, /* DENALI_PHY_516_DATA */
+ 0x00000000, /* DENALI_PHY_517_DATA */
+ 0x00000000, /* DENALI_PHY_518_DATA */
+ 0x00000002, /* DENALI_PHY_519_DATA */
+ 0x00000000, /* DENALI_PHY_520_DATA */
+ 0x00000000, /* DENALI_PHY_521_DATA */
+ 0x00000000, /* DENALI_PHY_522_DATA */
+ 0x00400320, /* DENALI_PHY_523_DATA */
+ 0x00000040, /* DENALI_PHY_524_DATA */
+ 0x00dcba98, /* DENALI_PHY_525_DATA */
+ 0x00000000, /* DENALI_PHY_526_DATA */
+ 0x00dcba98, /* DENALI_PHY_527_DATA */
+ 0x01000000, /* DENALI_PHY_528_DATA */
+ 0x00020003, /* DENALI_PHY_529_DATA */
+ 0x00000000, /* DENALI_PHY_530_DATA */
+ 0x00000000, /* DENALI_PHY_531_DATA */
+ 0x00000000, /* DENALI_PHY_532_DATA */
+ 0x0000002a, /* DENALI_PHY_533_DATA */
+ 0x00000015, /* DENALI_PHY_534_DATA */
+ 0x00000015, /* DENALI_PHY_535_DATA */
+ 0x0000002a, /* DENALI_PHY_536_DATA */
+ 0x00000033, /* DENALI_PHY_537_DATA */
+ 0x0000000c, /* DENALI_PHY_538_DATA */
+ 0x0000000c, /* DENALI_PHY_539_DATA */
+ 0x00000033, /* DENALI_PHY_540_DATA */
+ 0x0a418820, /* DENALI_PHY_541_DATA */
+ 0x003f0000, /* DENALI_PHY_542_DATA */
+ 0x0000003f, /* DENALI_PHY_543_DATA */
+ 0x00030055, /* DENALI_PHY_544_DATA */
+ 0x03000300, /* DENALI_PHY_545_DATA */
+ 0x03000300, /* DENALI_PHY_546_DATA */
+ 0x00000300, /* DENALI_PHY_547_DATA */
+ 0x42080010, /* DENALI_PHY_548_DATA */
+ 0x00000003, /* DENALI_PHY_549_DATA */
+ 0x00000000, /* DENALI_PHY_550_DATA */
+ 0x00000000, /* DENALI_PHY_551_DATA */
+ 0x00000000, /* DENALI_PHY_552_DATA */
+ 0x00000000, /* DENALI_PHY_553_DATA */
+ 0x00000000, /* DENALI_PHY_554_DATA */
+ 0x00000000, /* DENALI_PHY_555_DATA */
+ 0x00000000, /* DENALI_PHY_556_DATA */
+ 0x00000000, /* DENALI_PHY_557_DATA */
+ 0x00000000, /* DENALI_PHY_558_DATA */
+ 0x00000000, /* DENALI_PHY_559_DATA */
+ 0x00000000, /* DENALI_PHY_560_DATA */
+ 0x00000000, /* DENALI_PHY_561_DATA */
+ 0x00000000, /* DENALI_PHY_562_DATA */
+ 0x00000000, /* DENALI_PHY_563_DATA */
+ 0x00000000, /* DENALI_PHY_564_DATA */
+ 0x00000000, /* DENALI_PHY_565_DATA */
+ 0x00000000, /* DENALI_PHY_566_DATA */
+ 0x00000000, /* DENALI_PHY_567_DATA */
+ 0x00000000, /* DENALI_PHY_568_DATA */
+ 0x00000000, /* DENALI_PHY_569_DATA */
+ 0x00000000, /* DENALI_PHY_570_DATA */
+ 0x00000000, /* DENALI_PHY_571_DATA */
+ 0x00000000, /* DENALI_PHY_572_DATA */
+ 0x00000000, /* DENALI_PHY_573_DATA */
+ 0x00000000, /* DENALI_PHY_574_DATA */
+ 0x00000000, /* DENALI_PHY_575_DATA */
+ 0x00000000, /* DENALI_PHY_576_DATA */
+ 0x00000000, /* DENALI_PHY_577_DATA */
+ 0x00000000, /* DENALI_PHY_578_DATA */
+ 0x00000000, /* DENALI_PHY_579_DATA */
+ 0x00000000, /* DENALI_PHY_580_DATA */
+ 0x00000000, /* DENALI_PHY_581_DATA */
+ 0x00000000, /* DENALI_PHY_582_DATA */
+ 0x00000000, /* DENALI_PHY_583_DATA */
+ 0x00000000, /* DENALI_PHY_584_DATA */
+ 0x00000000, /* DENALI_PHY_585_DATA */
+ 0x00000000, /* DENALI_PHY_586_DATA */
+ 0x00000000, /* DENALI_PHY_587_DATA */
+ 0x00000000, /* DENALI_PHY_588_DATA */
+ 0x00000000, /* DENALI_PHY_589_DATA */
+ 0x00000000, /* DENALI_PHY_590_DATA */
+ 0x00000000, /* DENALI_PHY_591_DATA */
+ 0x00000000, /* DENALI_PHY_592_DATA */
+ 0x00000000, /* DENALI_PHY_593_DATA */
+ 0x00000000, /* DENALI_PHY_594_DATA */
+ 0x00000000, /* DENALI_PHY_595_DATA */
+ 0x00000000, /* DENALI_PHY_596_DATA */
+ 0x00000000, /* DENALI_PHY_597_DATA */
+ 0x00000000, /* DENALI_PHY_598_DATA */
+ 0x00000000, /* DENALI_PHY_599_DATA */
+ 0x00000000, /* DENALI_PHY_600_DATA */
+ 0x00000000, /* DENALI_PHY_601_DATA */
+ 0x00000000, /* DENALI_PHY_602_DATA */
+ 0x00000000, /* DENALI_PHY_603_DATA */
+ 0x00000000, /* DENALI_PHY_604_DATA */
+ 0x00000000, /* DENALI_PHY_605_DATA */
+ 0x00000000, /* DENALI_PHY_606_DATA */
+ 0x00000000, /* DENALI_PHY_607_DATA */
+ 0x00000000, /* DENALI_PHY_608_DATA */
+ 0x00000000, /* DENALI_PHY_609_DATA */
+ 0x00000000, /* DENALI_PHY_610_DATA */
+ 0x00000000, /* DENALI_PHY_611_DATA */
+ 0x00000000, /* DENALI_PHY_612_DATA */
+ 0x00000000, /* DENALI_PHY_613_DATA */
+ 0x00000000, /* DENALI_PHY_614_DATA */
+ 0x00000000, /* DENALI_PHY_615_DATA */
+ 0x00000000, /* DENALI_PHY_616_DATA */
+ 0x00000000, /* DENALI_PHY_617_DATA */
+ 0x00000000, /* DENALI_PHY_618_DATA */
+ 0x00000000, /* DENALI_PHY_619_DATA */
+ 0x00000000, /* DENALI_PHY_620_DATA */
+ 0x00000000, /* DENALI_PHY_621_DATA */
+ 0x00000000, /* DENALI_PHY_622_DATA */
+ 0x00000000, /* DENALI_PHY_623_DATA */
+ 0x00000000, /* DENALI_PHY_624_DATA */
+ 0x00000000, /* DENALI_PHY_625_DATA */
+ 0x00000000, /* DENALI_PHY_626_DATA */
+ 0x00000000, /* DENALI_PHY_627_DATA */
+ 0x00000000, /* DENALI_PHY_628_DATA */
+ 0x00000000, /* DENALI_PHY_629_DATA */
+ 0x00000000, /* DENALI_PHY_630_DATA */
+ 0x00000000, /* DENALI_PHY_631_DATA */
+ 0x00000000, /* DENALI_PHY_632_DATA */
+ 0x00000000, /* DENALI_PHY_633_DATA */
+ 0x00000000, /* DENALI_PHY_634_DATA */
+ 0x00000000, /* DENALI_PHY_635_DATA */
+ 0x00000000, /* DENALI_PHY_636_DATA */
+ 0x00000000, /* DENALI_PHY_637_DATA */
+ 0x00000000, /* DENALI_PHY_638_DATA */
+ 0x00000000, /* DENALI_PHY_639_DATA */
+ 0x00000000, /* DENALI_PHY_640_DATA */
+ 0x00000000, /* DENALI_PHY_641_DATA */
+ 0x00000000, /* DENALI_PHY_642_DATA */
+ 0x00000000, /* DENALI_PHY_643_DATA */
+ 0x00000000, /* DENALI_PHY_644_DATA */
+ 0x00000000, /* DENALI_PHY_645_DATA */
+ 0x00000000, /* DENALI_PHY_646_DATA */
+ 0x00000002, /* DENALI_PHY_647_DATA */
+ 0x00000000, /* DENALI_PHY_648_DATA */
+ 0x00000000, /* DENALI_PHY_649_DATA */
+ 0x00000000, /* DENALI_PHY_650_DATA */
+ 0x00400320, /* DENALI_PHY_651_DATA */
+ 0x00000040, /* DENALI_PHY_652_DATA */
+ 0x00000000, /* DENALI_PHY_653_DATA */
+ 0x00000000, /* DENALI_PHY_654_DATA */
+ 0x00000000, /* DENALI_PHY_655_DATA */
+ 0x01000000, /* DENALI_PHY_656_DATA */
+ 0x00020003, /* DENALI_PHY_657_DATA */
+ 0x00000000, /* DENALI_PHY_658_DATA */
+ 0x00000000, /* DENALI_PHY_659_DATA */
+ 0x00000000, /* DENALI_PHY_660_DATA */
+ 0x0000002a, /* DENALI_PHY_661_DATA */
+ 0x00000015, /* DENALI_PHY_662_DATA */
+ 0x00000015, /* DENALI_PHY_663_DATA */
+ 0x0000002a, /* DENALI_PHY_664_DATA */
+ 0x00000033, /* DENALI_PHY_665_DATA */
+ 0x0000000c, /* DENALI_PHY_666_DATA */
+ 0x0000000c, /* DENALI_PHY_667_DATA */
+ 0x00000033, /* DENALI_PHY_668_DATA */
+ 0x00000000, /* DENALI_PHY_669_DATA */
+ 0x00000000, /* DENALI_PHY_670_DATA */
+ 0x00000000, /* DENALI_PHY_671_DATA */
+ 0x00030055, /* DENALI_PHY_672_DATA */
+ 0x03000300, /* DENALI_PHY_673_DATA */
+ 0x03000300, /* DENALI_PHY_674_DATA */
+ 0x00000300, /* DENALI_PHY_675_DATA */
+ 0x42080010, /* DENALI_PHY_676_DATA */
+ 0x00000003, /* DENALI_PHY_677_DATA */
+ 0x00000000, /* DENALI_PHY_678_DATA */
+ 0x00000000, /* DENALI_PHY_679_DATA */
+ 0x00000000, /* DENALI_PHY_680_DATA */
+ 0x00000000, /* DENALI_PHY_681_DATA */
+ 0x00000000, /* DENALI_PHY_682_DATA */
+ 0x00000000, /* DENALI_PHY_683_DATA */
+ 0x00000000, /* DENALI_PHY_684_DATA */
+ 0x00000000, /* DENALI_PHY_685_DATA */
+ 0x00000000, /* DENALI_PHY_686_DATA */
+ 0x00000000, /* DENALI_PHY_687_DATA */
+ 0x00000000, /* DENALI_PHY_688_DATA */
+ 0x00000000, /* DENALI_PHY_689_DATA */
+ 0x00000000, /* DENALI_PHY_690_DATA */
+ 0x00000000, /* DENALI_PHY_691_DATA */
+ 0x00000000, /* DENALI_PHY_692_DATA */
+ 0x00000000, /* DENALI_PHY_693_DATA */
+ 0x00000000, /* DENALI_PHY_694_DATA */
+ 0x00000000, /* DENALI_PHY_695_DATA */
+ 0x00000000, /* DENALI_PHY_696_DATA */
+ 0x00000000, /* DENALI_PHY_697_DATA */
+ 0x00000000, /* DENALI_PHY_698_DATA */
+ 0x00000000, /* DENALI_PHY_699_DATA */
+ 0x00000000, /* DENALI_PHY_700_DATA */
+ 0x00000000, /* DENALI_PHY_701_DATA */
+ 0x00000000, /* DENALI_PHY_702_DATA */
+ 0x00000000, /* DENALI_PHY_703_DATA */
+ 0x00000000, /* DENALI_PHY_704_DATA */
+ 0x00000000, /* DENALI_PHY_705_DATA */
+ 0x00000000, /* DENALI_PHY_706_DATA */
+ 0x00000000, /* DENALI_PHY_707_DATA */
+ 0x00000000, /* DENALI_PHY_708_DATA */
+ 0x00000000, /* DENALI_PHY_709_DATA */
+ 0x00000000, /* DENALI_PHY_710_DATA */
+ 0x00000000, /* DENALI_PHY_711_DATA */
+ 0x00000000, /* DENALI_PHY_712_DATA */
+ 0x00000000, /* DENALI_PHY_713_DATA */
+ 0x00000000, /* DENALI_PHY_714_DATA */
+ 0x00000000, /* DENALI_PHY_715_DATA */
+ 0x00000000, /* DENALI_PHY_716_DATA */
+ 0x00000000, /* DENALI_PHY_717_DATA */
+ 0x00000000, /* DENALI_PHY_718_DATA */
+ 0x00000000, /* DENALI_PHY_719_DATA */
+ 0x00000000, /* DENALI_PHY_720_DATA */
+ 0x00000000, /* DENALI_PHY_721_DATA */
+ 0x00000000, /* DENALI_PHY_722_DATA */
+ 0x00000000, /* DENALI_PHY_723_DATA */
+ 0x00000000, /* DENALI_PHY_724_DATA */
+ 0x00000000, /* DENALI_PHY_725_DATA */
+ 0x00000000, /* DENALI_PHY_726_DATA */
+ 0x00000000, /* DENALI_PHY_727_DATA */
+ 0x00000000, /* DENALI_PHY_728_DATA */
+ 0x00000000, /* DENALI_PHY_729_DATA */
+ 0x00000000, /* DENALI_PHY_730_DATA */
+ 0x00000000, /* DENALI_PHY_731_DATA */
+ 0x00000000, /* DENALI_PHY_732_DATA */
+ 0x00000000, /* DENALI_PHY_733_DATA */
+ 0x00000000, /* DENALI_PHY_734_DATA */
+ 0x00000000, /* DENALI_PHY_735_DATA */
+ 0x00000000, /* DENALI_PHY_736_DATA */
+ 0x00000000, /* DENALI_PHY_737_DATA */
+ 0x00000000, /* DENALI_PHY_738_DATA */
+ 0x00000000, /* DENALI_PHY_739_DATA */
+ 0x00000000, /* DENALI_PHY_740_DATA */
+ 0x00000000, /* DENALI_PHY_741_DATA */
+ 0x00000000, /* DENALI_PHY_742_DATA */
+ 0x00000000, /* DENALI_PHY_743_DATA */
+ 0x00000000, /* DENALI_PHY_744_DATA */
+ 0x00000000, /* DENALI_PHY_745_DATA */
+ 0x00000000, /* DENALI_PHY_746_DATA */
+ 0x00000000, /* DENALI_PHY_747_DATA */
+ 0x00000000, /* DENALI_PHY_748_DATA */
+ 0x00000000, /* DENALI_PHY_749_DATA */
+ 0x00000000, /* DENALI_PHY_750_DATA */
+ 0x00000000, /* DENALI_PHY_751_DATA */
+ 0x00000000, /* DENALI_PHY_752_DATA */
+ 0x00000000, /* DENALI_PHY_753_DATA */
+ 0x00000000, /* DENALI_PHY_754_DATA */
+ 0x00000000, /* DENALI_PHY_755_DATA */
+ 0x00000000, /* DENALI_PHY_756_DATA */
+ 0x00000000, /* DENALI_PHY_757_DATA */
+ 0x00000000, /* DENALI_PHY_758_DATA */
+ 0x00000000, /* DENALI_PHY_759_DATA */
+ 0x00000000, /* DENALI_PHY_760_DATA */
+ 0x00000000, /* DENALI_PHY_761_DATA */
+ 0x00000000, /* DENALI_PHY_762_DATA */
+ 0x00000000, /* DENALI_PHY_763_DATA */
+ 0x00000000, /* DENALI_PHY_764_DATA */
+ 0x00000000, /* DENALI_PHY_765_DATA */
+ 0x00000000, /* DENALI_PHY_766_DATA */
+ 0x00000000, /* DENALI_PHY_767_DATA */
+ 0x00000000, /* DENALI_PHY_768_DATA */
+ 0x00000000, /* DENALI_PHY_769_DATA */
+ 0x00000000, /* DENALI_PHY_770_DATA */
+ 0x00000000, /* DENALI_PHY_771_DATA */
+ 0x00000000, /* DENALI_PHY_772_DATA */
+ 0x00000000, /* DENALI_PHY_773_DATA */
+ 0x00000000, /* DENALI_PHY_774_DATA */
+ 0x00000002, /* DENALI_PHY_775_DATA */
+ 0x00000000, /* DENALI_PHY_776_DATA */
+ 0x00000000, /* DENALI_PHY_777_DATA */
+ 0x00000000, /* DENALI_PHY_778_DATA */
+ 0x00400320, /* DENALI_PHY_779_DATA */
+ 0x00000040, /* DENALI_PHY_780_DATA */
+ 0x00000000, /* DENALI_PHY_781_DATA */
+ 0x00000000, /* DENALI_PHY_782_DATA */
+ 0x00000000, /* DENALI_PHY_783_DATA */
+ 0x01000000, /* DENALI_PHY_784_DATA */
+ 0x00020003, /* DENALI_PHY_785_DATA */
+ 0x00000000, /* DENALI_PHY_786_DATA */
+ 0x00000000, /* DENALI_PHY_787_DATA */
+ 0x00000000, /* DENALI_PHY_788_DATA */
+ 0x0000002a, /* DENALI_PHY_789_DATA */
+ 0x00000015, /* DENALI_PHY_790_DATA */
+ 0x00000015, /* DENALI_PHY_791_DATA */
+ 0x0000002a, /* DENALI_PHY_792_DATA */
+ 0x00000033, /* DENALI_PHY_793_DATA */
+ 0x0000000c, /* DENALI_PHY_794_DATA */
+ 0x0000000c, /* DENALI_PHY_795_DATA */
+ 0x00000033, /* DENALI_PHY_796_DATA */
+ 0x1ee6b16a, /* DENALI_PHY_797_DATA */
+ 0x10000000, /* DENALI_PHY_798_DATA */
+ 0x00000000, /* DENALI_PHY_799_DATA */
+ 0x00030055, /* DENALI_PHY_800_DATA */
+ 0x03000300, /* DENALI_PHY_801_DATA */
+ 0x03000300, /* DENALI_PHY_802_DATA */
+ 0x00000300, /* DENALI_PHY_803_DATA */
+ 0x42080010, /* DENALI_PHY_804_DATA */
+ 0x00000003, /* DENALI_PHY_805_DATA */
+ 0x00000000, /* DENALI_PHY_806_DATA */
+ 0x00000000, /* DENALI_PHY_807_DATA */
+ 0x00000000, /* DENALI_PHY_808_DATA */
+ 0x00000000, /* DENALI_PHY_809_DATA */
+ 0x00000000, /* DENALI_PHY_810_DATA */
+ 0x00000000, /* DENALI_PHY_811_DATA */
+ 0x00000000, /* DENALI_PHY_812_DATA */
+ 0x00000000, /* DENALI_PHY_813_DATA */
+ 0x00000000, /* DENALI_PHY_814_DATA */
+ 0x00000000, /* DENALI_PHY_815_DATA */
+ 0x00000000, /* DENALI_PHY_816_DATA */
+ 0x00000000, /* DENALI_PHY_817_DATA */
+ 0x00000000, /* DENALI_PHY_818_DATA */
+ 0x00000000, /* DENALI_PHY_819_DATA */
+ 0x00000000, /* DENALI_PHY_820_DATA */
+ 0x00000000, /* DENALI_PHY_821_DATA */
+ 0x00000000, /* DENALI_PHY_822_DATA */
+ 0x00000000, /* DENALI_PHY_823_DATA */
+ 0x00000000, /* DENALI_PHY_824_DATA */
+ 0x00000000, /* DENALI_PHY_825_DATA */
+ 0x00000000, /* DENALI_PHY_826_DATA */
+ 0x00000000, /* DENALI_PHY_827_DATA */
+ 0x00000000, /* DENALI_PHY_828_DATA */
+ 0x00000000, /* DENALI_PHY_829_DATA */
+ 0x00000000, /* DENALI_PHY_830_DATA */
+ 0x00000000, /* DENALI_PHY_831_DATA */
+ 0x00000000, /* DENALI_PHY_832_DATA */
+ 0x00000000, /* DENALI_PHY_833_DATA */
+ 0x00000000, /* DENALI_PHY_834_DATA */
+ 0x00000000, /* DENALI_PHY_835_DATA */
+ 0x00000000, /* DENALI_PHY_836_DATA */
+ 0x00000000, /* DENALI_PHY_837_DATA */
+ 0x00000000, /* DENALI_PHY_838_DATA */
+ 0x00000000, /* DENALI_PHY_839_DATA */
+ 0x00000000, /* DENALI_PHY_840_DATA */
+ 0x00000000, /* DENALI_PHY_841_DATA */
+ 0x00000000, /* DENALI_PHY_842_DATA */
+ 0x00000000, /* DENALI_PHY_843_DATA */
+ 0x00000000, /* DENALI_PHY_844_DATA */
+ 0x00000000, /* DENALI_PHY_845_DATA */
+ 0x00000000, /* DENALI_PHY_846_DATA */
+ 0x00000000, /* DENALI_PHY_847_DATA */
+ 0x00000000, /* DENALI_PHY_848_DATA */
+ 0x00000000, /* DENALI_PHY_849_DATA */
+ 0x00000000, /* DENALI_PHY_850_DATA */
+ 0x00000000, /* DENALI_PHY_851_DATA */
+ 0x00000000, /* DENALI_PHY_852_DATA */
+ 0x00000000, /* DENALI_PHY_853_DATA */
+ 0x00000000, /* DENALI_PHY_854_DATA */
+ 0x00000000, /* DENALI_PHY_855_DATA */
+ 0x00000000, /* DENALI_PHY_856_DATA */
+ 0x00000000, /* DENALI_PHY_857_DATA */
+ 0x00000000, /* DENALI_PHY_858_DATA */
+ 0x00000000, /* DENALI_PHY_859_DATA */
+ 0x00000000, /* DENALI_PHY_860_DATA */
+ 0x00000000, /* DENALI_PHY_861_DATA */
+ 0x00000000, /* DENALI_PHY_862_DATA */
+ 0x00000000, /* DENALI_PHY_863_DATA */
+ 0x00000000, /* DENALI_PHY_864_DATA */
+ 0x00000000, /* DENALI_PHY_865_DATA */
+ 0x00000000, /* DENALI_PHY_866_DATA */
+ 0x00000000, /* DENALI_PHY_867_DATA */
+ 0x00000000, /* DENALI_PHY_868_DATA */
+ 0x00000000, /* DENALI_PHY_869_DATA */
+ 0x00000000, /* DENALI_PHY_870_DATA */
+ 0x00000000, /* DENALI_PHY_871_DATA */
+ 0x00000000, /* DENALI_PHY_872_DATA */
+ 0x00000000, /* DENALI_PHY_873_DATA */
+ 0x00000000, /* DENALI_PHY_874_DATA */
+ 0x00000000, /* DENALI_PHY_875_DATA */
+ 0x00000000, /* DENALI_PHY_876_DATA */
+ 0x00000000, /* DENALI_PHY_877_DATA */
+ 0x00000000, /* DENALI_PHY_878_DATA */
+ 0x00000000, /* DENALI_PHY_879_DATA */
+ 0x00000000, /* DENALI_PHY_880_DATA */
+ 0x00000000, /* DENALI_PHY_881_DATA */
+ 0x00000000, /* DENALI_PHY_882_DATA */
+ 0x00000000, /* DENALI_PHY_883_DATA */
+ 0x00000000, /* DENALI_PHY_884_DATA */
+ 0x00000000, /* DENALI_PHY_885_DATA */
+ 0x00000000, /* DENALI_PHY_886_DATA */
+ 0x00000000, /* DENALI_PHY_887_DATA */
+ 0x00000000, /* DENALI_PHY_888_DATA */
+ 0x00000000, /* DENALI_PHY_889_DATA */
+ 0x00000000, /* DENALI_PHY_890_DATA */
+ 0x00000000, /* DENALI_PHY_891_DATA */
+ 0x00000000, /* DENALI_PHY_892_DATA */
+ 0x00000000, /* DENALI_PHY_893_DATA */
+ 0x00000000, /* DENALI_PHY_894_DATA */
+ 0x00000000, /* DENALI_PHY_895_DATA */
+ 0x00000000, /* DENALI_PHY_896_DATA */
+ 0x00000000, /* DENALI_PHY_897_DATA */
+ 0x00000005, /* DENALI_PHY_898_DATA */
+ 0x04000f01, /* DENALI_PHY_899_DATA */
+ 0x00020040, /* DENALI_PHY_900_DATA */
+ 0x00020055, /* DENALI_PHY_901_DATA */
+ 0x00000000, /* DENALI_PHY_902_DATA */
+ 0x00000000, /* DENALI_PHY_903_DATA */
+ 0x00000000, /* DENALI_PHY_904_DATA */
+ 0x00000050, /* DENALI_PHY_905_DATA */
+ 0x00000000, /* DENALI_PHY_906_DATA */
+ 0x01010100, /* DENALI_PHY_907_DATA */
+ 0x00000600, /* DENALI_PHY_908_DATA */
+ 0x00000000, /* DENALI_PHY_909_DATA */
+ 0x00006400, /* DENALI_PHY_910_DATA */
+ 0x03221302, /* DENALI_PHY_911_DATA */
+ 0x00000000, /* DENALI_PHY_912_DATA */
+ 0x000d1f01, /* DENALI_PHY_913_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_914_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_915_DATA */
+ 0x00030003, /* DENALI_PHY_916_DATA */
+ 0x03000300, /* DENALI_PHY_917_DATA */
+ 0x00000300, /* DENALI_PHY_918_DATA */
+ 0x03221302, /* DENALI_PHY_919_DATA */
+ 0x00000000, /* DENALI_PHY_920_DATA */
+ 0x00000000, /* DENALI_PHY_921_DATA */
+ 0x01020000, /* DENALI_PHY_922_DATA */
+ 0x00000001, /* DENALI_PHY_923_DATA */
+ 0x00000411, /* DENALI_PHY_924_DATA */
+ 0x00000411, /* DENALI_PHY_925_DATA */
+ 0x00000040, /* DENALI_PHY_926_DATA */
+ 0x00000040, /* DENALI_PHY_927_DATA */
+ 0x00000411, /* DENALI_PHY_928_DATA */
+ 0x00000411, /* DENALI_PHY_929_DATA */
+ 0x00004410, /* DENALI_PHY_930_DATA */
+ 0x00004410, /* DENALI_PHY_931_DATA */
+ 0x00004410, /* DENALI_PHY_932_DATA */
+ 0x00004410, /* DENALI_PHY_933_DATA */
+ 0x00004410, /* DENALI_PHY_934_DATA */
+ 0x00000411, /* DENALI_PHY_935_DATA */
+ 0x00004410, /* DENALI_PHY_936_DATA */
+ 0x00000411, /* DENALI_PHY_937_DATA */
+ 0x00004410, /* DENALI_PHY_938_DATA */
+ 0x00000411, /* DENALI_PHY_939_DATA */
+ 0x00004410, /* DENALI_PHY_940_DATA */
+ 0x00000000, /* DENALI_PHY_941_DATA */
+ 0x00000000, /* DENALI_PHY_942_DATA */
+ 0x00000000, /* DENALI_PHY_943_DATA */
+ 0x64000000, /* DENALI_PHY_944_DATA */
+ 0x00000000, /* DENALI_PHY_945_DATA */
+ 0x00000000, /* DENALI_PHY_946_DATA */
+ 0x00000408, /* DENALI_PHY_947_DATA */
+ 0x00000000, /* DENALI_PHY_948_DATA */
+ 0x00000000, /* DENALI_PHY_949_DATA */
+ 0x00000000, /* DENALI_PHY_950_DATA */
+ 0x00000000, /* DENALI_PHY_951_DATA */
+ 0x00000000, /* DENALI_PHY_952_DATA */
+ 0x00000000, /* DENALI_PHY_953_DATA */
+ 0xe4000000, /* DENALI_PHY_954_DATA */
+ 0x00000000, /* DENALI_PHY_955_DATA */
+ 0x00000000, /* DENALI_PHY_956_DATA */
+ 0x01010000, /* DENALI_PHY_957_DATA */
+ 0x00000000 /* DENALI_PHY_958_DATA */
+ }
+ },
+},
diff --git a/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
new file mode 100644
index 00000000000..d8ae3359a39
--- /dev/null
+++ b/drivers/ram/rockchip/sdram-rk3399-lpddr4-800.inc
@@ -0,0 +1,1570 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd.
+ * (C) Copyright 2019 Amarula Solutions
+ */
+
+{
+ {
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ },
+ {
+ {
+ .rank = 0x2,
+ .col = 0xA,
+ .bk = 0x3,
+ .bw = 0x2,
+ .dbw = 0x1,
+ .row_3_4 = 0x0,
+ .cs0_row = 0xF,
+ .cs1_row = 0xF,
+ .ddrconfig = 1,
+ },
+ {
+ .ddrtiminga0 = 0x80241d22,
+ .ddrtimingb0 = 0x15050f08,
+ .ddrtimingc0 = {
+ 0x00000602,
+ },
+ .devtodev0 = 0x00002122,
+ .ddrmode = {
+ 0x0000004c,
+ },
+ .agingx0 = 0x00000000,
+ }
+ }
+ },
+ {
+ .ddr_freq = 800 * MHz,
+ .dramtype = LPDDR4,
+ .num_channels = 2,
+ .stride = 13,
+ .odt = 1,
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_CTL_00_DATA */
+ 0x00000000, /* DENALI_CTL_01_DATA */
+ 0x00000000, /* DENALI_CTL_02_DATA */
+ 0x00000000, /* DENALI_CTL_03_DATA */
+ 0x00000000, /* DENALI_CTL_04_DATA */
+ 0x00013880, /* DENALI_CTL_05_DATA */
+ 0x000c3500, /* DENALI_CTL_06_DATA */
+ 0x00000005, /* DENALI_CTL_07_DATA */
+ 0x00000320, /* DENALI_CTL_08_DATA */
+ 0x00027100, /* DENALI_CTL_09_DATA */
+ 0x00186a00, /* DENALI_CTL_10_DATA */
+ 0x00000005, /* DENALI_CTL_11_DATA */
+ 0x00000640, /* DENALI_CTL_12_DATA */
+ 0x00002710, /* DENALI_CTL_13_DATA */
+ 0x000186a0, /* DENALI_CTL_14_DATA */
+ 0x00000005, /* DENALI_CTL_15_DATA */
+ 0x01000064, /* DENALI_CTL_16_DATA */
+ 0x00000000, /* DENALI_CTL_17_DATA */
+ 0x02020101, /* DENALI_CTL_18_DATA */
+ 0x00000102, /* DENALI_CTL_19_DATA */
+ 0x00000050, /* DENALI_CTL_20_DATA */
+ 0x000000c8, /* DENALI_CTL_21_DATA */
+ 0x00000000, /* DENALI_CTL_22_DATA */
+ 0x06140000, /* DENALI_CTL_23_DATA */
+ 0x00081c00, /* DENALI_CTL_24_DATA */
+ 0x0400040c, /* DENALI_CTL_25_DATA */
+ 0x19042008, /* DENALI_CTL_26_DATA */
+ 0x10080a11, /* DENALI_CTL_27_DATA */
+ 0x22310800, /* DENALI_CTL_28_DATA */
+ 0x00200f0a, /* DENALI_CTL_29_DATA */
+ 0x0a030704, /* DENALI_CTL_30_DATA */
+ 0x08000204, /* DENALI_CTL_31_DATA */
+ 0x00000a0a, /* DENALI_CTL_32_DATA */
+ 0x04006db0, /* DENALI_CTL_33_DATA */
+ 0x0a0a0804, /* DENALI_CTL_34_DATA */
+ 0x0600db60, /* DENALI_CTL_35_DATA */
+ 0x0a0a0806, /* DENALI_CTL_36_DATA */
+ 0x04000db6, /* DENALI_CTL_37_DATA */
+ 0x02030404, /* DENALI_CTL_38_DATA */
+ 0x0f0a0800, /* DENALI_CTL_39_DATA */
+ 0x08040411, /* DENALI_CTL_40_DATA */
+ 0x1400640a, /* DENALI_CTL_41_DATA */
+ 0x02010a0a, /* DENALI_CTL_42_DATA */
+ 0x00010001, /* DENALI_CTL_43_DATA */
+ 0x04082012, /* DENALI_CTL_44_DATA */
+ 0x00041109, /* DENALI_CTL_45_DATA */
+ 0x00000000, /* DENALI_CTL_46_DATA */
+ 0x03010000, /* DENALI_CTL_47_DATA */
+ 0x06100034, /* DENALI_CTL_48_DATA */
+ 0x0c280068, /* DENALI_CTL_49_DATA */
+ 0x00bb0007, /* DENALI_CTL_50_DATA */
+ 0x00000000, /* DENALI_CTL_51_DATA */
+ 0x00060003, /* DENALI_CTL_52_DATA */
+ 0x000a0003, /* DENALI_CTL_53_DATA */
+ 0x000a0014, /* DENALI_CTL_54_DATA */
+ 0x01000000, /* DENALI_CTL_55_DATA */
+ 0x030a0000, /* DENALI_CTL_56_DATA */
+ 0x0c000002, /* DENALI_CTL_57_DATA */
+ 0x00000103, /* DENALI_CTL_58_DATA */
+ 0x0003030a, /* DENALI_CTL_59_DATA */
+ 0x00060037, /* DENALI_CTL_60_DATA */
+ 0x0003006e, /* DENALI_CTL_61_DATA */
+ 0x05050007, /* DENALI_CTL_62_DATA */
+ 0x03020605, /* DENALI_CTL_63_DATA */
+ 0x06050301, /* DENALI_CTL_64_DATA */
+ 0x06020c05, /* DENALI_CTL_65_DATA */
+ 0x05050302, /* DENALI_CTL_66_DATA */
+ 0x03020305, /* DENALI_CTL_67_DATA */
+ 0x00000301, /* DENALI_CTL_68_DATA */
+ 0x00000301, /* DENALI_CTL_69_DATA */
+ 0x00000001, /* DENALI_CTL_70_DATA */
+ 0x00000000, /* DENALI_CTL_71_DATA */
+ 0x00000000, /* DENALI_CTL_72_DATA */
+ 0x01000000, /* DENALI_CTL_73_DATA */
+ 0x80104002, /* DENALI_CTL_74_DATA */
+ 0x00040003, /* DENALI_CTL_75_DATA */
+ 0x00040005, /* DENALI_CTL_76_DATA */
+ 0x00030000, /* DENALI_CTL_77_DATA */
+ 0x00050004, /* DENALI_CTL_78_DATA */
+ 0x00000004, /* DENALI_CTL_79_DATA */
+ 0x00040003, /* DENALI_CTL_80_DATA */
+ 0x00040005, /* DENALI_CTL_81_DATA */
+ 0x18400000, /* DENALI_CTL_82_DATA */
+ 0x00000c20, /* DENALI_CTL_83_DATA */
+ 0x185030a0, /* DENALI_CTL_84_DATA */
+ 0x02ec0000, /* DENALI_CTL_85_DATA */
+ 0x00000176, /* DENALI_CTL_86_DATA */
+ 0x00000000, /* DENALI_CTL_87_DATA */
+ 0x00000000, /* DENALI_CTL_88_DATA */
+ 0x00000000, /* DENALI_CTL_89_DATA */
+ 0x00000000, /* DENALI_CTL_90_DATA */
+ 0x00000000, /* DENALI_CTL_91_DATA */
+ 0x06030300, /* DENALI_CTL_92_DATA */
+ 0x00030303, /* DENALI_CTL_93_DATA */
+ 0x02030200, /* DENALI_CTL_94_DATA */
+ 0x00040703, /* DENALI_CTL_95_DATA */
+ 0x03020302, /* DENALI_CTL_96_DATA */
+ 0x02000407, /* DENALI_CTL_97_DATA */
+ 0x07030203, /* DENALI_CTL_98_DATA */
+ 0x00030f04, /* DENALI_CTL_99_DATA */
+ 0x00070004, /* DENALI_CTL_100_DATA */
+ 0x00000000, /* DENALI_CTL_101_DATA */
+ 0x00000000, /* DENALI_CTL_102_DATA */
+ 0x00000000, /* DENALI_CTL_103_DATA */
+ 0x00000000, /* DENALI_CTL_104_DATA */
+ 0x00000000, /* DENALI_CTL_105_DATA */
+ 0x00000000, /* DENALI_CTL_106_DATA */
+ 0x00000000, /* DENALI_CTL_107_DATA */
+ 0x00010000, /* DENALI_CTL_108_DATA */
+ 0x20040020, /* DENALI_CTL_109_DATA */
+ 0x00200400, /* DENALI_CTL_110_DATA */
+ 0x01000400, /* DENALI_CTL_111_DATA */
+ 0x00000b80, /* DENALI_CTL_112_DATA */
+ 0x00000000, /* DENALI_CTL_113_DATA */
+ 0x00000001, /* DENALI_CTL_114_DATA */
+ 0x00000002, /* DENALI_CTL_115_DATA */
+ 0x0000000e, /* DENALI_CTL_116_DATA */
+ 0x00000000, /* DENALI_CTL_117_DATA */
+ 0x00000000, /* DENALI_CTL_118_DATA */
+ 0x00000000, /* DENALI_CTL_119_DATA */
+ 0x00000000, /* DENALI_CTL_120_DATA */
+ 0x00000000, /* DENALI_CTL_121_DATA */
+ 0x00500000, /* DENALI_CTL_122_DATA */
+ 0x00640028, /* DENALI_CTL_123_DATA */
+ 0x00640404, /* DENALI_CTL_124_DATA */
+ 0x005000a0, /* DENALI_CTL_125_DATA */
+ 0x060600c8, /* DENALI_CTL_126_DATA */
+ 0x000a00c8, /* DENALI_CTL_127_DATA */
+ 0x000d0005, /* DENALI_CTL_128_DATA */
+ 0x000d0404, /* DENALI_CTL_129_DATA */
+ 0x00000000, /* DENALI_CTL_130_DATA */
+ 0x00000000, /* DENALI_CTL_131_DATA */
+ 0x00000000, /* DENALI_CTL_132_DATA */
+ 0x001400a3, /* DENALI_CTL_133_DATA */
+ 0x00e30009, /* DENALI_CTL_134_DATA */
+ 0x00120024, /* DENALI_CTL_135_DATA */
+ 0x00040063, /* DENALI_CTL_136_DATA */
+ 0x00000000, /* DENALI_CTL_137_DATA */
+ 0x00310031, /* DENALI_CTL_138_DATA */
+ 0x00000031, /* DENALI_CTL_139_DATA */
+ 0x004d0000, /* DENALI_CTL_140_DATA */
+ 0x004d004d, /* DENALI_CTL_141_DATA */
+ 0x004d0000, /* DENALI_CTL_142_DATA */
+ 0x004d004d, /* DENALI_CTL_143_DATA */
+ 0x00010101, /* DENALI_CTL_144_DATA */
+ 0x00000000, /* DENALI_CTL_145_DATA */
+ 0x00000000, /* DENALI_CTL_146_DATA */
+ 0x001400a3, /* DENALI_CTL_147_DATA */
+ 0x00e30009, /* DENALI_CTL_148_DATA */
+ 0x00120024, /* DENALI_CTL_149_DATA */
+ 0x00040063, /* DENALI_CTL_150_DATA */
+ 0x00000000, /* DENALI_CTL_151_DATA */
+ 0x00310031, /* DENALI_CTL_152_DATA */
+ 0x00000031, /* DENALI_CTL_153_DATA */
+ 0x004d0000, /* DENALI_CTL_154_DATA */
+ 0x004d004d, /* DENALI_CTL_155_DATA */
+ 0x004d0000, /* DENALI_CTL_156_DATA */
+ 0x004d004d, /* DENALI_CTL_157_DATA */
+ 0x00010101, /* DENALI_CTL_158_DATA */
+ 0x00000000, /* DENALI_CTL_159_DATA */
+ 0x00000000, /* DENALI_CTL_160_DATA */
+ 0x00000000, /* DENALI_CTL_161_DATA */
+ 0x00000001, /* DENALI_CTL_162_DATA */
+ 0x00000000, /* DENALI_CTL_163_DATA */
+ 0x18151100, /* DENALI_CTL_164_DATA */
+ 0x0000000c, /* DENALI_CTL_165_DATA */
+ 0x00000000, /* DENALI_CTL_166_DATA */
+ 0x00000000, /* DENALI_CTL_167_DATA */
+ 0x00000000, /* DENALI_CTL_168_DATA */
+ 0x00000000, /* DENALI_CTL_169_DATA */
+ 0x00000000, /* DENALI_CTL_170_DATA */
+ 0x00000000, /* DENALI_CTL_171_DATA */
+ 0x00000000, /* DENALI_CTL_172_DATA */
+ 0x00000000, /* DENALI_CTL_173_DATA */
+ 0x00000000, /* DENALI_CTL_174_DATA */
+ 0x00000000, /* DENALI_CTL_175_DATA */
+ 0x00000000, /* DENALI_CTL_176_DATA */
+ 0x00000000, /* DENALI_CTL_177_DATA */
+ 0x00000000, /* DENALI_CTL_178_DATA */
+ 0x00020003, /* DENALI_CTL_179_DATA */
+ 0x00400100, /* DENALI_CTL_180_DATA */
+ 0x000c0190, /* DENALI_CTL_181_DATA */
+ 0x01000200, /* DENALI_CTL_182_DATA */
+ 0x03200040, /* DENALI_CTL_183_DATA */
+ 0x00020018, /* DENALI_CTL_184_DATA */
+ 0x00400100, /* DENALI_CTL_185_DATA */
+ 0x00080032, /* DENALI_CTL_186_DATA */
+ 0x00140000, /* DENALI_CTL_187_DATA */
+ 0x00030028, /* DENALI_CTL_188_DATA */
+ 0x01010100, /* DENALI_CTL_189_DATA */
+ 0x02000202, /* DENALI_CTL_190_DATA */
+ 0x0b000002, /* DENALI_CTL_191_DATA */
+ 0x01000f0f, /* DENALI_CTL_192_DATA */
+ 0x00000000, /* DENALI_CTL_193_DATA */
+ 0x00000000, /* DENALI_CTL_194_DATA */
+ 0x00010003, /* DENALI_CTL_195_DATA */
+ 0x00000c03, /* DENALI_CTL_196_DATA */
+ 0x00040101, /* DENALI_CTL_197_DATA */
+ 0x04010100, /* DENALI_CTL_198_DATA */
+ 0x01000000, /* DENALI_CTL_199_DATA */
+ 0x02010000, /* DENALI_CTL_200_DATA */
+ 0x00000001, /* DENALI_CTL_201_DATA */
+ 0x00000000, /* DENALI_CTL_202_DATA */
+ 0x00000000, /* DENALI_CTL_203_DATA */
+ 0x00000000, /* DENALI_CTL_204_DATA */
+ 0x00000000, /* DENALI_CTL_205_DATA */
+ 0x00000000, /* DENALI_CTL_206_DATA */
+ 0x00000000, /* DENALI_CTL_207_DATA */
+ 0x00000000, /* DENALI_CTL_208_DATA */
+ 0x00000000, /* DENALI_CTL_209_DATA */
+ 0x00000000, /* DENALI_CTL_210_DATA */
+ 0x00010000, /* DENALI_CTL_211_DATA */
+ 0x00000001, /* DENALI_CTL_212_DATA */
+ 0x01010001, /* DENALI_CTL_213_DATA */
+ 0x05040001, /* DENALI_CTL_214_DATA */
+ 0x040a0703, /* DENALI_CTL_215_DATA */
+ 0x02080808, /* DENALI_CTL_216_DATA */
+ 0x020e000a, /* DENALI_CTL_217_DATA */
+ 0x020f010b, /* DENALI_CTL_218_DATA */
+ 0x000d0008, /* DENALI_CTL_219_DATA */
+ 0x00080b0a, /* DENALI_CTL_220_DATA */
+ 0x03000200, /* DENALI_CTL_221_DATA */
+ 0x00000100, /* DENALI_CTL_222_DATA */
+ 0x00000000, /* DENALI_CTL_223_DATA */
+ 0x00000000, /* DENALI_CTL_224_DATA */
+ 0x0d000001, /* DENALI_CTL_225_DATA */
+ 0x00000028, /* DENALI_CTL_226_DATA */
+ 0x00010000, /* DENALI_CTL_227_DATA */
+ 0x00000003, /* DENALI_CTL_228_DATA */
+ 0x00000000, /* DENALI_CTL_229_DATA */
+ 0x00000000, /* DENALI_CTL_230_DATA */
+ 0x00000000, /* DENALI_CTL_231_DATA */
+ 0x00000000, /* DENALI_CTL_232_DATA */
+ 0x00000000, /* DENALI_CTL_233_DATA */
+ 0x00000000, /* DENALI_CTL_234_DATA */
+ 0x00000000, /* DENALI_CTL_235_DATA */
+ 0x00000000, /* DENALI_CTL_236_DATA */
+ 0x00010100, /* DENALI_CTL_237_DATA */
+ 0x01000000, /* DENALI_CTL_238_DATA */
+ 0x00000001, /* DENALI_CTL_239_DATA */
+ 0x00000303, /* DENALI_CTL_240_DATA */
+ 0x00000000, /* DENALI_CTL_241_DATA */
+ 0x00000000, /* DENALI_CTL_242_DATA */
+ 0x00000000, /* DENALI_CTL_243_DATA */
+ 0x00000000, /* DENALI_CTL_244_DATA */
+ 0x00000000, /* DENALI_CTL_245_DATA */
+ 0x00000000, /* DENALI_CTL_246_DATA */
+ 0x00000000, /* DENALI_CTL_247_DATA */
+ 0x00000000, /* DENALI_CTL_248_DATA */
+ 0x00000000, /* DENALI_CTL_249_DATA */
+ 0x00000000, /* DENALI_CTL_250_DATA */
+ 0x00000000, /* DENALI_CTL_251_DATA */
+ 0x00000000, /* DENALI_CTL_252_DATA */
+ 0x00000000, /* DENALI_CTL_253_DATA */
+ 0x00000000, /* DENALI_CTL_254_DATA */
+ 0x00000000, /* DENALI_CTL_255_DATA */
+ 0x000556aa, /* DENALI_CTL_256_DATA */
+ 0x000aaaaa, /* DENALI_CTL_257_DATA */
+ 0x000aa955, /* DENALI_CTL_258_DATA */
+ 0x00055555, /* DENALI_CTL_259_DATA */
+ 0x000b3133, /* DENALI_CTL_260_DATA */
+ 0x0004cd33, /* DENALI_CTL_261_DATA */
+ 0x0004cecc, /* DENALI_CTL_262_DATA */
+ 0x000b32cc, /* DENALI_CTL_263_DATA */
+ 0x00010300, /* DENALI_CTL_264_DATA */
+ 0x03000100, /* DENALI_CTL_265_DATA */
+ 0x00000000, /* DENALI_CTL_266_DATA */
+ 0x00000000, /* DENALI_CTL_267_DATA */
+ 0x00000000, /* DENALI_CTL_268_DATA */
+ 0x00000000, /* DENALI_CTL_269_DATA */
+ 0x00000000, /* DENALI_CTL_270_DATA */
+ 0x00000000, /* DENALI_CTL_271_DATA */
+ 0x00000000, /* DENALI_CTL_272_DATA */
+ 0x00000000, /* DENALI_CTL_273_DATA */
+ 0x00ffff00, /* DENALI_CTL_274_DATA */
+ 0x1a160000, /* DENALI_CTL_275_DATA */
+ 0x08000012, /* DENALI_CTL_276_DATA */
+ 0x00000c20, /* DENALI_CTL_277_DATA */
+ 0x00000200, /* DENALI_CTL_278_DATA */
+ 0x00000200, /* DENALI_CTL_279_DATA */
+ 0x00000200, /* DENALI_CTL_280_DATA */
+ 0x00000200, /* DENALI_CTL_281_DATA */
+ 0x00000c20, /* DENALI_CTL_282_DATA */
+ 0x00007940, /* DENALI_CTL_283_DATA */
+ 0x18500409, /* DENALI_CTL_284_DATA */
+ 0x00000200, /* DENALI_CTL_285_DATA */
+ 0x00000200, /* DENALI_CTL_286_DATA */
+ 0x00000200, /* DENALI_CTL_287_DATA */
+ 0x00000200, /* DENALI_CTL_288_DATA */
+ 0x00001850, /* DENALI_CTL_289_DATA */
+ 0x0000f320, /* DENALI_CTL_290_DATA */
+ 0x0176060c, /* DENALI_CTL_291_DATA */
+ 0x00000200, /* DENALI_CTL_292_DATA */
+ 0x00000200, /* DENALI_CTL_293_DATA */
+ 0x00000200, /* DENALI_CTL_294_DATA */
+ 0x00000200, /* DENALI_CTL_295_DATA */
+ 0x00000176, /* DENALI_CTL_296_DATA */
+ 0x00000e9c, /* DENALI_CTL_297_DATA */
+ 0x02020205, /* DENALI_CTL_298_DATA */
+ 0x03030202, /* DENALI_CTL_299_DATA */
+ 0x00000018, /* DENALI_CTL_300_DATA */
+ 0x00000000, /* DENALI_CTL_301_DATA */
+ 0x00000000, /* DENALI_CTL_302_DATA */
+ 0x00001403, /* DENALI_CTL_303_DATA */
+ 0x00000000, /* DENALI_CTL_304_DATA */
+ 0x00000000, /* DENALI_CTL_305_DATA */
+ 0x00000000, /* DENALI_CTL_306_DATA */
+ 0x00030000, /* DENALI_CTL_307_DATA */
+ 0x000a001c, /* DENALI_CTL_308_DATA */
+ 0x000e0020, /* DENALI_CTL_309_DATA */
+ 0x00060018, /* DENALI_CTL_310_DATA */
+ 0x00000000, /* DENALI_CTL_311_DATA */
+ 0x00000000, /* DENALI_CTL_312_DATA */
+ 0x02000000, /* DENALI_CTL_313_DATA */
+ 0x00090305, /* DENALI_CTL_314_DATA */
+ 0x00050101, /* DENALI_CTL_315_DATA */
+ 0x00000000, /* DENALI_CTL_316_DATA */
+ 0x00000000, /* DENALI_CTL_317_DATA */
+ 0x00000000, /* DENALI_CTL_318_DATA */
+ 0x00000000, /* DENALI_CTL_319_DATA */
+ 0x00000000, /* DENALI_CTL_320_DATA */
+ 0x00000000, /* DENALI_CTL_321_DATA */
+ 0x00000000, /* DENALI_CTL_322_DATA */
+ 0x00000000, /* DENALI_CTL_323_DATA */
+ 0x01000001, /* DENALI_CTL_324_DATA */
+ 0x01010101, /* DENALI_CTL_325_DATA */
+ 0x01000101, /* DENALI_CTL_326_DATA */
+ 0x01000100, /* DENALI_CTL_327_DATA */
+ 0x00010001, /* DENALI_CTL_328_DATA */
+ 0x00010002, /* DENALI_CTL_329_DATA */
+ 0x00020100, /* DENALI_CTL_330_DATA */
+ 0x00000002 /* DENALI_CTL_331_DATA */
+ }
+ },
+ {
+ {
+ 0x00000b00, /* DENALI_PI_00_DATA */
+ 0x00000000, /* DENALI_PI_01_DATA */
+ 0x000002ec, /* DENALI_PI_02_DATA */
+ 0x00000176, /* DENALI_PI_03_DATA */
+ 0x000030a0, /* DENALI_PI_04_DATA */
+ 0x00001850, /* DENALI_PI_05_DATA */
+ 0x00001840, /* DENALI_PI_06_DATA */
+ 0x01760c20, /* DENALI_PI_07_DATA */
+ 0x00000200, /* DENALI_PI_08_DATA */
+ 0x00000200, /* DENALI_PI_09_DATA */
+ 0x00000200, /* DENALI_PI_10_DATA */
+ 0x00000200, /* DENALI_PI_11_DATA */
+ 0x00001850, /* DENALI_PI_12_DATA */
+ 0x00000200, /* DENALI_PI_13_DATA */
+ 0x00000200, /* DENALI_PI_14_DATA */
+ 0x00000200, /* DENALI_PI_15_DATA */
+ 0x00000200, /* DENALI_PI_16_DATA */
+ 0x00000c20, /* DENALI_PI_17_DATA */
+ 0x00000200, /* DENALI_PI_18_DATA */
+ 0x00000200, /* DENALI_PI_19_DATA */
+ 0x00000200, /* DENALI_PI_20_DATA */
+ 0x00000200, /* DENALI_PI_21_DATA */
+ 0x00010000, /* DENALI_PI_22_DATA */
+ 0x00000007, /* DENALI_PI_23_DATA */
+ 0x01000001, /* DENALI_PI_24_DATA */
+ 0x00000000, /* DENALI_PI_25_DATA */
+ 0x3fffffff, /* DENALI_PI_26_DATA */
+ 0x00000000, /* DENALI_PI_27_DATA */
+ 0x00000000, /* DENALI_PI_28_DATA */
+ 0x00000000, /* DENALI_PI_29_DATA */
+ 0x00000000, /* DENALI_PI_30_DATA */
+ 0x00000000, /* DENALI_PI_31_DATA */
+ 0x00000000, /* DENALI_PI_32_DATA */
+ 0x00000000, /* DENALI_PI_33_DATA */
+ 0x00000000, /* DENALI_PI_34_DATA */
+ 0x00000000, /* DENALI_PI_35_DATA */
+ 0x00000000, /* DENALI_PI_36_DATA */
+ 0x00000000, /* DENALI_PI_37_DATA */
+ 0x00000000, /* DENALI_PI_38_DATA */
+ 0x00000000, /* DENALI_PI_39_DATA */
+ 0x00000000, /* DENALI_PI_40_DATA */
+ 0x0f000101, /* DENALI_PI_41_DATA */
+ 0x082b3223, /* DENALI_PI_42_DATA */
+ 0x080c0004, /* DENALI_PI_43_DATA */
+ 0x00061c00, /* DENALI_PI_44_DATA */
+ 0x00000214, /* DENALI_PI_45_DATA */
+ 0x00bb0007, /* DENALI_PI_46_DATA */
+ 0x0c280068, /* DENALI_PI_47_DATA */
+ 0x06100034, /* DENALI_PI_48_DATA */
+ 0x00000500, /* DENALI_PI_49_DATA */
+ 0x00000000, /* DENALI_PI_50_DATA */
+ 0x00000000, /* DENALI_PI_51_DATA */
+ 0x00000000, /* DENALI_PI_52_DATA */
+ 0x00000000, /* DENALI_PI_53_DATA */
+ 0x00000000, /* DENALI_PI_54_DATA */
+ 0x00000000, /* DENALI_PI_55_DATA */
+ 0x00000000, /* DENALI_PI_56_DATA */
+ 0x00000000, /* DENALI_PI_57_DATA */
+ 0x04040100, /* DENALI_PI_58_DATA */
+ 0x0a000004, /* DENALI_PI_59_DATA */
+ 0x00000128, /* DENALI_PI_60_DATA */
+ 0x00000000, /* DENALI_PI_61_DATA */
+ 0x0003000f, /* DENALI_PI_62_DATA */
+ 0x00000018, /* DENALI_PI_63_DATA */
+ 0x00000000, /* DENALI_PI_64_DATA */
+ 0x00000000, /* DENALI_PI_65_DATA */
+ 0x00060002, /* DENALI_PI_66_DATA */
+ 0x00010001, /* DENALI_PI_67_DATA */
+ 0x00000101, /* DENALI_PI_68_DATA */
+ 0x00020001, /* DENALI_PI_69_DATA */
+ 0x00080004, /* DENALI_PI_70_DATA */
+ 0x00000000, /* DENALI_PI_71_DATA */
+ 0x05030000, /* DENALI_PI_72_DATA */
+ 0x070a0404, /* DENALI_PI_73_DATA */
+ 0x00000000, /* DENALI_PI_74_DATA */
+ 0x00000000, /* DENALI_PI_75_DATA */
+ 0x00000000, /* DENALI_PI_76_DATA */
+ 0x000f0f00, /* DENALI_PI_77_DATA */
+ 0x0000001e, /* DENALI_PI_78_DATA */
+ 0x00000000, /* DENALI_PI_79_DATA */
+ 0x01010300, /* DENALI_PI_80_DATA */
+ 0x00000000, /* DENALI_PI_81_DATA */
+ 0x00000000, /* DENALI_PI_82_DATA */
+ 0x01000000, /* DENALI_PI_83_DATA */
+ 0x00000101, /* DENALI_PI_84_DATA */
+ 0x55555a5a, /* DENALI_PI_85_DATA */
+ 0x55555a5a, /* DENALI_PI_86_DATA */
+ 0x55555a5a, /* DENALI_PI_87_DATA */
+ 0x55555a5a, /* DENALI_PI_88_DATA */
+ 0x0c050001, /* DENALI_PI_89_DATA */
+ 0x06020009, /* DENALI_PI_90_DATA */
+ 0x00010004, /* DENALI_PI_91_DATA */
+ 0x00000203, /* DENALI_PI_92_DATA */
+ 0x00030000, /* DENALI_PI_93_DATA */
+ 0x170f0000, /* DENALI_PI_94_DATA */
+ 0x00060018, /* DENALI_PI_95_DATA */
+ 0x000e0020, /* DENALI_PI_96_DATA */
+ 0x000a001c, /* DENALI_PI_97_DATA */
+ 0x00000000, /* DENALI_PI_98_DATA */
+ 0x00000000, /* DENALI_PI_99_DATA */
+ 0x00000100, /* DENALI_PI_100_DATA */
+ 0x140a0000, /* DENALI_PI_101_DATA */
+ 0x000d010a, /* DENALI_PI_102_DATA */
+ 0x0100c802, /* DENALI_PI_103_DATA */
+ 0x010a0064, /* DENALI_PI_104_DATA */
+ 0x000e0100, /* DENALI_PI_105_DATA */
+ 0x0100000e, /* DENALI_PI_106_DATA */
+ 0x00c900c9, /* DENALI_PI_107_DATA */
+ 0x00650100, /* DENALI_PI_108_DATA */
+ 0x1e1a0065, /* DENALI_PI_109_DATA */
+ 0x10010204, /* DENALI_PI_110_DATA */
+ 0x06070605, /* DENALI_PI_111_DATA */
+ 0x20000202, /* DENALI_PI_112_DATA */
+ 0x00201000, /* DENALI_PI_113_DATA */
+ 0x00201000, /* DENALI_PI_114_DATA */
+ 0x04041000, /* DENALI_PI_115_DATA */
+ 0x10020100, /* DENALI_PI_116_DATA */
+ 0x0003010c, /* DENALI_PI_117_DATA */
+ 0x004b004a, /* DENALI_PI_118_DATA */
+ 0x1a0f0000, /* DENALI_PI_119_DATA */
+ 0x0102041e, /* DENALI_PI_120_DATA */
+ 0x34000000, /* DENALI_PI_121_DATA */
+ 0x00000000, /* DENALI_PI_122_DATA */
+ 0x00000000, /* DENALI_PI_123_DATA */
+ 0x00010000, /* DENALI_PI_124_DATA */
+ 0x00000400, /* DENALI_PI_125_DATA */
+ 0x00310000, /* DENALI_PI_126_DATA */
+ 0x004d4d00, /* DENALI_PI_127_DATA */
+ 0x00120024, /* DENALI_PI_128_DATA */
+ 0x4d000031, /* DENALI_PI_129_DATA */
+ 0x0000144d, /* DENALI_PI_130_DATA */
+ 0x00310009, /* DENALI_PI_131_DATA */
+ 0x004d4d00, /* DENALI_PI_132_DATA */
+ 0x00000004, /* DENALI_PI_133_DATA */
+ 0x4d000031, /* DENALI_PI_134_DATA */
+ 0x0000244d, /* DENALI_PI_135_DATA */
+ 0x00310012, /* DENALI_PI_136_DATA */
+ 0x004d4d00, /* DENALI_PI_137_DATA */
+ 0x00090014, /* DENALI_PI_138_DATA */
+ 0x4d000031, /* DENALI_PI_139_DATA */
+ 0x0004004d, /* DENALI_PI_140_DATA */
+ 0x00310000, /* DENALI_PI_141_DATA */
+ 0x004d4d00, /* DENALI_PI_142_DATA */
+ 0x00120024, /* DENALI_PI_143_DATA */
+ 0x4d000031, /* DENALI_PI_144_DATA */
+ 0x0000144d, /* DENALI_PI_145_DATA */
+ 0x00310009, /* DENALI_PI_146_DATA */
+ 0x004d4d00, /* DENALI_PI_147_DATA */
+ 0x00000004, /* DENALI_PI_148_DATA */
+ 0x4d000031, /* DENALI_PI_149_DATA */
+ 0x0000244d, /* DENALI_PI_150_DATA */
+ 0x00310012, /* DENALI_PI_151_DATA */
+ 0x004d4d00, /* DENALI_PI_152_DATA */
+ 0x00090014, /* DENALI_PI_153_DATA */
+ 0x4d000031, /* DENALI_PI_154_DATA */
+ 0x0200004d, /* DENALI_PI_155_DATA */
+ 0x00c8000d, /* DENALI_PI_156_DATA */
+ 0x08080064, /* DENALI_PI_157_DATA */
+ 0x040a0404, /* DENALI_PI_158_DATA */
+ 0x03000d92, /* DENALI_PI_159_DATA */
+ 0x010a2001, /* DENALI_PI_160_DATA */
+ 0x0f11080a, /* DENALI_PI_161_DATA */
+ 0x0000110a, /* DENALI_PI_162_DATA */
+ 0x2200d92e, /* DENALI_PI_163_DATA */
+ 0x080c2003, /* DENALI_PI_164_DATA */
+ 0x0809080a, /* DENALI_PI_165_DATA */
+ 0x00000a0a, /* DENALI_PI_166_DATA */
+ 0x11006c97, /* DENALI_PI_167_DATA */
+ 0x040a2002, /* DENALI_PI_168_DATA */
+ 0x0200020a, /* DENALI_PI_169_DATA */
+ 0x02000200, /* DENALI_PI_170_DATA */
+ 0x02000200, /* DENALI_PI_171_DATA */
+ 0x02000200, /* DENALI_PI_172_DATA */
+ 0x02000200, /* DENALI_PI_173_DATA */
+ 0x00000000, /* DENALI_PI_174_DATA */
+ 0x00000000, /* DENALI_PI_175_DATA */
+ 0x00000000, /* DENALI_PI_176_DATA */
+ 0x00000000, /* DENALI_PI_177_DATA */
+ 0x00000000, /* DENALI_PI_178_DATA */
+ 0x00000000, /* DENALI_PI_179_DATA */
+ 0x00000000, /* DENALI_PI_180_DATA */
+ 0x00000000, /* DENALI_PI_181_DATA */
+ 0x00000000, /* DENALI_PI_182_DATA */
+ 0x00000000, /* DENALI_PI_183_DATA */
+ 0x00000000, /* DENALI_PI_184_DATA */
+ 0x00000000, /* DENALI_PI_185_DATA */
+ 0x01000400, /* DENALI_PI_186_DATA */
+ 0x00017600, /* DENALI_PI_187_DATA */
+ 0x00000e9c, /* DENALI_PI_188_DATA */
+ 0x00001850, /* DENALI_PI_189_DATA */
+ 0x0000f320, /* DENALI_PI_190_DATA */
+ 0x00000c20, /* DENALI_PI_191_DATA */
+ 0x00007940, /* DENALI_PI_192_DATA */
+ 0x08000000, /* DENALI_PI_193_DATA */
+ 0x00000100, /* DENALI_PI_194_DATA */
+ 0x00000000, /* DENALI_PI_195_DATA */
+ 0x00000000, /* DENALI_PI_196_DATA */
+ 0x00000000, /* DENALI_PI_197_DATA */
+ 0x00000000, /* DENALI_PI_198_DATA */
+ 0x00000002 /* DENALI_PI_199_DATA */
+ }
+ },
+ {
+ {
+ 0x76543210, /* DENALI_PHY_00_DATA */
+ 0x0004f008, /* DENALI_PHY_01_DATA */
+ 0x00020119, /* DENALI_PHY_02_DATA */
+ 0x00000000, /* DENALI_PHY_03_DATA */
+ 0x00000000, /* DENALI_PHY_04_DATA */
+ 0x00010000, /* DENALI_PHY_05_DATA */
+ 0x01665555, /* DENALI_PHY_06_DATA */
+ 0x03665555, /* DENALI_PHY_07_DATA */
+ 0x00010f00, /* DENALI_PHY_08_DATA */
+ 0x05010200, /* DENALI_PHY_09_DATA */
+ 0x00000002, /* DENALI_PHY_10_DATA */
+ 0x00170180, /* DENALI_PHY_11_DATA */
+ 0x00cc0201, /* DENALI_PHY_12_DATA */
+ 0x00030066, /* DENALI_PHY_13_DATA */
+ 0x00000000, /* DENALI_PHY_14_DATA */
+ 0x00000000, /* DENALI_PHY_15_DATA */
+ 0x00000000, /* DENALI_PHY_16_DATA */
+ 0x00000000, /* DENALI_PHY_17_DATA */
+ 0x00000000, /* DENALI_PHY_18_DATA */
+ 0x00000000, /* DENALI_PHY_19_DATA */
+ 0x00000000, /* DENALI_PHY_20_DATA */
+ 0x00000000, /* DENALI_PHY_21_DATA */
+ 0x04080000, /* DENALI_PHY_22_DATA */
+ 0x04080400, /* DENALI_PHY_23_DATA */
+ 0x30000000, /* DENALI_PHY_24_DATA */
+ 0x0c00c007, /* DENALI_PHY_25_DATA */
+ 0x00000100, /* DENALI_PHY_26_DATA */
+ 0x00000000, /* DENALI_PHY_27_DATA */
+ 0xfd02fe01, /* DENALI_PHY_28_DATA */
+ 0xf708fb04, /* DENALI_PHY_29_DATA */
+ 0xdf20ef10, /* DENALI_PHY_30_DATA */
+ 0x7f80bf40, /* DENALI_PHY_31_DATA */
+ 0x0001aaaa, /* DENALI_PHY_32_DATA */
+ 0x00000000, /* DENALI_PHY_33_DATA */
+ 0x00000000, /* DENALI_PHY_34_DATA */
+ 0x00000000, /* DENALI_PHY_35_DATA */
+ 0x00000000, /* DENALI_PHY_36_DATA */
+ 0x00000000, /* DENALI_PHY_37_DATA */
+ 0x00000000, /* DENALI_PHY_38_DATA */
+ 0x00000000, /* DENALI_PHY_39_DATA */
+ 0x00000000, /* DENALI_PHY_40_DATA */
+ 0x00000000, /* DENALI_PHY_41_DATA */
+ 0x00000000, /* DENALI_PHY_42_DATA */
+ 0x00000000, /* DENALI_PHY_43_DATA */
+ 0x00000000, /* DENALI_PHY_44_DATA */
+ 0x00000000, /* DENALI_PHY_45_DATA */
+ 0x00000000, /* DENALI_PHY_46_DATA */
+ 0x00000000, /* DENALI_PHY_47_DATA */
+ 0x00000000, /* DENALI_PHY_48_DATA */
+ 0x00000000, /* DENALI_PHY_49_DATA */
+ 0x00000000, /* DENALI_PHY_50_DATA */
+ 0x00000000, /* DENALI_PHY_51_DATA */
+ 0x00200000, /* DENALI_PHY_52_DATA */
+ 0x00000000, /* DENALI_PHY_53_DATA */
+ 0x00000000, /* DENALI_PHY_54_DATA */
+ 0x00000000, /* DENALI_PHY_55_DATA */
+ 0x00000000, /* DENALI_PHY_56_DATA */
+ 0x00000000, /* DENALI_PHY_57_DATA */
+ 0x00000000, /* DENALI_PHY_58_DATA */
+ 0x02800280, /* DENALI_PHY_59_DATA */
+ 0x02800280, /* DENALI_PHY_60_DATA */
+ 0x02800280, /* DENALI_PHY_61_DATA */
+ 0x02800280, /* DENALI_PHY_62_DATA */
+ 0x00000280, /* DENALI_PHY_63_DATA */
+ 0x00000000, /* DENALI_PHY_64_DATA */
+ 0x00000000, /* DENALI_PHY_65_DATA */
+ 0x00000000, /* DENALI_PHY_66_DATA */
+ 0x00000000, /* DENALI_PHY_67_DATA */
+ 0x00800000, /* DENALI_PHY_68_DATA */
+ 0x00800080, /* DENALI_PHY_69_DATA */
+ 0x00800080, /* DENALI_PHY_70_DATA */
+ 0x00800080, /* DENALI_PHY_71_DATA */
+ 0x00800080, /* DENALI_PHY_72_DATA */
+ 0x00800080, /* DENALI_PHY_73_DATA */
+ 0x00800080, /* DENALI_PHY_74_DATA */
+ 0x00800080, /* DENALI_PHY_75_DATA */
+ 0x00800080, /* DENALI_PHY_76_DATA */
+ 0x01190080, /* DENALI_PHY_77_DATA */
+ 0x00000002, /* DENALI_PHY_78_DATA */
+ 0x00000000, /* DENALI_PHY_79_DATA */
+ 0x00000000, /* DENALI_PHY_80_DATA */
+ 0x00000200, /* DENALI_PHY_81_DATA */
+ 0x00000000, /* DENALI_PHY_82_DATA */
+ 0x51315152, /* DENALI_PHY_83_DATA */
+ 0xc0013150, /* DENALI_PHY_84_DATA */
+ 0x020000c0, /* DENALI_PHY_85_DATA */
+ 0x00100001, /* DENALI_PHY_86_DATA */
+ 0x07054204, /* DENALI_PHY_87_DATA */
+ 0x000f0c18, /* DENALI_PHY_88_DATA */
+ 0x01000140, /* DENALI_PHY_89_DATA */
+ 0x00000c10, /* DENALI_PHY_90_DATA */
+ 0x00000000, /* DENALI_PHY_91_DATA */
+ 0x00000000, /* DENALI_PHY_92_DATA */
+ 0x00000000, /* DENALI_PHY_93_DATA */
+ 0x00000000, /* DENALI_PHY_94_DATA */
+ 0x00000000, /* DENALI_PHY_95_DATA */
+ 0x00000000, /* DENALI_PHY_96_DATA */
+ 0x00000000, /* DENALI_PHY_97_DATA */
+ 0x00000000, /* DENALI_PHY_98_DATA */
+ 0x00000000, /* DENALI_PHY_99_DATA */
+ 0x00000000, /* DENALI_PHY_100_DATA */
+ 0x00000000, /* DENALI_PHY_101_DATA */
+ 0x00000000, /* DENALI_PHY_102_DATA */
+ 0x00000000, /* DENALI_PHY_103_DATA */
+ 0x00000000, /* DENALI_PHY_104_DATA */
+ 0x00000000, /* DENALI_PHY_105_DATA */
+ 0x00000000, /* DENALI_PHY_106_DATA */
+ 0x00000000, /* DENALI_PHY_107_DATA */
+ 0x00000000, /* DENALI_PHY_108_DATA */
+ 0x00000000, /* DENALI_PHY_109_DATA */
+ 0x00000000, /* DENALI_PHY_110_DATA */
+ 0x00000000, /* DENALI_PHY_111_DATA */
+ 0x00000000, /* DENALI_PHY_112_DATA */
+ 0x00000000, /* DENALI_PHY_113_DATA */
+ 0x00000000, /* DENALI_PHY_114_DATA */
+ 0x00000000, /* DENALI_PHY_115_DATA */
+ 0x00000000, /* DENALI_PHY_116_DATA */
+ 0x00000000, /* DENALI_PHY_117_DATA */
+ 0x00000000, /* DENALI_PHY_118_DATA */
+ 0x00000000, /* DENALI_PHY_119_DATA */
+ 0x00000000, /* DENALI_PHY_120_DATA */
+ 0x00000000, /* DENALI_PHY_121_DATA */
+ 0x00000000, /* DENALI_PHY_122_DATA */
+ 0x00000000, /* DENALI_PHY_123_DATA */
+ 0x00000000, /* DENALI_PHY_124_DATA */
+ 0x00000000, /* DENALI_PHY_125_DATA */
+ 0x00000000, /* DENALI_PHY_126_DATA */
+ 0x00000000, /* DENALI_PHY_127_DATA */
+ 0x76543210, /* DENALI_PHY_128_DATA */
+ 0x0004f008, /* DENALI_PHY_129_DATA */
+ 0x00020119, /* DENALI_PHY_130_DATA */
+ 0x00000000, /* DENALI_PHY_131_DATA */
+ 0x00000000, /* DENALI_PHY_132_DATA */
+ 0x00010000, /* DENALI_PHY_133_DATA */
+ 0x01665555, /* DENALI_PHY_134_DATA */
+ 0x03665555, /* DENALI_PHY_135_DATA */
+ 0x00010f00, /* DENALI_PHY_136_DATA */
+ 0x05010200, /* DENALI_PHY_137_DATA */
+ 0x00000002, /* DENALI_PHY_138_DATA */
+ 0x00170180, /* DENALI_PHY_139_DATA */
+ 0x00cc0201, /* DENALI_PHY_140_DATA */
+ 0x00030066, /* DENALI_PHY_141_DATA */
+ 0x00000000, /* DENALI_PHY_142_DATA */
+ 0x00000000, /* DENALI_PHY_143_DATA */
+ 0x00000000, /* DENALI_PHY_144_DATA */
+ 0x00000000, /* DENALI_PHY_145_DATA */
+ 0x00000000, /* DENALI_PHY_146_DATA */
+ 0x00000000, /* DENALI_PHY_147_DATA */
+ 0x00000000, /* DENALI_PHY_148_DATA */
+ 0x00000000, /* DENALI_PHY_149_DATA */
+ 0x04080000, /* DENALI_PHY_150_DATA */
+ 0x04080400, /* DENALI_PHY_151_DATA */
+ 0x30000000, /* DENALI_PHY_152_DATA */
+ 0x0c00c007, /* DENALI_PHY_153_DATA */
+ 0x00000100, /* DENALI_PHY_154_DATA */
+ 0x00000000, /* DENALI_PHY_155_DATA */
+ 0xfd02fe01, /* DENALI_PHY_156_DATA */
+ 0xf708fb04, /* DENALI_PHY_157_DATA */
+ 0xdf20ef10, /* DENALI_PHY_158_DATA */
+ 0x7f80bf40, /* DENALI_PHY_159_DATA */
+ 0x0000aaaa, /* DENALI_PHY_160_DATA */
+ 0x00000000, /* DENALI_PHY_161_DATA */
+ 0x00000000, /* DENALI_PHY_162_DATA */
+ 0x00000000, /* DENALI_PHY_163_DATA */
+ 0x00000000, /* DENALI_PHY_164_DATA */
+ 0x00000000, /* DENALI_PHY_165_DATA */
+ 0x00000000, /* DENALI_PHY_166_DATA */
+ 0x00000000, /* DENALI_PHY_167_DATA */
+ 0x00000000, /* DENALI_PHY_168_DATA */
+ 0x00000000, /* DENALI_PHY_169_DATA */
+ 0x00000000, /* DENALI_PHY_170_DATA */
+ 0x00000000, /* DENALI_PHY_171_DATA */
+ 0x00000000, /* DENALI_PHY_172_DATA */
+ 0x00000000, /* DENALI_PHY_173_DATA */
+ 0x00000000, /* DENALI_PHY_174_DATA */
+ 0x00000000, /* DENALI_PHY_175_DATA */
+ 0x00000000, /* DENALI_PHY_176_DATA */
+ 0x00000000, /* DENALI_PHY_177_DATA */
+ 0x00000000, /* DENALI_PHY_178_DATA */
+ 0x00000000, /* DENALI_PHY_179_DATA */
+ 0x00200000, /* DENALI_PHY_180_DATA */
+ 0x00000000, /* DENALI_PHY_181_DATA */
+ 0x00000000, /* DENALI_PHY_182_DATA */
+ 0x00000000, /* DENALI_PHY_183_DATA */
+ 0x00000000, /* DENALI_PHY_184_DATA */
+ 0x00000000, /* DENALI_PHY_185_DATA */
+ 0x00000000, /* DENALI_PHY_186_DATA */
+ 0x02800280, /* DENALI_PHY_187_DATA */
+ 0x02800280, /* DENALI_PHY_188_DATA */
+ 0x02800280, /* DENALI_PHY_189_DATA */
+ 0x02800280, /* DENALI_PHY_190_DATA */
+ 0x00000280, /* DENALI_PHY_191_DATA */
+ 0x00000000, /* DENALI_PHY_192_DATA */
+ 0x00000000, /* DENALI_PHY_193_DATA */
+ 0x00000000, /* DENALI_PHY_194_DATA */
+ 0x00000000, /* DENALI_PHY_195_DATA */
+ 0x00800000, /* DENALI_PHY_196_DATA */
+ 0x00800080, /* DENALI_PHY_197_DATA */
+ 0x00800080, /* DENALI_PHY_198_DATA */
+ 0x00800080, /* DENALI_PHY_199_DATA */
+ 0x00800080, /* DENALI_PHY_200_DATA */
+ 0x00800080, /* DENALI_PHY_201_DATA */
+ 0x00800080, /* DENALI_PHY_202_DATA */
+ 0x00800080, /* DENALI_PHY_203_DATA */
+ 0x00800080, /* DENALI_PHY_204_DATA */
+ 0x01190080, /* DENALI_PHY_205_DATA */
+ 0x00000002, /* DENALI_PHY_206_DATA */
+ 0x00000000, /* DENALI_PHY_207_DATA */
+ 0x00000000, /* DENALI_PHY_208_DATA */
+ 0x00000200, /* DENALI_PHY_209_DATA */
+ 0x00000000, /* DENALI_PHY_210_DATA */
+ 0x51315152, /* DENALI_PHY_211_DATA */
+ 0xc0013150, /* DENALI_PHY_212_DATA */
+ 0x020000c0, /* DENALI_PHY_213_DATA */
+ 0x00100001, /* DENALI_PHY_214_DATA */
+ 0x07054204, /* DENALI_PHY_215_DATA */
+ 0x000f0c18, /* DENALI_PHY_216_DATA */
+ 0x01000140, /* DENALI_PHY_217_DATA */
+ 0x00000c10, /* DENALI_PHY_218_DATA */
+ 0x00000000, /* DENALI_PHY_219_DATA */
+ 0x00000000, /* DENALI_PHY_220_DATA */
+ 0x00000000, /* DENALI_PHY_221_DATA */
+ 0x00000000, /* DENALI_PHY_222_DATA */
+ 0x00000000, /* DENALI_PHY_223_DATA */
+ 0x00000000, /* DENALI_PHY_224_DATA */
+ 0x00000000, /* DENALI_PHY_225_DATA */
+ 0x00000000, /* DENALI_PHY_226_DATA */
+ 0x00000000, /* DENALI_PHY_227_DATA */
+ 0x00000000, /* DENALI_PHY_228_DATA */
+ 0x00000000, /* DENALI_PHY_229_DATA */
+ 0x00000000, /* DENALI_PHY_230_DATA */
+ 0x00000000, /* DENALI_PHY_231_DATA */
+ 0x00000000, /* DENALI_PHY_232_DATA */
+ 0x00000000, /* DENALI_PHY_233_DATA */
+ 0x00000000, /* DENALI_PHY_234_DATA */
+ 0x00000000, /* DENALI_PHY_235_DATA */
+ 0x00000000, /* DENALI_PHY_236_DATA */
+ 0x00000000, /* DENALI_PHY_237_DATA */
+ 0x00000000, /* DENALI_PHY_238_DATA */
+ 0x00000000, /* DENALI_PHY_239_DATA */
+ 0x00000000, /* DENALI_PHY_240_DATA */
+ 0x00000000, /* DENALI_PHY_241_DATA */
+ 0x00000000, /* DENALI_PHY_242_DATA */
+ 0x00000000, /* DENALI_PHY_243_DATA */
+ 0x00000000, /* DENALI_PHY_244_DATA */
+ 0x00000000, /* DENALI_PHY_245_DATA */
+ 0x00000000, /* DENALI_PHY_246_DATA */
+ 0x00000000, /* DENALI_PHY_247_DATA */
+ 0x00000000, /* DENALI_PHY_248_DATA */
+ 0x00000000, /* DENALI_PHY_249_DATA */
+ 0x00000000, /* DENALI_PHY_250_DATA */
+ 0x00000000, /* DENALI_PHY_251_DATA */
+ 0x00000000, /* DENALI_PHY_252_DATA */
+ 0x00000000, /* DENALI_PHY_253_DATA */
+ 0x00000000, /* DENALI_PHY_254_DATA */
+ 0x00000000, /* DENALI_PHY_255_DATA */
+ 0x76543210, /* DENALI_PHY_256_DATA */
+ 0x0004f008, /* DENALI_PHY_257_DATA */
+ 0x00020119, /* DENALI_PHY_258_DATA */
+ 0x00000000, /* DENALI_PHY_259_DATA */
+ 0x00000000, /* DENALI_PHY_260_DATA */
+ 0x00010000, /* DENALI_PHY_261_DATA */
+ 0x01665555, /* DENALI_PHY_262_DATA */
+ 0x03665555, /* DENALI_PHY_263_DATA */
+ 0x00010f00, /* DENALI_PHY_264_DATA */
+ 0x05010200, /* DENALI_PHY_265_DATA */
+ 0x00000002, /* DENALI_PHY_266_DATA */
+ 0x00170180, /* DENALI_PHY_267_DATA */
+ 0x00cc0201, /* DENALI_PHY_268_DATA */
+ 0x00030066, /* DENALI_PHY_269_DATA */
+ 0x00000000, /* DENALI_PHY_270_DATA */
+ 0x00000000, /* DENALI_PHY_271_DATA */
+ 0x00000000, /* DENALI_PHY_272_DATA */
+ 0x00000000, /* DENALI_PHY_273_DATA */
+ 0x00000000, /* DENALI_PHY_274_DATA */
+ 0x00000000, /* DENALI_PHY_275_DATA */
+ 0x00000000, /* DENALI_PHY_276_DATA */
+ 0x00000000, /* DENALI_PHY_277_DATA */
+ 0x04080000, /* DENALI_PHY_278_DATA */
+ 0x04080400, /* DENALI_PHY_279_DATA */
+ 0x30000000, /* DENALI_PHY_280_DATA */
+ 0x0c00c007, /* DENALI_PHY_281_DATA */
+ 0x00000100, /* DENALI_PHY_282_DATA */
+ 0x00000000, /* DENALI_PHY_283_DATA */
+ 0xfd02fe01, /* DENALI_PHY_284_DATA */
+ 0xf708fb04, /* DENALI_PHY_285_DATA */
+ 0xdf20ef10, /* DENALI_PHY_286_DATA */
+ 0x7f80bf40, /* DENALI_PHY_287_DATA */
+ 0x0001aaaa, /* DENALI_PHY_288_DATA */
+ 0x00000000, /* DENALI_PHY_289_DATA */
+ 0x00000000, /* DENALI_PHY_290_DATA */
+ 0x00000000, /* DENALI_PHY_291_DATA */
+ 0x00000000, /* DENALI_PHY_292_DATA */
+ 0x00000000, /* DENALI_PHY_293_DATA */
+ 0x00000000, /* DENALI_PHY_294_DATA */
+ 0x00000000, /* DENALI_PHY_295_DATA */
+ 0x00000000, /* DENALI_PHY_296_DATA */
+ 0x00000000, /* DENALI_PHY_297_DATA */
+ 0x00000000, /* DENALI_PHY_298_DATA */
+ 0x00000000, /* DENALI_PHY_299_DATA */
+ 0x00000000, /* DENALI_PHY_300_DATA */
+ 0x00000000, /* DENALI_PHY_301_DATA */
+ 0x00000000, /* DENALI_PHY_302_DATA */
+ 0x00000000, /* DENALI_PHY_303_DATA */
+ 0x00000000, /* DENALI_PHY_304_DATA */
+ 0x00000000, /* DENALI_PHY_305_DATA */
+ 0x00000000, /* DENALI_PHY_306_DATA */
+ 0x00000000, /* DENALI_PHY_307_DATA */
+ 0x00200000, /* DENALI_PHY_308_DATA */
+ 0x00000000, /* DENALI_PHY_309_DATA */
+ 0x00000000, /* DENALI_PHY_310_DATA */
+ 0x00000000, /* DENALI_PHY_311_DATA */
+ 0x00000000, /* DENALI_PHY_312_DATA */
+ 0x00000000, /* DENALI_PHY_313_DATA */
+ 0x00000000, /* DENALI_PHY_314_DATA */
+ 0x02800280, /* DENALI_PHY_315_DATA */
+ 0x02800280, /* DENALI_PHY_316_DATA */
+ 0x02800280, /* DENALI_PHY_317_DATA */
+ 0x02800280, /* DENALI_PHY_318_DATA */
+ 0x00000280, /* DENALI_PHY_319_DATA */
+ 0x00000000, /* DENALI_PHY_320_DATA */
+ 0x00000000, /* DENALI_PHY_321_DATA */
+ 0x00000000, /* DENALI_PHY_322_DATA */
+ 0x00000000, /* DENALI_PHY_323_DATA */
+ 0x00800000, /* DENALI_PHY_324_DATA */
+ 0x00800080, /* DENALI_PHY_325_DATA */
+ 0x00800080, /* DENALI_PHY_326_DATA */
+ 0x00800080, /* DENALI_PHY_327_DATA */
+ 0x00800080, /* DENALI_PHY_328_DATA */
+ 0x00800080, /* DENALI_PHY_329_DATA */
+ 0x00800080, /* DENALI_PHY_330_DATA */
+ 0x00800080, /* DENALI_PHY_331_DATA */
+ 0x00800080, /* DENALI_PHY_332_DATA */
+ 0x01190080, /* DENALI_PHY_333_DATA */
+ 0x00000002, /* DENALI_PHY_334_DATA */
+ 0x00000000, /* DENALI_PHY_335_DATA */
+ 0x00000000, /* DENALI_PHY_336_DATA */
+ 0x00000200, /* DENALI_PHY_337_DATA */
+ 0x00000000, /* DENALI_PHY_338_DATA */
+ 0x51315152, /* DENALI_PHY_339_DATA */
+ 0xc0013150, /* DENALI_PHY_340_DATA */
+ 0x020000c0, /* DENALI_PHY_341_DATA */
+ 0x00100001, /* DENALI_PHY_342_DATA */
+ 0x07054204, /* DENALI_PHY_343_DATA */
+ 0x000f0c18, /* DENALI_PHY_344_DATA */
+ 0x01000140, /* DENALI_PHY_345_DATA */
+ 0x00000c10, /* DENALI_PHY_346_DATA */
+ 0x00000000, /* DENALI_PHY_347_DATA */
+ 0x00000000, /* DENALI_PHY_348_DATA */
+ 0x00000000, /* DENALI_PHY_349_DATA */
+ 0x00000000, /* DENALI_PHY_350_DATA */
+ 0x00000000, /* DENALI_PHY_351_DATA */
+ 0x00000000, /* DENALI_PHY_352_DATA */
+ 0x00000000, /* DENALI_PHY_353_DATA */
+ 0x00000000, /* DENALI_PHY_354_DATA */
+ 0x00000000, /* DENALI_PHY_355_DATA */
+ 0x00000000, /* DENALI_PHY_356_DATA */
+ 0x00000000, /* DENALI_PHY_357_DATA */
+ 0x00000000, /* DENALI_PHY_358_DATA */
+ 0x00000000, /* DENALI_PHY_359_DATA */
+ 0x00000000, /* DENALI_PHY_360_DATA */
+ 0x00000000, /* DENALI_PHY_361_DATA */
+ 0x00000000, /* DENALI_PHY_362_DATA */
+ 0x00000000, /* DENALI_PHY_363_DATA */
+ 0x00000000, /* DENALI_PHY_364_DATA */
+ 0x00000000, /* DENALI_PHY_365_DATA */
+ 0x00000000, /* DENALI_PHY_366_DATA */
+ 0x00000000, /* DENALI_PHY_367_DATA */
+ 0x00000000, /* DENALI_PHY_368_DATA */
+ 0x00000000, /* DENALI_PHY_369_DATA */
+ 0x00000000, /* DENALI_PHY_370_DATA */
+ 0x00000000, /* DENALI_PHY_371_DATA */
+ 0x00000000, /* DENALI_PHY_372_DATA */
+ 0x00000000, /* DENALI_PHY_373_DATA */
+ 0x00000000, /* DENALI_PHY_374_DATA */
+ 0x00000000, /* DENALI_PHY_375_DATA */
+ 0x00000000, /* DENALI_PHY_376_DATA */
+ 0x00000000, /* DENALI_PHY_377_DATA */
+ 0x00000000, /* DENALI_PHY_378_DATA */
+ 0x00000000, /* DENALI_PHY_379_DATA */
+ 0x00000000, /* DENALI_PHY_380_DATA */
+ 0x00000000, /* DENALI_PHY_381_DATA */
+ 0x00000000, /* DENALI_PHY_382_DATA */
+ 0x00000000, /* DENALI_PHY_383_DATA */
+ 0x76543210, /* DENALI_PHY_384_DATA */
+ 0x0004f008, /* DENALI_PHY_385_DATA */
+ 0x00020119, /* DENALI_PHY_386_DATA */
+ 0x00000000, /* DENALI_PHY_387_DATA */
+ 0x00000000, /* DENALI_PHY_388_DATA */
+ 0x00010000, /* DENALI_PHY_389_DATA */
+ 0x01665555, /* DENALI_PHY_390_DATA */
+ 0x03665555, /* DENALI_PHY_391_DATA */
+ 0x00010f00, /* DENALI_PHY_392_DATA */
+ 0x05010200, /* DENALI_PHY_393_DATA */
+ 0x00000002, /* DENALI_PHY_394_DATA */
+ 0x00170180, /* DENALI_PHY_395_DATA */
+ 0x00cc0201, /* DENALI_PHY_396_DATA */
+ 0x00030066, /* DENALI_PHY_397_DATA */
+ 0x00000000, /* DENALI_PHY_398_DATA */
+ 0x00000000, /* DENALI_PHY_399_DATA */
+ 0x00000000, /* DENALI_PHY_400_DATA */
+ 0x00000000, /* DENALI_PHY_401_DATA */
+ 0x00000000, /* DENALI_PHY_402_DATA */
+ 0x00000000, /* DENALI_PHY_403_DATA */
+ 0x00000000, /* DENALI_PHY_404_DATA */
+ 0x00000000, /* DENALI_PHY_405_DATA */
+ 0x04080000, /* DENALI_PHY_406_DATA */
+ 0x04080400, /* DENALI_PHY_407_DATA */
+ 0x30000000, /* DENALI_PHY_408_DATA */
+ 0x0c00c007, /* DENALI_PHY_409_DATA */
+ 0x00000100, /* DENALI_PHY_410_DATA */
+ 0x00000000, /* DENALI_PHY_411_DATA */
+ 0xfd02fe01, /* DENALI_PHY_412_DATA */
+ 0xf708fb04, /* DENALI_PHY_413_DATA */
+ 0xdf20ef10, /* DENALI_PHY_414_DATA */
+ 0x7f80bf40, /* DENALI_PHY_415_DATA */
+ 0x0000aaaa, /* DENALI_PHY_416_DATA */
+ 0x00000000, /* DENALI_PHY_417_DATA */
+ 0x00000000, /* DENALI_PHY_418_DATA */
+ 0x00000000, /* DENALI_PHY_419_DATA */
+ 0x00000000, /* DENALI_PHY_420_DATA */
+ 0x00000000, /* DENALI_PHY_421_DATA */
+ 0x00000000, /* DENALI_PHY_422_DATA */
+ 0x00000000, /* DENALI_PHY_423_DATA */
+ 0x00000000, /* DENALI_PHY_424_DATA */
+ 0x00000000, /* DENALI_PHY_425_DATA */
+ 0x00000000, /* DENALI_PHY_426_DATA */
+ 0x00000000, /* DENALI_PHY_427_DATA */
+ 0x00000000, /* DENALI_PHY_428_DATA */
+ 0x00000000, /* DENALI_PHY_429_DATA */
+ 0x00000000, /* DENALI_PHY_430_DATA */
+ 0x00000000, /* DENALI_PHY_431_DATA */
+ 0x00000000, /* DENALI_PHY_432_DATA */
+ 0x00000000, /* DENALI_PHY_433_DATA */
+ 0x00000000, /* DENALI_PHY_434_DATA */
+ 0x00000000, /* DENALI_PHY_435_DATA */
+ 0x00200000, /* DENALI_PHY_436_DATA */
+ 0x00000000, /* DENALI_PHY_437_DATA */
+ 0x00000000, /* DENALI_PHY_438_DATA */
+ 0x00000000, /* DENALI_PHY_439_DATA */
+ 0x00000000, /* DENALI_PHY_440_DATA */
+ 0x00000000, /* DENALI_PHY_441_DATA */
+ 0x00000000, /* DENALI_PHY_442_DATA */
+ 0x02800280, /* DENALI_PHY_443_DATA */
+ 0x02800280, /* DENALI_PHY_444_DATA */
+ 0x02800280, /* DENALI_PHY_445_DATA */
+ 0x02800280, /* DENALI_PHY_446_DATA */
+ 0x00000280, /* DENALI_PHY_447_DATA */
+ 0x00000000, /* DENALI_PHY_448_DATA */
+ 0x00000000, /* DENALI_PHY_449_DATA */
+ 0x00000000, /* DENALI_PHY_450_DATA */
+ 0x00000000, /* DENALI_PHY_451_DATA */
+ 0x00800000, /* DENALI_PHY_452_DATA */
+ 0x00800080, /* DENALI_PHY_453_DATA */
+ 0x00800080, /* DENALI_PHY_454_DATA */
+ 0x00800080, /* DENALI_PHY_455_DATA */
+ 0x00800080, /* DENALI_PHY_456_DATA */
+ 0x00800080, /* DENALI_PHY_457_DATA */
+ 0x00800080, /* DENALI_PHY_458_DATA */
+ 0x00800080, /* DENALI_PHY_459_DATA */
+ 0x00800080, /* DENALI_PHY_460_DATA */
+ 0x01190080, /* DENALI_PHY_461_DATA */
+ 0x00000002, /* DENALI_PHY_462_DATA */
+ 0x00000000, /* DENALI_PHY_463_DATA */
+ 0x00000000, /* DENALI_PHY_464_DATA */
+ 0x00000200, /* DENALI_PHY_465_DATA */
+ 0x00000000, /* DENALI_PHY_466_DATA */
+ 0x51315152, /* DENALI_PHY_467_DATA */
+ 0xc0013150, /* DENALI_PHY_468_DATA */
+ 0x020000c0, /* DENALI_PHY_469_DATA */
+ 0x00100001, /* DENALI_PHY_470_DATA */
+ 0x07054204, /* DENALI_PHY_471_DATA */
+ 0x000f0c18, /* DENALI_PHY_472_DATA */
+ 0x01000140, /* DENALI_PHY_473_DATA */
+ 0x00000c10, /* DENALI_PHY_474_DATA */
+ 0x00000000, /* DENALI_PHY_475_DATA */
+ 0x00000000, /* DENALI_PHY_476_DATA */
+ 0x00000000, /* DENALI_PHY_477_DATA */
+ 0x00000000, /* DENALI_PHY_478_DATA */
+ 0x00000000, /* DENALI_PHY_479_DATA */
+ 0x00000000, /* DENALI_PHY_480_DATA */
+ 0x00000000, /* DENALI_PHY_481_DATA */
+ 0x00000000, /* DENALI_PHY_482_DATA */
+ 0x00000000, /* DENALI_PHY_483_DATA */
+ 0x00000000, /* DENALI_PHY_484_DATA */
+ 0x00000000, /* DENALI_PHY_485_DATA */
+ 0x00000000, /* DENALI_PHY_486_DATA */
+ 0x00000000, /* DENALI_PHY_487_DATA */
+ 0x00000000, /* DENALI_PHY_488_DATA */
+ 0x00000000, /* DENALI_PHY_489_DATA */
+ 0x00000000, /* DENALI_PHY_490_DATA */
+ 0x00000000, /* DENALI_PHY_491_DATA */
+ 0x00000000, /* DENALI_PHY_492_DATA */
+ 0x00000000, /* DENALI_PHY_493_DATA */
+ 0x00000000, /* DENALI_PHY_494_DATA */
+ 0x00000000, /* DENALI_PHY_495_DATA */
+ 0x00000000, /* DENALI_PHY_496_DATA */
+ 0x00000000, /* DENALI_PHY_497_DATA */
+ 0x00000000, /* DENALI_PHY_498_DATA */
+ 0x00000000, /* DENALI_PHY_499_DATA */
+ 0x00000000, /* DENALI_PHY_500_DATA */
+ 0x00000000, /* DENALI_PHY_501_DATA */
+ 0x00000000, /* DENALI_PHY_502_DATA */
+ 0x00000000, /* DENALI_PHY_503_DATA */
+ 0x00000000, /* DENALI_PHY_504_DATA */
+ 0x00000000, /* DENALI_PHY_505_DATA */
+ 0x00000000, /* DENALI_PHY_506_DATA */
+ 0x00000000, /* DENALI_PHY_507_DATA */
+ 0x00000000, /* DENALI_PHY_508_DATA */
+ 0x00000000, /* DENALI_PHY_509_DATA */
+ 0x00000000, /* DENALI_PHY_510_DATA */
+ 0x00000000, /* DENALI_PHY_511_DATA */
+ 0x00000000, /* DENALI_PHY_512_DATA */
+ 0x00000000, /* DENALI_PHY_513_DATA */
+ 0x00000000, /* DENALI_PHY_514_DATA */
+ 0x00000000, /* DENALI_PHY_515_DATA */
+ 0x00000000, /* DENALI_PHY_516_DATA */
+ 0x00000000, /* DENALI_PHY_517_DATA */
+ 0x00000000, /* DENALI_PHY_518_DATA */
+ 0x00000002, /* DENALI_PHY_519_DATA */
+ 0x00000000, /* DENALI_PHY_520_DATA */
+ 0x00000000, /* DENALI_PHY_521_DATA */
+ 0x00000000, /* DENALI_PHY_522_DATA */
+ 0x00400320, /* DENALI_PHY_523_DATA */
+ 0x00000040, /* DENALI_PHY_524_DATA */
+ 0x00dcba98, /* DENALI_PHY_525_DATA */
+ 0x00000000, /* DENALI_PHY_526_DATA */
+ 0x00dcba98, /* DENALI_PHY_527_DATA */
+ 0x01000000, /* DENALI_PHY_528_DATA */
+ 0x00020003, /* DENALI_PHY_529_DATA */
+ 0x00000000, /* DENALI_PHY_530_DATA */
+ 0x00000000, /* DENALI_PHY_531_DATA */
+ 0x00000000, /* DENALI_PHY_532_DATA */
+ 0x0000002a, /* DENALI_PHY_533_DATA */
+ 0x00000015, /* DENALI_PHY_534_DATA */
+ 0x00000015, /* DENALI_PHY_535_DATA */
+ 0x0000002a, /* DENALI_PHY_536_DATA */
+ 0x00000033, /* DENALI_PHY_537_DATA */
+ 0x0000000c, /* DENALI_PHY_538_DATA */
+ 0x0000000c, /* DENALI_PHY_539_DATA */
+ 0x00000033, /* DENALI_PHY_540_DATA */
+ 0x0a418820, /* DENALI_PHY_541_DATA */
+ 0x003f0000, /* DENALI_PHY_542_DATA */
+ 0x0000003f, /* DENALI_PHY_543_DATA */
+ 0x00030055, /* DENALI_PHY_544_DATA */
+ 0x03000300, /* DENALI_PHY_545_DATA */
+ 0x03000300, /* DENALI_PHY_546_DATA */
+ 0x00000300, /* DENALI_PHY_547_DATA */
+ 0x42080010, /* DENALI_PHY_548_DATA */
+ 0x00000003, /* DENALI_PHY_549_DATA */
+ 0x00000000, /* DENALI_PHY_550_DATA */
+ 0x00000000, /* DENALI_PHY_551_DATA */
+ 0x00000000, /* DENALI_PHY_552_DATA */
+ 0x00000000, /* DENALI_PHY_553_DATA */
+ 0x00000000, /* DENALI_PHY_554_DATA */
+ 0x00000000, /* DENALI_PHY_555_DATA */
+ 0x00000000, /* DENALI_PHY_556_DATA */
+ 0x00000000, /* DENALI_PHY_557_DATA */
+ 0x00000000, /* DENALI_PHY_558_DATA */
+ 0x00000000, /* DENALI_PHY_559_DATA */
+ 0x00000000, /* DENALI_PHY_560_DATA */
+ 0x00000000, /* DENALI_PHY_561_DATA */
+ 0x00000000, /* DENALI_PHY_562_DATA */
+ 0x00000000, /* DENALI_PHY_563_DATA */
+ 0x00000000, /* DENALI_PHY_564_DATA */
+ 0x00000000, /* DENALI_PHY_565_DATA */
+ 0x00000000, /* DENALI_PHY_566_DATA */
+ 0x00000000, /* DENALI_PHY_567_DATA */
+ 0x00000000, /* DENALI_PHY_568_DATA */
+ 0x00000000, /* DENALI_PHY_569_DATA */
+ 0x00000000, /* DENALI_PHY_570_DATA */
+ 0x00000000, /* DENALI_PHY_571_DATA */
+ 0x00000000, /* DENALI_PHY_572_DATA */
+ 0x00000000, /* DENALI_PHY_573_DATA */
+ 0x00000000, /* DENALI_PHY_574_DATA */
+ 0x00000000, /* DENALI_PHY_575_DATA */
+ 0x00000000, /* DENALI_PHY_576_DATA */
+ 0x00000000, /* DENALI_PHY_577_DATA */
+ 0x00000000, /* DENALI_PHY_578_DATA */
+ 0x00000000, /* DENALI_PHY_579_DATA */
+ 0x00000000, /* DENALI_PHY_580_DATA */
+ 0x00000000, /* DENALI_PHY_581_DATA */
+ 0x00000000, /* DENALI_PHY_582_DATA */
+ 0x00000000, /* DENALI_PHY_583_DATA */
+ 0x00000000, /* DENALI_PHY_584_DATA */
+ 0x00000000, /* DENALI_PHY_585_DATA */
+ 0x00000000, /* DENALI_PHY_586_DATA */
+ 0x00000000, /* DENALI_PHY_587_DATA */
+ 0x00000000, /* DENALI_PHY_588_DATA */
+ 0x00000000, /* DENALI_PHY_589_DATA */
+ 0x00000000, /* DENALI_PHY_590_DATA */
+ 0x00000000, /* DENALI_PHY_591_DATA */
+ 0x00000000, /* DENALI_PHY_592_DATA */
+ 0x00000000, /* DENALI_PHY_593_DATA */
+ 0x00000000, /* DENALI_PHY_594_DATA */
+ 0x00000000, /* DENALI_PHY_595_DATA */
+ 0x00000000, /* DENALI_PHY_596_DATA */
+ 0x00000000, /* DENALI_PHY_597_DATA */
+ 0x00000000, /* DENALI_PHY_598_DATA */
+ 0x00000000, /* DENALI_PHY_599_DATA */
+ 0x00000000, /* DENALI_PHY_600_DATA */
+ 0x00000000, /* DENALI_PHY_601_DATA */
+ 0x00000000, /* DENALI_PHY_602_DATA */
+ 0x00000000, /* DENALI_PHY_603_DATA */
+ 0x00000000, /* DENALI_PHY_604_DATA */
+ 0x00000000, /* DENALI_PHY_605_DATA */
+ 0x00000000, /* DENALI_PHY_606_DATA */
+ 0x00000000, /* DENALI_PHY_607_DATA */
+ 0x00000000, /* DENALI_PHY_608_DATA */
+ 0x00000000, /* DENALI_PHY_609_DATA */
+ 0x00000000, /* DENALI_PHY_610_DATA */
+ 0x00000000, /* DENALI_PHY_611_DATA */
+ 0x00000000, /* DENALI_PHY_612_DATA */
+ 0x00000000, /* DENALI_PHY_613_DATA */
+ 0x00000000, /* DENALI_PHY_614_DATA */
+ 0x00000000, /* DENALI_PHY_615_DATA */
+ 0x00000000, /* DENALI_PHY_616_DATA */
+ 0x00000000, /* DENALI_PHY_617_DATA */
+ 0x00000000, /* DENALI_PHY_618_DATA */
+ 0x00000000, /* DENALI_PHY_619_DATA */
+ 0x00000000, /* DENALI_PHY_620_DATA */
+ 0x00000000, /* DENALI_PHY_621_DATA */
+ 0x00000000, /* DENALI_PHY_622_DATA */
+ 0x00000000, /* DENALI_PHY_623_DATA */
+ 0x00000000, /* DENALI_PHY_624_DATA */
+ 0x00000000, /* DENALI_PHY_625_DATA */
+ 0x00000000, /* DENALI_PHY_626_DATA */
+ 0x00000000, /* DENALI_PHY_627_DATA */
+ 0x00000000, /* DENALI_PHY_628_DATA */
+ 0x00000000, /* DENALI_PHY_629_DATA */
+ 0x00000000, /* DENALI_PHY_630_DATA */
+ 0x00000000, /* DENALI_PHY_631_DATA */
+ 0x00000000, /* DENALI_PHY_632_DATA */
+ 0x00000000, /* DENALI_PHY_633_DATA */
+ 0x00000000, /* DENALI_PHY_634_DATA */
+ 0x00000000, /* DENALI_PHY_635_DATA */
+ 0x00000000, /* DENALI_PHY_636_DATA */
+ 0x00000000, /* DENALI_PHY_637_DATA */
+ 0x00000000, /* DENALI_PHY_638_DATA */
+ 0x00000000, /* DENALI_PHY_639_DATA */
+ 0x00000000, /* DENALI_PHY_640_DATA */
+ 0x00000000, /* DENALI_PHY_641_DATA */
+ 0x00000000, /* DENALI_PHY_642_DATA */
+ 0x00000000, /* DENALI_PHY_643_DATA */
+ 0x00000000, /* DENALI_PHY_644_DATA */
+ 0x00000000, /* DENALI_PHY_645_DATA */
+ 0x00000000, /* DENALI_PHY_646_DATA */
+ 0x00000002, /* DENALI_PHY_647_DATA */
+ 0x00000000, /* DENALI_PHY_648_DATA */
+ 0x00000000, /* DENALI_PHY_649_DATA */
+ 0x00000000, /* DENALI_PHY_650_DATA */
+ 0x00400320, /* DENALI_PHY_651_DATA */
+ 0x00000040, /* DENALI_PHY_652_DATA */
+ 0x00000000, /* DENALI_PHY_653_DATA */
+ 0x00000000, /* DENALI_PHY_654_DATA */
+ 0x00000000, /* DENALI_PHY_655_DATA */
+ 0x01000000, /* DENALI_PHY_656_DATA */
+ 0x00020003, /* DENALI_PHY_657_DATA */
+ 0x00000000, /* DENALI_PHY_658_DATA */
+ 0x00000000, /* DENALI_PHY_659_DATA */
+ 0x00000000, /* DENALI_PHY_660_DATA */
+ 0x0000002a, /* DENALI_PHY_661_DATA */
+ 0x00000015, /* DENALI_PHY_662_DATA */
+ 0x00000015, /* DENALI_PHY_663_DATA */
+ 0x0000002a, /* DENALI_PHY_664_DATA */
+ 0x00000033, /* DENALI_PHY_665_DATA */
+ 0x0000000c, /* DENALI_PHY_666_DATA */
+ 0x0000000c, /* DENALI_PHY_667_DATA */
+ 0x00000033, /* DENALI_PHY_668_DATA */
+ 0x00000000, /* DENALI_PHY_669_DATA */
+ 0x00000000, /* DENALI_PHY_670_DATA */
+ 0x00000000, /* DENALI_PHY_671_DATA */
+ 0x00030055, /* DENALI_PHY_672_DATA */
+ 0x03000300, /* DENALI_PHY_673_DATA */
+ 0x03000300, /* DENALI_PHY_674_DATA */
+ 0x00000300, /* DENALI_PHY_675_DATA */
+ 0x42080010, /* DENALI_PHY_676_DATA */
+ 0x00000003, /* DENALI_PHY_677_DATA */
+ 0x00000000, /* DENALI_PHY_678_DATA */
+ 0x00000000, /* DENALI_PHY_679_DATA */
+ 0x00000000, /* DENALI_PHY_680_DATA */
+ 0x00000000, /* DENALI_PHY_681_DATA */
+ 0x00000000, /* DENALI_PHY_682_DATA */
+ 0x00000000, /* DENALI_PHY_683_DATA */
+ 0x00000000, /* DENALI_PHY_684_DATA */
+ 0x00000000, /* DENALI_PHY_685_DATA */
+ 0x00000000, /* DENALI_PHY_686_DATA */
+ 0x00000000, /* DENALI_PHY_687_DATA */
+ 0x00000000, /* DENALI_PHY_688_DATA */
+ 0x00000000, /* DENALI_PHY_689_DATA */
+ 0x00000000, /* DENALI_PHY_690_DATA */
+ 0x00000000, /* DENALI_PHY_691_DATA */
+ 0x00000000, /* DENALI_PHY_692_DATA */
+ 0x00000000, /* DENALI_PHY_693_DATA */
+ 0x00000000, /* DENALI_PHY_694_DATA */
+ 0x00000000, /* DENALI_PHY_695_DATA */
+ 0x00000000, /* DENALI_PHY_696_DATA */
+ 0x00000000, /* DENALI_PHY_697_DATA */
+ 0x00000000, /* DENALI_PHY_698_DATA */
+ 0x00000000, /* DENALI_PHY_699_DATA */
+ 0x00000000, /* DENALI_PHY_700_DATA */
+ 0x00000000, /* DENALI_PHY_701_DATA */
+ 0x00000000, /* DENALI_PHY_702_DATA */
+ 0x00000000, /* DENALI_PHY_703_DATA */
+ 0x00000000, /* DENALI_PHY_704_DATA */
+ 0x00000000, /* DENALI_PHY_705_DATA */
+ 0x00000000, /* DENALI_PHY_706_DATA */
+ 0x00000000, /* DENALI_PHY_707_DATA */
+ 0x00000000, /* DENALI_PHY_708_DATA */
+ 0x00000000, /* DENALI_PHY_709_DATA */
+ 0x00000000, /* DENALI_PHY_710_DATA */
+ 0x00000000, /* DENALI_PHY_711_DATA */
+ 0x00000000, /* DENALI_PHY_712_DATA */
+ 0x00000000, /* DENALI_PHY_713_DATA */
+ 0x00000000, /* DENALI_PHY_714_DATA */
+ 0x00000000, /* DENALI_PHY_715_DATA */
+ 0x00000000, /* DENALI_PHY_716_DATA */
+ 0x00000000, /* DENALI_PHY_717_DATA */
+ 0x00000000, /* DENALI_PHY_718_DATA */
+ 0x00000000, /* DENALI_PHY_719_DATA */
+ 0x00000000, /* DENALI_PHY_720_DATA */
+ 0x00000000, /* DENALI_PHY_721_DATA */
+ 0x00000000, /* DENALI_PHY_722_DATA */
+ 0x00000000, /* DENALI_PHY_723_DATA */
+ 0x00000000, /* DENALI_PHY_724_DATA */
+ 0x00000000, /* DENALI_PHY_725_DATA */
+ 0x00000000, /* DENALI_PHY_726_DATA */
+ 0x00000000, /* DENALI_PHY_727_DATA */
+ 0x00000000, /* DENALI_PHY_728_DATA */
+ 0x00000000, /* DENALI_PHY_729_DATA */
+ 0x00000000, /* DENALI_PHY_730_DATA */
+ 0x00000000, /* DENALI_PHY_731_DATA */
+ 0x00000000, /* DENALI_PHY_732_DATA */
+ 0x00000000, /* DENALI_PHY_733_DATA */
+ 0x00000000, /* DENALI_PHY_734_DATA */
+ 0x00000000, /* DENALI_PHY_735_DATA */
+ 0x00000000, /* DENALI_PHY_736_DATA */
+ 0x00000000, /* DENALI_PHY_737_DATA */
+ 0x00000000, /* DENALI_PHY_738_DATA */
+ 0x00000000, /* DENALI_PHY_739_DATA */
+ 0x00000000, /* DENALI_PHY_740_DATA */
+ 0x00000000, /* DENALI_PHY_741_DATA */
+ 0x00000000, /* DENALI_PHY_742_DATA */
+ 0x00000000, /* DENALI_PHY_743_DATA */
+ 0x00000000, /* DENALI_PHY_744_DATA */
+ 0x00000000, /* DENALI_PHY_745_DATA */
+ 0x00000000, /* DENALI_PHY_746_DATA */
+ 0x00000000, /* DENALI_PHY_747_DATA */
+ 0x00000000, /* DENALI_PHY_748_DATA */
+ 0x00000000, /* DENALI_PHY_749_DATA */
+ 0x00000000, /* DENALI_PHY_750_DATA */
+ 0x00000000, /* DENALI_PHY_751_DATA */
+ 0x00000000, /* DENALI_PHY_752_DATA */
+ 0x00000000, /* DENALI_PHY_753_DATA */
+ 0x00000000, /* DENALI_PHY_754_DATA */
+ 0x00000000, /* DENALI_PHY_755_DATA */
+ 0x00000000, /* DENALI_PHY_756_DATA */
+ 0x00000000, /* DENALI_PHY_757_DATA */
+ 0x00000000, /* DENALI_PHY_758_DATA */
+ 0x00000000, /* DENALI_PHY_759_DATA */
+ 0x00000000, /* DENALI_PHY_760_DATA */
+ 0x00000000, /* DENALI_PHY_761_DATA */
+ 0x00000000, /* DENALI_PHY_762_DATA */
+ 0x00000000, /* DENALI_PHY_763_DATA */
+ 0x00000000, /* DENALI_PHY_764_DATA */
+ 0x00000000, /* DENALI_PHY_765_DATA */
+ 0x00000000, /* DENALI_PHY_766_DATA */
+ 0x00000000, /* DENALI_PHY_767_DATA */
+ 0x00000000, /* DENALI_PHY_768_DATA */
+ 0x00000000, /* DENALI_PHY_769_DATA */
+ 0x00000000, /* DENALI_PHY_770_DATA */
+ 0x00000000, /* DENALI_PHY_771_DATA */
+ 0x00000000, /* DENALI_PHY_772_DATA */
+ 0x00000000, /* DENALI_PHY_773_DATA */
+ 0x00000000, /* DENALI_PHY_774_DATA */
+ 0x00000002, /* DENALI_PHY_775_DATA */
+ 0x00000000, /* DENALI_PHY_776_DATA */
+ 0x00000000, /* DENALI_PHY_777_DATA */
+ 0x00000000, /* DENALI_PHY_778_DATA */
+ 0x00400320, /* DENALI_PHY_779_DATA */
+ 0x00000040, /* DENALI_PHY_780_DATA */
+ 0x00000000, /* DENALI_PHY_781_DATA */
+ 0x00000000, /* DENALI_PHY_782_DATA */
+ 0x00000000, /* DENALI_PHY_783_DATA */
+ 0x01000000, /* DENALI_PHY_784_DATA */
+ 0x00020003, /* DENALI_PHY_785_DATA */
+ 0x00000000, /* DENALI_PHY_786_DATA */
+ 0x00000000, /* DENALI_PHY_787_DATA */
+ 0x00000000, /* DENALI_PHY_788_DATA */
+ 0x0000002a, /* DENALI_PHY_789_DATA */
+ 0x00000015, /* DENALI_PHY_790_DATA */
+ 0x00000015, /* DENALI_PHY_791_DATA */
+ 0x0000002a, /* DENALI_PHY_792_DATA */
+ 0x00000033, /* DENALI_PHY_793_DATA */
+ 0x0000000c, /* DENALI_PHY_794_DATA */
+ 0x0000000c, /* DENALI_PHY_795_DATA */
+ 0x00000033, /* DENALI_PHY_796_DATA */
+ 0x1ee6b16a, /* DENALI_PHY_797_DATA */
+ 0x10000000, /* DENALI_PHY_798_DATA */
+ 0x00000000, /* DENALI_PHY_799_DATA */
+ 0x00030055, /* DENALI_PHY_800_DATA */
+ 0x03000300, /* DENALI_PHY_801_DATA */
+ 0x03000300, /* DENALI_PHY_802_DATA */
+ 0x00000300, /* DENALI_PHY_803_DATA */
+ 0x42080010, /* DENALI_PHY_804_DATA */
+ 0x00000003, /* DENALI_PHY_805_DATA */
+ 0x00000000, /* DENALI_PHY_806_DATA */
+ 0x00000000, /* DENALI_PHY_807_DATA */
+ 0x00000000, /* DENALI_PHY_808_DATA */
+ 0x00000000, /* DENALI_PHY_809_DATA */
+ 0x00000000, /* DENALI_PHY_810_DATA */
+ 0x00000000, /* DENALI_PHY_811_DATA */
+ 0x00000000, /* DENALI_PHY_812_DATA */
+ 0x00000000, /* DENALI_PHY_813_DATA */
+ 0x00000000, /* DENALI_PHY_814_DATA */
+ 0x00000000, /* DENALI_PHY_815_DATA */
+ 0x00000000, /* DENALI_PHY_816_DATA */
+ 0x00000000, /* DENALI_PHY_817_DATA */
+ 0x00000000, /* DENALI_PHY_818_DATA */
+ 0x00000000, /* DENALI_PHY_819_DATA */
+ 0x00000000, /* DENALI_PHY_820_DATA */
+ 0x00000000, /* DENALI_PHY_821_DATA */
+ 0x00000000, /* DENALI_PHY_822_DATA */
+ 0x00000000, /* DENALI_PHY_823_DATA */
+ 0x00000000, /* DENALI_PHY_824_DATA */
+ 0x00000000, /* DENALI_PHY_825_DATA */
+ 0x00000000, /* DENALI_PHY_826_DATA */
+ 0x00000000, /* DENALI_PHY_827_DATA */
+ 0x00000000, /* DENALI_PHY_828_DATA */
+ 0x00000000, /* DENALI_PHY_829_DATA */
+ 0x00000000, /* DENALI_PHY_830_DATA */
+ 0x00000000, /* DENALI_PHY_831_DATA */
+ 0x00000000, /* DENALI_PHY_832_DATA */
+ 0x00000000, /* DENALI_PHY_833_DATA */
+ 0x00000000, /* DENALI_PHY_834_DATA */
+ 0x00000000, /* DENALI_PHY_835_DATA */
+ 0x00000000, /* DENALI_PHY_836_DATA */
+ 0x00000000, /* DENALI_PHY_837_DATA */
+ 0x00000000, /* DENALI_PHY_838_DATA */
+ 0x00000000, /* DENALI_PHY_839_DATA */
+ 0x00000000, /* DENALI_PHY_840_DATA */
+ 0x00000000, /* DENALI_PHY_841_DATA */
+ 0x00000000, /* DENALI_PHY_842_DATA */
+ 0x00000000, /* DENALI_PHY_843_DATA */
+ 0x00000000, /* DENALI_PHY_844_DATA */
+ 0x00000000, /* DENALI_PHY_845_DATA */
+ 0x00000000, /* DENALI_PHY_846_DATA */
+ 0x00000000, /* DENALI_PHY_847_DATA */
+ 0x00000000, /* DENALI_PHY_848_DATA */
+ 0x00000000, /* DENALI_PHY_849_DATA */
+ 0x00000000, /* DENALI_PHY_850_DATA */
+ 0x00000000, /* DENALI_PHY_851_DATA */
+ 0x00000000, /* DENALI_PHY_852_DATA */
+ 0x00000000, /* DENALI_PHY_853_DATA */
+ 0x00000000, /* DENALI_PHY_854_DATA */
+ 0x00000000, /* DENALI_PHY_855_DATA */
+ 0x00000000, /* DENALI_PHY_856_DATA */
+ 0x00000000, /* DENALI_PHY_857_DATA */
+ 0x00000000, /* DENALI_PHY_858_DATA */
+ 0x00000000, /* DENALI_PHY_859_DATA */
+ 0x00000000, /* DENALI_PHY_860_DATA */
+ 0x00000000, /* DENALI_PHY_861_DATA */
+ 0x00000000, /* DENALI_PHY_862_DATA */
+ 0x00000000, /* DENALI_PHY_863_DATA */
+ 0x00000000, /* DENALI_PHY_864_DATA */
+ 0x00000000, /* DENALI_PHY_865_DATA */
+ 0x00000000, /* DENALI_PHY_866_DATA */
+ 0x00000000, /* DENALI_PHY_867_DATA */
+ 0x00000000, /* DENALI_PHY_868_DATA */
+ 0x00000000, /* DENALI_PHY_869_DATA */
+ 0x00000000, /* DENALI_PHY_870_DATA */
+ 0x00000000, /* DENALI_PHY_871_DATA */
+ 0x00000000, /* DENALI_PHY_872_DATA */
+ 0x00000000, /* DENALI_PHY_873_DATA */
+ 0x00000000, /* DENALI_PHY_874_DATA */
+ 0x00000000, /* DENALI_PHY_875_DATA */
+ 0x00000000, /* DENALI_PHY_876_DATA */
+ 0x00000000, /* DENALI_PHY_877_DATA */
+ 0x00000000, /* DENALI_PHY_878_DATA */
+ 0x00000000, /* DENALI_PHY_879_DATA */
+ 0x00000000, /* DENALI_PHY_880_DATA */
+ 0x00000000, /* DENALI_PHY_881_DATA */
+ 0x00000000, /* DENALI_PHY_882_DATA */
+ 0x00000000, /* DENALI_PHY_883_DATA */
+ 0x00000000, /* DENALI_PHY_884_DATA */
+ 0x00000000, /* DENALI_PHY_885_DATA */
+ 0x00000000, /* DENALI_PHY_886_DATA */
+ 0x00000000, /* DENALI_PHY_887_DATA */
+ 0x00000000, /* DENALI_PHY_888_DATA */
+ 0x00000000, /* DENALI_PHY_889_DATA */
+ 0x00000000, /* DENALI_PHY_890_DATA */
+ 0x00000000, /* DENALI_PHY_891_DATA */
+ 0x00000000, /* DENALI_PHY_892_DATA */
+ 0x00000000, /* DENALI_PHY_893_DATA */
+ 0x00000000, /* DENALI_PHY_894_DATA */
+ 0x00000000, /* DENALI_PHY_895_DATA */
+ 0x00000000, /* DENALI_PHY_896_DATA */
+ 0x00000000, /* DENALI_PHY_897_DATA */
+ 0x00000005, /* DENALI_PHY_898_DATA */
+ 0x04000f01, /* DENALI_PHY_899_DATA */
+ 0x00020040, /* DENALI_PHY_900_DATA */
+ 0x00020055, /* DENALI_PHY_901_DATA */
+ 0x00000000, /* DENALI_PHY_902_DATA */
+ 0x00000000, /* DENALI_PHY_903_DATA */
+ 0x00000000, /* DENALI_PHY_904_DATA */
+ 0x00000050, /* DENALI_PHY_905_DATA */
+ 0x00000000, /* DENALI_PHY_906_DATA */
+ 0x01010100, /* DENALI_PHY_907_DATA */
+ 0x00000600, /* DENALI_PHY_908_DATA */
+ 0x00000000, /* DENALI_PHY_909_DATA */
+ 0x00006400, /* DENALI_PHY_910_DATA */
+ 0x01221102, /* DENALI_PHY_911_DATA */
+ 0x00000000, /* DENALI_PHY_912_DATA */
+ 0x000d1f00, /* DENALI_PHY_913_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_914_DATA */
+ 0x0d1f0d1f, /* DENALI_PHY_915_DATA */
+ 0x00030003, /* DENALI_PHY_916_DATA */
+ 0x03000300, /* DENALI_PHY_917_DATA */
+ 0x00000300, /* DENALI_PHY_918_DATA */
+ 0x01221102, /* DENALI_PHY_919_DATA */
+ 0x00000000, /* DENALI_PHY_920_DATA */
+ 0x00000000, /* DENALI_PHY_921_DATA */
+ 0x03020000, /* DENALI_PHY_922_DATA */
+ 0x00000001, /* DENALI_PHY_923_DATA */
+ 0x00000411, /* DENALI_PHY_924_DATA */
+ 0x00000411, /* DENALI_PHY_925_DATA */
+ 0x00000040, /* DENALI_PHY_926_DATA */
+ 0x00000040, /* DENALI_PHY_927_DATA */
+ 0x00000411, /* DENALI_PHY_928_DATA */
+ 0x00000411, /* DENALI_PHY_929_DATA */
+ 0x00004410, /* DENALI_PHY_930_DATA */
+ 0x00004410, /* DENALI_PHY_931_DATA */
+ 0x00004410, /* DENALI_PHY_932_DATA */
+ 0x00004410, /* DENALI_PHY_933_DATA */
+ 0x00004410, /* DENALI_PHY_934_DATA */
+ 0x00000411, /* DENALI_PHY_935_DATA */
+ 0x00004410, /* DENALI_PHY_936_DATA */
+ 0x00000411, /* DENALI_PHY_937_DATA */
+ 0x00004410, /* DENALI_PHY_938_DATA */
+ 0x00000411, /* DENALI_PHY_939_DATA */
+ 0x00004410, /* DENALI_PHY_940_DATA */
+ 0x00000000, /* DENALI_PHY_941_DATA */
+ 0x00000000, /* DENALI_PHY_942_DATA */
+ 0x00000000, /* DENALI_PHY_943_DATA */
+ 0x64000000, /* DENALI_PHY_944_DATA */
+ 0x00000000, /* DENALI_PHY_945_DATA */
+ 0x00000000, /* DENALI_PHY_946_DATA */
+ 0x00000508, /* DENALI_PHY_947_DATA */
+ 0x00000000, /* DENALI_PHY_948_DATA */
+ 0x00000000, /* DENALI_PHY_949_DATA */
+ 0x00000000, /* DENALI_PHY_950_DATA */
+ 0x00000000, /* DENALI_PHY_951_DATA */
+ 0x00000000, /* DENALI_PHY_952_DATA */
+ 0x00000000, /* DENALI_PHY_953_DATA */
+ 0xe4000000, /* DENALI_PHY_954_DATA */
+ 0x00000000, /* DENALI_PHY_955_DATA */
+ 0x00000000, /* DENALI_PHY_956_DATA */
+ 0x01010000, /* DENALI_PHY_957_DATA */
+ 0x00000000 /* DENALI_PHY_958_DATA */
+ }
+ },
+},
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c
new file mode 100644
index 00000000000..9cf662675b2
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_debug.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
+ * (C) Copyright 2019 Amarula Solutions.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <asm/arch-rockchip/sdram_common.h>
+
+void sdram_print_dram_type(unsigned char dramtype)
+{
+ switch (dramtype) {
+ case DDR3:
+ printascii("DDR3");
+ break;
+ case DDR4:
+ printascii("DDR4");
+ break;
+ case LPDDR2:
+ printascii("LPDDR2");
+ break;
+ case LPDDR3:
+ printascii("LPDDR3");
+ break;
+ case LPDDR4:
+ printascii("LPDDR4");
+ break;
+ default:
+ printascii("Unknown Device");
+ break;
+ }
+}
+
+/**
+ * cs = 0, cs0
+ * cs = 1, cs1
+ * cs => 2, cs0+cs1
+ * note: it didn't consider about row_3_4
+ */
+u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
+{
+ u32 bg;
+ u64 cap[2];
+
+ if (dram_type == DDR4)
+ /* DDR4 8bit dram BG = 2(4bank groups),
+ * 16bit dram BG = 1 (2 bank groups)
+ */
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+ else
+ bg = 0;
+
+ cap[0] = 1llu << (cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs0_row);
+
+ if (cap_info->rank == 2)
+ cap[1] = 1llu << (cap_info->bw + cap_info->col +
+ bg + cap_info->bk + cap_info->cs1_row);
+ else
+ cap[1] = 0;
+
+ if (cs == 0)
+ return cap[0];
+ else if (cs == 1)
+ return cap[1];
+ else
+ return (cap[0] + cap[1]);
+}
+
+void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
+ struct sdram_base_params *base)
+{
+ u32 bg, cap;
+
+ bg = (cap_info->dbw == 0) ? 2 : 1;
+
+ sdram_print_dram_type(base->dramtype);
+
+ printascii(", ");
+ printdec(base->ddr_freq);
+ printascii("MHz\n");
+
+ printascii("BW=");
+ printdec(8 << cap_info->bw);
+
+ printascii(" Col=");
+ printdec(cap_info->col);
+
+ printascii(" Bk=");
+ printdec(0x1 << cap_info->bk);
+ if (base->dramtype == DDR4) {
+ printascii(" BG=");
+ printdec(1 << bg);
+ }
+
+ printascii(" CS0 Row=");
+ printdec(cap_info->cs0_row);
+ if (cap_info->rank > 1) {
+ printascii(" CS1 Row=");
+ printdec(cap_info->cs1_row);
+ }
+
+ printascii(" CS=");
+ printdec(cap_info->rank);
+
+ printascii(" Die BW=");
+ printdec(8 << cap_info->dbw);
+
+ cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
+ if (cap_info->row_3_4)
+ cap = cap * 3 / 4;
+
+ printascii(" Size=");
+ printdec(cap >> 20);
+ printascii("MB\n");
+}
+
+void sdram_print_stride(unsigned int stride)
+{
+ switch (stride) {
+ case 0xc:
+ printf("128B stride\n");
+ break;
+ case 5:
+ case 9:
+ case 0xd:
+ case 0x11:
+ case 0x19:
+ printf("256B stride\n");
+ break;
+ case 0xa:
+ case 0xe:
+ case 0x12:
+ printf("512B stride\n");
+ break;
+ case 0xf:
+ printf("4K stride\n");
+ break;
+ case 0x1f:
+ printf("32MB + 256B stride\n");
+ break;
+ default:
+ printf("no stride\n");
+ }
+}
diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c
index e96ac54c395..94893e17cf5 100644
--- a/drivers/ram/rockchip/sdram_rk322x.c
+++ b/drivers/ram/rockchip/sdram_rk322x.c
@@ -16,7 +16,6 @@
#include <asm/arch-rockchip/grf_rk322x.h>
#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/sdram_rk322x.h>
-#include <asm/arch-rockchip/timer.h>
#include <asm/arch-rockchip/uart.h>
#include <asm/arch-rockchip/sdram_common.h>
#include <asm/types.h>
@@ -96,26 +95,26 @@ void phy_pctrl_reset(struct rk322x_cru *cru,
1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
rk_clrreg(&cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT |
1 << DDRPHY_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
rk_clrreg(&cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
1 << DDRCTRL_SRST_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
clrbits_le32(&ddr_phy->ddrphy_reg[0],
SOFT_RESET_MASK << SOFT_RESET_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
setbits_le32(&ddr_phy->ddrphy_reg[0],
SOFT_DERESET_ANALOG);
- rockchip_udelay(5);
+ udelay(5);
setbits_le32(&ddr_phy->ddrphy_reg[0],
SOFT_DERESET_DIGITAL);
- rockchip_udelay(1);
+ udelay(1);
}
void phy_dll_bypass_set(struct rk322x_ddr_phy *ddr_phy, u32 freq)
@@ -154,7 +153,7 @@ static void send_command(struct rk322x_ddr_pctl *pctl,
u32 rank, u32 cmd, u32 arg)
{
writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
- rockchip_udelay(1);
+ udelay(1);
while (readl(&pctl->mcmd) & START_CMD)
;
}
@@ -167,7 +166,7 @@ static void memory_init(struct chan_info *chan,
if (dramtype == DDR3) {
send_command(pctl, 3, DESELECT_CMD, 0);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, PREA_CMD, 0);
send_command(pctl, 3, MRS_CMD,
(0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
@@ -196,17 +195,17 @@ static void memory_init(struct chan_info *chan,
(0x63 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(0 & LPDDR23_OP_MASK) <<
LPDDR23_OP_SHIFT);
- rockchip_udelay(10);
+ udelay(10);
send_command(pctl, 3, MRS_CMD,
(0x10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(0xff & LPDDR23_OP_MASK) <<
LPDDR23_OP_SHIFT);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, MRS_CMD,
(0x10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(0xff & LPDDR23_OP_MASK) <<
LPDDR23_OP_SHIFT);
- rockchip_udelay(1);
+ udelay(1);
send_command(pctl, 3, MRS_CMD,
(1 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
(sdram_params->phy_timing.mr[1] &
@@ -243,7 +242,7 @@ static u32 data_training(struct chan_info *chan)
DQS_SQU_CAL_SEL_CS0);
setbits_le32(&ddr_phy->ddrphy_reg[2], DQS_SQU_CAL_START);
- rockchip_udelay(30);
+ udelay(30);
ret = readl(&ddr_phy->ddrphy_reg[0xff]);
clrbits_le32(&ddr_phy->ddrphy_reg[2],
@@ -367,9 +366,9 @@ static void phy_softreset(struct dram_info *dram)
writel(GRF_DDRPHY_BUFFEREN_CORE_EN, &grf->soc_con[0]);
clrbits_le32(&ddr_phy->ddrphy_reg[0], 0x3 << 2);
- rockchip_udelay(1);
+ udelay(1);
setbits_le32(&ddr_phy->ddrphy_reg[0], 1 << 2);
- rockchip_udelay(5);
+ udelay(5);
setbits_le32(&ddr_phy->ddrphy_reg[0], 1 << 3);
writel(GRF_DDRPHY_BUFFEREN_CORE_DIS, &grf->soc_con[0]);
}
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
index 52518656c4a..81fc71c051d 100644
--- a/drivers/ram/rockchip/sdram_rk3399.c
+++ b/drivers/ram/rockchip/sdram_rk3399.c
@@ -14,14 +14,40 @@
#include <syscon.h>
#include <asm/io.h>
#include <asm/arch-rockchip/clock.h>
-#include <asm/arch-rockchip/sdram_common.h>
-#include <asm/arch-rockchip/sdram_rk3399.h>
#include <asm/arch-rockchip/cru_rk3399.h>
#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/pmu_rk3399.h>
#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/sdram_common.h>
+#include <asm/arch-rockchip/sdram_rk3399.h>
#include <linux/err.h>
#include <time.h>
+#define PRESET_SGRF_HOLD(n) ((0x1 << (6 + 16)) | ((n) << 6))
+#define PRESET_GPIO0_HOLD(n) ((0x1 << (7 + 16)) | ((n) << 7))
+#define PRESET_GPIO1_HOLD(n) ((0x1 << (8 + 16)) | ((n) << 8))
+
+#define PHY_DRV_ODT_HI_Z 0x0
+#define PHY_DRV_ODT_240 0x1
+#define PHY_DRV_ODT_120 0x8
+#define PHY_DRV_ODT_80 0x9
+#define PHY_DRV_ODT_60 0xc
+#define PHY_DRV_ODT_48 0xd
+#define PHY_DRV_ODT_40 0xe
+#define PHY_DRV_ODT_34_3 0xf
+
+#define PHY_BOOSTP_EN 0x1
+#define PHY_BOOSTN_EN 0x1
+#define PHY_SLEWP_EN 0x1
+#define PHY_SLEWN_EN 0x1
+#define PHY_RX_CM_INPUT 0x1
+#define CS0_MR22_VAL 0
+#define CS1_MR22_VAL 3
+
+#define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \
+ ((n) << (8 + (ch) * 4)))
+#define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \
+ ((n) << (9 + (ch) * 4)))
struct chan_info {
struct rk3399_ddr_pctl_regs *pctl;
struct rk3399_ddr_pi_regs *pi;
@@ -32,29 +58,27 @@ struct chan_info {
struct dram_info {
#if defined(CONFIG_TPL_BUILD) || \
(!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
+ u32 pwrup_srefresh_exit[2];
struct chan_info chan[2];
struct clk ddr_clk;
struct rk3399_cru *cru;
+ struct rk3399_grf_regs *grf;
+ struct rk3399_pmu_regs *pmu;
struct rk3399_pmucru *pmucru;
struct rk3399_pmusgrf_regs *pmusgrf;
struct rk3399_ddr_cic_regs *cic;
+ const struct sdram_rk3399_ops *ops;
#endif
struct ram_info info;
struct rk3399_pmugrf_regs *pmugrf;
};
-#define PRESET_SGRF_HOLD(n) ((0x1 << (6 + 16)) | ((n) << 6))
-#define PRESET_GPIO0_HOLD(n) ((0x1 << (7 + 16)) | ((n) << 7))
-#define PRESET_GPIO1_HOLD(n) ((0x1 << (8 + 16)) | ((n) << 8))
-
-#define PHY_DRV_ODT_Hi_Z 0x0
-#define PHY_DRV_ODT_240 0x1
-#define PHY_DRV_ODT_120 0x8
-#define PHY_DRV_ODT_80 0x9
-#define PHY_DRV_ODT_60 0xc
-#define PHY_DRV_ODT_48 0xd
-#define PHY_DRV_ODT_40 0xe
-#define PHY_DRV_ODT_34_3 0xf
+struct sdram_rk3399_ops {
+ int (*data_training)(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *sdram);
+ int (*set_rate)(struct dram_info *dram,
+ struct rk3399_sdram_params *params);
+};
#if defined(CONFIG_TPL_BUILD) || \
(!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
@@ -68,6 +92,154 @@ struct rockchip_dmc_plat {
struct regmap *map;
};
+struct io_setting {
+ u32 mhz;
+ u32 mr5;
+ /* dram side */
+ u32 dq_odt;
+ u32 ca_odt;
+ u32 pdds;
+ u32 dq_vref;
+ u32 ca_vref;
+ /* phy side */
+ u32 rd_odt;
+ u32 wr_dq_drv;
+ u32 wr_ca_drv;
+ u32 wr_ckcs_drv;
+ u32 rd_odt_en;
+ u32 rd_vref;
+} lpddr4_io_setting[] = {
+ {
+ 50 * MHz,
+ 0,
+ /* dram side */
+ 0, /* dq_odt; */
+ 0, /* ca_odt; */
+ 6, /* pdds; */
+ 0x72, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_HI_Z, /* rd_odt; */
+ PHY_DRV_ODT_40, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 0, /* rd_odt_en;*/
+ 41, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 600 * MHz,
+ 0,
+ /* dram side */
+ 1, /* dq_odt; */
+ 0, /* ca_odt; */
+ 6, /* pdds; */
+ 0x72, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_HI_Z, /* rd_odt; */
+ PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 0, /* rd_odt_en; */
+ 32, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 800 * MHz,
+ 0,
+ /* dram side */
+ 1, /* dq_odt; */
+ 0, /* ca_odt; */
+ 1, /* pdds; */
+ 0x72, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_40, /* rd_odt; */
+ PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 1, /* rd_odt_en; */
+ 17, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 933 * MHz,
+ 0,
+ /* dram side */
+ 3, /* dq_odt; */
+ 0, /* ca_odt; */
+ 6, /* pdds; */
+ 0x59, /* dq_vref; 32% */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_HI_Z, /* rd_odt; */
+ PHY_DRV_ODT_48, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 0, /* rd_odt_en; */
+ 32, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+ {
+ 1066 * MHz,
+ 0,
+ /* dram side */
+ 6, /* dq_odt; */
+ 0, /* ca_odt; */
+ 1, /* pdds; */
+ 0x10, /* dq_vref; */
+ 0x72, /* ca_vref; */
+ /* phy side */
+ PHY_DRV_ODT_40, /* rd_odt; */
+ PHY_DRV_ODT_60, /* wr_dq_drv; */
+ PHY_DRV_ODT_40, /* wr_ca_drv; */
+ PHY_DRV_ODT_40, /* wr_ckcs_drv; */
+ 1, /* rd_odt_en; */
+ 17, /* rd_vref; (unit %, range 3.3% - 48.7%) */
+ },
+};
+
+/**
+ * phy = 0, PHY boot freq
+ * phy = 1, PHY index 0
+ * phy = 2, PHY index 1
+ */
+static struct io_setting *
+lpddr4_get_io_settings(const struct rk3399_sdram_params *params, u32 mr5)
+{
+ struct io_setting *io = NULL;
+ u32 n;
+
+ for (n = 0; n < ARRAY_SIZE(lpddr4_io_setting); n++) {
+ io = &lpddr4_io_setting[n];
+
+ if (io->mr5 != 0) {
+ if (io->mhz >= params->base.ddr_freq &&
+ io->mr5 == mr5)
+ break;
+ } else {
+ if (io->mhz >= params->base.ddr_freq)
+ break;
+ }
+ }
+
+ return io;
+}
+
+static void *get_denali_phy(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
+{
+ return reg ? &chan->publ->denali_phy : &params->phy_regs.denali_phy;
+}
+
+static void *get_denali_ctl(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
+{
+ return reg ? &chan->pctl->denali_ctl : &params->pctl_regs.denali_ctl;
+}
+
+static void *get_ddrc0_con(struct dram_info *dram, u8 channel)
+{
+ return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc0_con1;
+}
+
static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
{
int i;
@@ -79,6 +251,29 @@ static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
}
}
+static void rkclk_ddr_reset(struct rk3399_cru *cru, u32 channel, u32 ctl,
+ u32 phy)
+{
+ channel &= 0x1;
+ ctl &= 0x1;
+ phy &= 0x1;
+ writel(CRU_SFTRST_DDR_CTRL(channel, ctl) |
+ CRU_SFTRST_DDR_PHY(channel, phy),
+ &cru->softrst_con[4]);
+}
+
+static void phy_pctrl_reset(struct rk3399_cru *cru, u32 channel)
+{
+ rkclk_ddr_reset(cru, channel, 1, 1);
+ udelay(10);
+
+ rkclk_ddr_reset(cru, channel, 1, 0);
+ udelay(10);
+
+ rkclk_ddr_reset(cru, channel, 0, 0);
+ udelay(10);
+}
+
static void phy_dll_bypass_set(struct rk3399_ddr_publ_regs *ddr_publ_regs,
u32 freq)
{
@@ -111,10 +306,9 @@ static void phy_dll_bypass_set(struct rk3399_ddr_publ_regs *ddr_publ_regs,
}
static void set_memory_map(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
- const struct rk3399_sdram_channel *sdram_ch =
- &sdram_params->ch[channel];
+ const struct rk3399_sdram_channel *sdram_ch = &params->ch[channel];
u32 *denali_ctl = chan->pctl->denali_ctl;
u32 *denali_pi = chan->pi->denali_pi;
u32 cs_map;
@@ -122,179 +316,51 @@ static void set_memory_map(const struct chan_info *chan, u32 channel,
u32 row;
/* Get row number from ddrconfig setting */
- if (sdram_ch->ddrconfig < 2 || sdram_ch->ddrconfig == 4)
+ if (sdram_ch->cap_info.ddrconfig < 2 ||
+ sdram_ch->cap_info.ddrconfig == 4)
row = 16;
- else if (sdram_ch->ddrconfig == 3)
+ else if (sdram_ch->cap_info.ddrconfig == 3)
row = 14;
else
row = 15;
- cs_map = (sdram_ch->rank > 1) ? 3 : 1;
- reduc = (sdram_ch->bw == 2) ? 0 : 1;
+ cs_map = (sdram_ch->cap_info.rank > 1) ? 3 : 1;
+ reduc = (sdram_ch->cap_info.bw == 2) ? 0 : 1;
/* Set the dram configuration to ctrl */
- clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->col));
+ clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->cap_info.col));
clrsetbits_le32(&denali_ctl[190], (0x3 << 16) | (0x7 << 24),
- ((3 - sdram_ch->bk) << 16) |
+ ((3 - sdram_ch->cap_info.bk) << 16) |
((16 - row) << 24));
clrsetbits_le32(&denali_ctl[196], 0x3 | (1 << 16),
cs_map | (reduc << 16));
/* PI_199 PI_COL_DIFF:RW:0:4 */
- clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->col));
+ clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->cap_info.col));
/* PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2 */
clrsetbits_le32(&denali_pi[155], (0x3 << 16) | (0x7 << 24),
- ((3 - sdram_ch->bk) << 16) |
+ ((3 - sdram_ch->cap_info.bk) << 16) |
((16 - row) << 24));
- /* PI_41 PI_CS_MAP:RW:24:4 */
- clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24);
- if ((sdram_ch->rank == 1) && (sdram_params->base.dramtype == DDR3))
- writel(0x2EC7FFFF, &denali_pi[34]);
-}
-static void set_ds_odt(const struct chan_info *chan,
- const struct rk3399_sdram_params *sdram_params)
-{
- u32 *denali_phy = chan->publ->denali_phy;
-
- u32 tsel_idle_en, tsel_wr_en, tsel_rd_en;
- u32 tsel_idle_select_p, tsel_wr_select_p, tsel_rd_select_p;
- u32 ca_tsel_wr_select_p, ca_tsel_wr_select_n;
- u32 tsel_idle_select_n, tsel_wr_select_n, tsel_rd_select_n;
- u32 reg_value;
-
- if (sdram_params->base.dramtype == LPDDR4) {
- tsel_rd_select_p = PHY_DRV_ODT_Hi_Z;
- tsel_wr_select_p = PHY_DRV_ODT_40;
- ca_tsel_wr_select_p = PHY_DRV_ODT_40;
- tsel_idle_select_p = PHY_DRV_ODT_Hi_Z;
-
- tsel_rd_select_n = PHY_DRV_ODT_240;
- tsel_wr_select_n = PHY_DRV_ODT_40;
- ca_tsel_wr_select_n = PHY_DRV_ODT_40;
- tsel_idle_select_n = PHY_DRV_ODT_240;
- } else if (sdram_params->base.dramtype == LPDDR3) {
- tsel_rd_select_p = PHY_DRV_ODT_240;
- tsel_wr_select_p = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_p = PHY_DRV_ODT_48;
- tsel_idle_select_p = PHY_DRV_ODT_240;
-
- tsel_rd_select_n = PHY_DRV_ODT_Hi_Z;
- tsel_wr_select_n = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_n = PHY_DRV_ODT_48;
- tsel_idle_select_n = PHY_DRV_ODT_Hi_Z;
- } else {
- tsel_rd_select_p = PHY_DRV_ODT_240;
- tsel_wr_select_p = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_p = PHY_DRV_ODT_34_3;
- tsel_idle_select_p = PHY_DRV_ODT_240;
-
- tsel_rd_select_n = PHY_DRV_ODT_240;
- tsel_wr_select_n = PHY_DRV_ODT_34_3;
- ca_tsel_wr_select_n = PHY_DRV_ODT_34_3;
- tsel_idle_select_n = PHY_DRV_ODT_240;
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ if (cs_map == 1)
+ cs_map = 0x5;
+ else if (cs_map == 2)
+ cs_map = 0xa;
+ else
+ cs_map = 0xF;
}
- if (sdram_params->base.odt == 1)
- tsel_rd_en = 1;
- else
- tsel_rd_en = 0;
-
- tsel_wr_en = 0;
- tsel_idle_en = 0;
-
- /*
- * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0
- * sets termination values for read/idle cycles and drive strength
- * for write cycles for DQ/DM
- */
- reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) |
- (tsel_wr_select_n << 8) | (tsel_wr_select_p << 12) |
- (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20);
- clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value);
-
- /*
- * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0
- * sets termination values for read/idle cycles and drive strength
- * for write cycles for DQS
- */
- clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value);
- clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value);
-
- /* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
- reg_value = ca_tsel_wr_select_n | (ca_tsel_wr_select_p << 0x4);
- clrsetbits_le32(&denali_phy[544], 0xff, reg_value);
- clrsetbits_le32(&denali_phy[672], 0xff, reg_value);
- clrsetbits_le32(&denali_phy[800], 0xff, reg_value);
-
- /* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */
- clrsetbits_le32(&denali_phy[928], 0xff, reg_value);
-
- /* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */
- clrsetbits_le32(&denali_phy[937], 0xff, reg_value);
-
- /* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */
- clrsetbits_le32(&denali_phy[935], 0xff, reg_value);
-
- /* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */
- clrsetbits_le32(&denali_phy[939], 0xff, reg_value);
-
- /* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */
- clrsetbits_le32(&denali_phy[929], 0xff, reg_value);
-
- /* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
- clrsetbits_le32(&denali_phy[924], 0xff,
- tsel_wr_select_n | (tsel_wr_select_p << 4));
- clrsetbits_le32(&denali_phy[925], 0xff,
- tsel_rd_select_n | (tsel_rd_select_p << 4));
-
- /* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
- reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
- << 16;
- clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value);
- clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value);
- clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value);
- clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value);
-
- /* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */
- reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
- << 24;
- clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value);
- clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value);
- clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value);
- clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value);
-
- /* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */
- reg_value = tsel_wr_en << 8;
- clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value);
- clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value);
- clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value);
-
- /* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */
- reg_value = tsel_wr_en << 17;
- clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value);
- /*
- * pad_rst/cke/cs/clk_term tsel 1bits
- * DENALI_PHY_938/936/940/934 offset_17
- */
- clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value);
- clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value);
- clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value);
- clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value);
-
- /* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */
- clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value);
+ /* PI_41 PI_CS_MAP:RW:24:4 */
+ clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24);
+ if (sdram_ch->cap_info.rank == 1 && params->base.dramtype == DDR3)
+ writel(0x2EC7FFFF, &denali_pi[34]);
}
static int phy_io_config(const struct chan_info *chan,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params, u32 mr5)
{
u32 *denali_phy = chan->publ->denali_phy;
u32 vref_mode_dq, vref_value_dq, vref_mode_ac, vref_value_ac;
@@ -303,15 +369,29 @@ static int phy_io_config(const struct chan_info *chan,
u32 drv_value, odt_value;
u32 speed;
- /* vref setting */
- if (sdram_params->base.dramtype == LPDDR4) {
- /* LPDDR4 */
- vref_mode_dq = 0x6;
- vref_value_dq = 0x1f;
+ /* vref setting & mode setting */
+ if (params->base.dramtype == LPDDR4) {
+ struct io_setting *io = lpddr4_get_io_settings(params, mr5);
+ u32 rd_vref = io->rd_vref * 1000;
+
+ if (rd_vref < 36700) {
+ /* MODE_LV[2:0] = LPDDR4 (Range 2)*/
+ vref_mode_dq = 0x7;
+ /* MODE[2:0]= LPDDR4 Range 2(0.4*VDDQ) */
+ mode_sel = 0x5;
+ vref_value_dq = (rd_vref - 3300) / 521;
+ } else {
+ /* MODE_LV[2:0] = LPDDR4 (Range 1)*/
+ vref_mode_dq = 0x6;
+ /* MODE[2:0]= LPDDR4 Range 1(0.33*VDDQ) */
+ mode_sel = 0x4;
+ vref_value_dq = (rd_vref - 15300) / 521;
+ }
vref_mode_ac = 0x6;
- vref_value_ac = 0x1f;
- } else if (sdram_params->base.dramtype == LPDDR3) {
- if (sdram_params->base.odt == 1) {
+ /* VDDQ/3/2=16.8% */
+ vref_value_ac = 0x3;
+ } else if (params->base.dramtype == LPDDR3) {
+ if (params->base.odt == 1) {
vref_mode_dq = 0x5; /* LPDDR3 ODT */
drv_value = (readl(&denali_phy[6]) >> 12) & 0xf;
odt_value = (readl(&denali_phy[6]) >> 4) & 0xf;
@@ -370,12 +450,14 @@ static int phy_io_config(const struct chan_info *chan,
}
vref_mode_ac = 0x2;
vref_value_ac = 0x1f;
- } else if (sdram_params->base.dramtype == DDR3) {
+ mode_sel = 0x0;
+ } else if (params->base.dramtype == DDR3) {
/* DDR3L */
vref_mode_dq = 0x1;
vref_value_dq = 0x1f;
vref_mode_ac = 0x1;
vref_value_ac = 0x1f;
+ mode_sel = 0x1;
} else {
debug("Unknown DRAM type.\n");
return -EINVAL;
@@ -397,15 +479,6 @@ static int phy_io_config(const struct chan_info *chan,
/* PHY_915 PHY_PAD_VREF_CTRL_AC 12bits offset_16 */
clrsetbits_le32(&denali_phy[915], 0xfff << 16, reg_value << 16);
- if (sdram_params->base.dramtype == LPDDR4)
- mode_sel = 0x6;
- else if (sdram_params->base.dramtype == LPDDR3)
- mode_sel = 0x0;
- else if (sdram_params->base.dramtype == DDR3)
- mode_sel = 0x1;
- else
- return -EINVAL;
-
/* PHY_924 PHY_PAD_FDBK_DRIVE */
clrsetbits_le32(&denali_phy[924], 0x7 << 15, mode_sel << 15);
/* PHY_926 PHY_PAD_DATA_DRIVE */
@@ -423,13 +496,52 @@ static int phy_io_config(const struct chan_info *chan,
/* PHY_939 PHY_PAD_CS_DRIVE */
clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ /* BOOSTP_EN & BOOSTN_EN */
+ reg_value = ((PHY_BOOSTP_EN << 4) | PHY_BOOSTN_EN);
+ /* PHY_925 PHY_PAD_FDBK_DRIVE2 */
+ clrsetbits_le32(&denali_phy[925], 0xff << 8, reg_value << 8);
+ /* PHY_926 PHY_PAD_DATA_DRIVE */
+ clrsetbits_le32(&denali_phy[926], 0xff << 12, reg_value << 12);
+ /* PHY_927 PHY_PAD_DQS_DRIVE */
+ clrsetbits_le32(&denali_phy[927], 0xff << 14, reg_value << 14);
+ /* PHY_928 PHY_PAD_ADDR_DRIVE */
+ clrsetbits_le32(&denali_phy[928], 0xff << 20, reg_value << 20);
+ /* PHY_929 PHY_PAD_CLK_DRIVE */
+ clrsetbits_le32(&denali_phy[929], 0xff << 22, reg_value << 22);
+ /* PHY_935 PHY_PAD_CKE_DRIVE */
+ clrsetbits_le32(&denali_phy[935], 0xff << 20, reg_value << 20);
+ /* PHY_937 PHY_PAD_RST_DRIVE */
+ clrsetbits_le32(&denali_phy[937], 0xff << 20, reg_value << 20);
+ /* PHY_939 PHY_PAD_CS_DRIVE */
+ clrsetbits_le32(&denali_phy[939], 0xff << 20, reg_value << 20);
+
+ /* SLEWP_EN & SLEWN_EN */
+ reg_value = ((PHY_SLEWP_EN << 3) | PHY_SLEWN_EN);
+ /* PHY_924 PHY_PAD_FDBK_DRIVE */
+ clrsetbits_le32(&denali_phy[924], 0x3f << 8, reg_value << 8);
+ /* PHY_926 PHY_PAD_DATA_DRIVE */
+ clrsetbits_le32(&denali_phy[926], 0x3f, reg_value);
+ /* PHY_927 PHY_PAD_DQS_DRIVE */
+ clrsetbits_le32(&denali_phy[927], 0x3f, reg_value);
+ /* PHY_928 PHY_PAD_ADDR_DRIVE */
+ clrsetbits_le32(&denali_phy[928], 0x3f << 8, reg_value << 8);
+ /* PHY_929 PHY_PAD_CLK_DRIVE */
+ clrsetbits_le32(&denali_phy[929], 0x3f << 8, reg_value << 8);
+ /* PHY_935 PHY_PAD_CKE_DRIVE */
+ clrsetbits_le32(&denali_phy[935], 0x3f << 8, reg_value << 8);
+ /* PHY_937 PHY_PAD_RST_DRIVE */
+ clrsetbits_le32(&denali_phy[937], 0x3f << 8, reg_value << 8);
+ /* PHY_939 PHY_PAD_CS_DRIVE */
+ clrsetbits_le32(&denali_phy[939], 0x3f << 8, reg_value << 8);
+ }
/* speed setting */
- if (sdram_params->base.ddr_freq < 400)
+ if (params->base.ddr_freq < 400)
speed = 0x0;
- else if (sdram_params->base.ddr_freq < 800)
+ else if (params->base.ddr_freq < 800)
speed = 0x1;
- else if (sdram_params->base.ddr_freq < 1200)
+ else if (params->base.ddr_freq < 1200)
speed = 0x2;
else
speed = 0x3;
@@ -451,21 +563,304 @@ static int phy_io_config(const struct chan_info *chan,
/* PHY_939 PHY_PAD_CS_DRIVE */
clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ /* RX_CM_INPUT */
+ reg_value = PHY_RX_CM_INPUT;
+ /* PHY_924 PHY_PAD_FDBK_DRIVE */
+ clrsetbits_le32(&denali_phy[924], 0x1 << 14, reg_value << 14);
+ /* PHY_926 PHY_PAD_DATA_DRIVE */
+ clrsetbits_le32(&denali_phy[926], 0x1 << 11, reg_value << 11);
+ /* PHY_927 PHY_PAD_DQS_DRIVE */
+ clrsetbits_le32(&denali_phy[927], 0x1 << 13, reg_value << 13);
+ /* PHY_928 PHY_PAD_ADDR_DRIVE */
+ clrsetbits_le32(&denali_phy[928], 0x1 << 19, reg_value << 19);
+ /* PHY_929 PHY_PAD_CLK_DRIVE */
+ clrsetbits_le32(&denali_phy[929], 0x1 << 21, reg_value << 21);
+ /* PHY_935 PHY_PAD_CKE_DRIVE */
+ clrsetbits_le32(&denali_phy[935], 0x1 << 19, reg_value << 19);
+ /* PHY_937 PHY_PAD_RST_DRIVE */
+ clrsetbits_le32(&denali_phy[937], 0x1 << 19, reg_value << 19);
+ /* PHY_939 PHY_PAD_CS_DRIVE */
+ clrsetbits_le32(&denali_phy[939], 0x1 << 19, reg_value << 19);
+ }
+
return 0;
}
-static int pctl_cfg(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+static void set_ds_odt(const struct chan_info *chan,
+ struct rk3399_sdram_params *params,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_phy = get_denali_phy(chan, params, ctl_phy_reg);
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 tsel_idle_en, tsel_wr_en, tsel_rd_en;
+ u32 tsel_idle_select_p, tsel_rd_select_p;
+ u32 tsel_idle_select_n, tsel_rd_select_n;
+ u32 tsel_wr_select_dq_p, tsel_wr_select_ca_p;
+ u32 tsel_wr_select_dq_n, tsel_wr_select_ca_n;
+ u32 tsel_ckcs_select_p, tsel_ckcs_select_n;
+ struct io_setting *io = NULL;
+ u32 soc_odt = 0;
+ u32 reg_value;
+
+ if (params->base.dramtype == LPDDR4) {
+ io = lpddr4_get_io_settings(params, mr5);
+
+ tsel_rd_select_p = PHY_DRV_ODT_HI_Z;
+ tsel_rd_select_n = io->rd_odt;
+
+ tsel_idle_select_p = PHY_DRV_ODT_HI_Z;
+ tsel_idle_select_n = PHY_DRV_ODT_240;
+
+ tsel_wr_select_dq_p = io->wr_dq_drv;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_40;
+
+ tsel_wr_select_ca_p = io->wr_ca_drv;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_40;
+
+ tsel_ckcs_select_p = io->wr_ckcs_drv;
+ tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+ switch (tsel_rd_select_n) {
+ case PHY_DRV_ODT_240:
+ soc_odt = 1;
+ break;
+ case PHY_DRV_ODT_120:
+ soc_odt = 2;
+ break;
+ case PHY_DRV_ODT_80:
+ soc_odt = 3;
+ break;
+ case PHY_DRV_ODT_60:
+ soc_odt = 4;
+ break;
+ case PHY_DRV_ODT_48:
+ soc_odt = 5;
+ break;
+ case PHY_DRV_ODT_40:
+ soc_odt = 6;
+ break;
+ case PHY_DRV_ODT_34_3:
+ soc_odt = 6;
+ printf("%s: Unable to support LPDDR4 MR22 Soc ODT\n",
+ __func__);
+ break;
+ case PHY_DRV_ODT_HI_Z:
+ default:
+ soc_odt = 0;
+ break;
+ }
+ } else if (params->base.dramtype == LPDDR3) {
+ tsel_rd_select_p = PHY_DRV_ODT_240;
+ tsel_rd_select_n = PHY_DRV_ODT_HI_Z;
+
+ tsel_idle_select_p = PHY_DRV_ODT_240;
+ tsel_idle_select_n = PHY_DRV_ODT_HI_Z;
+
+ tsel_wr_select_dq_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_34_3;
+
+ tsel_wr_select_ca_p = PHY_DRV_ODT_48;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_48;
+
+ tsel_ckcs_select_p = PHY_DRV_ODT_34_3;
+ tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+ } else {
+ tsel_rd_select_p = PHY_DRV_ODT_240;
+ tsel_rd_select_n = PHY_DRV_ODT_240;
+
+ tsel_idle_select_p = PHY_DRV_ODT_240;
+ tsel_idle_select_n = PHY_DRV_ODT_240;
+
+ tsel_wr_select_dq_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_dq_n = PHY_DRV_ODT_34_3;
+
+ tsel_wr_select_ca_p = PHY_DRV_ODT_34_3;
+ tsel_wr_select_ca_n = PHY_DRV_ODT_34_3;
+
+ tsel_ckcs_select_p = PHY_DRV_ODT_34_3;
+ tsel_ckcs_select_n = PHY_DRV_ODT_34_3;
+ }
+
+ if (params->base.odt == 1) {
+ tsel_rd_en = 1;
+
+ if (params->base.dramtype == LPDDR4)
+ tsel_rd_en = io->rd_odt_en;
+ } else {
+ tsel_rd_en = 0;
+ }
+
+ tsel_wr_en = 0;
+ tsel_idle_en = 0;
+
+ /* F0_0 */
+ clrsetbits_le32(&denali_ctl[145], 0xFF << 16,
+ (soc_odt | (CS0_MR22_VAL << 3)) << 16);
+ /* F2_0, F1_0 */
+ clrsetbits_le32(&denali_ctl[146], 0xFF00FF,
+ ((soc_odt | (CS0_MR22_VAL << 3)) << 16) |
+ (soc_odt | (CS0_MR22_VAL << 3)));
+ /* F0_1 */
+ clrsetbits_le32(&denali_ctl[159], 0xFF << 16,
+ (soc_odt | (CS1_MR22_VAL << 3)) << 16);
+ /* F2_1, F1_1 */
+ clrsetbits_le32(&denali_ctl[160], 0xFF00FF,
+ ((soc_odt | (CS1_MR22_VAL << 3)) << 16) |
+ (soc_odt | (CS1_MR22_VAL << 3)));
+
+ /*
+ * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0
+ * sets termination values for read/idle cycles and drive strength
+ * for write cycles for DQ/DM
+ */
+ reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) |
+ (tsel_wr_select_dq_n << 8) | (tsel_wr_select_dq_p << 12) |
+ (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20);
+ clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value);
+
+ /*
+ * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0
+ * sets termination values for read/idle cycles and drive strength
+ * for write cycles for DQS
+ */
+ clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value);
+ clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value);
+
+ /* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */
+ reg_value = tsel_wr_select_ca_n | (tsel_wr_select_ca_p << 0x4);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ /* LPDDR4 these register read always return 0, so
+ * can not use clrsetbits_le32(), need to write32
+ */
+ writel((0x300 << 8) | reg_value, &denali_phy[544]);
+ writel((0x300 << 8) | reg_value, &denali_phy[672]);
+ writel((0x300 << 8) | reg_value, &denali_phy[800]);
+ } else {
+ clrsetbits_le32(&denali_phy[544], 0xff, reg_value);
+ clrsetbits_le32(&denali_phy[672], 0xff, reg_value);
+ clrsetbits_le32(&denali_phy[800], 0xff, reg_value);
+ }
+
+ /* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */
+ clrsetbits_le32(&denali_phy[928], 0xff, reg_value);
+
+ /* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */
+ if (!ctl_phy_reg)
+ clrsetbits_le32(&denali_phy[937], 0xff, reg_value);
+
+ /* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */
+ clrsetbits_le32(&denali_phy[935], 0xff, reg_value);
+
+ /* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */
+ clrsetbits_le32(&denali_phy[939], 0xff,
+ tsel_ckcs_select_n | (tsel_ckcs_select_p << 0x4));
+
+ /* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */
+ clrsetbits_le32(&denali_phy[929], 0xff,
+ tsel_ckcs_select_n | (tsel_ckcs_select_p << 0x4));
+
+ /* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */
+ clrsetbits_le32(&denali_phy[924], 0xff,
+ tsel_wr_select_dq_n | (tsel_wr_select_dq_p << 4));
+ clrsetbits_le32(&denali_phy[925], 0xff,
+ tsel_rd_select_n | (tsel_rd_select_p << 4));
+
+ /* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */
+ reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
+ << 16;
+ clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value);
+ clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value);
+ clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value);
+ clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value);
+
+ /* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */
+ reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2))
+ << 24;
+ clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value);
+ clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value);
+ clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value);
+ clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value);
+
+ /* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */
+ reg_value = tsel_wr_en << 8;
+ clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value);
+ clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value);
+ clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value);
+
+ /* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */
+ reg_value = tsel_wr_en << 17;
+ clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value);
+ /*
+ * pad_rst/cke/cs/clk_term tsel 1bits
+ * DENALI_PHY_938/936/940/934 offset_17
+ */
+ clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value);
+ clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value);
+ clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value);
+ clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value);
+
+ /* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */
+ clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value);
+
+ phy_io_config(chan, params, mr5);
+}
+
+static void pctl_start(struct dram_info *dram, u8 channel)
+{
+ const struct chan_info *chan = &dram->chan[channel];
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 *denali_phy = chan->publ->denali_phy;
+ u32 *ddrc0_con = get_ddrc0_con(dram, channel);
+ u32 count = 0;
+ u32 byte, tmp;
+
+ writel(0x01000000, &ddrc0_con);
+
+ clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
+
+ while (!(readl(&denali_ctl[203]) & (1 << 3))) {
+ if (count > 1000) {
+ printf("%s: Failed to init pctl for channel %d\n",
+ __func__, channel);
+ while (1)
+ ;
+ }
+
+ udelay(1);
+ count++;
+ }
+
+ writel(0x01000100, &ddrc0_con);
+
+ for (byte = 0; byte < 4; byte++) {
+ tmp = 0x820;
+ writel((tmp << 16) | tmp, &denali_phy[53 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[54 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[55 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[56 + (128 * byte)]);
+ writel((tmp << 16) | tmp, &denali_phy[57 + (128 * byte)]);
+
+ clrsetbits_le32(&denali_phy[58 + (128 * byte)], 0xffff, tmp);
+ }
+
+ clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
+ dram->pwrup_srefresh_exit[channel]);
+}
+
+static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
+ u32 channel, struct rk3399_sdram_params *params)
{
u32 *denali_ctl = chan->pctl->denali_ctl;
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
- const u32 *params_ctl = sdram_params->pctl_regs.denali_ctl;
- const u32 *params_phy = sdram_params->phy_regs.denali_phy;
+ const u32 *params_ctl = params->pctl_regs.denali_ctl;
+ const u32 *params_phy = params->phy_regs.denali_phy;
u32 tmp, tmp1, tmp2;
- u32 pwrup_srefresh_exit;
- int ret;
- const ulong timeout_ms = 200;
/*
* work around controller bug:
@@ -474,16 +869,38 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel,
copy_to_reg(&denali_ctl[1], &params_ctl[1],
sizeof(struct rk3399_ddr_pctl_regs) - 4);
writel(params_ctl[0], &denali_ctl[0]);
- copy_to_reg(denali_pi, &sdram_params->pi_regs.denali_pi[0],
+
+ /*
+ * two channel init at the same time, then ZQ Cal Start
+ * at the same time, it will use the same RZQ, but cannot
+ * start at the same time.
+ *
+ * So, increase tINIT3 for channel 1, will avoid two
+ * channel ZQ Cal Start at the same time
+ */
+ if (params->base.dramtype == LPDDR4 && channel == 1) {
+ tmp = ((params->base.ddr_freq * MHz + 999) / 1000);
+ tmp1 = readl(&denali_ctl[14]);
+ writel(tmp + tmp1, &denali_ctl[14]);
+ }
+
+ copy_to_reg(denali_pi, &params->pi_regs.denali_pi[0],
sizeof(struct rk3399_ddr_pi_regs));
+
/* rank count need to set for init */
- set_memory_map(chan, channel, sdram_params);
+ set_memory_map(chan, channel, params);
+
+ writel(params->phy_regs.denali_phy[910], &denali_phy[910]);
+ writel(params->phy_regs.denali_phy[911], &denali_phy[911]);
+ writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
- writel(sdram_params->phy_regs.denali_phy[910], &denali_phy[910]);
- writel(sdram_params->phy_regs.denali_phy[911], &denali_phy[911]);
- writel(sdram_params->phy_regs.denali_phy[912], &denali_phy[912]);
+ if (IS_ENABLED(CONFIG_RAM_RK3399_LPDDR4)) {
+ writel(params->phy_regs.denali_phy[898], &denali_phy[898]);
+ writel(params->phy_regs.denali_phy[919], &denali_phy[919]);
+ }
- pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT;
+ dram->pwrup_srefresh_exit[channel] = readl(&denali_ctl[68]) &
+ PWRUP_SREFRESH_EXIT;
clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
/* PHY_DLL_RST_EN */
@@ -492,16 +909,22 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel,
setbits_le32(&denali_pi[0], START);
setbits_le32(&denali_ctl[0], START);
- /* Wating for phy DLL lock */
- while (1) {
- tmp = readl(&denali_phy[920]);
- tmp1 = readl(&denali_phy[921]);
- tmp2 = readl(&denali_phy[922]);
- if ((((tmp >> 16) & 0x1) == 0x1) &&
- (((tmp1 >> 16) & 0x1) == 0x1) &&
- (((tmp1 >> 0) & 0x1) == 0x1) &&
- (((tmp2 >> 0) & 0x1) == 0x1))
- break;
+ /**
+ * LPDDR4 use PLL bypass mode for init
+ * not need to wait for the PLL to lock
+ */
+ if (params->base.dramtype != LPDDR4) {
+ /* Waiting for phy DLL lock */
+ while (1) {
+ tmp = readl(&denali_phy[920]);
+ tmp1 = readl(&denali_phy[921]);
+ tmp2 = readl(&denali_phy[922]);
+ if ((((tmp >> 16) & 0x1) == 0x1) &&
+ (((tmp1 >> 16) & 0x1) == 0x1) &&
+ (((tmp1 >> 0) & 0x1) == 0x1) &&
+ (((tmp2 >> 0) & 0x1) == 0x1))
+ break;
+ }
}
copy_to_reg(&denali_phy[896], &params_phy[896], (958 - 895) * 4);
@@ -512,7 +935,7 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel,
copy_to_reg(&denali_phy[512], &params_phy[512], (549 - 512 + 1) * 4);
copy_to_reg(&denali_phy[640], &params_phy[640], (677 - 640 + 1) * 4);
copy_to_reg(&denali_phy[768], &params_phy[768], (805 - 768 + 1) * 4);
- set_ds_odt(chan, sdram_params);
+ set_ds_odt(chan, params, true, 0);
/*
* phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8
@@ -540,26 +963,6 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel,
tmp = (readl(&denali_phy[467]) >> 16) & 0xff;
clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16);
- ret = phy_io_config(chan, sdram_params);
- if (ret)
- return ret;
-
- /* PHY_DLL_RST_EN */
- clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
-
- /* Wating for PHY and DRAM init complete */
- tmp = get_timer(0);
- do {
- if (get_timer(tmp) > timeout_ms) {
- pr_err("DRAM (%s): phy failed to lock within %ld ms\n",
- __func__, timeout_ms);
- return -ETIME;
- }
- } while (!(readl(&denali_ctl[203]) & (1 << 3)));
- debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp));
-
- clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
- pwrup_srefresh_exit);
return 0;
}
@@ -569,7 +972,7 @@ static void select_per_cs_training_index(const struct chan_info *chan,
u32 *denali_phy = chan->publ->denali_phy;
/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
- if ((readl(&denali_phy[84])>>16) & 1) {
+ if ((readl(&denali_phy[84]) >> 16) & 1) {
/*
* PHY_8/136/264/392
* phy_per_cs_training_index_X 1bit offset_24
@@ -611,18 +1014,32 @@ static void override_write_leveling_value(const struct chan_info *chan)
}
static int data_training_ca(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
u32 i, tmp;
u32 obs_0, obs_1, obs_2, obs_err = 0;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+ u32 rank_mask;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
+
+ if (params->base.dramtype == LPDDR4)
+ rank_mask = (rank == 1) ? 0x5 : 0xf;
+ else
+ rank_mask = (rank == 1) ? 0x1 : 0x3;
+
+ for (i = 0; i < 4; i++) {
+ if (!(rank_mask & (1 << i)))
+ continue;
- for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_100 PI_CALVL_EN:RW:8:2 */
clrsetbits_le32(&denali_pi[100], 0x3 << 8, 0x2 << 8);
+
/* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
clrsetbits_le32(&denali_pi[92],
(0x1 << 16) | (0x3 << 24),
@@ -646,33 +1063,40 @@ static int data_training_ca(const struct chan_info *chan, u32 channel,
if ((((tmp >> 11) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 5) & 0x1) == 0x0) &&
- (obs_err == 0))
+ obs_err == 0)
break;
else if ((((tmp >> 5) & 0x1) == 0x1) ||
(obs_err == 1))
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[100], 0x3 << 8);
return 0;
}
static int data_training_wl(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
u32 i, tmp;
u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_60 PI_WRLVL_EN:RW:8:2 */
clrsetbits_le32(&denali_pi[60], 0x3 << 8, 0x2 << 8);
+
/* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
clrsetbits_le32(&denali_pi[59],
(0x1 << 8) | (0x3 << 16),
@@ -700,12 +1124,13 @@ static int data_training_wl(const struct chan_info *chan, u32 channel,
if ((((tmp >> 10) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 4) & 0x1) == 0x0) &&
- (obs_err == 0))
+ obs_err == 0)
break;
else if ((((tmp >> 4) & 0x1) == 0x1) ||
(obs_err == 1))
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
@@ -717,18 +1142,23 @@ static int data_training_wl(const struct chan_info *chan, u32 channel,
}
static int data_training_rg(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 *denali_phy = chan->publ->denali_phy;
u32 i, tmp;
u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
clrsetbits_le32(&denali_pi[80], 0x3 << 24, 0x2 << 24);
+
/*
* PI_74 PI_RDLVL_GATE_REQ:WR:16:1
* PI_RDLVL_CS:RW:24:2
@@ -759,31 +1189,38 @@ static int data_training_rg(const struct chan_info *chan, u32 channel,
if ((((tmp >> 9) & 0x1) == 0x1) &&
(((tmp >> 13) & 0x1) == 0x1) &&
(((tmp >> 3) & 0x1) == 0x0) &&
- (obs_err == 0))
+ obs_err == 0)
break;
else if ((((tmp >> 3) & 0x1) == 0x1) ||
(obs_err == 1))
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[80], 0x3 << 24);
return 0;
}
static int data_training_rl(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 i, tmp;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/* PI_80 PI_RDLVL_EN:RW:16:2 */
clrsetbits_le32(&denali_pi[80], 0x3 << 16, 0x2 << 16);
+
/* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
clrsetbits_le32(&denali_pi[74],
(0x1 << 8) | (0x3 << 24),
@@ -806,30 +1243,47 @@ static int data_training_rl(const struct chan_info *chan, u32 channel,
else if (((tmp >> 2) & 0x1) == 0x1)
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[80], 0x3 << 16);
return 0;
}
static int data_training_wdql(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
u32 *denali_pi = chan->pi->denali_pi;
u32 i, tmp;
- u32 rank = sdram_params->ch[channel].rank;
+ u32 rank = params->ch[channel].cap_info.rank;
+ u32 rank_mask;
+
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ writel(0x00003f7c, (&denali_pi[175]));
+
+ if (params->base.dramtype == LPDDR4)
+ rank_mask = (rank == 1) ? 0x5 : 0xf;
+ else
+ rank_mask = (rank == 1) ? 0x1 : 0x3;
+
+ for (i = 0; i < 4; i++) {
+ if (!(rank_mask & (1 << i)))
+ continue;
- for (i = 0; i < rank; i++) {
select_per_cs_training_index(chan, i);
+
/*
* disable PI_WDQLVL_VREF_EN before wdq leveling?
* PI_181 PI_WDQLVL_VREF_EN:RW:8:1
*/
clrbits_le32(&denali_pi[181], 0x1 << 8);
+
/* PI_124 PI_WDQLVL_EN:RW:16:2 */
clrsetbits_le32(&denali_pi[124], 0x3 << 16, 0x2 << 16);
+
/* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
clrsetbits_le32(&denali_pi[121],
(0x1 << 8) | (0x3 << 16),
@@ -846,32 +1300,36 @@ static int data_training_wdql(const struct chan_info *chan, u32 channel,
else if (((tmp >> 6) & 0x1) == 0x1)
return -EIO;
}
+
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
writel(0x00003f7c, (&denali_pi[175]));
}
+
clrbits_le32(&denali_pi[124], 0x3 << 16);
return 0;
}
-static int data_training(const struct chan_info *chan, u32 channel,
- const struct rk3399_sdram_params *sdram_params,
+static int data_training(struct dram_info *dram, u32 channel,
+ const struct rk3399_sdram_params *params,
u32 training_flag)
{
+ struct chan_info *chan = &dram->chan[channel];
u32 *denali_phy = chan->publ->denali_phy;
+ int ret;
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
setbits_le32(&denali_phy[927], (1 << 22));
if (training_flag == PI_FULL_TRAINING) {
- if (sdram_params->base.dramtype == LPDDR4) {
- training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
+ if (params->base.dramtype == LPDDR4) {
+ training_flag = PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING |
PI_READ_LEVELING | PI_WDQ_LEVELING;
- } else if (sdram_params->base.dramtype == LPDDR3) {
+ } else if (params->base.dramtype == LPDDR3) {
training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING;
- } else if (sdram_params->base.dramtype == DDR3) {
+ } else if (params->base.dramtype == DDR3) {
training_flag = PI_WRITE_LEVELING |
PI_READ_GATE_TRAINING |
PI_READ_LEVELING;
@@ -879,24 +1337,49 @@ static int data_training(const struct chan_info *chan, u32 channel,
}
/* ca training(LPDDR4,LPDDR3 support) */
- if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING)
- data_training_ca(chan, channel, sdram_params);
+ if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
+ ret = data_training_ca(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training ca failed\n", __func__);
+ return ret;
+ }
+ }
/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING)
- data_training_wl(chan, channel, sdram_params);
+ if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
+ ret = data_training_wl(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training wl failed\n", __func__);
+ return ret;
+ }
+ }
/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING)
- data_training_rg(chan, channel, sdram_params);
+ if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
+ ret = data_training_rg(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training rg failed\n", __func__);
+ return ret;
+ }
+ }
/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING)
- data_training_rl(chan, channel, sdram_params);
+ if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
+ ret = data_training_rl(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training rl failed\n", __func__);
+ return ret;
+ }
+ }
/* wdq leveling(LPDDR4 support) */
- if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING)
- data_training_wdql(chan, channel, sdram_params);
+ if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
+ ret = data_training_wdql(chan, channel, params);
+ if (ret < 0) {
+ debug("%s: data training wdql failed\n", __func__);
+ return ret;
+ }
+ }
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
clrbits_le32(&denali_phy[927], (1 << 22));
@@ -905,7 +1388,7 @@ static int data_training(const struct chan_info *chan, u32 channel,
}
static void set_ddrconfig(const struct chan_info *chan,
- const struct rk3399_sdram_params *sdram_params,
+ const struct rk3399_sdram_params *params,
unsigned char channel, u32 ddrconfig)
{
/* only need to set ddrconfig */
@@ -913,14 +1396,14 @@ static void set_ddrconfig(const struct chan_info *chan,
unsigned int cs0_cap = 0;
unsigned int cs1_cap = 0;
- cs0_cap = (1 << (sdram_params->ch[channel].cs0_row
- + sdram_params->ch[channel].col
- + sdram_params->ch[channel].bk
- + sdram_params->ch[channel].bw - 20));
- if (sdram_params->ch[channel].rank > 1)
- cs1_cap = cs0_cap >> (sdram_params->ch[channel].cs0_row
- - sdram_params->ch[channel].cs1_row);
- if (sdram_params->ch[channel].row_3_4) {
+ cs0_cap = (1 << (params->ch[channel].cap_info.cs0_row
+ + params->ch[channel].cap_info.col
+ + params->ch[channel].cap_info.bk
+ + params->ch[channel].cap_info.bw - 20));
+ if (params->ch[channel].cap_info.rank > 1)
+ cs1_cap = cs0_cap >> (params->ch[channel].cap_info.cs0_row
+ - params->ch[channel].cap_info.cs1_row);
+ if (params->ch[channel].cap_info.row_3_4) {
cs0_cap = cs0_cap * 3 / 4;
cs1_cap = cs1_cap * 3 / 4;
}
@@ -931,57 +1414,72 @@ static void set_ddrconfig(const struct chan_info *chan,
}
static void dram_all_config(struct dram_info *dram,
- const struct rk3399_sdram_params *sdram_params)
+ const struct rk3399_sdram_params *params)
{
- u32 sys_reg = 0;
+ u32 sys_reg2 = 0;
+ u32 sys_reg3 = 0;
unsigned int channel, idx;
- sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT;
- sys_reg |= (sdram_params->base.num_channels - 1)
- << SYS_REG_NUM_CH_SHIFT;
+ sys_reg2 |= SYS_REG_ENC_DDRTYPE(params->base.dramtype);
+ sys_reg2 |= SYS_REG_ENC_NUM_CH(params->base.num_channels);
+
for (channel = 0, idx = 0;
- (idx < sdram_params->base.num_channels) && (channel < 2);
+ (idx < params->base.num_channels) && (channel < 2);
channel++) {
- const struct rk3399_sdram_channel *info =
- &sdram_params->ch[channel];
+ const struct rk3399_sdram_channel *info = &params->ch[channel];
struct rk3399_msch_regs *ddr_msch_regs;
const struct rk3399_msch_timings *noc_timing;
- if (sdram_params->ch[channel].col == 0)
+ if (params->ch[channel].cap_info.col == 0)
continue;
idx++;
- sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(channel);
- sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(channel);
- sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(channel);
- sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(channel);
- sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(channel);
- sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(channel);
- sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(channel);
- sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(channel);
- sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(channel);
+ sys_reg2 |= SYS_REG_ENC_ROW_3_4(info->cap_info.row_3_4, channel);
+ sys_reg2 |= SYS_REG_ENC_CHINFO(channel);
+ sys_reg2 |= SYS_REG_ENC_RANK(info->cap_info.rank, channel);
+ sys_reg2 |= SYS_REG_ENC_COL(info->cap_info.col, channel);
+ sys_reg2 |= SYS_REG_ENC_BK(info->cap_info.bk, channel);
+ sys_reg2 |= SYS_REG_ENC_BW(info->cap_info.bw, channel);
+ sys_reg2 |= SYS_REG_ENC_DBW(info->cap_info.dbw, channel);
+ SYS_REG_ENC_CS0_ROW(info->cap_info.cs0_row, sys_reg2, sys_reg3, channel);
+ if (info->cap_info.cs1_row)
+ SYS_REG_ENC_CS1_ROW(info->cap_info.cs1_row, sys_reg2,
+ sys_reg3, channel);
+ sys_reg3 |= SYS_REG_ENC_CS1_COL(info->cap_info.col, channel);
+ sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
ddr_msch_regs = dram->chan[channel].msch;
- noc_timing = &sdram_params->ch[channel].noc_timings;
+ noc_timing = &params->ch[channel].noc_timings;
writel(noc_timing->ddrtiminga0,
&ddr_msch_regs->ddrtiminga0);
writel(noc_timing->ddrtimingb0,
&ddr_msch_regs->ddrtimingb0);
- writel(noc_timing->ddrtimingc0,
+ writel(noc_timing->ddrtimingc0.d32,
&ddr_msch_regs->ddrtimingc0);
writel(noc_timing->devtodev0,
&ddr_msch_regs->devtodev0);
- writel(noc_timing->ddrmode,
+ writel(noc_timing->ddrmode.d32,
&ddr_msch_regs->ddrmode);
- /* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
- if (sdram_params->ch[channel].rank == 1)
+ /**
+ * rank 1 memory clock disable (dfi_dram_clk_disable = 1)
+ *
+ * The hardware for LPDDR4 with
+ * - CLK0P/N connect to lower 16-bits
+ * - CLK1P/N connect to higher 16-bits
+ *
+ * dfi dram clk is configured via CLK1P/N, so disabling
+ * dfi dram clk will disable the CLK1P/N as well for lpddr4.
+ */
+ if (params->ch[channel].cap_info.rank == 1 &&
+ params->base.dramtype != LPDDR4)
setbits_le32(&dram->chan[channel].pctl->denali_ctl[276],
1 << 17);
}
- writel(sys_reg, &dram->pmugrf->os_reg2);
+ writel(sys_reg2, &dram->pmugrf->os_reg2);
+ writel(sys_reg3, &dram->pmugrf->os_reg3);
rk_clrsetreg(&dram->pmusgrf->soc_con4, 0x1f << 10,
- sdram_params->base.stride << 10);
+ params->base.stride << 10);
/* reboot hold register set */
writel(PRESET_SGRF_HOLD(0) | PRESET_GPIO0_HOLD(1) |
@@ -990,12 +1488,30 @@ static void dram_all_config(struct dram_info *dram,
clrsetbits_le32(&dram->cru->glb_rst_con, 0x3, 0x3);
}
+#if !defined(CONFIG_RAM_RK3399_LPDDR4)
+static int default_data_training(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *params)
+{
+ u8 training_flag = PI_READ_GATE_TRAINING;
+
+ /*
+ * LPDDR3 CA training msut be trigger before
+ * other training.
+ * DDR3 is not have CA training.
+ */
+
+ if (params->base.dramtype == LPDDR3)
+ training_flag |= PI_CA_TRAINING;
+
+ return data_training(dram, channel, params, training_flag);
+}
+
static int switch_to_phy_index1(struct dram_info *dram,
- const struct rk3399_sdram_params *sdram_params)
+ struct rk3399_sdram_params *params)
{
u32 channel;
u32 *denali_phy;
- u32 ch_count = sdram_params->base.num_channels;
+ u32 ch_count = params->base.num_channels;
int ret;
int i = 0;
@@ -1025,9 +1541,8 @@ static int switch_to_phy_index1(struct dram_info *dram,
for (channel = 0; channel < ch_count; channel++) {
denali_phy = dram->chan[channel].publ->denali_phy;
clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8);
- ret = data_training(&dram->chan[channel], channel,
- sdram_params, PI_FULL_TRAINING);
- if (ret) {
+ ret = data_training(dram, channel, params, PI_FULL_TRAINING);
+ if (ret < 0) {
debug("index1 training failed\n");
return ret;
}
@@ -1036,12 +1551,979 @@ static int switch_to_phy_index1(struct dram_info *dram,
return 0;
}
-static int sdram_init(struct dram_info *dram,
- const struct rk3399_sdram_params *sdram_params)
+#else
+
+struct rk3399_sdram_params lpddr4_timings[] = {
+ #include "sdram-rk3399-lpddr4-400.inc"
+ #include "sdram-rk3399-lpddr4-800.inc"
+};
+
+static void *get_denali_pi(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, bool reg)
+{
+ return reg ? &chan->pi->denali_pi : &params->pi_regs.denali_pi;
+}
+
+static u32 lpddr4_get_phy(struct rk3399_sdram_params *params, u32 ctl)
+{
+ u32 lpddr4_phy[] = {1, 0, 0xb};
+
+ return lpddr4_phy[ctl];
+}
+
+static u32 lpddr4_get_ctl(struct rk3399_sdram_params *params, u32 phy)
+{
+ u32 lpddr4_ctl[] = {1, 0, 2};
+
+ return lpddr4_ctl[phy];
+}
+
+static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
+{
+ return ((readl(&pmusgrf->soc_con4) >> 10) & 0x1F);
+}
+
+static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
+{
+ rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
+}
+
+static void set_cap_relate_config(const struct chan_info *chan,
+ struct rk3399_sdram_params *params,
+ unsigned int channel)
+{
+ u32 *denali_ctl = chan->pctl->denali_ctl;
+ u32 tmp;
+ struct rk3399_msch_timings *noc_timing;
+
+ if (params->base.dramtype == LPDDR3) {
+ tmp = (8 << params->ch[channel].cap_info.bw) /
+ (8 << params->ch[channel].cap_info.dbw);
+
+ /**
+ * memdata_ratio
+ * 1 -> 0, 2 -> 1, 4 -> 2
+ */
+ clrsetbits_le32(&denali_ctl[197], 0x7,
+ (tmp >> 1));
+ clrsetbits_le32(&denali_ctl[198], 0x7 << 8,
+ (tmp >> 1) << 8);
+ }
+
+ noc_timing = &params->ch[channel].noc_timings;
+
+ /*
+ * noc timing bw relate timing is 32 bit, and real bw is 16bit
+ * actually noc reg is setting at function dram_all_config
+ */
+ if (params->ch[channel].cap_info.bw == 16 &&
+ noc_timing->ddrmode.b.mwrsize == 2) {
+ if (noc_timing->ddrmode.b.burstsize)
+ noc_timing->ddrmode.b.burstsize -= 1;
+ noc_timing->ddrmode.b.mwrsize -= 1;
+ noc_timing->ddrtimingc0.b.burstpenalty *= 2;
+ noc_timing->ddrtimingc0.b.wrtomwr *= 2;
+ }
+}
+
+static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel)
+{
+ unsigned int cs0_row = params->ch[channel].cap_info.cs0_row;
+ unsigned int col = params->ch[channel].cap_info.col;
+ unsigned int bw = params->ch[channel].cap_info.bw;
+ u16 ddr_cfg_2_rbc[] = {
+ /*
+ * [6] highest bit col
+ * [5:3] max row(14+n)
+ * [2] insertion row
+ * [1:0] col(9+n),col, data bus 32bit
+ *
+ * highbitcol, max_row, insertion_row, col
+ */
+ ((0 << 6) | (2 << 3) | (0 << 2) | 0), /* 0 */
+ ((0 << 6) | (2 << 3) | (0 << 2) | 1), /* 1 */
+ ((0 << 6) | (1 << 3) | (0 << 2) | 2), /* 2 */
+ ((0 << 6) | (0 << 3) | (0 << 2) | 3), /* 3 */
+ ((0 << 6) | (2 << 3) | (1 << 2) | 1), /* 4 */
+ ((0 << 6) | (1 << 3) | (1 << 2) | 2), /* 5 */
+ ((1 << 6) | (0 << 3) | (0 << 2) | 2), /* 6 */
+ ((1 << 6) | (1 << 3) | (0 << 2) | 2), /* 7 */
+ };
+ u32 i;
+
+ col -= (bw == 2) ? 0 : 1;
+ col -= 9;
+
+ for (i = 0; i < 4; i++) {
+ if ((col == (ddr_cfg_2_rbc[i] & 0x3)) &&
+ (cs0_row <= (((ddr_cfg_2_rbc[i] >> 3) & 0x7) + 14)))
+ break;
+ }
+
+ if (i >= 4)
+ i = -EINVAL;
+
+ return i;
+}
+
+/**
+ * read mr_num mode register
+ * rank = 1: cs0
+ * rank = 2: cs1
+ */
+static int read_mr(struct rk3399_ddr_pctl_regs *ddr_pctl_regs, u32 rank,
+ u32 mr_num, u32 *buf)
+{
+ s32 timeout = 100;
+
+ writel(((1 << 16) | (((rank == 2) ? 1 : 0) << 8) | mr_num) << 8,
+ &ddr_pctl_regs->denali_ctl[118]);
+
+ while (0 == (readl(&ddr_pctl_regs->denali_ctl[203]) &
+ ((1 << 21) | (1 << 12)))) {
+ udelay(1);
+
+ if (timeout <= 0) {
+ printf("%s: pctl timeout!\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ timeout--;
+ }
+
+ if (!(readl(&ddr_pctl_regs->denali_ctl[203]) & (1 << 12))) {
+ *buf = readl(&ddr_pctl_regs->denali_ctl[119]) & 0xFF;
+ } else {
+ printf("%s: read mr failed with 0x%x status\n", __func__,
+ readl(&ddr_pctl_regs->denali_ctl[17]) & 0x3);
+ *buf = 0;
+ }
+
+ setbits_le32(&ddr_pctl_regs->denali_ctl[205], (1 << 21) | (1 << 12));
+
+ return 0;
+}
+
+static int lpddr4_mr_detect(struct dram_info *dram, u32 channel, u8 rank,
+ struct rk3399_sdram_params *params)
+{
+ u64 cs0_cap;
+ u32 stride;
+ u32 cs = 0, col = 0, bk = 0, bw = 0, row_3_4 = 0;
+ u32 cs0_row = 0, cs1_row = 0, ddrconfig = 0;
+ u32 mr5, mr12, mr14;
+ struct chan_info *chan = &dram->chan[channel];
+ struct rk3399_ddr_pctl_regs *ddr_pctl_regs = chan->pctl;
+ void __iomem *addr = NULL;
+ int ret = 0;
+ u32 val;
+
+ stride = get_ddr_stride(dram->pmusgrf);
+
+ if (params->ch[channel].cap_info.col == 0) {
+ ret = -EPERM;
+ goto end;
+ }
+
+ cs = params->ch[channel].cap_info.rank;
+ col = params->ch[channel].cap_info.col;
+ bk = params->ch[channel].cap_info.bk;
+ bw = params->ch[channel].cap_info.bw;
+ row_3_4 = params->ch[channel].cap_info.row_3_4;
+ cs0_row = params->ch[channel].cap_info.cs0_row;
+ cs1_row = params->ch[channel].cap_info.cs1_row;
+ ddrconfig = params->ch[channel].cap_info.ddrconfig;
+
+ /* 2GB */
+ params->ch[channel].cap_info.rank = 2;
+ params->ch[channel].cap_info.col = 10;
+ params->ch[channel].cap_info.bk = 3;
+ params->ch[channel].cap_info.bw = 2;
+ params->ch[channel].cap_info.row_3_4 = 0;
+ params->ch[channel].cap_info.cs0_row = 15;
+ params->ch[channel].cap_info.cs1_row = 15;
+ params->ch[channel].cap_info.ddrconfig = 1;
+
+ set_memory_map(chan, channel, params);
+ params->ch[channel].cap_info.ddrconfig =
+ calculate_ddrconfig(params, channel);
+ set_ddrconfig(chan, params, channel,
+ params->ch[channel].cap_info.ddrconfig);
+ set_cap_relate_config(chan, params, channel);
+
+ cs0_cap = (1 << (params->ch[channel].cap_info.bw
+ + params->ch[channel].cap_info.col
+ + params->ch[channel].cap_info.bk
+ + params->ch[channel].cap_info.cs0_row));
+
+ if (params->ch[channel].cap_info.row_3_4)
+ cs0_cap = cs0_cap * 3 / 4;
+
+ if (channel == 0)
+ set_ddr_stride(dram->pmusgrf, 0x17);
+ else
+ set_ddr_stride(dram->pmusgrf, 0x18);
+
+ /* read and write data to DRAM, avoid be optimized by compiler. */
+ if (rank == 1)
+ addr = (void __iomem *)0x100;
+ else if (rank == 2)
+ addr = (void __iomem *)(cs0_cap + 0x100);
+
+ val = readl(addr);
+ writel(val + 1, addr);
+
+ read_mr(ddr_pctl_regs, rank, 5, &mr5);
+ read_mr(ddr_pctl_regs, rank, 12, &mr12);
+ read_mr(ddr_pctl_regs, rank, 14, &mr14);
+
+ if (mr5 == 0 || mr12 != 0x4d || mr14 != 0x4d) {
+ ret = -EINVAL;
+ goto end;
+ }
+end:
+ params->ch[channel].cap_info.rank = cs;
+ params->ch[channel].cap_info.col = col;
+ params->ch[channel].cap_info.bk = bk;
+ params->ch[channel].cap_info.bw = bw;
+ params->ch[channel].cap_info.row_3_4 = row_3_4;
+ params->ch[channel].cap_info.cs0_row = cs0_row;
+ params->ch[channel].cap_info.cs1_row = cs1_row;
+ params->ch[channel].cap_info.ddrconfig = ddrconfig;
+
+ set_ddr_stride(dram->pmusgrf, stride);
+
+ return ret;
+}
+
+static void set_lpddr4_dq_odt(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool en, bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ if (!en)
+ return;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->dq_odt;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[139], 0x7 << 24, reg_value << 24);
+ clrsetbits_le32(&denali_ctl[153], 0x7 << 24, reg_value << 24);
+
+ clrsetbits_le32(&denali_pi[132], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[139], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[147], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[154], 0x7 << 16, (reg_value << 16));
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 0, reg_value << 0);
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 0, reg_value << 0);
+
+ clrsetbits_le32(&denali_pi[129], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[137], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[144], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[152], 0x7 << 0, (reg_value << 0));
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 8, (reg_value << 8));
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 8, (reg_value << 8));
+
+ clrsetbits_le32(&denali_pi[127], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[134], 0x7 << 16, (reg_value << 16));
+ clrsetbits_le32(&denali_pi[142], 0x7 << 0, (reg_value << 0));
+ clrsetbits_le32(&denali_pi[149], 0x7 << 16, (reg_value << 16));
+ break;
+ }
+}
+
+static void set_lpddr4_ca_odt(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool en, bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ if (!en)
+ return;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->ca_odt;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[139], 0x7 << 28, reg_value << 28);
+ clrsetbits_le32(&denali_ctl[153], 0x7 << 28, reg_value << 28);
+
+ clrsetbits_le32(&denali_pi[132], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[139], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[147], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[154], 0x7 << 20, reg_value << 20);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 4, reg_value << 4);
+
+ clrsetbits_le32(&denali_pi[129], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[137], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[144], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[152], 0x7 << 4, reg_value << 4);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[140], 0x7 << 12, (reg_value << 12));
+ clrsetbits_le32(&denali_ctl[154], 0x7 << 12, (reg_value << 12));
+
+ clrsetbits_le32(&denali_pi[127], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[134], 0x7 << 20, reg_value << 20);
+ clrsetbits_le32(&denali_pi[142], 0x7 << 4, reg_value << 4);
+ clrsetbits_le32(&denali_pi[149], 0x7 << 20, reg_value << 20);
+ break;
+ }
+}
+
+static void set_lpddr4_MR3(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = ((io->pdds << 3) | 1);
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[138], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[152], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[131], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[139], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[146], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[154], 0xFFFF, reg_value);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[138], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[152], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[129], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[136], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[144], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[151], 0xFFFF << 16, reg_value << 16);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[139], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[153], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[126], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[134], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_pi[141], 0xFFFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[149], 0xFFFF, reg_value);
+ break;
+ }
+}
+
+static void set_lpddr4_MR12(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->ca_vref;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[140], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[154], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[132], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[139], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[147], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[154], 0xFF << 24, reg_value << 24);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[141], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[155], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[129], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[137], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[144], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[152], 0xFF << 8, reg_value << 8);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[141], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[155], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[127], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[134], 0xFF << 24, reg_value << 24);
+ clrsetbits_le32(&denali_pi[142], 0xFF << 8, reg_value << 8);
+ clrsetbits_le32(&denali_pi[149], 0xFF << 24, reg_value << 24);
+ break;
+ }
+}
+
+static void set_lpddr4_MR14(const struct chan_info *chan,
+ struct rk3399_sdram_params *params, u32 ctl,
+ bool ctl_phy_reg, u32 mr5)
+{
+ u32 *denali_ctl = get_denali_ctl(chan, params, ctl_phy_reg);
+ u32 *denali_pi = get_denali_pi(chan, params, ctl_phy_reg);
+ struct io_setting *io;
+ u32 reg_value;
+
+ io = lpddr4_get_io_settings(params, mr5);
+
+ reg_value = io->dq_vref;
+
+ switch (ctl) {
+ case 0:
+ clrsetbits_le32(&denali_ctl[142], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[156], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[132], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[140], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[147], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[155], 0xFF << 0, reg_value << 0);
+ break;
+ case 1:
+ clrsetbits_le32(&denali_ctl[143], 0xFFFF, reg_value);
+ clrsetbits_le32(&denali_ctl[157], 0xFFFF, reg_value);
+
+ clrsetbits_le32(&denali_pi[130], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[137], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[145], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[152], 0xFF << 16, reg_value << 16);
+ break;
+ case 2:
+ default:
+ clrsetbits_le32(&denali_ctl[143], 0xFFFF << 16,
+ reg_value << 16);
+ clrsetbits_le32(&denali_ctl[157], 0xFFFF << 16,
+ reg_value << 16);
+
+ clrsetbits_le32(&denali_pi[127], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[135], 0xFF << 0, reg_value << 0);
+ clrsetbits_le32(&denali_pi[142], 0xFF << 16, reg_value << 16);
+ clrsetbits_le32(&denali_pi[150], 0xFF << 0, reg_value << 0);
+ break;
+ }
+}
+
+static void lpddr4_copy_phy(struct dram_info *dram,
+ struct rk3399_sdram_params *params, u32 phy,
+ struct rk3399_sdram_params *timings,
+ u32 channel)
+{
+ u32 *denali_ctl, *denali_phy;
+ u32 *denali_phy_params;
+ u32 speed = 0;
+ u32 ctl, mr5;
+
+ denali_ctl = dram->chan[channel].pctl->denali_ctl;
+ denali_phy = dram->chan[channel].publ->denali_phy;
+ denali_phy_params = timings->phy_regs.denali_phy;
+
+ /* switch index */
+ clrsetbits_le32(&denali_phy_params[896], 0x3 << 8, phy << 8);
+ writel(denali_phy_params[896], &denali_phy[896]);
+
+ /* phy_pll_ctrl_ca, phy_pll_ctrl */
+ writel(denali_phy_params[911], &denali_phy[911]);
+
+ /* phy_low_freq_sel */
+ clrsetbits_le32(&denali_phy[913], 0x1,
+ denali_phy_params[913] & 0x1);
+
+ /* phy_grp_slave_delay_x, phy_cslvl_dly_step */
+ writel(denali_phy_params[916], &denali_phy[916]);
+ writel(denali_phy_params[917], &denali_phy[917]);
+ writel(denali_phy_params[918], &denali_phy[918]);
+
+ /* phy_adrz_sw_wraddr_shift_x */
+ writel(denali_phy_params[512], &denali_phy[512]);
+ clrsetbits_le32(&denali_phy[513], 0xffff,
+ denali_phy_params[513] & 0xffff);
+ writel(denali_phy_params[640], &denali_phy[640]);
+ clrsetbits_le32(&denali_phy[641], 0xffff,
+ denali_phy_params[641] & 0xffff);
+ writel(denali_phy_params[768], &denali_phy[768]);
+ clrsetbits_le32(&denali_phy[769], 0xffff,
+ denali_phy_params[769] & 0xffff);
+
+ writel(denali_phy_params[544], &denali_phy[544]);
+ writel(denali_phy_params[545], &denali_phy[545]);
+ writel(denali_phy_params[546], &denali_phy[546]);
+ writel(denali_phy_params[547], &denali_phy[547]);
+
+ writel(denali_phy_params[672], &denali_phy[672]);
+ writel(denali_phy_params[673], &denali_phy[673]);
+ writel(denali_phy_params[674], &denali_phy[674]);
+ writel(denali_phy_params[675], &denali_phy[675]);
+
+ writel(denali_phy_params[800], &denali_phy[800]);
+ writel(denali_phy_params[801], &denali_phy[801]);
+ writel(denali_phy_params[802], &denali_phy[802]);
+ writel(denali_phy_params[803], &denali_phy[803]);
+
+ /*
+ * phy_adr_master_delay_start_x
+ * phy_adr_master_delay_step_x
+ * phy_adr_master_delay_wait_x
+ */
+ writel(denali_phy_params[548], &denali_phy[548]);
+ writel(denali_phy_params[676], &denali_phy[676]);
+ writel(denali_phy_params[804], &denali_phy[804]);
+
+ /* phy_adr_calvl_dly_step_x */
+ writel(denali_phy_params[549], &denali_phy[549]);
+ writel(denali_phy_params[677], &denali_phy[677]);
+ writel(denali_phy_params[805], &denali_phy[805]);
+
+ /*
+ * phy_clk_wrdm_slave_delay_x
+ * phy_clk_wrdqz_slave_delay_x
+ * phy_clk_wrdqs_slave_delay_x
+ */
+ copy_to_reg((u32 *)&denali_phy[59], (u32 *)&denali_phy_params[59],
+ (63 - 58) * 4);
+ copy_to_reg((u32 *)&denali_phy[187], (u32 *)&denali_phy_params[187],
+ (191 - 186) * 4);
+ copy_to_reg((u32 *)&denali_phy[315], (u32 *)&denali_phy_params[315],
+ (319 - 314) * 4);
+ copy_to_reg((u32 *)&denali_phy[443], (u32 *)&denali_phy_params[443],
+ (447 - 442) * 4);
+
+ /*
+ * phy_dqs_tsel_wr_timing_x 8bits denali_phy_84/212/340/468 offset_8
+ * dqs_tsel_wr_end[7:4] add half cycle
+ * phy_dq_tsel_wr_timing_x 8bits denali_phy_83/211/339/467 offset_8
+ * dq_tsel_wr_end[7:4] add half cycle
+ */
+ writel(denali_phy_params[83] + (0x10 << 16), &denali_phy[83]);
+ writel(denali_phy_params[84] + (0x10 << 8), &denali_phy[84]);
+ writel(denali_phy_params[85], &denali_phy[85]);
+
+ writel(denali_phy_params[211] + (0x10 << 16), &denali_phy[211]);
+ writel(denali_phy_params[212] + (0x10 << 8), &denali_phy[212]);
+ writel(denali_phy_params[213], &denali_phy[213]);
+
+ writel(denali_phy_params[339] + (0x10 << 16), &denali_phy[339]);
+ writel(denali_phy_params[340] + (0x10 << 8), &denali_phy[340]);
+ writel(denali_phy_params[341], &denali_phy[341]);
+
+ writel(denali_phy_params[467] + (0x10 << 16), &denali_phy[467]);
+ writel(denali_phy_params[468] + (0x10 << 8), &denali_phy[468]);
+ writel(denali_phy_params[469], &denali_phy[469]);
+
+ /*
+ * phy_gtlvl_resp_wait_cnt_x
+ * phy_gtlvl_dly_step_x
+ * phy_wrlvl_resp_wait_cnt_x
+ * phy_gtlvl_final_step_x
+ * phy_gtlvl_back_step_x
+ * phy_rdlvl_dly_step_x
+ *
+ * phy_master_delay_step_x
+ * phy_master_delay_wait_x
+ * phy_wrlvl_dly_step_x
+ * phy_rptr_update_x
+ * phy_wdqlvl_dly_step_x
+ */
+ writel(denali_phy_params[87], &denali_phy[87]);
+ writel(denali_phy_params[88], &denali_phy[88]);
+ writel(denali_phy_params[89], &denali_phy[89]);
+ writel(denali_phy_params[90], &denali_phy[90]);
+
+ writel(denali_phy_params[215], &denali_phy[215]);
+ writel(denali_phy_params[216], &denali_phy[216]);
+ writel(denali_phy_params[217], &denali_phy[217]);
+ writel(denali_phy_params[218], &denali_phy[218]);
+
+ writel(denali_phy_params[343], &denali_phy[343]);
+ writel(denali_phy_params[344], &denali_phy[344]);
+ writel(denali_phy_params[345], &denali_phy[345]);
+ writel(denali_phy_params[346], &denali_phy[346]);
+
+ writel(denali_phy_params[471], &denali_phy[471]);
+ writel(denali_phy_params[472], &denali_phy[472]);
+ writel(denali_phy_params[473], &denali_phy[473]);
+ writel(denali_phy_params[474], &denali_phy[474]);
+
+ /*
+ * phy_gtlvl_lat_adj_start_x
+ * phy_gtlvl_rddqs_slv_dly_start_x
+ * phy_rdlvl_rddqs_dq_slv_dly_start_x
+ * phy_wdqlvl_dqdm_slv_dly_start_x
+ */
+ writel(denali_phy_params[80], &denali_phy[80]);
+ writel(denali_phy_params[81], &denali_phy[81]);
+
+ writel(denali_phy_params[208], &denali_phy[208]);
+ writel(denali_phy_params[209], &denali_phy[209]);
+
+ writel(denali_phy_params[336], &denali_phy[336]);
+ writel(denali_phy_params[337], &denali_phy[337]);
+
+ writel(denali_phy_params[464], &denali_phy[464]);
+ writel(denali_phy_params[465], &denali_phy[465]);
+
+ /*
+ * phy_master_delay_start_x
+ * phy_sw_master_mode_x
+ * phy_rddata_en_tsel_dly_x
+ */
+ writel(denali_phy_params[86], &denali_phy[86]);
+ writel(denali_phy_params[214], &denali_phy[214]);
+ writel(denali_phy_params[342], &denali_phy[342]);
+ writel(denali_phy_params[470], &denali_phy[470]);
+
+ /*
+ * phy_rddqz_slave_delay_x
+ * phy_rddqs_dqz_fall_slave_delay_x
+ * phy_rddqs_dqz_rise_slave_delay_x
+ * phy_rddqs_dm_fall_slave_delay_x
+ * phy_rddqs_dm_rise_slave_delay_x
+ * phy_rddqs_gate_slave_delay_x
+ * phy_wrlvl_delay_early_threshold_x
+ * phy_write_path_lat_add_x
+ * phy_rddqs_latency_adjust_x
+ * phy_wrlvl_delay_period_threshold_x
+ * phy_wrlvl_early_force_zero_x
+ */
+ copy_to_reg((u32 *)&denali_phy[64], (u32 *)&denali_phy_params[64],
+ (67 - 63) * 4);
+ clrsetbits_le32(&denali_phy[68], 0xfffffc00,
+ denali_phy_params[68] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[69], (u32 *)&denali_phy_params[69],
+ (79 - 68) * 4);
+ copy_to_reg((u32 *)&denali_phy[192], (u32 *)&denali_phy_params[192],
+ (195 - 191) * 4);
+ clrsetbits_le32(&denali_phy[196], 0xfffffc00,
+ denali_phy_params[196] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[197], (u32 *)&denali_phy_params[197],
+ (207 - 196) * 4);
+ copy_to_reg((u32 *)&denali_phy[320], (u32 *)&denali_phy_params[320],
+ (323 - 319) * 4);
+ clrsetbits_le32(&denali_phy[324], 0xfffffc00,
+ denali_phy_params[324] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[325], (u32 *)&denali_phy_params[325],
+ (335 - 324) * 4);
+
+ copy_to_reg((u32 *)&denali_phy[448], (u32 *)&denali_phy_params[448],
+ (451 - 447) * 4);
+ clrsetbits_le32(&denali_phy[452], 0xfffffc00,
+ denali_phy_params[452] & 0xfffffc00);
+ copy_to_reg((u32 *)&denali_phy[453], (u32 *)&denali_phy_params[453],
+ (463 - 452) * 4);
+
+ /* phy_two_cyc_preamble_x */
+ clrsetbits_le32(&denali_phy[7], 0x3 << 24,
+ denali_phy_params[7] & (0x3 << 24));
+ clrsetbits_le32(&denali_phy[135], 0x3 << 24,
+ denali_phy_params[135] & (0x3 << 24));
+ clrsetbits_le32(&denali_phy[263], 0x3 << 24,
+ denali_phy_params[263] & (0x3 << 24));
+ clrsetbits_le32(&denali_phy[391], 0x3 << 24,
+ denali_phy_params[391] & (0x3 << 24));
+
+ /* speed */
+ if (timings->base.ddr_freq < 400 * MHz)
+ speed = 0x0;
+ else if (timings->base.ddr_freq < 800 * MHz)
+ speed = 0x1;
+ else if (timings->base.ddr_freq < 1200 * MHz)
+ speed = 0x2;
+
+ /* phy_924 phy_pad_fdbk_drive */
+ clrsetbits_le32(&denali_phy[924], 0x3 << 21, speed << 21);
+ /* phy_926 phy_pad_data_drive */
+ clrsetbits_le32(&denali_phy[926], 0x3 << 9, speed << 9);
+ /* phy_927 phy_pad_dqs_drive */
+ clrsetbits_le32(&denali_phy[927], 0x3 << 9, speed << 9);
+ /* phy_928 phy_pad_addr_drive */
+ clrsetbits_le32(&denali_phy[928], 0x3 << 17, speed << 17);
+ /* phy_929 phy_pad_clk_drive */
+ clrsetbits_le32(&denali_phy[929], 0x3 << 17, speed << 17);
+ /* phy_935 phy_pad_cke_drive */
+ clrsetbits_le32(&denali_phy[935], 0x3 << 17, speed << 17);
+ /* phy_937 phy_pad_rst_drive */
+ clrsetbits_le32(&denali_phy[937], 0x3 << 17, speed << 17);
+ /* phy_939 phy_pad_cs_drive */
+ clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17);
+
+ read_mr(dram->chan[channel].pctl, 1, 5, &mr5);
+ set_ds_odt(&dram->chan[channel], timings, true, mr5);
+
+ ctl = lpddr4_get_ctl(timings, phy);
+ set_lpddr4_dq_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
+ set_lpddr4_ca_odt(&dram->chan[channel], timings, ctl, true, true, mr5);
+ set_lpddr4_MR3(&dram->chan[channel], timings, ctl, true, mr5);
+ set_lpddr4_MR12(&dram->chan[channel], timings, ctl, true, mr5);
+ set_lpddr4_MR14(&dram->chan[channel], timings, ctl, true, mr5);
+
+ /*
+ * if phy_sw_master_mode_x not bypass mode,
+ * clear phy_slice_pwr_rdc_disable.
+ * note: need use timings, not ddr_publ_regs
+ */
+ if (!((denali_phy_params[86] >> 8) & (1 << 2))) {
+ clrbits_le32(&denali_phy[10], 1 << 16);
+ clrbits_le32(&denali_phy[138], 1 << 16);
+ clrbits_le32(&denali_phy[266], 1 << 16);
+ clrbits_le32(&denali_phy[394], 1 << 16);
+ }
+
+ /*
+ * when PHY_PER_CS_TRAINING_EN=1, W2W_DIFFCS_DLY_Fx can't
+ * smaller than 8
+ * NOTE: need use timings, not ddr_publ_regs
+ */
+ if ((denali_phy_params[84] >> 16) & 1) {
+ if (((readl(&denali_ctl[217 + ctl]) >> 16) & 0x1f) < 8)
+ clrsetbits_le32(&denali_ctl[217 + ctl],
+ 0x1f << 16, 8 << 16);
+ }
+}
+
+static void lpddr4_set_phy(struct dram_info *dram,
+ struct rk3399_sdram_params *params, u32 phy,
+ struct rk3399_sdram_params *timings)
+{
+ u32 channel;
+
+ for (channel = 0; channel < 2; channel++)
+ lpddr4_copy_phy(dram, params, phy, timings, channel);
+}
+
+static int lpddr4_set_ctl(struct dram_info *dram,
+ struct rk3399_sdram_params *params, u32 ctl, u32 hz)
+{
+ u32 channel;
+ int ret_clk, ret;
+
+ /* cci idle req stall */
+ writel(0x70007, &dram->grf->soc_con0);
+
+ /* enable all clk */
+ setbits_le32(&dram->pmu->pmu_noc_auto_ena, (0x3 << 7));
+
+ /* idle */
+ setbits_le32(&dram->pmu->pmu_bus_idle_req, (0x3 << 18));
+ while ((readl(&dram->pmu->pmu_bus_idle_st) & (0x3 << 18))
+ != (0x3 << 18))
+ ;
+
+ /* change freq */
+ writel((((0x3 << 4) | (1 << 2) | 1) << 16) |
+ (ctl << 4) | (1 << 2) | 1, &dram->cic->cic_ctrl0);
+ while (!(readl(&dram->cic->cic_status0) & (1 << 2)))
+ ;
+
+ ret_clk = clk_set_rate(&dram->ddr_clk, hz);
+ if (ret_clk < 0) {
+ printf("%s clk set failed %d\n", __func__, ret_clk);
+ return ret_clk;
+ }
+
+ writel(0x20002, &dram->cic->cic_ctrl0);
+ while (!(readl(&dram->cic->cic_status0) & (1 << 0)))
+ ;
+
+ /* deidle */
+ clrbits_le32(&dram->pmu->pmu_bus_idle_req, (0x3 << 18));
+ while (readl(&dram->pmu->pmu_bus_idle_st) & (0x3 << 18))
+ ;
+
+ /* clear enable all clk */
+ clrbits_le32(&dram->pmu->pmu_noc_auto_ena, (0x3 << 7));
+
+ /* lpddr4 ctl2 can not do training, all training will fail */
+ if (!(params->base.dramtype == LPDDR4 && ctl == 2)) {
+ for (channel = 0; channel < 2; channel++) {
+ if (!(params->ch[channel].cap_info.col))
+ continue;
+ ret = data_training(dram, channel, params,
+ PI_FULL_TRAINING);
+ if (ret)
+ printf("%s: channel %d training failed!\n",
+ __func__, channel);
+ else
+ debug("%s: channel %d training pass\n",
+ __func__, channel);
+ }
+ }
+
+ return 0;
+}
+
+static int lpddr4_set_rate(struct dram_info *dram,
+ struct rk3399_sdram_params *params)
+{
+ u32 ctl;
+ u32 phy;
+
+ for (ctl = 0; ctl < 2; ctl++) {
+ phy = lpddr4_get_phy(params, ctl);
+
+ lpddr4_set_phy(dram, params, phy, &lpddr4_timings[ctl]);
+ lpddr4_set_ctl(dram, params, ctl,
+ lpddr4_timings[ctl].base.ddr_freq);
+
+ debug("%s: change freq to %d mhz %d, %d\n", __func__,
+ lpddr4_timings[ctl].base.ddr_freq / MHz, ctl, phy);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_RAM_RK3399_LPDDR4 */
+
+static unsigned char calculate_stride(struct rk3399_sdram_params *params)
+{
+ unsigned int stride = params->base.stride;
+ unsigned int channel, chinfo = 0;
+ unsigned int ch_cap[2] = {0, 0};
+ u64 cap;
+
+ for (channel = 0; channel < 2; channel++) {
+ unsigned int cs0_cap = 0;
+ unsigned int cs1_cap = 0;
+ struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
+
+ if (cap_info->col == 0)
+ continue;
+
+ cs0_cap = (1 << (cap_info->cs0_row + cap_info->col +
+ cap_info->bk + cap_info->bw - 20));
+ if (cap_info->rank > 1)
+ cs1_cap = cs0_cap >> (cap_info->cs0_row
+ - cap_info->cs1_row);
+ if (cap_info->row_3_4) {
+ cs0_cap = cs0_cap * 3 / 4;
+ cs1_cap = cs1_cap * 3 / 4;
+ }
+ ch_cap[channel] = cs0_cap + cs1_cap;
+ chinfo |= 1 << channel;
+ }
+
+ /* stride calculation for 1 channel */
+ if (params->base.num_channels == 1 && chinfo & 1)
+ return 0x17; /* channel a */
+
+ /* stride calculation for 2 channels, default gstride type is 256B */
+ if (ch_cap[0] == ch_cap[1]) {
+ cap = ch_cap[0] + ch_cap[1];
+ switch (cap) {
+ /* 512MB */
+ case 512:
+ stride = 0;
+ break;
+ /* 1GB */
+ case 1024:
+ stride = 0x5;
+ break;
+ /*
+ * 768MB + 768MB same as total 2GB memory
+ * useful space: 0-768MB 1GB-1792MB
+ */
+ case 1536:
+ /* 2GB */
+ case 2048:
+ stride = 0x9;
+ break;
+ /* 1536MB + 1536MB */
+ case 3072:
+ stride = 0x11;
+ break;
+ /* 4GB */
+ case 4096:
+ stride = 0xD;
+ break;
+ default:
+ printf("%s: Unable to calculate stride for ", __func__);
+ print_size((cap * (1 << 20)), " capacity\n");
+ break;
+ }
+ }
+
+ sdram_print_stride(stride);
+
+ return stride;
+}
+
+static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel)
+{
+ params->ch[channel].cap_info.rank = 0;
+ params->ch[channel].cap_info.col = 0;
+ params->ch[channel].cap_info.bk = 0;
+ params->ch[channel].cap_info.bw = 32;
+ params->ch[channel].cap_info.dbw = 32;
+ params->ch[channel].cap_info.row_3_4 = 0;
+ params->ch[channel].cap_info.cs0_row = 0;
+ params->ch[channel].cap_info.cs1_row = 0;
+ params->ch[channel].cap_info.ddrconfig = 0;
+}
+
+static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params)
{
- unsigned char dramtype = sdram_params->base.dramtype;
- unsigned int ddr_freq = sdram_params->base.ddr_freq;
int channel;
+ int ret;
+
+ for (channel = 0; channel < 2; channel++) {
+ const struct chan_info *chan = &dram->chan[channel];
+ struct rk3399_cru *cru = dram->cru;
+ struct rk3399_ddr_publ_regs *publ = chan->publ;
+
+ phy_pctrl_reset(cru, channel);
+ phy_dll_bypass_set(publ, params->base.ddr_freq);
+
+ ret = pctl_cfg(dram, chan, channel, params);
+ if (ret < 0) {
+ printf("%s: pctl config failed\n", __func__);
+ return ret;
+ }
+
+ /* start to trigger initialization */
+ pctl_start(dram, channel);
+ }
+
+ return 0;
+}
+
+static int sdram_init(struct dram_info *dram,
+ struct rk3399_sdram_params *params)
+{
+ unsigned char dramtype = params->base.dramtype;
+ unsigned int ddr_freq = params->base.ddr_freq;
+ int channel, ch, rank;
+ int ret;
debug("Starting SDRAM initialization...\n");
@@ -1052,35 +2534,78 @@ static int sdram_init(struct dram_info *dram,
return -E2BIG;
}
+ for (ch = 0; ch < 2; ch++) {
+ params->ch[ch].cap_info.rank = 2;
+ for (rank = 2; rank != 0; rank--) {
+ ret = pctl_init(dram, params);
+ if (ret < 0) {
+ printf("%s: pctl init failed\n", __func__);
+ return ret;
+ }
+
+ /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
+ if (dramtype == LPDDR3)
+ udelay(10);
+
+ params->ch[ch].cap_info.rank = rank;
+
+ ret = dram->ops->data_training(dram, ch, rank, params);
+ if (!ret) {
+ debug("%s: data trained for rank %d, ch %d\n",
+ __func__, rank, ch);
+ break;
+ }
+ }
+ /* Computed rank with associated channel number */
+ params->ch[ch].cap_info.rank = rank;
+ }
+
+ params->base.num_channels = 0;
for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
- struct rk3399_ddr_publ_regs *publ = chan->publ;
-
- phy_dll_bypass_set(publ, ddr_freq);
+ struct sdram_cap_info *cap_info = &params->ch[channel].cap_info;
+ u8 training_flag = PI_FULL_TRAINING;
- if (channel >= sdram_params->base.num_channels)
+ if (cap_info->rank == 0) {
+ clear_channel_params(params, channel);
continue;
-
- if (pctl_cfg(chan, channel, sdram_params) != 0) {
- printf("pctl_cfg fail, reset\n");
- return -EIO;
+ } else {
+ params->base.num_channels++;
}
- /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
- if (dramtype == LPDDR3)
- udelay(10);
+ debug("Channel ");
+ debug(channel ? "1: " : "0: ");
- if (data_training(chan, channel,
- sdram_params, PI_FULL_TRAINING)) {
- printf("SDRAM initialization failed, reset\n");
- return -EIO;
+ /* LPDDR3 should have write and read gate training */
+ if (params->base.dramtype == LPDDR3)
+ training_flag = PI_WRITE_LEVELING |
+ PI_READ_GATE_TRAINING;
+
+ if (params->base.dramtype != LPDDR4) {
+ ret = data_training(dram, channel, params,
+ training_flag);
+ if (!ret) {
+ debug("%s: data train failed for channel %d\n",
+ __func__, ret);
+ continue;
+ }
}
- set_ddrconfig(chan, sdram_params, channel,
- sdram_params->ch[channel].ddrconfig);
+ sdram_print_ddr_info(cap_info, &params->base);
+
+ set_ddrconfig(chan, params, channel, cap_info->ddrconfig);
}
- dram_all_config(dram, sdram_params);
- switch_to_phy_index1(dram, sdram_params);
+
+ if (params->base.num_channels == 0) {
+ printf("%s: ", __func__);
+ sdram_print_dram_type(params->base.dramtype);
+ printf(" - %dMHz failed!\n", params->base.ddr_freq);
+ return -EINVAL;
+ }
+
+ params->base.stride = calculate_stride(params);
+ dram_all_config(dram, params);
+ dram->ops->set_rate(dram, params);
debug("Finish SDRAM initialization...\n");
return 0;
@@ -1116,8 +2641,8 @@ static int conv_of_platdata(struct udevice *dev)
int ret;
ret = regmap_init_mem_platdata(dev, dtplat->reg,
- ARRAY_SIZE(dtplat->reg) / 2,
- &plat->map);
+ ARRAY_SIZE(dtplat->reg) / 2,
+ &plat->map);
if (ret)
return ret;
@@ -1125,6 +2650,16 @@ static int conv_of_platdata(struct udevice *dev)
}
#endif
+static const struct sdram_rk3399_ops rk3399_ops = {
+#if !defined(CONFIG_RAM_RK3399_LPDDR4)
+ .data_training = default_data_training,
+ .set_rate = switch_to_phy_index1,
+#else
+ .data_training = lpddr4_mr_detect,
+ .set_rate = lpddr4_set_rate,
+#endif
+};
+
static int rk3399_dmc_init(struct udevice *dev)
{
struct dram_info *priv = dev_get_priv(dev);
@@ -1142,7 +2677,10 @@ static int rk3399_dmc_init(struct udevice *dev)
return ret;
#endif
+ priv->ops = &rk3399_ops;
priv->cic = syscon_get_first_range(ROCKCHIP_SYSCON_CIC);
+ priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
priv->pmusgrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUSGRF);
priv->pmucru = rockchip_get_pmucru();
@@ -1161,8 +2699,9 @@ static int rk3399_dmc_init(struct udevice *dev)
priv->chan[0].publ, priv->chan[0].msch,
priv->chan[1].pctl, priv->chan[1].pi,
priv->chan[1].publ, priv->chan[1].msch);
- debug("cru %p, cic %p, grf %p, sgrf %p, pmucru %p\n", priv->cru,
- priv->cic, priv->pmugrf, priv->pmusgrf, priv->pmucru);
+ debug("cru %p, cic %p, grf %p, sgrf %p, pmucru %p, pmu %p\n", priv->cru,
+ priv->cic, priv->pmugrf, priv->pmusgrf, priv->pmucru, priv->pmu);
+
#if CONFIG_IS_ENABLED(OF_PLATDATA)
ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->ddr_clk);
#else
@@ -1172,14 +2711,16 @@ static int rk3399_dmc_init(struct udevice *dev)
printf("%s clk get failed %d\n", __func__, ret);
return ret;
}
+
ret = clk_set_rate(&priv->ddr_clk, params->base.ddr_freq * MHz);
if (ret < 0) {
printf("%s clk set failed %d\n", __func__, ret);
return ret;
}
+
ret = sdram_init(priv, params);
if (ret < 0) {
- printf("%s DRAM init failed%d\n", __func__, ret);
+ printf("%s DRAM init failed %d\n", __func__, ret);
return ret;
}
@@ -1197,10 +2738,10 @@ static int rk3399_dmc_probe(struct udevice *dev)
struct dram_info *priv = dev_get_priv(dev);
priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
- debug("%s: pmugrf=%p\n", __func__, priv->pmugrf);
+ debug("%s: pmugrf = %p\n", __func__, priv->pmugrf);
priv->info.base = CONFIG_SYS_SDRAM_BASE;
- priv->info.size = rockchip_sdram_size(
- (phys_addr_t)&priv->pmugrf->os_reg2);
+ priv->info.size =
+ rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg2);
#endif
return 0;
}
@@ -1218,7 +2759,6 @@ static struct ram_ops rk3399_dmc_ops = {
.get_info = rk3399_dmc_get_info,
};
-
static const struct udevice_id rk3399_dmc_ids[] = {
{ .compatible = "rockchip,rk3399-dmc" },
{ }
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 9eb532bc7a7..f54a245424a 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -22,15 +22,6 @@ config K3_SYSTEM_CONTROLLER
help
Say 'y' here to add support for TI' K3 System Controller.
-config REMOTEPROC_K3
- bool "Support for TI's K3 based remoteproc driver"
- select REMOTEPROC
- depends on DM
- depends on ARCH_K3
- depends on OF_CONTROL
- help
- Say 'y' here to add support for TI' K3 remoteproc driver.
-
config REMOTEPROC_SANDBOX
bool "Support for Test processor for Sandbox"
select REMOTEPROC
@@ -40,6 +31,27 @@ config REMOTEPROC_SANDBOX
Say 'y' here to add support for test processor which does dummy
operations for sandbox platform.
+config REMOTEPROC_STM32_COPRO
+ bool "Support for STM32 coprocessor"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_STM32MP
+ depends on OF_CONTROL
+ help
+ Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
+ remoteproc framework.
+
+config REMOTEPROC_TI_K3_ARM64
+ bool "Support for TI's K3 based ARM64 remoteproc driver"
+ select REMOTEPROC
+ depends on DM
+ depends on ARCH_K3
+ depends on OF_CONTROL
+ help
+ Say y here to support TI's ARM64 processor subsystems
+ on various TI K3 family of SoCs through the remote processor
+ framework.
+
config REMOTEPROC_TI_POWER
bool "Support for TI Power processor"
select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 77eb7085235..271ba55b093 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -4,10 +4,11 @@
# Texas Instruments Incorporated - http://www.ti.com/
#
-obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o
+obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
-obj-$(CONFIG_REMOTEPROC_K3) += k3_rproc.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
+obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
+obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
new file mode 100644
index 00000000000..67937a75957
--- /dev/null
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <dm.h>
+#include <elf.h>
+#include <remoteproc.h>
+
+/* Basic function to verify ELF32 image format */
+int rproc_elf32_sanity_check(ulong addr, ulong size)
+{
+ Elf32_Ehdr *ehdr;
+ char class;
+
+ if (!addr) {
+ pr_debug("Invalid fw address?\n");
+ return -EFAULT;
+ }
+
+ if (size < sizeof(Elf32_Ehdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ ehdr = (Elf32_Ehdr *)addr;
+ class = ehdr->e_ident[EI_CLASS];
+
+ if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
+ pr_debug("Not an executable ELF32 image\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ /* We assume the firmware has the same endianness as the host */
+# ifdef __LITTLE_ENDIAN
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+ pr_debug("Unsupported firmware endianness\n");
+ return -EILSEQ;
+ }
+
+ if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
+ pr_debug("Image is too small\n");
+ return -ENOSPC;
+ }
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ pr_debug("Image is corrupted (bad magic)\n");
+ return -EBADF;
+ }
+
+ if (ehdr->e_phnum == 0) {
+ pr_debug("No loadable segments\n");
+ return -ENOEXEC;
+ }
+
+ if (ehdr->e_phoff > size) {
+ pr_debug("Firmware size is too small\n");
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/* A very simple elf loader, assumes the image is valid */
+int rproc_elf32_load_image(struct udevice *dev, unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+ Elf32_Phdr *phdr; /* Program header structure pointer */
+ const struct dm_rproc_ops *ops;
+ unsigned int i;
+
+ ehdr = (Elf32_Ehdr *)addr;
+ phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
+
+ ops = rproc_get_ops(dev);
+
+ /* Load each program header */
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ void *dst = (void *)(uintptr_t)phdr->p_paddr;
+ void *src = (void *)addr + phdr->p_offset;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (ops->device_to_virt)
+ dst = ops->device_to_virt(dev, (ulong)dst);
+
+ dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
+ i, dst, phdr->p_filesz);
+ if (phdr->p_filesz)
+ memcpy(dst, src, phdr->p_filesz);
+ if (phdr->p_filesz != phdr->p_memsz)
+ memset(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
+ roundup((unsigned long)dst + phdr->p_filesz,
+ ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ ++phdr;
+ }
+
+ return 0;
+}
diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c
index 51a67e6bf1a..5f35119ab71 100644
--- a/drivers/remoteproc/sandbox_testproc.c
+++ b/drivers/remoteproc/sandbox_testproc.c
@@ -8,6 +8,7 @@
#include <dm.h>
#include <errno.h>
#include <remoteproc.h>
+#include <asm/io.h>
/**
* enum sandbox_state - different device states
@@ -300,6 +301,23 @@ static int sandbox_testproc_ping(struct udevice *dev)
return ret;
}
+#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000
+/**
+ * sandbox_testproc_device_to_virt() - Convert device address to virtual address
+ * @dev: device to operate upon
+ * @da: device address
+ * @return converted virtual address
+ */
+static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da)
+{
+ u64 paddr;
+
+ /* Use a simple offset conversion */
+ paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
+
+ return phys_to_virt(paddr);
+}
+
static const struct dm_rproc_ops sandbox_testproc_ops = {
.init = sandbox_testproc_init,
.reset = sandbox_testproc_reset,
@@ -308,6 +326,7 @@ static const struct dm_rproc_ops sandbox_testproc_ops = {
.stop = sandbox_testproc_stop,
.is_running = sandbox_testproc_is_running,
.ping = sandbox_testproc_ping,
+ .device_to_virt = sandbox_testproc_device_to_virt,
};
static const struct udevice_id sandbox_ids[] = {
diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c
new file mode 100644
index 00000000000..de3b9729f39
--- /dev/null
+++ b/drivers/remoteproc/stm32_copro.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/io.h>
+
+#define RCC_GCR_HOLD_BOOT 0
+#define RCC_GCR_RELEASE_BOOT 1
+
+/**
+ * struct stm32_copro_privdata - power processor private data
+ * @reset_ctl: reset controller handle
+ * @hold_boot_regmap: regmap for remote processor reset hold boot
+ * @hold_boot_offset: offset of the register controlling the hold boot setting
+ * @hold_boot_mask: bitmask of the register for the hold boot field
+ * @is_running: is the remote processor running
+ */
+struct stm32_copro_privdata {
+ struct reset_ctl reset_ctl;
+ struct regmap *hold_boot_regmap;
+ uint hold_boot_offset;
+ uint hold_boot_mask;
+ bool is_running;
+};
+
+/**
+ * stm32_copro_probe() - Basic probe
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_probe(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ struct regmap *regmap;
+ const fdt32_t *cell;
+ int len, ret;
+
+ priv = dev_get_priv(dev);
+
+ regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-holdboot");
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "unable to find holdboot regmap (%ld)\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ cell = dev_read_prop(dev, "st,syscfg-holdboot", &len);
+ if (len < 3 * sizeof(fdt32_t)) {
+ dev_err(dev, "holdboot offset and mask not available\n");
+ return -EINVAL;
+ }
+
+ priv->hold_boot_regmap = regmap;
+ priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1);
+ priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1);
+
+ ret = reset_get_by_index(dev, 0, &priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "failed to get reset (%d)\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "probed\n");
+
+ return 0;
+}
+
+/**
+ * stm32_copro_set_hold_boot() - Hold boot bit management
+ * @dev: corresponding STM32 remote processor device
+ * @hold: hold boot value
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold)
+{
+ struct stm32_copro_privdata *priv;
+ uint val;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT;
+
+ /*
+ * Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured.
+ * To be updated when the code for this SMC service is available which
+ * is not the case for the time being.
+ */
+ ret = regmap_update_bits(priv->hold_boot_regmap, priv->hold_boot_offset,
+ priv->hold_boot_mask, val);
+ if (ret)
+ dev_err(dev, "failed to set hold boot\n");
+
+ return ret;
+}
+
+/**
+ * stm32_copro_device_to_virt() - Convert device address to virtual address
+ * @dev: corresponding STM32 remote processor device
+ * @da: device address
+ * @return converted virtual address
+ */
+static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da)
+{
+ fdt32_t in_addr = cpu_to_be32(da);
+ u64 paddr;
+
+ paddr = dev_translate_dma_address(dev, &in_addr);
+ if (paddr == OF_BAD_ADDR) {
+ dev_err(dev, "Unable to convert address %ld\n", da);
+ return NULL;
+ }
+
+ return phys_to_virt(paddr);
+}
+
+/**
+ * stm32_copro_load() - Loadup the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @addr: Address in memory where image is stored
+ * @size: Size in bytes of the image
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = stm32_copro_set_hold_boot(dev, true);
+ if (ret)
+ return ret;
+
+ ret = reset_assert(&priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
+ return ret;
+ }
+
+ /* Support only ELF32 image */
+ ret = rproc_elf32_sanity_check(addr, size);
+ if (ret) {
+ dev_err(dev, "Invalid ELF32 image (%d)\n", ret);
+ return ret;
+ }
+
+ return rproc_elf32_load_image(dev, addr);
+}
+
+/**
+ * stm32_copro_start() - Start the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_start(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ /* move hold boot from true to false start the copro */
+ ret = stm32_copro_set_hold_boot(dev, false);
+ if (ret)
+ return ret;
+
+ /*
+ * Once copro running, reset hold boot flag to avoid copro
+ * rebooting autonomously
+ */
+ ret = stm32_copro_set_hold_boot(dev, true);
+ priv->is_running = !ret;
+ return ret;
+}
+
+/**
+ * stm32_copro_reset() - Reset the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_reset(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+ int ret;
+
+ priv = dev_get_priv(dev);
+
+ ret = stm32_copro_set_hold_boot(dev, true);
+ if (ret)
+ return ret;
+
+ ret = reset_assert(&priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
+ return ret;
+ }
+
+ priv->is_running = false;
+
+ return 0;
+}
+
+/**
+ * stm32_copro_stop() - Stop the STM32 remote processor
+ * @dev: corresponding STM32 remote processor device
+ * @return 0 if all went ok, else corresponding -ve error
+ */
+static int stm32_copro_stop(struct udevice *dev)
+{
+ return stm32_copro_reset(dev);
+}
+
+/**
+ * stm32_copro_is_running() - Is the STM32 remote processor running
+ * @dev: corresponding STM32 remote processor device
+ * @return 1 if the remote processor is running, 0 otherwise
+ */
+static int stm32_copro_is_running(struct udevice *dev)
+{
+ struct stm32_copro_privdata *priv;
+
+ priv = dev_get_priv(dev);
+ return priv->is_running;
+}
+
+static const struct dm_rproc_ops stm32_copro_ops = {
+ .load = stm32_copro_load,
+ .start = stm32_copro_start,
+ .stop = stm32_copro_stop,
+ .reset = stm32_copro_reset,
+ .is_running = stm32_copro_is_running,
+ .device_to_virt = stm32_copro_device_to_virt,
+};
+
+static const struct udevice_id stm32_copro_ids[] = {
+ {.compatible = "st,stm32mp1-rproc"},
+ {}
+};
+
+U_BOOT_DRIVER(stm32_copro) = {
+ .name = "stm32_m4_proc",
+ .of_match = stm32_copro_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &stm32_copro_ops,
+ .probe = stm32_copro_probe,
+ .priv_auto_alloc_size = sizeof(struct stm32_copro_privdata),
+};
diff --git a/drivers/remoteproc/k3_rproc.c b/drivers/remoteproc/ti_k3_arm64_rproc.c
index 3c29d925ce0..9676a96f988 100644
--- a/drivers/remoteproc/k3_rproc.c
+++ b/drivers/remoteproc/ti_k3_arm64_rproc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Texas Instruments' K3 Remoteproc driver
+ * Texas Instruments' K3 ARM64 Remoteproc driver
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
@@ -16,6 +16,7 @@
#include <asm/io.h>
#include <power-domain.h>
#include <linux/soc/ti/ti_sci_protocol.h>
+#include "ti_sci_proc.h"
#define INVALID_ID 0xffff
@@ -23,68 +24,53 @@
#define GTC_CNTR_EN 0x3
/**
- * struct k3_rproc_privdata - Structure representing Remote processor data.
+ * struct k3_arm64_privdata - Structure representing Remote processor data.
* @rproc_pwrdmn: rproc power domain data
* @rproc_rst: rproc reset control data
* @sci: Pointer to TISCI handle
+ * @tsp: TISCI processor control helper structure
* @gtc_base: Timer base address.
- * @proc_id: TISCI processor ID
- * @host_id: TISCI host id to which the processor gets assigned to.
*/
-struct k3_rproc_privdata {
+struct k3_arm64_privdata {
struct power_domain rproc_pwrdmn;
struct power_domain gtc_pwrdmn;
struct reset_ctl rproc_rst;
- const struct ti_sci_handle *sci;
+ struct ti_sci_proc tsp;
void *gtc_base;
- u16 proc_id;
- u16 host_id;
};
/**
- * k3_rproc_load() - Load up the Remote processor image
+ * k3_arm64_load() - Load up the Remote processor image
* @dev: rproc device pointer
* @addr: Address at which image is available
* @size: size of the image
*
* Return: 0 if all goes good, else appropriate error message.
*/
-static int k3_rproc_load(struct udevice *dev, ulong addr, ulong size)
+static int k3_arm64_load(struct udevice *dev, ulong addr, ulong size)
{
- struct k3_rproc_privdata *rproc = dev_get_priv(dev);
- const struct ti_sci_proc_ops *pops = &rproc->sci->ops.proc_ops;
+ struct k3_arm64_privdata *rproc = dev_get_priv(dev);
int ret;
dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
/* request for the processor */
- ret = pops->proc_request(rproc->sci, rproc->proc_id);
- if (ret) {
- dev_err(dev, "Requesting processor failed %d\n", ret);
+ ret = ti_sci_proc_request(&rproc->tsp);
+ if (ret)
return ret;
- }
-
- ret = pops->set_proc_boot_cfg(rproc->sci, rproc->proc_id, addr, 0, 0);
- if (ret) {
- dev_err(dev, "set_proc_boot_cfg failed %d\n", ret);
- return ret;
- }
-
- dev_dbg(dev, "%s: rproc successfully loaded\n", __func__);
- return 0;
+ return ti_sci_proc_set_config(&rproc->tsp, addr, 0, 0);
}
/**
- * k3_rproc_start() - Start the remote processor
+ * k3_arm64_start() - Start the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
-static int k3_rproc_start(struct udevice *dev)
+static int k3_arm64_start(struct udevice *dev)
{
- struct k3_rproc_privdata *rproc = dev_get_priv(dev);
- const struct ti_sci_proc_ops *pops = &rproc->sci->ops.proc_ops;
+ struct k3_arm64_privdata *rproc = dev_get_priv(dev);
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -109,33 +95,16 @@ static int k3_rproc_start(struct udevice *dev)
return ret;
}
- if (rproc->host_id != INVALID_ID) {
- ret = pops->proc_handover(rproc->sci, rproc->proc_id,
- rproc->host_id);
- if (ret) {
- dev_err(dev, "Handover processor failed %d\n", ret);
- return ret;
- }
- } else {
- ret = pops->proc_release(rproc->sci, rproc->proc_id);
- if (ret) {
- dev_err(dev, "Processor release failed %d\n", ret);
- return ret;
- }
- }
-
- dev_dbg(dev, "%s: rproc successfully started\n", __func__);
-
- return 0;
+ return ti_sci_proc_release(&rproc->tsp);
}
/**
- * k3_rproc_init() - Initialize the remote processor
+ * k3_arm64_init() - Initialize the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
-static int k3_rproc_init(struct udevice *dev)
+static int k3_arm64_init(struct udevice *dev)
{
dev_dbg(dev, "%s\n", __func__);
@@ -145,12 +114,33 @@ static int k3_rproc_init(struct udevice *dev)
return 0;
}
-static const struct dm_rproc_ops k3_rproc_ops = {
- .init = k3_rproc_init,
- .load = k3_rproc_load,
- .start = k3_rproc_start,
+static const struct dm_rproc_ops k3_arm64_ops = {
+ .init = k3_arm64_init,
+ .load = k3_arm64_load,
+ .start = k3_arm64_start,
};
+static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
+{
+ dev_dbg(dev, "%s\n", __func__);
+
+ tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(tsp->sci)) {
+ dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
+ return PTR_ERR(tsp->sci);
+ }
+
+ tsp->proc_id = dev_read_u32_default(dev, "ti,sci-proc-id", INVALID_ID);
+ if (tsp->proc_id == INVALID_ID) {
+ dev_err(dev, "proc id not populated\n");
+ return -ENOENT;
+ }
+ tsp->host_id = dev_read_u32_default(dev, "ti,sci-host-id", INVALID_ID);
+ tsp->ops = &tsp->sci->ops.proc_ops;
+
+ return 0;
+}
+
/**
* k3_of_to_priv() - generate private data from device tree
* @dev: corresponding k3 remote processor device
@@ -158,8 +148,8 @@ static const struct dm_rproc_ops k3_rproc_ops = {
*
* Return: 0 if all goes good, else appropriate error message.
*/
-static int k3_rproc_of_to_priv(struct udevice *dev,
- struct k3_rproc_privdata *rproc)
+static int k3_arm64_of_to_priv(struct udevice *dev,
+ struct k3_arm64_privdata *rproc)
{
int ret;
@@ -183,11 +173,9 @@ static int k3_rproc_of_to_priv(struct udevice *dev,
return ret;
}
- rproc->sci = ti_sci_get_by_phandle(dev, "ti,sci");
- if (IS_ERR(rproc->sci)) {
- dev_err(dev, "ti_sci get failed: %d\n", ret);
- return PTR_ERR(rproc->sci);
- }
+ ret = ti_sci_proc_of_to_priv(dev, &rproc->tsp);
+ if (ret)
+ return ret;
rproc->gtc_base = dev_read_addr_ptr(dev);
if (!rproc->gtc_base) {
@@ -195,30 +183,25 @@ static int k3_rproc_of_to_priv(struct udevice *dev,
return -ENODEV;
}
- rproc->proc_id = dev_read_u32_default(dev, "ti,sci-proc-id",
- INVALID_ID);
- rproc->host_id = dev_read_u32_default(dev, "ti,sci-host-id",
- INVALID_ID);
-
return 0;
}
/**
- * k3_rproc_probe() - Basic probe
+ * k3_arm64_probe() - Basic probe
* @dev: corresponding k3 remote processor device
*
* Return: 0 if all goes good, else appropriate error message.
*/
-static int k3_rproc_probe(struct udevice *dev)
+static int k3_arm64_probe(struct udevice *dev)
{
- struct k3_rproc_privdata *priv;
+ struct k3_arm64_privdata *priv;
int ret;
dev_dbg(dev, "%s\n", __func__);
priv = dev_get_priv(dev);
- ret = k3_rproc_of_to_priv(dev, priv);
+ ret = k3_arm64_of_to_priv(dev, priv);
if (ret) {
dev_dbg(dev, "%s: Probe failed with error %d\n", __func__, ret);
return ret;
@@ -229,16 +212,17 @@ static int k3_rproc_probe(struct udevice *dev)
return 0;
}
-static const struct udevice_id k3_rproc_ids[] = {
+static const struct udevice_id k3_arm64_ids[] = {
+ { .compatible = "ti,am654-arm64"},
{ .compatible = "ti,am654-rproc"},
{}
};
-U_BOOT_DRIVER(k3_rproc) = {
- .name = "k3_rproc",
- .of_match = k3_rproc_ids,
+U_BOOT_DRIVER(k3_arm64) = {
+ .name = "k3_arm64",
+ .of_match = k3_arm64_ids,
.id = UCLASS_REMOTEPROC,
- .ops = &k3_rproc_ops,
- .probe = k3_rproc_probe,
- .priv_auto_alloc_size = sizeof(struct k3_rproc_privdata),
+ .ops = &k3_arm64_ops,
+ .probe = k3_arm64_probe,
+ .priv_auto_alloc_size = sizeof(struct k3_arm64_privdata),
};
diff --git a/drivers/remoteproc/ti_sci_proc.h b/drivers/remoteproc/ti_sci_proc.h
new file mode 100644
index 00000000000..ccfc39ec887
--- /dev/null
+++ b/drivers/remoteproc/ti_sci_proc.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Texas Instruments TI-SCI Processor Controller Helper Functions
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ */
+
+#ifndef REMOTEPROC_TI_SCI_PROC_H
+#define REMOTEPROC_TI_SCI_PROC_H
+
+#define TISCI_INVALID_HOST 0xff
+
+/**
+ * struct ti_sci_proc - structure representing a processor control client
+ * @sci: cached TI-SCI protocol handle
+ * @ops: cached TI-SCI proc ops
+ * @proc_id: processor id for the consumer remoteproc device
+ * @host_id: host id to pass the control over for this consumer remoteproc
+ * device
+ */
+struct ti_sci_proc {
+ const struct ti_sci_handle *sci;
+ const struct ti_sci_proc_ops *ops;
+ u8 proc_id;
+ u8 host_id;
+};
+
+static inline int ti_sci_proc_request(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
+
+ ret = tsp->ops->proc_request(tsp->sci, tsp->proc_id);
+ if (ret)
+ pr_err("ti-sci processor request failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_release(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
+
+ if (tsp->host_id != TISCI_INVALID_HOST)
+ ret = tsp->ops->proc_handover(tsp->sci, tsp->proc_id,
+ tsp->host_id);
+ else
+ ret = tsp->ops->proc_release(tsp->sci, tsp->proc_id);
+
+ if (ret)
+ pr_err("ti-sci processor release failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_handover(struct ti_sci_proc *tsp)
+{
+ int ret;
+
+ debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
+
+ ret = tsp->ops->proc_handover(tsp->sci, tsp->proc_id, tsp->host_id);
+ if (ret)
+ pr_err("ti-sci processor handover of %d to %d failed: %d\n",
+ tsp->proc_id, tsp->host_id, ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_get_status(struct ti_sci_proc *tsp,
+ u64 *boot_vector, u32 *cfg_flags,
+ u32 *ctrl_flags, u32 *status_flags)
+{
+ int ret;
+
+ ret = tsp->ops->get_proc_boot_status(tsp->sci, tsp->proc_id,
+ boot_vector, cfg_flags, ctrl_flags,
+ status_flags);
+ if (ret)
+ pr_err("ti-sci processor get_status failed: %d\n", ret);
+
+ debug("%s: proc_id = %d, boot_vector = 0x%llx, cfg_flags = 0x%x, ctrl_flags = 0x%x, sts = 0x%x\n",
+ __func__, tsp->proc_id, *boot_vector, *cfg_flags, *ctrl_flags,
+ *status_flags);
+ return ret;
+}
+
+static inline int ti_sci_proc_set_config(struct ti_sci_proc *tsp,
+ u64 boot_vector,
+ u32 cfg_set, u32 cfg_clr)
+{
+ int ret;
+
+ debug("%s: proc_id = %d, boot_vector = 0x%llx, cfg_set = 0x%x, cfg_clr = 0x%x\n",
+ __func__, tsp->proc_id, boot_vector, cfg_set, cfg_clr);
+
+ ret = tsp->ops->set_proc_boot_cfg(tsp->sci, tsp->proc_id, boot_vector,
+ cfg_set, cfg_clr);
+ if (ret)
+ pr_err("ti-sci processor set_config failed: %d\n", ret);
+ return ret;
+}
+
+static inline int ti_sci_proc_set_control(struct ti_sci_proc *tsp,
+ u32 ctrl_set, u32 ctrl_clr)
+{
+ int ret;
+
+ debug("%s: proc_id = %d, ctrl_set = 0x%x, ctrl_clr = 0x%x\n", __func__,
+ tsp->proc_id, ctrl_set, ctrl_clr);
+
+ ret = tsp->ops->set_proc_boot_ctrl(tsp->sci, tsp->proc_id, ctrl_set,
+ ctrl_clr);
+ if (ret)
+ pr_err("ti-sci processor set_control failed: %d\n", ret);
+ return ret;
+}
+
+#endif /* REMOTEPROC_TI_SCI_PROC_H */
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 532e94d337b..0b58a18f5fc 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -120,4 +120,10 @@ config RTC_M41T62
Enable driver for ST's M41T62 compatible RTC devices (like RV-4162).
It is a serial (I2C) real-time clock (RTC) with alarm.
+config RTC_STM32
+ bool "Enable STM32 RTC driver"
+ depends on DM_RTC
+ help
+ Enable STM32 RTC driver. This driver supports the rtc that is present
+ on some STM32 SoCs.
endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 915adb87fe2..f97a6699820 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_RTC_RX8025) += rx8025.o
obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o
obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
obj-$(CONFIG_RTC_S35392A) += s35392a.o
+obj-$(CONFIG_RTC_STM32) += stm32_rtc.o
obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
obj-$(CONFIG_RTC_X1205) += x1205.o
diff --git a/drivers/rtc/stm32_rtc.c b/drivers/rtc/stm32_rtc.c
new file mode 100644
index 00000000000..abd339076ad
--- /dev/null
+++ b/drivers/rtc/stm32_rtc.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+
+#define STM32_RTC_TR 0x00
+#define STM32_RTC_DR 0x04
+#define STM32_RTC_ISR 0x0C
+#define STM32_RTC_PRER 0x10
+#define STM32_RTC_CR 0x18
+#define STM32_RTC_WPR 0x24
+
+/* STM32_RTC_TR bit fields */
+#define STM32_RTC_SEC_SHIFT 0
+#define STM32_RTC_SEC GENMASK(6, 0)
+#define STM32_RTC_MIN_SHIFT 8
+#define STM32_RTC_MIN GENMASK(14, 8)
+#define STM32_RTC_HOUR_SHIFT 16
+#define STM32_RTC_HOUR GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DATE_SHIFT 0
+#define STM32_RTC_DATE GENMASK(5, 0)
+#define STM32_RTC_MONTH_SHIFT 8
+#define STM32_RTC_MONTH GENMASK(12, 8)
+#define STM32_RTC_WDAY_SHIFT 13
+#define STM32_RTC_WDAY GENMASK(15, 13)
+#define STM32_RTC_YEAR_SHIFT 16
+#define STM32_RTC_YEAR GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT BIT(6)
+
+/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
+#define STM32_RTC_ISR_INITS BIT(4)
+#define STM32_RTC_ISR_RSF BIT(5)
+#define STM32_RTC_ISR_INITF BIT(6)
+#define STM32_RTC_ISR_INIT BIT(7)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT 0
+#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT 16
+#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY 0xCA
+#define RTC_WPR_2ND_KEY 0x53
+#define RTC_WPR_WRONG_KEY 0xFF
+
+struct stm32_rtc_priv {
+ fdt_addr_t base;
+};
+
+static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 tr, dr;
+
+ tr = readl(priv->base + STM32_RTC_TR);
+ dr = readl(priv->base + STM32_RTC_DR);
+
+ tm->tm_sec = bcd2bin((tr & STM32_RTC_SEC) >> STM32_RTC_SEC_SHIFT);
+ tm->tm_min = bcd2bin((tr & STM32_RTC_MIN) >> STM32_RTC_MIN_SHIFT);
+ tm->tm_hour = bcd2bin((tr & STM32_RTC_HOUR) >> STM32_RTC_HOUR_SHIFT);
+
+ tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT);
+ tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT);
+ tm->tm_year = bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT);
+ tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT);
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ dev_dbg(dev, "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static void stm32_rtc_unlock(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+
+ writel(RTC_WPR_1ST_KEY, priv->base + STM32_RTC_WPR);
+ writel(RTC_WPR_2ND_KEY, priv->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_lock(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+
+ writel(RTC_WPR_WRONG_KEY, priv->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ if (!(isr & STM32_RTC_ISR_INITF)) {
+ isr |= STM32_RTC_ISR_INIT;
+ writel(isr, priv->base + STM32_RTC_ISR);
+
+ return readl_poll_timeout(priv->base + STM32_RTC_ISR,
+ isr,
+ (isr & STM32_RTC_ISR_INITF),
+ 100000);
+ }
+
+ return 0;
+}
+
+static int stm32_rtc_wait_sync(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_RSF;
+ writel(isr, priv->base + STM32_RTC_ISR);
+
+ /*
+ * Wait for RSF to be set to ensure the calendar registers are
+ * synchronised, it takes around 2 rtc_ck clock cycles
+ */
+ return readl_poll_timeout(priv->base + STM32_RTC_ISR,
+ isr, (isr & STM32_RTC_ISR_RSF),
+ 100000);
+}
+
+static void stm32_rtc_exit_init_mode(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_INIT;
+ writel(isr, priv->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_set_time(struct udevice *dev, u32 time, u32 date)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ stm32_rtc_unlock(dev);
+
+ ret = stm32_rtc_enter_init_mode(dev);
+ if (ret)
+ goto lock;
+
+ writel(time, priv->base + STM32_RTC_TR);
+ writel(date, priv->base + STM32_RTC_DR);
+
+ stm32_rtc_exit_init_mode(dev);
+
+ ret = stm32_rtc_wait_sync(dev);
+
+lock:
+ stm32_rtc_lock(dev);
+ return ret;
+}
+
+static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u32 t, d;
+
+ dev_dbg(dev, "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Time in BCD format */
+ t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC;
+ t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN;
+ t |= (bin2bcd(tm->tm_hour) << STM32_RTC_HOUR_SHIFT) & STM32_RTC_HOUR;
+
+ /* Date in BCD format */
+ d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE;
+ d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH;
+ d |= (bin2bcd(tm->tm_year) << STM32_RTC_YEAR_SHIFT) & STM32_RTC_YEAR;
+ d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY;
+
+ return stm32_rtc_set_time(dev, t, d);
+}
+
+static int stm32_rtc_reset(struct udevice *dev)
+{
+ dev_dbg(dev, "Reset DATE\n");
+
+ return stm32_rtc_set_time(dev, 0, 0);
+}
+
+static int stm32_rtc_init(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+ unsigned int rate;
+ struct clk clk;
+ int ret;
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ if (isr & STM32_RTC_ISR_INITS)
+ return 0;
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ clk_free(&clk);
+ return ret;
+ }
+
+ rate = clk_get_rate(&clk);
+
+ /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+ pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+ pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+ for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
+ pred_s = (rate / (pred_a + 1)) - 1;
+
+ if (((pred_s + 1) * (pred_a + 1)) == rate)
+ break;
+ }
+
+ /*
+ * Can't find a 1Hz, so give priority to RTC power consumption
+ * by choosing the higher possible value for prediv_a
+ */
+ if (pred_s > pred_s_max || pred_a > pred_a_max) {
+ pred_a = pred_a_max;
+ pred_s = (rate / (pred_a + 1)) - 1;
+ }
+
+ stm32_rtc_unlock(dev);
+
+ ret = stm32_rtc_enter_init_mode(dev);
+ if (ret) {
+ dev_err(dev,
+ "Can't enter in init mode. Prescaler config failed.\n");
+ goto unlock;
+ }
+
+ prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+ prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+ writel(prer, priv->base + STM32_RTC_PRER);
+
+ /* Force 24h time format */
+ cr = readl(priv->base + STM32_RTC_CR);
+ cr &= ~STM32_RTC_CR_FMT;
+ writel(cr, priv->base + STM32_RTC_CR);
+
+ stm32_rtc_exit_init_mode(dev);
+
+ ret = stm32_rtc_wait_sync(dev);
+
+unlock:
+ stm32_rtc_lock(dev);
+
+ if (ret) {
+ clk_disable(&clk);
+ clk_free(&clk);
+ }
+
+ return ret;
+}
+
+static int stm32_rtc_probe(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ int ret;
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ clk_free(&clk);
+ return ret;
+ }
+
+ ret = stm32_rtc_init(dev);
+
+ if (ret) {
+ clk_disable(&clk);
+ clk_free(&clk);
+ }
+
+ return ret;
+}
+
+static const struct rtc_ops stm32_rtc_ops = {
+ .get = stm32_rtc_get,
+ .set = stm32_rtc_set,
+ .reset = stm32_rtc_reset,
+};
+
+static const struct udevice_id stm32_rtc_ids[] = {
+ { .compatible = "st,stm32mp1-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_stm32) = {
+ .name = "rtc-stm32",
+ .id = UCLASS_RTC,
+ .probe = stm32_rtc_probe,
+ .of_match = stm32_rtc_ids,
+ .ops = &stm32_rtc_ops,
+ .priv_auto_alloc_size = sizeof(struct stm32_rtc_priv),
+};
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index a435e68005f..42abb96a26f 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -342,6 +342,8 @@ static int mxc_serial_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id mxc_serial_ids[] = {
+ { .compatible = "fsl,imx21-uart" },
+ { .compatible = "fsl,imx53-uart" },
{ .compatible = "fsl,imx6sx-uart" },
{ .compatible = "fsl,imx6ul-uart" },
{ .compatible = "fsl,imx7d-uart" },
@@ -360,9 +362,7 @@ U_BOOT_DRIVER(serial_mxc) = {
#endif
.probe = mxc_serial_probe,
.ops = &mxc_serial_ops,
-#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
-#endif
};
#endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index cc174dd0363..f459c0a4113 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -158,13 +158,14 @@ config MT7621_SPI
the SPI NOR flash on platforms embedding this Ralink / MediaTek
SPI core, like MT7621/7628/7688.
-config MTK_QSPI
- bool "Mediatek QSPI driver"
- imply SPI_FLASH_BAR
+config MTK_SNFI_SPI
+ bool "Mediatek SPI memory controller driver"
+ depends on SPI_MEM
help
- Enable the Mediatek QSPI driver. This driver can be
- used to access the SPI NOR flash on platforms embedding this
- Mediatek QSPI IP core.
+ Enable the Mediatek SPI memory controller driver. This driver is
+ originally based on the MediaTek SNFI IP core. It can only be
+ used to access SPI memory devices like SPI-NOR or SPI-NAND on
+ platforms embedding this IP core, like MT7622/M7629.
config MVEBU_A3700_SPI
bool "Marvell Armada 3700 SPI driver"
@@ -232,6 +233,14 @@ config SANDBOX_SPI
};
};
+config SPI_SIFIVE
+ bool "SiFive SPI driver"
+ help
+ This driver supports the SiFive SPI IP. If unsure say N.
+ Enable the SiFive SPI controller driver.
+
+ The SiFive SPI controller driver is found on various SiFive SoCs.
+
config SPI_SUNXI
bool "Allwinner SoC SPI controllers"
help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index ab84122f083..ae4f2958f8a 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
-obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
+obj-$(CONFIG_MTK_SNFI_SPI) += mtk_snfi_spi.o
obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o
obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
@@ -50,6 +50,7 @@ obj-$(CONFIG_PL022_SPI) += pl022_spi.o
obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
+obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
obj-$(CONFIG_SPI_SUNXI) += spi-sunxi.o
obj-$(CONFIG_SH_SPI) += sh_spi.o
obj-$(CONFIG_SH_QSPI) += sh_qspi.o
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 1598c4f6989..41abe1996f2 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -10,6 +10,7 @@
#include <spi.h>
#include <asm/io.h>
#include <linux/sizes.h>
+#include <linux/iopoll.h>
#include <dm.h>
#include <errno.h>
#include <watchdog.h>
@@ -150,20 +151,13 @@ static void qspi_write32(u32 flags, u32 *addr, u32 val)
static inline int is_controller_busy(const struct fsl_qspi_priv *priv)
{
u32 val;
- const u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
- QSPI_SR_IP_ACC_MASK;
- unsigned int retry = 5;
+ u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
+ QSPI_SR_IP_ACC_MASK;
- do {
- val = qspi_read32(priv->flags, &priv->regs->sr);
+ if (priv->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG)
+ mask = (u32)cpu_to_be32(mask);
- if ((~val & mask) == mask)
- return 0;
-
- udelay(1);
- } while (--retry);
-
- return -ETIMEDOUT;
+ return readl_poll_timeout(&priv->regs->sr, val, !(val & mask), 1000);
}
/* QSPI support swapping the flash read/write data
diff --git a/drivers/spi/mtk_qspi.c b/drivers/spi/mtk_qspi.c
deleted file mode 100644
index b510733e92c..00000000000
--- a/drivers/spi/mtk_qspi.c
+++ /dev/null
@@ -1,359 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2018 MediaTek, Inc.
- * Author : Guochun.Mao@mediatek.com
- */
-
-#include <common.h>
-#include <dm.h>
-#include <malloc.h>
-#include <spi.h>
-#include <asm/io.h>
-#include <linux/iopoll.h>
-#include <linux/ioport.h>
-
-/* Register Offset */
-struct mtk_qspi_regs {
- u32 cmd;
- u32 cnt;
- u32 rdsr;
- u32 rdata;
- u32 radr[3];
- u32 wdata;
- u32 prgdata[6];
- u32 shreg[10];
- u32 cfg[2];
- u32 shreg10;
- u32 mode_mon;
- u32 status[4];
- u32 flash_time;
- u32 flash_cfg;
- u32 reserved_0[3];
- u32 sf_time;
- u32 pp_dw_data;
- u32 reserved_1;
- u32 delsel_0[2];
- u32 intrstus;
- u32 intren;
- u32 reserved_2;
- u32 cfg3;
- u32 reserved_3;
- u32 chksum;
- u32 aaicmd;
- u32 wrprot;
- u32 radr3;
- u32 dual;
- u32 delsel_1[3];
-};
-
-struct mtk_qspi_platdata {
- fdt_addr_t reg_base;
- fdt_addr_t mem_base;
-};
-
-struct mtk_qspi_priv {
- struct mtk_qspi_regs *regs;
- unsigned long *mem_base;
- u8 op;
- u8 tx[3]; /* only record max 3 bytes paras, when it's address. */
- u32 txlen; /* dout buffer length - op code length */
- u8 *rx;
- u32 rxlen;
-};
-
-#define MTK_QSPI_CMD_POLLINGREG_US 500000
-#define MTK_QSPI_WRBUF_SIZE 256
-#define MTK_QSPI_COMMAND_ENABLE 0x30
-
-/* NOR flash controller commands */
-#define MTK_QSPI_RD_TRIGGER BIT(0)
-#define MTK_QSPI_READSTATUS BIT(1)
-#define MTK_QSPI_PRG_CMD BIT(2)
-#define MTK_QSPI_WR_TRIGGER BIT(4)
-#define MTK_QSPI_WRITESTATUS BIT(5)
-#define MTK_QSPI_AUTOINC BIT(7)
-
-#define MTK_QSPI_MAX_RX_TX_SHIFT 0x6
-#define MTK_QSPI_MAX_SHIFT 0x8
-
-#define MTK_QSPI_WR_BUF_ENABLE 0x1
-#define MTK_QSPI_WR_BUF_DISABLE 0x0
-
-static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd)
-{
- u8 tmp;
- u8 val = cmd & ~MTK_QSPI_AUTOINC;
-
- writeb(cmd, &priv->regs->cmd);
-
- return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp),
- MTK_QSPI_CMD_POLLINGREG_US);
-}
-
-static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv)
-{
- int len = 1 + priv->txlen + priv->rxlen;
- int i, ret, idx;
-
- if (len > MTK_QSPI_MAX_SHIFT)
- return -ERR_INVAL;
-
- writeb(len * 8, &priv->regs->cnt);
-
- /* start at PRGDATA5, go down to PRGDATA0 */
- idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1;
-
- /* opcode */
- writeb(priv->op, &priv->regs->prgdata[idx]);
- idx--;
-
- /* program TX data */
- for (i = 0; i < priv->txlen; i++, idx--)
- writeb(priv->tx[i], &priv->regs->prgdata[idx]);
-
- /* clear out rest of TX registers */
- while (idx >= 0) {
- writeb(0, &priv->regs->prgdata[idx]);
- idx--;
- }
-
- ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD);
- if (ret)
- return ret;
-
- /* restart at first RX byte */
- idx = priv->rxlen - 1;
-
- /* read out RX data */
- for (i = 0; i < priv->rxlen; i++, idx--)
- priv->rx[i] = readb(&priv->regs->shreg[idx]);
-
- return 0;
-}
-
-static int mtk_qspi_read(struct mtk_qspi_priv *priv,
- u32 addr, u8 *buf, u32 len)
-{
- memcpy(buf, (u8 *)priv->mem_base + addr, len);
- return 0;
-}
-
-static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr)
-{
- int i;
-
- for (i = 0; i < 3; i++) {
- writeb(addr & 0xff, &priv->regs->radr[i]);
- addr >>= 8;
- }
-}
-
-static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv,
- u32 addr, u32 length, const u8 *data)
-{
- int i, ret;
-
- mtk_qspi_set_addr(priv, addr);
-
- for (i = 0; i < length; i++) {
- writeb(*data++, &priv->regs->wdata);
- ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
- if (ret < 0)
- return ret;
- }
- return 0;
-}
-
-static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr,
- const u8 *buf)
-{
- int i, data;
-
- mtk_qspi_set_addr(priv, addr);
-
- for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) {
- data = buf[i + 3] << 24 | buf[i + 2] << 16 |
- buf[i + 1] << 8 | buf[i];
- writel(data, &priv->regs->pp_dw_data);
- }
-
- return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
-}
-
-static int mtk_qspi_write(struct mtk_qspi_priv *priv,
- u32 addr, const u8 *buf, u32 len)
-{
- int ret;
-
- /* setting pre-fetch buffer for page program */
- writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]);
- while (len >= MTK_QSPI_WRBUF_SIZE) {
- ret = mtk_qspi_write_buffer(priv, addr, buf);
- if (ret < 0)
- return ret;
-
- len -= MTK_QSPI_WRBUF_SIZE;
- addr += MTK_QSPI_WRBUF_SIZE;
- buf += MTK_QSPI_WRBUF_SIZE;
- }
- /* disable pre-fetch buffer for page program */
- writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]);
-
- if (len)
- return mtk_qspi_write_single_byte(priv, addr, len, buf);
-
- return 0;
-}
-
-static int mtk_qspi_claim_bus(struct udevice *dev)
-{
- /* nothing to do */
- return 0;
-}
-
-static int mtk_qspi_release_bus(struct udevice *dev)
-{
- /* nothing to do */
- return 0;
-}
-
-static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
-{
- u32 bytes = DIV_ROUND_UP(bitlen, 8);
- u32 addr;
-
- if (!bytes)
- return -ERR_INVAL;
-
- if (dout) {
- if (flags & SPI_XFER_BEGIN) {
- /* parse op code and potential paras first */
- priv->op = *(u8 *)dout;
- if (bytes > 1)
- memcpy(priv->tx, (u8 *)dout + 1,
- bytes <= 4 ? bytes - 1 : 3);
- priv->txlen = bytes - 1;
- }
-
- if (flags == SPI_XFER_ONCE) {
- /* operations without receiving or sending data.
- * for example: erase, write flash register or write
- * enable...
- */
- priv->rx = NULL;
- priv->rxlen = 0;
- return mtk_qspi_tx_rx(priv);
- }
-
- if (flags & SPI_XFER_END) {
- /* here, dout should be data to be written.
- * and priv->tx should be filled 3Bytes address.
- */
- addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
- priv->tx[2];
- return mtk_qspi_write(priv, addr, (u8 *)dout, bytes);
- }
- }
-
- if (din) {
- if (priv->txlen >= 3) {
- /* if run to here, priv->tx[] should be the address
- * where read data from,
- * and, din is the buf to receive data.
- */
- addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
- priv->tx[2];
- return mtk_qspi_read(priv, addr, (u8 *)din, bytes);
- }
-
- /* should be reading flash's register */
- priv->rx = (u8 *)din;
- priv->rxlen = bytes;
- return mtk_qspi_tx_rx(priv);
- }
-
- return 0;
-}
-
-static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
-{
- struct udevice *bus = dev->parent;
- struct mtk_qspi_priv *priv = dev_get_priv(bus);
-
- return mtk_qspi_transfer(priv, bitlen, dout, din, flags);
-}
-
-static int mtk_qspi_set_speed(struct udevice *bus, uint speed)
-{
- /* nothing to do */
- return 0;
-}
-
-static int mtk_qspi_set_mode(struct udevice *bus, uint mode)
-{
- /* nothing to do */
- return 0;
-}
-
-static int mtk_qspi_ofdata_to_platdata(struct udevice *bus)
-{
- struct resource res_reg, res_mem;
- struct mtk_qspi_platdata *plat = bus->platdata;
- int ret;
-
- ret = dev_read_resource_byname(bus, "reg_base", &res_reg);
- if (ret) {
- debug("can't get reg_base resource(ret = %d)\n", ret);
- return -ENOMEM;
- }
-
- ret = dev_read_resource_byname(bus, "mem_base", &res_mem);
- if (ret) {
- debug("can't get map_base resource(ret = %d)\n", ret);
- return -ENOMEM;
- }
-
- plat->mem_base = res_mem.start;
- plat->reg_base = res_reg.start;
-
- return 0;
-}
-
-static int mtk_qspi_probe(struct udevice *bus)
-{
- struct mtk_qspi_platdata *plat = dev_get_platdata(bus);
- struct mtk_qspi_priv *priv = dev_get_priv(bus);
-
- priv->regs = (struct mtk_qspi_regs *)plat->reg_base;
- priv->mem_base = (unsigned long *)plat->mem_base;
-
- writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot);
-
- return 0;
-}
-
-static const struct dm_spi_ops mtk_qspi_ops = {
- .claim_bus = mtk_qspi_claim_bus,
- .release_bus = mtk_qspi_release_bus,
- .xfer = mtk_qspi_xfer,
- .set_speed = mtk_qspi_set_speed,
- .set_mode = mtk_qspi_set_mode,
-};
-
-static const struct udevice_id mtk_qspi_ids[] = {
- { .compatible = "mediatek,mt7629-qspi" },
- { }
-};
-
-U_BOOT_DRIVER(mtk_qspi) = {
- .name = "mtk_qspi",
- .id = UCLASS_SPI,
- .of_match = mtk_qspi_ids,
- .ops = &mtk_qspi_ops,
- .ofdata_to_platdata = mtk_qspi_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata),
- .priv_auto_alloc_size = sizeof(struct mtk_qspi_priv),
- .probe = mtk_qspi_probe,
-};
diff --git a/drivers/spi/mtk_snfi_spi.c b/drivers/spi/mtk_snfi_spi.c
new file mode 100644
index 00000000000..2a894765159
--- /dev/null
+++ b/drivers/spi/mtk_snfi_spi.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <stdbool.h>
+#include <watchdog.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#define SNFI_MAC_CTL 0x500
+#define MAC_XIO_SEL BIT(4)
+#define SF_MAC_EN BIT(3)
+#define SF_TRIG BIT(2)
+#define WIP_READY BIT(1)
+#define WIP BIT(0)
+
+#define SNFI_MAC_OUTL 0x504
+#define SNFI_MAC_INL 0x508
+
+#define SNFI_MISC_CTL 0x538
+#define SW_RST BIT(28)
+#define FIFO_RD_LTC_SHIFT 25
+#define FIFO_RD_LTC GENMASK(26, 25)
+#define LATCH_LAT_SHIFT 8
+#define LATCH_LAT GENMASK(9, 8)
+#define CS_DESELECT_CYC_SHIFT 0
+#define CS_DESELECT_CYC GENMASK(4, 0)
+
+#define SNF_STA_CTL1 0x550
+#define SPI_STATE GENMASK(3, 0)
+
+#define SNFI_GPRAM_OFFSET 0x800
+#define SNFI_GPRAM_SIZE 0x80
+
+#define SNFI_POLL_INTERVAL 500000
+#define SNFI_RST_POLL_INTERVAL 1000000
+
+struct mtk_snfi_priv {
+ void __iomem *base;
+
+ struct clk nfi_clk;
+ struct clk pad_clk;
+};
+
+static int mtk_snfi_adjust_op_size(struct spi_slave *slave,
+ struct spi_mem_op *op)
+{
+ u32 nbytes;
+
+ /*
+ * When there is input data, it will be appended after the output
+ * data in the GPRAM. So the total size of either pure output data
+ * or the output+input data must not exceed the GPRAM size.
+ */
+
+ nbytes = sizeof(op->cmd.opcode) + op->addr.nbytes +
+ op->dummy.nbytes;
+
+ if (nbytes + op->data.nbytes <= SNFI_GPRAM_SIZE)
+ return 0;
+
+ if (nbytes >= SNFI_GPRAM_SIZE)
+ return -ENOTSUPP;
+
+ op->data.nbytes = SNFI_GPRAM_SIZE - nbytes;
+
+ return 0;
+}
+
+static bool mtk_snfi_supports_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 ||
+ op->dummy.buswidth > 1 || op->data.buswidth > 1)
+ return false;
+
+ return true;
+}
+
+static int mtk_snfi_mac_trigger(struct mtk_snfi_priv *priv,
+ struct udevice *bus, u32 outlen, u32 inlen)
+{
+ int ret;
+ u32 val;
+
+#ifdef CONFIG_PINCTRL
+ pinctrl_select_state(bus, "snfi");
+#endif
+
+ writel(SF_MAC_EN, priv->base + SNFI_MAC_CTL);
+ writel(outlen, priv->base + SNFI_MAC_OUTL);
+ writel(inlen, priv->base + SNFI_MAC_INL);
+
+ writel(SF_MAC_EN | SF_TRIG, priv->base + SNFI_MAC_CTL);
+
+ ret = readl_poll_timeout(priv->base + SNFI_MAC_CTL, val,
+ val & WIP_READY, SNFI_POLL_INTERVAL);
+ if (ret) {
+ printf("%s: timed out waiting for WIP_READY\n", __func__);
+ goto cleanup;
+ }
+
+ ret = readl_poll_timeout(priv->base + SNFI_MAC_CTL, val,
+ !(val & WIP), SNFI_POLL_INTERVAL);
+ if (ret)
+ printf("%s: timed out waiting for WIP cleared\n", __func__);
+
+ writel(0, priv->base + SNFI_MAC_CTL);
+
+cleanup:
+#ifdef CONFIG_PINCTRL
+ pinctrl_select_state(bus, "default");
+#endif
+
+ return ret;
+}
+
+static int mtk_snfi_mac_reset(struct mtk_snfi_priv *priv)
+{
+ int ret;
+ u32 val;
+
+ setbits_32(priv->base + SNFI_MISC_CTL, SW_RST);
+
+ ret = readl_poll_timeout(priv->base + SNF_STA_CTL1, val,
+ !(val & SPI_STATE), SNFI_POLL_INTERVAL);
+ if (ret)
+ printf("%s: failed to reset snfi mac\n", __func__);
+
+ writel((2 << FIFO_RD_LTC_SHIFT) |
+ (10 << CS_DESELECT_CYC_SHIFT),
+ priv->base + SNFI_MISC_CTL);
+
+ return ret;
+}
+
+static void mtk_snfi_copy_to_gpram(struct mtk_snfi_priv *priv,
+ const void *data, size_t len)
+{
+ void __iomem *gpram = priv->base + SNFI_GPRAM_OFFSET;
+ size_t i, n = (len + sizeof(u32) - 1) / sizeof(u32);
+ const u32 *buff = data;
+
+ /*
+ * The output data will always be copied to the beginning of
+ * the GPRAM. Uses word write for better performace.
+ *
+ * Trailing bytes in the last word are not cared.
+ */
+
+ for (i = 0; i < n; i++)
+ writel(buff[i], gpram + i * sizeof(u32));
+}
+
+static void mtk_snfi_copy_from_gpram(struct mtk_snfi_priv *priv, u8 *cache,
+ void *data, size_t pos, size_t len)
+{
+ void __iomem *gpram = priv->base + SNFI_GPRAM_OFFSET;
+ u32 *buff = (u32 *)cache;
+ size_t i, off, end;
+
+ /* Start position in the buffer */
+ off = pos & (sizeof(u32) - 1);
+
+ /* End position for copy */
+ end = (len + pos + sizeof(u32) - 1) & (~(sizeof(u32) - 1));
+
+ /* Start position for copy */
+ pos &= ~(sizeof(u32) - 1);
+
+ /*
+ * Read aligned data from GPRAM to buffer first.
+ * Uses word read for better performace.
+ */
+ i = 0;
+ while (pos < end) {
+ buff[i++] = readl(gpram + pos);
+ pos += sizeof(u32);
+ }
+
+ /* Copy rx data */
+ memcpy(data, cache + off, len);
+}
+
+static int mtk_snfi_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ struct udevice *bus = dev_get_parent(slave->dev);
+ struct mtk_snfi_priv *priv = dev_get_priv(bus);
+ u8 gpram_cache[SNFI_GPRAM_SIZE];
+ u32 i, len = 0, inlen = 0;
+ int addr_sh;
+ int ret;
+
+ WATCHDOG_RESET();
+
+ ret = mtk_snfi_mac_reset(priv);
+ if (ret)
+ return ret;
+
+ /* Put opcode */
+ gpram_cache[len++] = op->cmd.opcode;
+
+ /* Put address */
+ addr_sh = (op->addr.nbytes - 1) * 8;
+ while (addr_sh >= 0) {
+ gpram_cache[len++] = (op->addr.val >> addr_sh) & 0xff;
+ addr_sh -= 8;
+ }
+
+ /* Put dummy bytes */
+ for (i = 0; i < op->dummy.nbytes; i++)
+ gpram_cache[len++] = 0;
+
+ /* Put output data */
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) {
+ memcpy(gpram_cache + len, op->data.buf.out, op->data.nbytes);
+ len += op->data.nbytes;
+ }
+
+ /* Copy final output data to GPRAM */
+ mtk_snfi_copy_to_gpram(priv, gpram_cache, len);
+
+ /* Start one SPI transaction */
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN)
+ inlen = op->data.nbytes;
+
+ ret = mtk_snfi_mac_trigger(priv, bus, len, inlen);
+ if (ret)
+ return ret;
+
+ /* Copy input data from GPRAM */
+ if (inlen)
+ mtk_snfi_copy_from_gpram(priv, gpram_cache, op->data.buf.in,
+ len, inlen);
+
+ return 0;
+}
+
+static int mtk_snfi_spi_probe(struct udevice *bus)
+{
+ struct mtk_snfi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ priv->base = (void __iomem *)devfdt_get_addr(bus);
+ if (!priv->base)
+ return -EINVAL;
+
+ ret = clk_get_by_name(bus, "nfi_clk", &priv->nfi_clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_by_name(bus, "pad_clk", &priv->pad_clk);
+ if (ret < 0)
+ return ret;
+
+ clk_enable(&priv->nfi_clk);
+ clk_enable(&priv->pad_clk);
+
+ return 0;
+}
+
+static int mtk_snfi_set_speed(struct udevice *bus, uint speed)
+{
+ /*
+ * The SNFI does not have a bus clock divider.
+ * The bus clock is set in dts (pad_clk, UNIVPLL2_D8 = 50MHz).
+ */
+
+ return 0;
+}
+
+static int mtk_snfi_set_mode(struct udevice *bus, uint mode)
+{
+ /* The SNFI supports only mode 0 */
+
+ if (mode)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops mtk_snfi_mem_ops = {
+ .adjust_op_size = mtk_snfi_adjust_op_size,
+ .supports_op = mtk_snfi_supports_op,
+ .exec_op = mtk_snfi_exec_op,
+};
+
+static const struct dm_spi_ops mtk_snfi_spi_ops = {
+ .mem_ops = &mtk_snfi_mem_ops,
+ .set_speed = mtk_snfi_set_speed,
+ .set_mode = mtk_snfi_set_mode,
+};
+
+static const struct udevice_id mtk_snfi_spi_ids[] = {
+ { .compatible = "mediatek,mtk-snfi-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(mtk_snfi_spi) = {
+ .name = "mtk_snfi_spi",
+ .id = UCLASS_SPI,
+ .of_match = mtk_snfi_spi_ids,
+ .ops = &mtk_snfi_spi_ops,
+ .priv_auto_alloc_size = sizeof(struct mtk_snfi_priv),
+ .probe = mtk_snfi_spi_probe,
+};
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 5065e407f82..3a9756fbf1b 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -2,6 +2,9 @@
/*
* Freescale i.MX28 SPI driver
*
+ * Copyright (C) 2019 DENX Software Engineering
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
+ *
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
@@ -27,6 +30,19 @@
#define MXSSSP_SMALL_TRANSFER 512
+static void mxs_spi_start_xfer(struct mxs_ssp_regs *ssp_regs)
+{
+ writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_set);
+ writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_clr);
+}
+
+static void mxs_spi_end_xfer(struct mxs_ssp_regs *ssp_regs)
+{
+ writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_clr);
+ writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_set);
+}
+
+#if !CONFIG_IS_ENABLED(DM_SPI)
struct mxs_spi_slave {
struct spi_slave slave;
uint32_t max_khz;
@@ -38,94 +54,38 @@ static inline struct mxs_spi_slave *to_mxs_slave(struct spi_slave *slave)
{
return container_of(slave, struct mxs_spi_slave, slave);
}
+#else
+#include <dm.h>
+#include <errno.h>
+struct mxs_spi_platdata {
+ s32 frequency; /* Default clock frequency, -1 for none */
+ fdt_addr_t base; /* SPI IP block base address */
+ int num_cs; /* Number of CSes supported */
+ int dma_id; /* ID of the DMA channel */
+ int clk_id; /* ID of the SSP clock */
+};
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
- /* MXS SPI: 4 ports and 3 chip selects maximum */
- if (!mxs_ssp_bus_id_valid(bus) || cs > 2)
- return 0;
- else
- return 1;
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
-{
- struct mxs_spi_slave *mxs_slave;
-
- if (!spi_cs_is_valid(bus, cs)) {
- printf("mxs_spi: invalid bus %d / chip select %d\n", bus, cs);
- return NULL;
- }
-
- mxs_slave = spi_alloc_slave(struct mxs_spi_slave, bus, cs);
- if (!mxs_slave)
- return NULL;
-
- if (mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + bus))
- goto err_init;
-
- mxs_slave->max_khz = max_hz / 1000;
- mxs_slave->mode = mode;
- mxs_slave->regs = mxs_ssp_regs_by_bus(bus);
-
- return &mxs_slave->slave;
-
-err_init:
- free(mxs_slave);
- return NULL;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
- struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
- free(mxs_slave);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
- struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
- struct mxs_ssp_regs *ssp_regs = mxs_slave->regs;
- uint32_t reg = 0;
-
- mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
-
- writel((slave->cs << MXS_SSP_CHIPSELECT_SHIFT) |
- SSP_CTRL0_BUS_WIDTH_ONE_BIT,
- &ssp_regs->hw_ssp_ctrl0);
-
- reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
- reg |= (mxs_slave->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
- reg |= (mxs_slave->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
- writel(reg, &ssp_regs->hw_ssp_ctrl1);
-
- writel(0, &ssp_regs->hw_ssp_cmd0);
-
- mxs_set_ssp_busclock(slave->bus, mxs_slave->max_khz);
-
- return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
-}
-
-static void mxs_spi_start_xfer(struct mxs_ssp_regs *ssp_regs)
-{
- writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_set);
- writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_clr);
-}
-
-static void mxs_spi_end_xfer(struct mxs_ssp_regs *ssp_regs)
-{
- writel(SSP_CTRL0_LOCK_CS, &ssp_regs->hw_ssp_ctrl0_clr);
- writel(SSP_CTRL0_IGNORE_CRC, &ssp_regs->hw_ssp_ctrl0_set);
-}
+struct mxs_spi_priv {
+ struct mxs_ssp_regs *regs;
+ unsigned int dma_channel;
+ unsigned int max_freq;
+ unsigned int clk_id;
+ unsigned int mode;
+};
+#endif
+#if !CONFIG_IS_ENABLED(DM_SPI)
static int mxs_spi_xfer_pio(struct mxs_spi_slave *slave,
char *data, int length, int write, unsigned long flags)
{
struct mxs_ssp_regs *ssp_regs = slave->regs;
+#else
+static int mxs_spi_xfer_pio(struct mxs_spi_priv *priv,
+ char *data, int length, int write,
+ unsigned long flags)
+{
+ struct mxs_ssp_regs *ssp_regs = priv->regs;
+#endif
if (flags & SPI_XFER_BEGIN)
mxs_spi_start_xfer(ssp_regs);
@@ -181,12 +141,19 @@ static int mxs_spi_xfer_pio(struct mxs_spi_slave *slave,
return 0;
}
+#if !CONFIG_IS_ENABLED(DM_SPI)
static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
char *data, int length, int write, unsigned long flags)
{
+ struct mxs_ssp_regs *ssp_regs = slave->regs;
+#else
+static int mxs_spi_xfer_dma(struct mxs_spi_priv *priv,
+ char *data, int length, int write,
+ unsigned long flags)
+{ struct mxs_ssp_regs *ssp_regs = priv->regs;
+#endif
const int xfer_max_sz = 0xff00;
const int desc_count = DIV_ROUND_UP(length, xfer_max_sz) + 1;
- struct mxs_ssp_regs *ssp_regs = slave->regs;
struct mxs_dma_desc *dp;
uint32_t ctrl0;
uint32_t cache_data_count;
@@ -225,7 +192,11 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
/* Invalidate the area, so no writeback into the RAM races with DMA */
invalidate_dcache_range(dstart, dstart + cache_data_count);
+#if !CONFIG_IS_ENABLED(DM_SPI)
dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + slave->slave.bus;
+#else
+ dmach = priv->dma_channel;
+#endif
dp = desc;
while (length) {
@@ -302,11 +273,20 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
return ret;
}
+#if !CONFIG_IS_ENABLED(DM_SPI)
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
struct mxs_ssp_regs *ssp_regs = mxs_slave->regs;
+#else
+int mxs_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct mxs_spi_priv *priv = dev_get_priv(bus);
+ struct mxs_ssp_regs *ssp_regs = priv->regs;
+#endif
int len = bitlen / 8;
char dummy;
int write = 0;
@@ -350,9 +330,263 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (!dma || (len < MXSSSP_SMALL_TRANSFER)) {
writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr);
+#if !CONFIG_IS_ENABLED(DM_SPI)
return mxs_spi_xfer_pio(mxs_slave, data, len, write, flags);
+#else
+ return mxs_spi_xfer_pio(priv, data, len, write, flags);
+#endif
} else {
writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set);
+#if !CONFIG_IS_ENABLED(DM_SPI)
return mxs_spi_xfer_dma(mxs_slave, data, len, write, flags);
+#else
+ return mxs_spi_xfer_dma(priv, data, len, write, flags);
+#endif
}
}
+
+#if !CONFIG_IS_ENABLED(DM_SPI)
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ /* MXS SPI: 4 ports and 3 chip selects maximum */
+ if (!mxs_ssp_bus_id_valid(bus) || cs > 2)
+ return 0;
+ else
+ return 1;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct mxs_spi_slave *mxs_slave;
+
+ if (!spi_cs_is_valid(bus, cs)) {
+ printf("mxs_spi: invalid bus %d / chip select %d\n", bus, cs);
+ return NULL;
+ }
+
+ mxs_slave = spi_alloc_slave(struct mxs_spi_slave, bus, cs);
+ if (!mxs_slave)
+ return NULL;
+
+ if (mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + bus))
+ goto err_init;
+
+ mxs_slave->max_khz = max_hz / 1000;
+ mxs_slave->mode = mode;
+ mxs_slave->regs = mxs_ssp_regs_by_bus(bus);
+
+ return &mxs_slave->slave;
+
+err_init:
+ free(mxs_slave);
+ return NULL;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
+
+ free(mxs_slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
+ struct mxs_ssp_regs *ssp_regs = mxs_slave->regs;
+ u32 reg = 0;
+
+ mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
+
+ writel((slave->cs << MXS_SSP_CHIPSELECT_SHIFT) |
+ SSP_CTRL0_BUS_WIDTH_ONE_BIT,
+ &ssp_regs->hw_ssp_ctrl0);
+
+ reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
+ reg |= (mxs_slave->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
+ reg |= (mxs_slave->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
+ writel(reg, &ssp_regs->hw_ssp_ctrl1);
+
+ writel(0, &ssp_regs->hw_ssp_cmd0);
+
+ mxs_set_ssp_busclock(slave->bus, mxs_slave->max_khz);
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+}
+
+#else /* CONFIG_DM_SPI */
+/* Base numbers of i.MX2[38] clk for ssp0 IP block */
+#define MXS_SSP_IMX23_CLKID_SSP0 33
+#define MXS_SSP_IMX28_CLKID_SSP0 46
+
+static int mxs_spi_probe(struct udevice *bus)
+{
+ struct mxs_spi_platdata *plat = dev_get_platdata(bus);
+ struct mxs_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ debug("%s: probe\n", __func__);
+ priv->regs = (struct mxs_ssp_regs *)plat->base;
+ priv->max_freq = plat->frequency;
+
+ priv->dma_channel = plat->dma_id;
+ priv->clk_id = plat->clk_id;
+
+ ret = mxs_dma_init_channel(priv->dma_channel);
+ if (ret) {
+ printf("%s: DMA init channel error %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxs_spi_claim_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct mxs_spi_priv *priv = dev_get_priv(bus);
+ struct mxs_ssp_regs *ssp_regs = priv->regs;
+ int cs = spi_chip_select(dev);
+
+ /*
+ * i.MX28 supports up to 3 CS (SSn0, SSn1, SSn2)
+ * To set them it uses following tuple (WAIT_FOR_IRQ,WAIT_FOR_CMD),
+ * where:
+ *
+ * WAIT_FOR_IRQ is bit 21 of HW_SSP_CTRL0
+ * WAIT_FOR_CMD is bit 20 (#defined as MXS_SSP_CHIPSELECT_SHIFT here) of
+ * HW_SSP_CTRL0
+ * SSn0 b00
+ * SSn1 b01
+ * SSn2 b10 (which require setting WAIT_FOR_IRQ)
+ *
+ * However, for now i.MX28 SPI driver will support up till 2 CSes
+ * (SSn0, and SSn1).
+ */
+
+ /* Ungate SSP clock and set active CS */
+ clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
+ BIT(MXS_SSP_CHIPSELECT_SHIFT) |
+ SSP_CTRL0_CLKGATE, (cs << MXS_SSP_CHIPSELECT_SHIFT));
+
+ return 0;
+}
+
+static int mxs_spi_release_bus(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct mxs_spi_priv *priv = dev_get_priv(bus);
+ struct mxs_ssp_regs *ssp_regs = priv->regs;
+
+ /* Gate SSP clock */
+ setbits_le32(&ssp_regs->hw_ssp_ctrl0, SSP_CTRL0_CLKGATE);
+
+ return 0;
+}
+
+static int mxs_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct mxs_spi_priv *priv = dev_get_priv(bus);
+#ifdef CONFIG_MX28
+ int clkid = priv->clk_id - MXS_SSP_IMX28_CLKID_SSP0;
+#else /* CONFIG_MX23 */
+ int clkid = priv->clk_id - MXS_SSP_IMX23_CLKID_SSP0;
+#endif
+ if (speed > priv->max_freq)
+ speed = priv->max_freq;
+
+ debug("%s speed: %u [Hz] clkid: %d\n", __func__, speed, clkid);
+ mxs_set_ssp_busclock(clkid, speed / 1000);
+
+ return 0;
+}
+
+static int mxs_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct mxs_spi_priv *priv = dev_get_priv(bus);
+ struct mxs_ssp_regs *ssp_regs = priv->regs;
+ u32 reg;
+
+ priv->mode = mode;
+ debug("%s: mode 0x%x\n", __func__, mode);
+
+ reg = SSP_CTRL1_SSP_MODE_SPI | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS;
+ reg |= (priv->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0;
+ reg |= (priv->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0;
+ writel(reg, &ssp_regs->hw_ssp_ctrl1);
+
+ /* Single bit SPI support */
+ writel(SSP_CTRL0_BUS_WIDTH_ONE_BIT, &ssp_regs->hw_ssp_ctrl0);
+
+ return 0;
+}
+
+static const struct dm_spi_ops mxs_spi_ops = {
+ .claim_bus = mxs_spi_claim_bus,
+ .release_bus = mxs_spi_release_bus,
+ .xfer = mxs_spi_xfer,
+ .set_speed = mxs_spi_set_speed,
+ .set_mode = mxs_spi_set_mode,
+ /*
+ * cs_info is not needed, since we require all chip selects to be
+ * in the device tree explicitly
+ */
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int mxs_ofdata_to_platdata(struct udevice *bus)
+{
+ struct mxs_spi_platdata *plat = bus->platdata;
+ u32 prop[2];
+ int ret;
+
+ plat->base = dev_read_addr(bus);
+ plat->frequency =
+ dev_read_u32_default(bus, "spi-max-frequency", 40000000);
+ plat->num_cs = dev_read_u32_default(bus, "num-cs", 2);
+
+ ret = dev_read_u32_array(bus, "dmas", prop, ARRAY_SIZE(prop));
+ if (ret) {
+ printf("%s: Reading 'dmas' property failed!\n", __func__);
+ return ret;
+ }
+ plat->dma_id = prop[1];
+
+ ret = dev_read_u32_array(bus, "clocks", prop, ARRAY_SIZE(prop));
+ if (ret) {
+ printf("%s: Reading 'clocks' property failed!\n", __func__);
+ return ret;
+ }
+ plat->clk_id = prop[1];
+
+ debug("%s: base=0x%x, max-frequency=%d num-cs=%d dma_id=%d clk_id=%d\n",
+ __func__, (uint)plat->base, plat->frequency, plat->num_cs,
+ plat->dma_id, plat->clk_id);
+
+ return 0;
+}
+#endif
+
+static const struct udevice_id mxs_spi_ids[] = {
+ { .compatible = "fsl,imx23-spi" },
+ { .compatible = "fsl,imx28-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(mxs_spi) = {
+ .name = "mxs_spi",
+ .id = UCLASS_SPI,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .of_match = mxs_spi_ids,
+ .ofdata_to_platdata = mxs_ofdata_to_platdata,
+#endif
+ .priv_auto_alloc_size = sizeof(struct mxs_spi_platdata),
+ .ops = &mxs_spi_ops,
+ .priv_auto_alloc_size = sizeof(struct mxs_spi_priv),
+ .probe = mxs_spi_probe,
+};
+#endif
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 7aabebeff5f..7788ab99534 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -430,12 +430,14 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
if (slave->max_write_size && len > slave->max_write_size)
return -EINVAL;
- if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size)
- op->data.nbytes = min(op->data.nbytes,
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ if (slave->max_read_size)
+ op->data.nbytes = min(op->data.nbytes,
slave->max_read_size);
- else if (slave->max_write_size)
+ } else if (slave->max_write_size) {
op->data.nbytes = min(op->data.nbytes,
slave->max_write_size - len);
+ }
if (!op->data.nbytes)
return -EINVAL;
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
new file mode 100644
index 00000000000..969bd4b75cb
--- /dev/null
+++ b/drivers/spi/spi-sifive.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 SiFive, Inc.
+ * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
+ *
+ * SiFive SPI controller driver (master mode only)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <linux/log2.h>
+#include <clk.h>
+
+#define SIFIVE_SPI_MAX_CS 32
+
+#define SIFIVE_SPI_DEFAULT_DEPTH 8
+#define SIFIVE_SPI_DEFAULT_BITS 8
+
+/* register offsets */
+#define SIFIVE_SPI_REG_SCKDIV 0x00 /* Serial clock divisor */
+#define SIFIVE_SPI_REG_SCKMODE 0x04 /* Serial clock mode */
+#define SIFIVE_SPI_REG_CSID 0x10 /* Chip select ID */
+#define SIFIVE_SPI_REG_CSDEF 0x14 /* Chip select default */
+#define SIFIVE_SPI_REG_CSMODE 0x18 /* Chip select mode */
+#define SIFIVE_SPI_REG_DELAY0 0x28 /* Delay control 0 */
+#define SIFIVE_SPI_REG_DELAY1 0x2c /* Delay control 1 */
+#define SIFIVE_SPI_REG_FMT 0x40 /* Frame format */
+#define SIFIVE_SPI_REG_TXDATA 0x48 /* Tx FIFO data */
+#define SIFIVE_SPI_REG_RXDATA 0x4c /* Rx FIFO data */
+#define SIFIVE_SPI_REG_TXMARK 0x50 /* Tx FIFO watermark */
+#define SIFIVE_SPI_REG_RXMARK 0x54 /* Rx FIFO watermark */
+#define SIFIVE_SPI_REG_FCTRL 0x60 /* SPI flash interface control */
+#define SIFIVE_SPI_REG_FFMT 0x64 /* SPI flash instruction format */
+#define SIFIVE_SPI_REG_IE 0x70 /* Interrupt Enable Register */
+#define SIFIVE_SPI_REG_IP 0x74 /* Interrupt Pendings Register */
+
+/* sckdiv bits */
+#define SIFIVE_SPI_SCKDIV_DIV_MASK 0xfffU
+
+/* sckmode bits */
+#define SIFIVE_SPI_SCKMODE_PHA BIT(0)
+#define SIFIVE_SPI_SCKMODE_POL BIT(1)
+#define SIFIVE_SPI_SCKMODE_MODE_MASK (SIFIVE_SPI_SCKMODE_PHA | \
+ SIFIVE_SPI_SCKMODE_POL)
+
+/* csmode bits */
+#define SIFIVE_SPI_CSMODE_MODE_AUTO 0U
+#define SIFIVE_SPI_CSMODE_MODE_HOLD 2U
+#define SIFIVE_SPI_CSMODE_MODE_OFF 3U
+
+/* delay0 bits */
+#define SIFIVE_SPI_DELAY0_CSSCK(x) ((u32)(x))
+#define SIFIVE_SPI_DELAY0_CSSCK_MASK 0xffU
+#define SIFIVE_SPI_DELAY0_SCKCS(x) ((u32)(x) << 16)
+#define SIFIVE_SPI_DELAY0_SCKCS_MASK (0xffU << 16)
+
+/* delay1 bits */
+#define SIFIVE_SPI_DELAY1_INTERCS(x) ((u32)(x))
+#define SIFIVE_SPI_DELAY1_INTERCS_MASK 0xffU
+#define SIFIVE_SPI_DELAY1_INTERXFR(x) ((u32)(x) << 16)
+#define SIFIVE_SPI_DELAY1_INTERXFR_MASK (0xffU << 16)
+
+/* fmt bits */
+#define SIFIVE_SPI_FMT_PROTO_SINGLE 0U
+#define SIFIVE_SPI_FMT_PROTO_DUAL 1U
+#define SIFIVE_SPI_FMT_PROTO_QUAD 2U
+#define SIFIVE_SPI_FMT_PROTO_MASK 3U
+#define SIFIVE_SPI_FMT_ENDIAN BIT(2)
+#define SIFIVE_SPI_FMT_DIR BIT(3)
+#define SIFIVE_SPI_FMT_LEN(x) ((u32)(x) << 16)
+#define SIFIVE_SPI_FMT_LEN_MASK (0xfU << 16)
+
+/* txdata bits */
+#define SIFIVE_SPI_TXDATA_DATA_MASK 0xffU
+#define SIFIVE_SPI_TXDATA_FULL BIT(31)
+
+/* rxdata bits */
+#define SIFIVE_SPI_RXDATA_DATA_MASK 0xffU
+#define SIFIVE_SPI_RXDATA_EMPTY BIT(31)
+
+/* ie and ip bits */
+#define SIFIVE_SPI_IP_TXWM BIT(0)
+#define SIFIVE_SPI_IP_RXWM BIT(1)
+
+struct sifive_spi {
+ void *regs; /* base address of the registers */
+ u32 fifo_depth;
+ u32 bits_per_word;
+ u32 cs_inactive; /* Level of the CS pins when inactive*/
+ u32 freq;
+ u32 num_cs;
+};
+
+static void sifive_spi_prep_device(struct sifive_spi *spi,
+ struct dm_spi_slave_platdata *slave)
+{
+ /* Update the chip select polarity */
+ if (slave->mode & SPI_CS_HIGH)
+ spi->cs_inactive &= ~BIT(slave->cs);
+ else
+ spi->cs_inactive |= BIT(slave->cs);
+ writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
+
+ /* Select the correct device */
+ writel(slave->cs, spi->regs + SIFIVE_SPI_REG_CSID);
+}
+
+static int sifive_spi_set_cs(struct sifive_spi *spi,
+ struct dm_spi_slave_platdata *slave)
+{
+ u32 cs_mode = SIFIVE_SPI_CSMODE_MODE_HOLD;
+
+ if (slave->mode & SPI_CS_HIGH)
+ cs_mode = SIFIVE_SPI_CSMODE_MODE_AUTO;
+
+ writel(cs_mode, spi->regs + SIFIVE_SPI_REG_CSMODE);
+
+ return 0;
+}
+
+static void sifive_spi_clear_cs(struct sifive_spi *spi)
+{
+ writel(SIFIVE_SPI_CSMODE_MODE_AUTO, spi->regs + SIFIVE_SPI_REG_CSMODE);
+}
+
+static void sifive_spi_prep_transfer(struct sifive_spi *spi,
+ bool is_rx_xfer,
+ struct dm_spi_slave_platdata *slave)
+{
+ u32 cr;
+
+ /* Modify the SPI protocol mode */
+ cr = readl(spi->regs + SIFIVE_SPI_REG_FMT);
+
+ /* Bits per word ? */
+ cr &= ~SIFIVE_SPI_FMT_LEN_MASK;
+ cr |= SIFIVE_SPI_FMT_LEN(spi->bits_per_word);
+
+ /* LSB first? */
+ cr &= ~SIFIVE_SPI_FMT_ENDIAN;
+ if (slave->mode & SPI_LSB_FIRST)
+ cr |= SIFIVE_SPI_FMT_ENDIAN;
+
+ /* Number of wires ? */
+ cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
+ if ((slave->mode & SPI_TX_QUAD) || (slave->mode & SPI_RX_QUAD))
+ cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
+ else if ((slave->mode & SPI_TX_DUAL) || (slave->mode & SPI_RX_DUAL))
+ cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
+ else
+ cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
+
+ /* SPI direction in/out ? */
+ cr &= ~SIFIVE_SPI_FMT_DIR;
+ if (!is_rx_xfer)
+ cr |= SIFIVE_SPI_FMT_DIR;
+
+ writel(cr, spi->regs + SIFIVE_SPI_REG_FMT);
+}
+
+static void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
+{
+ u32 data;
+
+ do {
+ data = readl(spi->regs + SIFIVE_SPI_REG_RXDATA);
+ } while (data & SIFIVE_SPI_RXDATA_EMPTY);
+
+ if (rx_ptr)
+ *rx_ptr = data & SIFIVE_SPI_RXDATA_DATA_MASK;
+}
+
+static void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr)
+{
+ u32 data;
+ u8 tx_data = (tx_ptr) ? *tx_ptr & SIFIVE_SPI_TXDATA_DATA_MASK :
+ SIFIVE_SPI_TXDATA_DATA_MASK;
+
+ do {
+ data = readl(spi->regs + SIFIVE_SPI_REG_TXDATA);
+ } while (data & SIFIVE_SPI_TXDATA_FULL);
+
+ writel(tx_data, spi->regs + SIFIVE_SPI_REG_TXDATA);
+}
+
+static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev->parent;
+ struct sifive_spi *spi = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev);
+ const unsigned char *tx_ptr = dout;
+ u8 *rx_ptr = din;
+ u32 remaining_len;
+ int ret;
+
+ if (flags & SPI_XFER_BEGIN) {
+ sifive_spi_prep_device(spi, slave);
+
+ ret = sifive_spi_set_cs(spi, slave);
+ if (ret)
+ return ret;
+ }
+
+ sifive_spi_prep_transfer(spi, true, slave);
+
+ remaining_len = bitlen / 8;
+
+ while (remaining_len) {
+ int n_words, tx_words, rx_words;
+
+ n_words = min(remaining_len, spi->fifo_depth);
+
+ /* Enqueue n_words for transmission */
+ if (tx_ptr) {
+ for (tx_words = 0; tx_words < n_words; ++tx_words) {
+ sifive_spi_tx(spi, tx_ptr);
+ sifive_spi_rx(spi, NULL);
+ tx_ptr++;
+ }
+ }
+
+ /* Read out all the data from the RX FIFO */
+ if (rx_ptr) {
+ for (rx_words = 0; rx_words < n_words; ++rx_words) {
+ sifive_spi_tx(spi, NULL);
+ sifive_spi_rx(spi, rx_ptr);
+ rx_ptr++;
+ }
+ }
+
+ remaining_len -= n_words;
+ }
+
+ if (flags & SPI_XFER_END)
+ sifive_spi_clear_cs(spi);
+
+ return 0;
+}
+
+static int sifive_spi_set_speed(struct udevice *bus, uint speed)
+{
+ struct sifive_spi *spi = dev_get_priv(bus);
+ u32 scale;
+
+ if (speed > spi->freq)
+ speed = spi->freq;
+
+ /* Cofigure max speed */
+ scale = (DIV_ROUND_UP(spi->freq >> 1, speed) - 1)
+ & SIFIVE_SPI_SCKDIV_DIV_MASK;
+ writel(scale, spi->regs + SIFIVE_SPI_REG_SCKDIV);
+
+ return 0;
+}
+
+static int sifive_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct sifive_spi *spi = dev_get_priv(bus);
+ u32 cr;
+
+ /* Switch clock mode bits */
+ cr = readl(spi->regs + SIFIVE_SPI_REG_SCKMODE) &
+ ~SIFIVE_SPI_SCKMODE_MODE_MASK;
+ if (mode & SPI_CPHA)
+ cr |= SIFIVE_SPI_SCKMODE_PHA;
+ if (mode & SPI_CPOL)
+ cr |= SIFIVE_SPI_SCKMODE_POL;
+
+ writel(cr, spi->regs + SIFIVE_SPI_REG_SCKMODE);
+
+ return 0;
+}
+
+static int sifive_spi_cs_info(struct udevice *bus, uint cs,
+ struct spi_cs_info *info)
+{
+ struct sifive_spi *spi = dev_get_priv(bus);
+
+ if (cs >= spi->num_cs)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void sifive_spi_init_hw(struct sifive_spi *spi)
+{
+ u32 cs_bits;
+
+ /* probe the number of CS lines */
+ spi->cs_inactive = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
+ writel(0xffffffffU, spi->regs + SIFIVE_SPI_REG_CSDEF);
+ cs_bits = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
+ writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
+ if (!cs_bits) {
+ printf("Could not auto probe CS lines\n");
+ return;
+ }
+
+ spi->num_cs = ilog2(cs_bits) + 1;
+ if (spi->num_cs > SIFIVE_SPI_MAX_CS) {
+ printf("Invalid number of spi slaves\n");
+ return;
+ }
+
+ /* Watermark interrupts are disabled by default */
+ writel(0, spi->regs + SIFIVE_SPI_REG_IE);
+
+ /* Set CS/SCK Delays and Inactive Time to defaults */
+ writel(SIFIVE_SPI_DELAY0_CSSCK(1) | SIFIVE_SPI_DELAY0_SCKCS(1),
+ spi->regs + SIFIVE_SPI_REG_DELAY0);
+ writel(SIFIVE_SPI_DELAY1_INTERCS(1) | SIFIVE_SPI_DELAY1_INTERXFR(0),
+ spi->regs + SIFIVE_SPI_REG_DELAY1);
+
+ /* Exit specialized memory-mapped SPI flash mode */
+ writel(0, spi->regs + SIFIVE_SPI_REG_FCTRL);
+}
+
+static int sifive_spi_probe(struct udevice *bus)
+{
+ struct sifive_spi *spi = dev_get_priv(bus);
+ struct clk clkdev;
+ int ret;
+
+ spi->regs = (void *)(ulong)dev_remap_addr(bus);
+ if (!spi->regs)
+ return -ENODEV;
+
+ spi->fifo_depth = dev_read_u32_default(bus,
+ "sifive,fifo-depth",
+ SIFIVE_SPI_DEFAULT_DEPTH);
+
+ spi->bits_per_word = dev_read_u32_default(bus,
+ "sifive,max-bits-per-word",
+ SIFIVE_SPI_DEFAULT_BITS);
+
+ ret = clk_get_by_index(bus, 0, &clkdev);
+ if (ret)
+ return ret;
+ spi->freq = clk_get_rate(&clkdev);
+
+ /* init the sifive spi hw */
+ sifive_spi_init_hw(spi);
+
+ return 0;
+}
+
+static const struct dm_spi_ops sifive_spi_ops = {
+ .xfer = sifive_spi_xfer,
+ .set_speed = sifive_spi_set_speed,
+ .set_mode = sifive_spi_set_mode,
+ .cs_info = sifive_spi_cs_info,
+};
+
+static const struct udevice_id sifive_spi_ids[] = {
+ { .compatible = "sifive,spi0" },
+ { }
+};
+
+U_BOOT_DRIVER(sifive_spi) = {
+ .name = "sifive_spi",
+ .id = UCLASS_SPI,
+ .of_match = sifive_spi_ids,
+ .ops = &sifive_spi_ops,
+ .priv_auto_alloc_size = sizeof(struct sifive_spi),
+ .probe = sifive_spi_probe,
+};
diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c
index 8d612f22d69..958c394a1a0 100644
--- a/drivers/spi/stm32_qspi.c
+++ b/drivers/spi/stm32_qspi.c
@@ -526,7 +526,6 @@ static const struct dm_spi_ops stm32_qspi_ops = {
};
static const struct udevice_id stm32_qspi_ids[] = {
- { .compatible = "st,stm32-qspi" },
{ .compatible = "st,stm32f469-qspi" },
{ }
};
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index a71b9be5fb5..bdf8dc6fef5 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -17,6 +17,15 @@ config IMX_THERMAL
cpufreq is used as the cooling device to throttle CPUs when the
passive trip is crossed.
+config IMX_SCU_THERMAL
+ bool "Temperature sensor driver for NXP i.MX8"
+ depends on ARCH_IMX8
+ help
+ Support for Temperature sensors on NXP i.MX8.
+ It supports one critical trip point and one passive trip point. The
+ boot is hold to the cool device to throttle CPUs when the passive
+ trip is crossed
+
config TI_DRA7_THERMAL
bool "Temperature sensor driver for TI dra7xx SOCs"
help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index cc75e387e4c..ef2929d1808 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -5,4 +5,5 @@
obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
+obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o
obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o
diff --git a/drivers/thermal/imx_scu_thermal.c b/drivers/thermal/imx_scu_thermal.c
new file mode 100644
index 00000000000..7e17377b696
--- /dev/null
+++ b/drivers/thermal/imx_scu_thermal.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <thermal.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <asm/arch/sci/sci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct imx_sc_thermal_plat {
+ int critical;
+ int alert;
+ int polling_delay;
+ int id;
+ bool zone_node;
+};
+
+static int read_temperature(struct udevice *dev, int *temp)
+{
+ s16 celsius;
+ s8 tenths;
+ int ret;
+
+ sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
+
+ struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+
+ if (!temp)
+ return -EINVAL;
+
+ ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
+ &celsius, &tenths);
+ if (ret) {
+ printf("Error: get temperature failed! (error = %d)\n", ret);
+ return ret;
+ }
+
+ *temp = celsius * 1000 + tenths * 100;
+
+ return 0;
+}
+
+int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
+{
+ struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+ int cpu_temp = 0;
+ int ret;
+
+ ret = read_temperature(dev, &cpu_temp);
+ if (ret)
+ return ret;
+
+ while (cpu_temp >= pdata->alert) {
+ printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)",
+ cpu_temp, pdata->alert, pdata->critical);
+ puts(" waiting...\n");
+ mdelay(pdata->polling_delay);
+ ret = read_temperature(dev, &cpu_temp);
+ if (ret)
+ return ret;
+ }
+
+ *temp = cpu_temp / 1000;
+
+ return 0;
+}
+
+static const struct dm_thermal_ops imx_sc_thermal_ops = {
+ .get_temp = imx_sc_thermal_get_temp,
+};
+
+static int imx_sc_thermal_probe(struct udevice *dev)
+{
+ debug("%s dev name %s\n", __func__, dev->name);
+ return 0;
+}
+
+static int imx_sc_thermal_bind(struct udevice *dev)
+{
+ struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+ int reg, ret;
+ int offset;
+ const char *name;
+ const void *prop;
+
+ debug("%s dev name %s\n", __func__, dev->name);
+
+ prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
+ NULL);
+ if (!prop)
+ return 0;
+
+ pdata->zone_node = 1;
+
+ reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
+ if (reg == 0) {
+ printf("%s: no temp sensor number provided!\n", __func__);
+ return -EINVAL;
+ }
+
+ offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
+ fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
+ /* Bind the subnode to this driver */
+ name = fdt_get_name(gd->fdt_blob, offset, NULL);
+
+ ret = device_bind_with_driver_data(dev, dev->driver, name,
+ dev->driver_data,
+ offset_to_ofnode(offset),
+ NULL);
+ if (ret)
+ printf("Error binding driver '%s': %d\n",
+ dev->driver->name, ret);
+ }
+ return 0;
+}
+
+static int imx_sc_thermal_ofdata_to_platdata(struct udevice *dev)
+{
+ struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
+ struct fdtdec_phandle_args args;
+ const char *type;
+ int ret;
+ int trips_np;
+
+ debug("%s dev name %s\n", __func__, dev->name);
+
+ if (pdata->zone_node)
+ return 0;
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
+ "thermal-sensors",
+ "#thermal-sensor-cells",
+ 0, 0, &args);
+ if (ret)
+ return ret;
+
+ if (args.node != dev_of_offset(dev->parent))
+ return -EFAULT;
+
+ if (args.args_count >= 1)
+ pdata->id = args.args[0];
+ else
+ pdata->id = 0;
+
+ debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
+
+ pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "polling-delay", 1000);
+
+ trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
+ "trips");
+ fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
+ type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
+ if (type) {
+ if (strcmp(type, "critical") == 0) {
+ pdata->critical = fdtdec_get_int(gd->fdt_blob,
+ trips_np,
+ "temperature",
+ 85);
+ } else if (strcmp(type, "passive") == 0) {
+ pdata->alert = fdtdec_get_int(gd->fdt_blob,
+ trips_np,
+ "temperature",
+ 80);
+ }
+ }
+ }
+
+ debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
+ pdata->polling_delay, pdata->critical, pdata->alert);
+
+ return 0;
+}
+
+static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
+ SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
+ SC_R_PMIC_1, SC_R_PMIC_2,
+};
+
+static const struct udevice_id imx_sc_thermal_ids[] = {
+ { .compatible = "nxp,imx8qxp-sc-tsens", .data =
+ (ulong)&imx8qxp_sensor_rsrc, },
+ { }
+};
+
+U_BOOT_DRIVER(imx_sc_thermal) = {
+ .name = "imx_sc_thermal",
+ .id = UCLASS_THERMAL,
+ .ops = &imx_sc_thermal_ops,
+ .of_match = imx_sc_thermal_ids,
+ .bind = imx_sc_thermal_bind,
+ .probe = imx_sc_thermal_probe,
+ .ofdata_to_platdata = imx_sc_thermal_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct imx_sc_thermal_plat),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 12ee6eb8043..97a4c748518 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -48,6 +48,10 @@ static int timer_pre_probe(struct udevice *dev)
int err;
ulong ret;
+ /* It is possible that a timer device has a null ofnode */
+ if (!dev_of_valid(dev))
+ return 0;
+
err = clk_get_by_index(dev, 0, &timer_clk);
if (!err) {
ret = clk_get_rate(&timer_clk);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b1188bcbf52..ac68aa2d276 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -24,6 +24,7 @@ config USB_XHCI_DWC3
config USB_XHCI_DWC3_OF_SIMPLE
bool "DesignWare USB3 DRD Generic OF Simple Glue Layer"
depends on DM_USB
+ default y if ARCH_ROCKCHIP
default y if DRA7XX
help
Support USB2/3 functionality in simple SoC integrations with
diff --git a/drivers/usb/host/dwc3-of-simple.c b/drivers/usb/host/dwc3-of-simple.c
index b118997f6ee..45df614b094 100644
--- a/drivers/usb/host/dwc3-of-simple.c
+++ b/drivers/usb/host/dwc3-of-simple.c
@@ -92,6 +92,7 @@ static int dwc3_of_simple_remove(struct udevice *dev)
static const struct udevice_id dwc3_of_simple_ids[] = {
{ .compatible = "amlogic,meson-gxl-dwc3" },
+ { .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "ti,dwc3" },
{ }
};
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c
index 83b9f119e71..9e8cae7ae44 100644
--- a/drivers/usb/host/xhci-dwc3.c
+++ b/drivers/usb/host/xhci-dwc3.c
@@ -118,6 +118,8 @@ static int xhci_dwc3_probe(struct udevice *dev)
struct dwc3 *dwc3_reg;
enum usb_dr_mode dr_mode;
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
+ const char *phy;
+ u32 reg;
int ret;
hccr = (struct xhci_hccr *)((uintptr_t)dev_read_addr(dev));
@@ -132,6 +134,24 @@ static int xhci_dwc3_probe(struct udevice *dev)
dwc3_core_init(dwc3_reg);
+ /* Set dwc3 usb2 phy config */
+ reg = readl(&dwc3_reg->g_usb2phycfg[0]);
+
+ phy = dev_read_string(dev, "phy_type");
+ if (phy && strcmp(phy, "utmi_wide") == 0) {
+ reg |= DWC3_GUSB2PHYCFG_PHYIF;
+ reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK;
+ reg |= DWC3_GUSB2PHYCFG_USBTRDTIM_16BIT;
+ }
+
+ if (dev_read_bool(dev, "snps,dis_enblslpm-quirk"))
+ reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+ if (dev_read_bool(dev, "snps,dis-u2-freeclk-exists-quirk"))
+ reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
+ writel(reg, &dwc3_reg->g_usb2phycfg[0]);
+
dr_mode = usb_get_dr_mode(dev_of_offset(dev));
if (dr_mode == USB_DR_MODE_UNKNOWN)
/* by default set dual role mode to HOST */
diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c
index f19bea3a91b..e7b0dbcca5d 100644
--- a/drivers/usb/host/xhci-rockchip.c
+++ b/drivers/usb/host/xhci-rockchip.c
@@ -167,7 +167,6 @@ static int xhci_usb_remove(struct udevice *dev)
}
static const struct udevice_id xhci_usb_ids[] = {
- { .compatible = "rockchip,rk3399-xhci" },
{ .compatible = "rockchip,rk3328-xhci" },
{ }
};
@@ -187,7 +186,6 @@ U_BOOT_DRIVER(usb_xhci) = {
};
static const struct udevice_id usb_phy_ids[] = {
- { .compatible = "rockchip,rk3399-usb3-phy" },
{ .compatible = "rockchip,rk3328-usb3-phy" },
{ }
};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index c3781b160d9..261fa985171 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -484,7 +484,7 @@ config VIDEO_IVYBRIDGE_IGD
config VIDEO_FSL_DCU_FB
bool "Enable Freescale Display Control Unit"
- depends on VIDEO
+ depends on VIDEO || DM_VIDEO
help
This enables support for Freescale Display Control Unit (DCU4)
module found on Freescale Vybrid and QorIQ family of SoCs.
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c
index bc41090aed7..1d2eda084c8 100644
--- a/drivers/video/bcm2835.c
+++ b/drivers/video/bcm2835.c
@@ -19,13 +19,15 @@ static int bcm2835_video_probe(struct udevice *dev)
debug("bcm2835: Query resolution...\n");
ret = bcm2835_get_video_size(&w, &h);
- if (ret)
+ if (ret || w == 0 || h == 0)
return -EIO;
debug("bcm2835: Setting up display for %d x %d\n", w, h);
ret = bcm2835_set_video_params(&w, &h, 32, BCM2835_MBOX_PIXEL_ORDER_RGB,
BCM2835_MBOX_ALPHA_MODE_IGNORED,
&fb_base, &fb_size, &pitch);
+ if (ret)
+ return -EIO;
debug("bcm2835: Final resolution is %d x %d\n", w, h);
diff --git a/drivers/video/display-uclass.c b/drivers/video/display-uclass.c
index 99ef5e76f54..1a29ce5d858 100644
--- a/drivers/video/display-uclass.c
+++ b/drivers/video/display-uclass.c
@@ -37,6 +37,17 @@ int display_enable(struct udevice *dev, int panel_bpp,
return 0;
}
+static bool display_mode_valid(void *priv, const struct display_timing *timing)
+{
+ struct udevice *dev = priv;
+ struct dm_display_ops *ops = display_get_ops(dev);
+
+ if (ops && ops->mode_valid)
+ return ops->mode_valid(dev, timing);
+
+ return true;
+}
+
int display_read_timing(struct udevice *dev, struct display_timing *timing)
{
struct dm_display_ops *ops = display_get_ops(dev);
@@ -53,7 +64,9 @@ int display_read_timing(struct udevice *dev, struct display_timing *timing)
if (ret < 0)
return ret;
- return edid_get_timing(buf, ret, timing, &panel_bits_per_colour);
+ return edid_get_timing_validate(buf, ret, timing,
+ &panel_bits_per_colour,
+ display_mode_valid, dev);
}
bool display_in_use(struct udevice *dev)
diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c
index 463436edf3e..bf74d6adf20 100644
--- a/drivers/video/dw_hdmi.c
+++ b/drivers/video/dw_hdmi.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <fdtdec.h>
#include <asm/io.h>
+#include <i2c.h>
#include <media_bus_format.h>
#include "dw_hdmi.h"
@@ -812,6 +813,18 @@ static int hdmi_read_edid(struct dw_hdmi *hdmi, int block, u8 *buff)
u32 trytime = 5;
u32 n;
+ if (CONFIG_IS_ENABLED(DM_I2C) && hdmi->ddc_bus) {
+ struct udevice *chip;
+
+ edid_read_err = i2c_get_chip(hdmi->ddc_bus,
+ HDMI_I2CM_SLAVE_DDC_ADDR,
+ 1, &chip);
+ if (edid_read_err)
+ return edid_read_err;
+
+ return dm_i2c_read(chip, shift, buff, HDMI_EDID_BLOCK_SIZE);
+ }
+
/* set ddc i2c clk which devided from ddc_clk to 100khz */
hdmi_write(hdmi, hdmi->i2c_clk_high, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
hdmi_write(hdmi, hdmi->i2c_clk_low, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c
index 9f6e7f83b0f..add64b85b59 100644
--- a/drivers/video/fsl_dcu_fb.c
+++ b/drivers/video/fsl_dcu_fb.c
@@ -1,16 +1,19 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2014 Freescale Semiconductor, Inc.
+ * Copyright 2019 Toradex AG
*
* FSL DCU Framebuffer driver
*/
#include <asm/io.h>
#include <common.h>
+#include <dm.h>
#include <fdt_support.h>
#include <fsl_dcu_fb.h>
#include <linux/fb.h>
#include <malloc.h>
+#include <video.h>
#include <video_fb.h>
#include "videomodes.h"
@@ -218,8 +221,6 @@ struct dcu_reg {
u32 ctrldescl[DCU_LAYER_MAX_NUM][16];
};
-static struct fb_info info;
-
static void reset_total_layers(void)
{
struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
@@ -240,20 +241,22 @@ static void reset_total_layers(void)
}
}
-static int layer_ctrldesc_init(int index, u32 pixel_format)
+static int layer_ctrldesc_init(struct fb_info fbinfo,
+ int index, u32 pixel_format)
{
struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
unsigned int bpp = BPP_24_RGB888;
dcu_write32(&regs->ctrldescl[index][0],
- DCU_CTRLDESCLN_1_HEIGHT(info.var.yres) |
- DCU_CTRLDESCLN_1_WIDTH(info.var.xres));
+ DCU_CTRLDESCLN_1_HEIGHT(fbinfo.var.yres) |
+ DCU_CTRLDESCLN_1_WIDTH(fbinfo.var.xres));
dcu_write32(&regs->ctrldescl[index][1],
DCU_CTRLDESCLN_2_POSY(0) |
DCU_CTRLDESCLN_2_POSX(0));
- dcu_write32(&regs->ctrldescl[index][2], (unsigned int)info.screen_base);
+ dcu_write32(&regs->ctrldescl[index][2],
+ (unsigned int)fbinfo.screen_base);
switch (pixel_format) {
case 16:
@@ -294,42 +297,46 @@ static int layer_ctrldesc_init(int index, u32 pixel_format)
return 0;
}
-int fsl_dcu_init(unsigned int xres, unsigned int yres,
- unsigned int pixel_format)
+int fsl_dcu_init(struct fb_info *fbinfo, unsigned int xres,
+ unsigned int yres, unsigned int pixel_format)
{
struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
unsigned int div, mode;
+/*
+ * When DM_VIDEO is enabled reservation of framebuffer is done
+ * in advance during bind() call.
+ */
+#if !CONFIG_IS_ENABLED(DM_VIDEO)
+ fbinfo->screen_size = fbinfo->var.xres * fbinfo->var.yres *
+ (fbinfo->var.bits_per_pixel / 8);
- info.screen_size =
- info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
-
- if (info.screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) {
- info.screen_size = 0;
+ if (fbinfo->screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) {
+ fbinfo->screen_size = 0;
return -ENOMEM;
}
-
/* Reserve framebuffer at the end of memory */
gd->fb_base = gd->bd->bi_dram[0].start +
- gd->bd->bi_dram[0].size - info.screen_size;
- info.screen_base = (char *)gd->fb_base;
+ gd->bd->bi_dram[0].size - fbinfo->screen_size;
+ fbinfo->screen_base = (char *)gd->fb_base;
- memset(info.screen_base, 0, info.screen_size);
+ memset(fbinfo->screen_base, 0, fbinfo->screen_size);
+#endif
reset_total_layers();
dcu_write32(&regs->disp_size,
- DCU_DISP_SIZE_DELTA_Y(info.var.yres) |
- DCU_DISP_SIZE_DELTA_X(info.var.xres / 16));
+ DCU_DISP_SIZE_DELTA_Y(fbinfo->var.yres) |
+ DCU_DISP_SIZE_DELTA_X(fbinfo->var.xres / 16));
dcu_write32(&regs->hsyn_para,
- DCU_HSYN_PARA_BP(info.var.left_margin) |
- DCU_HSYN_PARA_PW(info.var.hsync_len) |
- DCU_HSYN_PARA_FP(info.var.right_margin));
+ DCU_HSYN_PARA_BP(fbinfo->var.left_margin) |
+ DCU_HSYN_PARA_PW(fbinfo->var.hsync_len) |
+ DCU_HSYN_PARA_FP(fbinfo->var.right_margin));
dcu_write32(&regs->vsyn_para,
- DCU_VSYN_PARA_BP(info.var.upper_margin) |
- DCU_VSYN_PARA_PW(info.var.vsync_len) |
- DCU_VSYN_PARA_FP(info.var.lower_margin));
+ DCU_VSYN_PARA_BP(fbinfo->var.upper_margin) |
+ DCU_VSYN_PARA_PW(fbinfo->var.vsync_len) |
+ DCU_VSYN_PARA_FP(fbinfo->var.lower_margin));
dcu_write32(&regs->synpol,
DCU_SYN_POL_INV_PXCK_FALL |
@@ -352,9 +359,9 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres,
mode = dcu_read32(&regs->mode);
dcu_write32(&regs->mode, mode | DCU_MODE_NORMAL);
- layer_ctrldesc_init(0, pixel_format);
+ layer_ctrldesc_init(*fbinfo, 0, pixel_format);
- div = dcu_set_pixel_clock(info.var.pixclock);
+ div = dcu_set_pixel_clock(fbinfo->var.pixclock);
dcu_write32(&regs->div_ratio, (div - 1));
dcu_write32(&regs->update_mode, DCU_UPDATE_MODE_READREG);
@@ -367,24 +374,26 @@ ulong board_get_usable_ram_top(ulong total_size)
return gd->ram_top - CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB;
}
-void *video_hw_init(void)
+int fsl_probe_common(struct fb_info *fbinfo, unsigned int *win_x,
+ unsigned int *win_y)
{
- static GraphicDevice ctfb;
const char *options;
unsigned int depth = 0, freq = 0;
+
struct fb_videomode *fsl_dcu_mode_db = &fsl_dcu_mode_480_272;
- if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
+ if (!video_get_video_mode(win_x, win_y, &depth, &freq,
&options))
- return NULL;
+ return -EINVAL;
/* Find the monitor port, which is a required option */
if (!options)
- return NULL;
+ return -EINVAL;
+
if (strncmp(options, "monitor=", 8) != 0)
- return NULL;
+ return -EINVAL;
- switch (RESOLUTION(ctfb.winSizeX, ctfb.winSizeY)) {
+ switch (RESOLUTION(*win_x, *win_y)) {
case RESOLUTION(480, 272):
fsl_dcu_mode_db = &fsl_dcu_mode_480_272;
break;
@@ -402,39 +411,31 @@ void *video_hw_init(void)
break;
default:
printf("unsupported resolution %ux%u\n",
- ctfb.winSizeX, ctfb.winSizeY);
+ *win_x, *win_y);
}
- info.var.xres = fsl_dcu_mode_db->xres;
- info.var.yres = fsl_dcu_mode_db->yres;
- info.var.bits_per_pixel = 32;
- info.var.pixclock = fsl_dcu_mode_db->pixclock;
- info.var.left_margin = fsl_dcu_mode_db->left_margin;
- info.var.right_margin = fsl_dcu_mode_db->right_margin;
- info.var.upper_margin = fsl_dcu_mode_db->upper_margin;
- info.var.lower_margin = fsl_dcu_mode_db->lower_margin;
- info.var.hsync_len = fsl_dcu_mode_db->hsync_len;
- info.var.vsync_len = fsl_dcu_mode_db->vsync_len;
- info.var.sync = fsl_dcu_mode_db->sync;
- info.var.vmode = fsl_dcu_mode_db->vmode;
- info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8;
-
- if (platform_dcu_init(ctfb.winSizeX, ctfb.winSizeY,
- options + 8, fsl_dcu_mode_db) < 0)
- return NULL;
-
- ctfb.frameAdrs = (unsigned int)info.screen_base;
- ctfb.plnSizeX = ctfb.winSizeX;
- ctfb.plnSizeY = ctfb.winSizeY;
-
- ctfb.gdfBytesPP = 4;
- ctfb.gdfIndex = GDF_32BIT_X888RGB;
-
- ctfb.memSize = info.screen_size;
-
- return &ctfb;
+ fbinfo->var.xres = fsl_dcu_mode_db->xres;
+ fbinfo->var.yres = fsl_dcu_mode_db->yres;
+ fbinfo->var.bits_per_pixel = 32;
+ fbinfo->var.pixclock = fsl_dcu_mode_db->pixclock;
+ fbinfo->var.left_margin = fsl_dcu_mode_db->left_margin;
+ fbinfo->var.right_margin = fsl_dcu_mode_db->right_margin;
+ fbinfo->var.upper_margin = fsl_dcu_mode_db->upper_margin;
+ fbinfo->var.lower_margin = fsl_dcu_mode_db->lower_margin;
+ fbinfo->var.hsync_len = fsl_dcu_mode_db->hsync_len;
+ fbinfo->var.vsync_len = fsl_dcu_mode_db->vsync_len;
+ fbinfo->var.sync = fsl_dcu_mode_db->sync;
+ fbinfo->var.vmode = fsl_dcu_mode_db->vmode;
+ fbinfo->fix.line_length = fbinfo->var.xres *
+ fbinfo->var.bits_per_pixel / 8;
+
+ return platform_dcu_init(fbinfo, *win_x, *win_y,
+ options + 8, fsl_dcu_mode_db);
}
+#ifndef CONFIG_DM_VIDEO
+static struct fb_info info;
+
#if defined(CONFIG_OF_BOARD_SETUP)
int fsl_dcu_fixedfb_setup(void *blob)
{
@@ -457,3 +458,89 @@ int fsl_dcu_fixedfb_setup(void *blob)
return 0;
}
#endif
+
+void *video_hw_init(void)
+{
+ static GraphicDevice ctfb;
+
+ if (fsl_probe_common(&info, &ctfb.winSizeX, &ctfb.winSizeY) < 0)
+ return NULL;
+
+ ctfb.frameAdrs = (unsigned int)info.screen_base;
+ ctfb.plnSizeX = ctfb.winSizeX;
+ ctfb.plnSizeY = ctfb.winSizeY;
+
+ ctfb.gdfBytesPP = 4;
+ ctfb.gdfIndex = GDF_32BIT_X888RGB;
+
+ ctfb.memSize = info.screen_size;
+
+ return &ctfb;
+}
+
+#else /* ifndef CONFIG_DM_VIDEO */
+
+static int fsl_dcu_video_probe(struct udevice *dev)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct fb_info fbinfo = { 0 };
+ unsigned int win_x;
+ unsigned int win_y;
+ u32 fb_start, fb_end;
+ int ret = 0;
+
+ fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
+ fb_end = plat->base + plat->size;
+ fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
+
+ fbinfo.screen_base = (char *)fb_start;
+ fbinfo.screen_size = plat->size;
+
+ ret = fsl_probe_common(&fbinfo, &win_x, &win_y);
+ if (ret < 0)
+ return ret;
+
+ uc_priv->bpix = VIDEO_BPP32;
+ uc_priv->xsize = win_x;
+ uc_priv->ysize = win_y;
+
+ /* Enable dcache for the frame buffer */
+ mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
+ DCACHE_WRITEBACK);
+ video_set_flush_dcache(dev, true);
+ return ret;
+}
+
+static int fsl_dcu_video_bind(struct udevice *dev)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ unsigned int win_x;
+ unsigned int win_y;
+ unsigned int depth = 0, freq = 0;
+ const char *options;
+ int ret = 0;
+
+ ret = video_get_video_mode(&win_x, &win_y, &depth, &freq, &options);
+ if (ret < 0)
+ return ret;
+
+ plat->size = win_x * win_y * 32;
+
+ return 0;
+}
+
+static const struct udevice_id fsl_dcu_video_ids[] = {
+ { .compatible = "fsl,vf610-dcu" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(fsl_dcu_video) = {
+ .name = "fsl_dcu_video",
+ .id = UCLASS_VIDEO,
+ .of_match = fsl_dcu_video_ids,
+ .bind = fsl_dcu_video_bind,
+ .probe = fsl_dcu_video_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#endif /* ifndef CONFIG_DM_VIDEO */
diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c
index 483c93f6b6c..9831d978fca 100644
--- a/drivers/video/meson/meson_dw_hdmi.c
+++ b/drivers/video/meson/meson_dw_hdmi.c
@@ -375,6 +375,9 @@ static int meson_dw_hdmi_probe(struct udevice *dev)
}
#endif
+ uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
+ &priv->hdmi.ddc_bus);
+
ret = reset_get_bulk(dev, &resets);
if (ret)
return ret;
@@ -426,9 +429,16 @@ static int meson_dw_hdmi_probe(struct udevice *dev)
return ret;
}
+static bool meson_dw_hdmi_mode_valid(struct udevice *dev,
+ const struct display_timing *timing)
+{
+ return meson_venc_hdmi_supported_mode(timing);
+}
+
static const struct dm_display_ops meson_dw_hdmi_ops = {
.read_edid = meson_dw_hdmi_read_edid,
.enable = meson_dw_hdmi_enable,
+ .mode_valid = meson_dw_hdmi_mode_valid,
};
static const struct udevice_id meson_dw_hdmi_ids[] = {
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index f02ba201384..6c9a7c05e82 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -271,6 +271,42 @@ dealloc_fb:
}
#else /* ifndef CONFIG_DM_VIDEO */
+static int mxs_of_get_timings(struct udevice *dev,
+ struct display_timing *timings,
+ u32 *bpp)
+{
+ int ret = 0;
+ u32 display_phandle;
+ ofnode display_node;
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "display", &display_phandle);
+ if (ret) {
+ dev_err(dev, "required display property isn't provided\n");
+ return -EINVAL;
+ }
+
+ display_node = ofnode_get_by_phandle(display_phandle);
+ if (!ofnode_valid(display_node)) {
+ dev_err(dev, "failed to find display subnode\n");
+ return -EINVAL;
+ }
+
+ ret = ofnode_read_u32(display_node, "bits-per-pixel", bpp);
+ if (ret) {
+ dev_err(dev,
+ "required bits-per-pixel property isn't provided\n");
+ return -EINVAL;
+ }
+
+ ret = ofnode_decode_display_timing(display_node, 0, timings);
+ if (ret) {
+ dev_err(dev, "failed to get any display timings\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
static int mxs_video_probe(struct udevice *dev)
{
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
@@ -278,18 +314,16 @@ static int mxs_video_probe(struct udevice *dev)
struct ctfb_res_modes mode;
struct display_timing timings;
- int bpp = -1;
+ u32 bpp = 0;
u32 fb_start, fb_end;
int ret;
debug("%s() plat: base 0x%lx, size 0x%x\n",
__func__, plat->base, plat->size);
- ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings);
- if (ret) {
- dev_err(dev, "failed to get any display timings\n");
- return -EINVAL;
- }
+ ret = mxs_of_get_timings(dev, &timings, &bpp);
+ if (ret)
+ return ret;
mode.xres = timings.hactive.typ;
mode.yres = timings.vactive.typ;
@@ -301,13 +335,12 @@ static int mxs_video_probe(struct udevice *dev)
mode.vsync_len = timings.vsync_len.typ;
mode.pixclock = HZ2PS(timings.pixelclock.typ);
- bpp = BITS_PP;
-
ret = mxs_probe_common(&mode, bpp, plat->base);
if (ret)
return ret;
switch (bpp) {
+ case 32:
case 24:
case 18:
uc_priv->bpix = VIDEO_BPP32;
@@ -341,15 +374,32 @@ static int mxs_video_bind(struct udevice *dev)
{
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
struct display_timing timings;
+ u32 bpp = 0;
+ u32 bytes_pp = 0;
int ret;
- ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings);
- if (ret) {
- dev_err(dev, "failed to get any display timings\n");
+ ret = mxs_of_get_timings(dev, &timings, &bpp);
+ if (ret)
+ return ret;
+
+ switch (bpp) {
+ case 32:
+ case 24:
+ case 18:
+ bytes_pp = 4;
+ break;
+ case 16:
+ bytes_pp = 2;
+ break;
+ case 8:
+ bytes_pp = 1;
+ break;
+ default:
+ dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp);
return -EINVAL;
}
- plat->size = timings.hactive.typ * timings.vactive.typ * BYTES_PP;
+ plat->size = timings.hactive.typ * timings.vactive.typ * bytes_pp;
return 0;
}
diff --git a/drivers/video/rockchip/rk3288_hdmi.c b/drivers/video/rockchip/rk3288_hdmi.c
index 315d3adf275..3d25ce924c2 100644
--- a/drivers/video/rockchip/rk3288_hdmi.c
+++ b/drivers/video/rockchip/rk3288_hdmi.c
@@ -33,7 +33,7 @@ static int rk3288_hdmi_enable(struct udevice *dev, int panel_bpp,
/* hdmi data from vop id */
rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0);
- return 0;
+ return dw_hdmi_enable(&priv->hdmi, edid);
}
static int rk3288_hdmi_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c
index 51931ceefae..5b44a7e8c97 100644
--- a/drivers/video/rockchip/rk_hdmi.c
+++ b/drivers/video/rockchip/rk_hdmi.c
@@ -93,6 +93,9 @@ int rk_hdmi_ofdata_to_platdata(struct udevice *dev)
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
+ &hdmi->ddc_bus);
+
return 0;
}
diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c
index 7a968e740c5..c3c0e847327 100644
--- a/drivers/video/simple_panel.c
+++ b/drivers/video/simple_panel.c
@@ -105,6 +105,7 @@ static const struct udevice_id simple_panel_ids[] = {
{ .compatible = "auo,b133xtn01" },
{ .compatible = "auo,b116xw03" },
{ .compatible = "auo,b133htn01" },
+ { .compatible = "lg,lb070wv8" },
{ }
};
diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 6fe1aa7ee46..cec23295b5c 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -373,6 +373,9 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
priv->mux = uc_plat->source_id;
+ uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
+ &priv->hdmi.ddc_bus);
+
dw_hdmi_init(&priv->hdmi);
return 0;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ee0ddffe735..ccda432f49a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -28,7 +28,7 @@ config BCM2835_WDT
config IMX_WATCHDOG
bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
- select HW_WATCHDOG
+ select HW_WATCHDOG if !WDT
help
Select this to enable the IMX and LSCH2 of Layerscape watchdog
driver.
@@ -169,4 +169,11 @@ config WDT_TANGIER
Intel Tangier SoC. If you're using a board with Intel Tangier
SoC, say Y here.
+config SPL_WDT
+ bool "Enable driver model for watchdog timer drivers in SPL"
+ depends on SPL_DM
+ help
+ Enable driver model for watchdog timer in SPL.
+ This is similar to CONFIG_WDT in U-Boot.
+
endmenu
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 68c989aa0b9..97aa6a836ce 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
-obj-$(CONFIG_WDT) += wdt-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o
obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 14cc618074b..53a3e9f5c78 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -5,7 +5,9 @@
*/
#include <common.h>
+#include <dm.h>
#include <asm/io.h>
+#include <wdt.h>
#include <watchdog.h>
#include <asm/arch/imx-regs.h>
#ifdef CONFIG_FSL_LSCH2
@@ -13,20 +15,40 @@
#endif
#include <fsl_wdog.h>
-#ifdef CONFIG_IMX_WATCHDOG
-void hw_watchdog_reset(void)
+static void imx_watchdog_expire_now(struct watchdog_regs *wdog)
+{
+ clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
+
+ writew(0x5555, &wdog->wsr);
+ writew(0xaaaa, &wdog->wsr); /* load minimum 1/2 second timeout */
+ while (1) {
+ /*
+ * spin for .5 seconds before reset
+ */
+ }
+}
+
+#if !defined(CONFIG_IMX_WATCHDOG) || \
+ (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
+void __attribute__((weak)) reset_cpu(ulong addr)
{
-#ifndef CONFIG_WATCHDOG_RESET_DISABLE
struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
+ imx_watchdog_expire_now(wdog);
+}
+#endif
+
+#if defined(CONFIG_IMX_WATCHDOG)
+static void imx_watchdog_reset(struct watchdog_regs *wdog)
+{
+#ifndef CONFIG_WATCHDOG_RESET_DISABLE
writew(0x5555, &wdog->wsr);
writew(0xaaaa, &wdog->wsr);
#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
}
-void hw_watchdog_init(void)
+static void imx_watchdog_init(struct watchdog_regs *wdog)
{
- struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
u16 timeout;
/*
@@ -44,21 +66,86 @@ void hw_watchdog_init(void)
writew(WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_WDT | WCR_SRS |
WCR_WDA | SET_WCR_WT(timeout), &wdog->wcr);
#endif /* CONFIG_FSL_LSCH2*/
- hw_watchdog_reset();
+ imx_watchdog_reset(wdog);
}
-#endif
-void __attribute__((weak)) reset_cpu(ulong addr)
+#if !CONFIG_IS_ENABLED(WDT)
+void hw_watchdog_reset(void)
{
struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
- clrsetbits_le16(&wdog->wcr, WCR_WT_MSK, WCR_WDE);
+ imx_watchdog_reset(wdog);
+}
- writew(0x5555, &wdog->wsr);
- writew(0xaaaa, &wdog->wsr); /* load minimum 1/2 second timeout */
- while (1) {
- /*
- * spin for .5 seconds before reset
- */
- }
+void hw_watchdog_init(void)
+{
+ struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
+
+ imx_watchdog_init(wdog);
+}
+#else
+struct imx_wdt_priv {
+ void __iomem *base;
+};
+
+static int imx_wdt_reset(struct udevice *dev)
+{
+ struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+ imx_watchdog_reset(priv->base);
+
+ return 0;
+}
+
+static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+ struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+ imx_watchdog_expire_now(priv->base);
+ hang();
+
+ return 0;
+}
+
+static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+ imx_watchdog_init(priv->base);
+
+ return 0;
+}
+
+static int imx_wdt_probe(struct udevice *dev)
+{
+ struct imx_wdt_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base)
+ return -ENOENT;
+
+ return 0;
}
+
+static const struct wdt_ops imx_wdt_ops = {
+ .start = imx_wdt_start,
+ .reset = imx_wdt_reset,
+ .expire_now = imx_wdt_expire_now,
+};
+
+static const struct udevice_id imx_wdt_ids[] = {
+ { .compatible = "fsl,imx21-wdt" },
+ {}
+};
+
+U_BOOT_DRIVER(imx_wdt) = {
+ .name = "imx_wdt",
+ .id = UCLASS_WDT,
+ .of_match = imx_wdt_ids,
+ .probe = imx_wdt_probe,
+ .ops = &imx_wdt_ops,
+ .priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#endif
+#endif