summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/clk-divider.c30
-rw-r--r--drivers/clk/clk-gate.c12
-rw-r--r--drivers/clk/clk-mux.c11
-rw-r--r--drivers/clk/imx/Makefile1
-rw-r--r--drivers/clk/imx/clk-composite-8m.c171
-rw-r--r--drivers/clk/imx/clk-imx5.c3
-rw-r--r--drivers/clk/imx/clk-imx8mq.c535
-rw-r--r--drivers/clk/imx/clk.h19
-rw-r--r--drivers/clocksource/Kconfig6
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/clps711x.c23
-rw-r--r--drivers/clocksource/timer-atmel-pit.c2
-rw-r--r--drivers/clocksource/timer-ti-32k.c106
-rw-r--r--drivers/clocksource/timer-ti-dm.c119
-rw-r--r--drivers/crypto/Kconfig1
-rw-r--r--drivers/gpio/gpio-clps711x.c19
-rw-r--r--drivers/led/core.c11
-rw-r--r--drivers/mci/dw_mmc.c3
-rw-r--r--drivers/mci/imx-esdhc.c4
-rw-r--r--drivers/mci/mci-core.c31
-rw-r--r--drivers/mci/mxs.c6
-rw-r--r--drivers/mci/omap_hsmmc.c43
-rw-r--r--drivers/mci/tegra-sdmmc.c3
-rw-r--r--drivers/mfd/rave-sp.c80
-rw-r--r--drivers/mfd/syscon.c2
-rw-r--r--drivers/mtd/core.c25
-rw-r--r--drivers/mtd/nand/atmel_nand.c3
-rw-r--r--drivers/mtd/nand/nand_base.c277
-rw-r--r--drivers/mtd/nand/nand_bbt.c396
-rw-r--r--drivers/mtd/nand/nand_bch.c27
-rw-r--r--drivers/mtd/nand/nand_imx_bbm.c2
-rw-r--r--drivers/mtd/nand/nand_mxs.c27
-rw-r--r--drivers/mtd/nand/nand_omap_gpmc.c142
-rw-r--r--drivers/net/davinci_emac.c210
-rw-r--r--drivers/net/e1000/e1000.h24
-rw-r--r--drivers/net/e1000/main.c98
-rw-r--r--drivers/net/fec_imx.c10
-rw-r--r--drivers/net/ks8851_mll.c2
-rw-r--r--drivers/net/macb.c27
-rw-r--r--drivers/net/macb.h2
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/dp83867.c323
-rw-r--r--drivers/nvmem/ocotp.c22
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/pci-imx6.c368
-rw-r--r--drivers/pci/pci-mvebu-phy.c5
-rw-r--r--drivers/pci/pci-mvebu.c5
-rw-r--r--drivers/pci/pci-mvebu.h5
-rw-r--r--drivers/pci/pci-tegra.c13
-rw-r--r--drivers/pci/pcie-designware-host.c416
-rw-r--r--drivers/pci/pcie-designware.c580
-rw-r--r--drivers/pci/pcie-designware.h188
-rw-r--r--drivers/pinctrl/imx-iomux-v3.c4
-rw-r--r--drivers/serial/amba-pl011.c4
-rw-r--r--drivers/serial/serial_clps711x.c25
-rw-r--r--drivers/spi/imx_spi.c11
-rw-r--r--drivers/usb/gadget/dfu.c5
-rw-r--r--drivers/usb/gadget/f_fastboot.c236
-rw-r--r--drivers/video/mtl017.c7
-rw-r--r--drivers/video/rave-sp-backlight.c2
-rw-r--r--drivers/w1/w1.c2
62 files changed, 3023 insertions, 1721 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 791e10ea99..7b1bdde1ce 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/log2.h>
+#include <asm-generic/div64.h>
#define div_mask(d) ((1 << ((d)->width)) - 1)
@@ -56,17 +57,17 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
return 0;
}
-static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags, u8 width)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return val;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
- if (divider->table)
- return _get_table_div(divider->table, val);
+ if (table)
+ return _get_table_div(table, val);
return val + 1;
}
-
static unsigned int _get_table_val(const struct clk_div_table *table,
unsigned int div)
{
@@ -89,6 +90,18 @@ static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
return div - 1;
}
+unsigned long divider_recalc_rate(struct clk *clk, 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);
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, div);
+}
+
static unsigned long clk_divider_recalc_rate(struct clk *clk,
unsigned long parent_rate)
{
@@ -98,9 +111,10 @@ static unsigned long clk_divider_recalc_rate(struct clk *clk,
val = readl(divider->reg) >> divider->shift;
val &= div_mask(divider);
- div = _get_div(divider, val);
+ div = _get_div(divider->table, val, divider->flags, divider->width);
- return parent_rate / div;
+ return divider_recalc_rate(clk, parent_rate, val, divider->table,
+ divider->flags, divider->width);
}
/*
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 695e19ab54..89240ff794 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -20,16 +20,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-struct clk_gate {
- struct clk clk;
- void __iomem *reg;
- int shift;
- const char *parent;
- unsigned flags;
-};
-
-#define to_clk_gate(_clk) container_of(_clk, struct clk_gate, clk)
-
static void clk_gate_endisable(struct clk *clk, int enable)
{
struct clk_gate *gate = container_of(clk, struct clk_gate, clk);
@@ -79,7 +69,7 @@ static int clk_gate_is_enabled(struct clk *clk)
return g->flags & CLK_GATE_INVERTED ? 1 : 0;
}
-static struct clk_ops clk_gate_ops = {
+struct clk_ops clk_gate_ops = {
.set_rate = clk_parent_set_rate,
.round_rate = clk_parent_round_rate,
.enable = clk_gate_enable,
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 22e131faae..d5fe640dce 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -20,15 +20,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-struct clk_mux {
- struct clk clk;
- void __iomem *reg;
- int shift;
- int width;
-};
-
-#define to_clk_mux(_clk) container_of(_clk, struct clk_mux, clk)
-
static int clk_mux_get_parent(struct clk *clk)
{
struct clk_mux *m = container_of(clk, struct clk_mux, clk);
@@ -53,7 +44,7 @@ static int clk_mux_set_parent(struct clk *clk, u8 idx)
return 0;
}
-static struct clk_ops clk_mux_ops = {
+struct clk_ops clk_mux_ops = {
.set_rate = clk_parent_set_rate,
.round_rate = clk_parent_round_rate,
.get_parent = clk_mux_get_parent,
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 8f441a97e7..97ae97a2a9 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_COMMON_CLK) += \
+ clk-composite-8m.o \
clk-pllv1.o \
clk-pllv2.o \
clk-pllv3.o \
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
new file mode 100644
index 0000000000..0cd52b5b46
--- /dev/null
+++ b/drivers/clk/imx/clk-composite-8m.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+#define PCG_PREDIV_SHIFT 16
+#define PCG_PREDIV_WIDTH 3
+#define PCG_PREDIV_MAX 8
+
+#define PCG_DIV_SHIFT 0
+#define PCG_DIV_WIDTH 6
+#define PCG_DIV_MAX 64
+
+#define PCG_PCS_SHIFT 24
+#define PCG_PCS_WIDTH 3
+
+#define PCG_CGC_SHIFT 28
+
+#define clk_div_mask(width) ((1 << (width)) - 1)
+
+static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = container_of(clk, struct clk_divider, clk);
+ unsigned long prediv_rate;
+ unsigned int prediv_value;
+ unsigned int div_value;
+
+ prediv_value = readl(divider->reg) >> divider->shift;
+ prediv_value &= clk_div_mask(divider->width);
+
+ prediv_rate = divider_recalc_rate(clk, parent_rate, prediv_value,
+ NULL, divider->flags,
+ divider->width);
+
+ div_value = readl(divider->reg) >> PCG_DIV_SHIFT;
+ div_value &= clk_div_mask(PCG_DIV_WIDTH);
+
+ return divider_recalc_rate(clk, prediv_rate, div_value, NULL,
+ divider->flags, PCG_DIV_WIDTH);
+}
+
+static int imx8m_clk_composite_compute_dividers(unsigned long rate,
+ unsigned long parent_rate,
+ int *prediv, int *postdiv)
+{
+ int div1, div2;
+ int error = INT_MAX;
+ int ret = -EINVAL;
+
+ *prediv = 1;
+ *postdiv = 1;
+
+ for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) {
+ for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) {
+ int new_error = ((parent_rate / div1) / div2) - rate;
+
+ if (abs(new_error) < abs(error)) {
+ *prediv = div1;
+ *postdiv = div2;
+ error = new_error;
+ ret = 0;
+ }
+ }
+ }
+ return ret;
+}
+
+static long imx8m_clk_composite_divider_round_rate(struct clk *clk,
+ unsigned long rate,
+ unsigned long *prate)
+{
+ int prediv_value;
+ int div_value;
+
+ imx8m_clk_composite_compute_dividers(rate, *prate,
+ &prediv_value, &div_value);
+ rate = DIV_ROUND_UP(*prate, prediv_value);
+
+ return DIV_ROUND_UP(rate, div_value);
+
+}
+
+static int imx8m_clk_composite_divider_set_rate(struct clk *clk,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = container_of(clk, struct clk_divider, clk);
+ int prediv_value;
+ int div_value;
+ int ret;
+ u32 val;
+
+ ret = imx8m_clk_composite_compute_dividers(rate, parent_rate,
+ &prediv_value, &div_value);
+ if (ret)
+ return -EINVAL;
+
+ val = readl(divider->reg);
+ val &= ~((clk_div_mask(divider->width) << divider->shift) |
+ (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
+
+ val |= (u32)(prediv_value - 1) << divider->shift;
+ val |= (u32)(div_value - 1) << PCG_DIV_SHIFT;
+ writel(val, divider->reg);
+
+ return ret;
+}
+
+static const struct clk_ops imx8m_clk_composite_divider_ops = {
+ .recalc_rate = imx8m_clk_composite_divider_recalc_rate,
+ .round_rate = imx8m_clk_composite_divider_round_rate,
+ .set_rate = imx8m_clk_composite_divider_set_rate,
+};
+
+struct clk *imx8m_clk_composite_flags(const char *name,
+ const char **parent_names,
+ int num_parents, void __iomem *reg,
+ unsigned long flags)
+{
+ struct clk *comp = ERR_PTR(-ENOMEM);
+ struct clk_divider *div = NULL;
+ struct clk_gate *gate = NULL;
+ struct clk_mux *mux = NULL;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ goto fail;
+
+ mux->reg = reg;
+ mux->shift = PCG_PCS_SHIFT;
+ mux->width = PCG_PCS_WIDTH;
+ mux->clk.ops = &clk_mux_ops;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ goto fail;
+
+ div->reg = reg;
+ div->shift = PCG_PREDIV_SHIFT;
+ div->width = PCG_PREDIV_WIDTH;
+ div->clk.ops = &imx8m_clk_composite_divider_ops;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto fail;
+
+ gate->reg = reg;
+ gate->shift = PCG_CGC_SHIFT;
+ gate->clk.ops = &clk_gate_ops;
+
+ comp = clk_register_composite(name, parent_names, num_parents,
+ &mux->clk, &div->clk, &gate->clk, flags);
+ if (IS_ERR(comp))
+ goto fail;
+
+ return comp;
+
+fail:
+ kfree(gate);
+ kfree(div);
+ kfree(mux);
+ return ERR_CAST(comp);
+}
diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c
index f59a41b001..69ac2f5e3e 100644
--- a/drivers/clk/imx/clk-imx5.c
+++ b/drivers/clk/imx/clk-imx5.c
@@ -271,6 +271,7 @@ static void mx5_clocks_mx51_mx53_init(void __iomem *base)
clks[IMX5_CLK_USBOH3_PODF] = imx_clk_divider("usboh3_podf", "usboh3_pred", base + CCM_CSCDR1, 6, 2);
clks[IMX5_CLK_USB_PHY_PRED] = imx_clk_divider("usb_phy_pred", "pll3_sw", base + CCM_CDCDR, 3, 3);
clks[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", base + CCM_CDCDR, 0, 3);
+ clks[IMX5_CLK_DI_PRED] = imx_clk_divider_np("di_pred", "pll3_sw", base + CCM_CDCDR, 6, 3);
clks[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", base + CCM_CSCMR1, 26, 1,
usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));
}
@@ -362,6 +363,8 @@ static void mx51_clocks_ipu_init(void __iomem *regs)
mx5_clocks_ipu_init(regs);
+ clk_set_rate(clks[IMX5_CLK_DI_PRED], clk_get_rate(clks[IMX5_CLK_PLL3_SW]));
+
clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX51_IPU_BASE_ADDR, "bus");
clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX51_IPU_BASE_ADDR, "di0");
clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX51_IPU_BASE_ADDR, "di1");
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index 0431f61f09..016d405e90 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -1,25 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright 2017 NXP.
- *
- * 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
+ * Copyright 2018 NXP.
+ * Copyright (C) 2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
-#include <common.h>
-#include <init.h>
-#include <driver.h>
-#include <linux/clk.h>
+#include <dt-bindings/clock/imx8mq-clock.h>
#include <io.h>
-#include <of.h>
-#include <of_address.h>
-#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <linux/err.h>
-#include <mach/revision.h>
-#include <dt-bindings/clock/imx8mq-clock.h>
+#include <linux/types.h>
+#include <of_address.h>
#include "clk.h"
@@ -37,18 +27,25 @@ static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", };
static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", };
static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", };
static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", };
-static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", };
static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", };
static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", };
static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", };
static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", };
-static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", };
/* CCM ROOT */
static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
"sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", };
+static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
+ "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", };
+
+static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out",
+ "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out",
+ "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m",
"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",};
@@ -58,9 +55,25 @@ static const char *imx8mq_enet_axi_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_p
static const char *imx8mq_nand_usdhc_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_200m",
"sys1_pll_133m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll1_out", };
+static const char *imx8mq_vpu_bus_sels[] = {"osc_25m", "sys1_pll_800m", "vpu_pll_out", "audio_pll2_out", "sys3_pll2_out", "sys2_pll_1000m", "sys2_pll_200m", "sys1_pll_100m", };
+
+static const char *imx8mq_disp_axi_sels[] = {"osc_25m", "sys2_pll_125m", "sys1_pll_800m", "sys3_pll2_out", "sys1_pll_400m", "audio_pll2_out", "clk_ext1", "clk_ext4", };
+
+static const char *imx8mq_disp_apb_sels[] = {"osc_25m", "sys2_pll_125m", "sys1_pll_800m", "sys3_pll2_out",
+ "sys1_pll_40m", "audio_pll2_out", "clk_ext1", "clk_ext3", };
+
+static const char *imx8mq_disp_rtrm_sels[] = {"osc_25m", "sys1_pll_800m", "sys2_pll_200m", "sys1_pll_400m",
+ "audio_pll1_out", "video_pll1_out", "clk_ext2", "clk_ext3", };
+
static const char *imx8mq_usb_bus_sels[] = {"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m",
"sys2_pll_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+static const char *imx8mq_gpu_axi_sels[] = {"osc_25m", "sys1_pll_800m", "gpu_pll_out", "sys3_pll2_out", "sys2_pll_1000m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_gpu_ahb_sels[] = {"osc_25m", "sys1_pll_800m", "gpu_pll_out", "sys3_pll2_out", "sys2_pll_1000m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
static const char *imx8mq_noc_sels[] = {"osc_25m", "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_1000m", "sys2_pll_500m",
"audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
@@ -70,11 +83,25 @@ static const char *imx8mq_noc_apb_sels[] = {"osc_25m", "sys1_pll_400m", "sys3_pl
static const char *imx8mq_ahb_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_800m", "sys1_pll_400m",
"sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", };
+static const char *imx8mq_audio_ahb_sels[] = {"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_1000m",
+ "sys2_pll_166m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_ahb_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out"};
+
static const char *imx8mq_dram_alt_sels[] = {"osc_25m", "sys1_pll_800m", "sys1_pll_100m", "sys2_pll_500m",
- "sys2_pll_250m", "sys1_pll_400m", "audio_pll1_out", "sys1_pll_266m", };
+ "sys2_pll_250m", "sys1_pll_400m", "audio_pll1_out", "sys1_pll_266m", };
static const char *imx8mq_dram_apb_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
- "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
+ "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
+
+static const char *imx8mq_vpu_g1_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_100m", "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", };
+
+static const char *imx8mq_vpu_g2_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_100m", "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", };
+
+static const char *imx8mq_disp_dtrc_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll2_out", "audio_pll2_out", };
+
+static const char *imx8mq_disp_dc8000_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll2_out", "audio_pll2_out", };
static const char *imx8mq_pcie1_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
"sys1_pll_800m", "sys2_pll_500m", "sys2_pll_250m", "sys3_pll2_out", };
@@ -89,6 +116,22 @@ static const char *imx8mq_dc_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio
static const char *imx8mq_lcdif_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll2_out", "clk_ext4", };
+static const char *imx8mq_sai1_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mq_sai2_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_sai3_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mq_sai4_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mq_sai5_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_sai6_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mq_spdif1_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_spdif2_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
+
static const char *imx8mq_enet_ref_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m",
"sys1_pll_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", };
@@ -167,6 +210,36 @@ static const char *imx8mq_wdog_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_1
static const char *imx8mq_wrclk_sels[] = {"osc_25m", "sys1_pll_40m", "vpu_pll_out", "sys3_pll2_out", "sys2_pll_200m",
"sys1_pll_266m", "sys2_pll_500m", "sys1_pll_100m", };
+static const char *imx8mq_dsi_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_dbi_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
+
static const char *imx8mq_pcie2_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
"sys1_pll_800m", "sys2_pll_500m", "sys2_pll_333m", "sys3_pll2_out", };
@@ -186,18 +259,19 @@ static const char *imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_
static struct clk_onecell_data clk_data;
static int const clks_init_on[] = {
- IMX8MQ_CLK_DRAM_CORE, IMX8MQ_CLK_AHB_CG,
- IMX8MQ_CLK_NOC_DIV, IMX8MQ_CLK_NOC_APB_DIV,
- IMX8MQ_CLK_NAND_USDHC_BUS_SRC,
- IMX8MQ_CLK_MAIN_AXI_SRC, IMX8MQ_CLK_A53_CG,
- IMX8MQ_CLK_AUDIO_AHB_DIV, IMX8MQ_CLK_TMU_ROOT,
- IMX8MQ_CLK_DRAM_APB_SRC,
+ IMX8MQ_CLK_A53_CG,
+ IMX8MQ_CLK_DRAM_CORE,
+ IMX8MQ_CLK_TMU_ROOT,
+ IMX8MQ_CLK_MAIN_AXI,
+ IMX8MQ_CLK_NOC,
+ IMX8MQ_CLK_NOC_APB,
+ IMX8MQ_CLK_DRAM_APB
};
-
-static void __init imx8mq_clocks_init(struct device_node *ccm_node)
+static int imx8mq_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
+ int err;
int i;
clks[IMX8MQ_CLK_DUMMY] = clk_fixed("dummy", 0);
@@ -211,7 +285,8 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
base = of_iomap(np, 0);
- WARN_ON(!base);
+ if (WARN_ON(!base))
+ return -ENOMEM;
clks[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
@@ -223,7 +298,6 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
clks[IMX8MQ_SYS2_PLL1_REF_SEL] = imx_clk_mux("sys2_pll1_ref_sel", base + 0x3c, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_SYS3_PLL1_REF_SEL] = imx_clk_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_DRAM_PLL1_REF_SEL] = imx_clk_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
- clks[IMX8MQ_VIDEO2_PLL1_REF_SEL] = imx_clk_mux("video2_pll1_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_ARM_PLL_REF_DIV] = imx_clk_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6);
clks[IMX8MQ_GPU_PLL_REF_DIV] = imx_clk_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6);
@@ -235,7 +309,6 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
clks[IMX8MQ_SYS2_PLL1_REF_DIV] = imx_clk_divider("sys2_pll1_ref_div", "sys2_pll1_ref_sel", base + 0x44, 25, 3);
clks[IMX8MQ_SYS3_PLL1_REF_DIV] = imx_clk_divider("sys3_pll1_ref_div", "sys3_pll1_ref_sel", base + 0x50, 25, 3);
clks[IMX8MQ_DRAM_PLL1_REF_DIV] = imx_clk_divider("dram_pll1_ref_div", "dram_pll1_ref_sel", base + 0x68, 25, 3);
- clks[IMX8MQ_VIDEO2_PLL1_REF_DIV] = imx_clk_divider("video2_pll1_ref_div", "video2_pll1_ref_sel", base + 0x5c, 25, 3);
clks[IMX8MQ_ARM_PLL] = imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28);
clks[IMX8MQ_GPU_PLL] = imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18);
@@ -247,25 +320,21 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
clks[IMX8MQ_SYS2_PLL1] = imx_clk_sccg_pll("sys2_pll1", "sys2_pll1_ref_div", base + 0x3c, SCCG_PLL1);
clks[IMX8MQ_SYS3_PLL1] = imx_clk_sccg_pll("sys3_pll1", "sys3_pll1_ref_div", base + 0x48, SCCG_PLL1);
clks[IMX8MQ_DRAM_PLL1] = imx_clk_sccg_pll("dram_pll1", "dram_pll1_ref_div", base + 0x60, SCCG_PLL1);
- clks[IMX8MQ_VIDEO2_PLL1] = imx_clk_sccg_pll("video2_pll1", "video2_pll1_ref_div", base + 0x5c, SCCG_PLL1);
clks[IMX8MQ_SYS1_PLL2] = imx_clk_sccg_pll("sys1_pll2", "sys1_pll1_out_div", base + 0x30, SCCG_PLL2);
clks[IMX8MQ_SYS2_PLL2] = imx_clk_sccg_pll("sys2_pll2", "sys2_pll1_out_div", base + 0x3c, SCCG_PLL2);
clks[IMX8MQ_SYS3_PLL2] = imx_clk_sccg_pll("sys3_pll2", "sys3_pll1_out_div", base + 0x48, SCCG_PLL2);
clks[IMX8MQ_DRAM_PLL2] = imx_clk_sccg_pll("dram_pll2", "dram_pll1_out_div", base + 0x60, SCCG_PLL2);
- clks[IMX8MQ_VIDEO2_PLL2] = imx_clk_sccg_pll("video2_pll2", "video2_pll1_out_div", base + 0x54, SCCG_PLL2);
/* PLL divs */
clks[IMX8MQ_SYS1_PLL1_OUT_DIV] = imx_clk_divider("sys1_pll1_out_div", "sys1_pll1_out", base + 0x38, 19, 6);
clks[IMX8MQ_SYS2_PLL1_OUT_DIV] = imx_clk_divider("sys2_pll1_out_div", "sys2_pll1_out", base + 0x44, 19, 6);
clks[IMX8MQ_SYS3_PLL1_OUT_DIV] = imx_clk_divider("sys3_pll1_out_div", "sys3_pll1_out", base + 0x50, 19, 6);
clks[IMX8MQ_DRAM_PLL1_OUT_DIV] = imx_clk_divider("dram_pll1_out_div", "dram_pll1_out", base + 0x68, 19, 6);
- clks[IMX8MQ_VIDEO2_PLL1_OUT_DIV] = imx_clk_divider("video2_pll1_out_div", "video2_pll1_out", base + 0x5c, 19, 6);
clks[IMX8MQ_SYS1_PLL2_DIV] = imx_clk_divider("sys1_pll2_div", "sys1_pll2", base + 0x38, 1, 6);
clks[IMX8MQ_SYS2_PLL2_DIV] = imx_clk_divider("sys2_pll2_div", "sys2_pll2", base + 0x44, 1, 6);
clks[IMX8MQ_SYS3_PLL2_DIV] = imx_clk_divider("sys3_pll2_div", "sys3_pll2", base + 0x50, 1, 6);
clks[IMX8MQ_DRAM_PLL2_DIV] = imx_clk_divider("dram_pll2_div", "dram_pll2", base + 0x68, 1, 6);
- clks[IMX8MQ_VIDEO2_PLL2_DIV] = imx_clk_divider("video2_pll2_div", "video2_pll2", base + 0x5c, 1, 6);
/* PLL bypass out */
clks[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_mux("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels));
@@ -279,21 +348,10 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
clks[IMX8MQ_SYS2_PLL1_OUT] = imx_clk_mux("sys2_pll1_out", base + 0x3c, 5, 1, sys2_pll1_out_sels, ARRAY_SIZE(sys2_pll1_out_sels));
clks[IMX8MQ_SYS3_PLL1_OUT] = imx_clk_mux("sys3_pll1_out", base + 0x48, 5, 1, sys3_pll1_out_sels, ARRAY_SIZE(sys3_pll1_out_sels));
clks[IMX8MQ_DRAM_PLL1_OUT] = imx_clk_mux("dram_pll1_out", base + 0x60, 5, 1, dram_pll1_out_sels, ARRAY_SIZE(dram_pll1_out_sels));
- clks[IMX8MQ_VIDEO2_PLL1_OUT] = imx_clk_mux("video2_pll1_out", base + 0x54, 5, 1, video2_pll1_out_sels, ARRAY_SIZE(video2_pll1_out_sels));
clks[IMX8MQ_SYS1_PLL2_OUT] = imx_clk_mux("sys1_pll2_out", base + 0x30, 4, 1, sys1_pll2_out_sels, ARRAY_SIZE(sys1_pll2_out_sels));
clks[IMX8MQ_SYS2_PLL2_OUT] = imx_clk_mux("sys2_pll2_out", base + 0x3c, 4, 1, sys2_pll2_out_sels, ARRAY_SIZE(sys2_pll2_out_sels));
clks[IMX8MQ_SYS3_PLL2_OUT] = imx_clk_mux("sys3_pll2_out", base + 0x48, 4, 1, sys3_pll2_out_sels, ARRAY_SIZE(sys3_pll2_out_sels));
clks[IMX8MQ_DRAM_PLL2_OUT] = imx_clk_mux("dram_pll2_out", base + 0x60, 4, 1, dram_pll2_out_sels, ARRAY_SIZE(dram_pll2_out_sels));
- clks[IMX8MQ_VIDEO2_PLL2_OUT] = imx_clk_mux("video2_pll2_out", base + 0x54, 4, 1, video2_pll2_out_sels, ARRAY_SIZE(video2_pll2_out_sels));
-
- /* unbypass all the plls */
- clk_set_parent(clks[IMX8MQ_GPU_PLL_BYPASS], clks[IMX8MQ_GPU_PLL]);
- clk_set_parent(clks[IMX8MQ_VPU_PLL_BYPASS], clks[IMX8MQ_VPU_PLL]);
- clk_set_parent(clks[IMX8MQ_AUDIO_PLL1_BYPASS], clks[IMX8MQ_AUDIO_PLL1]);
- clk_set_parent(clks[IMX8MQ_AUDIO_PLL2_BYPASS], clks[IMX8MQ_AUDIO_PLL2]);
- clk_set_parent(clks[IMX8MQ_VIDEO_PLL1_BYPASS], clks[IMX8MQ_VIDEO_PLL1]);
- clk_set_parent(clks[IMX8MQ_SYS3_PLL1_OUT], clks[IMX8MQ_SYS3_PLL1]);
- clk_set_parent(clks[IMX8MQ_SYS3_PLL2_OUT], clks[IMX8MQ_SYS3_PLL2_DIV]);
/* PLL OUT GATE */
clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
@@ -306,7 +364,6 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_gate("sys2_pll_out", "sys2_pll2_out", base + 0x3c, 9);
clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_gate("sys3_pll_out", "sys3_pll2_out", base + 0x48, 9);
clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll2_out", base + 0x60, 9);
- clks[IMX8MQ_VIDEO2_PLL_OUT] = imx_clk_gate("video2_pll_out", "video2_pll2_out", base + 0x54, 9);
/* SYS PLL fixed output */
clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
@@ -331,251 +388,172 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
np = ccm_node;
base = of_iomap(np, 0);
- WARN_ON(!base);
+ if (WARN_ON(!base))
+ return -ENOMEM;
+
/* CORE */
clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
+ clks[IMX8MQ_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mq_vpu_sels, ARRAY_SIZE(imx8mq_vpu_sels));
+ clks[IMX8MQ_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mq_gpu_core_sels, ARRAY_SIZE(imx8mq_gpu_core_sels));
+ clks[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mq_gpu_shader_sels, ARRAY_SIZE(imx8mq_gpu_shader_sels));
clks[IMX8MQ_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
+ clks[IMX8MQ_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
+ clks[IMX8MQ_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
+ clks[IMX8MQ_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
+
clks[IMX8MQ_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
+ clks[IMX8MQ_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
+ clks[IMX8MQ_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
+ clks[IMX8MQ_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
/* BUS */
- clks[IMX8MQ_CLK_MAIN_AXI_SRC] = imx_clk_mux2("main_axi_src", base + 0x8800, 24, 3, imx8mq_main_axi_sels, ARRAY_SIZE(imx8mq_main_axi_sels));
- clks[IMX8MQ_CLK_ENET_AXI_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8880, 24, 3, imx8mq_enet_axi_sels, ARRAY_SIZE(imx8mq_enet_axi_sels));
- clks[IMX8MQ_CLK_NAND_USDHC_BUS_SRC] = imx_clk_mux2("nand_usdhc_bus_src", base + 0x8900, 24, 3, imx8mq_nand_usdhc_sels, ARRAY_SIZE(imx8mq_nand_usdhc_sels));
- clks[IMX8MQ_CLK_USB_BUS_SRC] = imx_clk_mux2("usb_bus_src", base + 0x8b80, 24, 3, imx8mq_usb_bus_sels, ARRAY_SIZE(imx8mq_usb_bus_sels));
- clks[IMX8MQ_CLK_NOC_SRC] = imx_clk_mux2("noc_src", base + 0x8d00, 24, 3, imx8mq_noc_sels, ARRAY_SIZE(imx8mq_noc_sels));
- clks[IMX8MQ_CLK_NOC_APB_SRC] = imx_clk_mux2("noc_apb_src", base + 0x8d80, 24, 3, imx8mq_noc_apb_sels, ARRAY_SIZE(imx8mq_noc_apb_sels));
-
- clks[IMX8MQ_CLK_MAIN_AXI_CG] = imx_clk_gate3("main_axi_cg", "main_axi_src", base + 0x8800, 28);
- clks[IMX8MQ_CLK_ENET_AXI_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8880, 28);
- clks[IMX8MQ_CLK_NAND_USDHC_BUS_CG] = imx_clk_gate3("nand_usdhc_bus_cg", "nand_usdhc_bus_src", base + 0x8900, 28);
- clks[IMX8MQ_CLK_USB_BUS_CG] = imx_clk_gate3("usb_bus_cg", "usb_bus_src", base + 0x8b80, 28);
- clks[IMX8MQ_CLK_NOC_CG] = imx_clk_gate3("noc_cg", "noc_src", base + 0x8d00, 28);
- clks[IMX8MQ_CLK_NOC_APB_CG] = imx_clk_gate3("noc_apb_cg", "noc_apb_src", base + 0x8d80, 28);
-
- clks[IMX8MQ_CLK_MAIN_AXI_PRE_DIV] = imx_clk_divider2("main_axi_pre_div", "main_axi_cg", base + 0x8800, 16, 3);
- clks[IMX8MQ_CLK_ENET_AXI_PRE_DIV] = imx_clk_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8880, 16, 3);
- clks[IMX8MQ_CLK_NAND_USDHC_BUS_PRE_DIV] = imx_clk_divider2("nand_usdhc_bus_pre_div", "nand_usdhc_bus_cg", base + 0x8900, 16, 3);
- clks[IMX8MQ_CLK_DISP_AXI_PRE_DIV] = imx_clk_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8a00, 16, 3);
- clks[IMX8MQ_CLK_DISP_APB_PRE_DIV] = imx_clk_divider2("disp_apb_pre_div", "disp_apb_cg", base + 0x8a80, 16, 3);
- clks[IMX8MQ_CLK_DISP_RTRM_PRE_DIV] = imx_clk_divider2("disp_rtrm_pre_div", "disp_rtrm_cg", base + 0x8b00, 16, 3);
- clks[IMX8MQ_CLK_USB_BUS_PRE_DIV] = imx_clk_divider2("usb_bus_pre_div", "usb_bus_cg", base + 0x8b80, 16, 3);
- clks[IMX8MQ_CLK_GPU_AXI_PRE_DIV] = imx_clk_divider2("gpu_axi_pre_div", "gpu_axi_cg", base + 0x8c00, 16, 3);
- clks[IMX8MQ_CLK_GPU_AHB_PRE_DIV] = imx_clk_divider2("gpu_ahb_pre_div", "gpu_ahb_cg", base + 0x8c80, 16, 3);
- clks[IMX8MQ_CLK_NOC_PRE_DIV] = imx_clk_divider2("noc_pre_div", "noc_cg", base + 0x8d00, 16, 3);
- clks[IMX8MQ_CLK_NOC_APB_PRE_DIV] = imx_clk_divider2("noc_apb_pre_div", "noc_apb_cg", base + 0x8d80, 16, 3);
-
- clks[IMX8MQ_CLK_MAIN_AXI_DIV] = imx_clk_divider2("main_axi_div", "main_axi_pre_div", base + 0x8800, 0, 6);
- clks[IMX8MQ_CLK_ENET_AXI_DIV] = imx_clk_divider2("enet_axi_div", "enet_axi_pre_div", base + 0x8880, 0, 6);
- clks[IMX8MQ_CLK_NAND_USDHC_BUS_DIV] = imx_clk_divider2("nand_usdhc_bus_div", "nand_usdhc_bus_pre_div", base + 0x8900, 0, 6);
- clks[IMX8MQ_CLK_USB_BUS_DIV] = imx_clk_divider2("usb_bus_div", "usb_bus_pre_div", base + 0x8b80, 0, 6);
- clks[IMX8MQ_CLK_NOC_DIV] = imx_clk_divider2("noc_div", "noc_pre_div", base + 0x8d00, 0, 6);
- clks[IMX8MQ_CLK_NOC_APB_DIV] = imx_clk_divider2("noc_apb_div", "noc_apb_pre_div", base + 0x8d80, 0, 6);
+ clks[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_composite("main_axi", imx8mq_main_axi_sels, base + 0x8800);
+ clks[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mq_enet_axi_sels, base + 0x8880);
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mq_nand_usdhc_sels, base + 0x8900);
+ clks[IMX8MQ_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mq_vpu_bus_sels, base + 0x8980);
+ clks[IMX8MQ_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mq_disp_axi_sels, base + 0x8a00);
+ clks[IMX8MQ_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mq_disp_apb_sels, base + 0x8a80);
+ clks[IMX8MQ_CLK_DISP_RTRM] = imx8m_clk_composite("disp_rtrm", imx8mq_disp_rtrm_sels, base + 0x8b00);
+ clks[IMX8MQ_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80);
+ clks[IMX8MQ_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mq_gpu_axi_sels, base + 0x8c00);
+ clks[IMX8MQ_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mq_gpu_ahb_sels, base + 0x8c80);
+ clks[IMX8MQ_CLK_NOC] = imx8m_clk_composite("noc", imx8mq_noc_sels, base + 0x8d00);
+ clks[IMX8MQ_CLK_NOC_APB] = imx8m_clk_composite("noc_apb", imx8mq_noc_apb_sels, base + 0x8d80);
/* AHB */
- clks[IMX8MQ_CLK_AHB_SRC] = imx_clk_mux2("ahb_src", base + 0x9000, 24, 3, imx8mq_ahb_sels, ARRAY_SIZE(imx8mq_ahb_sels));
- clks[IMX8MQ_CLK_AHB_CG] = imx_clk_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
- clks[IMX8MQ_CLK_AHB_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
- clks[IMX8MQ_CLK_AHB_DIV] = imx_clk_divider_flags("ahb_div", "ahb_pre_div", base + 0x9000, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_AHB] = imx8m_clk_composite("ahb", imx8mq_ahb_sels, base + 0x9000);
+ clks[IMX8MQ_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mq_audio_ahb_sels, base + 0x9100);
/* IPG */
- clks[IMX8MQ_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb_div", base + 0x9080, 0, 1);
+ clks[IMX8MQ_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
+ clks[IMX8MQ_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
/* IP */
- clks[IMX8MQ_CLK_DRAM_ALT_SRC] = imx_clk_mux2("dram_alt_src", base + 0xa000, 24, 3, imx8mq_dram_alt_sels, ARRAY_SIZE(imx8mq_dram_alt_sels));
clks[IMX8MQ_CLK_DRAM_CORE] = imx_clk_mux2("dram_core_clk", base + 0x9800, 24, 1, imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels));
- clks[IMX8MQ_CLK_DRAM_APB_SRC] = imx_clk_mux2("dram_apb_src", base + 0xa080, 24, 3, imx8mq_dram_apb_sels, ARRAY_SIZE(imx8mq_dram_apb_sels));
- clks[IMX8MQ_CLK_PCIE1_CTRL_SRC] = imx_clk_mux2("pcie1_ctrl_src", base + 0xa300, 24, 3, imx8mq_pcie1_ctrl_sels, ARRAY_SIZE(imx8mq_pcie1_ctrl_sels));
- clks[IMX8MQ_CLK_PCIE1_PHY_SRC] = imx_clk_mux2("pcie1_phy_src", base + 0xa380, 24, 3, imx8mq_pcie1_phy_sels, ARRAY_SIZE(imx8mq_pcie1_phy_sels));
- clks[IMX8MQ_CLK_PCIE1_AUX_SRC] = imx_clk_mux2("pcie1_aux_src", base + 0xa400, 24, 3, imx8mq_pcie1_aux_sels, ARRAY_SIZE(imx8mq_pcie1_aux_sels));
- clks[IMX8MQ_CLK_DC_PIXEL_SRC] = imx_clk_mux2("dc_pixel_src", base + 0xa480, 24, 3, imx8mq_dc_pixel_sels, ARRAY_SIZE(imx8mq_dc_pixel_sels));
- clks[IMX8MQ_CLK_LCDIF_PIXEL_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa500, 24, 3, imx8mq_lcdif_pixel_sels, ARRAY_SIZE(imx8mq_lcdif_pixel_sels));
- clks[IMX8MQ_CLK_ENET_REF_SRC] = imx_clk_mux2("enet_ref_src", base + 0xa980, 24, 3, imx8mq_enet_ref_sels, ARRAY_SIZE(imx8mq_enet_ref_sels));
- clks[IMX8MQ_CLK_ENET_TIMER_SRC] = imx_clk_mux2("enet_timer_src", base + 0xaa00, 24, 3, imx8mq_enet_timer_sels, ARRAY_SIZE(imx8mq_enet_timer_sels));
- clks[IMX8MQ_CLK_ENET_PHY_REF_SRC] = imx_clk_mux2("enet_phy_src", base + 0xaa80, 24, 3, imx8mq_enet_phy_sels, ARRAY_SIZE(imx8mq_enet_phy_sels));
- clks[IMX8MQ_CLK_NAND_SRC] = imx_clk_mux2("nand_src", base + 0xab00, 24, 3, imx8mq_nand_sels, ARRAY_SIZE(imx8mq_nand_sels));
- clks[IMX8MQ_CLK_QSPI_SRC] = imx_clk_mux2("qspi_src", base + 0xab80, 24, 3, imx8mq_qspi_sels, ARRAY_SIZE(imx8mq_qspi_sels));
- clks[IMX8MQ_CLK_USDHC1_SRC] = imx_clk_mux2("usdhc1_src", base + 0xac00, 24, 3, imx8mq_usdhc1_sels, ARRAY_SIZE(imx8mq_usdhc1_sels));
- clks[IMX8MQ_CLK_USDHC2_SRC] = imx_clk_mux2("usdhc2_src", base + 0xac80, 24, 3, imx8mq_usdhc2_sels, ARRAY_SIZE(imx8mq_usdhc2_sels));
- clks[IMX8MQ_CLK_I2C1_SRC] = imx_clk_mux2("i2c1_src", base + 0xad00, 24, 3, imx8mq_i2c1_sels, ARRAY_SIZE(imx8mq_i2c1_sels));
- clks[IMX8MQ_CLK_I2C2_SRC] = imx_clk_mux2("i2c2_src", base + 0xad80, 24, 3, imx8mq_i2c2_sels, ARRAY_SIZE(imx8mq_i2c2_sels));
- clks[IMX8MQ_CLK_I2C3_SRC] = imx_clk_mux2("i2c3_src", base + 0xae00, 24, 3, imx8mq_i2c3_sels, ARRAY_SIZE(imx8mq_i2c3_sels));
- clks[IMX8MQ_CLK_I2C4_SRC] = imx_clk_mux2("i2c4_src", base + 0xae80, 24, 3, imx8mq_i2c4_sels, ARRAY_SIZE(imx8mq_i2c4_sels));
- clks[IMX8MQ_CLK_UART1_SRC] = imx_clk_mux2("uart1_src", base + 0xaf00, 24, 3, imx8mq_uart1_sels, ARRAY_SIZE(imx8mq_uart1_sels));
- clks[IMX8MQ_CLK_UART2_SRC] = imx_clk_mux2("uart2_src", base + 0xaf80, 24, 3, imx8mq_uart2_sels, ARRAY_SIZE(imx8mq_uart2_sels));
- clks[IMX8MQ_CLK_UART3_SRC] = imx_clk_mux2("uart3_src", base + 0xb000, 24, 3, imx8mq_uart3_sels, ARRAY_SIZE(imx8mq_uart3_sels));
- clks[IMX8MQ_CLK_UART4_SRC] = imx_clk_mux2("uart4_src", base + 0xb080, 24, 3, imx8mq_uart4_sels, ARRAY_SIZE(imx8mq_uart4_sels));
- clks[IMX8MQ_CLK_USB_CORE_REF_SRC] = imx_clk_mux2("usb_core_ref_src", base + 0xb100, 24, 3, imx8mq_usb_core_sels, ARRAY_SIZE(imx8mq_usb_core_sels));
- clks[IMX8MQ_CLK_USB_PHY_REF_SRC] = imx_clk_mux2("usb_phy_ref_src", base + 0xb180, 24, 3, imx8mq_usb_phy_sels, ARRAY_SIZE(imx8mq_usb_phy_sels));
- clks[IMX8MQ_CLK_ECSPI1_SRC] = imx_clk_mux2("ecspi1_src", base + 0xb280, 24, 3, imx8mq_ecspi1_sels, ARRAY_SIZE(imx8mq_ecspi1_sels));
- clks[IMX8MQ_CLK_ECSPI2_SRC] = imx_clk_mux2("ecspi2_src", base + 0xb300, 24, 3, imx8mq_ecspi2_sels, ARRAY_SIZE(imx8mq_ecspi2_sels));
- clks[IMX8MQ_CLK_PWM1_SRC] = imx_clk_mux2("pwm1_src", base + 0xb380, 24, 3, imx8mq_pwm1_sels, ARRAY_SIZE(imx8mq_pwm1_sels));
- clks[IMX8MQ_CLK_PWM2_SRC] = imx_clk_mux2("pwm2_src", base + 0xb400, 24, 3, imx8mq_pwm2_sels, ARRAY_SIZE(imx8mq_pwm2_sels));
- clks[IMX8MQ_CLK_PWM3_SRC] = imx_clk_mux2("pwm3_src", base + 0xb480, 24, 3, imx8mq_pwm3_sels, ARRAY_SIZE(imx8mq_pwm3_sels));
- clks[IMX8MQ_CLK_PWM4_SRC] = imx_clk_mux2("pwm4_src", base + 0xb500, 24, 3, imx8mq_pwm4_sels, ARRAY_SIZE(imx8mq_pwm4_sels));
- clks[IMX8MQ_CLK_GPT1_SRC] = imx_clk_mux2("gpt1_src", base + 0xb580, 24, 3, imx8mq_gpt1_sels, ARRAY_SIZE(imx8mq_gpt1_sels));
- clks[IMX8MQ_CLK_WDOG_SRC] = imx_clk_mux2("wdog_src", base + 0xb900, 24, 3, imx8mq_wdog_sels, ARRAY_SIZE(imx8mq_wdog_sels));
- clks[IMX8MQ_CLK_WRCLK_SRC] = imx_clk_mux2("wrclk_src", base + 0xb980, 24, 3, imx8mq_wrclk_sels, ARRAY_SIZE(imx8mq_wrclk_sels));
- clks[IMX8MQ_CLK_CLKO2_SRC] = imx_clk_mux2("clko2_src", base + 0xba80, 24, 3, imx8mq_clko2_sels, ARRAY_SIZE(imx8mq_clko2_sels));
- clks[IMX8MQ_CLK_PCIE2_CTRL_SRC] = imx_clk_mux2("pcie2_ctrl_src", base + 0xc000, 24, 3, imx8mq_pcie2_ctrl_sels, ARRAY_SIZE(imx8mq_pcie2_ctrl_sels));
- clks[IMX8MQ_CLK_PCIE2_PHY_SRC] = imx_clk_mux2("pcie2_phy_src", base + 0xc080, 24, 3, imx8mq_pcie2_phy_sels, ARRAY_SIZE(imx8mq_pcie2_phy_sels));
- clks[IMX8MQ_CLK_PCIE2_AUX_SRC] = imx_clk_mux2("pcie2_aux_src", base + 0xc100, 24, 3, imx8mq_pcie2_aux_sels, ARRAY_SIZE(imx8mq_pcie2_aux_sels));
- clks[IMX8MQ_CLK_ECSPI3_SRC] = imx_clk_mux2("ecspi3_src", base + 0xc180, 24, 3, imx8mq_ecspi3_sels, ARRAY_SIZE(imx8mq_ecspi3_sels));
-
- clks[IMX8MQ_CLK_DRAM_ALT_CG] = imx_clk_gate3("dram_alt_cg", "dram_alt_src", base + 0xa000, 28);
- clks[IMX8MQ_CLK_DRAM_APB_CG] = imx_clk_gate3("dram_apb_cg", "dram_apb_src", base + 0xa080, 28);
- clks[IMX8MQ_CLK_PCIE1_CTRL_CG] = imx_clk_gate3("pcie1_ctrl_cg", "pcie1_ctrl_src", base + 0xa300, 28);
- clks[IMX8MQ_CLK_PCIE1_PHY_CG] = imx_clk_gate3("pcie1_phy_cg", "pcie1_phy_src", base + 0xa380, 28);
- clks[IMX8MQ_CLK_PCIE1_AUX_CG] = imx_clk_gate3("pcie1_aux_cg", "pcie1_aux_src", base + 0xa400, 28);
- clks[IMX8MQ_CLK_ENET_REF_CG] = imx_clk_gate3("enet_ref_cg", "enet_ref_src", base + 0xa980, 28);
- clks[IMX8MQ_CLK_ENET_TIMER_CG] = imx_clk_gate3("enet_timer_cg", "enet_timer_src", base + 0xaa00, 28);
- clks[IMX8MQ_CLK_ENET_PHY_REF_CG] = imx_clk_gate3("enet_phy_cg", "enet_phy_src", base + 0xaa80, 28);
- clks[IMX8MQ_CLK_NAND_CG] = imx_clk_gate3("nand_cg", "nand_src", base + 0xab00, 28);
- clks[IMX8MQ_CLK_QSPI_CG] = imx_clk_gate3("qspi_cg", "qspi_src", base + 0xab80, 28);
- clks[IMX8MQ_CLK_USDHC1_CG] = imx_clk_gate3("usdhc1_cg", "usdhc1_src", base + 0xac00, 28);
- clks[IMX8MQ_CLK_USDHC2_CG] = imx_clk_gate3("usdhc2_cg", "usdhc2_src", base + 0xac80, 28);
- clks[IMX8MQ_CLK_I2C1_CG] = imx_clk_gate3("i2c1_cg", "i2c1_src", base + 0xad00, 28);
- clks[IMX8MQ_CLK_I2C2_CG] = imx_clk_gate3("i2c2_cg", "i2c2_src", base + 0xad80, 28);
- clks[IMX8MQ_CLK_I2C3_CG] = imx_clk_gate3("i2c3_cg", "i2c3_src", base + 0xae00, 28);
- clks[IMX8MQ_CLK_I2C4_CG] = imx_clk_gate3("i2c4_cg", "i2c4_src", base + 0xae80, 28);
- clks[IMX8MQ_CLK_UART1_CG] = imx_clk_gate3("uart1_cg", "uart1_src", base + 0xaf00, 28);
- clks[IMX8MQ_CLK_UART2_CG] = imx_clk_gate3("uart2_cg", "uart2_src", base + 0xaf80, 28);
- clks[IMX8MQ_CLK_UART3_CG] = imx_clk_gate3("uart3_cg", "uart3_src", base + 0xb000, 28);
- clks[IMX8MQ_CLK_UART4_CG] = imx_clk_gate3("uart4_cg", "uart4_src", base + 0xb080, 28);
- clks[IMX8MQ_CLK_USB_CORE_REF_CG] = imx_clk_gate3("usb_core_ref_cg", "usb_core_ref_src", base + 0xb100, 28);
- clks[IMX8MQ_CLK_USB_PHY_REF_CG] = imx_clk_gate3("usb_phy_ref_cg", "usb_phy_ref_src", base + 0xb180, 28);
- clks[IMX8MQ_CLK_ECSPI1_CG] = imx_clk_gate3("ecspi1_cg", "ecspi1_src", base + 0xb280, 28);
- clks[IMX8MQ_CLK_ECSPI2_CG] = imx_clk_gate3("ecspi2_cg", "ecspi2_src", base + 0xb300, 28);
- clks[IMX8MQ_CLK_PWM1_CG] = imx_clk_gate3("pwm1_cg", "pwm1_src", base + 0xb380, 28);
- clks[IMX8MQ_CLK_PWM2_CG] = imx_clk_gate3("pwm2_cg", "pwm2_src", base + 0xb400, 28);
- clks[IMX8MQ_CLK_PWM3_CG] = imx_clk_gate3("pwm3_cg", "pwm3_src", base + 0xb480, 28);
- clks[IMX8MQ_CLK_PWM4_CG] = imx_clk_gate3("pwm4_cg", "pwm4_src", base + 0xb500, 28);
- clks[IMX8MQ_CLK_GPT1_CG] = imx_clk_gate3("gpt1_cg", "gpt1_src", base + 0xb580, 28);
- clks[IMX8MQ_CLK_WDOG_CG] = imx_clk_gate3("wdog_cg", "wdog_src", base + 0xb900, 28);
- clks[IMX8MQ_CLK_WRCLK_CG] = imx_clk_gate3("wrclk_cg", "wrclk_src", base + 0xb980, 28);
- clks[IMX8MQ_CLK_CLKO2_CG] = imx_clk_gate3("clko2_cg", "clko2_src", base + 0xba80, 28);
- clks[IMX8MQ_CLK_PCIE2_CTRL_CG] = imx_clk_gate3("pcie2_ctrl_cg", "pcie2_ctrl_src", base + 0xc000, 28);
- clks[IMX8MQ_CLK_PCIE2_PHY_CG] = imx_clk_gate3("pcie2_phy_cg", "pcie2_phy_src", base + 0xc080, 28);
- clks[IMX8MQ_CLK_PCIE2_AUX_CG] = imx_clk_gate3("pcie2_aux_cg", "pcie2_aux_src", base + 0xc100, 28);
- clks[IMX8MQ_CLK_ECSPI3_CG] = imx_clk_gate3("ecspi3_cg", "ecspi3_src", base + 0xc180, 28);
-
- clks[IMX8MQ_CLK_DRAM_ALT_PRE_DIV] = imx_clk_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa000, 16, 3);
- clks[IMX8MQ_CLK_DRAM_APB_PRE_DIV] = imx_clk_divider_flags("dram_apb_pre_div", "dram_apb_cg", base + 0xa080, 16, 3, CLK_OPS_PARENT_ENABLE);
- clks[IMX8MQ_CLK_PCIE1_CTRL_PRE_DIV] = imx_clk_divider2("pcie1_ctrl_pre_div", "pcie1_ctrl_cg", base + 0xa300, 16, 3);
- clks[IMX8MQ_CLK_PCIE1_PHY_PRE_DIV] = imx_clk_divider2("pcie1_phy_pre_div", "pcie1_phy_cg", base + 0xa380, 16, 3);
- clks[IMX8MQ_CLK_PCIE1_AUX_PRE_DIV] = imx_clk_divider2("pcie1_aux_pre_div", "pcie1_aux_cg", base + 0xa400, 16, 3);
- clks[IMX8MQ_CLK_DC_PIXEL_PRE_DIV] = imx_clk_divider2("dc_pixel_pre_div", "dc_pixel_cg", base + 0xa480, 16, 3);
- clks[IMX8MQ_CLK_LCDIF_PIXEL_PRE_DIV] = imx_clk_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa500, 16, 3);
- clks[IMX8MQ_CLK_SPDIF1_PRE_DIV] = imx_clk_divider2("spdif1_pre_div", "spdif1_cg", base + 0xa880, 16, 3);
- clks[IMX8MQ_CLK_SPDIF2_PRE_DIV] = imx_clk_divider2("spdif2_pre_div", "spdif2_cg", base + 0xa900, 16, 3);
- clks[IMX8MQ_CLK_ENET_REF_PRE_DIV] = imx_clk_divider2("enet_ref_pre_div", "enet_ref_cg", base + 0xa980, 16, 3);
- clks[IMX8MQ_CLK_ENET_TIMER_PRE_DIV] = imx_clk_divider2("enet_timer_pre_div", "enet_timer_cg", base + 0xaa00, 16, 3);
- clks[IMX8MQ_CLK_ENET_PHY_REF_PRE_DIV] = imx_clk_divider2("enet_phy_pre_div", "enet_phy_cg", base + 0xaa80, 16, 3);
- clks[IMX8MQ_CLK_NAND_PRE_DIV] = imx_clk_divider2("nand_pre_div", "nand_cg", base + 0xab00, 16, 3);
- clks[IMX8MQ_CLK_QSPI_PRE_DIV] = imx_clk_divider2("qspi_pre_div", "qspi_cg", base + 0xab80, 16, 3);
- clks[IMX8MQ_CLK_USDHC1_PRE_DIV] = imx_clk_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xac00, 16, 3);
- clks[IMX8MQ_CLK_USDHC2_PRE_DIV] = imx_clk_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xac80, 16, 3);
- clks[IMX8MQ_CLK_I2C1_PRE_DIV] = imx_clk_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad00, 16, 3);
- clks[IMX8MQ_CLK_I2C2_PRE_DIV] = imx_clk_divider2("i2c2_pre_div", "i2c2_cg", base + 0xad80, 16, 3);
- clks[IMX8MQ_CLK_I2C3_PRE_DIV] = imx_clk_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae00, 16, 3);
- clks[IMX8MQ_CLK_I2C4_PRE_DIV] = imx_clk_divider2("i2c4_pre_div", "i2c4_cg", base + 0xae80, 16, 3);
- clks[IMX8MQ_CLK_UART1_PRE_DIV] = imx_clk_divider2("uart1_pre_div", "uart1_cg", base + 0xaf00, 16, 3);
- clks[IMX8MQ_CLK_UART2_PRE_DIV] = imx_clk_divider2("uart2_pre_div", "uart2_cg", base + 0xaf80, 16, 3);
- clks[IMX8MQ_CLK_UART3_PRE_DIV] = imx_clk_divider2("uart3_pre_div", "uart3_cg", base + 0xb000, 16, 3);
- clks[IMX8MQ_CLK_UART4_PRE_DIV] = imx_clk_divider2("uart4_pre_div", "uart4_cg", base + 0xb080, 16, 3);
- clks[IMX8MQ_CLK_USB_CORE_REF_PRE_DIV] = imx_clk_divider2("usb_core_ref_pre_div", "usb_core_ref_cg", base + 0xb100, 16, 3);
- clks[IMX8MQ_CLK_USB_PHY_REF_PRE_DIV] = imx_clk_divider2("usb_phy_ref_pre_div", "usb_phy_ref_cg", base + 0xb180, 16, 3);
- clks[IMX8MQ_CLK_ECSPI1_PRE_DIV] = imx_clk_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb280, 16, 3);
- clks[IMX8MQ_CLK_ECSPI2_PRE_DIV] = imx_clk_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb300, 16, 3);
- clks[IMX8MQ_CLK_PWM1_PRE_DIV] = imx_clk_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb380, 16, 3);
- clks[IMX8MQ_CLK_PWM2_PRE_DIV] = imx_clk_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb400, 16, 3);
- clks[IMX8MQ_CLK_PWM3_PRE_DIV] = imx_clk_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb480, 16, 3);
- clks[IMX8MQ_CLK_PWM4_PRE_DIV] = imx_clk_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb500, 16, 3);
- clks[IMX8MQ_CLK_GPT1_PRE_DIV] = imx_clk_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb580, 16, 3);
- clks[IMX8MQ_CLK_WDOG_PRE_DIV] = imx_clk_divider2("wdog_pre_div", "wdog_cg", base + 0xb900, 16, 3);
- clks[IMX8MQ_CLK_WRCLK_PRE_DIV] = imx_clk_divider2("wrclk_pre_div", "wrclk_cg", base + 0xb980, 16, 3);
- clks[IMX8MQ_CLK_CLKO2_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xba80, 16, 3);
- clks[IMX8MQ_CLK_PCIE2_CTRL_PRE_DIV] = imx_clk_divider2("pcie2_ctrl_pre_div", "pcie2_ctrl_cg", base + 0xc000, 16, 3);
- clks[IMX8MQ_CLK_PCIE2_PHY_PRE_DIV] = imx_clk_divider2("pcie2_phy_pre_div", "pcie2_phy_cg", base + 0xc080, 16, 3);
- clks[IMX8MQ_CLK_PCIE2_AUX_PRE_DIV] = imx_clk_divider2("pcie2_aux_pre_div", "pcie2_aux_cg", base + 0xc100, 16, 3);
- clks[IMX8MQ_CLK_ECSPI3_PRE_DIV] = imx_clk_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xc180, 16, 3);
-
- clks[IMX8MQ_CLK_DRAM_ALT_DIV] = imx_clk_divider2("dram_alt_div", "dram_alt_pre_div", base + 0xa000, 0, 6);
- clks[IMX8MQ_CLK_DRAM_APB_DIV] = imx_clk_divider2("dram_apb_div", "dram_apb_pre_div", base + 0xa080, 0, 6);
- clks[IMX8MQ_CLK_PCIE1_CTRL_DIV] = imx_clk_divider2("pcie1_ctrl_div", "pcie1_ctrl_pre_div", base + 0xa300, 0, 6);
- clks[IMX8MQ_CLK_PCIE1_PHY_DIV] = imx_clk_divider2("pcie1_phy_div", "pcie1_phy_pre_div", base + 0xa380, 0, 6);
- clks[IMX8MQ_CLK_PCIE1_AUX_DIV] = imx_clk_divider2("pcie1_aux_div", "pcie1_aux_pre_div", base + 0xa400, 0, 6);
- clks[IMX8MQ_CLK_DC_PIXEL_DIV] = imx_clk_divider2("dc_pixel_div", "dc_pixel_pre_div", base + 0xa480, 0, 6);
- clks[IMX8MQ_CLK_LCDIF_PIXEL_DIV] = imx_clk_divider2("lcdif_pixel_div", "lcdif_pixel_pre_div", base + 0xa500, 0, 6);
- clks[IMX8MQ_CLK_ENET_REF_DIV] = imx_clk_divider2("enet_ref_div", "enet_ref_pre_div", base + 0xa980, 0, 6);
- clks[IMX8MQ_CLK_ENET_TIMER_DIV] = imx_clk_divider2("enet_timer_div", "enet_timer_pre_div", base + 0xaa00, 0, 6);
- clks[IMX8MQ_CLK_ENET_PHY_REF_DIV] = imx_clk_divider2("enet_phy_div", "enet_phy_pre_div", base + 0xaa80, 0, 6);
- clks[IMX8MQ_CLK_NAND_DIV] = imx_clk_divider2("nand_div", "nand_pre_div", base + 0xab00, 0, 6);
- clks[IMX8MQ_CLK_QSPI_DIV] = imx_clk_divider2("qspi_div", "qspi_pre_div", base + 0xab80, 0, 6);
- clks[IMX8MQ_CLK_USDHC1_DIV] = imx_clk_divider2("usdhc1_div", "usdhc1_pre_div", base + 0xac00, 0, 6);
- clks[IMX8MQ_CLK_USDHC2_DIV] = imx_clk_divider2("usdhc2_div", "usdhc2_pre_div", base + 0xac80, 0, 6);
- clks[IMX8MQ_CLK_I2C1_DIV] = imx_clk_divider2("i2c1_div", "i2c1_pre_div", base + 0xad00, 0, 6);
- clks[IMX8MQ_CLK_I2C2_DIV] = imx_clk_divider2("i2c2_div", "i2c2_pre_div", base + 0xad80, 0, 6);
- clks[IMX8MQ_CLK_I2C3_DIV] = imx_clk_divider2("i2c3_div", "i2c3_pre_div", base + 0xae00, 0, 6);
- clks[IMX8MQ_CLK_I2C4_DIV] = imx_clk_divider2("i2c4_div", "i2c4_pre_div", base + 0xae80, 0, 6);
- clks[IMX8MQ_CLK_UART1_DIV] = imx_clk_divider2("uart1_div", "uart1_pre_div", base + 0xaf00, 0, 6);
- clks[IMX8MQ_CLK_UART2_DIV] = imx_clk_divider2("uart2_div", "uart2_pre_div", base + 0xaf80, 0, 6);
- clks[IMX8MQ_CLK_UART3_DIV] = imx_clk_divider2("uart3_div", "uart3_pre_div", base + 0xb000, 0, 6);
- clks[IMX8MQ_CLK_UART4_DIV] = imx_clk_divider2("uart4_div", "uart4_pre_div", base + 0xb080, 0, 6);
- clks[IMX8MQ_CLK_USB_CORE_REF_DIV] = imx_clk_divider2("usb_core_ref_div", "usb_core_ref_pre_div", base + 0xb100, 0, 6);
- clks[IMX8MQ_CLK_USB_PHY_REF_DIV] = imx_clk_divider2("usb_phy_ref_div", "usb_phy_ref_pre_div", base + 0xb180, 0, 6);
- clks[IMX8MQ_CLK_ECSPI1_DIV] = imx_clk_divider2("ecspi1_div", "ecspi1_pre_div", base + 0xb280, 0, 6);
- clks[IMX8MQ_CLK_ECSPI2_DIV] = imx_clk_divider2("ecspi2_div", "ecspi2_pre_div", base + 0xb300, 0, 6);
- clks[IMX8MQ_CLK_PWM1_DIV] = imx_clk_divider2("pwm1_div", "pwm1_pre_div", base + 0xb380, 0, 6);
- clks[IMX8MQ_CLK_PWM2_DIV] = imx_clk_divider2("pwm2_div", "pwm2_pre_div", base + 0xb400, 0, 6);
- clks[IMX8MQ_CLK_PWM3_DIV] = imx_clk_divider2("pwm3_div", "pwm3_pre_div", base + 0xb480, 0, 6);
- clks[IMX8MQ_CLK_PWM4_DIV] = imx_clk_divider2("pwm4_div", "pwm4_pre_div", base + 0xb500, 0, 6);
- clks[IMX8MQ_CLK_GPT1_DIV] = imx_clk_divider2("gpt1_div", "gpt1_pre_div", base + 0xb580, 0, 6);
- clks[IMX8MQ_CLK_WDOG_DIV] = imx_clk_divider2("wdog_div", "wdog_pre_div", base + 0xb900, 0, 6);
- clks[IMX8MQ_CLK_WRCLK_DIV] = imx_clk_divider2("wrclk_div", "wrclk_pre_div", base + 0xb980, 0, 6);
- clks[IMX8MQ_CLK_CLKO2_DIV] = imx_clk_divider2("clko2_div", "clko2_pre_div", base + 0xba80, 0, 6);
- clks[IMX8MQ_CLK_PCIE2_CTRL_DIV] = imx_clk_divider2("pcie2_ctrl_div", "pcie2_ctrl_pre_div", base + 0xc000, 0, 6);
- clks[IMX8MQ_CLK_PCIE2_PHY_DIV] = imx_clk_divider2("pcie2_phy_div", "pcie2_phy_pre_div", base + 0xc080, 0, 6);
- clks[IMX8MQ_CLK_PCIE2_AUX_DIV] = imx_clk_divider2("pcie2_aux_div", "pcie2_aux_pre_div", base + 0xc100, 0, 6);
- clks[IMX8MQ_CLK_ECSPI3_DIV] = imx_clk_divider2("ecspi3_div", "ecspi3_pre_div", base + 0xc180, 0, 6);
-
- /*FIXME, the doc is not ready now */
- clks[IMX8MQ_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1_div", base + 0x4070, 0);
- clks[IMX8MQ_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2_div", base + 0x4080, 0);
- clks[IMX8MQ_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3_div", base + 0x4090, 0);
- clks[IMX8MQ_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi_div", base + 0x40a0, 0);
- clks[IMX8MQ_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1_div", base + 0x4100, 0);
- clks[IMX8MQ_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1_div", base + 0x4170, 0);
- clks[IMX8MQ_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2_div", base + 0x4180, 0);
- clks[IMX8MQ_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3_div", base + 0x4190, 0);
- clks[IMX8MQ_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4_div", base + 0x41a0, 0);
+
+ clks[IMX8MQ_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000);
+ clks[IMX8MQ_CLK_DRAM_APB] = imx8m_clk_composite("dram_apb", imx8mq_dram_apb_sels, base + 0xa080);
+ clks[IMX8MQ_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mq_vpu_g1_sels, base + 0xa100);
+ clks[IMX8MQ_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mq_vpu_g2_sels, base + 0xa180);
+ clks[IMX8MQ_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mq_disp_dtrc_sels, base + 0xa200);
+ clks[IMX8MQ_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mq_disp_dc8000_sels, base + 0xa280);
+ clks[IMX8MQ_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mq_pcie1_ctrl_sels, base + 0xa300);
+ clks[IMX8MQ_CLK_PCIE1_PHY] = imx8m_clk_composite("pcie1_phy", imx8mq_pcie1_phy_sels, base + 0xa380);
+ clks[IMX8MQ_CLK_PCIE1_AUX] = imx8m_clk_composite("pcie1_aux", imx8mq_pcie1_aux_sels, base + 0xa400);
+ clks[IMX8MQ_CLK_DC_PIXEL] = imx8m_clk_composite("dc_pixel", imx8mq_dc_pixel_sels, base + 0xa480);
+ clks[IMX8MQ_CLK_LCDIF_PIXEL] = imx8m_clk_composite("lcdif_pixel", imx8mq_lcdif_pixel_sels, base + 0xa500);
+ clks[IMX8MQ_CLK_SAI1] = imx8m_clk_composite("sai1", imx8mq_sai1_sels, base + 0xa580);
+ clks[IMX8MQ_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mq_sai2_sels, base + 0xa600);
+ clks[IMX8MQ_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mq_sai3_sels, base + 0xa680);
+ clks[IMX8MQ_CLK_SAI4] = imx8m_clk_composite("sai4", imx8mq_sai4_sels, base + 0xa700);
+ clks[IMX8MQ_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mq_sai5_sels, base + 0xa780);
+ clks[IMX8MQ_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mq_sai6_sels, base + 0xa800);
+ clks[IMX8MQ_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mq_spdif1_sels, base + 0xa880);
+ clks[IMX8MQ_CLK_SPDIF2] = imx8m_clk_composite("spdif2", imx8mq_spdif2_sels, base + 0xa900);
+ clks[IMX8MQ_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mq_enet_ref_sels, base + 0xa980);
+ clks[IMX8MQ_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mq_enet_timer_sels, base + 0xaa00);
+ clks[IMX8MQ_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mq_enet_phy_sels, base + 0xaa80);
+ clks[IMX8MQ_CLK_NAND] = imx8m_clk_composite("nand", imx8mq_nand_sels, base + 0xab00);
+ clks[IMX8MQ_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mq_qspi_sels, base + 0xab80);
+ clks[IMX8MQ_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mq_usdhc1_sels, base + 0xac00);
+ clks[IMX8MQ_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mq_usdhc2_sels, base + 0xac80);
+ clks[IMX8MQ_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mq_i2c1_sels, base + 0xad00);
+ clks[IMX8MQ_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mq_i2c2_sels, base + 0xad80);
+ clks[IMX8MQ_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mq_i2c3_sels, base + 0xae00);
+ clks[IMX8MQ_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mq_i2c4_sels, base + 0xae80);
+ clks[IMX8MQ_CLK_UART1] = imx8m_clk_composite("uart1", imx8mq_uart1_sels, base + 0xaf00);
+ clks[IMX8MQ_CLK_UART2] = imx8m_clk_composite("uart2", imx8mq_uart2_sels, base + 0xaf80);
+ clks[IMX8MQ_CLK_UART3] = imx8m_clk_composite("uart3", imx8mq_uart3_sels, base + 0xb000);
+ clks[IMX8MQ_CLK_UART4] = imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
+ clks[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
+ clks[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
+ clks[IMX8MQ_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
+ clks[IMX8MQ_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
+ clks[IMX8MQ_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
+ clks[IMX8MQ_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mq_pwm2_sels, base + 0xb400);
+ clks[IMX8MQ_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mq_pwm3_sels, base + 0xb480);
+ clks[IMX8MQ_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mq_pwm4_sels, base + 0xb500);
+ clks[IMX8MQ_CLK_GPT1] = imx8m_clk_composite("gpt1", imx8mq_gpt1_sels, base + 0xb580);
+ clks[IMX8MQ_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mq_wdog_sels, base + 0xb900);
+ clks[IMX8MQ_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mq_wrclk_sels, base + 0xb980);
+ clks[IMX8MQ_CLK_CLKO2] = imx8m_clk_composite("clko2", imx8mq_clko2_sels, base + 0xba80);
+ clks[IMX8MQ_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mq_dsi_core_sels, base + 0xbb00);
+ clks[IMX8MQ_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mq_dsi_phy_sels, base + 0xbb80);
+ clks[IMX8MQ_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mq_dsi_dbi_sels, base + 0xbc00);
+ clks[IMX8MQ_CLK_DSI_ESC] = imx8m_clk_composite("dsi_esc", imx8mq_dsi_esc_sels, base + 0xbc80);
+ clks[IMX8MQ_CLK_DSI_AHB] = imx8m_clk_composite("dsi_ahb", imx8mq_dsi_ahb_sels, base + 0x9200);
+ clks[IMX8MQ_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mq_csi1_core_sels, base + 0xbd00);
+ clks[IMX8MQ_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mq_csi1_phy_sels, base + 0xbd80);
+ clks[IMX8MQ_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mq_csi1_esc_sels, base + 0xbe00);
+ clks[IMX8MQ_CLK_CSI2_CORE] = imx8m_clk_composite("csi2_core", imx8mq_csi2_core_sels, base + 0xbe80);
+ clks[IMX8MQ_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mq_csi2_phy_sels, base + 0xbf00);
+ clks[IMX8MQ_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mq_csi2_esc_sels, base + 0xbf80);
+ clks[IMX8MQ_CLK_PCIE2_CTRL] = imx8m_clk_composite("pcie2_ctrl", imx8mq_pcie2_ctrl_sels, base + 0xc000);
+ clks[IMX8MQ_CLK_PCIE2_PHY] = imx8m_clk_composite("pcie2_phy", imx8mq_pcie2_phy_sels, base + 0xc080);
+ clks[IMX8MQ_CLK_PCIE2_AUX] = imx8m_clk_composite("pcie2_aux", imx8mq_pcie2_aux_sels, base + 0xc100);
+ clks[IMX8MQ_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mq_ecspi3_sels, base + 0xc180);
+
+ clks[IMX8MQ_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
+ clks[IMX8MQ_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
+ clks[IMX8MQ_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
+ clks[IMX8MQ_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+ clks[IMX8MQ_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
+ clks[IMX8MQ_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
+ clks[IMX8MQ_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
+ clks[IMX8MQ_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
+ clks[IMX8MQ_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
clks[IMX8MQ_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
clks[IMX8MQ_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
- clks[IMX8MQ_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl_div", base + 0x4250, 0);
- clks[IMX8MQ_CLK_PCIE2_ROOT] = imx_clk_gate4("pcie2_root_clk", "pcie2_ctrl_div", base + 0x4640, 0);
- clks[IMX8MQ_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1_div", base + 0x4280, 0);
- clks[IMX8MQ_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2_div", base + 0x4290, 0);
- clks[IMX8MQ_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3_div", base + 0x42a0, 0);
- clks[IMX8MQ_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4_div", base + 0x42b0, 0);
- clks[IMX8MQ_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi_div", base + 0x42f0, 0);
- clks[IMX8MQ_CLK_RAWNAND_ROOT] = imx_clk_gate4("nand_root_clk", "nand_div", base + 0x4300, 0);
- clks[IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate_shared("nand_usdhc_rawnand_clk", "nand_usdhc_bus_div", "nand_root_clk");
- clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1_div", base + 0x4490, 0);
- clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2_div", base + 0x44a0, 0);
- clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3_div", base + 0x44b0, 0);
- clks[IMX8MQ_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4_div", base + 0x44c0, 0);
- clks[IMX8MQ_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref_div", base + 0x44d0, 0);
- clks[IMX8MQ_CLK_USB2_CTRL_ROOT] = imx_clk_gate4("usb2_ctrl_root_clk", "usb_core_ref_div", base + 0x44e0, 0);
- clks[IMX8MQ_CLK_USB1_PHY_ROOT] = imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref_div", base + 0x44f0, 0);
- clks[IMX8MQ_CLK_USB2_PHY_ROOT] = imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref_div", base + 0x4500, 0);
- clks[IMX8MQ_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_div", base + 0x4510, 0);
- clks[IMX8MQ_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_div", base + 0x4520, 0);
- clks[IMX8MQ_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog_div", base + 0x4530, 0);
- clks[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog_div", base + 0x4540, 0);
- clks[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog_div", base + 0x4550, 0);
+ clks[IMX8MQ_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0);
+ clks[IMX8MQ_CLK_PCIE2_ROOT] = imx_clk_gate4("pcie2_root_clk", "pcie2_ctrl", base + 0x4640, 0);
+ clks[IMX8MQ_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
+ clks[IMX8MQ_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
+ clks[IMX8MQ_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
+ clks[IMX8MQ_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
+ clks[IMX8MQ_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
+ clks[IMX8MQ_CLK_RAWNAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0);
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0);
+ clks[IMX8MQ_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0);
+ clks[IMX8MQ_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0);
+ clks[IMX8MQ_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0);
+ clks[IMX8MQ_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root", base + 0x4340, 0);
+ clks[IMX8MQ_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0);
+ clks[IMX8MQ_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root", base + 0x4350, 0);
+ clks[IMX8MQ_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0);
+ clks[IMX8MQ_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0);
+ clks[IMX8MQ_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0);
+ clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0);
+ clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0);
+ clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0);
+ clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
+ clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
+ clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
+ clks[IMX8MQ_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
+ clks[IMX8MQ_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref", base + 0x44d0, 0);
+ clks[IMX8MQ_CLK_USB2_CTRL_ROOT] = imx_clk_gate4("usb2_ctrl_root_clk", "usb_core_ref", base + 0x44e0, 0);
+ clks[IMX8MQ_CLK_USB1_PHY_ROOT] = imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0);
+ clks[IMX8MQ_CLK_USB2_PHY_ROOT] = imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0);
+ clks[IMX8MQ_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
+ clks[IMX8MQ_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
+ clks[IMX8MQ_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
+ clks[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
+ clks[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
+ clks[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_gate2_flags("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_GPU_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_core_div", base + 0x4570, 0);
+ clks[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_gate2_flags("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0);
+ clks[IMX8MQ_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0);
+ clks[IMX8MQ_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0);
+ clks[IMX8MQ_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0);
clks[IMX8MQ_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
+ clks[IMX8MQ_CLK_VPU_DEC_ROOT] = imx_clk_gate2_flags("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
+ clks[IMX8MQ_CLK_CSI2_ROOT] = imx_clk_gate4("csi2_root_clk", "csi2_core", base + 0x4660, 0);
+ clks[IMX8MQ_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
+ clks[IMX8MQ_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
clks[IMX8MQ_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc_25m", 1, 8);
- clks[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt_div", 1, 4);
+ clks[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
for (i = 0; i < IMX8MQ_CLK_END; i++)
if (IS_ERR(clks[i]))
@@ -587,7 +565,10 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-}
+ err = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ WARN_ON(err);
+
+ return err;
+}
CLK_OF_DECLARE(imx8mq, "fsl,imx8mq-ccm", imx8mq_clocks_init);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index c6ec0fc403..945671cbad 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -102,6 +102,13 @@ static inline struct clk *imx_clk_gate2_shared2(const char *name, const char *pa
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
}
+static inline struct clk *imx_clk_gate2_flags(const char *name,
+ const char *parent, void __iomem *reg, u8 shift,
+ unsigned long flags)
+{
+ return clk_gate2(name, parent, reg, shift, 0x3, flags);
+}
+
static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 cgr_val)
{
@@ -194,4 +201,16 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
+struct clk *imx8m_clk_composite_flags(const char *name,
+ const char **parent_names, int num_parents, void __iomem *reg,
+ unsigned long flags);
+
+#define __imx8m_clk_composite(name, parent_names, reg, flags) \
+ imx8m_clk_composite_flags(name, parent_names, \
+ ARRAY_SIZE(parent_names), reg, \
+ flags | CLK_OPS_PARENT_ENABLE)
+
+#define imx8m_clk_composite(name, parent_names, reg) \
+ __imx8m_clk_composite(name, parent_names, reg, 0)
+
#endif /* __IMX_CLK_H */
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 337a7a2e13..7b04663d2e 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -88,4 +88,10 @@ config CLOCKSOURCE_DW_APB_TIMER
help
Enables the support for the dw_apb timer.
+config CLOCKSOURCE_TI_DM
+ bool
+
+config CLOCKSOURCE_TI_32K
+ bool
+
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index ab78f0700d..f8ff83d60a 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -15,3 +15,5 @@ obj-$(CONFIG_CLOCKSOURCE_ARMV8_TIMER) += armv8-timer.o
obj-$(CONFIG_CLOCKSOURCE_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLOCKSOURCE_IMX_GPT) += timer-imx-gpt.o
obj-$(CONFIG_CLOCKSOURCE_DW_APB_TIMER) += dw_apb_timer.o
+obj-$(CONFIG_CLOCKSOURCE_TI_DM) += timer-ti-dm.o
+obj-$(CONFIG_CLOCKSOURCE_TI_32K) += timer-ti-32k.o \ No newline at end of file
diff --git a/drivers/clocksource/clps711x.c b/drivers/clocksource/clps711x.c
index f6399e9300..a99147f30c 100644
--- a/drivers/clocksource/clps711x.c
+++ b/drivers/clocksource/clps711x.c
@@ -1,11 +1,5 @@
-/*
- * Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+/* Author: Alexander Shiyan <shc_work@mail.ru> */
#include <common.h>
#include <clock.h>
@@ -51,13 +45,14 @@ static int clps711x_cs_probe(struct device_d *dev)
return init_clock(&clps711x_cs);
}
+static __maybe_unused struct of_device_id clps711x_timer_dt_ids[] = {
+ { .compatible = "cirrus,ep7209-timer", },
+ { }
+};
+
static struct driver_d clps711x_cs_driver = {
.name = "clps711x-cs",
.probe = clps711x_cs_probe,
+ .of_compatible = DRV_OF_COMPAT(clps711x_timer_dt_ids),
};
-
-static __init int clps711x_cs_init(void)
-{
- return platform_driver_register(&clps711x_cs_driver);
-}
-coredevice_initcall(clps711x_cs_init);
+coredevice_platform_driver(clps711x_cs_driver);
diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
index 40895847f0..e23f1e5ec4 100644
--- a/drivers/clocksource/timer-atmel-pit.c
+++ b/drivers/clocksource/timer-atmel-pit.c
@@ -40,7 +40,7 @@
static __iomem void *pit_base;
-uint64_t at91sam9_clocksource_read(void)
+static uint64_t at91sam9_clocksource_read(void)
{
return pit_read(AT91_PIT_PIIR);
}
diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c
new file mode 100644
index 0000000000..f93ab5bcff
--- /dev/null
+++ b/drivers/clocksource/timer-ti-32k.c
@@ -0,0 +1,106 @@
+/**
+ * @file
+ * @brief Provide @ref clocksource functionality for OMAP
+ *
+ * @ref clocksource provides a neat architecture. all we do is
+ * To loop in with Sync 32Khz clock ticking away at 32768hz on OMAP.
+ * Sync 32Khz clock is an always ON clock.
+ *
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <init.h>
+#include <io.h>
+#include <mach/omap3-silicon.h>
+#include <mach/omap4-silicon.h>
+#include <mach/clocks.h>
+#include <mach/timers.h>
+#include <mach/sys_info.h>
+#include <mach/syslib.h>
+
+/** Sync 32Khz Timer registers */
+#define S32K_CR 0x10
+#define S32K_FREQUENCY 32768
+
+static void __iomem *timerbase;
+
+/**
+ * @brief Provide a simple clock read
+ *
+ * Nothing is simpler.. read direct from clock and provide it
+ * to the caller.
+ *
+ * @return S32K clock counter
+ */
+static uint64_t s32k_clocksource_read(void)
+{
+ return readl(timerbase + S32K_CR);
+}
+
+/* A bit obvious isn't it? */
+static struct clocksource s32k_cs = {
+ .read = s32k_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 10,
+};
+
+/**
+ * @brief Initialize the Clock
+ *
+ * There is nothing to do on OMAP as SYNC32K clock is
+ * always on, and we do a simple data structure initialization.
+ * 32K clock gives 32768 ticks a seconds
+ *
+ * @return result of @ref init_clock
+ */
+static int omap_32ktimer_probe(struct device_d *dev)
+{
+ struct resource *iores;
+
+ /* one timer is enough */
+ if (timerbase)
+ return 0;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ timerbase = IOMEM(iores->start);
+
+ s32k_cs.mult = clocksource_hz2mult(S32K_FREQUENCY, s32k_cs.shift);
+
+ return init_clock(&s32k_cs);
+}
+
+static __maybe_unused struct of_device_id omap_32ktimer_dt_ids[] = {
+ {
+ .compatible = "ti,omap-counter32k",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d omap_32ktimer_driver = {
+ .name = "omap-32ktimer",
+ .probe = omap_32ktimer_probe,
+ .of_compatible = DRV_OF_COMPAT(omap_32ktimer_dt_ids),
+};
+
+static int omap_32ktimer_init(void)
+{
+ return platform_driver_register(&omap_32ktimer_driver);
+}
+postcore_initcall(omap_32ktimer_init);
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
new file mode 100644
index 0000000000..f41f0bb423
--- /dev/null
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -0,0 +1,119 @@
+/**
+ * @file
+ * @brief Support DMTimer counter
+ *
+ * FileName: arch/arm/mach-omap/dmtimer.c
+ */
+/*
+ * This File is based on arch/arm/mach-omap/s32k_clksource.c
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * (C) Copyright 2012 Phytec Messtechnik GmbH
+ * Author: Teresa Gámez <t.gamez@phytec.de>
+ * (C) Copyright 2015 Phytec Messtechnik GmbH
+ * Author: Daniel Schultz <d.schultz@phytec.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <init.h>
+#include <io.h>
+#include <mach/am33xx-silicon.h>
+#include <mach/am33xx-clock.h>
+
+#include <stdio.h>
+
+#define CLK_RC32K 32768
+
+#define TIDR 0x0
+#define TIOCP_CFG 0x10
+#define IRQ_EOI 0x20
+#define IRQSTATUS_RAW 0x24
+#define IRQSTATUS 0x28
+#define IRQSTATUS_SET 0x2c
+#define IRQSTATUS_CLR 0x30
+#define IRQWAKEEN 0x34
+#define TCLR 0x38
+#define TCRR 0x3C
+#define TLDR 0x40
+#define TTGR 0x44
+#define TWPS 0x48
+#define TMAR 0x4C
+#define TCAR1 0x50
+#define TSICR 0x54
+#define TCAR2 0x58
+
+static void *base;
+
+/**
+ * @brief Provide a simple counter read
+ *
+ * @return DMTimer counter
+ */
+static uint64_t dmtimer_read(void)
+{
+ return readl(base + TCRR);
+}
+
+static struct clocksource dmtimer_cs = {
+ .read = dmtimer_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 10,
+};
+
+static int omap_dmtimer_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ u64 clk_speed;
+
+ /* one timer is enough */
+ if (base)
+ return 0;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ clk_speed = am33xx_get_osc_clock();
+ clk_speed *= 1000;
+ dmtimer_cs.mult = clocksource_hz2mult(clk_speed, dmtimer_cs.shift);
+
+ /* Enable counter */
+ writel(0x3, base + TCLR);
+
+ return init_clock(&dmtimer_cs);
+}
+
+static __maybe_unused struct of_device_id omap_dmtimer_dt_ids[] = {
+ {
+ .compatible = "ti,am335x-timer",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d omap_dmtimer_driver = {
+ .name = "omap-dmtimer",
+ .probe = omap_dmtimer_probe,
+ .of_compatible = DRV_OF_COMPAT(omap_dmtimer_dt_ids),
+};
+
+static int omap_dmtimer_init(void)
+{
+ return platform_driver_register(&omap_dmtimer_driver);
+}
+postcore_initcall(omap_dmtimer_init);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 9f02c17c26..d1687e3774 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -1,7 +1,6 @@
menuconfig CRYPTO_HW
bool "Hardware crypto devices"
- help
if CRYPTO_HW
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index c1ec6ab685..44f40c36e4 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -1,11 +1,5 @@
-/*
- * Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+/* Author: Alexander Shiyan <shc_work@mail.ru> */
#include <init.h>
#include <common.h>
@@ -71,7 +65,7 @@ out_err:
}
static struct of_device_id __maybe_unused clps711x_gpio_dt_ids[] = {
- { .compatible = "cirrus,clps711x-gpio", },
+ { .compatible = "cirrus,ep7209-gpio", },
{ /* sentinel */ }
};
@@ -80,9 +74,4 @@ static struct driver_d clps711x_gpio_driver = {
.probe = clps711x_gpio_probe,
.of_compatible = DRV_OF_COMPAT(clps711x_gpio_dt_ids),
};
-
-static __init int clps711x_gpio_register(void)
-{
- return platform_driver_register(&clps711x_gpio_driver);
-}
-coredevice_initcall(clps711x_gpio_register);
+coredevice_platform_driver(clps711x_gpio_driver);
diff --git a/drivers/led/core.c b/drivers/led/core.c
index a388e6b365..431966d067 100644
--- a/drivers/led/core.c
+++ b/drivers/led/core.c
@@ -127,12 +127,13 @@ static void led_blink_func(struct poller_struct *poller)
struct led *led;
list_for_each_entry(led, &leds, list) {
+ const uint64_t now = get_time_ns();
int on;
if (!led->blink && !led->flash)
continue;
- if (led->blink_next_event > get_time_ns()) {
+ if (led->blink_next_event > now) {
continue;
}
@@ -140,7 +141,7 @@ static void led_blink_func(struct poller_struct *poller)
if (on)
on = led->max_value;
- led->blink_next_event = get_time_ns() +
+ led->blink_next_event = now +
(led->blink_states[led->blink_next_state] * MSECOND);
led->blink_next_state = (led->blink_next_state + 1) %
led->blink_nr_states;
@@ -176,7 +177,7 @@ int led_blink_pattern(struct led *led, const unsigned int *pattern,
pattern_len * sizeof(*led->blink_states));
led->blink_nr_states = pattern_len;
led->blink_next_state = 0;
- led->blink_next_event = get_time_ns();
+ led->blink_next_event = 0;
led->blink = 1;
led->flash = 0;
@@ -187,7 +188,7 @@ int led_blink(struct led *led, unsigned int on_ms, unsigned int off_ms)
{
unsigned int pattern[] = {on_ms, off_ms};
- return led_blink_pattern(led, pattern, 2);
+ return led_blink_pattern(led, ARRAY_AND_SIZE(pattern));
}
int led_flash(struct led *led, unsigned int duration_ms)
@@ -195,7 +196,7 @@ int led_flash(struct led *led, unsigned int duration_ms)
unsigned int pattern[] = {duration_ms, 0};
int ret;
- ret = led_blink_pattern(led, pattern, 2);
+ ret = led_blink_pattern(led, ARRAY_AND_SIZE(pattern));
if (ret)
return ret;
diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c
index e4c550c3ed..f035317ef2 100644
--- a/drivers/mci/dw_mmc.c
+++ b/drivers/mci/dw_mmc.c
@@ -602,9 +602,6 @@ static int dw_mmc_probe(struct device_d *dev)
host->mci.host_caps &= ~MMC_CAP_BIT_DATA_MASK;
host->mci.host_caps |= pdata->bus_width_caps;
} else if (dev->device_node) {
- const char *alias = of_alias_get(dev->device_node);
- if (alias)
- host->mci.devname = xstrdup(alias);
of_property_read_u32(dev->device_node, "dw-mshc-ciu-div",
&host->ciu_div);
}
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 7f2285635b..09df7945cb 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -668,10 +668,6 @@ static int fsl_esdhc_probe(struct device_d *dev)
mci->host_caps = pdata->caps;
if (pdata->devname)
mci->devname = pdata->devname;
- } else if (dev->device_node) {
- const char *alias = of_alias_get(dev->device_node);
- if (alias)
- mci->devname = xstrdup(alias);
}
if (caps & ESDHC_HOSTCAPBLT_HSS)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index c8d1d5e164..67257bcd18 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1628,7 +1628,12 @@ static int mci_register_partition(struct mci_part *part)
if (np) {
of_parse_partitions(&part->blk.cdev, np);
- of_partitions_register_fixup(&part->blk.cdev);
+
+ /* bootN-partitions binding barebox-specific, so don't register
+ * for fixup into kernel device tree
+ */
+ if (part->area_type != MMC_BLK_DATA_AREA_BOOT)
+ of_partitions_register_fixup(&part->blk.cdev);
}
return 0;
@@ -1650,13 +1655,11 @@ static int mci_card_probe(struct mci *mci)
return -ENODEV;
}
- if (!IS_ERR(host->supply)) {
- ret = regulator_enable(host->supply);
- if (ret) {
- dev_err(&mci->dev, "failed to enable regulator: %s\n",
- strerror(-ret));
- return ret;
- }
+ ret = regulator_enable(host->supply);
+ if (ret) {
+ dev_err(&mci->dev, "failed to enable regulator: %s\n",
+ strerror(-ret));
+ return ret;
}
/* start with a host interface reset */
@@ -1728,8 +1731,7 @@ on_error:
if (rc != 0) {
host->clock = 0; /* disable the MCI clock */
mci_set_ios(mci);
- if (!IS_ERR(host->supply))
- regulator_disable(host->supply);
+ regulator_disable(host->supply);
}
return rc;
@@ -1816,8 +1818,10 @@ int mci_register(struct mci_host *host)
mci->dev.detect = mci_detect;
host->supply = regulator_get(host->hw_dev, "vmmc");
- if (IS_ERR(host->supply))
+ if (IS_ERR(host->supply)) {
dev_err(&mci->dev, "Failed to get 'vmmc' regulator.\n");
+ host->supply = NULL;
+ }
ret = register_device(&mci->dev);
if (ret)
@@ -1858,6 +1862,7 @@ void mci_of_parse_node(struct mci_host *host,
{
u32 bus_width;
u32 dsr_val;
+ const char *alias;
if (!IS_ENABLED(CONFIG_OFDEVICE))
return;
@@ -1865,6 +1870,10 @@ void mci_of_parse_node(struct mci_host *host,
if (!host->hw_dev || !np)
return;
+ alias = of_alias_get(np);
+ if (alias)
+ host->devname = xstrdup(alias);
+
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
/* If bus-width is missing we get the driver's default, which
diff --git a/drivers/mci/mxs.c b/drivers/mci/mxs.c
index 446da8ad53..afd6a56397 100644
--- a/drivers/mci/mxs.c
+++ b/drivers/mci/mxs.c
@@ -574,12 +574,6 @@ static int mxs_mci_probe(struct device_d *hw_dev)
/* fixed to 3.3 V */
host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- if (hw_dev->device_node) {
- const char *alias = of_alias_get(hw_dev->device_node);
- if (alias)
- host->devname = xstrdup(alias);
- }
-
mci_of_parse(host);
}
diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c
index cbc69e4083..4e809bae4f 100644
--- a/drivers/mci/omap_hsmmc.c
+++ b/drivers/mci/omap_hsmmc.c
@@ -316,13 +316,16 @@ static int mmc_read_data(struct omap_hsmmc *hsmmc, char *buf, unsigned int size)
do {
mmc_stat = readl(&mmc_base->stat);
if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for status!\n");
+ dev_err(hsmmc->dev, "timedout waiting for status!\n");
return -ETIMEDOUT;
}
} while (mmc_stat == 0);
- if ((mmc_stat & ERRI_MASK) != 0)
- return 1;
+ if ((mmc_stat & ERRI_MASK) != 0) {
+ dev_err(hsmmc->dev, "Error while reading data. status: 0x%08x\n",
+ mmc_stat);
+ return -EIO;
+ }
if (mmc_stat & BRR_MASK) {
unsigned int k;
@@ -349,7 +352,6 @@ static int mmc_read_data(struct omap_hsmmc *hsmmc, char *buf, unsigned int size)
return 0;
}
-#ifdef CONFIG_MCI_WRITE
static int mmc_write_data(struct omap_hsmmc *hsmmc, const char *buf, unsigned int size)
{
struct hsmmc *mmc_base = hsmmc->base;
@@ -373,8 +375,11 @@ static int mmc_write_data(struct omap_hsmmc *hsmmc, const char *buf, unsigned in
}
} while (mmc_stat == 0);
- if ((mmc_stat & ERRI_MASK) != 0)
- return 1;
+ if ((mmc_stat & ERRI_MASK) != 0) {
+ dev_err(hsmmc->dev, "Error while reading data. status: 0x%08x\n",
+ mmc_stat);
+ return -EIO;
+ }
if (mmc_stat & BWR_MASK) {
unsigned int k;
@@ -400,7 +405,6 @@ static int mmc_write_data(struct omap_hsmmc *hsmmc, const char *buf, unsigned in
}
return 0;
}
-#endif
static int mmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
struct mci_data *data)
@@ -511,13 +515,18 @@ static int mmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
}
}
- if (data && (data->flags & MMC_DATA_READ))
- mmc_read_data(hsmmc, data->dest, data->blocksize * data->blocks);
-#ifdef CONFIG_MCI_WRITE
- else if (data && (data->flags & MMC_DATA_WRITE))
- mmc_write_data(hsmmc, data->src, data->blocksize * data->blocks);
-#endif
- return 0;
+ if (!data)
+ return 0;
+
+ if (data->flags & MMC_DATA_READ)
+ return mmc_read_data(hsmmc, data->dest,
+ data->blocksize * data->blocks);
+
+ if (IS_ENABLED(CONFIG_MCI_WRITE))
+ return mmc_write_data(hsmmc, data->src,
+ data->blocksize * data->blocks);
+
+ return -ENOSYS;
}
static void mmc_set_ios(struct mci_host *mci, struct mci_ios *ios)
@@ -625,12 +634,6 @@ static int omap_mmc_probe(struct device_d *dev)
hsmmc->mci.devname = pdata->devname;
}
- if (dev->device_node) {
- const char *alias = of_alias_get(dev->device_node);
- if (alias)
- hsmmc->mci.devname = xstrdup(alias);
- }
-
mci_of_parse(&hsmmc->mci);
dev->priv = hsmmc;
diff --git a/drivers/mci/tegra-sdmmc.c b/drivers/mci/tegra-sdmmc.c
index e465d891a2..4c47918076 100644
--- a/drivers/mci/tegra-sdmmc.c
+++ b/drivers/mci/tegra-sdmmc.c
@@ -411,10 +411,7 @@ static int tegra_sdmmc_detect(struct device_d *dev)
static void tegra_sdmmc_parse_dt(struct tegra_sdmmc_host *host)
{
struct device_node *np = host->mci.hw_dev->device_node;
- const char *alias = of_alias_get(np);
- if (alias)
- host->mci.devname = xstrdup(alias);
host->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0);
host->gpio_pwr = of_get_named_gpio(np, "power-gpios", 0);
mci_of_parse(&host->mci);
diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c
index 469ce4cc0d..1448c4143f 100644
--- a/drivers/mfd/rave-sp.c
+++ b/drivers/mfd/rave-sp.c
@@ -57,6 +57,8 @@
#define RAVE_SP_TX_BUFFER_SIZE \
(RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE)
+#define RAVE_SP_IPADDR_INVALID U32_MAX
+
/**
* enum rave_sp_deframer_state - Possible state for de-framer
*
@@ -183,6 +185,7 @@ struct rave_sp_variant {
* @part_number_bootloader: Bootloader version
*/
struct rave_sp {
+ struct device_d dev;
struct serdev_device *serdev;
struct rave_sp_deframer deframer;
unsigned int ackid;
@@ -192,6 +195,9 @@ struct rave_sp {
const char *part_number_firmware;
const char *part_number_bootloader;
+
+ IPaddr_t ipaddr;
+ IPaddr_t netmask;
};
static bool rave_sp_id_is_event(u8 code)
@@ -314,7 +320,6 @@ int rave_sp_exec(struct rave_sp *sp,
unsigned char *data = __data;
int command, ret = 0;
u8 ackid;
- uint64_t start = get_time_ns();
command = sp->variant->cmd.translate(data[0]);
if (command < 0)
@@ -334,12 +339,9 @@ int rave_sp_exec(struct rave_sp *sp,
* is_timeout will implicitly poll serdev via poller
* infrastructure
*/
- while (!is_timeout(start, SECOND) && !reply.received)
- ;
-
- if (!reply.received) {
+ ret = wait_on_timeout(SECOND, reply.received);
+ if (ret) {
dev_err(dev, "Command timeout\n");
- ret = -ETIMEDOUT;
sp->reply = NULL;
}
@@ -718,6 +720,65 @@ static const struct of_device_id __maybe_unused rave_sp_dt_ids[] = {
{ /* sentinel */ }
};
+static int rave_sp_req_ip_addr(struct param_d *p, void *context)
+{
+ struct rave_sp *sp = context;
+ u8 cmd[] = {
+ [0] = RAVE_SP_CMD_REQ_IP_ADDR,
+ [1] = 0,
+ [2] = 0, /* FIXME: Support for RJU? */
+ [3] = 0, /* Add support for IPs other than "self" */
+ };
+ struct {
+ __le32 ipaddr;
+ __le32 netmask;
+ } __packed rsp;
+ int ret;
+
+ /*
+ * We only query RAVE SP device for IP/Netmask once, after
+ * that we just "serve" cached data.
+ */
+ if (sp->ipaddr != RAVE_SP_IPADDR_INVALID)
+ return 0;
+
+ ret = rave_sp_exec(sp, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
+ if (ret < 0)
+ return ret;
+
+ sp->ipaddr = le32_to_cpu(rsp.ipaddr);
+ sp->netmask = le32_to_cpu(rsp.netmask);
+
+ return 0;
+}
+
+static int rave_sp_add_params(struct rave_sp *sp)
+{
+ struct device_d *dev = &sp->dev;
+ struct param_d *p;
+ int ret;
+
+ dev->parent = sp->serdev->dev;
+ dev_set_name(dev, "sp");
+ dev->id = DEVICE_ID_SINGLE;
+
+ ret = register_device(dev);
+ if (ret)
+ return ret;
+
+ p = dev_add_param_ip(dev, "ipaddr", NULL, rave_sp_req_ip_addr,
+ &sp->ipaddr, sp);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ p = dev_add_param_ip(dev, "netmask", NULL, rave_sp_req_ip_addr,
+ &sp->netmask, sp);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ return 0;
+}
+
static int rave_sp_probe(struct device_d *dev)
{
struct serdev_device *serdev = to_serdev_device(dev->parent);
@@ -733,6 +794,7 @@ static int rave_sp_probe(struct device_d *dev)
sp = xzalloc(sizeof(*sp));
sp->serdev = serdev;
+ sp->ipaddr = RAVE_SP_IPADDR_INVALID;
dev->priv = sp;
serdev->dev = dev;
serdev->receive_buf = rave_sp_receive_buf;
@@ -773,6 +835,12 @@ static int rave_sp_probe(struct device_d *dev)
dev_info(dev, "Firmware version: %s", sp->part_number_firmware);
dev_info(dev, "Bootloader version: %s", sp->part_number_bootloader);
+ ret = rave_sp_add_params(sp);
+ if (ret) {
+ dev_err(dev, "Failed to add parameters to RAVE SP\n");
+ return ret;
+ }
+
return of_platform_populate(dev->device_node, NULL, dev);
}
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 957d9a7267..30ed65f737 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -176,7 +176,7 @@ static int syscon_probe(struct device_d *dev)
syscon->base = IOMEM(res->start);
dev->priv = syscon;
- dev_dbg(dev, "map 0x%x-0x%x registered\n", res->start, res->end);
+ dev_dbg(dev, "map %pa-%pa registered\n", &res->start, &res->end);
return 0;
}
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index d3cbe502fa..f44c6cfc69 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -141,15 +141,28 @@ static struct mtd_erase_region_info *mtd_find_erase_region(struct mtd_info *mtd,
return NULL;
}
+static loff_t __mtd_erase_round(loff_t x, uint32_t esize, int up)
+{
+ uint64_t dividend = x;
+ uint32_t mod = do_div(dividend, esize);
+ if (mod == 0)
+ return x;
+ if (up)
+ x += esize;
+ return x - mod;
+}
+#define mtd_erase_round_up(x, esize) __mtd_erase_round(x, esize, 1)
+#define mtd_erase_round_down(x, esize) __mtd_erase_round(x, esize, 0)
+
static int mtd_erase_align(struct mtd_info *mtd, loff_t *count, loff_t *offset)
{
struct mtd_erase_region_info *e;
loff_t ofs;
if (mtd->numeraseregions == 0) {
- ofs = *offset & ~(loff_t)(mtd->erasesize - 1);
- *count += (*offset - ofs);
- *count = ALIGN(*count, mtd->erasesize);
+ ofs = mtd_erase_round_down(*offset, mtd->erasesize);
+ *count += *offset - ofs;
+ *count = mtd_erase_round_up(*count, mtd->erasesize);
*offset = ofs;
return 0;
}
@@ -158,14 +171,14 @@ static int mtd_erase_align(struct mtd_info *mtd, loff_t *count, loff_t *offset)
if (!e)
return -EINVAL;
- ofs = *offset & ~(e->erasesize - 1);
- *count += (*offset - ofs);
+ ofs = mtd_erase_round_down(*offset, e->erasesize);
+ *count += *offset - ofs;
e = mtd_find_erase_region(mtd, *offset + *count);
if (!e)
return -EINVAL;
- *count = ALIGN(*count, e->erasesize);
+ *count = mtd_erase_round_up(*count, e->erasesize);
*offset = ofs;
return 0;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 4c1725d096..b4d4e79d91 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1297,6 +1297,7 @@ static int atmel_hw_nand_init_params(struct device_d *dev,
nand_chip->ecc.hwctl = atmel_nand_hwctl;
nand_chip->ecc.read_page = atmel_nand_read_page;
nand_chip->ecc.bytes = 4;
+ nand_chip->ecc.strength = 1;
return 0;
}
@@ -1387,6 +1388,8 @@ static int __init atmel_nand_probe(struct device_d *dev)
}
nand_chip->ecc.mode = pdata->ecc_mode;
+ nand_chip->ecc.strength = pdata->ecc_strength ? : 1;
+ nand_chip->ecc.size = 1 << pdata->ecc_size_shift ? : 512;
if (IS_ENABLED(CONFIG_NAND_ECC_HW) &&
pdata->ecc_mode == NAND_ECC_HW) {
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 128802fa5c..8ae6f34468 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -36,13 +36,13 @@
#include <clock.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
-#include <linux/err.h>
+#include <linux/mtd/nand_bch.h>
#include <linux/mtd/nand_ecc.h>
+#include <linux/err.h>
#include <asm/byteorder.h>
#include <io.h>
#include <malloc.h>
#include <module.h>
-#include <linux/mtd/nand_bch.h>
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
@@ -326,28 +326,70 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
}
/**
- * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This is the default implementation, which can be overridden by a hardware
- * specific driver. We try operations in the following order, according to our
- * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ * specific driver. It provides the details for writing a bad block marker to a
+ * block.
+ */
+static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mtd_oob_ops ops;
+ uint8_t buf[2] = { 0, 0 };
+ int ret = 0, res, i = 0;
+
+ ops.datbuf = NULL;
+ ops.oobbuf = buf;
+ ops.ooboffs = chip->badblockpos;
+ if (chip->options & NAND_BUSWIDTH_16) {
+ ops.ooboffs &= ~0x01;
+ ops.len = ops.ooblen = 2;
+ } else {
+ ops.len = ops.ooblen = 1;
+ }
+ ops.mode = MTD_OPS_PLACE_OOB;
+
+ /* Write to first/last page(s) if necessary */
+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+ ofs += mtd->erasesize - mtd->writesize;
+ do {
+ res = nand_do_write_oob(mtd, ofs, &ops);
+ if (!ret)
+ ret = res;
+
+ i++;
+ ofs += mtd->writesize;
+ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+ return ret;
+}
+
+/**
+ * nand_block_markbad_lowlevel - mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This function performs the generic NAND bad block marking steps (i.e., bad
+ * block table(s) and/or marker(s)). We only allow the hardware driver to
+ * specify how to write bad block markers to OOB (chip->block_markbad).
+ *
+ * We try operations in the following order:
* (1) erase the affected block, to allow OOB marker to be written cleanly
- * (2) update in-memory BBT
- * (3) write bad block marker to OOB area of affected block
- * (4) update flash-based BBT
- * Note that we retain the first error encountered in (3) or (4), finish the
+ * (2) write bad block marker to OOB area of affected block (unless flag
+ * NAND_BBT_NO_OOB_BBM is present)
+ * (3) update the BBT
+ * Note that we retain the first error encountered in (2) or (3), finish the
* procedures, and dump the error in the end.
-*/
-static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+ */
+static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
- uint8_t buf[2] = { 0, 0 };
- int block, res, ret = 0, i = 0;
- int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
+ int res, ret = 0;
- if (write_oob) {
+ if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
struct erase_info einfo;
/* Attempt erase before marking OOB */
@@ -356,50 +398,16 @@ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff
einfo.addr = ofs;
einfo.len = 1 << chip->phys_erase_shift;
nand_erase_nand(mtd, &einfo, 0);
- }
-
- /* Get block number */
- block = (int)(ofs >> chip->bbt_erase_shift);
- /* Mark block bad in memory-based BBT */
- if (chip->bbt)
- chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
-
- /* Write bad block marker to OOB */
- if (write_oob) {
- struct mtd_oob_ops ops;
- loff_t wr_ofs = ofs;
+ /* Write bad block marker to OOB */
nand_get_device(mtd, FL_WRITING);
-
- ops.datbuf = NULL;
- ops.oobbuf = buf;
- ops.ooboffs = chip->badblockpos;
- if (chip->options & NAND_BUSWIDTH_16) {
- ops.ooboffs &= ~0x01;
- ops.len = ops.ooblen = 2;
- } else {
- ops.len = ops.ooblen = 1;
- }
- ops.mode = MTD_OPS_PLACE_OOB;
-
- /* Write to first/last page(s) if necessary */
- if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
- wr_ofs += mtd->erasesize - mtd->writesize;
- do {
- res = nand_do_write_oob(mtd, wr_ofs, &ops);
- if (!ret)
- ret = res;
-
- i++;
- wr_ofs += mtd->writesize;
- } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-
+ ret = chip->block_markbad(mtd, ofs);
nand_release_device(mtd);
}
- /* Update flash-based bad block table */
- if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt_options & NAND_BBT_USE_FLASH) {
- res = nand_update_bbt(mtd, ofs);
+ /* Mark block bad in BBT */
+ if (chip->bbt) {
+ res = nand_markbad_bbt(mtd, ofs);
if (!ret)
ret = res;
}
@@ -411,6 +419,57 @@ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff
}
/**
+ * nand_block_markgood_lowlevel - mark a block good
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * We try operations in the following order:
+ * (1) erase the affected block
+ * (2) check bad block marker
+ * (3) update the BBT
+ */
+static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ bool allow_erasebad;
+ int ret;
+
+ if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+ struct erase_info einfo;
+
+ /* Attempt erase possibly bad block */
+ allow_erasebad = mtd->allow_erasebad;
+ mtd->allow_erasebad = true;
+ memset(&einfo, 0, sizeof(einfo));
+ einfo.mtd = mtd;
+ einfo.addr = ofs;
+ einfo.len = 1 << chip->phys_erase_shift;
+ nand_erase_nand(mtd, &einfo, 0);
+ mtd->allow_erasebad = allow_erasebad;
+
+ /*
+ * Verify erase succeded. We need to select chip again,
+ * as nand_erase_nand deselected it.
+ */
+ ret = chip->block_bad(mtd, ofs, 1);
+ if (ret)
+ return ret;
+ }
+
+ /* Mark block good in BBT */
+ if (chip->bbt) {
+ ret = nand_markgood_bbt(mtd, ofs);
+ if (ret)
+ return ret;
+ }
+
+ if (mtd->ecc_stats.badblocks > 0)
+ mtd->ecc_stats.badblocks--;
+
+ return 0;
+}
+
+/**
* nand_check_wp - [GENERIC] check if the chip is write protected
* @mtd: MTD device structure
*
@@ -453,38 +512,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return chip->block_bad(mtd, ofs, getchip);
}
-/**
- * nand_default_block_markgood - [DEFAULT] mark a block good
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * This is the default implementation, which can be overridden by
- * a hardware specific driver.
-*/
-static __maybe_unused int nand_default_block_markgood(struct mtd_info *mtd, loff_t ofs)
-{
- struct nand_chip *chip = mtd->priv;
- int block, res, ret = 0;
-
- /* Get block number */
- block = (int)(ofs >> chip->bbt_erase_shift);
- /* Mark block good in memory-based BBT */
- if (chip->bbt)
- chip->bbt[block >> 2] &= ~(0x01 << ((block & 0x03) << 1));
-
- /* Update flash-based bad block table */
- if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt_options & NAND_BBT_USE_FLASH) {
- res = nand_update_bbt(mtd, ofs);
- if (!ret)
- ret = res;
- }
-
- if (!ret)
- mtd->ecc_stats.badblocks++;
-
- return ret;
-}
-
/* Wait for the ready pin, after a command. The timeout is caught later. */
void nand_wait_ready(struct mtd_info *mtd)
{
@@ -2804,7 +2831,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
*/
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
int ret;
if (!IS_ENABLED(CONFIG_MTD_WRITE))
@@ -2818,17 +2844,16 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret;
}
- return chip->block_markbad(mtd, ofs);
+ return nand_block_markbad_lowlevel(mtd, ofs);
}
/**
- * nand_block_markgood - [MTD Interface] Mark block at the given offset as bad
+ * nand_block_markgood - [MTD Interface] Mark block at the given offset as good
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
*/
static int nand_block_markgood(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
int ret;
if (!IS_ENABLED(CONFIG_MTD_WRITE))
@@ -2842,7 +2867,7 @@ static int nand_block_markgood(struct mtd_info *mtd, loff_t ofs)
if (!ret)
return 0;
- return chip->block_markgood(mtd, ofs);
+ return nand_block_markgood_lowlevel(mtd, ofs);
}
/**
@@ -2926,17 +2951,11 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
#ifdef CONFIG_MTD_WRITE
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
- if (!chip->block_markgood)
- chip->block_markgood = nand_default_block_markgood;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
#endif
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-#ifdef CONFIG_NAND_BBT
- if (!chip->scan_bbt)
- chip->scan_bbt = nand_default_bbt;
-#endif
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
}
@@ -3100,6 +3119,16 @@ static int nand_id_len(u8 *id_data, int arrlen)
return arrlen;
}
+/* Extract the bits of per cell from the 3rd byte of the extended ID */
+static int nand_get_bits_per_cell(u8 cellinfo)
+{
+ int bits;
+
+ bits = cellinfo & NAND_CI_CELLTYPE_MSK;
+ bits >>= NAND_CI_CELLTYPE_SHIFT;
+ return bits + 1;
+}
+
/*
* Many new NAND share similar device ID codes, which represent the size of the
* chip. The rest of the parameters must be decoded according to generic or
@@ -3110,7 +3139,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
{
int extid, id_len;
/* The 3rd id byte holds MLC / multichip data */
- chip->cellinfo = id_data[2];
+ chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
/* The 4th id byte is the important one */
extid = id_data[3];
@@ -3126,8 +3155,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
* ID to decide what to do.
*/
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
- (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
- id_data[5] != 0x00) {
+ !nand_is_slc(chip) && id_data[5] != 0x00) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
@@ -3159,7 +3187,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
(((extid >> 1) & 0x04) | (extid & 0x03));
*busw = 0;
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
- (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+ !nand_is_slc(chip)) {
unsigned int tmp;
/* Calc pagesize */
@@ -3212,6 +3240,20 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
extid >>= 2;
/* Get buswidth information */
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ /*
+ * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+ * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+ * follows:
+ * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+ * 110b -> 24nm
+ * - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
+ */
+ if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
+ nand_is_slc(chip) &&
+ (id_data[5] & 0x7) == 0x6 /* 24nm */ &&
+ !(id_data[4] & 0x80) /* !BENAND */) {
+ mtd->oobsize = 32 * mtd->writesize >> 9;
+ }
}
}
@@ -3231,6 +3273,9 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
mtd->oobsize = mtd->writesize / 32;
*busw = type->options & NAND_BUSWIDTH_16;
+ /* All legacy ID NAND are small-page, SLC */
+ chip->bits_per_cell = 1;
+
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
@@ -3267,11 +3312,11 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
- if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ if (!nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
- else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ else if ((nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX ||
maf_id == NAND_MFR_TOSHIBA ||
@@ -3295,7 +3340,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
mtd->erasesize = type->erasesize;
mtd->oobsize = type->oobsize;
- chip->cellinfo = id_data[2];
+ chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
chip->chipsize = (uint64_t)type->chipsize << 20;
chip->options |= type->options;
@@ -3675,25 +3720,22 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
/*
- * Board driver should supply ecc.size and ecc.bytes values to
- * select how many bits are correctable; see nand_bch_init()
- * for details. Otherwise, default to 4 bits for large page
- * devices.
+ * Board driver should supply ecc.size and ecc.strength values
+ * to select how many bits are correctable. Otherwise, default
+ * to 4 bits for large page devices.
*/
if (!chip->ecc.size && (mtd->oobsize >= 64)) {
chip->ecc.size = 512;
- chip->ecc.bytes = 7;
+ chip->ecc.strength = 4;
}
- chip->ecc.priv = nand_bch_init(mtd,
- chip->ecc.size,
- chip->ecc.bytes,
- &chip->ecc.layout);
+
+ /* See nand_bch_init() for details. */
+ chip->ecc.bytes = 0;
+ chip->ecc.priv = nand_bch_init(mtd);
if (!chip->ecc.priv) {
pr_warn("BCH ECC initialization failed!\n");
BUG();
}
- chip->ecc.strength =
- chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);
break;
#endif
#ifdef CONFIG_NAND_ECC_NONE
@@ -3744,8 +3786,7 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
- if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
- !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
switch (chip->ecc.steps) {
case 2:
mtd->subpage_sft = 1;
@@ -3805,7 +3846,7 @@ int nand_scan_tail(struct mtd_info *mtd)
return 0;
/* Build bad block table */
- return chip->scan_bbt(mtd);
+ return nand_create_bbt(mtd);
}
EXPORT_SYMBOL(nand_scan_tail);
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 94a2e57834..90c10862c5 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -77,6 +77,8 @@
#define BBT_ENTRY_MASK 0x03
#define BBT_ENTRY_SHIFT 2
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
+
static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
{
uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
@@ -87,8 +89,14 @@ static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
static inline void bbt_mark_entry(struct nand_chip *chip, int block,
uint8_t mark)
{
- uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
- chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+ /*
+ * Unlike original Linux implementation, Barebox needs also
+ * mark block as good again, so mask entry comletely.
+ */
+ int index = block >> BBT_ENTRY_SHIFT;
+ int shift = (block & BBT_ENTRY_MASK) * 2;
+ chip->bbt[index] &= ~(BBT_ENTRY_MASK << shift);
+ chip->bbt[index] |= (mark & BBT_ENTRY_MASK) << shift;
}
static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
@@ -106,33 +114,17 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
* @td: search pattern descriptor
*
* Check for a pattern at the given place. Used to search bad block tables and
- * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
- * all bytes except the pattern area contain 0xff.
+ * good / bad block identifiers.
*/
static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
- int end = 0;
- uint8_t *p = buf;
-
if (td->options & NAND_BBT_NO_OOB)
return check_pattern_no_oob(buf, td);
- end = paglen + td->offs;
- if (td->options & NAND_BBT_SCANEMPTY)
- if (memchr_inv(p, 0xff, end))
- return -1;
- p += end;
-
/* Compare the pattern */
- if (memcmp(p, td->pattern, td->len))
+ if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
return -1;
- if (td->options & NAND_BBT_SCANEMPTY) {
- p += td->len;
- end += td->len;
- if (memchr_inv(p, 0xff, len - end))
- return -1;
- }
return 0;
}
@@ -179,7 +171,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
* @page: the starting page
* @num: the number of bbt descriptors to read
* @td: the bbt describtion table
- * @offs: offset in the memory table
+ * @offs: block number offset in the table
*
* Read the bad block table starting from page.
*/
@@ -229,29 +221,28 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
/* Analyse data */
for (i = 0; i < len; i++) {
uint8_t dat = buf[i];
- for (j = 0; j < 8; j += bits, act += 2) {
+ for (j = 0; j < 8; j += bits, act++) {
uint8_t tmp = (dat >> j) & msk;
if (tmp == msk)
continue;
if (reserved_block_code && (tmp == reserved_block_code)) {
pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
- bbt_mark_entry(this, (offs << 2) +
- (act >> 1),
+ (loff_t)(offs + act) <<
+ this->bbt_erase_shift);
+ bbt_mark_entry(this, offs + act,
BBT_BLOCK_RESERVED);
mtd->ecc_stats.bbtblocks++;
continue;
}
pr_debug("nand_read_bbt: bad block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ (loff_t)(offs + act) <<
+ this->bbt_erase_shift);
/* Factory marked bad or worn out? */
if (tmp == 0)
- bbt_mark_entry(this, (offs << 2) +
- (act >> 1),
+ bbt_mark_entry(this, offs + act,
BBT_BLOCK_FACTORY_BAD);
else
- bbt_mark_entry(this, (offs << 2) +
- (act >> 1),
+ bbt_mark_entry(this, offs + act,
BBT_BLOCK_WORN);
mtd->ecc_stats.badblocks++;
}
@@ -287,7 +278,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
td, offs);
if (res)
return res;
- offs += this->chipsize >> (this->bbt_erase_shift + 2);
+ offs += this->chipsize >> this->bbt_erase_shift;
}
} else {
res = read_bbt(mtd, buf, td->pages[0],
@@ -421,25 +412,6 @@ static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
}
}
-/* Scan a given block full */
-static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
- loff_t offs, uint8_t *buf, size_t readlen,
- int scanlen, int numpages)
-{
- int ret, j;
-
- ret = scan_read_oob(mtd, buf, offs, readlen);
- /* Ignore ECC errors when checking for BBM */
- if (ret && !mtd_is_bitflip_or_eccerr(ret))
- return ret;
-
- for (j = 0; j < numpages; j++, buf += scanlen) {
- if (check_pattern(buf, scanlen, mtd->writesize, bd))
- return 1;
- }
- return 0;
-}
-
/* Scan a given block partially */
static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
loff_t offs, uint8_t *buf, int numpages)
@@ -486,36 +458,19 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
- int i, numblocks, numpages, scanlen;
+ int i, numblocks, numpages;
int startblock;
loff_t from;
- size_t readlen;
pr_info("Scanning device for bad blocks\n");
- if (bd->options & NAND_BBT_SCANALLPAGES)
- numpages = 1 << (this->bbt_erase_shift - this->page_shift);
- else if (bd->options & NAND_BBT_SCAN2NDPAGE)
+ if (bd->options & NAND_BBT_SCAN2NDPAGE)
numpages = 2;
else
numpages = 1;
- if (!(bd->options & NAND_BBT_SCANEMPTY)) {
- /* We need only read few bytes from the OOB area */
- scanlen = 0;
- readlen = bd->len;
- } else {
- /* Full page content should be read */
- scanlen = mtd->writesize + mtd->oobsize;
- readlen = numpages * mtd->writesize;
- }
-
if (chip == -1) {
- /*
- * Note that numblocks is 2 * (real numblocks) here, see i+=2
- * below as it makes shifting and masking less painful
- */
- numblocks = mtd->size >> (this->bbt_erase_shift - 1);
+ numblocks = mtd->size >> this->bbt_erase_shift;
startblock = 0;
from = 0;
} else {
@@ -524,37 +479,31 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
chip + 1, this->numchips);
return -EINVAL;
}
- numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
+ numblocks = this->chipsize >> this->bbt_erase_shift;
startblock = chip * numblocks;
numblocks += startblock;
- from = (loff_t)startblock << (this->bbt_erase_shift - 1);
+ from = (loff_t)startblock << this->bbt_erase_shift;
}
if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
from += mtd->erasesize - (mtd->writesize * numpages);
- for (i = startblock; i < numblocks;) {
+ for (i = startblock; i < numblocks; i++) {
int ret;
BUG_ON(bd->options & NAND_BBT_NO_OOB);
- if (bd->options & NAND_BBT_SCANALLPAGES)
- ret = scan_block_full(mtd, bd, from, buf, readlen,
- scanlen, numpages);
- else
- ret = scan_block_fast(mtd, bd, from, buf, numpages);
-
+ ret = scan_block_fast(mtd, bd, from, buf, numpages);
if (ret < 0)
return ret;
if (ret) {
- bbt_mark_entry(this, i >> 1, BBT_BLOCK_FACTORY_BAD);
+ bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
pr_warn("Bad eraseblock %d at 0x%012llx\n",
- i >> 1, (unsigned long long)from);
+ i, (unsigned long long)from);
mtd->ecc_stats.badblocks++;
}
- i += 2;
from += (1 << this->bbt_erase_shift);
}
return 0;
@@ -659,6 +608,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
}
/**
+ * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
+ * @this: the NAND device
+ * @td: the BBT description
+ * @md: the mirror BBT descriptor
+ * @chip: the CHIP selector
+ *
+ * This functions returns a positive block number pointing a valid eraseblock
+ * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
+ * all blocks are already used of marked bad. If td->pages[chip] was already
+ * pointing to a valid block we re-use it, otherwise we search for the next
+ * valid one.
+ */
+static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
+ struct nand_bbt_descr *md, int chip)
+{
+ int startblock, dir, page, numblocks, i;
+
+ /*
+ * There was already a version of the table, reuse the page. This
+ * applies for absolute placement too, as we have the page number in
+ * td->pages.
+ */
+ if (td->pages[chip] != -1)
+ return td->pages[chip] >>
+ (this->bbt_erase_shift - this->page_shift);
+
+ numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+ if (!(td->options & NAND_BBT_PERCHIP))
+ numblocks *= this->numchips;
+
+ /*
+ * Automatic placement of the bad block table. Search direction
+ * top -> down?
+ */
+ if (td->options & NAND_BBT_LASTBLOCK) {
+ startblock = numblocks * (chip + 1) - 1;
+ dir = -1;
+ } else {
+ startblock = chip * numblocks;
+ dir = 1;
+ }
+
+ for (i = 0; i < td->maxblocks; i++) {
+ int block = startblock + dir * i;
+
+ /* Check, if the block is bad */
+ switch (bbt_get_entry(this, block)) {
+ case BBT_BLOCK_WORN:
+ case BBT_BLOCK_FACTORY_BAD:
+ continue;
+ }
+
+ page = block << (this->bbt_erase_shift - this->page_shift);
+
+ /* Check, if the block is used by the mirror table */
+ if (!md || md->pages[chip] != page)
+ return block;
+ }
+
+ return -ENOSPC;
+}
+
+/**
+ * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
+ * @mtd: the MTD device
+ * @td: the BBT description
+ * @chip: the CHIP selector
+ * @block: the BBT block to mark
+ *
+ * Blocks reserved for BBT can become bad. This functions is an helper to mark
+ * such blocks as bad. It takes care of updating the in-memory BBT, marking the
+ * block as bad using a bad block marker and invalidating the associated
+ * td->pages[] entry.
+ */
+static void mark_bbt_block_bad(struct mtd_info *mtd,
+ struct nand_bbt_descr *td,
+ int chip, int block)
+{
+ struct nand_chip *this = mtd->priv;
+ loff_t to;
+ int res;
+
+ bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+ to = (loff_t)block << this->bbt_erase_shift;
+ res = this->block_markbad(mtd, to);
+ if (res)
+ pr_warn("nand_bbt: error %d while marking block %d bad\n",
+ res, block);
+
+ td->pages[chip] = -1;
+}
+
+/**
* write_bbt - [GENERIC] (Re)write the bad block table
* @mtd: MTD device structure
* @buf: temporary buffer
@@ -674,9 +717,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
{
struct nand_chip *this = mtd->priv;
struct erase_info einfo;
- int i, j, res, chip = 0;
- int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
- int nrchips, bbtoffs, pageoffs, ooboffs;
+ int i, res, chip = 0;
+ int bits, page, offs, numblocks, sft, sftmsk;
+ int nrchips, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
size_t retlen, len = 0;
@@ -706,46 +749,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
}
/* Loop through the chips */
- for (; chip < nrchips; chip++) {
- /*
- * There was already a version of the table, reuse the page
- * This applies for absolute placement too, as we have the
- * page nr. in td->pages.
- */
- if (td->pages[chip] != -1) {
- page = td->pages[chip];
- goto write;
+ while (chip < nrchips) {
+ int block;
+
+ block = get_bbt_block(this, td, md, chip);
+ if (block < 0) {
+ pr_err("No space left to write bad block table\n");
+ res = block;
+ goto outerr;
}
/*
- * Automatic placement of the bad block table. Search direction
- * top -> down?
+ * get_bbt_block() returns a block number, shift the value to
+ * get a page number.
*/
- if (td->options & NAND_BBT_LASTBLOCK) {
- startblock = numblocks * (chip + 1) - 1;
- dir = -1;
- } else {
- startblock = chip * numblocks;
- dir = 1;
- }
-
- for (i = 0; i < td->maxblocks; i++) {
- int block = startblock + dir * i;
- /* Check, if the block is bad */
- switch (bbt_get_entry(this, block)) {
- case BBT_BLOCK_WORN:
- case BBT_BLOCK_FACTORY_BAD:
- continue;
- }
- page = block <<
- (this->bbt_erase_shift - this->page_shift);
- /* Check, if the block is used by the mirror table */
- if (!md || md->pages[chip] != page)
- goto write;
- }
- pr_err("No space left to write bad block table\n");
- return -ENOSPC;
- write:
+ page = block << (this->bbt_erase_shift - this->page_shift);
/* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -766,8 +784,6 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
default: return -EINVAL;
}
- bbtoffs = chip * (numblocks >> 2);
-
to = ((loff_t)page) << this->page_shift;
/* Must we save the block contents? */
@@ -830,16 +846,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
buf[ooboffs + td->veroffs] = td->version[chip];
/* Walk through the memory table */
- for (i = 0; i < numblocks;) {
+ for (i = 0; i < numblocks; i++) {
uint8_t dat;
- dat = bbt_get_entry(this, (bbtoffs << 2) + i);
- for (j = 0; j < 4; j++, i++) {
- int sftcnt = (i << (3 - sft)) & sftmsk;
- /* Do not store the reserved bbt blocks! */
- buf[offs + (i >> sft)] &=
- ~(msk[dat & 0x03] << sftcnt);
- dat >>= 2;
- }
+ int sftcnt = (i << (3 - sft)) & sftmsk;
+ dat = bbt_get_entry(this, chip * numblocks + i);
+ /* Do not store the reserved bbt blocks! */
+ buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
}
memset(&einfo, 0, sizeof(einfo));
@@ -847,20 +859,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
- if (res < 0)
- goto outerr;
+ if (res < 0) {
+ pr_warn("nand_bbt: error while erasing BBT block %d\n",
+ res);
+ mark_bbt_block_bad(mtd, td, chip, block);
+ continue;
+ }
res = scan_write_bbt(mtd, to, len, buf,
td->options & NAND_BBT_NO_OOB ? NULL :
&buf[len]);
- if (res < 0)
- goto outerr;
+ if (res < 0) {
+ pr_warn("nand_bbt: error while writing BBT block %d\n",
+ res);
+ mark_bbt_block_bad(mtd, td, chip, block);
+ continue;
+ }
pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
(unsigned long long)to, td->version[chip]);
/* Mark it as used */
- td->pages[chip] = page;
+ td->pages[chip++] = page;
}
return 0;
@@ -881,7 +901,6 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
{
struct nand_chip *this = mtd->priv;
- bd->options &= ~NAND_BBT_SCANEMPTY;
return create_bbt(mtd, this->buffers->databuf, bd, -1);
}
@@ -1042,12 +1061,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
if (td->pages[i] == -1)
continue;
block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
- block <<= 1;
- oldval = bbt_get_entry(this, block >> 1);
- bbt_mark_entry(this, block >> 1, BBT_BLOCK_RESERVED);
+ oldval = bbt_get_entry(this, block);
+ bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
if ((oldval != BBT_BLOCK_RESERVED) &&
td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)block <<
+ this->bbt_erase_shift);
continue;
}
update = 0;
@@ -1055,13 +1074,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
block = ((i + 1) * nrblocks) - td->maxblocks;
else
block = i * nrblocks;
- block <<= 1;
for (j = 0; j < td->maxblocks; j++) {
- oldval = bbt_get_entry(this, block >> 1);
- bbt_mark_entry(this, block >> 1, BBT_BLOCK_RESERVED);
+ oldval = bbt_get_entry(this, block);
+ bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
if (oldval != BBT_BLOCK_RESERVED)
update = 1;
- block += 2;
+ block++;
}
/*
* If we want reserved blocks to be recorded to flash, and some
@@ -1069,7 +1087,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
* bbts. This should only happen once.
*/
if (update && td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)(block - 1) <<
+ this->bbt_erase_shift);
}
}
@@ -1133,10 +1152,10 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
* The bad block table memory is allocated here. It must be freed by calling
* the nand_free_bbt function.
*/
-int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
- int len, res = 0;
+ int len, res;
uint8_t *buf;
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
@@ -1157,10 +1176,9 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
if (!td) {
if ((res = nand_memory_bbt(mtd, bd))) {
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
- kfree(this->bbt);
- this->bbt = NULL;
+ goto err;
}
- return res;
+ return 0;
}
verify_bbt_descr(mtd, td);
verify_bbt_descr(mtd, md);
@@ -1170,9 +1188,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
len += (len >> this->page_shift) * mtd->oobsize;
buf = vmalloc(len);
if (!buf) {
- kfree(this->bbt);
- this->bbt = NULL;
- return -ENOMEM;
+ res = -ENOMEM;
+ goto err;
}
/* Is the bbt at a given page? */
@@ -1184,6 +1201,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
}
res = check_create(mtd, buf, bd);
+ if (res)
+ goto err;
/* Prevent the bbt regions from erasing / writing */
mark_bbt_region(mtd, td);
@@ -1191,17 +1210,22 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
mark_bbt_region(mtd, md);
vfree(buf);
+ return 0;
+
+err:
+ kfree(this->bbt);
+ this->bbt = NULL;
return res;
}
/**
- * nand_update_bbt - [NAND Interface] update bad block table(s)
+ * nand_update_bbt - update bad block table(s)
* @mtd: MTD device structure
* @offs: the offset of the newly marked block
*
* The function updates the bad block table(s).
*/
-int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
{
struct nand_chip *this = mtd->priv;
int len, res = 0;
@@ -1329,15 +1353,16 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
}
/**
- * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
+ * nand_create_bbt - [NAND Interface] Select a default bad block table for the device
* @mtd: MTD device structure
*
* This function selects the default bad block table support for the device and
* calls the nand_scan_bbt function.
*/
-int nand_default_bbt(struct mtd_info *mtd)
+int nand_create_bbt(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
+ int ret;
/* Is a flash based bad block table requested? */
if (this->bbt_options & NAND_BBT_USE_FLASH) {
@@ -1356,8 +1381,11 @@ int nand_default_bbt(struct mtd_info *mtd)
this->bbt_md = NULL;
}
- if (!this->badblock_pattern)
- nand_create_badblock_pattern(this);
+ if (!this->badblock_pattern) {
+ ret = nand_create_badblock_pattern(this);
+ if (ret)
+ return ret;
+ }
return nand_scan_bbt(mtd, this->badblock_pattern);
}
@@ -1374,12 +1402,11 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
int block;
uint8_t res;
- /* Get block number * 2 */
- block = (int)(offs >> (this->bbt_erase_shift - 1));
- res = bbt_get_entry(this, block >> 1);
+ block = (int)(offs >> this->bbt_erase_shift);
+ res = bbt_get_entry(this, block);
pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
- (unsigned int)offs, block >> 1, res);
+ (unsigned int)offs, block, res);
switch ((int)res) {
case BBT_BLOCK_GOOD:
@@ -1392,6 +1419,41 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
return 1;
}
+static int nand_mark_bbt(struct mtd_info *mtd, loff_t offs, uint8_t mark)
+{
+ struct nand_chip *this = mtd->priv;
+ int block, ret = 0;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+
+ /* Mark bad block in memory */
+ bbt_mark_entry(this, block, mark);
+
+ /* Update flash-based bad block table */
+ if (this->bbt_options & NAND_BBT_USE_FLASH)
+ ret = nand_update_bbt(mtd, offs);
+
+ return ret;
+}
+
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the bad block
+ */
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+{
+ return nand_mark_bbt(mtd, offs, BBT_BLOCK_WORN);
+}
+
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block good in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the good block
+ */
+int nand_markgood_bbt(struct mtd_info *mtd, loff_t offs)
+{
+ return nand_mark_bbt(mtd, offs, BBT_BLOCK_GOOD);
+}
+
EXPORT_SYMBOL(nand_scan_bbt);
-EXPORT_SYMBOL(nand_default_bbt);
-EXPORT_SYMBOL_GPL(nand_update_bbt);
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index e37135f514..d4f2a8cbe4 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -104,9 +104,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
/**
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
* @mtd: MTD block structure
- * @eccsize: ecc block size in bytes
- * @eccbytes: ecc length in bytes
- * @ecclayout: output default layout
*
* Returns:
* a pointer to a new NAND BCH control structure, or NULL upon failure
@@ -120,14 +117,21 @@ EXPORT_SYMBOL(nand_bch_correct_data);
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
*/
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
- struct nand_ecclayout **ecclayout)
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
{
+ struct nand_chip *nand = mtd->priv;
unsigned int m, t, eccsteps, i;
- struct nand_ecclayout *layout;
+ struct nand_ecclayout *layout = nand->ecc.layout;
struct nand_bch_control *nbc = NULL;
unsigned char *erased_page;
+ unsigned int eccsize = nand->ecc.size;
+ unsigned int eccbytes = nand->ecc.bytes;
+ unsigned int eccstrength = nand->ecc.strength;
+
+ if (!eccbytes && eccstrength) {
+ eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
+ nand->ecc.bytes = eccbytes;
+ }
if (!eccsize || !eccbytes) {
printk(KERN_WARNING "ecc parameters not supplied\n");
@@ -155,7 +159,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
eccsteps = mtd->writesize/eccsize;
/* if no ecc placement scheme was provided, build one */
- if (!*ecclayout) {
+ if (!layout) {
/* handle large page devices only */
if (mtd->oobsize < 64) {
@@ -181,7 +185,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
- *ecclayout = layout;
+ nand->ecc.layout = layout;
}
/* sanity checks */
@@ -189,7 +193,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
goto fail;
}
- if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
+ if (layout->eccbytes != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n");
goto fail;
}
@@ -213,6 +217,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
for (i = 0; i < eccbytes; i++)
nbc->eccmask[i] ^= 0xff;
+ if (!eccstrength)
+ nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
+
return nbc;
fail:
nand_bch_free(nbc);
diff --git a/drivers/mtd/nand/nand_imx_bbm.c b/drivers/mtd/nand/nand_imx_bbm.c
index 23722a9064..4fd5487aa2 100644
--- a/drivers/mtd/nand/nand_imx_bbm.c
+++ b/drivers/mtd/nand/nand_imx_bbm.c
@@ -129,7 +129,7 @@ static int attach_bbt(struct mtd_info *mtd, void *bbt)
free(chip->bbt);
chip->bbt = bbt;
- return nand_update_bbt(mtd, 0);
+ return nand_create_bbt(mtd);
}
static int do_imx_nand_bbm(int argc, char *argv[])
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index 28a07d4cba..f69453aba5 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -1201,21 +1201,7 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
return 0;
}
-/*
- * Nominally, the purpose of this function is to look for or create the bad
- * block table. In fact, since the we call this function at the very end of
- * the initialization process started by nand_scan(), and we doesn't have a
- * more formal mechanism, we "hook" this function to continue init process.
- *
- * At this point, the physical NAND Flash chips have been identified and
- * counted, so we know the physical geometry. This enables us to make some
- * important configuration decisions.
- *
- * The return value of this function propogates directly back to this driver's
- * call to nand_scan(). Anything other than zero will cause this driver to
- * tear everything down and declare failure.
- */
-static int mxs_nand_scan_bbt(struct mtd_info *mtd)
+static int mxs_nand_init_bch(struct mtd_info *mtd)
{
struct nand_chip *nand = mtd->priv;
struct mxs_nand_info *nand_info = nand->priv;
@@ -1252,8 +1238,7 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
mtd->block_markbad = mxs_nand_hook_block_markbad;
}
- /* We use the reference implementation for bad block management. */
- return nand_default_bbt(mtd);
+ return 0;
}
/*
@@ -2183,7 +2168,6 @@ static int mxs_nand_probe(struct device_d *dev)
nand->dev_ready = mxs_nand_device_ready;
nand->select_chip = mxs_nand_select_chip;
nand->block_bad = mxs_nand_block_bad;
- nand->scan_bbt = mxs_nand_scan_bbt;
nand->read_byte = mxs_nand_read_byte;
@@ -2215,6 +2199,13 @@ static int mxs_nand_probe(struct device_d *dev)
mxs_nand_setup_timing(nand_info);
+ err = mxs_nand_init_bch(mtd);
+ if (err)
+ goto err2;
+ err = nand_create_bbt(mtd);
+ if (err)
+ goto err2;
+
/* second phase scan */
err = nand_scan_tail(mtd);
if (err)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 323a9c7532..2dcf7e723b 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -125,7 +125,6 @@ static struct nand_ecclayout omap_oobinfo;
*/
static uint8_t scan_ff_pattern[] = { 0xff };
static struct nand_bbt_descr bb_descrip_flashbased = {
- .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
.offs = 0,
.len = 1,
.pattern = scan_ff_pattern,
@@ -162,7 +161,7 @@ static void gpmc_nand_wp(struct gpmc_nand_info *oinfo, int mode)
{
unsigned long config = readl(oinfo->gpmc_base + GPMC_CFG);
- debug("%s: mode=%x\n", __func__, mode);
+ dev_dbg(oinfo->pdev, "%s: mode=%x\n", __func__, mode);
if (mode)
config &= ~(NAND_WP_BIT); /* WP is ON */
@@ -228,47 +227,44 @@ static unsigned int gen_true_ecc(u8 *ecc_buf)
((ecc_buf[2] & 0x0F) << 8);
}
-static int __omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code, int sblock)
+static int __omap_calculate_ecc(struct mtd_info *mtd, uint8_t *ecc_code,
+ int sblock)
{
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
unsigned int reg;
unsigned int val1 = 0x0, val2 = 0x0;
unsigned int val3 = 0x0, val4 = 0x0;
- int i;
int ecc_size = 8;
switch (oinfo->ecc_mode) {
case OMAP_ECC_BCH8_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
- for (i = 0; i < 4; i++) {
- /*
- * Reading HW ECC_BCH_Results
- * 0x240-0x24C, 0x250-0x25C, 0x260-0x26C, 0x270-0x27C
- */
- reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * (i + sblock));
- val1 = readl(oinfo->gpmc_base + reg);
- val2 = readl(oinfo->gpmc_base + reg + 4);
- if (ecc_size == 8) {
- val3 = readl(oinfo->gpmc_base +reg + 8);
- val4 = readl(oinfo->gpmc_base + reg + 12);
-
- *ecc_code++ = (val4 & 0xFF);
- *ecc_code++ = ((val3 >> 24) & 0xFF);
- *ecc_code++ = ((val3 >> 16) & 0xFF);
- *ecc_code++ = ((val3 >> 8) & 0xFF);
- *ecc_code++ = (val3 & 0xFF);
- *ecc_code++ = ((val2 >> 24) & 0xFF);
- }
- *ecc_code++ = ((val2 >> 16) & 0xFF);
- *ecc_code++ = ((val2 >> 8) & 0xFF);
- *ecc_code++ = (val2 & 0xFF);
- *ecc_code++ = ((val1 >> 24) & 0xFF);
- *ecc_code++ = ((val1 >> 16) & 0xFF);
- *ecc_code++ = ((val1 >> 8) & 0xFF);
- *ecc_code++ = (val1 & 0xFF);
+ /*
+ * Reading HW ECC_BCH_Results
+ * 0x240-0x24C, 0x250-0x25C, 0x260-0x26C, 0x270-0x27C
+ */
+ reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * sblock);
+ val1 = readl(oinfo->gpmc_base + reg);
+ val2 = readl(oinfo->gpmc_base + reg + 4);
+ if (ecc_size == 8) {
+ val3 = readl(oinfo->gpmc_base +reg + 8);
+ val4 = readl(oinfo->gpmc_base + reg + 12);
+
+ *ecc_code++ = (val4 & 0xFF);
+ *ecc_code++ = ((val3 >> 24) & 0xFF);
+ *ecc_code++ = ((val3 >> 16) & 0xFF);
+ *ecc_code++ = ((val3 >> 8) & 0xFF);
+ *ecc_code++ = (val3 & 0xFF);
+ *ecc_code++ = ((val2 >> 24) & 0xFF);
}
+ *ecc_code++ = ((val2 >> 16) & 0xFF);
+ *ecc_code++ = ((val2 >> 8) & 0xFF);
+ *ecc_code++ = (val2 & 0xFF);
+ *ecc_code++ = ((val1 >> 24) & 0xFF);
+ *ecc_code++ = ((val1 >> 16) & 0xFF);
+ *ecc_code++ = ((val1 >> 8) & 0xFF);
+ *ecc_code++ = (val1 & 0xFF);
break;
case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
/* read ecc result */
@@ -288,7 +284,7 @@ static int __omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
uint8_t *ecc_code)
{
- return __omap_calculate_ecc(mtd, dat, ecc_code, 0);
+ return __omap_calculate_ecc(mtd, ecc_code, 0);
}
static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
@@ -302,7 +298,6 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
int bch_max_err;
int bitflip_count = 0;
bool eccflag = 0;
-
int eccsize = oinfo->nand.ecc.bytes;
switch (oinfo->ecc_mode) {
@@ -391,14 +386,13 @@ static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat,
byte = (parity_bits >> 3) & 0x1FF;
/* Flip the bit to correct */
dat[byte] ^= (0x1 << bit);
+ return 1;
} else if (hm == 1) {
- printf("Ecc is wrong\n");
/* ECC itself is corrupted */
- return 2;
+ return -EBADMSG;
} else {
- printf("bad compare! failed\n");
/* detected 2 bit error */
- return -1;
+ return -EBADMSG;
}
}
@@ -425,23 +419,10 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- debug("%s\n", __func__);
-
- switch (oinfo->ecc_mode) {
- case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
- return omap_correct_hamming(mtd, dat, read_ecc, calc_ecc);
- case OMAP_ECC_BCH8_CODE_HW:
- case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
- /*
- * The nand layer already called omap_calculate_ecc,
- * but before it has read the oob data. Do it again,
- * this time with oob data.
- */
- __omap_calculate_ecc(mtd, dat, calc_ecc, 0);
- return omap_correct_bch(mtd, dat, read_ecc, calc_ecc);
- default:
+ if (oinfo->ecc_mode != OMAP_ECC_HAMMING_CODE_HW_ROMCODE)
return -EINVAL;
- }
+
+ return omap_correct_hamming(mtd, dat, read_ecc, calc_ecc);
return 0;
}
@@ -692,11 +673,10 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
- __omap_calculate_ecc(mtd, buf, ecc_calc, 1);
-
p = buf;
for (i = 0, j = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, j++) {
+ __omap_calculate_ecc(mtd, &ecc_calc[i - j], j + 1);
stat = omap_correct_bch(mtd, p, &ecc_code[i], &ecc_calc[i - j]);
if (stat < 0) {
mtd->ecc_stats.failed++;
@@ -709,6 +689,44 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
return max_bitflips;
}
+static int gpmc_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ unsigned int max_bitflips = 0;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, mtd->writesize);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+
+ for (i = 0 ; eccsteps; eccsteps--, i++, p += eccsize) {
+ int stat;
+
+ __omap_calculate_ecc(mtd, &ecc_calc[i * eccbytes], i);
+ stat = omap_correct_bch(mtd, p, &ecc_code[i * eccbytes], &ecc_calc[i * eccbytes]);
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+ mtd->ecc_stats.corrected += stat;
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ }
+ }
+ return max_bitflips;
+}
+
static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
enum gpmc_ecc_mode mode)
{
@@ -737,6 +755,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
nand->ecc.read_oob = NULL;
nand->ecc.write_oob = NULL;
nand->ecc.mode = NAND_ECC_HW;
+ nand->options &= ~NAND_SUBPAGE_READ;
}
switch (mode) {
@@ -762,11 +781,17 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
oinfo->nand.ecc.bytes = 13;
oinfo->nand.ecc.size = 512;
oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
+ nand->ecc.read_page = gpmc_read_page_hwecc;
omap_oobinfo.oobfree->offset = offset;
+ oinfo->nand.ecc.steps = minfo->writesize / oinfo->nand.ecc.size;
+ oinfo->nand.ecc.total = oinfo->nand.ecc.steps * oinfo->nand.ecc.bytes;
+ omap_oobinfo.eccbytes = oinfo->nand.ecc.total;
+
omap_oobinfo.oobfree->length = minfo->oobsize -
offset - omap_oobinfo.eccbytes;
- offset = minfo->oobsize - oinfo->nand.ecc.bytes;
- for (i = 0; i < oinfo->nand.ecc.bytes; i++)
+ offset = minfo->oobsize - oinfo->nand.ecc.total;
+
+ for (i = 0; i < oinfo->nand.ecc.total; i++)
omap_oobinfo.eccpos[i] = i + offset;
break;
case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
@@ -775,6 +800,9 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
nand->ecc.read_page = omap_gpmc_read_page_bch_rom_mode;
omap_oobinfo.oobfree->length = 0;
+ oinfo->nand.ecc.steps = minfo->writesize / oinfo->nand.ecc.size;
+ oinfo->nand.ecc.total = oinfo->nand.ecc.steps * oinfo->nand.ecc.bytes;
+ omap_oobinfo.eccbytes = oinfo->nand.ecc.total;
j = 0;
for (i = 2; i < 58; i++)
omap_oobinfo.eccpos[j++] = i;
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 2fccd4681e..ff35b746e2 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -32,18 +32,16 @@
#include <asm/system.h>
#include <linux/phy.h>
#include <mach/emac_defs.h>
-#include <platform_data/eth-davinci-emac.h>
+#include <of_net.h>
#include "davinci_emac.h"
struct davinci_emac_priv {
struct device_d *dev;
struct eth_device edev;
- struct mii_bus miibus;
/* EMAC Addresses */
void __iomem *adap_emac; /* = EMAC_BASE_ADDR */
void __iomem *adap_ewrap; /* = EMAC_WRAPPER_BASE_ADDR */
- void __iomem *adap_mdio; /* = EMAC_MDIO_BASE_ADDR */
/* EMAC descriptors */
void __iomem *emac_desc_base; /* = EMAC_WRAPPER_RAM_ADDR */
@@ -58,8 +56,6 @@ struct davinci_emac_priv {
/* PHY-specific information */
phy_interface_t interface;
- uint8_t phy_addr;
- uint32_t phy_flags;
/* mac_addr[0] goes out on the wire first */
uint8_t mac_addr[6];
@@ -86,7 +82,13 @@ static inline void __iomem *HW_TO_BD(uint32_t x)
#define HW_TO_BD(x) (x)
#endif
-static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
+struct davinci_mdio_priv {
+ struct device_d *dev;
+ struct mii_bus miibus;
+ void __iomem *adap_mdio; /* = EMAC_MDIO_BASE_ADDR */
+};
+
+static void davinci_eth_mdio_enable(struct davinci_mdio_priv *priv)
{
uint32_t clkdiv;
@@ -105,13 +107,40 @@ static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
while (readl(priv->adap_mdio + EMAC_MDIO_CONTROL) & MDIO_CONTROL_IDLE);
}
+/* wait until hardware is ready for another user access */
+static int wait_for_user_access(struct davinci_mdio_priv *priv, uint32_t *val)
+{
+ u32 tmp;
+ uint64_t start = get_time_ns();
+
+ do {
+ tmp = readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0);
+
+ if (!(tmp & MDIO_USERACCESS0_GO))
+ break;
+
+ if (is_timeout(start, 100 * MSECOND)) {
+ dev_err(priv->dev, "timeout waiting for user access\n");
+ return -ETIMEDOUT;
+ }
+ } while (1);
+
+ if (val)
+ *val = tmp;
+
+ return 0;
+}
+
+
static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
{
- struct davinci_emac_priv *priv = bus->priv;
+ struct davinci_mdio_priv *priv = bus->priv;
uint16_t value;
- int tmp;
+ int tmp, ret;
- while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+ ret = wait_for_user_access(priv, NULL);
+ if (ret)
+ return ret;
writel(MDIO_USERACCESS0_GO |
MDIO_USERACCESS0_WRITE_READ |
@@ -119,8 +148,9 @@ static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
((addr & 0x1f) << 16),
priv->adap_mdio + EMAC_MDIO_USERACCESS0);
- /* Wait for command to complete */
- while ((tmp = readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0)) & MDIO_USERACCESS0_GO);
+ ret = wait_for_user_access(priv, &tmp);
+ if (ret)
+ return ret;
if (tmp & MDIO_USERACCESS0_ACK) {
value = tmp & 0xffff;
@@ -134,8 +164,12 @@ static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
static int davinci_miibus_write(struct mii_bus *bus, int addr, int reg, u16 value)
{
- struct davinci_emac_priv *priv = bus->priv;
- while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+ struct davinci_mdio_priv *priv = bus->priv;
+ int ret;
+
+ ret = wait_for_user_access(priv, NULL);
+ if (ret)
+ return ret;
dev_dbg(priv->dev, "davinci_miibus_write: addr=0x%02x reg=0x%02x value=0x%04x\n",
addr, reg, value);
@@ -146,10 +180,7 @@ static int davinci_miibus_write(struct mii_bus *bus, int addr, int reg, u16 valu
(value & 0xffff),
priv->adap_mdio + EMAC_MDIO_USERACCESS0);
- /* Wait for command to complete */
- while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
-
- return 0;
+ return wait_for_user_access(priv, NULL);
}
static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
@@ -173,6 +204,17 @@ static int davinci_emac_set_ethaddr(struct eth_device *edev, const unsigned char
static int davinci_emac_init(struct eth_device *edev)
{
+ struct davinci_emac_priv *priv = edev->priv;
+ uint32_t cnt;
+
+ /* Set DMA head and completion pointers to 0 */
+ for(cnt = 0; cnt < 8; cnt++) {
+ writel(0, (void *)priv->adap_emac + EMAC_TX0HDP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_RX0HDP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_TX0CP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_RX0CP + 4 * cnt);
+ }
+
dev_dbg(&edev->dev, "* emac_init\n");
return 0;
}
@@ -180,7 +222,7 @@ static int davinci_emac_init(struct eth_device *edev)
static int davinci_emac_open(struct eth_device *edev)
{
struct davinci_emac_priv *priv = edev->priv;
- uint32_t clkdiv, cnt;
+ uint32_t cnt;
void __iomem *rx_desc;
unsigned long mac_hi, mac_lo;
int ret;
@@ -282,16 +324,10 @@ static int davinci_emac_open(struct eth_device *edev)
EMAC_MACCONTROL_RMIISPEED_100),
priv->adap_emac + EMAC_MACCONTROL);
- /* Init MDIO & get link state */
- clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
- writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
- priv->adap_mdio + EMAC_MDIO_CONTROL);
-
/* Start receive process */
writel(BD_TO_HW(priv->emac_rx_desc), priv->adap_emac + EMAC_RX0HDP);
- ret = phy_device_connect(edev, &priv->miibus, priv->phy_addr, NULL,
- priv->phy_flags, priv->interface);
+ ret = phy_device_connect(edev, NULL, -1, NULL, 0, priv->interface);
if (ret)
return ret;
@@ -500,19 +536,13 @@ out:
static int davinci_emac_probe(struct device_d *dev)
{
struct resource *iores;
- struct davinci_emac_platform_data *pdata;
struct davinci_emac_priv *priv;
- uint64_t start;
- uint32_t phy_mask;
+ uint32_t ctrl_reg_offset;
+ uint32_t ctrl_ram_offset;
+ struct device_node *np = dev->device_node;
dev_dbg(dev, "+ emac_probe\n");
- if (!dev->platform_data) {
- dev_err(dev, "no platform_data\n");
- return -ENODEV;
- }
- pdata = dev->platform_data;
-
priv = xzalloc(sizeof(*priv));
dev->priv = priv;
@@ -521,22 +551,14 @@ static int davinci_emac_probe(struct device_d *dev)
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
- priv->adap_emac = IOMEM(iores->start);
- iores = dev_request_mem_resource(dev, 1);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
priv->adap_ewrap = IOMEM(iores->start);
- iores = dev_request_mem_resource(dev, 2);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- priv->adap_mdio = IOMEM(iores->start);
+ of_property_read_u32(np, "ti,davinci-ctrl-reg-offset", &ctrl_reg_offset);
+ priv->adap_emac = IOMEM(iores->start) + ctrl_reg_offset;
- iores = dev_request_mem_resource(dev, 3);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- priv->emac_desc_base = IOMEM(iores->start);
+ of_property_read_u32(np, "ti,davinci-ctrl-ram-offset", &ctrl_ram_offset);
+ priv->emac_desc_base = IOMEM(iores->start) + ctrl_ram_offset;
/* EMAC descriptors */
priv->emac_rx_desc = priv->emac_desc_base + EMAC_RX_DESC_BASE;
@@ -558,37 +580,7 @@ static int davinci_emac_probe(struct device_d *dev)
priv->edev.set_ethaddr = davinci_emac_set_ethaddr;
priv->edev.parent = dev;
- davinci_eth_mdio_enable(priv);
-
- start = get_time_ns();
- while (1) {
- phy_mask = readl(priv->adap_mdio + EMAC_MDIO_ALIVE);
- if (phy_mask) {
- dev_info(dev, "detected phy mask 0x%x\n", phy_mask);
- phy_mask = ~phy_mask;
- break;
- }
- if (is_timeout(start, 256 * MSECOND)) {
- dev_err(dev, "no live phy, scanning all\n");
- phy_mask = 0;
- break;
- }
- }
-
- if (pdata->interface_rmii)
- priv->interface = PHY_INTERFACE_MODE_RMII;
- else
- priv->interface = PHY_INTERFACE_MODE_MII;
- priv->phy_addr = pdata->phy_addr;
- priv->phy_flags = pdata->force_link ? PHYLIB_FORCE_LINK : 0;
-
- priv->miibus.read = davinci_miibus_read;
- priv->miibus.write = davinci_miibus_write;
- priv->miibus.priv = priv;
- priv->miibus.parent = dev;
- priv->miibus.phy_mask = phy_mask;
-
- mdiobus_register(&priv->miibus);
+ priv->interface = of_get_phy_mode(np);
eth_register(&priv->edev);
@@ -603,9 +595,73 @@ static void davinci_emac_remove(struct device_d *dev)
davinci_emac_halt(&priv->edev);
}
+static __maybe_unused struct of_device_id davinci_emac_dt_ids[] = {
+ {
+ .compatible = "ti,am3517-emac",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d davinci_emac_driver = {
.name = "davinci_emac",
.probe = davinci_emac_probe,
.remove = davinci_emac_remove,
+ .of_compatible = DRV_OF_COMPAT(davinci_emac_dt_ids),
};
device_platform_driver(davinci_emac_driver);
+
+static int davinci_mdio_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ struct davinci_mdio_priv *priv;
+ int ret;
+ uint32_t clkdiv;
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->dev = dev;
+ priv->miibus.read = davinci_miibus_read;
+ priv->miibus.write = davinci_miibus_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ priv->adap_mdio = IOMEM(iores->start);
+
+ davinci_eth_mdio_enable(priv);
+
+ /* Init MDIO & get link state */
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+ writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
+ priv->adap_mdio + EMAC_MDIO_CONTROL);
+
+ ret = mdiobus_register(&priv->miibus);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ free(priv);
+
+ return ret;
+}
+
+static __maybe_unused struct of_device_id davinci_mdio_dt_ids[] = {
+ {
+ .compatible = "ti,davinci_mdio",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d davinci_mdio_driver = {
+ .name = "davinci_mdio",
+ .probe = davinci_mdio_probe,
+ .of_compatible = DRV_OF_COMPAT(davinci_mdio_dt_ids),
+};
+device_platform_driver(davinci_mdio_driver);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 4a1a1aa336..0a9e107c07 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -95,19 +95,17 @@ typedef enum {
/* Error Codes */
#define E1000_SUCCESS 0
-#define E1000_ERR_EEPROM 1
-#define E1000_ERR_PHY 2
-#define E1000_ERR_CONFIG 3
-#define E1000_ERR_PARAM 4
-#define E1000_ERR_MAC_TYPE 5
-#define E1000_ERR_PHY_TYPE 6
-#define E1000_ERR_NOLINK 7
-#define E1000_ERR_TIMEOUT 8
-#define E1000_ERR_RESET 9
-#define E1000_ERR_MASTER_REQUESTS_PENDING 10
-#define E1000_ERR_HOST_INTERFACE_COMMAND 11
-#define E1000_BLK_PHY_RESET 12
-#define E1000_ERR_SWFW_SYNC 13
+#define E1000_ERR_EEPROM EIO
+#define E1000_ERR_PHY EIO
+#define E1000_ERR_CONFIG EINVAL
+#define E1000_ERR_PARAM EINVAL
+#define E1000_ERR_MAC_TYPE EINVAL
+#define E1000_ERR_PHY_TYPE EINVAL
+#define E1000_ERR_NOLINK ENETDOWN
+#define E1000_ERR_TIMEOUT ETIMEDOUT
+#define E1000_ERR_RESET EIO
+#define E1000_BLK_PHY_RESET EWOULDBLOCK
+#define E1000_ERR_SWFW_SYNC EBUSY
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index caa7274a8d..0ef8fd6231 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -231,7 +231,7 @@ static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
if (!timeout) {
/* Release semaphores */
e1000_put_hw_eeprom_semaphore(hw);
- dev_dbg(hw->dev, "Driver can't access the Eeprom - "
+ dev_err(hw->dev, "Driver can't access the Eeprom - "
"SWESMBI bit is set.\n");
return -E1000_ERR_EEPROM;
}
@@ -262,7 +262,7 @@ int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
}
if (!timeout) {
- dev_dbg(hw->dev, "Driver can't access resource, SW_FW_SYNC timeout.\n");
+ dev_err(hw->dev, "Driver can't access resource, SW_FW_SYNC timeout.\n");
return -E1000_ERR_SWFW_SYNC;
}
@@ -332,7 +332,7 @@ static int e1000_get_ethaddr(struct eth_device *edev, unsigned char *adr)
for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
if (e1000_read_eeprom(hw, i >> 1, 1, &eeprom_data) < 0) {
- dev_dbg(hw->dev, "EEPROM Read Error\n");
+ dev_err(hw->dev, "EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
adr[i] = eeprom_data & 0xff;
@@ -832,20 +832,6 @@ static int e1000_setup_link(struct e1000_hw *hw)
if (e1000_check_phy_reset_block(hw))
return E1000_SUCCESS;
- /* Read and store word 0x0F of the EEPROM. This word contains bits
- * that determine the hardware's default PAUSE (flow control) mode,
- * a bit that determines whether the HW defaults to enabling or
- * disabling auto-negotiation, and the direction of the
- * SW defined pins. If there is no SW over-ride of the flow
- * control setting, then the variable hw->fc will
- * be initialized based on a value in the EEPROM.
- */
- if (e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1,
- &eeprom_data) < 0) {
- dev_dbg(hw->dev, "EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
- }
-
switch (hw->mac_type) {
case e1000_ich8lan:
case e1000_82573:
@@ -854,6 +840,22 @@ static int e1000_setup_link(struct e1000_hw *hw)
hw->fc = e1000_fc_full;
break;
default:
+ /* Read and store word 0x0F of the EEPROM. This word
+ * contains bits that determine the hardware's default
+ * PAUSE (flow control) mode, a bit that determines
+ * whether the HW defaults to enabling or disabling
+ * auto-negotiation, and the direction of the SW
+ * defined pins. If there is no SW over-ride of the
+ * flow control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1,
+ &eeprom_data);
+ if (ret_val < 0) {
+ dev_err(hw->dev, "EEPROM Read Error\n");
+ return ret_val;
+ }
+
if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
hw->fc = e1000_fc_none;
else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR)
@@ -1006,7 +1008,7 @@ static int e1000_setup_fiber_link(struct e1000_hw *hw)
txcw = E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK;
break;
default:
- dev_dbg(hw->dev, "Flow control param set incorrectly\n");
+ dev_err(hw->dev, "Flow control param set incorrectly\n");
return -E1000_ERR_CONFIG;
break;
}
@@ -1044,7 +1046,7 @@ static int e1000_setup_fiber_link(struct e1000_hw *hw)
* detect a signal. This will allow us to communicate with
* non-autonegotiating link partners.
*/
- dev_dbg(hw->dev, "Never got a valid link from auto-neg!!!\n");
+ dev_err(hw->dev, "Never got a valid link from auto-neg!!!\n");
hw->autoneg_failed = 1;
return -E1000_ERR_NOLINK;
} else {
@@ -1052,7 +1054,7 @@ static int e1000_setup_fiber_link(struct e1000_hw *hw)
dev_dbg(hw->dev, "Valid Link Found\n");
}
} else {
- dev_dbg(hw->dev, "No Signal Detected\n");
+ dev_err(hw->dev, "No Signal Detected\n");
return -E1000_ERR_NOLINK;
}
return 0;
@@ -1092,7 +1094,7 @@ static int32_t e1000_copper_link_preconfig(struct e1000_hw *hw)
/* Make sure we have a valid PHY */
ret_val = e1000_detect_gig_phy(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error, did not detect valid phy.\n");
+ dev_err(hw->dev, "Error, did not detect valid phy.\n");
return ret_val;
}
dev_dbg(hw->dev, "Phy ID = %x \n", hw->phy_id);
@@ -1236,7 +1238,7 @@ static int32_t e1000_copper_link_igp_setup(struct e1000_hw *hw)
ret_val = e1000_phy_reset(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Resetting the PHY\n");
+ dev_err(hw->dev, "Error Resetting the PHY\n");
return ret_val;
}
@@ -1255,7 +1257,7 @@ static int32_t e1000_copper_link_igp_setup(struct e1000_hw *hw)
/* disable lplu d3 during driver init */
ret_val = e1000_set_d3_lplu_state_off(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Disabling LPLU D3\n");
+ dev_err(hw->dev, "Error Disabling LPLU D3\n");
return ret_val;
}
}
@@ -1263,7 +1265,7 @@ static int32_t e1000_copper_link_igp_setup(struct e1000_hw *hw)
/* disable lplu d0 during driver init */
ret_val = e1000_set_d0_lplu_state_off(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Disabling LPLU D0\n");
+ dev_err(hw->dev, "Error Disabling LPLU D0\n");
return ret_val;
}
@@ -1457,7 +1459,7 @@ static int32_t e1000_copper_link_ggp_setup(struct e1000_hw *hw)
/* SW Reset the PHY so all changes take effect */
ret_val = e1000_phy_reset(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Resetting the PHY\n");
+ dev_err(hw->dev, "Error Resetting the PHY\n");
return ret_val;
}
@@ -1586,7 +1588,7 @@ static int32_t e1000_copper_link_mgp_setup(struct e1000_hw *hw)
/* SW Reset the PHY so all changes take effect */
ret_val = e1000_phy_reset(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Resetting the PHY\n");
+ dev_err(hw->dev, "Error Resetting the PHY\n");
return ret_val;
}
@@ -1615,7 +1617,7 @@ static int32_t e1000_copper_link_autoneg(struct e1000_hw *hw)
dev_dbg(hw->dev, "Reconfiguring auto-neg advertisement params\n");
ret_val = e1000_phy_setup_autoneg(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Setting up Auto-Negotiation\n");
+ dev_err(hw->dev, "Error Setting up Auto-Negotiation\n");
return ret_val;
}
dev_dbg(hw->dev, "Restarting Auto-Neg\n");
@@ -1634,7 +1636,7 @@ static int32_t e1000_copper_link_autoneg(struct e1000_hw *hw)
ret_val = e1000_wait_autoneg(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error while waiting for autoneg to complete\n");
+ dev_err(hw->dev, "Error while waiting for autoneg to complete\n");
return ret_val;
}
@@ -1663,14 +1665,14 @@ static int32_t e1000_copper_link_postconfig(struct e1000_hw *hw)
} else {
ret_val = e1000_config_mac_to_phy(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error configuring MAC to PHY settings\n");
+ dev_err(hw->dev, "Error configuring MAC to PHY settings\n");
return ret_val;
}
}
ret_val = e1000_config_fc_after_link_up(hw);
if (ret_val) {
- dev_dbg(hw->dev, "Error Configuring Flow Control\n");
+ dev_err(hw->dev, "Error Configuring Flow Control\n");
return ret_val;
}
@@ -1983,7 +1985,7 @@ static int e1000_config_mac_to_phy(struct e1000_hw *hw)
* registers depending on negotiated values.
*/
if (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
- dev_dbg(hw->dev, "PHY Read Error\n");
+ dev_err(hw->dev, "PHY Read Error\n");
return -E1000_ERR_PHY;
}
if (phy_data & M88E1000_PSSR_DPLX)
@@ -2059,7 +2061,7 @@ static int e1000_force_mac_fc(struct e1000_hw *hw)
ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
break;
default:
- dev_dbg(hw->dev, "Flow control param set incorrectly\n");
+ dev_err(hw->dev, "Flow control param set incorrectly\n");
return -E1000_ERR_CONFIG;
}
@@ -2098,17 +2100,17 @@ static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw)
* some "sticky" (latched) bits.
*/
if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
- dev_dbg(hw->dev, "PHY Read Error \n");
+ dev_err(hw->dev, "PHY Read Error \n");
return -E1000_ERR_PHY;
}
if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
- dev_dbg(hw->dev, "PHY Read Error \n");
+ dev_err(hw->dev, "PHY Read Error \n");
return -E1000_ERR_PHY;
}
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
- dev_dbg(hw->dev, "Copper PHY and Auto Neg has not completed.\n");
+ dev_err(hw->dev, "Copper PHY and Auto Neg has not completed.\n");
return 0;
}
@@ -2119,12 +2121,12 @@ static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw)
* negotiated.
*/
if (e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
- dev_dbg(hw->dev, "PHY Read Error\n");
+ dev_err(hw->dev, "PHY Read Error\n");
return -E1000_ERR_PHY;
}
if (e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
- dev_dbg(hw->dev, "PHY Read Error\n");
+ dev_err(hw->dev, "PHY Read Error\n");
return -E1000_ERR_PHY;
}
@@ -2250,7 +2252,7 @@ static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw)
*/
ret_val = e1000_force_mac_fc(hw);
if (ret_val < 0) {
- dev_dbg(hw->dev, "Error forcing flow control settings\n");
+ dev_err(hw->dev, "Error forcing flow control settings\n");
return ret_val;
}
@@ -2399,11 +2401,11 @@ static int e1000_wait_autoneg(struct e1000_hw *hw)
* Complete bit to be set.
*/
if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
- dev_dbg(hw->dev, "PHY Read Error\n");
+ dev_err(hw->dev, "PHY Read Error\n");
return -E1000_ERR_PHY;
}
if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
- dev_dbg(hw->dev, "PHY Read Error\n");
+ dev_err(hw->dev, "PHY Read Error\n");
return -E1000_ERR_PHY;
}
if (phy_data & MII_SR_AUTONEG_COMPLETE) {
@@ -2412,7 +2414,7 @@ static int e1000_wait_autoneg(struct e1000_hw *hw)
}
mdelay(100);
}
- dev_dbg(hw->dev, "Auto-Neg timedout.\n");
+ dev_err(hw->dev, "Auto-Neg timedout.\n");
return -E1000_ERR_TIMEOUT;
}
@@ -2578,11 +2580,11 @@ static int e1000_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
break;
}
if (!(mdic & E1000_MDIC_READY)) {
- dev_dbg(hw->dev, "MDI Read did not complete\n");
+ dev_err(hw->dev, "MDI Read did not complete\n");
return -E1000_ERR_PHY;
}
if (mdic & E1000_MDIC_ERROR) {
- dev_dbg(hw->dev, "MDI Error\n");
+ dev_err(hw->dev, "MDI Error\n");
return -E1000_ERR_PHY;
}
return mdic;
@@ -2667,7 +2669,7 @@ static int e1000_phy_write(struct mii_bus *bus, int phy_addr,
break;
}
if (!(mdic & E1000_MDIC_READY)) {
- dev_dbg(hw->dev, "MDI Write did not complete\n");
+ dev_err(hw->dev, "MDI Write did not complete\n");
return -E1000_ERR_PHY;
}
} else {
@@ -2774,7 +2776,7 @@ static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw)
timeout--;
}
if (!timeout) {
- dev_dbg(hw->dev, "MNG configuration cycle has not completed.\n");
+ dev_err(hw->dev, "MNG configuration cycle has not completed.\n");
return -E1000_ERR_RESET;
}
break;
@@ -2810,7 +2812,7 @@ static int32_t e1000_phy_hw_reset(struct e1000_hw *hw)
swfw = E1000_SWFW_PHY1_SM;
if (e1000_swfw_sync_acquire(hw, swfw)) {
- dev_dbg(hw->dev, "Unable to acquire swfw sync\n");
+ dev_err(hw->dev, "Unable to acquire swfw sync\n");
return -E1000_ERR_SWFW_SYNC;
}
@@ -3109,12 +3111,12 @@ static int32_t e1000_detect_gig_phy(struct e1000_hw *hw)
phy_type = e1000_phy_igb;
break;
default:
- dev_dbg(hw->dev, "Invalid MAC type %d\n", hw->mac_type);
+ dev_err(hw->dev, "Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
}
if (phy_type == e1000_phy_undefined) {
- dev_dbg(hw->dev, "Invalid PHY ID 0x%X\n", hw->phy_id);
+ dev_err(hw->dev, "Invalid PHY ID 0x%X\n", hw->phy_id);
return -EINVAL;
}
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c
index c2628cc1d6..4823b08340 100644
--- a/drivers/net/fec_imx.c
+++ b/drivers/net/fec_imx.c
@@ -51,7 +51,7 @@ static int fec_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr)
* wait for the related interrupt
*/
if (readl_poll_timeout(fec->regs + FEC_IEVENT, reg,
- reg & FEC_IEVENT_MII, MSECOND)) {
+ reg & FEC_IEVENT_MII, USEC_PER_MSEC)) {
dev_err(&fec->edev.dev, "Read MDIO failed...\n");
return -1;
}
@@ -88,7 +88,7 @@ static int fec_miibus_write(struct mii_bus *bus, int phyAddr,
* wait for the MII interrupt
*/
if (readl_poll_timeout(fec->regs + FEC_IEVENT, reg,
- reg & FEC_IEVENT_MII, MSECOND)) {
+ reg & FEC_IEVENT_MII, USEC_PER_MSEC)) {
dev_err(&fec->edev.dev, "Write MDIO failed...\n");
return -1;
}
@@ -401,7 +401,7 @@ static void fec_halt(struct eth_device *dev)
/* wait for graceful stop to register */
if (readl_poll_timeout(fec->regs + FEC_IEVENT, reg,
- reg & FEC_IEVENT_GRA, SECOND))
+ reg & FEC_IEVENT_GRA, USEC_PER_SEC))
dev_err(&dev->dev, "graceful stop timeout\n");
/* Disable SmartDMA tasks */
@@ -475,7 +475,7 @@ static int fec_send(struct eth_device *dev, void *eth_data, int data_length)
fec_tx_task_enable(fec);
if (readw_poll_timeout(&fec->tbd_base[fec->tbd_index].status,
- status, !(status & FEC_TBD_READY), SECOND))
+ status, !(status & FEC_TBD_READY), USEC_PER_SEC))
dev_err(&dev->dev, "transmission timeout\n");
dma_unmap_single(fec->dev, dma, data_length, DMA_TO_DEVICE);
@@ -796,7 +796,7 @@ static int fec_probe(struct device_d *dev)
/* Reset chip. */
writel(FEC_ECNTRL_RESET, fec->regs + FEC_ECNTRL);
ret = readl_poll_timeout(fec->regs + FEC_ECNTRL, reg,
- !(reg & FEC_ECNTRL_RESET), SECOND);
+ !(reg & FEC_ECNTRL_RESET), USEC_PER_SEC);
if (ret)
goto free_gpio;
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
index c0608112d5..b037e19633 100644
--- a/drivers/net/ks8851_mll.c
+++ b/drivers/net/ks8851_mll.c
@@ -435,7 +435,7 @@ static inline void ks_outblk(struct ks_net *ks, u16 *wptr, u32 len)
writew(*wptr++, ks->hw_addr);
}
-void ks_enable_qmu(struct ks_net *ks)
+static void ks_enable_qmu(struct ks_net *ks)
{
u16 w;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 1a8f6da31b..2a304579e6 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -46,9 +46,11 @@
#define RX_BUFFER_MULTIPLE 64 /* bytes */
#define RX_NB_PACKET 10
#define TX_RING_SIZE 2 /* must be power of 2 */
+#define GEM_Q1_DESCS 2
#define RX_RING_BYTES(bp) (sizeof(struct macb_dma_desc) * bp->rx_ring_size)
#define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+#define GEM_Q1_DESC_BYTES (sizeof(struct macb_dma_desc) * GEM_Q1_DESCS)
struct macb_device {
void __iomem *regs;
@@ -60,6 +62,7 @@ struct macb_device {
void *tx_buffer;
struct macb_dma_desc *rx_ring;
struct macb_dma_desc *tx_ring;
+ struct macb_dma_desc *gem_q1_descs;
int rx_buffer_size;
int rx_ring_size;
@@ -86,7 +89,7 @@ static inline bool macb_is_gem(struct macb_device *macb)
static inline bool read_is_gem(struct macb_device *macb)
{
- return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
+ return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) >= 0x2;
}
static int macb_send(struct eth_device *edev, void *packet,
@@ -340,6 +343,20 @@ static void macb_init(struct macb_device *macb)
macb_writel(macb, RBQP, (ulong)macb->rx_ring);
macb_writel(macb, TBQP, (ulong)macb->tx_ring);
+ if (macb->is_gem && macb->gem_q1_descs) {
+ /* Disable the second priority queue */
+ macb->gem_q1_descs[0].addr = 0;
+ macb->gem_q1_descs[0].ctrl = MACB_BIT(TX_WRAP) |
+ MACB_BIT(TX_LAST) |
+ MACB_BIT(TX_USED);
+ macb->gem_q1_descs[1].addr = MACB_BIT(RX_USED) |
+ MACB_BIT(RX_WRAP);
+ macb->gem_q1_descs[1].ctrl = 0;
+
+ gem_writel(macb, TQ1, (ulong)&macb->gem_q1_descs[0]);
+ gem_writel(macb, RQ1, (ulong)&macb->gem_q1_descs[1]);
+ }
+
switch(macb->interface) {
case PHY_INTERFACE_MODE_RGMII:
val = GEM_BIT(RGMII);
@@ -592,11 +609,9 @@ static void macb_init_rx_buffer_size(struct macb_device *bp, size_t size)
bp->rx_buffer_size =
roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE);
}
- bp->rx_buffer = dma_alloc_coherent(bp->rx_buffer_size * bp->rx_ring_size,
- DMA_ADDRESS_BROKEN);
}
- dev_dbg(bp->dev, "[%d] rx_buffer_size [%d]\n",
+ dev_dbg(bp->dev, "[%zu] rx_buffer_size [%d]\n",
size, bp->rx_buffer_size);
}
@@ -691,6 +706,10 @@ static int macb_probe(struct device_d *dev)
macb->rx_ring = dma_alloc_coherent(RX_RING_BYTES(macb), DMA_ADDRESS_BROKEN);
macb->tx_ring = dma_alloc_coherent(TX_RING_BYTES, DMA_ADDRESS_BROKEN);
+ if (macb->is_gem)
+ macb->gem_q1_descs = dma_alloc_coherent(GEM_Q1_DESC_BYTES,
+ DMA_ADDRESS_BROKEN);
+
macb_reset_hw(macb);
ncfgr = macb_mdc_clk_div(macb);
ncfgr |= MACB_BIT(PAE); /* PAuse Enable */
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 6be9732761..979f53cb71 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -72,6 +72,8 @@
#define GEM_DCFG5 0x0290
#define GEM_DCFG6 0x0294
#define GEM_DCFG7 0x0298
+#define GEM_TQ1 0x0440
+#define GEM_RQ1 0x0480
/* Bitfields in NCR */
#define MACB_LB_OFFSET 0
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3b1a6ea7e3..0665aefd99 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -23,6 +23,11 @@ config DAVICOM_PHY
---help---
Currently supports dm9161e and dm9131
+config DP83867_PHY
+ tristate "Texas Instruments DP83867 Gigabit PHY"
+ ---help---
+ Currently supports the DP83867 PHY.
+
config LXT_PHY
bool "Driver for the Intel LXT PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e4d9ec65a3..5f11a857d4 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -14,4 +14,5 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o
obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o
+obj-$(CONFIG_DP83867_PHY) += dp83867.o
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
new file mode 100644
index 0000000000..b3328b7e44
--- /dev/null
+++ b/drivers/net/phy/dp83867.c
@@ -0,0 +1,323 @@
+/*
+ * Driver for the Texas Instruments DP83867 PHY
+ *
+ * Copyright (C) 2015 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/phy.h>
+
+#include <dt-bindings/net/ti-dp83867.h>
+
+#define DP83867_PHY_ID 0x2000a231
+#define DP83867_DEVADDR 0x1f
+
+#define MII_DP83867_PHYCTRL 0x10
+#define MII_DP83867_MICR 0x12
+#define MII_DP83867_ISR 0x13
+#define MII_DP83867_CFG2 0x14
+#define MII_DP83867_BISCR 0x16
+#define DP83867_CTRL 0x1f
+#define DP83867_CFG3 0x1e
+
+/* Extended Registers */
+#define DP83867_CFG4 0x0031
+#define DP83867_RGMIICTL 0x0032
+#define DP83867_STRAP_STS1 0x006E
+#define DP83867_RGMIIDCTL 0x0086
+#define DP83867_IO_MUX_CFG 0x0170
+
+#define DP83867_SW_RESET BIT(15)
+#define DP83867_SW_RESTART BIT(14)
+
+/* MICR Interrupt bits */
+#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
+#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
+#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
+#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
+#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
+#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
+#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
+#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
+#define MII_DP83867_MICR_WOL_INT_EN BIT(3)
+#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
+#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
+#define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
+
+/* RGMIICTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
+#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
+
+/* STRAP_STS1 bits */
+#define DP83867_STRAP_STS1_RESERVED BIT(11)
+
+/* PHY CTRL bits */
+#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
+#define DP83867_PHYCR_FIFO_DEPTH_MASK (3 << 14)
+#define DP83867_MDI_CROSSOVER 5
+#define DP83867_MDI_CROSSOVER_AUTO 0b10
+#define DP83867_MDI_CROSSOVER_MDIX 0b01
+#define DP83867_PHYCTRL_SGMIIEN 0x0800
+#define DP83867_PHYCTRL_RXFIFO_SHIFT 12
+#define DP83867_PHYCTRL_TXFIFO_SHIFT 14
+#define DP83867_PHYCR_RESERVED_MASK BIT(11)
+
+/* RGMIIDCTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
+
+/* CFG2 bits */
+#define MII_DP83867_CFG2_SPEEDOPT_10EN 0x0040
+#define MII_DP83867_CFG2_SGMII_AUTONEGEN 0x0080
+#define MII_DP83867_CFG2_SPEEDOPT_ENH 0x0100
+#define MII_DP83867_CFG2_SPEEDOPT_CNT 0x0800
+#define MII_DP83867_CFG2_SPEEDOPT_INTLOW 0x2000
+#define MII_DP83867_CFG2_MASK 0x003F
+
+/* CFG4 bits */
+#define DP83867_CFG4_SGMII_AUTONEG_TIMER_MASK 0x60
+#define DP83867_CFG4_SGMII_AUTONEG_TIMER_16MS 0x00
+#define DP83867_CFG4_SGMII_AUTONEG_TIMER_2US 0x20
+#define DP83867_CFG4_SGMII_AUTONEG_TIMER_800US 0x40
+#define DP83867_CFG4_SGMII_AUTONEG_TIMER_11MS 0x60
+#define DP83867_CFG4_RESVDBIT7 BIT(7)
+#define DP83867_CFG4_RESVDBIT8 BIT(8)
+
+/* IO_MUX_CFG bits */
+#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f
+
+#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0
+#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f
+
+/* CFG4 bits */
+#define DP83867_CFG4_PORT_MIRROR_EN BIT(0)
+
+enum {
+ DP83867_PORT_MIRROING_KEEP,
+ DP83867_PORT_MIRROING_EN,
+ DP83867_PORT_MIRROING_DIS,
+};
+
+struct dp83867_private {
+ int rx_id_delay;
+ int tx_id_delay;
+ int fifo_depth;
+ int io_impedance;
+ int port_mirroring;
+ bool rxctrl_strap_quirk;
+};
+
+static int dp83867_config_port_mirroring(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867 = (struct dp83867_private *)phydev->priv;
+ u16 val;
+
+ val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR);
+
+ if (dp83867->port_mirroring == DP83867_PORT_MIRROING_EN)
+ val |= DP83867_CFG4_PORT_MIRROR_EN;
+ else
+ val &= ~DP83867_CFG4_PORT_MIRROR_EN;
+
+ phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, val);
+
+ return 0;
+}
+
+static int dp83867_of_init(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867 = phydev->priv;
+ struct device_d *dev = &phydev->dev;
+ struct device_node *of_node = dev->device_node;
+ int ret;
+
+ if (!of_node)
+ return -ENODEV;
+
+ dp83867->io_impedance = -EINVAL;
+
+ /* Optional configuration */
+ if (of_property_read_bool(of_node, "ti,max-output-impedance"))
+ dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
+ else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
+ dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
+
+ dp83867->rxctrl_strap_quirk =
+ of_property_read_bool(of_node,
+ "ti,dp83867-rxctrl-strap-quirk");
+
+ ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
+ &dp83867->rx_id_delay);
+ if (ret && (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID))
+ return ret;
+
+ ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
+ &dp83867->tx_id_delay);
+ if (ret && (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID))
+ return ret;
+
+ if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
+ dp83867->port_mirroring = DP83867_PORT_MIRROING_EN;
+
+ if (of_property_read_bool(of_node, "enet-phy-lane-no-swap"))
+ dp83867->port_mirroring = DP83867_PORT_MIRROING_DIS;
+
+ return of_property_read_u32(of_node, "ti,fifo-depth",
+ &dp83867->fifo_depth);
+}
+
+static inline bool phy_interface_is_rgmii(struct phy_device *phydev)
+{
+ return phydev->interface >= PHY_INTERFACE_MODE_RGMII &&
+ phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID;
+}
+
+static inline bool phy_interface_is_sgmii(struct phy_device *phydev)
+{
+ return phydev->interface == PHY_INTERFACE_MODE_SGMII ||
+ phydev->interface == PHY_INTERFACE_MODE_QSGMII;
+}
+
+static int dp83867_config_init(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867;
+ int ret;
+ u16 val, delay, cfg2;
+
+ if (!phydev->priv) {
+ dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
+ if (!dp83867)
+ return -ENOMEM;
+
+ phydev->priv = dp83867;
+ ret = dp83867_of_init(phydev);
+ if (ret)
+ return ret;
+ } else {
+ dp83867 = (struct dp83867_private *)phydev->priv;
+ }
+
+ /* Restart the PHY. */
+ val = phy_read(phydev, DP83867_CTRL);
+ phy_write(phydev, DP83867_CTRL, val | DP83867_SW_RESTART);
+
+ if (dp83867->rxctrl_strap_quirk) {
+ val = phy_read_mmd_indirect(phydev, DP83867_CFG4,
+ DP83867_DEVADDR);
+ val &= ~BIT(7);
+ phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
+ val);
+ }
+
+ if (phy_interface_is_rgmii(phydev)) {
+ val = DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER |
+ dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT;
+ ret = phy_write(phydev, MII_DP83867_PHYCTRL, val);
+ if (ret)
+ return ret;
+ } else if (phy_interface_is_sgmii(phydev)) {
+ phy_write(phydev, MII_BMCR, BMCR_ANENABLE |
+ BMCR_FULLDPLX |
+ BMCR_SPEED1000);
+
+ cfg2 = phy_read(phydev, MII_DP83867_CFG2);
+ cfg2 &= MII_DP83867_CFG2_MASK;
+ cfg2 |= MII_DP83867_CFG2_SPEEDOPT_10EN |
+ MII_DP83867_CFG2_SGMII_AUTONEGEN |
+ MII_DP83867_CFG2_SPEEDOPT_ENH |
+ MII_DP83867_CFG2_SPEEDOPT_CNT |
+ MII_DP83867_CFG2_SPEEDOPT_INTLOW;
+
+ phy_write(phydev, MII_DP83867_CFG2, cfg2);
+
+ phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
+ DP83867_DEVADDR, 0x0);
+
+ val = DP83867_PHYCTRL_SGMIIEN |
+ DP83867_MDI_CROSSOVER_MDIX << DP83867_MDI_CROSSOVER |
+ dp83867->fifo_depth << DP83867_PHYCTRL_RXFIFO_SHIFT |
+ dp83867->fifo_depth << DP83867_PHYCTRL_TXFIFO_SHIFT;
+
+ phy_write(phydev, MII_DP83867_PHYCTRL, val);
+ phy_write(phydev, MII_DP83867_BISCR, 0x0);
+ }
+
+ if (phy_interface_is_rgmii(phydev)) {
+ val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
+ DP83867_DEVADDR);
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ val |= (DP83867_RGMII_TX_CLK_DELAY_EN
+ | DP83867_RGMII_RX_CLK_DELAY_EN);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val |= DP83867_RGMII_TX_CLK_DELAY_EN;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ val |= DP83867_RGMII_RX_CLK_DELAY_EN;
+ break;
+ default:
+ break;
+ }
+ phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
+ DP83867_DEVADDR, val);
+
+ delay = (dp83867->rx_id_delay |
+ (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
+
+ phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
+ DP83867_DEVADDR, delay);
+
+ if (dp83867->io_impedance >= 0) {
+ val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
+ DP83867_DEVADDR);
+ val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
+ val |= dp83867->io_impedance
+ & DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
+
+ phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
+ DP83867_DEVADDR, val);
+ }
+ }
+
+ genphy_config_aneg(phydev);
+
+ if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
+ dp83867_config_port_mirroring(phydev);
+
+ dev_info(&phydev->dev, "DP83867\n");
+
+ return 0;
+}
+
+static struct phy_driver dp83867_driver[] = {
+ {
+ .phy_id = DP83867_PHY_ID,
+ .phy_id_mask = 0xfffffff0,
+ .drv.name = "TI DP83867",
+ .features = PHY_GBIT_FEATURES,
+
+ .config_init = dp83867_config_init,
+
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ },
+};
+
+static int dp83867_phy_init(void)
+{
+ return phy_drivers_register(dp83867_driver, ARRAY_SIZE(dp83867_driver));
+}
+fs_initcall(dp83867_phy_init);
diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index e0cf35f0b7..5b8b925cb4 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -446,9 +446,18 @@ static int imx_ocotp_set_mac(struct param_d *param, void *priv)
{
char buf[MAC_BYTES];
struct ocotp_priv_ethaddr *ethaddr = priv;
+ int ret;
- ethaddr->data->format_mac(buf, ethaddr->value,
- OCOTP_MAC_TO_HW);
+ ret = regmap_bulk_read(ethaddr->map, ethaddr->offset, buf, MAC_BYTES);
+ if (ret < 0)
+ return ret;
+
+ if (ethaddr->offset != IMX6UL_MAC_OFFSET_1)
+ ethaddr->data->format_mac(buf, ethaddr->value,
+ OCOTP_MAC_TO_HW);
+ else
+ ethaddr->data->format_mac(buf + 2, ethaddr->value,
+ OCOTP_MAC_TO_HW);
return regmap_bulk_write(ethaddr->map, ethaddr->offset,
buf, MAC_BYTES);
@@ -697,11 +706,4 @@ static struct driver_d imx_ocotp_driver = {
.probe = imx_ocotp_probe,
.of_compatible = DRV_OF_COMPAT(imx_ocotp_dt_ids),
};
-
-static int imx_ocotp_init(void)
-{
- platform_driver_register(&imx_ocotp_driver);
-
- return 0;
-}
-postcore_initcall(imx_ocotp_init);
+postcore_platform_driver(imx_ocotp_driver);
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index ce5d0e2c89..562304c65d 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -9,5 +9,5 @@ CPPFLAGS += $(ccflags-y)
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o pci-mvebu-phy.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
-obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCIE_DW) += pcie-designware.o pcie-designware-host.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index fc56a0d14a..38e002a1c6 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCIe host controller driver for Freescale i.MX6 SoCs
*
@@ -5,10 +6,6 @@
* http://www.kosagi.com
*
* Author: Sean Cross <xobs@kosagi.com>
- *
- * 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.
*/
#include <common.h>
@@ -35,7 +32,7 @@
#include "pcie-designware.h"
-#define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp)
+#define to_imx6_pcie(x) ((x)->dev->priv)
enum imx6_pcie_variants {
IMX6Q,
@@ -43,19 +40,19 @@ enum imx6_pcie_variants {
};
struct imx6_pcie {
+ struct dw_pcie *pci;
int reset_gpio;
struct clk *pcie_bus;
struct clk *pcie_phy;
struct clk *pcie;
- struct pcie_port pp;
void __iomem *iomuxc_gpr;
enum imx6_pcie_variants variant;
- void __iomem *mem_base;
u32 tx_deemph_gen1;
u32 tx_deemph_gen2_3p5db;
u32 tx_deemph_gen2_6db;
u32 tx_swing_full;
u32 tx_swing_low;
+ int link_gen;
};
/* PCIe Root Complex registers (memory-mapped) */
@@ -72,7 +69,6 @@ struct imx6_pcie {
#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16)
#define PCIE_PL_PFLR_FORCE_LINK (1 << 15)
#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
-#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4)
@@ -96,14 +92,15 @@ struct imx6_pcie {
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
-static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
+static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val)
{
+ struct dw_pcie *pci = imx6_pcie->pci;
u32 val;
u32 max_iterations = 10;
u32 wait_counter = 0;
do {
- val = readl(dbi_base + PCIE_PHY_STAT);
+ val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT);
val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1;
wait_counter++;
@@ -116,129 +113,130 @@ static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
return -ETIMEDOUT;
}
-static int pcie_phy_wait_ack(void __iomem *dbi_base, int addr)
+static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr)
{
+ struct dw_pcie *pci = imx6_pcie->pci;
u32 val;
int ret;
val = addr << PCIE_PHY_CTRL_DATA_LOC;
- writel(val, dbi_base + PCIE_PHY_CTRL);
val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC);
- writel(val, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val);
- ret = pcie_phy_poll_ack(dbi_base, 1);
+ ret = pcie_phy_poll_ack(imx6_pcie, 1);
if (ret)
return ret;
val = addr << PCIE_PHY_CTRL_DATA_LOC;
- writel(val, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val);
- return pcie_phy_poll_ack(dbi_base, 0);
+ return pcie_phy_poll_ack(imx6_pcie, 0);
}
/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
-static int pcie_phy_read(void __iomem *dbi_base, int addr , int *data)
+static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr , int *data)
{
+ struct dw_pcie *pci = imx6_pcie->pci;
u32 val, phy_ctl;
int ret;
- ret = pcie_phy_wait_ack(dbi_base, addr);
+ ret = pcie_phy_wait_ack(imx6_pcie, addr);
if (ret)
return ret;
/* assert Read signal */
phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC;
- writel(phy_ctl, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl);
- ret = pcie_phy_poll_ack(dbi_base, 1);
+ ret = pcie_phy_poll_ack(imx6_pcie, 1);
if (ret)
return ret;
- val = readl(dbi_base + PCIE_PHY_STAT);
+ val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT);
*data = val & 0xffff;
/* deassert Read signal */
- writel(0x00, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00);
- return pcie_phy_poll_ack(dbi_base, 0);
+ return pcie_phy_poll_ack(imx6_pcie, 0);
}
-static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
+static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
{
+ struct dw_pcie *pci = imx6_pcie->pci;
u32 var;
int ret;
/* write addr */
/* cap addr */
- ret = pcie_phy_wait_ack(dbi_base, addr);
+ ret = pcie_phy_wait_ack(imx6_pcie, addr);
if (ret)
return ret;
var = data << PCIE_PHY_CTRL_DATA_LOC;
- writel(var, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
/* capture data */
var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC);
- writel(var, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
- ret = pcie_phy_poll_ack(dbi_base, 1);
+ ret = pcie_phy_poll_ack(imx6_pcie, 1);
if (ret)
return ret;
/* deassert cap data */
var = data << PCIE_PHY_CTRL_DATA_LOC;
- writel(var, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
/* wait for ack de-assertion */
- ret = pcie_phy_poll_ack(dbi_base, 0);
+ ret = pcie_phy_poll_ack(imx6_pcie, 0);
if (ret)
return ret;
/* assert wr signal */
var = 0x1 << PCIE_PHY_CTRL_WR_LOC;
- writel(var, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
/* wait for ack */
- ret = pcie_phy_poll_ack(dbi_base, 1);
+ ret = pcie_phy_poll_ack(imx6_pcie, 1);
if (ret)
return ret;
/* deassert wr signal */
var = data << PCIE_PHY_CTRL_DATA_LOC;
- writel(var, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
/* wait for ack de-assertion */
- ret = pcie_phy_poll_ack(dbi_base, 0);
+ ret = pcie_phy_poll_ack(imx6_pcie, 0);
if (ret)
return ret;
- writel(0x0, dbi_base + PCIE_PHY_CTRL);
+ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x0);
return 0;
}
-static void imx6_pcie_reset_phy(struct pcie_port *pp)
+static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
{
uint32_t temp;
- pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
+ pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &temp);
temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp);
+ pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, temp);
udelay(2000);
- pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
+ pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &temp);
temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp);
+ pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, temp);
}
-static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
+static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
{
- struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
- u32 val, gpr1, gpr12;
+ u32 gpr1;
switch (imx6_pcie->variant) {
case IMX6QP:
@@ -247,34 +245,7 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
break;
case IMX6Q:
- /*
- * If the bootloader already enabled the link we need some special
- * handling to get the core back into a state where it is safe to
- * touch it for configuration. As there is no dedicated reset signal
- * wired up for MX6QDL, we need to manually force LTSSM into "detect"
- * state before completely disabling LTSSM, which is a prerequisite
- * for core configuration.
- *
- * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
- * indication that the bootloader activated the link.
- */
gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
- gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
-
- if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) &&
- (gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) {
- val = readl(pp->dbi_base + PCIE_PL_PFLR);
- val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
- val |= PCIE_PL_PFLR_FORCE_LINK;
-
- data_abort_mask();
- writel(val, pp->dbi_base + PCIE_PL_PFLR);
- data_abort_unmask();
-
- gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
- writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- }
-
gpr1 |= IMX6Q_GPR1_PCIE_TEST_PD;
writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
@@ -282,28 +253,12 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
break;
}
-
- return 0;
}
-static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
+static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
{
- struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
- int ret;
u32 gpr1;
- ret = clk_enable(imx6_pcie->pcie_phy);
- if (ret)
- goto err_pcie_phy;
-
- ret = clk_enable(imx6_pcie->pcie_bus);
- if (ret)
- goto err_pcie_bus;
-
- ret = clk_enable(imx6_pcie->pcie);
- if (ret)
- goto err_pcie;
-
/* power up core phy and enable ref clock */
gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
gpr1 &= ~IMX6Q_GPR1_PCIE_TEST_PD;
@@ -319,6 +274,39 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
gpr1 |= IMX6Q_GPR1_PCIE_REF_CLK_EN;
writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ return 0;
+}
+
+static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
+{
+ struct device_d *dev = imx6_pcie->pci->dev;
+ int ret;
+ u32 gpr1;
+
+ ret = clk_enable(imx6_pcie->pcie_phy);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie_phy clock\n");
+ return;
+ }
+
+ ret = clk_enable(imx6_pcie->pcie_bus);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie_bus clock\n");
+ goto err_pcie_bus;
+ }
+
+ ret = clk_enable(imx6_pcie->pcie);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie clock\n");
+ goto err_pcie;
+ }
+
+ ret = imx6_pcie_enable_ref_clk(imx6_pcie);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie ref clock\n");
+ goto err_ref_clk;
+ }
+
/* allow the clocks to stabilize */
udelay(200);
@@ -344,20 +332,18 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
break;
}
- return 0;
+ return;
+err_ref_clk:
+ clk_disable(imx6_pcie->pcie);
err_pcie:
clk_disable(imx6_pcie->pcie_bus);
err_pcie_bus:
clk_disable(imx6_pcie->pcie_phy);
-err_pcie_phy:
- return ret;
-
}
-static void imx6_pcie_init_phy(struct pcie_port *pp)
+static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
- struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
u32 gpr12, gpr8;
gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
@@ -395,41 +381,34 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
}
-static int imx6_pcie_wait_for_link(struct pcie_port *pp)
+static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
{
- uint64_t start = get_time_ns();
-
- while (1) {
- if (dw_pcie_link_up(pp))
- return 0;
-
- if (!is_timeout(start, SECOND))
- continue;
-
- return -EINVAL;
- }
+ return dw_pcie_wait_for_link(imx6_pcie->pci);
}
-static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp)
+static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
{
+ struct dw_pcie *pci = imx6_pcie->pci;
+ struct device_d *dev = pci->dev;
uint32_t tmp;
uint64_t start = get_time_ns();
while (!is_timeout(start, SECOND)) {
- tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
/* Test if the speed change finished. */
if (!(tmp & PORT_LOGIC_SPEED_CHANGE))
return 0;
}
- dev_err(pp->dev, "Speed change timeout\n");
+ dev_err(dev, "Speed change timeout\n");
return -EINVAL;
}
-static int imx6_pcie_establish_link(struct pcie_port *pp)
+static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
{
- struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+ struct dw_pcie *pci = imx6_pcie->pci;
+ struct device_d *dev = pci->dev;
uint32_t tmp;
int ret;
u32 gpr12;
@@ -439,124 +418,98 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
* started in Gen2 mode, there is a possibility the devices on the
* bus will not be detected at all. This happens with PCIe switches.
*/
- tmp = readl(pp->dbi_base + PCIE_RC_LCR);
+ tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
- writel(tmp, pp->dbi_base + PCIE_RC_LCR);
+ dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
/* Start LTSSM. */
gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
- ret = imx6_pcie_wait_for_link(pp);
- if (ret) {
- dev_info(pp->dev, "Link never came up\n");
+ ret = imx6_pcie_wait_for_link(imx6_pcie);
+ if (ret)
goto err_reset_phy;
- }
- /* Allow Gen2 mode after the link is up. */
- tmp = readl(pp->dbi_base + PCIE_RC_LCR);
- tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
- tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
- writel(tmp, pp->dbi_base + PCIE_RC_LCR);
+
+ if (imx6_pcie->link_gen == 2) {
+ /* Allow Gen2 mode after the link is up. */
+ tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
+ tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
+ tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
+ dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
+ } else {
+ dev_info(dev, "Link: Gen2 disabled\n");
+ }
/*
* Start Directed Speed Change so the best possible speed both link
* partners support can be negotiated.
*/
- tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
tmp |= PORT_LOGIC_SPEED_CHANGE;
- writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
- ret = imx6_pcie_wait_for_speed_change(pp);
+ ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
if (ret) {
- dev_err(pp->dev, "Failed to bring link up!\n");
+ dev_err(dev, "Failed to bring link up!\n");
goto err_reset_phy;
}
/* Make sure link training is finished as well! */
- ret = imx6_pcie_wait_for_link(pp);
+ ret = imx6_pcie_wait_for_link(imx6_pcie);
if (ret) {
- dev_err(pp->dev, "Failed to bring link up!\n");
+ dev_err(dev, "Failed to bring link up!\n");
goto err_reset_phy;
}
- tmp = readl(pp->dbi_base + PCIE_RC_LCSR);
- dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
-
+ tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR);
+ dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
return 0;
err_reset_phy:
- dev_dbg(pp->dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
- readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
- readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
- imx6_pcie_reset_phy(pp);
+ dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
+ dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0),
+ dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1));
+ imx6_pcie_reset_phy(imx6_pcie);
return ret;
}
-static void imx6_pcie_host_init(struct pcie_port *pp)
+static int imx6_pcie_host_init(struct pcie_port *pp)
{
- imx6_pcie_assert_core_reset(pp);
-
- imx6_pcie_init_phy(pp);
-
- imx6_pcie_deassert_core_reset(pp);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
+ imx6_pcie_assert_core_reset(imx6_pcie);
+ imx6_pcie_init_phy(imx6_pcie);
+ imx6_pcie_deassert_core_reset(imx6_pcie);
dw_pcie_setup_rc(pp);
+ imx6_pcie_establish_link(imx6_pcie);
- imx6_pcie_establish_link(pp);
+ return 0;
}
-static int imx6_pcie_link_up(struct pcie_port *pp)
+static int imx6_pcie_link_up(struct dw_pcie *pci)
{
- u32 rc;
- int count = 5;
-
- /*
- * Test if the PHY reports that the link is up and also that the LTSSM
- * training finished. There are three possible states of the link when
- * this code is called:
- * 1) The link is DOWN (unlikely)
- * The link didn't come up yet for some reason. This usually means
- * we have a real problem somewhere. Reset the PHY and exit. This
- * state calls for inspection of the DEBUG registers.
- * 2) The link is UP, but still in LTSSM training
- * Wait for the training to finish, which should take a very short
- * time. If the training does not finish, we have a problem and we
- * need to inspect the DEBUG registers. If the training does finish,
- * the link is up and operating correctly.
- * 3) The link is UP and no longer in LTSSM training
- * The link is up and operating correctly.
- */
- while (1) {
- rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
- if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
- break;
- if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
- return 1;
- if (!count--)
- break;
- dev_dbg(pp->dev, "Link is up, but still in training\n");
- /*
- * Wait a little bit, then re-check if the link finished
- * the training.
- */
- udelay(1000);
- }
-
- return 0;
+ return dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1) &
+ PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
}
-static struct pcie_host_ops imx6_pcie_host_ops = {
- .link_up = imx6_pcie_link_up,
+static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = imx6_pcie_link_up,
+};
+
+static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
.host_init = imx6_pcie_host_init,
};
-static int __init imx6_add_pcie_port(struct pcie_port *pp,
- struct device_d *dev)
+static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
+ struct device_d *dev)
{
+ struct dw_pcie *pci = imx6_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
int ret;
pp->root_bus_nr = -1;
@@ -574,23 +527,25 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp,
static int __init imx6_pcie_probe(struct device_d *dev)
{
struct resource *iores;
+ struct dw_pcie *pci;
struct imx6_pcie *imx6_pcie;
- struct pcie_port *pp;
struct device_node *np = dev->device_node;
int ret;
imx6_pcie = xzalloc(sizeof(*imx6_pcie));
- pp = &imx6_pcie->pp;
- pp->dev = dev;
+ pci = xzalloc(sizeof(*pci));
+ pci->dev = dev;
+ pci->ops = &dw_pcie_ops;
+ imx6_pcie->pci = pci;
imx6_pcie->variant =
(enum imx6_pcie_variants)of_device_get_match_data(dev);
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
- pp->dbi_base = IOMEM(iores->start);
+ pci->dbi_base = IOMEM(iores->start);
/* Fetch GPIOs */
imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
@@ -646,12 +601,18 @@ static int __init imx6_pcie_probe(struct device_d *dev)
&imx6_pcie->tx_swing_low))
imx6_pcie->tx_swing_low = 127;
- ret = imx6_add_pcie_port(pp, dev);
+ /* Limit link speed */
+ ret = of_property_read_u32(np, "fsl,max-link-speed",
+ &imx6_pcie->link_gen);
+ if (ret)
+ imx6_pcie->link_gen = 1;
+
+ dev->priv = imx6_pcie;
+
+ ret = imx6_add_pcie_port(imx6_pcie, dev);
if (ret < 0)
return ret;
- dev->priv = imx6_pcie;
-
return 0;
}
@@ -659,7 +620,34 @@ static void imx6_pcie_remove(struct device_d *dev)
{
struct imx6_pcie *imx6_pcie = dev->priv;
- imx6_pcie_assert_core_reset(&imx6_pcie->pp);
+ if (imx6_pcie->variant == IMX6Q) {
+ /*
+ * If the bootloader already enabled the link we need
+ * some special handling to get the core back into a
+ * state where it is safe to touch it for
+ * configuration. As there is no dedicated reset
+ * signal wired up for MX6QDL, we need to manually
+ * force LTSSM into "detect" state before completely
+ * disabling LTSSM, which is a prerequisite for core
+ * configuration.
+ */
+ struct dw_pcie *pci = imx6_pcie->pci;
+ u32 gpr12, val;
+
+ val = dw_pcie_readl_dbi(pci, PCIE_PL_PFLR);
+ val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
+ val |= PCIE_PL_PFLR_FORCE_LINK;
+
+ data_abort_mask();
+ dw_pcie_writel_dbi(pci, PCIE_PL_PFLR, val);
+ data_abort_unmask();
+
+ gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
+ writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ }
+
+ imx6_pcie_assert_core_reset(imx6_pcie);
}
static struct of_device_id imx6_pcie_of_match[] = {
diff --git a/drivers/pci/pci-mvebu-phy.c b/drivers/pci/pci-mvebu-phy.c
index 55a1d39f62..f1bfc99eef 100644
--- a/drivers/pci/pci-mvebu-phy.c
+++ b/drivers/pci/pci-mvebu-phy.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SoC specific PCIe PHY setup for Marvell MVEBU SoCs
*
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
*
* based on Marvell BSP code (C) Marvell International Ltd.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <common.h>
diff --git a/drivers/pci/pci-mvebu.c b/drivers/pci/pci-mvebu.c
index 91e8ca870b..1c20f91544 100644
--- a/drivers/pci/pci-mvebu.c
+++ b/drivers/pci/pci-mvebu.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCIe driver for Marvell MVEBU SoCs
*
* Based on Linux drivers/pci/host/pci-mvebu.c
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <common.h>
diff --git a/drivers/pci/pci-mvebu.h b/drivers/pci/pci-mvebu.h
index 8ced9fefca..2797bc4c8b 100644
--- a/drivers/pci/pci-mvebu.h
+++ b/drivers/pci/pci-mvebu.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* PCIe include for Marvell MVEBU SoCs
*
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#ifndef __MVEBU_PCI_H
diff --git a/drivers/pci/pci-tegra.c b/drivers/pci/pci-tegra.c
index b532c464a6..b6ccf8e5b5 100644
--- a/drivers/pci/pci-tegra.c
+++ b/drivers/pci/pci-tegra.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2014 Lucas Stach <l.stach@pengutronix.de>
*
* based on code
* Copyright (c) 2010, CompuLab, Ltd.
* Copyright (c) 2008-2009, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <common.h>
diff --git a/drivers/pci/pcie-designware-host.c b/drivers/pci/pcie-designware-host.c
new file mode 100644
index 0000000000..6cc4b93a31
--- /dev/null
+++ b/drivers/pci/pcie-designware-host.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Synopsys DesignWare PCIe host controller driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ */
+
+
+#include <common.h>
+#include <clock.h>
+#include <malloc.h>
+#include <io.h>
+#include <init.h>
+#include <asm/mmu.h>
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <of_address.h>
+#include <of_pci.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+
+#include "pcie-designware.h"
+
+#include <abort.h>
+
+static struct pci_ops dw_pcie_ops;
+static unsigned long global_io_offset;
+
+static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+ u32 *val)
+{
+ struct dw_pcie *pci;
+
+ if (pp->ops->rd_own_conf)
+ return pp->ops->rd_own_conf(pp, where, size, val);
+
+ pci = to_dw_pcie_from_pp(pp);
+ return dw_pcie_read(pci->dbi_base + where, size, val);
+}
+
+static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
+ u32 val)
+{
+ struct dw_pcie *pci;
+
+ if (pp->ops->wr_own_conf)
+ return pp->ops->wr_own_conf(pp, where, size, val);
+
+ pci = to_dw_pcie_from_pp(pp);
+ return dw_pcie_write(pci->dbi_base + where, size, val);
+}
+
+static inline struct pcie_port *host_to_pcie(struct pci_controller *host)
+{
+ return container_of(host, struct pcie_port, pci);
+}
+
+static void dw_pcie_set_local_bus_nr(struct pci_controller *host, int busno)
+{
+ struct pcie_port *pp = host_to_pcie(host);
+
+ pp->root_bus_nr = busno;
+}
+
+int __init dw_pcie_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device_d *dev = pci->dev;
+ struct device_node *np = dev->device_node;
+ struct of_pci_range range;
+ struct of_pci_range_parser parser;
+ struct resource *cfg_res;
+ u32 na, ns;
+ const __be32 *addrp;
+ int index, ret;
+
+ /* Find the address cell size and the number of cells in order to get
+ * the untranslated address.
+ */
+ of_property_read_u32(np, "#address-cells", &na);
+ ns = of_n_size_cells(np);
+
+ cfg_res = dev_get_resource_by_name(dev, IORESOURCE_MEM, "config");
+ if (cfg_res) {
+ pp->cfg0_size = resource_size(cfg_res) >> 1;
+ pp->cfg1_size = resource_size(cfg_res) >> 1;
+ pp->cfg0_base = cfg_res->start;
+ pp->cfg1_base = cfg_res->start + pp->cfg0_size;
+
+ /* Find the untranslated configuration space address */
+ index = of_property_match_string(np, "reg-names", "config");
+ addrp = of_get_address(np, index, NULL, NULL);
+ pp->cfg0_mod_base = of_read_number(addrp, ns);
+ pp->cfg1_mod_base = pp->cfg0_mod_base + pp->cfg0_size;
+ } else {
+ dev_err(dev, "Missing *config* reg space\n");
+ }
+
+ if (of_pci_range_parser_init(&parser, np)) {
+ dev_err(dev, "Missing ranges property\n");
+ return -EINVAL;
+ }
+
+ /* Get the I/O and memory ranges from DT */
+ for_each_of_pci_range(&parser, &range) {
+ unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
+
+ if (restype == IORESOURCE_IO) {
+ of_pci_range_to_resource(&range, np, &pp->io);
+ pp->io.name = "I/O";
+ pp->io.start = range.pci_addr + global_io_offset;
+ pp->io.end = range.pci_addr + range.size + global_io_offset - 1;
+ pp->io_size = resource_size(&pp->io);
+ pp->io_bus_addr = range.pci_addr;
+ pp->io_base = range.cpu_addr;
+
+ /* Find the untranslated IO space address */
+ pp->io_mod_base = of_read_number(parser.range -
+ parser.np + na, ns);
+ }
+ if (restype == IORESOURCE_MEM) {
+ of_pci_range_to_resource(&range, np, &pp->mem);
+ pp->mem.name = "MEM";
+ pp->mem_size = resource_size(&pp->mem);
+ pp->mem_bus_addr = range.pci_addr;
+
+ /* Find the untranslated MEM space address */
+ pp->mem_mod_base = of_read_number(parser.range -
+ parser.np + na, ns);
+ }
+ if (restype == 0) {
+ of_pci_range_to_resource(&range, np, &pp->cfg);
+ pp->cfg0_size = resource_size(&pp->cfg) >> 1;
+ pp->cfg1_size = resource_size(&pp->cfg) >> 1;
+ pp->cfg0_base = pp->cfg.start;
+ pp->cfg1_base = pp->cfg.start + pp->cfg0_size;
+
+ /* Find the untranslated configuration space address */
+ pp->cfg0_mod_base = of_read_number(parser.range -
+ parser.np + na, ns);
+ pp->cfg1_mod_base = pp->cfg0_mod_base +
+ pp->cfg0_size;
+ }
+ }
+
+ if (!pci->dbi_base)
+ pci->dbi_base = (void __force *)pp->cfg.start;
+
+ pp->mem_base = pp->mem.start;
+
+ if (!pp->va_cfg0_base)
+ pp->va_cfg0_base = (void __force *)(u32)pp->cfg0_base;
+
+ if (!pp->va_cfg1_base)
+ pp->va_cfg1_base = (void __force *)(u32)pp->cfg1_base;
+
+ ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
+ if (ret)
+ pci->num_viewport = 2;
+
+ if (pp->ops->host_init) {
+ ret = pp->ops->host_init(pp);
+ if (ret)
+ return ret;
+ }
+
+ pp->pci.parent = dev;
+ pp->pci.pci_ops = &dw_pcie_ops;
+ pp->pci.set_busno = dw_pcie_set_local_bus_nr;
+ pp->pci.mem_resource = &pp->mem;
+ pp->pci.io_resource = &pp->io;
+
+ register_pci_controller(&pp->pci);
+
+ return 0;
+}
+
+static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 *val)
+{
+ int ret, type;
+ u32 address, busdev, cfg_size;
+ u64 cpu_addr;
+ void __iomem *va_cfg_base;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ if (pp->ops->rd_other_conf)
+ return pp->ops->rd_other_conf(pp, bus, devfn,
+ where, size, val);
+
+ busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
+ PCIE_ATU_FUNC(PCI_FUNC(devfn));
+ address = where & ~0x3;
+
+ if (bus->primary == pp->root_bus_nr) {
+ type = PCIE_ATU_TYPE_CFG0;
+ cpu_addr = pp->cfg0_mod_base;
+ cfg_size = pp->cfg0_size;
+ va_cfg_base = pp->va_cfg0_base;
+ } else {
+ type = PCIE_ATU_TYPE_CFG1;
+ cpu_addr = pp->cfg1_mod_base;
+ cfg_size = pp->cfg1_size;
+ va_cfg_base = pp->va_cfg1_base;
+ }
+
+ dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+ type, cpu_addr,
+ busdev, cfg_size);
+ ret = dw_pcie_read(va_cfg_base + where, size, val);
+ if (pci->num_viewport <= 2)
+ dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pp->io_mod_base,
+ pp->io_bus_addr, pp->io_size);
+
+ return ret;
+}
+
+static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 val)
+{
+ int ret, type;
+ u32 busdev, cfg_size;
+ u64 cpu_addr;
+ void __iomem *va_cfg_base;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ if (pp->ops->wr_other_conf)
+ return pp->ops->wr_other_conf(pp, bus, devfn,
+ where, size, val);
+
+ busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
+ PCIE_ATU_FUNC(PCI_FUNC(devfn));
+
+ if (bus->primary == pp->root_bus_nr) {
+ type = PCIE_ATU_TYPE_CFG0;
+ cpu_addr = pp->cfg0_mod_base;
+ cfg_size = pp->cfg0_size;
+ va_cfg_base = pp->va_cfg0_base;
+ } else {
+ type = PCIE_ATU_TYPE_CFG1;
+ cpu_addr = pp->cfg1_mod_base;
+ cfg_size = pp->cfg1_size;
+ va_cfg_base = pp->va_cfg1_base;
+ }
+
+ dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+ type, cpu_addr,
+ busdev, cfg_size);
+ ret = dw_pcie_write(va_cfg_base + where, size, val);
+ if (pci->num_viewport <= 2)
+ dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
+ PCIE_ATU_TYPE_IO, pp->io_mod_base,
+ pp->io_bus_addr, pp->io_size);
+
+ return ret;
+}
+
+static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus,
+ int dev)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ /* If there is no link, then there is no device */
+ if (bus->number != pp->root_bus_nr) {
+ if (!dw_pcie_link_up(pci))
+ return 0;
+ }
+
+ /* Access only one slot on each root port */
+ if (bus->number == pp->root_bus_nr && dev > 0)
+ return 0;
+
+ /*
+ * Do not read more than one device on the bus directly attached
+ * to RC's (Virtual Bridge's) DS side.
+ */
+ if (bus->primary == pp->root_bus_nr && dev > 0)
+ return 0;
+
+ return 1;
+}
+
+static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ struct pcie_port *pp = host_to_pcie(bus->host);
+ int ret;
+
+ *val = 0xffffffff;
+
+ if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ data_abort_mask();
+
+ if (bus->number == pp->root_bus_nr)
+ ret = dw_pcie_rd_own_conf(pp, where, size, val);
+ else
+ ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+ where, size, val);
+
+ if (data_abort_unmask())
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return ret;
+}
+
+static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ struct pcie_port *pp = host_to_pcie(bus->host);
+ int ret;
+
+ if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ data_abort_mask();
+
+ if (bus->number == pp->root_bus_nr)
+ ret = dw_pcie_wr_own_conf(pp, where, size, val);
+ else
+ ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+ where, size, val);
+
+ if (data_abort_unmask())
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return ret;
+}
+
+static int dw_pcie_res_start(struct pci_bus *bus, resource_size_t res_addr)
+{
+ return res_addr;
+}
+
+static struct pci_ops dw_pcie_ops = {
+ .read = dw_pcie_rd_conf,
+ .write = dw_pcie_wr_conf,
+ .res_start = dw_pcie_res_start,
+};
+
+static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
+{
+ u32 val;
+
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
+ if (val == 0xffffffff)
+ return 1;
+
+ return 0;
+}
+
+void dw_pcie_setup_rc(struct pcie_port *pp)
+{
+ u32 val;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ dw_pcie_setup(pci);
+
+ /* Setup RC BARs */
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
+
+ /* Setup bus numbers */
+ val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
+ val &= 0xff000000;
+ val |= 0x00ff0100;
+ dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val);
+
+ /* Setup command register */
+ val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
+ val &= 0xffff0000;
+ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+ dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+
+ /*
+ * If the platform provides ->rd_other_conf, it means the platform
+ * uses its own address translation component rather than ATU, so
+ * we should not program the ATU here.
+ */
+ if (!pp->ops->rd_other_conf) {
+ /* get iATU unroll support */
+ pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci);
+ dev_dbg(pci->dev, "iATU unroll: %s\n",
+ pci->iatu_unroll_enabled ? "enabled" : "disabled");
+
+ dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM, pp->mem_mod_base,
+ pp->mem_bus_addr, pp->mem_size);
+ if (pci->num_viewport > 2)
+ dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
+ PCIE_ATU_TYPE_IO, pp->io_base,
+ pp->io_bus_addr, pp->io_size);
+ }
+
+ dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
+
+ /* Enable write permission for the DBI read-only register */
+ dw_pcie_dbi_ro_wr_en(pci);
+ /* Program correct class for RC */
+ dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
+ /* Better disable write permission right after the update */
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
+ val |= PORT_LOGIC_SPEED_CHANGE;
+ dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
+} \ No newline at end of file
diff --git a/drivers/pci/pcie-designware.c b/drivers/pci/pcie-designware.c
index 4962a19649..aaea316e90 100644
--- a/drivers/pci/pcie-designware.c
+++ b/drivers/pci/pcie-designware.c
@@ -1,14 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Synopsys Designware PCIe host controller driver
+ * Synopsys DesignWare PCIe host controller driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
- *
- * 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.
*/
@@ -30,476 +27,213 @@
#include "pcie-designware.h"
-/* Synopsis specific PCIE configuration registers */
-#define PCIE_PORT_LINK_CONTROL 0x710
-#define PORT_LINK_MODE_MASK (0x3f << 16)
-#define PORT_LINK_MODE_1_LANES (0x1 << 16)
-#define PORT_LINK_MODE_2_LANES (0x3 << 16)
-#define PORT_LINK_MODE_4_LANES (0x7 << 16)
-
-#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
-#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
-#define PORT_LOGIC_LINK_WIDTH_MASK (0x1ff << 8)
-#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
-#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
-#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
-
-#define PCIE_MSI_ADDR_LO 0x820
-#define PCIE_MSI_ADDR_HI 0x824
-#define PCIE_MSI_INTR0_ENABLE 0x828
-#define PCIE_MSI_INTR0_MASK 0x82C
-#define PCIE_MSI_INTR0_STATUS 0x830
-
-#define PCIE_ATU_VIEWPORT 0x900
-#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
-#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
-#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
-#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
-#define PCIE_ATU_CR1 0x904
-#define PCIE_ATU_TYPE_MEM (0x0 << 0)
-#define PCIE_ATU_TYPE_IO (0x2 << 0)
-#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
-#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
-#define PCIE_ATU_CR2 0x908
-#define PCIE_ATU_ENABLE (0x1 << 31)
-#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
-#define PCIE_ATU_LOWER_BASE 0x90C
-#define PCIE_ATU_UPPER_BASE 0x910
-#define PCIE_ATU_LIMIT 0x914
-#define PCIE_ATU_LOWER_TARGET 0x918
-#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
-#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
-#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
-#define PCIE_ATU_UPPER_TARGET 0x91C
-
-static unsigned long global_io_offset;
-
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
+int dw_pcie_read(void __iomem *addr, int size, u32 *val)
{
- *val = readl(addr);
+ if ((uintptr_t)addr & (size - 1)) {
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
- if (size == 1)
- *val = (*val >> (8 * (where & 3))) & 0xff;
- else if (size == 2)
- *val = (*val >> (8 * (where & 3))) & 0xffff;
- else if (size != 4)
+ if (size == 4) {
+ *val = readl(addr);
+ } else if (size == 2) {
+ *val = readw(addr);
+ } else if (size == 1) {
+ *val = readb(addr);
+ } else {
+ *val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
return PCIBIOS_SUCCESSFUL;
}
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
+int dw_pcie_write(void __iomem *addr, int size, u32 val)
{
+ if ((uintptr_t)addr & (size - 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
if (size == 4)
writel(val, addr);
else if (size == 2)
- writew(val, addr + (where & 2));
+ writew(val, addr);
else if (size == 1)
- writeb(val, addr + (where & 3));
+ writeb(val, addr);
else
return PCIBIOS_BAD_REGISTER_NUMBER;
return PCIBIOS_SUCCESSFUL;
}
-static inline void dw_pcie_readl_rc(struct pcie_port *pp, u32 reg, u32 *val)
-{
- if (pp->ops->readl_rc)
- pp->ops->readl_rc(pp, pp->dbi_base + reg, val);
- else
- *val = readl(pp->dbi_base + reg);
-}
-
-static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
-{
- if (pp->ops->writel_rc)
- pp->ops->writel_rc(pp, val, pp->dbi_base + reg);
- else
- writel(val, pp->dbi_base + reg);
-}
-
-#include <abort.h>
-
-static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
- u32 *val)
+u32 __dw_pcie_readl_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
+ size_t size)
{
int ret;
+ u32 val;
- if (pp->ops->rd_own_conf)
- ret = pp->ops->rd_own_conf(pp, where, size, val);
- else
- ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
- size, val);
+ if (pci->ops->readl_dbi)
+ return pci->ops->readl_dbi(pci, base, reg, size);
+
+ ret = dw_pcie_read(base + reg, size, &val);
+ if (ret)
+ dev_err(pci->dev, "Read DBI address failed\n");
- return ret;
+ return val;
}
-static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
- u32 val)
+void __dw_pcie_writel_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
+ size_t size, u32 val)
{
int ret;
- if (pp->ops->wr_own_conf)
- ret = pp->ops->wr_own_conf(pp, where, size, val);
- else
- ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
- size, val);
+ if (pci->ops->writel_dbi) {
+ pci->ops->writel_dbi(pci, base, reg, size, val);
+ return;
+ }
- return ret;
+ ret = dw_pcie_write(base + reg, size, val);
+ if (ret)
+ dev_err(pci->dev, "Write DBI address failed\n");
}
-int dw_pcie_link_up(struct pcie_port *pp)
+static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
{
- if (pp->ops->link_up)
- return pp->ops->link_up(pp);
- else
- return 0;
-}
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-static inline struct pcie_port *host_to_pcie(struct pci_controller *host)
-{
- return container_of(host, struct pcie_port, pci);
+ return dw_pcie_readl_dbi(pci, offset + reg);
}
-static void dw_pcie_set_local_bus_nr(struct pci_controller *host, int busno)
+static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index,
+ u32 reg, u32 val)
{
- struct pcie_port *pp = host_to_pcie(host);
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
- pp->root_bus_nr = busno;
+ dw_pcie_writel_dbi(pci, offset + reg, val);
}
-static struct pci_ops dw_pcie_ops;
-
-int __init dw_pcie_host_init(struct pcie_port *pp)
+static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
+ int type, u64 cpu_addr,
+ u64 pci_addr, u32 size)
{
- struct device_node *np = pp->dev->device_node;
- struct of_pci_range range;
- struct of_pci_range_parser parser;
- struct resource *cfg_res;
- u32 val, na, ns;
- const __be32 *addrp;
- int index;
-
- /* Find the address cell size and the number of cells in order to get
- * the untranslated address.
- */
- of_property_read_u32(np, "#address-cells", &na);
- ns = of_n_size_cells(np);
-
- cfg_res = dev_get_resource_by_name(pp->dev, IORESOURCE_MEM, "config");
- if (cfg_res) {
- pp->cfg0_size = resource_size(cfg_res)/2;
- pp->cfg1_size = resource_size(cfg_res)/2;
- pp->cfg0_base = cfg_res->start;
- pp->cfg1_base = cfg_res->start + pp->cfg0_size;
-
- /* Find the untranslated configuration space address */
- index = of_property_match_string(np, "reg-names", "config");
- addrp = of_get_address(np, index, NULL, NULL);
- pp->cfg0_mod_base = of_read_number(addrp, ns);
- pp->cfg1_mod_base = pp->cfg0_mod_base + pp->cfg0_size;
- } else {
- dev_err(pp->dev, "missing *config* reg space\n");
- }
+ u32 retries, val;
+
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
+ lower_32_bits(cpu_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
+ upper_32_bits(cpu_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
+ lower_32_bits(cpu_addr + size - 1));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+ lower_32_bits(pci_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+ upper_32_bits(pci_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
+ type);
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+ PCIE_ATU_ENABLE);
- if (of_pci_range_parser_init(&parser, np)) {
- dev_err(pp->dev, "missing ranges property\n");
- return -EINVAL;
- }
-
- /* Get the I/O and memory ranges from DT */
- for_each_of_pci_range(&parser, &range) {
- unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
-
- if (restype == IORESOURCE_IO) {
- of_pci_range_to_resource(&range, np, &pp->io);
- pp->io.name = "I/O";
- pp->io.start = range.pci_addr + global_io_offset;
- pp->io.end = range.pci_addr + range.size + global_io_offset - 1;
- pp->io_size = resource_size(&pp->io);
- pp->io_bus_addr = range.pci_addr;
- pp->io_base = range.cpu_addr;
-
- /* Find the untranslated IO space address */
- pp->io_mod_base = of_read_number(parser.range -
- parser.np + na, ns);
- }
- if (restype == IORESOURCE_MEM) {
- of_pci_range_to_resource(&range, np, &pp->mem);
- pp->mem.name = "MEM";
- pp->mem_size = resource_size(&pp->mem);
- pp->mem_bus_addr = range.pci_addr;
-
- /* Find the untranslated MEM space address */
- pp->mem_mod_base = of_read_number(parser.range -
- parser.np + na, ns);
- }
- if (restype == 0) {
- of_pci_range_to_resource(&range, np, &pp->cfg);
- pp->cfg0_size = resource_size(&pp->cfg)/2;
- pp->cfg1_size = resource_size(&pp->cfg)/2;
- pp->cfg0_base = pp->cfg.start;
- pp->cfg1_base = pp->cfg.start + pp->cfg0_size;
-
- /* Find the untranslated configuration space address */
- pp->cfg0_mod_base = of_read_number(parser.range -
- parser.np + na, ns);
- pp->cfg1_mod_base = pp->cfg0_mod_base +
- pp->cfg0_size;
- }
- }
-
- if (!pp->dbi_base)
- pp->dbi_base = (void __force *)pp->cfg.start;
-
- pp->mem_base = pp->mem.start;
-
- if (!pp->va_cfg0_base)
- pp->va_cfg0_base = (void __force *)(u32)pp->cfg0_base;
-
- if (!pp->va_cfg1_base)
- pp->va_cfg1_base = (void __force *)(u32)pp->cfg1_base;
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = dw_pcie_readl_ob_unroll(pci, index,
+ PCIE_ATU_UNR_REGION_CTRL2);
+ if (val & PCIE_ATU_ENABLE)
+ return;
- if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
- dev_err(pp->dev, "Failed to parse the number of lanes\n");
- return -EINVAL;
+ udelay(LINK_WAIT_IATU_MAX);
}
-
- if (pp->ops->host_init)
- pp->ops->host_init(pp);
-
- dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
-
- /* program correct class for RC */
- dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
-
- dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
- val |= PORT_LOGIC_SPEED_CHANGE;
- dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
-
- pp->pci.parent = pp->dev;
- pp->pci.pci_ops = &dw_pcie_ops;
- pp->pci.set_busno = dw_pcie_set_local_bus_nr;
- pp->pci.mem_resource = &pp->mem;
- pp->pci.io_resource = &pp->io;
-
- register_pci_controller(&pp->pci);
-
- return 0;
+ dev_err(pci->dev, "Outbound iATU is not being enabled\n");
}
-static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
+void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
+ int type, u64 cpu_addr, u64 pci_addr,
+ u32 size)
{
- /* Program viewport 0 : OUTBOUND : CFG0 */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->cfg0_size - 1,
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG0, PCIE_ATU_CR1);
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
-}
+ u32 retries, val;
-static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
-{
- /* Program viewport 1 : OUTBOUND : CFG1 */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
- dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->cfg1_size - 1,
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
-}
+ if (pci->iatu_unroll_enabled) {
+ dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr,
+ pci_addr, size);
+ return;
+ }
-static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
-{
- /* Program viewport 0 : OUTBOUND : MEM */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
- dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->mem_size - 1,
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, pp->mem_bus_addr, PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, upper_32_bits(pp->mem_bus_addr),
- PCIE_ATU_UPPER_TARGET);
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
-}
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
+ PCIE_ATU_REGION_OUTBOUND | index);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE,
+ lower_32_bits(cpu_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE,
+ upper_32_bits(cpu_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
+ lower_32_bits(cpu_addr + size - 1));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
+ lower_32_bits(pci_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
+ upper_32_bits(pci_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
-static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
-{
- /* Program viewport 1 : OUTBOUND : IO */
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_VIEWPORT);
- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
- dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE);
- dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE);
- dw_pcie_writel_rc(pp, pp->io_mod_base + pp->io_size - 1,
- PCIE_ATU_LIMIT);
- dw_pcie_writel_rc(pp, pp->io_bus_addr, PCIE_ATU_LOWER_TARGET);
- dw_pcie_writel_rc(pp, upper_32_bits(pp->io_bus_addr),
- PCIE_ATU_UPPER_TARGET);
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
-}
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
+ if (val & PCIE_ATU_ENABLE)
+ return;
-static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
- u32 devfn, int where, int size, u32 *val)
-{
- int ret = PCIBIOS_SUCCESSFUL;
- u32 address, busdev;
-
- busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
- PCIE_ATU_FUNC(PCI_FUNC(devfn));
- address = where & ~0x3;
-
- if (bus->primary == pp->root_bus_nr) {
- dw_pcie_prog_viewport_cfg0(pp, busdev);
- ret = dw_pcie_cfg_read(pp->va_cfg0_base + address, where, size,
- val);
- dw_pcie_prog_viewport_mem_outbound(pp);
- } else {
- dw_pcie_prog_viewport_cfg1(pp, busdev);
- ret = dw_pcie_cfg_read(pp->va_cfg1_base + address, where, size,
- val);
- dw_pcie_prog_viewport_io_outbound(pp);
+ udelay(LINK_WAIT_IATU_MAX);
}
-
- return ret;
+ dev_err(pci->dev, "Outbound iATU is not being enabled\n");
}
-static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
- u32 devfn, int where, int size, u32 val)
+int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
- int ret = PCIBIOS_SUCCESSFUL;
- u32 address, busdev;
-
- busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
- PCIE_ATU_FUNC(PCI_FUNC(devfn));
- address = where & ~0x3;
-
- if (bus->primary == pp->root_bus_nr) {
- dw_pcie_prog_viewport_cfg0(pp, busdev);
- ret = dw_pcie_cfg_write(pp->va_cfg0_base + address, where, size,
- val);
- dw_pcie_prog_viewport_mem_outbound(pp);
- } else {
- dw_pcie_prog_viewport_cfg1(pp, busdev);
- ret = dw_pcie_cfg_write(pp->va_cfg1_base + address, where, size,
- val);
- dw_pcie_prog_viewport_io_outbound(pp);
- }
+ int retries;
- return ret;
-}
-
-static int dw_pcie_valid_config(struct pcie_port *pp,
- struct pci_bus *bus, int dev)
-{
- /* If there is no link, then there is no device */
- if (bus->number != pp->root_bus_nr) {
- if (!dw_pcie_link_up(pp))
+ /* Check if the link is up or not */
+ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+ if (dw_pcie_link_up(pci)) {
+ dev_info(pci->dev, "Link up\n");
return 0;
+ }
+ udelay(LINK_WAIT_USLEEP_MAX);
}
- /* access only one slot on each root port */
- if (bus->number == pp->root_bus_nr && dev > 0)
- return 0;
+ dev_err(pci->dev, "Phy link never came up\n");
- /*
- * do not read more than one device on the bus directly attached
- * to RC's (Virtual Bridge's) DS side.
- */
- if (bus->primary == pp->root_bus_nr && dev > 0)
- return 0;
-
- return 1;
+ return -ETIMEDOUT;
}
-static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
- int size, u32 *val)
+int dw_pcie_link_up(struct dw_pcie *pci)
{
- struct pcie_port *pp = host_to_pcie(bus->host);
- int ret;
-
- *val = 0xffffffff;
-
- if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- data_abort_mask();
-
- if (bus->number != pp->root_bus_nr)
- if (pp->ops->rd_other_conf)
- ret = pp->ops->rd_other_conf(pp, bus, devfn,
- where, size, val);
- else
- ret = dw_pcie_rd_other_conf(pp, bus, devfn,
- where, size, val);
- else
- ret = dw_pcie_rd_own_conf(pp, where, size, val);
+ u32 val;
- if (data_abort_unmask())
- return PCIBIOS_DEVICE_NOT_FOUND;
+ if (pci->ops->link_up)
+ return pci->ops->link_up(pci);
- return ret;
+ val = readl(pci->dbi_base + PCIE_PHY_DEBUG_R1);
+ return ((val & PCIE_PHY_DEBUG_R1_LINK_UP) &&
+ !(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING));
}
-static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
- int where, int size, u32 val)
+void dw_pcie_setup(struct dw_pcie *pci)
{
- struct pcie_port *pp = host_to_pcie(bus->host);
int ret;
-
- if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- data_abort_mask();
-
- if (bus->number != pp->root_bus_nr)
- if (pp->ops->wr_other_conf)
- ret = pp->ops->wr_other_conf(pp, bus, devfn,
- where, size, val);
- else
- ret = dw_pcie_wr_other_conf(pp, bus, devfn,
- where, size, val);
- else
- ret = dw_pcie_wr_own_conf(pp, where, size, val);
-
- if (data_abort_unmask())
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- return ret;
-}
-
-static int dw_pcie_res_start(struct pci_bus *bus, resource_size_t res_addr)
-{
- return res_addr;
-}
-
-static struct pci_ops dw_pcie_ops = {
- .read = dw_pcie_rd_conf,
- .write = dw_pcie_wr_conf,
- .res_start = dw_pcie_res_start,
-};
-
-void dw_pcie_setup_rc(struct pcie_port *pp)
-{
u32 val;
- u32 membase;
- u32 memlimit;
+ u32 lanes;
+ struct device_d *dev = pci->dev;
+ struct device_node *np = dev->device_node;
+
+ ret = of_property_read_u32(np, "num-lanes", &lanes);
+ if (ret)
+ lanes = 0;
- /* set the number of lanes */
- dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
+ /* Set the number of lanes */
+ val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
val &= ~PORT_LINK_MODE_MASK;
- switch (pp->lanes) {
+ switch (lanes) {
case 1:
val |= PORT_LINK_MODE_1_LANES;
break;
@@ -509,13 +243,16 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
case 4:
val |= PORT_LINK_MODE_4_LANES;
break;
+ default:
+ dev_err(pci->dev, "num-lanes %u: invalid value\n", lanes);
+ return;
}
- dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
+ dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
- /* set link width speed control register */
- dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, &val);
+ /* Set link width speed control register */
+ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
- switch (pp->lanes) {
+ switch (lanes) {
case 1:
val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
break;
@@ -526,30 +263,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
break;
}
- dw_pcie_writel_rc(pp, val, PCIE_LINK_WIDTH_SPEED_CONTROL);
-
- /* setup RC BARs */
- dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
- dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
-
- /* setup bus numbers */
- dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
- val &= 0xff000000;
- val |= 0x00010100;
- dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
-
- /* setup memory base, memory limit */
- membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
- memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000;
- val = memlimit | membase;
- dw_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);
-
- /* setup command register */
- dw_pcie_readl_rc(pp, PCI_COMMAND, &val);
- val &= 0xffff0000;
- val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
- dw_pcie_writel_rc(pp, val, PCI_COMMAND);
+ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
}
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
diff --git a/drivers/pci/pcie-designware.h b/drivers/pci/pcie-designware.h
index 8d0330a5a1..058a0acbb2 100644
--- a/drivers/pci/pcie-designware.h
+++ b/drivers/pci/pcie-designware.h
@@ -1,23 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Synopsys Designware PCIe host controller driver
+ * Synopsys DesignWare PCIe host controller driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
- *
- * 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.
*/
#ifndef _PCIE_DESIGNWARE_H
#define _PCIE_DESIGNWARE_H
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_USLEEP_MAX 100000
+
+/* Parameters for the waiting for iATU enabled routine */
+#define LINK_WAIT_MAX_IATU_RETRIES 5
+#define LINK_WAIT_IATU_MAX 10000
+
+/* Synopsis specific PCIE configuration registers */
+#define PCIE_PORT_LINK_CONTROL 0x710
+#define PORT_LINK_MODE_MASK (0x3f << 16)
+#define PORT_LINK_MODE_1_LANES (0x1 << 16)
+#define PORT_LINK_MODE_2_LANES (0x3 << 16)
+#define PORT_LINK_MODE_4_LANES (0x7 << 16)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
+#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
+#define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
+
+#define PCIE_MSI_ADDR_LO 0x820
+#define PCIE_MSI_ADDR_HI 0x824
+#define PCIE_MSI_INTR0_ENABLE 0x828
+#define PCIE_MSI_INTR0_MASK 0x82C
+#define PCIE_MSI_INTR0_STATUS 0x830
+
+#define PCIE_ATU_VIEWPORT 0x900
+#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX2 (0x2 << 0)
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_CR1 0x904
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_CR2 0x908
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_LOWER_BASE 0x90C
+#define PCIE_ATU_UPPER_BASE 0x910
+#define PCIE_ATU_LIMIT 0x914
+#define PCIE_ATU_LOWER_TARGET 0x918
+#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
+#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
+#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
+#define PCIE_ATU_UPPER_TARGET 0x91C
+
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll
+ */
+#define PCIE_ATU_UNR_REGION_CTRL1 0x00
+#define PCIE_ATU_UNR_REGION_CTRL2 0x04
+#define PCIE_ATU_UNR_LOWER_BASE 0x08
+#define PCIE_ATU_UNR_UPPER_BASE 0x0C
+#define PCIE_ATU_UNR_LIMIT 0x10
+#define PCIE_ATU_UNR_LOWER_TARGET 0x14
+#define PCIE_ATU_UNR_UPPER_TARGET 0x18
+
+/* Register address builder */
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((0x3 << 20) | (region << 9))
+
+/* PCIe Port Logic registers */
+#define PLR_OFFSET 0x700
+#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
+#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4)
+#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
+
+#define PCIE_MISC_CONTROL_1_OFF 0x8BC
+#define PCIE_DBI_RO_WR_EN (0x1 << 0)
+
+/* PCIe Port Logic registers */
+#define PLR_OFFSET 0x700
+#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
+#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4)
+#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29)
+
+struct pcie_port;
+struct dw_pcie;
+
+struct dw_pcie_host_ops {
+ int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
+ int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+ int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val);
+ int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val);
+ int (*host_init)(struct pcie_port *pp);
+ void (*scan_bus)(struct pcie_port *pp);
+};
+
struct pcie_port {
- struct device_d *dev;
u8 root_bus_nr;
- void __iomem *dbi_base;
u64 cfg0_base;
u64 cfg0_mod_base;
void __iomem *va_cfg0_base;
@@ -39,33 +129,75 @@ struct pcie_port {
struct resource mem;
struct resource busn;
int irq;
- u32 lanes;
- struct pcie_host_ops *ops;
+ const struct dw_pcie_host_ops *ops;
struct pci_controller pci;
};
-struct pcie_host_ops {
- void (*readl_rc)(struct pcie_port *pp,
- void __iomem *dbi_base, u32 *val);
- void (*writel_rc)(struct pcie_port *pp,
- u32 val, void __iomem *dbi_base);
- int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
- int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
- int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 *val);
- int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 val);
- int (*link_up)(struct pcie_port *pp);
- void (*host_init)(struct pcie_port *pp);
- void (*scan_bus)(struct pcie_port *pp);
+struct dw_pcie_ops {
+ u32 (*readl_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
+ size_t size);
+ void (*writel_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
+ size_t size, u32 val);
+ int (*link_up)(struct dw_pcie *pcie);
+};
+
+struct dw_pcie {
+ struct device_d *dev;
+ void __iomem *dbi_base;
+ u32 num_viewport;
+ u8 iatu_unroll_enabled;
+ struct pcie_port pp;
+ const struct dw_pcie_ops *ops;
};
-int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val);
-irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
-void dw_pcie_msi_init(struct pcie_port *pp);
-int dw_pcie_link_up(struct pcie_port *pp);
+#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
+
+int dw_pcie_read(void __iomem *addr, int size, u32 *val);
+int dw_pcie_write(void __iomem *addr, int size, u32 val);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
+u32 __dw_pcie_readl_dbi(struct dw_pcie *pci, void __iomem *addr, u32 reg,
+ size_t size);
+void __dw_pcie_writel_dbi(struct dw_pcie *pci, void __iomem *addr, u32 reg,
+ size_t size, u32 val);
+int dw_pcie_link_up(struct dw_pcie *pci);
+int dw_pcie_wait_for_link(struct dw_pcie *pci);
+void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
+ int type, u64 cpu_addr, u64 pci_addr,
+ u32 size);
+void dw_pcie_setup(struct dw_pcie *pci);
+
+static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
+{
+ __dw_pcie_writel_dbi(pci, pci->dbi_base, reg, 0x4, val);
+}
+
+static inline u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg)
+{
+ return __dw_pcie_readl_dbi(pci, pci->dbi_base, reg, 0x4);
+}
+
+static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
+{
+ u32 reg;
+ u32 val;
+
+ reg = PCIE_MISC_CONTROL_1_OFF;
+ val = dw_pcie_readl_dbi(pci, reg);
+ val |= PCIE_DBI_RO_WR_EN;
+ dw_pcie_writel_dbi(pci, reg, val);
+}
+
+static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
+{
+ u32 reg;
+ u32 val;
+
+ reg = PCIE_MISC_CONTROL_1_OFF;
+ val = dw_pcie_readl_dbi(pci, reg);
+ val &= ~PCIE_DBI_RO_WR_EN;
+ dw_pcie_writel_dbi(pci, reg, val);
+}
+
#endif /* _PCIE_DESIGNWARE_H */
diff --git a/drivers/pinctrl/imx-iomux-v3.c b/drivers/pinctrl/imx-iomux-v3.c
index b2a67fcccc..5fadc84151 100644
--- a/drivers/pinctrl/imx-iomux-v3.c
+++ b/drivers/pinctrl/imx-iomux-v3.c
@@ -220,9 +220,6 @@ static struct imx_iomux_v3_data imx_iomux_imx7_lpsr_data = {
.flags = ZERO_OFFSET_VALID | IMX7_PINMUX_LPSR,
};
-static struct imx_iomux_v3_data imx_iomux_imx8_data = {
- .flags = SHARE_CONF,
-};
static __maybe_unused struct of_device_id imx_iomux_v3_dt_ids[] = {
{
@@ -250,7 +247,6 @@ static __maybe_unused struct of_device_id imx_iomux_v3_dt_ids[] = {
.data = &imx_iomux_imx7_lpsr_data,
}, {
.compatible = "fsl,imx8mq-iomuxc",
- .data = &imx_iomux_imx8_data,
}, {
/* sentinel */
}
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 4c4067d5b5..9b567e3cd2 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -148,7 +148,7 @@ static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
}
}
-int pl011_init_port (struct console_device *cdev)
+static int pl011_init_port(struct console_device *cdev)
{
struct amba_uart_port *uart = to_amba_uart_port(cdev);
@@ -185,7 +185,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
struct regulator *r;
r = regulator_get(&dev->dev, NULL);
- if (r) {
+ if (!IS_ERR(r)) {
int ret;
ret = regulator_enable(r);
diff --git a/drivers/serial/serial_clps711x.c b/drivers/serial/serial_clps711x.c
index fa6342346a..7a7d595dff 100644
--- a/drivers/serial/serial_clps711x.c
+++ b/drivers/serial/serial_clps711x.c
@@ -1,13 +1,5 @@
-/*
- * Simple CLPS711X serial driver
- *
- * (C) Copyright 2012-2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+/* Author: Alexander Shiyan <shc_work@mail.ru> */
#include <common.h>
#include <malloc.h>
@@ -54,7 +46,7 @@ static int clps711x_setbaudrate(struct console_device *cdev, int baudrate)
int divisor;
u32 tmp;
- divisor = (clk_get_rate(s->uart_clk) / 16) / baudrate;
+ divisor = DIV_ROUND_CLOSEST(clk_get_rate(s->uart_clk), baudrate * 16);
tmp = readl(s->base + UBRLCR) & ~UBRLCR_BAUD_MASK;
tmp |= divisor - 1;
@@ -132,6 +124,7 @@ static int clps711x_probe(struct device_d *dev)
struct clps711x_uart *s;
int err, id = dev->id;
char syscon_dev[8];
+ const char *devname;
if (dev->device_node)
id = of_alias_get_id(dev->device_node, "serial");
@@ -170,6 +163,14 @@ static int clps711x_probe(struct device_d *dev)
s->cdev.getc = clps711x_getc;
s->cdev.flush = clps711x_flush;
s->cdev.setbrg = clps711x_setbaudrate;
+ s->cdev.linux_console_name = "ttyCL";
+
+ devname = of_alias_get(dev->device_node);
+ if (devname) {
+ s->cdev.devname = xstrdup(devname);
+ s->cdev.devid = DEVICE_ID_SINGLE;
+ }
+
clps711x_init_port(&s->cdev);
err = console_register(&s->cdev);
@@ -182,7 +183,7 @@ out_err:
}
static struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
- { .compatible = "cirrus,clps711x-uart", },
+ { .compatible = "cirrus,ep7209-uart", },
};
static struct driver_d clps711x_driver = {
diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c
index 10621d00c8..46e8955abb 100644
--- a/drivers/spi/imx_spi.c
+++ b/drivers/spi/imx_spi.c
@@ -605,17 +605,20 @@ static int imx_spi_probe(struct device_d *dev)
master = &imx->master;
master->dev = dev;
- master->bus_num = dev->id;
master->setup = imx_spi_setup;
master->transfer = imx_spi_transfer;
if (pdata) {
+ master->bus_num = dev->id;
master->num_chipselect = pdata->num_chipselect;
imx->cs_array = pdata->chipselect;
- } else {
- if (IS_ENABLED(CONFIG_OFDEVICE))
- imx_spi_dt_probe(imx);
+ } else if (IS_ENABLED(CONFIG_OFDEVICE)) {
+ ret = of_alias_get_id(dev->device_node, "spi");
+ if (ret < 0)
+ goto err_free;
+ master->bus_num = ret;
+ imx_spi_dt_probe(imx);
}
imx->clk = clk_get(dev, NULL);
diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c
index d7bf92cdff..c2b3d481af 100644
--- a/drivers/usb/gadget/dfu.c
+++ b/drivers/usb/gadget/dfu.c
@@ -489,7 +489,6 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
value = handle_dnload(f, ctrl);
dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
return 0;
- break;
case USB_REQ_DFU_UPLOAD:
dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
debug("dfu: starting upload from %s\n", dfu_file_entry->filename);
@@ -505,7 +504,6 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
}
handle_upload(f, ctrl);
return 0;
- break;
case USB_REQ_DFU_ABORT:
dfu->dfu_status = DFU_STATUS_OK;
value = 0;
@@ -517,7 +515,6 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
default:
dfu->dfu_state = DFU_STATE_dfuERROR;
value = -EINVAL;
- goto out;
break;
}
break;
@@ -544,7 +541,6 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
case USB_REQ_DFU_UPLOAD:
handle_upload(f, ctrl);
return 0;
- break;
case USB_REQ_DFU_ABORT:
dfu_abort(dfu);
value = 0;
@@ -574,7 +570,6 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
case DFU_STATE_dfuMANIFEST:
dfu->dfu_state = DFU_STATE_dfuERROR;
value = -EINVAL;
- goto out;
break;
default:
break;
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index d61920e42d..bdf0c807df 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -80,6 +80,7 @@ struct f_fastboot {
const char *filename, const void *buf, size_t len);
int download_fd;
void *buf;
+ bool active;
size_t download_bytes;
size_t download_size;
@@ -182,15 +183,8 @@ static struct usb_gadget_strings *fastboot_strings[] = {
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
-static int in_req_complete;
-
static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
{
- int status = req->status;
-
- in_req_complete = 1;
-
- pr_debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
}
static struct usb_request *fastboot_alloc_request(struct usb_ep *ep)
@@ -404,7 +398,6 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
return ret;
}
f_fb->in_req->complete = fastboot_complete;
- f_fb->out_req->context = f_fb;
ret = usb_assign_descriptors(f, fb_fs_descs, fb_hs_descs, NULL);
if (ret)
@@ -434,6 +427,8 @@ static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
list_del(&var->list);
free(var);
}
+
+ f_fb->active = false;
}
static void fastboot_disable(struct usb_function *f)
@@ -486,13 +481,36 @@ err:
return ret;
}
+static struct f_fastboot *g_f_fb;
+
static void fastboot_free_func(struct usb_function *f)
{
struct f_fastboot *f_fb = container_of(f, struct f_fastboot, func);
+ if (g_f_fb == f_fb)
+ g_f_fb = NULL;
+
free(f_fb);
}
+/*
+ * A "oem exec bootm" or similar commands will stop barebox. Tell the
+ * fastboot command on the other side so that it doesn't run into a
+ * timeout.
+ */
+static void fastboot_shutdown(void)
+{
+ struct f_fastboot *f_fb = g_f_fb;
+
+ if (!f_fb || !f_fb->active)
+ return;
+
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "barebox shutting down");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
+}
+
+early_exitcall(fastboot_shutdown);
+
static struct usb_function *fastboot_alloc_func(struct usb_function_instance *fi)
{
struct f_fastboot *f_fb;
@@ -509,6 +527,9 @@ static struct usb_function *fastboot_alloc_func(struct usb_function_instance *fi
f_fb->func.unbind = fastboot_unbind;
f_fb->func.free_func = fastboot_free_func;
+ if (!g_f_fb)
+ g_f_fb = f_fb;
+
return &f_fb->func;
}
@@ -540,30 +561,62 @@ static int fastboot_tx_write(struct f_fastboot *f_fb, const char *buffer, unsign
memcpy(in_req->buf, buffer, buffer_size);
in_req->length = buffer_size;
- in_req_complete = 0;
+
ret = usb_ep_queue(f_fb->in_ep, in_req);
if (ret)
pr_err("Error %d on queue\n", ret);
start = get_time_ns();
- while (!in_req_complete) {
+ while (in_req->status == -EINPROGRESS) {
if (is_timeout(start, 2 * SECOND))
return -ETIMEDOUT;
usb_gadget_poll();
}
+ if (in_req->status)
+ pr_err("Failed to send answer: %d\n", in_req->status);
+
return 0;
}
-int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
+static char *fastboot_msg[] = {
+ [FASTBOOT_MSG_OKAY] = "OKAY",
+ [FASTBOOT_MSG_FAIL] = "FAIL",
+ [FASTBOOT_MSG_INFO] = "INFO",
+ [FASTBOOT_MSG_DATA] = "DATA",
+};
+
+int fastboot_tx_print(struct f_fastboot *f_fb, enum fastboot_msg_type type,
+ const char *fmt, ...)
{
+ struct va_format vaf;
char buf[64];
va_list ap;
int n;
+ const char *msg = fastboot_msg[type];
va_start(ap, fmt);
- n = vsnprintf(buf, 64, fmt, ap);
+ vaf.fmt = fmt;
+ vaf.va = &ap;
+
+ n = snprintf(buf, 64, "%s%pV", msg, &vaf);
+
+ switch (type) {
+ case FASTBOOT_MSG_OKAY:
+ f_fb->active = false;
+ break;
+ case FASTBOOT_MSG_FAIL:
+ f_fb->active = false;
+ pr_err("%pV\n", &vaf);
+ break;
+ case FASTBOOT_MSG_INFO:
+ pr_info("%pV\n", &vaf);
+ break;
+ case FASTBOOT_MSG_DATA:
+ break;
+ }
+
va_end(ap);
if (n > 64)
@@ -572,15 +625,9 @@ int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
return fastboot_tx_write(f_fb, buf, n);
}
-static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
-{
- restart_machine();
-}
-
static void cb_reboot(struct f_fastboot *f_fb, const char *cmd)
{
- f_fb->in_req->complete = compl_do_reset;
- fastboot_tx_print(f_fb, "OKAY");
+ restart_machine();
}
static int strcmp_l1(const char *s1, const char *s2)
@@ -598,20 +645,21 @@ static void cb_getvar(struct f_fastboot *f_fb, const char *cmd)
if (!strcmp_l1(cmd, "all")) {
list_for_each_entry(var, &f_fb->variables, list) {
- fastboot_tx_print(f_fb, "INFO%s: %s", var->name, var->value);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "%s: %s",
+ var->name, var->value);
}
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
return;
}
list_for_each_entry(var, &f_fb->variables, list) {
if (!strcmp(cmd, var->name)) {
- fastboot_tx_print(f_fb, "OKAY%s", var->value);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, var->value);
return;
}
}
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
}
static int rx_bytes_expected(struct f_fastboot *f_fb)
@@ -640,7 +688,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
} else {
ret = write(f_fb->download_fd, buffer, req->actual);
if (ret < 0) {
- fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret));
return;
}
}
@@ -657,12 +705,12 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
req->length = EP_BUFFER_SIZE;
close(f_fb->download_fd);
- fastboot_tx_print(f_fb, "INFODownloading %d bytes finished",
- f_fb->download_bytes);
+ printf("\n");
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Downloading %d bytes finished",
+ f_fb->download_bytes);
- printf("\n");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
}
req->actual = 0;
@@ -674,7 +722,8 @@ static void cb_download(struct f_fastboot *f_fb, const char *cmd)
f_fb->download_size = simple_strtoul(cmd, NULL, 16);
f_fb->download_bytes = 0;
- fastboot_tx_print(f_fb, "INFODownloading %d bytes...", f_fb->download_size);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Downloading %d bytes...",
+ f_fb->download_size);
init_progression_bar(f_fb->download_size);
@@ -682,28 +731,32 @@ static void cb_download(struct f_fastboot *f_fb, const char *cmd)
free(f_fb->buf);
f_fb->buf = malloc(f_fb->download_size);
if (!f_fb->buf) {
- fastboot_tx_print(f_fb, "FAILnot enough memory");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "not enough memory");
return;
}
} else {
f_fb->download_fd = open(FASTBOOT_TMPFILE, O_WRONLY | O_CREAT | O_TRUNC);
if (f_fb->download_fd < 0) {
- fastboot_tx_print(f_fb, "FAILInternal Error");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "internal error");
return;
}
}
if (!f_fb->download_size) {
- fastboot_tx_print(f_fb, "FAILdata invalid size");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "data invalid size");
} else {
struct usb_request *req = f_fb->out_req;
- fastboot_tx_print(f_fb, "DATA%08x", f_fb->download_size);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_DATA,
+ "%08x", f_fb->download_size);
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected(f_fb);
}
}
-static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+static void __maybe_unused cb_boot(struct f_fastboot *f_fb, const char *opt)
{
int ret;
struct bootm_data data = {
@@ -711,7 +764,7 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
.os_address = UIMAGE_SOME_ADDRESS,
};
- pr_info("Booting kernel..\n");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Booting kernel..\n");
globalvar_set_match("linux.bootargs.dyn.", "");
globalvar_set_match("bootm.", "");
@@ -719,14 +772,12 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
data.os_file = xstrdup(FASTBOOT_TMPFILE);
ret = bootm_boot(&data);
- if (ret)
- pr_err("Booting failed\n");
-}
-static void __maybe_unused cb_boot(struct f_fastboot *f_fb, const char *opt)
-{
- f_fb->in_req->complete = do_bootm_on_complete;
- fastboot_tx_print(f_fb, "OKAY");
+ if (ret)
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "Booting failed: %s",
+ strerror(-ret));
+ else
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
}
static struct mtd_info *get_mtd(struct f_fastboot *f_fb, const char *filename)
@@ -762,7 +813,8 @@ static int do_ubiformat(struct f_fastboot *f_fb, struct mtd_info *mtd,
args.novtbl = 1;
if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
- fastboot_tx_print(f_fb, "FAILubiformat is not available");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "ubiformat is not available");
return -ENODEV;
}
@@ -784,31 +836,37 @@ static int check_ubi(struct f_fastboot *f_fb, struct file_list_entry *fentry,
*/
if (!IS_ERR(mtd) && filetype == filetype_ubi &&
!(fentry->flags & FILE_LIST_FLAG_UBI)) {
- fastboot_tx_print(f_fb, "INFOwriting UBI image to MTD device, "
- "add the 'u' ");
- fastboot_tx_print(f_fb, "INFOflag to the partition description");
- return 0;
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO,
+ "writing UBI image to MTD device, "
+ "add the 'u' ");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO,
+ "flag to the partition description");
+ return 0;
}
if (!(fentry->flags & FILE_LIST_FLAG_UBI))
return 0;
if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
- fastboot_tx_print(f_fb, "FAILformat not available");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "ubiformat not available");
return -ENOSYS;
}
if (IS_ERR(mtd)) {
- fastboot_tx_print(f_fb, "FAILUBI flag given on non-MTD device");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "UBI flag given on non-MTD device");
return -EINVAL;
}
if (filetype == filetype_ubi) {
- fastboot_tx_print(f_fb, "INFOThis is an UBI image...");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO,
+ "This is an UBI image...");
return 1;
} else {
- fastboot_tx_print(f_fb, "FAILThis is no UBI image but %s",
- file_type_to_string(filetype));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "This is no UBI image but %s",
+ file_type_to_string(filetype));
return -EINVAL;
}
}
@@ -937,12 +995,14 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
filetype = file_name_detect_type(FASTBOOT_TMPFILE);
}
- fastboot_tx_print(f_fb, "INFOCopying file to %s...", cmd);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Copying file to %s...",
+ cmd);
fentry = file_list_entry_by_name(f_fb->files, cmd);
if (!fentry) {
- fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "No such partition: %s",
+ cmd);
ret = -ENOENT;
goto out;
}
@@ -957,20 +1017,18 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
filename = fentry->filename;
if (filetype == filetype_android_sparse) {
- if (!IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE)) {
- fastboot_tx_print(f_fb, "FAILsparse image not supported");
+ if (!IS_ENABLED(CONFIG_USB_GADGET_FASTBOOT_SPARSE) ||
+ fastboot_download_to_buf(f_fb)) {
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "sparse image not supported");
ret = -EOPNOTSUPP;
goto out;
}
- if (fastboot_download_to_buf(f_fb)) {
- fastboot_tx_print(f_fb, "FAILsparse image not supported");
- goto out;
- }
-
ret = fastboot_handle_sparse(f_fb, fentry);
if (ret)
- fastboot_tx_print(f_fb, "FAILwriting sparse image: %s",
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "writing sparse image: %s",
strerror(-ret));
goto out;
@@ -988,7 +1046,9 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
ret = do_ubiformat(f_fb, mtd, sourcefile, f_fb->buf,
f_fb->download_size);
if (ret) {
- fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "write partition: %s",
+ strerror(-ret));
goto out;
}
@@ -1006,7 +1066,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
if (!handler)
goto copy;
- fastboot_tx_print(f_fb, "INFOThis is a barebox image...");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO,
+ "This is a barebox image...");
if (fastboot_download_to_buf(f_fb)) {
data.len = f_fb->download_size;
@@ -1014,7 +1075,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
ret = read_file_2(sourcefile, &data.len, &f_fb->buf,
f_fb->download_size);
if (ret) {
- fastboot_tx_print(f_fb, "FAILreading barebox");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "reading barebox");
goto out;
}
}
@@ -1025,7 +1087,8 @@ static void cb_flash(struct f_fastboot *f_fb, const char *cmd)
ret = barebox_update(&data, handler);
if (ret)
- fastboot_tx_print(f_fb, "FAILupdate barebox: %s", strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "update barebox: %s", strerror(-ret));
goto out;
}
@@ -1037,11 +1100,12 @@ copy:
ret = copy_file(FASTBOOT_TMPFILE, filename, 1);
if (ret)
- fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "write partition: %s", strerror(-ret));
out:
if (!ret)
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
free(f_fb->buf);
f_fb->buf = NULL;
@@ -1057,7 +1121,7 @@ static void cb_erase(struct f_fastboot *f_fb, const char *cmd)
const char *filename = NULL;
int fd;
- fastboot_tx_print(f_fb, "INFOErasing %s...", cmd);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, "Erasing %s...", cmd);
file_list_for_each_entry(f_fb->files, fentry) {
if (!strcmp(cmd, fentry->name)) {
@@ -1067,23 +1131,25 @@ static void cb_erase(struct f_fastboot *f_fb, const char *cmd)
}
if (!filename) {
- fastboot_tx_print(f_fb, "FAILNo such partition: %s", cmd);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "No such partition: %s", cmd);
return;
}
fd = open(filename, O_RDWR);
if (fd < 0)
- fastboot_tx_print(f_fb, "FAIL%s", strerror(-fd));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-fd));
ret = erase(fd, ERASE_SIZE_ALL, 0);
close(fd);
if (ret)
- fastboot_tx_print(f_fb, "FAILcannot erase partition %s: %s",
- filename, strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "cannot erase partition %s: %s",
+ filename, strerror(-ret));
else
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
}
struct cmd_dispatch_info {
@@ -1109,7 +1175,8 @@ static void fb_run_command(struct f_fastboot *f_fb, const char *cmdbuf,
}
}
- fastboot_tx_print(f_fb, "FAILunknown command %s", cmdbuf);
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "unknown command %s",
+ cmdbuf);
}
static void cb_oem_getenv(struct f_fastboot *f_fb, const char *cmd)
@@ -1120,8 +1187,8 @@ static void cb_oem_getenv(struct f_fastboot *f_fb, const char *cmd)
value = getenv(cmd);
- fastboot_tx_print(f_fb, "INFO%s", value ? value : "");
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_INFO, value ? value : "");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
}
static void cb_oem_setenv(struct f_fastboot *f_fb, const char *cmd)
@@ -1144,12 +1211,12 @@ static void cb_oem_setenv(struct f_fastboot *f_fb, const char *cmd)
if (ret)
goto out;
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
out:
free(var);
if (ret)
- fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret));
}
static void cb_oem_exec(struct f_fastboot *f_fb, const char *cmd)
@@ -1157,17 +1224,18 @@ static void cb_oem_exec(struct f_fastboot *f_fb, const char *cmd)
int ret;
if (!IS_ENABLED(CONFIG_COMMAND_SUPPORT)) {
- fastboot_tx_print(f_fb, "FAILno command support available");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL,
+ "no command support available");
return;
}
ret = run_command(cmd);
if (ret < 0)
- fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret));
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, strerror(-ret));
else if (ret > 0)
- fastboot_tx_print(f_fb, "FAIL");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_FAIL, "");
else
- fastboot_tx_print(f_fb, "OKAY");
+ fastboot_tx_print(f_fb, FASTBOOT_MSG_OKAY, "");
}
static const struct cmd_dispatch_info cmd_oem_dispatch_info[] = {
@@ -1226,6 +1294,8 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
if (req->status != 0)
return;
+ f_fb->active = true;
+
*(cmdbuf + req->actual) = 0;
if (f_fb->cmd_exec) {
diff --git a/drivers/video/mtl017.c b/drivers/video/mtl017.c
index 085ea110ba..c04875cd07 100644
--- a/drivers/video/mtl017.c
+++ b/drivers/video/mtl017.c
@@ -244,6 +244,9 @@ static int mtl017_probe(struct device_d *dev)
mtl017->client = to_i2c_client(dev);
mtl017->regulator = regulator_get(dev, "vdd");
+ if (IS_ERR(mtl017->regulator))
+ mtl017->regulator = NULL;
+
mtl017->enable_gpio = of_get_named_gpio_flags(dev->device_node,
"enable-gpios", 0, &flags);
if (gpio_is_valid(mtl017->enable_gpio)) {
@@ -265,8 +268,8 @@ static int mtl017_probe(struct device_d *dev)
return 0;
}
-static struct driver_d twl_driver = {
+static struct driver_d mtl_driver = {
.name = "mtl017",
.probe = mtl017_probe,
};
-device_i2c_driver(twl_driver);
+device_i2c_driver(mtl_driver);
diff --git a/drivers/video/rave-sp-backlight.c b/drivers/video/rave-sp-backlight.c
index 3a20def661..877a5feeb6 100644
--- a/drivers/video/rave-sp-backlight.c
+++ b/drivers/video/rave-sp-backlight.c
@@ -47,7 +47,7 @@ static int rave_sp_backlight_probe(struct device_d *dev)
bd = xzalloc(sizeof(*bd));
bd->dev.priv = dev->parent->priv;
bd->dev.parent = dev;
- bd->brightness_default = 50;
+ bd->brightness = bd->brightness_cur = bd->brightness_default = 50;
bd->brightness_max = 100;
bd->brightness_set = rave_sp_backlight_set;
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 694ffa853e..f74046c0b7 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -456,7 +456,7 @@ int w1_driver_register(struct w1_driver *drv)
return register_driver(&drv->drv);
}
-void w1_found(struct w1_bus *bus, u64 rn)
+static void w1_found(struct w1_bus *bus, u64 rn)
{
struct w1_device *dev;
u64 tmp = be64_to_cpu(rn);