diff options
Diffstat (limited to 'drivers')
45 files changed, 3331 insertions, 155 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 01b659b02c..2636eed1a3 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -41,7 +41,7 @@ source "drivers/fpga/Kconfig" source "drivers/phy/Kconfig" source "drivers/crypto/Kconfig" source "drivers/memory/Kconfig" -source "drivers/soc/imx/Kconfig" +source "drivers/soc/Kconfig" source "drivers/nvme/Kconfig" source "drivers/ddr/Kconfig" source "drivers/power/Kconfig" diff --git a/drivers/base/driver.c b/drivers/base/driver.c index dd965eb165..f54f4d0b37 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -41,7 +41,8 @@ EXPORT_SYMBOL(device_list); LIST_HEAD(driver_list); EXPORT_SYMBOL(driver_list); -static LIST_HEAD(active); +LIST_HEAD(active_device_list); +EXPORT_SYMBOL(active_device_list); static LIST_HEAD(deferred); struct device_d *get_device_by_name(const char *name) @@ -91,7 +92,7 @@ int device_probe(struct device_d *dev) pinctrl_select_state_default(dev); of_clk_set_defaults(dev->device_node, false); - list_add(&dev->active, &active); + list_add(&dev->active, &active_device_list); ret = dev->bus->probe(dev); if (ret == 0) @@ -502,11 +503,15 @@ EXPORT_SYMBOL_GPL(dev_set_name); static void devices_shutdown(void) { struct device_d *dev; + int depth = 0; - list_for_each_entry(dev, &active, active) { + list_for_each_entry(dev, &active_device_list, active) { if (dev->bus->remove) { + depth++; + pr_report_probe("%*sremove-> %s\n", depth * 4, "", dev_name(dev)); dev->bus->remove(dev); dev->driver = NULL; + depth--; } } } diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 628ff407d9..e639fb3a1a 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -92,7 +92,7 @@ static int clk_generated_set_parent(struct clk_hw *hw, u8 index) { struct clk_generated *gck = to_clk_generated(hw); - if (index >= clk_get_num_parents(clk_hw_to_clk(hw))) + if (index >= clk_hw_get_num_parents(hw)) return -EINVAL; gck->parent_id = index; diff --git a/drivers/clk/clk-fixed.c b/drivers/clk/clk-fixed.c index b961c382ec..e813f31d76 100644 --- a/drivers/clk/clk-fixed.c +++ b/drivers/clk/clk-fixed.c @@ -45,6 +45,10 @@ struct clk *clk_register_fixed_rate(const char *name, if (!parent_names) return ERR_PTR(-ENOMEM); + parent_names[0] = strdup(parent_name); + if (!parent_names[0]) + return ERR_PTR(-ENOMEM); + fix->hw.clk.parent_names = parent_names; fix->hw.clk.num_parents = 1; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 189c9c62df..18373edbe4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -643,11 +643,9 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { struct of_clk_provider *provider; struct clk *clk = ERR_PTR(-EPROBE_DEFER); - int ret; - ret = of_device_ensure_probed(clkspec->np); - if (ret) - return ERR_PTR(ret); + /* Ignore error, as CLK_OF_DECLARE clocks have no proper driver. */ + of_device_ensure_probed(clkspec->np); /* Check if we have such a provider in our array */ list_for_each_entry(provider, &of_clk_providers, link) { @@ -845,15 +843,9 @@ int of_clk_init(struct device_node *root, const struct of_device_id *matches) struct device_node *np = clk_provider->np; if (force || parent_ready(np)) { - struct device_d *dev; of_pinctrl_select_state_default(np); - - dev = of_device_create_on_demand(np); - - if (clk_provider->clk_init_cb(np) == 0 && dev) - of_platform_device_dummy_drv(dev); - + clk_provider->clk_init_cb(np); of_clk_set_defaults(np, true); list_del(&clk_provider->node); diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index a2461d16c1..7adbaf266f 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -3,4 +3,5 @@ obj-y += clk-cpu.o clk-pll.o clk.o clk-muxgrf.o clk-mmc-phase.o clk-inverter.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-$(CONFIG_ARCH_RK3188) += clk-rk3188.o obj-$(CONFIG_ARCH_RK3288) += clk-rk3288.o +obj-$(CONFIG_ARCH_RK3399) += clk-rk3399.o obj-$(CONFIG_ARCH_RK3568) += clk-rk3568.o diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c new file mode 100644 index 0000000000..399d6006c6 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -0,0 +1,1653 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Xing Zheng <zhengxing@rock-chips.com> + */ + +#include <common.h> +#include <linux/clk.h> +#include <of.h> +#include <of_address.h> +#include <linux/barebox-wrapper.h> +#include <init.h> +#include <linux/spinlock.h> +#include <of_device.h> +#include <dt-bindings/clock/rk3399-cru.h> +#include "clk.h" + +enum rk3399_plls { + lpll, bpll, dpll, cpll, gpll, npll, vpll, +}; + +enum rk3399_pmu_plls { + ppll, +}; + +static struct rockchip_pll_rate_table rk3399_pll_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0), + RK3036_PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0), + RK3036_PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0), + RK3036_PLL_RATE(2136000000, 1, 89, 1, 1, 1, 0), + RK3036_PLL_RATE(2112000000, 1, 88, 1, 1, 1, 0), + RK3036_PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0), + RK3036_PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0), + RK3036_PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0), + RK3036_PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0), + RK3036_PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0), + RK3036_PLL_RATE(1968000000, 1, 82, 1, 1, 1, 0), + RK3036_PLL_RATE(1944000000, 1, 81, 1, 1, 1, 0), + RK3036_PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0), + RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), + RK3036_PLL_RATE(1872000000, 1, 78, 1, 1, 1, 0), + RK3036_PLL_RATE(1848000000, 1, 77, 1, 1, 1, 0), + RK3036_PLL_RATE(1824000000, 1, 76, 1, 1, 1, 0), + RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), + RK3036_PLL_RATE(1776000000, 1, 74, 1, 1, 1, 0), + RK3036_PLL_RATE(1752000000, 1, 73, 1, 1, 1, 0), + RK3036_PLL_RATE(1728000000, 1, 72, 1, 1, 1, 0), + RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), + RK3036_PLL_RATE(1680000000, 1, 70, 1, 1, 1, 0), + RK3036_PLL_RATE(1656000000, 1, 69, 1, 1, 1, 0), + RK3036_PLL_RATE(1632000000, 1, 68, 1, 1, 1, 0), + RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + RK3036_PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0), + RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0), + RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0), + RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0), + RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), + RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0), + RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0), + RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0), + RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), + RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0), + RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0), + RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0), + RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0), + RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), + RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0), + RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0), + RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), + RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), + RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0), + RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), + RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0), + RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0), + RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0), + RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0), + RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0), + RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0), + RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0), + RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0), + RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0), + RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0), + RK3036_PLL_RATE( 800000000, 1, 100, 3, 1, 1, 0), + RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0), + RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0), + RK3036_PLL_RATE( 676000000, 3, 169, 2, 1, 1, 0), + RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0), + RK3036_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0), + RK3036_PLL_RATE( 533250000, 8, 711, 4, 1, 1, 0), + RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0), + RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0), + RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0), + RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0), + RK3036_PLL_RATE( 297000000, 1, 99, 4, 2, 1, 0), + RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE( 148500000, 1, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 106500000, 1, 71, 4, 4, 1, 0), + RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0), + RK3036_PLL_RATE( 74250000, 2, 99, 4, 4, 1, 0), + RK3036_PLL_RATE( 65000000, 1, 65, 6, 4, 1, 0), + RK3036_PLL_RATE( 54000000, 1, 54, 6, 4, 1, 0), + RK3036_PLL_RATE( 27000000, 1, 27, 6, 4, 1, 0), + { /* sentinel */ }, +}; + +/* CRU parents */ +PNAME(mux_pll_p) = { "xin24m", "xin32k" }; + +PNAME(mux_armclkl_p) = { "clk_core_l_lpll_src", + "clk_core_l_bpll_src", + "clk_core_l_dpll_src", + "clk_core_l_gpll_src" }; +PNAME(mux_armclkb_p) = { "clk_core_b_lpll_src", + "clk_core_b_bpll_src", + "clk_core_b_dpll_src", + "clk_core_b_gpll_src" }; +PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src", + "clk_ddrc_bpll_src", + "clk_ddrc_dpll_src", + "clk_ddrc_gpll_src" }; +PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", + "gpll_aclk_cci_src", + "npll_aclk_cci_src", + "vpll_aclk_cci_src" }; +PNAME(mux_cci_trace_p) = { "cpll_cci_trace", + "gpll_cci_trace" }; +PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", + "npll_cs"}; +PNAME(mux_aclk_perihp_p) = { "cpll_aclk_perihp_src", + "gpll_aclk_perihp_src" }; + +PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; +PNAME(mux_pll_src_cpll_gpll_ppll_p) = { "cpll", "gpll", "ppll" }; +PNAME(mux_pll_src_cpll_gpll_upll_p) = { "cpll", "gpll", "upll" }; +PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_ppll_p) = { "cpll", "gpll", "npll", + "ppll" }; +PNAME(mux_pll_src_cpll_gpll_npll_24m_p) = { "cpll", "gpll", "npll", + "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_usbphy480m_p) = { "cpll", "gpll", "npll", + "clk_usbphy_480m" }; +PNAME(mux_pll_src_ppll_cpll_gpll_npll_p) = { "ppll", "cpll", "gpll", + "npll", "upll" }; +PNAME(mux_pll_src_cpll_gpll_npll_upll_24m_p) = { "cpll", "gpll", "npll", + "upll", "xin24m" }; +PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", + "ppll", "upll", "xin24m" }; + +PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" }; +PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", + "npll" }; +PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", + "xin24m" }; + +PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", + "dclk_vop0_frac" }; +PNAME(mux_dclk_vop1_p) = { "dclk_vop1_div", + "dclk_vop1_frac" }; + +PNAME(mux_clk_cif_p) = { "clk_cifout_src", "xin24m" }; + +PNAME(mux_pll_src_24m_usbphy480m_p) = { "xin24m", "clk_usbphy_480m" }; +PNAME(mux_pll_src_24m_pciephy_p) = { "xin24m", "clk_pciephy_ref100m" }; +PNAME(mux_pll_src_24m_32k_cpll_gpll_p) = { "xin24m", "xin32k", + "cpll", "gpll" }; +PNAME(mux_pciecore_cru_phy_p) = { "clk_pcie_core_cru", + "clk_pcie_core_phy" }; + +PNAME(mux_aclk_emmc_p) = { "cpll_aclk_emmc_src", + "gpll_aclk_emmc_src" }; + +PNAME(mux_aclk_perilp0_p) = { "cpll_aclk_perilp0_src", + "gpll_aclk_perilp0_src" }; + +PNAME(mux_fclk_cm0s_p) = { "cpll_fclk_cm0s_src", + "gpll_fclk_cm0s_src" }; + +PNAME(mux_hclk_perilp1_p) = { "cpll_hclk_perilp1_src", + "gpll_hclk_perilp1_src" }; + +PNAME(mux_clk_testout1_p) = { "clk_testout1_pll_src", "xin24m" }; +PNAME(mux_clk_testout2_p) = { "clk_testout2_pll_src", "xin24m" }; + +PNAME(mux_usbphy_480m_p) = { "clk_usbphy0_480m_src", + "clk_usbphy1_480m_src" }; +PNAME(mux_aclk_gmac_p) = { "cpll_aclk_gmac_src", + "gpll_aclk_gmac_src" }; +PNAME(mux_rmii_p) = { "clk_gmac", "clkin_gmac" }; +PNAME(mux_spdif_p) = { "clk_spdif_div", "clk_spdif_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s0_p) = { "clk_i2s0_div", "clk_i2s0_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s1_p) = { "clk_i2s1_div", "clk_i2s1_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2s2_p) = { "clk_i2s2_div", "clk_i2s2_frac", + "clkin_i2s", "xin12m" }; +PNAME(mux_i2sch_p) = { "clk_i2s0", "clk_i2s1", + "clk_i2s2" }; +PNAME(mux_i2sout_p) = { "clk_i2sout_src", "xin12m" }; + +PNAME(mux_uart0_p) = { "clk_uart0_div", "clk_uart0_frac", "xin24m" }; +PNAME(mux_uart1_p) = { "clk_uart1_div", "clk_uart1_frac", "xin24m" }; +PNAME(mux_uart2_p) = { "clk_uart2_div", "clk_uart2_frac", "xin24m" }; +PNAME(mux_uart3_p) = { "clk_uart3_div", "clk_uart3_frac", "xin24m" }; + +/* PMU CRU parents */ +PNAME(mux_ppll_24m_p) = { "ppll", "xin24m" }; +PNAME(mux_24m_ppll_p) = { "xin24m", "ppll" }; +PNAME(mux_fclk_cm0s_pmu_ppll_p) = { "fclk_cm0s_pmu_ppll_src", "xin24m" }; +PNAME(mux_wifi_pmu_p) = { "clk_wifi_div", "clk_wifi_frac" }; +PNAME(mux_uart4_pmu_p) = { "clk_uart4_div", "clk_uart4_frac", + "xin24m" }; +PNAME(mux_clk_testout2_2io_p) = { "clk_testout2", "clk_32k_suspend_pmu" }; + +static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = { + [lpll] = PLL(pll_rk3399, PLL_APLLL, "lpll", mux_pll_p, 0, RK3399_PLL_CON(0), + RK3399_PLL_CON(3), 8, 31, 0, rk3399_pll_rates), + [bpll] = PLL(pll_rk3399, PLL_APLLB, "bpll", mux_pll_p, 0, RK3399_PLL_CON(8), + RK3399_PLL_CON(11), 8, 31, 0, rk3399_pll_rates), + [dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RK3399_PLL_CON(16), + RK3399_PLL_CON(19), 8, 31, 0, NULL), + [cpll] = PLL(pll_rk3399, PLL_CPLL, "cpll", mux_pll_p, 0, RK3399_PLL_CON(24), + RK3399_PLL_CON(27), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RK3399_PLL_CON(32), + RK3399_PLL_CON(35), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [npll] = PLL(pll_rk3399, PLL_NPLL, "npll", mux_pll_p, 0, RK3399_PLL_CON(40), + RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll", mux_pll_p, 0, RK3399_PLL_CON(48), + RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), +}; + +static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = { + [ppll] = PLL(pll_rk3399, PLL_PPLL, "ppll", mux_pll_p, 0, RK3399_PMU_PLL_CON(0), + RK3399_PMU_PLL_CON(3), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) +#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK + +static struct rockchip_clk_branch rk3399_spdif_fracmux __initdata = + MUX(0, "clk_spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(32), 13, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_i2s0_fracmux __initdata = + MUX(0, "clk_i2s0_mux", mux_i2s0_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(28), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_i2s1_fracmux __initdata = + MUX(0, "clk_i2s1_mux", mux_i2s1_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(29), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_i2s2_fracmux __initdata = + MUX(0, "clk_i2s2_mux", mux_i2s2_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(30), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart0_fracmux __initdata = + MUX(SCLK_UART0, "clk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(33), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart1_fracmux __initdata = + MUX(SCLK_UART1, "clk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(34), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart2_fracmux __initdata = + MUX(SCLK_UART2, "clk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(35), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart3_fracmux __initdata = + MUX(SCLK_UART3, "clk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(36), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata = + MUX(SCLK_UART4_PMU, "clk_uart4_pmu", mux_uart4_pmu_p, CLK_SET_RATE_PARENT, + RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata = + MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(49), 11, 1, MFLAGS); + +static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata = + MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(50), 11, 1, MFLAGS); + +static struct rockchip_clk_branch rk3399_pmuclk_wifi_fracmux __initdata = + MUX(SCLK_WIFI_PMU, "clk_wifi_pmu", mux_wifi_pmu_p, CLK_SET_RATE_PARENT, + RK3399_PMU_CLKSEL_CON(1), 14, 1, MFLAGS); + +static const struct rockchip_cpuclk_reg_data rk3399_cpuclkl_data = { + .core_reg[0] = RK3399_CLKSEL_CON(0), + .div_core_shift[0] = 0, + .div_core_mask[0] = 0x1f, + .num_cores = 1, + .mux_core_alt = 3, + .mux_core_main = 0, + .mux_core_shift = 6, + .mux_core_mask = 0x3, +}; + +static const struct rockchip_cpuclk_reg_data rk3399_cpuclkb_data = { + .core_reg[0] = RK3399_CLKSEL_CON(2), + .div_core_shift[0] = 0, + .div_core_mask[0] = 0x1f, + .num_cores = 1, + .mux_core_alt = 3, + .mux_core_main = 1, + .mux_core_shift = 6, + .mux_core_mask = 0x3, +}; + +#define RK3399_DIV_ACLKM_MASK 0x1f +#define RK3399_DIV_ACLKM_SHIFT 8 +#define RK3399_DIV_ATCLK_MASK 0x1f +#define RK3399_DIV_ATCLK_SHIFT 0 +#define RK3399_DIV_PCLK_DBG_MASK 0x1f +#define RK3399_DIV_PCLK_DBG_SHIFT 8 + +#define RK3399_CLKSEL0(_offs, _aclkm) \ + { \ + .reg = RK3399_CLKSEL_CON(0 + _offs), \ + .val = HIWORD_UPDATE(_aclkm, RK3399_DIV_ACLKM_MASK, \ + RK3399_DIV_ACLKM_SHIFT), \ + } +#define RK3399_CLKSEL1(_offs, _atclk, _pdbg) \ + { \ + .reg = RK3399_CLKSEL_CON(1 + _offs), \ + .val = HIWORD_UPDATE(_atclk, RK3399_DIV_ATCLK_MASK, \ + RK3399_DIV_ATCLK_SHIFT) | \ + HIWORD_UPDATE(_pdbg, RK3399_DIV_PCLK_DBG_MASK, \ + RK3399_DIV_PCLK_DBG_SHIFT), \ + } + +/* cluster_l: aclkm in clksel0, rest in clksel1 */ +#define RK3399_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate##U, \ + .divs = { \ + RK3399_CLKSEL0(0, _aclkm), \ + RK3399_CLKSEL1(0, _atclk, _pdbg), \ + }, \ + } + +/* cluster_b: aclkm in clksel2, rest in clksel3 */ +#define RK3399_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate##U, \ + .divs = { \ + RK3399_CLKSEL0(2, _aclkm), \ + RK3399_CLKSEL1(2, _atclk, _pdbg), \ + }, \ + } + +static struct rockchip_cpuclk_rate_table rk3399_cpuclkl_rates[] __initdata = { + RK3399_CPUCLKL_RATE(1800000000, 1, 8, 8), + RK3399_CPUCLKL_RATE(1704000000, 1, 8, 8), + RK3399_CPUCLKL_RATE(1608000000, 1, 7, 7), + RK3399_CPUCLKL_RATE(1512000000, 1, 7, 7), + RK3399_CPUCLKL_RATE(1488000000, 1, 6, 6), + RK3399_CPUCLKL_RATE(1416000000, 1, 6, 6), + RK3399_CPUCLKL_RATE(1200000000, 1, 5, 5), + RK3399_CPUCLKL_RATE(1008000000, 1, 5, 5), + RK3399_CPUCLKL_RATE( 816000000, 1, 4, 4), + RK3399_CPUCLKL_RATE( 696000000, 1, 3, 3), + RK3399_CPUCLKL_RATE( 600000000, 1, 3, 3), + RK3399_CPUCLKL_RATE( 408000000, 1, 2, 2), + RK3399_CPUCLKL_RATE( 312000000, 1, 1, 1), + RK3399_CPUCLKL_RATE( 216000000, 1, 1, 1), + RK3399_CPUCLKL_RATE( 96000000, 1, 1, 1), +}; + +static struct rockchip_cpuclk_rate_table rk3399_cpuclkb_rates[] __initdata = { + RK3399_CPUCLKB_RATE(2208000000, 1, 11, 11), + RK3399_CPUCLKB_RATE(2184000000, 1, 11, 11), + RK3399_CPUCLKB_RATE(2088000000, 1, 10, 10), + RK3399_CPUCLKB_RATE(2040000000, 1, 10, 10), + RK3399_CPUCLKB_RATE(2016000000, 1, 9, 9), + RK3399_CPUCLKB_RATE(1992000000, 1, 9, 9), + RK3399_CPUCLKB_RATE(1896000000, 1, 9, 9), + RK3399_CPUCLKB_RATE(1800000000, 1, 8, 8), + RK3399_CPUCLKB_RATE(1704000000, 1, 8, 8), + RK3399_CPUCLKB_RATE(1608000000, 1, 7, 7), + RK3399_CPUCLKB_RATE(1512000000, 1, 7, 7), + RK3399_CPUCLKB_RATE(1488000000, 1, 6, 6), + RK3399_CPUCLKB_RATE(1416000000, 1, 6, 6), + RK3399_CPUCLKB_RATE(1200000000, 1, 5, 5), + RK3399_CPUCLKB_RATE(1008000000, 1, 5, 5), + RK3399_CPUCLKB_RATE( 816000000, 1, 4, 4), + RK3399_CPUCLKB_RATE( 696000000, 1, 3, 3), + RK3399_CPUCLKB_RATE( 600000000, 1, 3, 3), + RK3399_CPUCLKB_RATE( 408000000, 1, 2, 2), + RK3399_CPUCLKB_RATE( 312000000, 1, 1, 1), + RK3399_CPUCLKB_RATE( 216000000, 1, 1, 1), + RK3399_CPUCLKB_RATE( 96000000, 1, 1, 1), +}; + +static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { + /* + * CRU Clock-Architecture + */ + + /* usbphy */ + GATE(SCLK_USB2PHY0_REF, "clk_usb2phy0_ref", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 5, GFLAGS), + GATE(SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 6, GFLAGS), + + GATE(0, "clk_usbphy0_480m_src", "clk_usbphy0_480m", 0, + RK3399_CLKGATE_CON(13), 12, GFLAGS), + GATE(0, "clk_usbphy1_480m_src", "clk_usbphy1_480m", 0, + RK3399_CLKGATE_CON(13), 12, GFLAGS), + MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, 0, + RK3399_CLKSEL_CON(14), 6, 1, MFLAGS), + + MUX(0, "upll", mux_pll_src_24m_usbphy480m_p, 0, + RK3399_CLKSEL_CON(14), 15, 1, MFLAGS), + + COMPOSITE_NODIV(SCLK_HSICPHY, "clk_hsicphy", mux_pll_src_cpll_gpll_npll_usbphy480m_p, 0, + RK3399_CLKSEL_CON(19), 0, 2, MFLAGS, + RK3399_CLKGATE_CON(6), 4, GFLAGS), + + COMPOSITE(ACLK_USB3, "aclk_usb3", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 0, GFLAGS), + GATE(ACLK_USB3_NOC, "aclk_usb3_noc", "aclk_usb3", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(30), 0, GFLAGS), + GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_usb3", 0, + RK3399_CLKGATE_CON(30), 1, GFLAGS), + GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_usb3", 0, + RK3399_CLKGATE_CON(30), 2, GFLAGS), + GATE(ACLK_USB3_RKSOC_AXI_PERF, "aclk_usb3_rksoc_axi_perf", "aclk_usb3", 0, + RK3399_CLKGATE_CON(30), 3, GFLAGS), + GATE(ACLK_USB3_GRF, "aclk_usb3_grf", "aclk_usb3", 0, + RK3399_CLKGATE_CON(30), 4, GFLAGS), + + GATE(SCLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", 0, + RK3399_CLKGATE_CON(12), 1, GFLAGS), + GATE(SCLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", 0, + RK3399_CLKGATE_CON(12), 2, GFLAGS), + + COMPOSITE(SCLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", mux_pll_p, 0, + RK3399_CLKSEL_CON(40), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(12), 3, GFLAGS), + + COMPOSITE(SCLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", mux_pll_p, 0, + RK3399_CLKSEL_CON(41), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(12), 4, GFLAGS), + + COMPOSITE(SCLK_UPHY0_TCPDPHY_REF, "clk_uphy0_tcpdphy_ref", mux_pll_p, 0, + RK3399_CLKSEL_CON(64), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 4, GFLAGS), + + COMPOSITE(SCLK_UPHY0_TCPDCORE, "clk_uphy0_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(64), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 5, GFLAGS), + + COMPOSITE(SCLK_UPHY1_TCPDPHY_REF, "clk_uphy1_tcpdphy_ref", mux_pll_p, 0, + RK3399_CLKSEL_CON(65), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 6, GFLAGS), + + COMPOSITE(SCLK_UPHY1_TCPDCORE, "clk_uphy1_tcpdcore", mux_pll_src_24m_32k_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(65), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 7, GFLAGS), + + /* little core */ + GATE(0, "clk_core_l_lpll_src", "lpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 0, GFLAGS), + GATE(0, "clk_core_l_bpll_src", "bpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 1, GFLAGS), + GATE(0, "clk_core_l_dpll_src", "dpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 2, GFLAGS), + GATE(0, "clk_core_l_gpll_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(0), 3, GFLAGS), + + COMPOSITE_NOMUX(0, "aclkm_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(0), 4, GFLAGS), + COMPOSITE_NOMUX(0, "atclk_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(0), 5, GFLAGS), + COMPOSITE_NOMUX(PCLK_COREDBG_L, "pclk_dbg_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(0), 6, GFLAGS), + + GATE(ACLK_CORE_ADB400_CORE_L_2_CCI500, "aclk_core_adb400_core_l_2_cci500", "aclkm_core_l", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 12, GFLAGS), + GATE(ACLK_PERF_CORE_L, "aclk_perf_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 13, GFLAGS), + + GATE(0, "clk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 9, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_core_adb400_gic_2_core_l", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 10, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_core_adb400_core_l_2_gic", "armclkl", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 11, GFLAGS), + GATE(SCLK_PVTM_CORE_L, "clk_pvtm_core_l", "xin24m", 0, + RK3399_CLKGATE_CON(0), 7, GFLAGS), + + /* big core */ + GATE(0, "clk_core_b_lpll_src", "lpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 0, GFLAGS), + GATE(0, "clk_core_b_bpll_src", "bpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 1, GFLAGS), + GATE(0, "clk_core_b_dpll_src", "dpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 2, GFLAGS), + GATE(0, "clk_core_b_gpll_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(1), 3, GFLAGS), + + COMPOSITE_NOMUX(0, "aclkm_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(1), 4, GFLAGS), + COMPOSITE_NOMUX(0, "atclk_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(1), 5, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK3399_CLKGATE_CON(1), 6, GFLAGS), + + GATE(ACLK_CORE_ADB400_CORE_B_2_CCI500, "aclk_core_adb400_core_b_2_cci500", "aclkm_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 5, GFLAGS), + GATE(ACLK_PERF_CORE_B, "aclk_perf_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 6, GFLAGS), + + GATE(0, "clk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 1, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_core_adb400_gic_2_core_b", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 3, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_core_adb400_core_b_2_gic", "armclkb", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 4, GFLAGS), + + DIV(PCLK_COREDBG_B, "pclken_dbg_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(3), 13, 2, DFLAGS | CLK_DIVIDER_READ_ONLY), + + GATE(0, "pclk_dbg_cxcs_pd_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(14), 2, GFLAGS), + + GATE(SCLK_PVTM_CORE_B, "clk_pvtm_core_b", "xin24m", 0, + RK3399_CLKGATE_CON(1), 7, GFLAGS), + + /* gmac */ + GATE(0, "cpll_aclk_gmac_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 9, GFLAGS), + GATE(0, "gpll_aclk_gmac_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 8, GFLAGS), + COMPOSITE(0, "aclk_gmac_pre", mux_aclk_gmac_p, 0, + RK3399_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(6), 10, GFLAGS), + + GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", 0, + RK3399_CLKGATE_CON(32), 0, GFLAGS), + GATE(ACLK_GMAC_NOC, "aclk_gmac_noc", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 1, GFLAGS), + GATE(ACLK_PERF_GMAC, "aclk_perf_gmac", "aclk_gmac_pre", 0, + RK3399_CLKGATE_CON(32), 4, GFLAGS), + + COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre", 0, + RK3399_CLKSEL_CON(19), 8, 3, DFLAGS, + RK3399_CLKGATE_CON(6), 11, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", 0, + RK3399_CLKGATE_CON(32), 2, GFLAGS), + GATE(PCLK_GMAC_NOC, "pclk_gmac_noc", "pclk_gmac_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 3, GFLAGS), + + COMPOSITE(SCLK_MAC, "clk_gmac", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(20), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(5), 5, GFLAGS), + + MUX(SCLK_RMII_SRC, "clk_rmii_src", mux_rmii_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(19), 4, 1, MFLAGS), + GATE(SCLK_MACREF_OUT, "clk_mac_refout", "clk_rmii_src", 0, + RK3399_CLKGATE_CON(5), 6, GFLAGS), + GATE(SCLK_MACREF, "clk_mac_ref", "clk_rmii_src", 0, + RK3399_CLKGATE_CON(5), 7, GFLAGS), + GATE(SCLK_MAC_RX, "clk_rmii_rx", "clk_rmii_src", 0, + RK3399_CLKGATE_CON(5), 8, GFLAGS), + GATE(SCLK_MAC_TX, "clk_rmii_tx", "clk_rmii_src", 0, + RK3399_CLKGATE_CON(5), 9, GFLAGS), + + /* spdif */ + COMPOSITE(0, "clk_spdif_div", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 13, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", 0, + RK3399_CLKSEL_CON(99), 0, + RK3399_CLKGATE_CON(8), 14, GFLAGS, + &rk3399_spdif_fracmux), + GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 15, GFLAGS), + + COMPOSITE(SCLK_SPDIF_REC_DPTX, "clk_spdif_rec_dptx", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(32), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 6, GFLAGS), + /* i2s */ + COMPOSITE(0, "clk_i2s0_div", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(28), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 3, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", 0, + RK3399_CLKSEL_CON(96), 0, + RK3399_CLKGATE_CON(8), 4, GFLAGS, + &rk3399_i2s0_fracmux), + GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 5, GFLAGS), + + COMPOSITE(0, "clk_i2s1_div", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(29), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 6, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", 0, + RK3399_CLKSEL_CON(97), 0, + RK3399_CLKGATE_CON(8), 7, GFLAGS, + &rk3399_i2s1_fracmux), + GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 8, GFLAGS), + + COMPOSITE(0, "clk_i2s2_div", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(30), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(8), 9, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", 0, + RK3399_CLKSEL_CON(98), 0, + RK3399_CLKGATE_CON(8), 10, GFLAGS, + &rk3399_i2s2_fracmux), + GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT, + RK3399_CLKGATE_CON(8), 11, GFLAGS), + + MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(31), 0, 2, MFLAGS), + COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(31), 2, 1, MFLAGS, + RK3399_CLKGATE_CON(8), 12, GFLAGS), + + /* uart */ + MUX(0, "clk_uart0_src", mux_pll_src_cpll_gpll_upll_p, 0, + RK3399_CLKSEL_CON(33), 12, 2, MFLAGS), + COMPOSITE_NOMUX(0, "clk_uart0_div", "clk_uart0_src", 0, + RK3399_CLKSEL_CON(33), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 0, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", 0, + RK3399_CLKSEL_CON(100), 0, + RK3399_CLKGATE_CON(9), 1, GFLAGS, + &rk3399_uart0_fracmux), + + MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(33), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "clk_uart1_div", "clk_uart_src", 0, + RK3399_CLKSEL_CON(34), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 2, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", 0, + RK3399_CLKSEL_CON(101), 0, + RK3399_CLKGATE_CON(9), 3, GFLAGS, + &rk3399_uart1_fracmux), + + COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0, + RK3399_CLKSEL_CON(35), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 4, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", 0, + RK3399_CLKSEL_CON(102), 0, + RK3399_CLKGATE_CON(9), 5, GFLAGS, + &rk3399_uart2_fracmux), + + COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0, + RK3399_CLKSEL_CON(36), 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 6, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", 0, + RK3399_CLKSEL_CON(103), 0, + RK3399_CLKGATE_CON(9), 7, GFLAGS, + &rk3399_uart3_fracmux), + + COMPOSITE(PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(3), 4, GFLAGS), + + GATE(PCLK_CENTER_MAIN_NOC, "pclk_center_main_noc", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(18), 10, GFLAGS), + GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_ddr", 0, + RK3399_CLKGATE_CON(18), 12, GFLAGS), + GATE(PCLK_CIC, "pclk_cic", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(18), 15, GFLAGS), + GATE(PCLK_DDR_SGRF, "pclk_ddr_sgrf", "pclk_ddr", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(19), 2, GFLAGS), + + GATE(SCLK_PVTM_DDR, "clk_pvtm_ddr", "xin24m", 0, + RK3399_CLKGATE_CON(4), 11, GFLAGS), + GATE(SCLK_DFIMON0_TIMER, "clk_dfimon0_timer", "xin24m", 0, + RK3399_CLKGATE_CON(3), 5, GFLAGS), + GATE(SCLK_DFIMON1_TIMER, "clk_dfimon1_timer", "xin24m", 0, + RK3399_CLKGATE_CON(3), 6, GFLAGS), + + /* cci */ + GATE(0, "cpll_aclk_cci_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 0, GFLAGS), + GATE(0, "gpll_aclk_cci_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 1, GFLAGS), + GATE(0, "npll_aclk_cci_src", "npll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 2, GFLAGS), + GATE(0, "vpll_aclk_cci_src", "vpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 3, GFLAGS), + + COMPOSITE(0, "aclk_cci_pre", mux_aclk_cci_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(2), 4, GFLAGS), + + GATE(ACLK_ADB400M_PD_CORE_L, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 0, GFLAGS), + GATE(ACLK_ADB400M_PD_CORE_B, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 1, GFLAGS), + GATE(ACLK_CCI, "aclk_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 2, GFLAGS), + GATE(ACLK_CCI_NOC0, "aclk_cci_noc0", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 3, GFLAGS), + GATE(ACLK_CCI_NOC1, "aclk_cci_noc1", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 4, GFLAGS), + GATE(ACLK_CCI_GRF, "aclk_cci_grf", "aclk_cci_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 7, GFLAGS), + + GATE(0, "cpll_cci_trace", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 5, GFLAGS), + GATE(0, "gpll_cci_trace", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE(SCLK_CCI_TRACE, "clk_cci_trace", mux_cci_trace_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(5), 15, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(2), 7, GFLAGS), + + GATE(0, "cpll_cs", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 8, GFLAGS), + GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 9, GFLAGS), + GATE(0, "npll_cs", "npll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE_NOGATE(0, "clk_cs", mux_cs_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS), + GATE(0, "clk_dbg_cxcs", "clk_cs", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 5, GFLAGS), + GATE(0, "clk_dbg_noc", "clk_cs", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(15), 6, GFLAGS), + + /* vcodec */ + COMPOSITE(0, "aclk_vcodec_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(7), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 0, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vcodec_pre", "aclk_vcodec_pre", 0, + RK3399_CLKSEL_CON(7), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 1, GFLAGS), + GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, + RK3399_CLKGATE_CON(17), 2, GFLAGS), + GATE(0, "hclk_vcodec_noc", "hclk_vcodec_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 3, GFLAGS), + + GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0, + RK3399_CLKGATE_CON(17), 0, GFLAGS), + GATE(0, "aclk_vcodec_noc", "aclk_vcodec_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 1, GFLAGS), + + /* vdu */ + COMPOSITE(SCLK_VDU_CORE, "clk_vdu_core", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 4, GFLAGS), + COMPOSITE(SCLK_VDU_CA, "clk_vdu_ca", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(9), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 5, GFLAGS), + + COMPOSITE(0, "aclk_vdu_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(8), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 2, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vdu_pre", "aclk_vdu_pre", 0, + RK3399_CLKSEL_CON(8), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 3, GFLAGS), + GATE(HCLK_VDU, "hclk_vdu", "hclk_vdu_pre", 0, + RK3399_CLKGATE_CON(17), 10, GFLAGS), + GATE(HCLK_VDU_NOC, "hclk_vdu_noc", "hclk_vdu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 11, GFLAGS), + + GATE(ACLK_VDU, "aclk_vdu", "aclk_vdu_pre", 0, + RK3399_CLKGATE_CON(17), 8, GFLAGS), + GATE(ACLK_VDU_NOC, "aclk_vdu_noc", "aclk_vdu_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(17), 9, GFLAGS), + + /* iep */ + COMPOSITE(0, "aclk_iep_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(10), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 6, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_iep_pre", "aclk_iep_pre", 0, + RK3399_CLKSEL_CON(10), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 7, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_iep_pre", 0, + RK3399_CLKGATE_CON(16), 2, GFLAGS), + GATE(HCLK_IEP_NOC, "hclk_iep_noc", "hclk_iep_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 3, GFLAGS), + + GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0, + RK3399_CLKGATE_CON(16), 0, GFLAGS), + GATE(ACLK_IEP_NOC, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 1, GFLAGS), + + /* rga */ + COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 10, GFLAGS), + + COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_npll_ppll_p, 0, + RK3399_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 8, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_rga_pre", "aclk_rga_pre", 0, + RK3399_CLKSEL_CON(11), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(4), 9, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", 0, + RK3399_CLKGATE_CON(16), 10, GFLAGS), + GATE(HCLK_RGA_NOC, "hclk_rga_noc", "hclk_rga_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 11, GFLAGS), + + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, + RK3399_CLKGATE_CON(16), 8, GFLAGS), + GATE(ACLK_RGA_NOC, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(16), 9, GFLAGS), + + /* center */ + COMPOSITE(0, "aclk_center", mux_pll_src_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(3), 7, GFLAGS), + GATE(ACLK_CENTER_MAIN_NOC, "aclk_center_main_noc", "aclk_center", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(19), 0, GFLAGS), + GATE(ACLK_CENTER_PERI_NOC, "aclk_center_peri_noc", "aclk_center", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(19), 1, GFLAGS), + + /* gpu */ + COMPOSITE(0, "aclk_gpu_pre", mux_pll_src_ppll_cpll_gpll_npll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(13), 5, 3, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 0, GFLAGS), + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, + RK3399_CLKGATE_CON(30), 8, GFLAGS), + GATE(ACLK_PERF_GPU, "aclk_perf_gpu", "aclk_gpu_pre", 0, + RK3399_CLKGATE_CON(30), 10, GFLAGS), + GATE(ACLK_GPU_GRF, "aclk_gpu_grf", "aclk_gpu_pre", 0, + RK3399_CLKGATE_CON(30), 11, GFLAGS), + GATE(SCLK_PVTM_GPU, "aclk_pvtm_gpu", "xin24m", 0, + RK3399_CLKGATE_CON(13), 1, GFLAGS), + + /* perihp */ + GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 1, GFLAGS), + GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(5), 0, GFLAGS), + COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(5), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERIHP, "hclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 8, 2, DFLAGS, + RK3399_CLKGATE_CON(5), 3, GFLAGS), + COMPOSITE_NOMUX(PCLK_PERIHP, "pclk_perihp", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(14), 12, 2, DFLAGS, + RK3399_CLKGATE_CON(5), 4, GFLAGS), + + GATE(ACLK_PERF_PCIE, "aclk_perf_pcie", "aclk_perihp", 0, + RK3399_CLKGATE_CON(20), 2, GFLAGS), + GATE(ACLK_PCIE, "aclk_pcie", "aclk_perihp", 0, + RK3399_CLKGATE_CON(20), 10, GFLAGS), + GATE(0, "aclk_perihp_noc", "aclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 12, GFLAGS), + + GATE(HCLK_HOST0, "hclk_host0", "hclk_perihp", 0, + RK3399_CLKGATE_CON(20), 5, GFLAGS), + GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_perihp", 0, + RK3399_CLKGATE_CON(20), 6, GFLAGS), + GATE(HCLK_HOST1, "hclk_host1", "hclk_perihp", 0, + RK3399_CLKGATE_CON(20), 7, GFLAGS), + GATE(HCLK_HOST1_ARB, "hclk_host1_arb", "hclk_perihp", 0, + RK3399_CLKGATE_CON(20), 8, GFLAGS), + GATE(HCLK_HSIC, "hclk_hsic", "hclk_perihp", 0, + RK3399_CLKGATE_CON(20), 9, GFLAGS), + GATE(0, "hclk_perihp_noc", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 13, GFLAGS), + GATE(0, "hclk_ahb1tom", "hclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 15, GFLAGS), + + GATE(PCLK_PERIHP_GRF, "pclk_perihp_grf", "pclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 4, GFLAGS), + GATE(PCLK_PCIE, "pclk_pcie", "pclk_perihp", 0, + RK3399_CLKGATE_CON(20), 11, GFLAGS), + GATE(0, "pclk_perihp_noc", "pclk_perihp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(20), 14, GFLAGS), + GATE(PCLK_HSICPHY, "pclk_hsicphy", "pclk_perihp", 0, + RK3399_CLKGATE_CON(31), 8, GFLAGS), + + /* sdio & sdmmc */ + COMPOSITE(HCLK_SD, "hclk_sd", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(13), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 13, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sd", 0, + RK3399_CLKGATE_CON(33), 8, GFLAGS), + GATE(0, "hclk_sdmmc_noc", "hclk_sd", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(33), 9, GFLAGS), + + COMPOSITE(SCLK_SDIO, "clk_sdio", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0, + RK3399_CLKSEL_CON(15), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 0, GFLAGS), + + COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p, 0, + RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 1, GFLAGS), + + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", RK3399_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", RK3399_SDIO_CON0, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", RK3399_SDIO_CON1, 1), + + /* pcie */ + COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0, + RK3399_CLKSEL_CON(17), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 2, GFLAGS), + + COMPOSITE_NOMUX(SCLK_PCIEPHY_REF100M, "clk_pciephy_ref100m", "npll", 0, + RK3399_CLKSEL_CON(18), 11, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 6, GFLAGS), + MUX(SCLK_PCIEPHY_REF, "clk_pciephy_ref", mux_pll_src_24m_pciephy_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(18), 10, 1, MFLAGS), + + COMPOSITE(0, "clk_pcie_core_cru", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(18), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 3, GFLAGS), + MUX(SCLK_PCIE_CORE, "clk_pcie_core", mux_pciecore_cru_phy_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(18), 7, 1, MFLAGS), + + /* emmc */ + COMPOSITE(SCLK_EMMC, "clk_emmc", mux_pll_src_cpll_gpll_npll_upll_24m_p, 0, + RK3399_CLKSEL_CON(22), 8, 3, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(6), 14, GFLAGS), + + GATE(0, "cpll_aclk_emmc_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 13, GFLAGS), + GATE(0, "gpll_aclk_emmc_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(6), 12, GFLAGS), + COMPOSITE_NOGATE(ACLK_EMMC, "aclk_emmc", mux_aclk_emmc_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(21), 7, 1, MFLAGS, 0, 5, DFLAGS), + GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 8, GFLAGS), + GATE(ACLK_EMMC_NOC, "aclk_emmc_noc", "aclk_emmc", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 9, GFLAGS), + GATE(ACLK_EMMC_GRF, "aclk_emmcgrf", "aclk_emmc", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 10, GFLAGS), + + /* perilp0 */ + GATE(0, "cpll_aclk_perilp0_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(7), 1, GFLAGS), + GATE(0, "gpll_aclk_perilp0_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(7), 0, GFLAGS), + COMPOSITE(ACLK_PERILP0, "aclk_perilp0", mux_aclk_perilp0_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(23), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERILP0, "hclk_perilp0", "aclk_perilp0", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(23), 8, 2, DFLAGS, + RK3399_CLKGATE_CON(7), 3, GFLAGS), + COMPOSITE_NOMUX(PCLK_PERILP0, "pclk_perilp0", "aclk_perilp0", 0, + RK3399_CLKSEL_CON(23), 12, 3, DFLAGS, + RK3399_CLKGATE_CON(7), 4, GFLAGS), + + /* aclk_perilp0 gates */ + GATE(ACLK_INTMEM, "aclk_intmem", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 0, GFLAGS), + GATE(ACLK_TZMA, "aclk_tzma", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 1, GFLAGS), + GATE(SCLK_INTMEM0, "clk_intmem0", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 2, GFLAGS), + GATE(SCLK_INTMEM1, "clk_intmem1", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 3, GFLAGS), + GATE(SCLK_INTMEM2, "clk_intmem2", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 4, GFLAGS), + GATE(SCLK_INTMEM3, "clk_intmem3", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 5, GFLAGS), + GATE(SCLK_INTMEM4, "clk_intmem4", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 6, GFLAGS), + GATE(SCLK_INTMEM5, "clk_intmem5", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 7, GFLAGS), + GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", 0, RK3399_CLKGATE_CON(23), 8, GFLAGS), + GATE(ACLK_DMAC0_PERILP, "aclk_dmac0_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 5, GFLAGS), + GATE(ACLK_DMAC1_PERILP, "aclk_dmac1_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 6, GFLAGS), + GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 7, GFLAGS), + + /* hclk_perilp0 gates */ + GATE(HCLK_ROM, "hclk_rom", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(24), 4, GFLAGS), + GATE(HCLK_M_CRYPTO0, "hclk_m_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 5, GFLAGS), + GATE(HCLK_S_CRYPTO0, "hclk_s_crypto0", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 6, GFLAGS), + GATE(HCLK_M_CRYPTO1, "hclk_m_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 14, GFLAGS), + GATE(HCLK_S_CRYPTO1, "hclk_s_crypto1", "hclk_perilp0", 0, RK3399_CLKGATE_CON(24), 15, GFLAGS), + GATE(HCLK_PERILP0_NOC, "hclk_perilp0_noc", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 8, GFLAGS), + + /* pclk_perilp0 gates */ + GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", 0, RK3399_CLKGATE_CON(23), 9, GFLAGS), + + /* crypto */ + COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, 0, + RK3399_CLKSEL_CON(24), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 7, GFLAGS), + + COMPOSITE(SCLK_CRYPTO1, "clk_crypto1", mux_pll_src_cpll_gpll_ppll_p, 0, + RK3399_CLKSEL_CON(26), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 8, GFLAGS), + + /* cm0s_perilp */ + GATE(0, "cpll_fclk_cm0s_src", "cpll", 0, + RK3399_CLKGATE_CON(7), 6, GFLAGS), + GATE(0, "gpll_fclk_cm0s_src", "gpll", 0, + RK3399_CLKGATE_CON(7), 5, GFLAGS), + COMPOSITE(FCLK_CM0S, "fclk_cm0s", mux_fclk_cm0s_p, 0, + RK3399_CLKSEL_CON(24), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(7), 9, GFLAGS), + + /* fclk_cm0s gates */ + GATE(SCLK_M0_PERILP, "sclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 8, GFLAGS), + GATE(HCLK_M0_PERILP, "hclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 9, GFLAGS), + GATE(DCLK_M0_PERILP, "dclk_m0_perilp", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 10, GFLAGS), + GATE(SCLK_M0_PERILP_DEC, "clk_m0_perilp_dec", "fclk_cm0s", 0, RK3399_CLKGATE_CON(24), 11, GFLAGS), + GATE(HCLK_M0_PERILP_NOC, "hclk_m0_perilp_noc", "fclk_cm0s", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 11, GFLAGS), + + /* perilp1 */ + GATE(0, "cpll_hclk_perilp1_src", "cpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(8), 1, GFLAGS), + GATE(0, "gpll_hclk_perilp1_src", "gpll", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(8), 0, GFLAGS), + COMPOSITE_NOGATE(HCLK_PERILP1, "hclk_perilp1", mux_hclk_perilp1_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(25), 7, 1, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(PCLK_PERILP1, "pclk_perilp1", "hclk_perilp1", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(25), 8, 3, DFLAGS, + RK3399_CLKGATE_CON(8), 2, GFLAGS), + + /* hclk_perilp1 gates */ + GATE(0, "hclk_perilp1_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 9, GFLAGS), + GATE(0, "hclk_sdio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 12, GFLAGS), + GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 0, GFLAGS), + GATE(HCLK_I2S1_8CH, "hclk_i2s1", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 1, GFLAGS), + GATE(HCLK_I2S2_8CH, "hclk_i2s2", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 2, GFLAGS), + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 3, GFLAGS), + GATE(HCLK_SDIO, "hclk_sdio", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 4, GFLAGS), + GATE(PCLK_SPI5, "pclk_spi5", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 5, GFLAGS), + GATE(0, "hclk_sdioaudio_noc", "hclk_perilp1", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(34), 6, GFLAGS), + + /* pclk_perilp1 gates */ + GATE(PCLK_UART0, "pclk_uart0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 0, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 1, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 2, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 3, GFLAGS), + GATE(PCLK_I2C7, "pclk_rki2c7", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 5, GFLAGS), + GATE(PCLK_I2C1, "pclk_rki2c1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 6, GFLAGS), + GATE(PCLK_I2C5, "pclk_rki2c5", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 7, GFLAGS), + GATE(PCLK_I2C6, "pclk_rki2c6", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 8, GFLAGS), + GATE(PCLK_I2C2, "pclk_rki2c2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 9, GFLAGS), + GATE(PCLK_I2C3, "pclk_rki2c3", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 10, GFLAGS), + GATE(PCLK_MAILBOX0, "pclk_mailbox0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 11, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 12, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 13, GFLAGS), + GATE(PCLK_EFUSE1024NS, "pclk_efuse1024ns", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 14, GFLAGS), + GATE(PCLK_EFUSE1024S, "pclk_efuse1024s", "pclk_perilp1", 0, RK3399_CLKGATE_CON(22), 15, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 10, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 11, GFLAGS), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 12, GFLAGS), + GATE(PCLK_SPI4, "pclk_spi4", "pclk_perilp1", 0, RK3399_CLKGATE_CON(23), 13, GFLAGS), + GATE(PCLK_PERIHP_GRF, "pclk_perilp_sgrf", "pclk_perilp1", 0, RK3399_CLKGATE_CON(24), 13, GFLAGS), + GATE(0, "pclk_perilp1_noc", "pclk_perilp1", 0, RK3399_CLKGATE_CON(25), 10, GFLAGS), + + /* saradc */ + COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "xin24m", 0, + RK3399_CLKSEL_CON(26), 8, 8, DFLAGS, + RK3399_CLKGATE_CON(9), 11, GFLAGS), + + /* tsadc */ + COMPOSITE(SCLK_TSADC, "clk_tsadc", mux_pll_p, 0, + RK3399_CLKSEL_CON(27), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(9), 10, GFLAGS), + + /* cif_testout */ + MUX(0, "clk_testout1_pll_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(38), 6, 2, MFLAGS), + COMPOSITE(SCLK_TESTCLKOUT1, "clk_testout1", mux_clk_testout1_p, 0, + RK3399_CLKSEL_CON(38), 5, 1, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 14, GFLAGS), + + MUX(0, "clk_testout2_pll_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(38), 14, 2, MFLAGS), + COMPOSITE(SCLK_TESTCLKOUT2, "clk_testout2", mux_clk_testout2_p, 0, + RK3399_CLKSEL_CON(38), 13, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 15, GFLAGS), + + /* vio */ + COMPOSITE(ACLK_VIO, "aclk_vio", mux_pll_src_cpll_gpll_ppll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 0, GFLAGS), + COMPOSITE_NOMUX(PCLK_VIO, "pclk_vio", "aclk_vio", 0, + RK3399_CLKSEL_CON(43), 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 1, GFLAGS), + + GATE(ACLK_VIO_NOC, "aclk_vio_noc", "aclk_vio", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 0, GFLAGS), + + GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "pclk_vio", 0, + RK3399_CLKGATE_CON(29), 1, GFLAGS), + GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "pclk_vio", 0, + RK3399_CLKGATE_CON(29), 2, GFLAGS), + GATE(PCLK_VIO_GRF, "pclk_vio_grf", "pclk_vio", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 12, GFLAGS), + + /* hdcp */ + COMPOSITE(ACLK_HDCP, "aclk_hdcp", mux_pll_src_cpll_gpll_ppll_p, 0, + RK3399_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 12, GFLAGS), + COMPOSITE_NOMUX(HCLK_HDCP, "hclk_hdcp", "aclk_hdcp", 0, + RK3399_CLKSEL_CON(43), 5, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 3, GFLAGS), + COMPOSITE_NOMUX(PCLK_HDCP, "pclk_hdcp", "aclk_hdcp", 0, + RK3399_CLKSEL_CON(43), 10, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 10, GFLAGS), + + GATE(ACLK_HDCP_NOC, "aclk_hdcp_noc", "aclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 4, GFLAGS), + GATE(ACLK_HDCP22, "aclk_hdcp22", "aclk_hdcp", 0, + RK3399_CLKGATE_CON(29), 10, GFLAGS), + + GATE(HCLK_HDCP_NOC, "hclk_hdcp_noc", "hclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 5, GFLAGS), + GATE(HCLK_HDCP22, "hclk_hdcp22", "hclk_hdcp", 0, + RK3399_CLKGATE_CON(29), 9, GFLAGS), + + GATE(PCLK_HDCP_NOC, "pclk_hdcp_noc", "pclk_hdcp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(29), 3, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_hdcp", 0, + RK3399_CLKGATE_CON(29), 6, GFLAGS), + GATE(PCLK_DP_CTRL, "pclk_dp_ctrl", "pclk_hdcp", 0, + RK3399_CLKGATE_CON(29), 7, GFLAGS), + GATE(PCLK_HDCP22, "pclk_hdcp22", "pclk_hdcp", 0, + RK3399_CLKGATE_CON(29), 8, GFLAGS), + GATE(PCLK_GASKET, "pclk_gasket", "pclk_hdcp", 0, + RK3399_CLKGATE_CON(29), 11, GFLAGS), + + /* edp */ + COMPOSITE(SCLK_DP_CORE, "clk_dp_core", mux_pll_src_npll_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 8, GFLAGS), + + COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 6, DFLAGS, + RK3399_CLKGATE_CON(11), 11, GFLAGS), + GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(32), 12, GFLAGS), + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_edp", 0, + RK3399_CLKGATE_CON(32), 13, GFLAGS), + + /* hdmi */ + GATE(SCLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", 0, + RK3399_CLKGATE_CON(11), 6, GFLAGS), + + COMPOSITE(SCLK_HDMI_CEC, "clk_hdmi_cec", mux_pll_p, 0, + RK3399_CLKSEL_CON(45), 15, 1, MFLAGS, 0, 10, DFLAGS, + RK3399_CLKGATE_CON(11), 7, GFLAGS), + + /* vop0 */ + COMPOSITE(ACLK_VOP0_PRE, "aclk_vop0_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(47), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 8, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vop0_pre", "aclk_vop0_pre", 0, + RK3399_CLKSEL_CON(47), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 9, GFLAGS), + + GATE(ACLK_VOP0, "aclk_vop0", "aclk_vop0_pre", 0, + RK3399_CLKGATE_CON(28), 3, GFLAGS), + GATE(ACLK_VOP0_NOC, "aclk_vop0_noc", "aclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 1, GFLAGS), + + GATE(HCLK_VOP0, "hclk_vop0", "hclk_vop0_pre", 0, + RK3399_CLKGATE_CON(28), 2, GFLAGS), + GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 0, GFLAGS), + + COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 12, GFLAGS), + + COMPOSITE_FRACMUX_NOGATE(DCLK_VOP0_FRAC, "dclk_vop0_frac", "dclk_vop0_div", 0, + RK3399_CLKSEL_CON(106), 0, + &rk3399_dclk_vop0_fracmux), + + COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, 0, + RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 14, GFLAGS), + + /* vop1 */ + COMPOSITE(ACLK_VOP1_PRE, "aclk_vop1_pre", mux_pll_src_vpll_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(48), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 10, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vop1_pre", "aclk_vop1_pre", 0, + RK3399_CLKSEL_CON(48), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 11, GFLAGS), + + GATE(ACLK_VOP1, "aclk_vop1", "aclk_vop1_pre", 0, + RK3399_CLKGATE_CON(28), 7, GFLAGS), + GATE(ACLK_VOP1_NOC, "aclk_vop1_noc", "aclk_vop1_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 5, GFLAGS), + + GATE(HCLK_VOP1, "hclk_vop1", "hclk_vop1_pre", 0, + RK3399_CLKGATE_CON(28), 6, GFLAGS), + GATE(HCLK_VOP1_NOC, "hclk_vop1_noc", "hclk_vop1_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 4, GFLAGS), + + COMPOSITE(DCLK_VOP1_DIV, "dclk_vop1_div", mux_pll_src_vpll_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 13, GFLAGS), + + COMPOSITE_FRACMUX_NOGATE(DCLK_VOP1_FRAC, "dclk_vop1_frac", "dclk_vop1_div", 0, + RK3399_CLKSEL_CON(107), 0, + &rk3399_dclk_vop1_fracmux), + + COMPOSITE(SCLK_VOP1_PWM, "clk_vop1_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(10), 15, GFLAGS), + + /* isp */ + COMPOSITE(ACLK_ISP0, "aclk_isp0", mux_pll_src_cpll_gpll_ppll_p, 0, + RK3399_CLKSEL_CON(53), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 8, GFLAGS), + COMPOSITE_NOMUX(HCLK_ISP0, "hclk_isp0", "aclk_isp0", 0, + RK3399_CLKSEL_CON(53), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 9, GFLAGS), + + GATE(ACLK_ISP0_NOC, "aclk_isp0_noc", "aclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 1, GFLAGS), + GATE(ACLK_ISP0_WRAPPER, "aclk_isp0_wrapper", "aclk_isp0", 0, + RK3399_CLKGATE_CON(27), 5, GFLAGS), + GATE(HCLK_ISP1_WRAPPER, "hclk_isp1_wrapper", "aclk_isp0", 0, + RK3399_CLKGATE_CON(27), 7, GFLAGS), + + GATE(HCLK_ISP0_NOC, "hclk_isp0_noc", "hclk_isp0", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 0, GFLAGS), + GATE(HCLK_ISP0_WRAPPER, "hclk_isp0_wrapper", "hclk_isp0", 0, + RK3399_CLKGATE_CON(27), 4, GFLAGS), + + COMPOSITE(SCLK_ISP0, "clk_isp0", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 4, GFLAGS), + + COMPOSITE(ACLK_ISP1, "aclk_isp1", mux_pll_src_cpll_gpll_ppll_p, 0, + RK3399_CLKSEL_CON(54), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 10, GFLAGS), + COMPOSITE_NOMUX(HCLK_ISP1, "hclk_isp1", "aclk_isp1", 0, + RK3399_CLKSEL_CON(54), 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 11, GFLAGS), + + GATE(ACLK_ISP1_NOC, "aclk_isp1_noc", "aclk_isp1", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 3, GFLAGS), + + GATE(HCLK_ISP1_NOC, "hclk_isp1_noc", "hclk_isp1", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(27), 2, GFLAGS), + GATE(ACLK_ISP1_WRAPPER, "aclk_isp1_wrapper", "hclk_isp1", 0, + RK3399_CLKGATE_CON(27), 8, GFLAGS), + + COMPOSITE(SCLK_ISP1, "clk_isp1", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(55), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(11), 5, GFLAGS), + + /* + * We use pclkin_cifinv by default GRF_SOC_CON20[9] (GSC20_9) setting in system, + * so we ignore the mux and make clocks nodes as following, + * + * pclkin_cifinv --|-------\ + * |GSC20_9|-- pclkin_cifmux -- |G27_6| -- pclkin_isp1_wrapper + * pclkin_cif --|-------/ + */ + GATE(PCLK_ISP1_WRAPPER, "pclkin_isp1_wrapper", "pclkin_cif", 0, + RK3399_CLKGATE_CON(27), 6, GFLAGS), + + /* cif */ + COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, + RK3399_CLKGATE_CON(10), 7, GFLAGS), + + COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, 0, + RK3399_CLKSEL_CON(56), 5, 1, MFLAGS, 0, 5, DFLAGS), + + /* gic */ + COMPOSITE(ACLK_GIC_PRE, "aclk_gic_pre", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(56), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKGATE_CON(12), 12, GFLAGS), + + GATE(ACLK_GIC, "aclk_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 0, GFLAGS), + GATE(ACLK_GIC_NOC, "aclk_gic_noc", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 1, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_gic_adb400_core_l_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 2, GFLAGS), + GATE(ACLK_GIC_ADB400_CORE_B_2_GIC, "aclk_gic_adb400_core_b_2_gic", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 3, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_L, "aclk_gic_adb400_gic_2_core_l", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 4, GFLAGS), + GATE(ACLK_GIC_ADB400_GIC_2_CORE_B, "aclk_gic_adb400_gic_2_core_b", "aclk_gic_pre", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(33), 5, GFLAGS), + + /* alive */ + /* pclk_alive_gpll_src is controlled by PMUGRF_SOC_CON0[6] */ + DIV(PCLK_ALIVE, "pclk_alive", "gpll", 0, + RK3399_CLKSEL_CON(57), 0, 5, DFLAGS), + + GATE(PCLK_USBPHY_MUX_G, "pclk_usbphy_mux_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 4, GFLAGS), + GATE(PCLK_UPHY0_TCPHY_G, "pclk_uphy0_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 5, GFLAGS), + GATE(PCLK_UPHY0_TCPD_G, "pclk_uphy0_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 6, GFLAGS), + GATE(PCLK_UPHY1_TCPHY_G, "pclk_uphy1_tcphy_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 8, GFLAGS), + GATE(PCLK_UPHY1_TCPD_G, "pclk_uphy1_tcpd_g", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 9, GFLAGS), + + GATE(PCLK_GRF, "pclk_grf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 1, GFLAGS), + GATE(PCLK_INTR_ARB, "pclk_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 2, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 3, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 4, GFLAGS), + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 5, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 6, GFLAGS), + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_alive", 0, RK3399_CLKGATE_CON(31), 7, GFLAGS), + GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS), + + /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */ + SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_alive"), + + GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS), + GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS), + + GATE(SCLK_MIPIDPHY_CFG, "clk_mipidphy_cfg", "xin24m", 0, RK3399_CLKGATE_CON(11), 15, GFLAGS), + GATE(SCLK_DPHY_TX0_CFG, "clk_dphy_tx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 1, GFLAGS), + GATE(SCLK_DPHY_TX1RX1_CFG, "clk_dphy_tx1rx1_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 2, GFLAGS), + GATE(SCLK_DPHY_RX0_CFG, "clk_dphy_rx0_cfg", "clk_mipidphy_cfg", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 3, GFLAGS), + + /* testout */ + MUX(0, "clk_test_pre", mux_pll_src_cpll_gpll_p, CLK_SET_RATE_PARENT, + RK3399_CLKSEL_CON(58), 7, 1, MFLAGS), + COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", 0, + RK3399_CLKSEL_CON(105), 0, + RK3399_CLKGATE_CON(13), 9, GFLAGS), + + DIV(0, "clk_test_24m", "xin24m", 0, + RK3399_CLKSEL_CON(57), 6, 10, DFLAGS), + + /* spi */ + COMPOSITE(SCLK_SPI0, "clk_spi0", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(59), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 12, GFLAGS), + + COMPOSITE(SCLK_SPI1, "clk_spi1", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(59), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 13, GFLAGS), + + COMPOSITE(SCLK_SPI2, "clk_spi2", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(60), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 14, GFLAGS), + + COMPOSITE(SCLK_SPI4, "clk_spi4", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(60), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(9), 15, GFLAGS), + + COMPOSITE(SCLK_SPI5, "clk_spi5", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(58), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(13), 13, GFLAGS), + + /* i2c */ + COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(61), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 0, GFLAGS), + + COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(62), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 2, GFLAGS), + + COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(63), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 4, GFLAGS), + + COMPOSITE(SCLK_I2C5, "clk_i2c5", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(61), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 1, GFLAGS), + + COMPOSITE(SCLK_I2C6, "clk_i2c6", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(62), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 3, GFLAGS), + + COMPOSITE(SCLK_I2C7, "clk_i2c7", mux_pll_src_cpll_gpll_p, 0, + RK3399_CLKSEL_CON(63), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3399_CLKGATE_CON(10), 5, GFLAGS), + + /* timer */ + GATE(SCLK_TIMER00, "clk_timer00", "xin24m", 0, RK3399_CLKGATE_CON(26), 0, GFLAGS), + GATE(SCLK_TIMER01, "clk_timer01", "xin24m", 0, RK3399_CLKGATE_CON(26), 1, GFLAGS), + GATE(SCLK_TIMER02, "clk_timer02", "xin24m", 0, RK3399_CLKGATE_CON(26), 2, GFLAGS), + GATE(SCLK_TIMER03, "clk_timer03", "xin24m", 0, RK3399_CLKGATE_CON(26), 3, GFLAGS), + GATE(SCLK_TIMER04, "clk_timer04", "xin24m", 0, RK3399_CLKGATE_CON(26), 4, GFLAGS), + GATE(SCLK_TIMER05, "clk_timer05", "xin24m", 0, RK3399_CLKGATE_CON(26), 5, GFLAGS), + GATE(SCLK_TIMER06, "clk_timer06", "xin24m", 0, RK3399_CLKGATE_CON(26), 6, GFLAGS), + GATE(SCLK_TIMER07, "clk_timer07", "xin24m", 0, RK3399_CLKGATE_CON(26), 7, GFLAGS), + GATE(SCLK_TIMER08, "clk_timer08", "xin24m", 0, RK3399_CLKGATE_CON(26), 8, GFLAGS), + GATE(SCLK_TIMER09, "clk_timer09", "xin24m", 0, RK3399_CLKGATE_CON(26), 9, GFLAGS), + GATE(SCLK_TIMER10, "clk_timer10", "xin24m", 0, RK3399_CLKGATE_CON(26), 10, GFLAGS), + GATE(SCLK_TIMER11, "clk_timer11", "xin24m", 0, RK3399_CLKGATE_CON(26), 11, GFLAGS), + + /* clk_test */ + /* clk_test_pre is controlled by CRU_MISC_CON[3] */ + COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(58), 0, 5, DFLAGS, + RK3399_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", 0, RK3399_CLKGATE_CON(3), + 0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", 0, RK3399_CLKGATE_CON(3), + 1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", 0, RK3399_CLKGATE_CON(3), + 2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", 0, RK3399_CLKGATE_CON(3), + 3, GFLAGS), + COMPOSITE_DDRCLK(SCLK_DDRC, "sclk_ddrc", mux_ddrclk_p, 0, + RK3399_CLKSEL_CON(6), 4, 2, 0, 0, ROCKCHIP_DDRCLK_SIP), +}; + +static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { + /* + * PMU CRU Clock-Architecture + */ + + GATE(0, "fclk_cm0s_pmu_ppll_src", "ppll", 0, + RK3399_PMU_CLKGATE_CON(0), 1, GFLAGS), + + COMPOSITE_NOGATE(FCLK_CM0S_SRC_PMU, "fclk_cm0s_src_pmu", mux_fclk_cm0s_pmu_ppll_p, 0, + RK3399_PMU_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS), + + COMPOSITE(SCLK_SPI3_PMU, "clk_spi3_pmu", mux_24m_ppll_p, 0, + RK3399_PMU_CLKSEL_CON(1), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 2, GFLAGS), + + COMPOSITE(0, "clk_wifi_div", mux_ppll_24m_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(1), 13, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 8, GFLAGS), + + COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", 0, + RK3399_PMU_CLKSEL_CON(7), 0, + &rk3399_pmuclk_wifi_fracmux), + + MUX(0, "clk_timer_src_pmu", mux_pll_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(1), 15, 1, MFLAGS), + + COMPOSITE_NOMUX(SCLK_I2C0_PMU, "clk_i2c0_pmu", "ppll", 0, + RK3399_PMU_CLKSEL_CON(2), 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 9, GFLAGS), + + COMPOSITE_NOMUX(SCLK_I2C4_PMU, "clk_i2c4_pmu", "ppll", 0, + RK3399_PMU_CLKSEL_CON(3), 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 10, GFLAGS), + + COMPOSITE_NOMUX(SCLK_I2C8_PMU, "clk_i2c8_pmu", "ppll", 0, + RK3399_PMU_CLKSEL_CON(2), 8, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 11, GFLAGS), + + DIV(0, "clk_32k_suspend_pmu", "xin24m", CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(4), 0, 10, DFLAGS), + MUX(0, "clk_testout_2io", mux_clk_testout2_2io_p, CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(4), 15, 1, MFLAGS), + + COMPOSITE(0, "clk_uart4_div", mux_24m_ppll_p, 0, + RK3399_PMU_CLKSEL_CON(5), 10, 1, MFLAGS, 0, 7, DFLAGS, + RK3399_PMU_CLKGATE_CON(0), 5, GFLAGS), + + COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", 0, + RK3399_PMU_CLKSEL_CON(6), 0, + RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS, + &rk3399_uart4_pmu_fracmux), + + DIV(PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLK_IGNORE_UNUSED, + RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS), + + /* pmu clock gates */ + GATE(SCLK_TIMER12_PMU, "clk_timer0_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 3, GFLAGS), + GATE(SCLK_TIMER13_PMU, "clk_timer1_pmu", "clk_timer_src_pmu", 0, RK3399_PMU_CLKGATE_CON(0), 4, GFLAGS), + + GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(0), 7, GFLAGS), + + GATE(PCLK_PMU, "pclk_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 0, GFLAGS), + GATE(PCLK_PMUGRF_PMU, "pclk_pmugrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 1, GFLAGS), + GATE(PCLK_INTMEM1_PMU, "pclk_intmem1_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 2, GFLAGS), + GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 3, GFLAGS), + GATE(PCLK_GPIO1_PMU, "pclk_gpio1_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 4, GFLAGS), + GATE(PCLK_SGRF_PMU, "pclk_sgrf_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 5, GFLAGS), + GATE(PCLK_NOC_PMU, "pclk_noc_pmu", "pclk_pmu_src", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(1), 6, GFLAGS), + GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 7, GFLAGS), + GATE(PCLK_I2C4_PMU, "pclk_i2c4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 8, GFLAGS), + GATE(PCLK_I2C8_PMU, "pclk_i2c8_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 9, GFLAGS), + GATE(PCLK_RKPWM_PMU, "pclk_rkpwm_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 10, GFLAGS), + GATE(PCLK_SPI3_PMU, "pclk_spi3_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 11, GFLAGS), + GATE(PCLK_TIMER_PMU, "pclk_timer_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 12, GFLAGS), + GATE(PCLK_MAILBOX_PMU, "pclk_mailbox_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 13, GFLAGS), + GATE(PCLK_UART4_PMU, "pclk_uart4_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 14, GFLAGS), + GATE(PCLK_WDT_M0_PMU, "pclk_wdt_m0_pmu", "pclk_pmu_src", 0, RK3399_PMU_CLKGATE_CON(1), 15, GFLAGS), + + GATE(FCLK_CM0S_PMU, "fclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 0, GFLAGS), + GATE(SCLK_CM0S_PMU, "sclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 1, GFLAGS), + GATE(HCLK_CM0S_PMU, "hclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 2, GFLAGS), + GATE(DCLK_CM0S_PMU, "dclk_cm0s_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 3, GFLAGS), + GATE(HCLK_NOC_PMU, "hclk_noc_pmu", "fclk_cm0s_src_pmu", CLK_IGNORE_UNUSED, RK3399_PMU_CLKGATE_CON(2), 5, GFLAGS), +}; + +static const char *const rk3399_cru_critical_clocks[] __initconst = { + "aclk_cci_pre", + "aclk_gic", + "aclk_gic_noc", + "aclk_hdcp_noc", + "hclk_hdcp_noc", + "pclk_hdcp_noc", + "pclk_perilp0", + "pclk_perilp0", + "hclk_perilp0", + "hclk_perilp0_noc", + "pclk_perilp1", + "pclk_perilp1_noc", + "pclk_perihp", + "pclk_perihp_noc", + "hclk_perihp", + "aclk_perihp", + "aclk_perihp_noc", + "aclk_perilp0", + "aclk_perilp0_noc", + "hclk_perilp1", + "hclk_perilp1_noc", + "aclk_dmac0_perilp", + "aclk_emmc_noc", + "gpll_hclk_perilp1_src", + "gpll_aclk_perilp0_src", + "gpll_aclk_perihp_src", + "aclk_vio_noc", + + /* ddrc */ + "sclk_ddrc", + + "armclkl", + "armclkb", +}; + +static const char *const rk3399_pmucru_critical_clocks[] __initconst = { + "ppll", + "pclk_pmu_src", + "fclk_cm0s_src_pmu", + "clk_timer_src_pmu", + "pclk_rkpwm_pmu", +}; + +static void __init rk3399_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + return; + } + + rockchip_clk_register_plls(ctx, rk3399_pll_clks, + ARRAY_SIZE(rk3399_pll_clks), -1); + + rockchip_clk_register_branches(ctx, rk3399_clk_branches, + ARRAY_SIZE(rk3399_clk_branches)); + + rockchip_clk_register_armclk(ctx, ARMCLKL, "armclkl", + mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p), + &rk3399_cpuclkl_data, rk3399_cpuclkl_rates, + ARRAY_SIZE(rk3399_cpuclkl_rates)); + + rockchip_clk_register_armclk(ctx, ARMCLKB, "armclkb", + mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p), + &rk3399_cpuclkb_data, rk3399_cpuclkb_rates, + ARRAY_SIZE(rk3399_cpuclkb_rates)); + + rockchip_clk_protect_critical(rk3399_cru_critical_clocks, + ARRAY_SIZE(rk3399_cru_critical_clocks)); + + rockchip_register_softrst(np, 21, reg_base + RK3399_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(ctx, RK3399_GLB_SRST_FST); + + rockchip_clk_of_add_provider(np, ctx); +} + +static void __init rk3399_pmu_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru pmu region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLKPMU_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip pmu clk init failed\n", __func__); + return; + } + + rockchip_clk_register_plls(ctx, rk3399_pmu_pll_clks, + ARRAY_SIZE(rk3399_pmu_pll_clks), -1); + + rockchip_clk_register_branches(ctx, rk3399_clk_pmu_branches, + ARRAY_SIZE(rk3399_clk_pmu_branches)); + + rockchip_clk_protect_critical(rk3399_pmucru_critical_clocks, + ARRAY_SIZE(rk3399_pmucru_critical_clocks)); + + rockchip_register_softrst(np, 2, reg_base + RK3399_PMU_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_clk_of_add_provider(np, ctx); +} + +struct clk_rk3399_inits { + void (*inits)(struct device_node *np); +}; + +static const struct clk_rk3399_inits clk_rk3399_pmucru_init = { + .inits = rk3399_pmu_clk_init, +}; + +static const struct clk_rk3399_inits clk_rk3399_cru_init = { + .inits = rk3399_clk_init, +}; + +static const struct of_device_id clk_rk3399_match_table[] = { + { + .compatible = "rockchip,rk3399-cru", + .data = &clk_rk3399_cru_init, + }, { + .compatible = "rockchip,rk3399-pmucru", + .data = &clk_rk3399_pmucru_init, + }, + { } +}; + +static int __init clk_rk3399_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + const struct of_device_id *match; + const struct clk_rk3399_inits *init_data; + + match = of_match_device(clk_rk3399_match_table, dev); + if (!match || !match->data) + return -EINVAL; + + init_data = match->data; + if (init_data->inits) + init_data->inits(np); + + return 0; +} + +static struct driver_d clk_rk3399_driver = { + .probe = clk_rk3399_probe, + .name = "clk-rk3399", + .of_compatible = DRV_OF_COMPAT(clk_rk3399_match_table), +}; + +core_platform_driver(clk_rk3399_driver); diff --git a/drivers/clocksource/kvx_timer.c b/drivers/clocksource/kvx_timer.c index 4125ddbee0..2a05d8deed 100644 --- a/drivers/clocksource/kvx_timer.c +++ b/drivers/clocksource/kvx_timer.c @@ -55,4 +55,4 @@ static struct driver_d kvx_timer_driver = { .of_compatible = DRV_OF_COMPAT(kvx_timer_dt_ids), }; -device_platform_driver(kvx_timer_driver); +postcore_platform_driver(kvx_timer_driver); diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c index 39724ec2f4..f91d09e8ea 100644 --- a/drivers/efi/efi-device.c +++ b/drivers/efi/efi-device.c @@ -473,7 +473,12 @@ void efi_pause_devices(void) bus_for_each_device(&efi_bus, dev) { struct driver_d *drv = dev->driver; struct efi_device *efidev = to_efi_device(dev); - struct efi_driver *efidrv = to_efi_driver(drv); + struct efi_driver *efidrv; + + if (!drv) + continue; + + efidrv = to_efi_driver(drv); if (efidrv->dev_pause) efidrv->dev_pause(efidev); @@ -487,7 +492,12 @@ void efi_continue_devices(void) bus_for_each_device(&efi_bus, dev) { struct driver_d *drv = dev->driver; struct efi_device *efidev = to_efi_device(dev); - struct efi_driver *efidrv = to_efi_driver(drv); + struct efi_driver *efidrv; + + if (!drv) + continue; + + efidrv = to_efi_driver(drv); if (efidrv->dev_continue) efidrv->dev_continue(efidev); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c1e76a0409..a551df537a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -62,4 +62,12 @@ config I2C_STM32 depends on HAVE_CLK depends on ARCH_STM32MP || COMPILE_TEST +config I2C_RK3X + tristate "Rockchip RK3xxx I2C adapter" + depends on HAVE_CLK + depends on ARCH_ROCKCHIP || COMPILE_TEST + help + Say Y here to include support for the I2C adapter in Rockchip RK3xxx + SoCs. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 34a12fcbea..d6273f3d86 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o obj-$(CONFIG_I2C_STM32) += i2c-stm32.o +obj-$(CONFIG_I2C_RK3X) += i2c-rockchip.o diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c new file mode 100644 index 0000000000..4990735a4b --- /dev/null +++ b/drivers/i2c/busses/i2c-rockchip.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright 2015 Google, Inc + * + * (C) Copyright 2008-2014 Rockchip Electronics + * Peter, Software Engineering, <superpeter.cai@gmail.com>. + */ + +#include <common.h> +#include <i2c/i2c.h> +#include <linux/iopoll.h> +#include <errno.h> +#include <linux/err.h> +#include <driver.h> +#include <io.h> +#include <linux/clk.h> +#include <mfd/syscon.h> +#include <regmap.h> +#include <linux/sizes.h> + +struct i2c_regs { + u32 con; + u32 clkdiv; + u32 mrxaddr; + u32 mrxraddr; + u32 mtxcnt; + u32 mrxcnt; + u32 ien; + u32 ipd; + u32 fcnt; + u32 reserved0[0x37]; + u32 txdata[8]; + u32 reserved1[0x38]; + u32 rxdata[8]; +}; + +/* Control register */ +#define I2C_CON_EN (1 << 0) +#define I2C_CON_MOD(mod) ((mod) << 1) +#define I2C_MODE_TX 0x00 +#define I2C_MODE_TRX 0x01 +#define I2C_MODE_RX 0x02 +#define I2C_MODE_RRX 0x03 +#define I2C_CON_MASK (3 << 1) + +#define I2C_CON_START (1 << 3) +#define I2C_CON_STOP (1 << 4) +#define I2C_CON_LASTACK (1 << 5) +#define I2C_CON_ACTACK (1 << 6) + +/* Clock divider register */ +#define I2C_CLKDIV_VAL(divl, divh) \ + (((divl) & 0xffff) | (((divh) << 16) & 0xffff0000)) + +/* the slave address accessed for master rx mode */ +#define I2C_MRXADDR_SET(vld, addr) (((vld) << 24) | (addr)) + +/* the slave register address accessed for master rx mode */ +#define I2C_MRXRADDR_SET(vld, raddr) (((vld) << 24) | (raddr)) + +/* interrupt enable register */ +#define I2C_BTFIEN (1 << 0) +#define I2C_BRFIEN (1 << 1) +#define I2C_MBTFIEN (1 << 2) +#define I2C_MBRFIEN (1 << 3) +#define I2C_STARTIEN (1 << 4) +#define I2C_STOPIEN (1 << 5) +#define I2C_NAKRCVIEN (1 << 6) + +/* interrupt pending register */ +#define I2C_BTFIPD (1 << 0) +#define I2C_BRFIPD (1 << 1) +#define I2C_MBTFIPD (1 << 2) +#define I2C_MBRFIPD (1 << 3) +#define I2C_STARTIPD (1 << 4) +#define I2C_STOPIPD (1 << 5) +#define I2C_NAKRCVIPD (1 << 6) +#define I2C_IPD_ALL_CLEAN 0x7f + +/* i2c timeout */ +#define I2C_TIMEOUT_US (100 * USEC_PER_MSEC) + +/* rk i2c fifo max transfer bytes */ +#define RK_I2C_FIFO_SIZE 32 + +struct rk_i2c { + struct i2c_adapter adapter; + struct clk *clk; + struct i2c_regs *regs; + unsigned int speed; +}; + +static inline struct rk_i2c *to_rk_i2c(struct i2c_adapter *adapter) +{ + return container_of(adapter, struct rk_i2c, adapter); +} + +static inline void rk_i2c_get_div(int div, int *divh, int *divl) +{ + *divl = div / 2; + *divh = DIV_ROUND_UP(div, 2); +} + +/* + * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1) + * SCL = PCLK / SCLK Divisor + * i2c_rate = PCLK + */ +static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate) +{ + struct device_d *dev = i2c->adapter.dev.parent; + uint32_t i2c_rate; + int div, divl, divh; + + /* First get i2c rate from pclk */ + i2c_rate = clk_get_rate(i2c->clk); + + div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2; + divh = 0; + divl = 0; + if (div >= 0) + rk_i2c_get_div(div, &divh, &divl); + writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv); + + dev_dbg(dev, "rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate, + scl_rate); + dev_dbg(dev, "set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl); + dev_dbg(dev, "set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv)); +} + +static void rk_i2c_show_regs(struct rk_i2c *i2c) +{ + struct device_d *dev = &i2c->adapter.dev; + struct i2c_regs *regs = i2c->regs; + int i; + + dev_dbg(dev, "i2c_con: 0x%08x\n", readl(®s->con)); + dev_dbg(dev, "i2c_clkdiv: 0x%08x\n", readl(®s->clkdiv)); + dev_dbg(dev, "i2c_mrxaddr: 0x%08x\n", readl(®s->mrxaddr)); + dev_dbg(dev, "i2c_mrxraddR: 0x%08x\n", readl(®s->mrxraddr)); + dev_dbg(dev, "i2c_mtxcnt: 0x%08x\n", readl(®s->mtxcnt)); + dev_dbg(dev, "i2c_mrxcnt: 0x%08x\n", readl(®s->mrxcnt)); + dev_dbg(dev, "i2c_ien: 0x%08x\n", readl(®s->ien)); + dev_dbg(dev, "i2c_ipd: 0x%08x\n", readl(®s->ipd)); + dev_dbg(dev, "i2c_fcnt: 0x%08x\n", readl(®s->fcnt)); + + for (i = 0; i < 8; i++) + dev_dbg(dev, "i2c_txdata%d: 0x%08x\n", i, readl(®s->txdata[i])); + for (i = 0; i < 8; i++) + dev_dbg(dev, "i2c_rxdata%d: 0x%08x\n", i, readl(®s->rxdata[i])); +} + +static int rk_i2c_send_start_bit(struct rk_i2c *i2c) +{ + struct device_d *dev = &i2c->adapter.dev; + struct i2c_regs *regs = i2c->regs; + u32 val; + int err; + + dev_dbg(dev, "I2c Send Start bit.\n"); + writel(I2C_IPD_ALL_CLEAN, ®s->ipd); + + writel(I2C_CON_EN | I2C_CON_START, ®s->con); + writel(I2C_STARTIEN, ®s->ien); + + err = readl_poll_timeout(®s->ipd, val, val & I2C_STARTIPD, I2C_TIMEOUT_US); + if (err) { + dev_dbg(dev, "I2C Send Start Bit Timeout\n"); + rk_i2c_show_regs(i2c); + return err; + } + + writel(I2C_STARTIPD, ®s->ipd); + return 0; +} + +static int rk_i2c_send_stop_bit(struct rk_i2c *i2c) +{ + struct device_d *dev = &i2c->adapter.dev; + struct i2c_regs *regs = i2c->regs; + u32 val; + int err; + + dev_dbg(dev, "I2c Send Stop bit.\n"); + writel(I2C_IPD_ALL_CLEAN, ®s->ipd); + + writel(I2C_CON_EN | I2C_CON_STOP, ®s->con); + writel(I2C_CON_STOP, ®s->ien); + + err = readl_poll_timeout(®s->ipd, val, val & I2C_STOPIPD, I2C_TIMEOUT_US); + if (err) { + dev_dbg(dev, "I2C Send Start Bit Timeout\n"); + rk_i2c_show_regs(i2c); + return err; + } + + writel(I2C_STOPIPD, ®s->ipd); + return 0; +} + +static inline void rk_i2c_disable(struct rk_i2c *i2c) +{ + writel(0, &i2c->regs->con); +} + +static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, + uchar *buf, uint b_len) +{ + struct device_d *dev = &i2c->adapter.dev; + struct i2c_regs *regs = i2c->regs; + uchar *pbuf = buf; + uint bytes_remain_len = b_len; + uint bytes_xferred = 0; + uint words_xferred = 0; + uint con = 0; + uint rxdata; + uint i, j; + int err; + u32 val; + bool snd_chunk = false; + + dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n", + chip, reg, r_len, b_len); + + err = rk_i2c_send_start_bit(i2c); + if (err) + return err; + + writel(I2C_MRXADDR_SET(1, chip << 1 | 1), ®s->mrxaddr); + if (r_len == 0) { + writel(0, ®s->mrxraddr); + } else if (r_len < 4) { + writel(I2C_MRXRADDR_SET(r_len, reg), ®s->mrxraddr); + } else { + dev_dbg(dev, "I2C Read: addr len %d not supported\n", r_len); + return -EIO; + } + + while (bytes_remain_len) { + if (bytes_remain_len > RK_I2C_FIFO_SIZE) { + con = I2C_CON_EN; + bytes_xferred = RK_I2C_FIFO_SIZE; + } else { + /* + * The hw can read up to 32 bytes at a time. If we need + * more than one chunk, send an ACK after the last byte. + */ + con = I2C_CON_EN | I2C_CON_LASTACK; + bytes_xferred = bytes_remain_len; + } + words_xferred = DIV_ROUND_UP(bytes_xferred, 4); + + /* + * make sure we are in plain RX mode if we read a second chunk + */ + if (snd_chunk) + con |= I2C_CON_MOD(I2C_MODE_RX); + else + con |= I2C_CON_MOD(I2C_MODE_TRX); + + writel(con, ®s->con); + writel(bytes_xferred, ®s->mrxcnt); + writel(I2C_MBRFIEN | I2C_NAKRCVIEN, ®s->ien); + + err = readl_poll_timeout(®s->ipd, val, val & (I2C_NAKRCVIPD|I2C_MBRFIPD), I2C_TIMEOUT_US); + if (err) { + dev_dbg(dev, "I2C Read Data Timeout\n"); + goto i2c_exit; + } + + if (val & I2C_NAKRCVIPD) { + writel(I2C_NAKRCVIPD, ®s->ipd); + err = -EREMOTEIO; + goto i2c_exit; + } + + writel(I2C_MBRFIPD, ®s->ipd); + + for (i = 0; i < words_xferred; i++) { + rxdata = readl(®s->rxdata[i]); + dev_dbg(dev, "I2c Read RXDATA[%d] = 0x%x\n", i, rxdata); + for (j = 0; j < 4; j++) { + if ((i * 4 + j) == bytes_xferred) + break; + *pbuf++ = (rxdata >> (j * 8)) & 0xff; + } + } + + bytes_remain_len -= bytes_xferred; + snd_chunk = true; + dev_dbg(dev, "I2C Read bytes_remain_len %d\n", bytes_remain_len); + } + +i2c_exit: + if (err) + rk_i2c_show_regs(i2c); + rk_i2c_disable(i2c); + + return err; +} + +static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, + uchar *buf, uint b_len) +{ + struct device_d *dev = &i2c->adapter.dev; + struct i2c_regs *regs = i2c->regs; + u32 val; + int err; + uchar *pbuf = buf; + uint bytes_remain_len = b_len + r_len + 1; + uint bytes_xferred = 0; + uint words_xferred = 0; + uint txdata; + uint i, j; + + dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n", + chip, reg, r_len, b_len); + err = rk_i2c_send_start_bit(i2c); + if (err) + return err; + + while (bytes_remain_len) { + if (bytes_remain_len > RK_I2C_FIFO_SIZE) + bytes_xferred = RK_I2C_FIFO_SIZE; + else + bytes_xferred = bytes_remain_len; + words_xferred = DIV_ROUND_UP(bytes_xferred, 4); + + for (i = 0; i < words_xferred; i++) { + txdata = 0; + for (j = 0; j < 4; j++) { + if ((i * 4 + j) == bytes_xferred) + break; + + if (i == 0 && j == 0 && pbuf == buf) { + txdata |= (chip << 1); + } else if (i == 0 && j <= r_len && pbuf == buf) { + txdata |= (reg & + (0xff << ((j - 1) * 8))) << 8; + } else { + txdata |= (*pbuf++)<<(j * 8); + } + } + writel(txdata, ®s->txdata[i]); + dev_dbg(dev, "I2c Write TXDATA[%d] = 0x%08x\n", i, txdata); + } + + writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), ®s->con); + writel(bytes_xferred, ®s->mtxcnt); + writel(I2C_MBTFIEN | I2C_NAKRCVIEN, ®s->ien); + + err = readl_poll_timeout(®s->ipd, val, val & (I2C_NAKRCVIPD|I2C_MBTFIPD), I2C_TIMEOUT_US); + if (err) { + dev_dbg(dev, "I2C Write Data Timeout\n"); + goto i2c_exit; + } + + if (val & I2C_NAKRCVIPD) { + writel(I2C_NAKRCVIPD, ®s->ipd); + err = -EREMOTEIO; + goto i2c_exit; + } + + writel(I2C_MBTFIPD, ®s->ipd); + + bytes_remain_len -= bytes_xferred; + dev_dbg(dev, "I2C Write bytes_remain_len %d\n", bytes_remain_len); + } + +i2c_exit: + if (err) + rk_i2c_show_regs(i2c); + rk_i2c_disable(i2c); + + return err; +} + +static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, + int nmsgs) +{ + struct rk_i2c *i2c = to_rk_i2c(adapter); + struct device_d *dev = &adapter->dev; + int ret; + + dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs); + for (; nmsgs > 0; nmsgs--, msg++) { + dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); + if (msg->flags & I2C_M_RD) { + ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf, + msg->len); + } else { + ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf, + msg->len); + } + if (ret) { + dev_dbg(dev, "i2c_write: error sending: %pe\n", + ERR_PTR(ret)); + return -EREMOTEIO; + } + } + + rk_i2c_send_stop_bit(i2c); + rk_i2c_disable(i2c); + + return 0; +} + +static int rk_i2c_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct resource *iores; + struct rk_i2c *i2c; + unsigned bitrate; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + + i2c = kzalloc(sizeof(struct rk_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + dev->priv = i2c; + i2c->regs = IOMEM(iores->start); + + /* Only one clock to use for bus clock and peripheral clock */ + i2c->clk = clk_get(dev, NULL); + if (IS_ERR(i2c->clk)) + return dev_err_probe(dev, PTR_ERR(i2c->clk), "Can't get bus clk\n"); + + i2c->adapter.master_xfer = rockchip_i2c_xfer; + i2c->adapter.nr = dev->id; + i2c->adapter.dev.parent = dev; + i2c->adapter.dev.device_node = np; + + /* Set up clock divider */ + bitrate = 100000; + of_property_read_u32(np, "clock-frequency", &bitrate); + + rk_i2c_set_clk(i2c, bitrate); + + return i2c_add_numbered_adapter(&i2c->adapter); +} + +static const struct of_device_id rk_i2c_match[] = { + { .compatible = "rockchip,rv1108-i2c" }, + { .compatible = "rockchip,rk3228-i2c" }, + { .compatible = "rockchip,rk3288-i2c" }, + { .compatible = "rockchip,rk3399-i2c" }, + {}, +}; + +static struct driver_d rk_i2c_driver = { + .name = "rk3x-i2c", + .of_compatible = rk_i2c_match, + .probe = rk_i2c_probe, +}; +coredevice_platform_driver(rk_i2c_driver); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 5656914507..5ab0506cd9 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -37,12 +37,6 @@ config UBOOTVAR While it can be used standalone, it is best when coupled with corresponding filesystem driver. -config ACPI_TEST - bool "ACPI Test driver" - depends on ACPI - help - This is a simple Test driver to test the ACPI bus. - config STARFIVE_PWRSEQ bool "StarFive power sequencing driver" depends on SOC_STARFIVE diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 05da264a42..6326e784fc 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -8,5 +8,4 @@ obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_STATE_DRV) += state.o obj-$(CONFIG_DEV_MEM) += mem.o obj-$(CONFIG_UBOOTVAR) += ubootvar.o -obj-$(CONFIG_ACPI_TEST) += acpi-test.o obj-$(CONFIG_STARFIVE_PWRSEQ) += starfive-pwrseq.o diff --git a/drivers/misc/acpi-test.c b/drivers/misc/acpi-test.c deleted file mode 100644 index af20370fbc..0000000000 --- a/drivers/misc/acpi-test.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2019 Ahmad Fatoum - */ - -#include <common.h> -#include <init.h> -#include <acpi.h> - -static const char *profiles[] = { - "Unspecified", - "Desktop", - "Mobile", - "Workstation", - "Enterprise Server", - "SOHO Server", - "Applicance PC", - "Performance Server", - "Tablet", -}; - -static int acpi_test_probe(struct device_d *dev) -{ - const char *profile = "reserved"; - u8 *sdt; - u8 profileno; - - dev_dbg(dev, "driver initializing...\n"); - - sdt = (u8 __force *)dev_request_mem_region_by_name(dev, "SDT"); - if (IS_ERR(sdt)) { - dev_err(dev, "no SDT resource available: %pe\n", sdt); - return PTR_ERR(sdt); - } - - dev_dbg(dev, "SDT is at 0x%p\n", sdt); - - profileno = sdt[45]; - - if (profileno < ARRAY_SIZE(profiles)) - profile = profiles[profileno]; - - dev_info(dev, "PM profile is for '%s'\n", profile); - - return 0; -} - -static void acpi_test_remove(struct device_d *dev) -{ - dev_dbg(dev, "FADT driver removed\n"); -} - -static struct acpi_driver acpi_test_driver = { - .signature = "FACP", - .driver = { - .name = "acpi-test", - .probe = acpi_test_probe, - .remove = acpi_test_remove, - } -}; -device_acpi_driver(acpi_test_driver); diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 4a8f9e67d6..6725c7b9bd 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -592,7 +592,12 @@ static int cpsw_mdio_probe(struct device_d *dev) priv = xzalloc(sizeof(*priv)); + /* If we can't request I/O memory region, we'll assume parent did + * it for us + */ iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY) + iores = dev_get_resource(dev, IORESOURCE_MEM, 0); if (IS_ERR(iores)) return PTR_ERR(iores); priv->mdio_regs = IOMEM(iores->start); @@ -1214,11 +1219,27 @@ static void cpsw_gmii_sel_am335x(struct cpsw_slave *slave) writel(reg, phy_sel_addr); } -static int cpsw_probe_dt(struct cpsw_priv *priv) +static void cpsw_add_slave(struct cpsw_slave *slave, struct device_node *child, int i) +{ + uint32_t phy_id[2] = {-1, -1}; + int ret; + + if (!of_find_node_by_name(child, "fixed-link")) { + ret = of_property_read_u32_array(child, "phy_id", phy_id, 2); + if (!ret) + dev_warn(slave->cpsw->dev, "phy_id is deprecated, use phy-handle\n"); + } + + slave->dev.device_node = child; + slave->phy_id = phy_id[1]; + slave->phy_if = of_get_phy_mode(child); + slave->slave_num = i; +} + +static int cpsw_legacy_probe_dt(struct cpsw_priv *priv) { struct device_d *dev = priv->dev; struct device_node *np = dev->device_node, *child; - struct device_node *physel; int ret, i = 0; ret = of_property_read_u32(np, "slaves", &priv->num_slaves); @@ -1227,15 +1248,6 @@ static int cpsw_probe_dt(struct cpsw_priv *priv) priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves); - physel = of_find_compatible_node(NULL, NULL, "ti,am3352-phy-gmii-sel"); - if (!physel) { - dev_err(dev, "Cannot find ti,am3352-phy-gmii-sel node\n"); - return -EINVAL; - } - ret = cpsw_phy_sel_init(priv, physel); - if (ret) - return ret; - for_each_child_of_node(np, child) { if (of_device_is_compatible(child, "ti,davinci_mdio")) { ret = of_pinctrl_select_state_default(child); @@ -1244,29 +1256,73 @@ static int cpsw_probe_dt(struct cpsw_priv *priv) } if (i < priv->num_slaves && !strncmp(child->name, "slave", 5)) { - struct cpsw_slave *slave = &priv->slaves[i]; - uint32_t phy_id[2] = {-1, -1}; + cpsw_add_slave(&priv->slaves[i], child, i); + i++; + } + } - if (!of_find_node_by_name(child, "fixed-link")) { - ret = of_property_read_u32_array(child, "phy_id", phy_id, 2); - if (!ret) - dev_warn(dev, "phy_id is deprecated, use phy-handle\n"); - } + return 0; +} + +static int cpsw_switch_probe_dt(struct cpsw_priv *priv) +{ + struct device_d *dev = priv->dev; + struct device_node *np = dev->device_node, *child; + struct device_node *ports = NULL; + int ret, i = 0; - slave->dev.device_node = child; - slave->phy_id = phy_id[1]; - slave->phy_if = of_get_phy_mode(child); - slave->slave_num = i; + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, "ti,davinci_mdio")) { + ret = of_pinctrl_select_state_default(child); + if (ret) + return ret; + } - i++; + if (!strcmp(child->name, "ethernet-ports")) { + ports = child; + priv->num_slaves = of_get_available_child_count(ports); } } - for (i = 0; i < priv->num_slaves; i++) { - struct cpsw_slave *slave = &priv->slaves[i]; + if (!ports) + return -EINVAL; + + priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves); + + for_each_available_child_of_node(ports, child) { + cpsw_add_slave(&priv->slaves[i], child, i); + i++; + } + + return 0; +} - cpsw_gmii_sel_am335x(slave); +static int cpsw_probe_dt(struct cpsw_priv *priv) +{ + struct device_d *dev = priv->dev; + struct device_node *physel; + int (*probe_slaves_dt)(struct cpsw_priv *priv); + int ret, i = 0; + + physel = of_find_compatible_node(NULL, NULL, "ti,am3352-phy-gmii-sel"); + if (!physel) { + dev_err(dev, "Cannot find ti,am3352-phy-gmii-sel node\n"); + return -EINVAL; } + ret = cpsw_phy_sel_init(priv, physel); + if (ret) + return ret; + + probe_slaves_dt = device_get_match_data(dev); + if (!probe_slaves_dt) + return -EINVAL; + + ret = probe_slaves_dt(priv); + if (ret < 0) + return ret; + + for (i = 0; i < priv->num_slaves; i++) + cpsw_gmii_sel_am335x(&priv->slaves[i]); return 0; } @@ -1282,15 +1338,15 @@ static int cpsw_probe(struct device_d *dev) dev_dbg(dev, "* %s\n", __func__); - ret = of_platform_populate(dev->device_node, NULL, dev); - if (ret) - return ret; - iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) return PTR_ERR(iores); regs = IOMEM(iores->start); + ret = of_platform_populate(dev->device_node, NULL, dev); + if (ret) + return ret; + priv = xzalloc(sizeof(*priv)); priv->dev = dev; @@ -1371,7 +1427,9 @@ static void cpsw_remove(struct device_d *dev) static __maybe_unused struct of_device_id cpsw_dt_ids[] = { { - .compatible = "ti,cpsw", + .compatible = "ti,cpsw", .data = cpsw_legacy_probe_dt + }, { + .compatible = "ti,cpsw-switch", .data = cpsw_switch_probe_dt }, { /* sentinel */ } diff --git a/drivers/net/designware_rockchip.c b/drivers/net/designware_rockchip.c index a4ada147b5..da57ed1717 100644 --- a/drivers/net/designware_rockchip.c +++ b/drivers/net/designware_rockchip.c @@ -44,7 +44,6 @@ enum { CLK_MAC_PCLK, CLK_MAC_SPEED, CLK_PTP_REF, - CLK_XPCS_PCLK, }; static const struct clk_bulk_data rk_gmac_clks[] = { @@ -56,7 +55,6 @@ static const struct clk_bulk_data rk_gmac_clks[] = { [CLK_MAC_PCLK] = { .id = "pclk_mac" }, [CLK_MAC_SPEED] = { .id = "clk_mac_speed" }, [CLK_PTP_REF] = { .id = "ptp_ref" }, - [CLK_XPCS_PCLK] = { .id = "pclk_xpcs" }, }; static inline struct eqos_rk_gmac *to_rk_gmac(struct eqos *eqos) diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 7b1ebe1d68..2e60734156 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -76,6 +76,13 @@ config STM32_BSEC_WRITE mw -l -d /dev/stm32-bsec 0x000000e4+4 0x78563412 mw -l -d /dev/stm32-bsec 0x000000e8+4 0x0000bc9a +config KVX_OTP_NV + tristate "kalray KVX OTP Non volatile regs Support" + depends on KVX + help + This is a simple driver to dump specified values of KVX OTP non + volatile regs. + config STARFIVE_OTP tristate "Starfive OTP Supprot" depends on SOC_STARFIVE diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 5865919612..62a1f925dd 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -24,4 +24,7 @@ nvmem_eeprom_93xx46-y := eeprom_93xx46.o obj-$(CONFIG_STM32_BSEC) += nvmem_bsec.o nvmem_bsec-y := bsec.o +obj-$(CONFIG_KVX_OTP_NV) += nvmem-kvx-otp-nv.o +nvmem-kvx-otp-nv-y := kvx-otp-nv.o + obj-$(CONFIG_STARFIVE_OTP) += starfive-otp.o diff --git a/drivers/nvmem/kvx-otp-nv.c b/drivers/nvmem/kvx-otp-nv.c new file mode 100644 index 0000000000..d614c16e1e --- /dev/null +++ b/drivers/nvmem/kvx-otp-nv.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Kalray Inc., Clément Léger + */ + +#include <common.h> +#include <driver.h> +#include <malloc.h> +#include <xfuncs.h> +#include <errno.h> +#include <init.h> +#include <net.h> +#include <io.h> + +#include <linux/nvmem-provider.h> + +#define OTP_NV_ALIGN 4 +#define OTP_NV_ALIGN_MASK (OTP_NV_ALIGN - 1) + +struct kvx_otp_nv_priv { + void __iomem *base; +}; + +static int kvx_otp_nv_read(void *context, unsigned int offset, + void *_val, size_t bytes) +{ + struct kvx_otp_nv_priv *priv = context; + u8 *val = _val; + u32 tmp, copy_size; + u8 skip = offset & OTP_NV_ALIGN_MASK; + + offset &= ~OTP_NV_ALIGN_MASK; + + while (bytes) { + tmp = readl(priv->base + offset); + if (skip != 0) + copy_size = min(OTP_NV_ALIGN - skip, (int) bytes); + else + copy_size = min(bytes, sizeof(tmp)); + + memcpy(val, ((u8 *) &tmp) + skip, copy_size); + skip = 0; + + bytes -= copy_size; + val += copy_size; + offset += OTP_NV_ALIGN; + } + + return 0; +} + +static const struct nvmem_bus kvx_otp_nv_bus = { + .read = kvx_otp_nv_read, +}; + +static const struct of_device_id kvx_otp_nv_match[] = { + { .compatible = "kalray,kvx-otp-nv" }, + { /* sentinel */}, +}; + +static int kvx_otp_nv_probe(struct device_d *dev) +{ + struct resource *res; + struct nvmem_device *nvmem; + struct nvmem_config econfig = { 0 }; + struct kvx_otp_nv_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + priv->base = IOMEM(res->start); + + econfig.name = "kvx-nv-regbank"; + econfig.stride = 1; + econfig.word_size = 1; + econfig.size = resource_size(res); + econfig.dev = dev; + econfig.priv = priv; + econfig.bus = &kvx_otp_nv_bus; + + dev->priv = priv; + + nvmem = nvmem_register(&econfig); + + return PTR_ERR_OR_ZERO(nvmem); +} + +static struct driver_d kvx_otp_nv_driver = { + .name = "kvx-otp-nv", + .probe = kvx_otp_nv_probe, + .of_compatible = DRV_OF_COMPAT(kvx_otp_nv_match), +}; +postcore_platform_driver(kvx_otp_nv_driver); diff --git a/drivers/of/base.c b/drivers/of/base.c index 06e37b0fca..80465d6d50 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2285,6 +2285,8 @@ int of_property_sprintf(struct device_node *np, if (len < 0) return -ENOMEM; + len++; /* trailing NUL */ + pp = of_find_property(np, propname, NULL); of_delete_property(pp); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 14478e6e37..3a82809cb3 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -365,14 +365,11 @@ int of_platform_populate(struct device_node *root, } EXPORT_SYMBOL_GPL(of_platform_populate); -struct device_d *of_device_create_on_demand(struct device_node *np) +static struct device_d *of_device_create_on_demand(struct device_node *np) { struct device_node *parent; struct device_d *parent_dev, *dev; - if (!deep_probe_is_supported()) - return NULL; - parent = of_get_parent(np); if (!parent) return NULL; diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 5cf77c58b2..869cce1982 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -334,6 +334,8 @@ static int rockchip_gpio_probe(struct device_d *dev) int ret, bankno; bankno = of_alias_get_id(dev->device_node, "gpio"); + if (bankno >= ctrl->nr_banks) + bankno = -EINVAL; if (bankno < 0) return bankno; @@ -877,18 +879,24 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( struct rockchip_pin_bank *bank; char *name; int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j; + int gpio = 0; match = of_match_node(rockchip_pinctrl_dt_match, node); ctrl = (struct rockchip_pin_ctrl *)match->data; for_each_child_of_node(node, np) { + int id; + if (!of_find_property(np, "gpio-controller", NULL)) continue; + id = of_alias_get_id(np, "gpio"); + if (id < 0) + id = gpio++; + bank = ctrl->pin_banks; for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { - name = bank->name; - if (!strncmp(name, np->name, strlen(name))) { + if (bank->bank_num == id) { bank->of_node = np; if (!rockchip_get_bank_data(bank, dev)) bank->valid = true; diff --git a/drivers/pinctrl/pinctrl-stm32.c b/drivers/pinctrl/pinctrl-stm32.c index 9b5b04b6d6..ceaa4254c4 100644 --- a/drivers/pinctrl/pinctrl-stm32.c +++ b/drivers/pinctrl/pinctrl-stm32.c @@ -63,11 +63,11 @@ static inline u32 stm32_gpio_get_mode(u32 function) { switch (function) { case STM32_PIN_GPIO: - return 0; + return STM32_PINMODE_GPIO; case STM32_PIN_AF(0) ... STM32_PIN_AF(15): - return 2; + return STM32_PINMODE_AF; case STM32_PIN_ANALOG: - return 3; + return STM32_PINMODE_ANALOG; } return 0; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index e4151d8bc6..968d4b8ba4 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -54,3 +54,10 @@ config POWER_RESET_GPIO_RESTART This driver supports restarting your board via a GPIO line. If your board needs a GPIO high/low to restart, say Y and create a binding in your devicetree. + +config POWER_RESET_HTIF_POWEROFF + bool "HTIF poweroff driver" + depends on RISCV + help + Adds poweroff support via the syscall device on systems + supporting the UC Berkely Host/Target Interface (HTIF). diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 10d6f2a41e..c581382be8 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o +obj-$(CONFIG_POWER_RESET_HTIF_POWEROFF) += htif-poweroff.o diff --git a/drivers/power/reset/htif-poweroff.c b/drivers/power/reset/htif-poweroff.c new file mode 100644 index 0000000000..8df060d507 --- /dev/null +++ b/drivers/power/reset/htif-poweroff.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Ahmad Fatoum, Pengutronix + */ + +#include <common.h> +#include <driver.h> +#include <poweroff.h> +#include <asm/htif.h> + +static void __iomem *htif = IOMEM(HTIF_DEFAULT_BASE_ADDR); + +static void __noreturn riscvemu_poweroff(struct poweroff_handler *pwr) +{ + shutdown_barebox(); + + __htif_tohost(htif, HTIF_DEV_SYSCALL, 0, 1); + + __builtin_unreachable(); +} + +static int htif_poweroff_probe(struct device_d *dev) +{ + struct resource *iores; + + iores = dev_request_mem_resource(dev, 0); + if (!IS_ERR(iores)) + htif = IOMEM(iores->start); + else if (PTR_ERR(iores) != -ENOENT) + return PTR_ERR(iores); + + return poweroff_handler_register_fn(riscvemu_poweroff); +} + + +static const struct of_device_id htif_poweroff_of_match[] = { + { .compatible = "ucb,htif0" }, + {} +}; + +static struct driver_d htif_poweroff_driver = { + .name = "htif-poweroff", + .of_compatible = htif_poweroff_of_match, + .probe = htif_poweroff_probe, +}; +coredevice_platform_driver(htif_poweroff_driver); diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 7819d321d3..648f75fb72 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -256,7 +256,7 @@ static int atmel_pwm_probe(struct device_d *dev) if (IS_ERR(res)) return PTR_ERR(res); - atmel_pwm->base = IOMEM(res); + atmel_pwm->base = IOMEM(res->start); for (i = 0; i < PWM_CHANNELS; i++) { struct atmel_pwm_chip *chip = &atmel_pwm->atmel_pwm_chip[i]; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d1d3a36dfc..b2e5f8caa2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -71,6 +71,11 @@ static int regulator_disable_internal(struct regulator_internal *ri) if (!ri->enable_count) return -EINVAL; + if (ri->enable_count > 1) { + ri->enable_count--; + return 0; + } + if (!ri->rdev->desc->ops->disable) return -ENOSYS; @@ -125,7 +130,7 @@ static struct regulator_internal * __regulator_register(struct regulator_dev *rd if (name) ri->name = xstrdup(name); - if (rd->boot_on) { + if (rd->boot_on && rd->always_on) { ret = regulator_enable_internal(ri); if (ret && ret != -ENOSYS) goto err; @@ -158,6 +163,7 @@ int of_regulator_register(struct regulator_dev *rd, struct device_node *node) return -EINVAL; rd->boot_on = of_property_read_bool(node, "regulator-boot-on"); + rd->always_on = of_property_read_bool(node, "regulator-always-on"); name = of_get_property(node, "regulator-name", NULL); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 84c32c1dc8..db87aee1f3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -37,6 +37,12 @@ config RTC_DRV_DS1307 config RTC_DRV_ABRACON tristate "Abracon RTCs" +config RTC_DRV_PCF85363 + tristate "NXP PCF85363" + depends on I2C + help + If you say yes here you get support for the PCF85363 RTC chip. + endif # I2C config RTC_DRV_IMXDI diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 27ab43f91e..ec9775b691 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_RTC_DRV_ABRACON) += rtc-abracon.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o +obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c new file mode 100644 index 0000000000..7b785d6a77 --- /dev/null +++ b/drivers/rtc/rtc-pcf85363.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/rtc/rtc-pcf85363.c + * + * Driver for NXP PCF85363 real-time clock. + * + * Copyright (C) 2017 Eric Nelson + * + * This code is ported from linux-5.12 + * by Antony Pavlov <antonynpavlov@gmail.com> + */ + +#include <common.h> +#include <driver.h> +#include <xfuncs.h> +#include <malloc.h> +#include <errno.h> +#include <i2c/i2c.h> +#include <regmap.h> +#include <rtc.h> +#include <linux/rtc.h> +#include <linux/bcd.h> + +/* + * Date/Time registers + */ +#define DT_100THS 0x00 +#define DT_SECS 0x01 +#define DT_MINUTES 0x02 +#define DT_HOURS 0x03 +#define DT_DAYS 0x04 +#define DT_WEEKDAYS 0x05 +#define DT_MONTHS 0x06 +#define DT_YEARS 0x07 + +/* + * control registers + */ +#define CTRL_STOP_EN 0x2e + +#define STOP_EN_STOP BIT(0) + +#define RESET_CPR 0xa4 + +struct pcf85363 { + struct rtc_device rtc; + struct regmap *regmap; +}; + +static inline struct pcf85363 *to_pcf85363_priv(struct rtc_device *rtcdev) +{ + return container_of(rtcdev, struct pcf85363, rtc); +} + +static int pcf85363_rtc_read_time(struct rtc_device *rtcdev, + struct rtc_time *tm) +{ + struct device_d *dev = rtcdev->dev; + struct pcf85363 *pcf85363 = to_pcf85363_priv(rtcdev); + unsigned char buf[DT_YEARS + 1]; + int ret, len = sizeof(buf); + + /* read the RTC date and time registers all at once */ + ret = regmap_bulk_read(pcf85363->regmap, DT_100THS, buf, len); + if (ret) { + dev_err(dev, "%s: error %d\n", __func__, ret); + return ret; + } + + tm->tm_year = bcd2bin(buf[DT_YEARS]); + /* adjust for 1900 base of rtc_time */ + tm->tm_year += 100; + + tm->tm_wday = buf[DT_WEEKDAYS] & 7; + buf[DT_SECS] &= 0x7F; + tm->tm_sec = bcd2bin(buf[DT_SECS]); + buf[DT_MINUTES] &= 0x7F; + tm->tm_min = bcd2bin(buf[DT_MINUTES]); + tm->tm_hour = bcd2bin(buf[DT_HOURS]); + tm->tm_mday = bcd2bin(buf[DT_DAYS]); + tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1; + + return 0; +} + +static int pcf85363_rtc_set_time(struct rtc_device *rtcdev, struct rtc_time *tm) +{ + struct pcf85363 *pcf85363 = to_pcf85363_priv(rtcdev); + unsigned char tmp[11]; + unsigned char *buf = &tmp[2]; + int ret; + + tmp[0] = STOP_EN_STOP; + tmp[1] = RESET_CPR; + + buf[DT_100THS] = 0; + buf[DT_SECS] = bin2bcd(tm->tm_sec); + buf[DT_MINUTES] = bin2bcd(tm->tm_min); + buf[DT_HOURS] = bin2bcd(tm->tm_hour); + buf[DT_DAYS] = bin2bcd(tm->tm_mday); + buf[DT_WEEKDAYS] = tm->tm_wday; + buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1); + buf[DT_YEARS] = bin2bcd(tm->tm_year % 100); + + ret = regmap_bulk_write(pcf85363->regmap, CTRL_STOP_EN, + tmp, 2); + if (ret) + return ret; + + ret = regmap_bulk_write(pcf85363->regmap, DT_100THS, + buf, sizeof(tmp) - 2); + if (ret) + return ret; + + return regmap_write(pcf85363->regmap, CTRL_STOP_EN, 0); +} + +static const struct rtc_class_ops rtc_ops = { + .read_time = pcf85363_rtc_read_time, + .set_time = pcf85363_rtc_set_time, +}; + +static const struct regmap_config pcf85363_regmap_i2c_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x7f, +}; + +static int pcf85363_probe(struct device_d *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf85363 *pcf85363; + struct regmap *regmap; + int ret; + + regmap = regmap_init_i2c(client, + &pcf85363_regmap_i2c_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + pcf85363 = xzalloc(sizeof(struct pcf85363)); + + pcf85363->regmap = regmap; + + i2c_set_clientdata(client, pcf85363); + + pcf85363->rtc.ops = &rtc_ops; + pcf85363->rtc.dev = dev; + + ret = rtc_register(&pcf85363->rtc); + + return ret; +} + +static struct platform_device_id dev_ids[] = { + { .name = "pcf85363" }, + { /* sentinel */ } +}; + +static struct driver_d pcf85363_driver = { + .name = "pcf85363", + .probe = pcf85363_probe, + .id_table = dev_ids, +}; +device_i2c_driver(pcf85363_driver); + +MODULE_AUTHOR("Eric Nelson"); +MODULE_DESCRIPTION("pcf85363 I2C RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 3baadd54e7..345c58e274 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -54,6 +54,23 @@ to_amba_uart_port(struct console_device *uart) return container_of(uart, struct amba_uart_port, uart); } +static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr) +{ + struct vendor_data *vendor = uart->vendor; + + writew(lcr, uart->base + vendor->lcrh_rx); + if (vendor->lcrh_tx != vendor->lcrh_rx) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, uart->base + UART011_MIS); + writew(lcr, uart->base + vendor->lcrh_tx); + } +} + static int pl011_setbaudrate(struct console_device *cdev, int baudrate) { struct amba_uart_port *uart = to_amba_uart_port(cdev); @@ -61,6 +78,7 @@ static int pl011_setbaudrate(struct console_device *cdev, int baudrate) unsigned int divider; unsigned int remainder; unsigned int fraction; + uint32_t cr; /* ** Set baud rate @@ -74,9 +92,15 @@ static int pl011_setbaudrate(struct console_device *cdev, int baudrate) temp = (8 * remainder) / baudrate; fraction = (temp >> 1) + (temp & 1); + cr = readl(uart->base + UART011_CR); + writel(0x0, uart->base + UART011_CR); + writel(divider, uart->base + UART011_IBRD); writel(fraction, uart->base + UART011_FBRD); + pl011_rlcr(uart, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN); + writel(cr, uart->base + UART011_CR); + return 0; } @@ -118,23 +142,6 @@ static int pl011_tstc(struct console_device *cdev) return !(readl(uart->base + UART01x_FR) & UART01x_FR_RXFE); } -static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr) -{ - struct vendor_data *vendor = uart->vendor; - - writew(lcr, uart->base + vendor->lcrh_rx); - if (vendor->lcrh_tx != vendor->lcrh_rx) { - int i; - /* - * Wait 10 PCLKs before writing LCRH_TX register, - * to get this delay write read only register 10 times - */ - for (i = 0; i < 10; ++i) - writew(0xff, uart->base + UART011_MIS); - writew(lcr, uart->base + vendor->lcrh_tx); - } -} - static int pl011_init_port(struct console_device *cdev) { struct amba_uart_port *uart = to_amba_uart_port(cdev); diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig new file mode 100644 index 0000000000..54b69cc42e --- /dev/null +++ b/drivers/soc/Kconfig @@ -0,0 +1,6 @@ +menu "SoC drivers" + +source "drivers/soc/imx/Kconfig" +source "drivers/soc/kvx/Kconfig" + +endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index c4efb8f02f..e5b319e6da 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -3,3 +3,4 @@ obj-y += imx/ obj-$(CONFIG_CPU_SIFIVE) += sifive/ obj-$(CONFIG_SOC_STARFIVE) += starfive/ +obj-$(CONFIG_KVX) += kvx/ diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 565c86cb02..62cfc21519 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -429,7 +429,7 @@ static int imx_gpcv2_probe(struct device_d *dev) struct device_node *pgc_np, *np; struct resource *res; void __iomem *base; - int ret; + int ret, pass = 0; pgc_np = of_get_child_by_name(dev->device_node, "pgc"); if (!pgc_np) { @@ -445,10 +445,23 @@ static int imx_gpcv2_probe(struct device_d *dev) domain_data = of_device_get_match_data(dev); + /* + * Run two passes for the registration of the PGC domain platform + * devices: first all devices that are not part of a power-domain + * themselves, then all the others. This avoids -EPROBE_DEFER being + * returned for nested domains, that need their parent PGC domains + * to be present on probe. + */ +again: for_each_child_of_node(pgc_np, np) { - struct device_d *pd_dev; + bool child_domain = of_property_read_bool(np, "power-domains"); struct imx_pgc_domain *domain; + struct device_d *pd_dev; u32 domain_index; + + if ((pass == 0 && child_domain) || (pass == 1 && !child_domain)) + continue; + ret = of_property_read_u32(np, "reg", &domain_index); if (ret) { dev_err(dev, "Failed to read 'reg' property\n"); @@ -481,6 +494,11 @@ static int imx_gpcv2_probe(struct device_d *dev) return ret; } + if (pass == 0) { + pass++; + goto again; + } + return 0; } diff --git a/drivers/soc/kvx/Kconfig b/drivers/soc/kvx/Kconfig new file mode 100644 index 0000000000..18dcb8ba14 --- /dev/null +++ b/drivers/soc/kvx/Kconfig @@ -0,0 +1,10 @@ +menu "KVX SoC drivers" + +config KVX_SOCINFO + bool "KVX SoC Info driver" + depends on KVX + select NVMEM + select KVX_OTP_NV + default y + +endmenu diff --git a/drivers/soc/kvx/Makefile b/drivers/soc/kvx/Makefile new file mode 100644 index 0000000000..cacfef21a1 --- /dev/null +++ b/drivers/soc/kvx/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_KVX_SOCINFO) += kvx_socinfo.o diff --git a/drivers/soc/kvx/kvx_socinfo.c b/drivers/soc/kvx/kvx_socinfo.c new file mode 100644 index 0000000000..100faae766 --- /dev/null +++ b/drivers/soc/kvx/kvx_socinfo.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Kalray Inc., Clément Léger + */ + +#define pr_fmt(fmt) "kvx_socinfo: " fmt + +#include <init.h> +#include <driver.h> +#include <globalvar.h> +#include <magicvar.h> +#include <command.h> +#include <libfile.h> +#include <getopt.h> +#include <common.h> +#include <fs.h> + +#include <asm/sfr.h> + +#include <linux/kernel.h> +#include <linux/nvmem-consumer.h> + +#define LOT_ID_STR_LEN 8 + +#define EWS_LOT_ID_MASK 0x1ffffffffffULL +#define EWS_WAFER_ID_SHIFT 42 +#define EWS_WAFER_ID_MASK 0x1fULL + +#define FT_COM_AP_SHIFT 16 +#define FT_COM_AP_MASK 0x3f +#define FT_DEVICE_ID_SHIFT 22 +#define FT_DEVICE_ID_MASK 0x1ff + +static char *kvx_mppa_id; +static char *kvx_arch_rev; + +BAREBOX_MAGICVAR(kvx.arch_rev, "KVX architecture revision"); +BAREBOX_MAGICVAR(kvx.mppa_id, "KVX MPPA chip id"); + +static void kvx_soc_info_read_revision(void) +{ + u64 pcr = kvx_sfr_get(PCR); + u8 sv = kvx_sfr_field_val(pcr, PCR, SV); + u8 car = kvx_sfr_field_val(pcr, PCR, CAR); + const char *car_str = "", *ver_str = ""; + + switch (car) { + case 0: + car_str = "kv3"; + break; + } + + switch (sv) { + case 0: + ver_str = "1"; + break; + case 1: + ver_str = "2"; + break; + } + + kvx_arch_rev = basprintf("%s-%s", car_str, ver_str); + + globalvar_add_simple_string("kvx.arch_rev", &kvx_arch_rev); +} + +static int base38_decode(char *s, u64 val, int nb_char) +{ + int i; + const char *alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_?"; + const int base = strlen(alphabet); + + if (s == NULL) + return -1; + + for (i = 0; i < nb_char; i++) { + s[i] = alphabet[val % base]; + val /= base; + } + + return 0; +} + +static int kvx_read_serial(struct device_node *socinfo) +{ + char lot_id[LOT_ID_STR_LEN + 1] = ""; + char com_ap; + u64 *cell_val64; + u64 ews_val; + u32 *cell_val32; + u32 ft_val; + u8 wafer_id; + u16 device_id; + + cell_val64 = (u64 *) nvmem_cell_get_and_read(socinfo, "ews_fuse", 8); + if (IS_ERR(cell_val64)) { + pr_debug("Fail to read ews_fuse\n"); + return PTR_ERR(cell_val64); + } + + ews_val = *cell_val64; + ews_val = (ews_val >> 32) | (ews_val << 32); + wafer_id = (ews_val >> EWS_WAFER_ID_SHIFT) & EWS_WAFER_ID_MASK; + base38_decode(lot_id, ews_val & EWS_LOT_ID_MASK, LOT_ID_STR_LEN); + + cell_val32 = (u32 *) nvmem_cell_get_and_read(socinfo, "ft_fuse", 4); + if (IS_ERR(cell_val32)) { + pr_debug("Fail to read ft_fuse\n"); + return PTR_ERR(cell_val32); + } + + ft_val = *cell_val32; + device_id = (ft_val >> FT_DEVICE_ID_SHIFT) & FT_DEVICE_ID_MASK; + base38_decode(&com_ap, (ft_val >> FT_COM_AP_SHIFT) & FT_COM_AP_MASK, 1); + + kvx_mppa_id = basprintf("%sA-%d%c-%03d", lot_id, wafer_id, com_ap, + device_id); + + globalvar_add_simple_string("kvx.mppa_id", &kvx_mppa_id); + + return 0; +} + +static int kvx_socinfo_probe(struct device_d *dev) +{ + kvx_soc_info_read_revision(); + + return kvx_read_serial(dev->device_node); +} + +static const struct of_device_id kvx_socinfo_dt_ids[] = { + { .compatible = "kalray,kvx-socinfo" }, + { } +}; + +static struct driver_d kvx_socinfo_driver = { + .name = "kvx-socinfo", + .probe = kvx_socinfo_probe, + .of_compatible = DRV_OF_COMPAT(kvx_socinfo_dt_ids), +}; +coredevice_platform_driver(kvx_socinfo_driver); diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c index f814778858..bf8b6f1eb8 100644 --- a/drivers/usb/imx/chipidea-imx.c +++ b/drivers/usb/imx/chipidea-imx.c @@ -218,6 +218,7 @@ static int imx_chipidea_probe(struct device_d *dev) struct resource *iores; struct imx_chipidea_data *imx_data; struct imxusb_platformdata *pdata = dev->platform_data; + char const *phynode_name; int ret; void __iomem *base; struct imx_chipidea *ci; @@ -262,8 +263,19 @@ static int imx_chipidea_probe(struct device_d *dev) if (!IS_ERR(ci->clk)) clk_enable(ci->clk); - if (of_property_read_bool(dev->device_node, "fsl,usbphy")) { - ci->phy = of_phy_get_by_phandle(dev, "fsl,usbphy", 0); + /* Device trees are using both "phys" and "fsl,usbphy". Prefer the + * more modern former one but fall back to the old one. + * + * Code should be removed when all devicetrees are using "phys" */ + if (of_property_read_bool(dev->device_node, "phys")) + phynode_name = "phys"; + else if (of_property_read_bool(dev->device_node, "fsl,usbphy")) + phynode_name = "fsl,usbphy"; + else + phynode_name = NULL; + + if (phynode_name) { + ci->phy = of_phy_get_by_phandle(dev, phynode_name, 0); if (IS_ERR(ci->phy)) { dev_err(dev, "Cannot get phy: %pe\n", ci->phy); return PTR_ERR(ci->phy); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d605e62c1e..70c8be7ca9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -149,4 +149,14 @@ config STARFIVE_WDT If you say yes here you get support for the watchdog device on StarFive SoCs. +config WDAT_WDT + bool "ACPI Watchdog Action Table (WDAT)" + depends on X86 + depends on ACPI + help + This driver adds support for systems with ACPI Watchdog Action + Table (WDAT) table. Servers typically have this but it can be + found on some desktop machines as well. This driver will take + over the native iTCO watchdog driver found on many Intel CPUs. + endif diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index dbb76a5cb8..0d2f273f78 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o obj-$(CONFIG_ITCO_WDT) += itco_wdt.o obj-$(CONFIG_STARFIVE_WDT) += starfive_wdt.o +obj-$(CONFIG_WDAT_WDT) += wdat_wdt.o diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 25b11077b9..31ea388c2c 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -47,6 +47,7 @@ struct imx_wd { #define IMX21_WDOG_WSR 0x02 /* Watchdog Service Register */ #define IMX21_WDOG_WSTR 0x04 /* Watchdog Status Register */ #define IMX21_WDOG_WMCR 0x08 /* Misc Register */ +#define IMX21_WDOG_WCR_WDZST (1 << 0) #define IMX21_WDOG_WCR_WDE (1 << 2) #define IMX21_WDOG_WCR_WDT (1 << 3) #define IMX21_WDOG_WCR_SRS (1 << 4) @@ -125,6 +126,9 @@ static int imx21_watchdog_set_timeout(struct imx_wd *priv, unsigned timeout) if (priv->ext_reset) val |= IMX21_WDOG_WCR_WDT; + /* Suspend timer in low power mode */ + val |= IMX21_WDOG_WCR_WDZST; + /* * set time and some write once bits first prior enabling the * watchdog according to the datasheet diff --git a/drivers/watchdog/kvx_wdt.c b/drivers/watchdog/kvx_wdt.c index da19136fda..df9430769b 100644 --- a/drivers/watchdog/kvx_wdt.c +++ b/drivers/watchdog/kvx_wdt.c @@ -73,11 +73,9 @@ static int kvx_wdt_drv_probe(struct device_d *dev) wdd->hwdev = dev; wdd->set_timeout = kvx_wdt_set_timeout; - /* Be sure that interrupt are disable */ + /* Be sure that interrupt are disabled */ kvx_sfr_set_field(TCR, WIE, 0); - kvx_watchdog_disable(); - return watchdog_register(wdd); } diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c new file mode 100644 index 0000000000..39e8cc4a3d --- /dev/null +++ b/drivers/watchdog/wdat_wdt.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ACPI Hardware Watchdog (WDAT) driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + */ +#include <common.h> +#include <acpi.h> +#include <errno.h> +#include <init.h> +#include <io.h> +#include <malloc.h> +#include <of.h> +#include <watchdog.h> + +enum acpi_wdat_actions { + ACPI_WDAT_RESET = 1, + ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4, + ACPI_WDAT_GET_COUNTDOWN = 5, + ACPI_WDAT_SET_COUNTDOWN = 6, + ACPI_WDAT_GET_RUNNING_STATE = 8, + ACPI_WDAT_SET_RUNNING_STATE = 9, + ACPI_WDAT_GET_STOPPED_STATE = 10, + ACPI_WDAT_SET_STOPPED_STATE = 11, + ACPI_WDAT_GET_REBOOT = 16, + ACPI_WDAT_SET_REBOOT = 17, + ACPI_WDAT_GET_SHUTDOWN = 18, + ACPI_WDAT_SET_SHUTDOWN = 19, + ACPI_WDAT_GET_STATUS = 32, + ACPI_WDAT_SET_STATUS = 33, + ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */ +}; + +enum acpi_wdat_instructions { + ACPI_WDAT_READ_VALUE = 0, + ACPI_WDAT_READ_COUNTDOWN = 1, + ACPI_WDAT_WRITE_VALUE = 2, + ACPI_WDAT_WRITE_COUNTDOWN = 3, + ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */ + ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */ +}; + +#define MAX_WDAT_ACTIONS ACPI_WDAT_ACTION_RESERVED + +#define WDAT_DEFAULT_TIMEOUT 30 + +/* WDAT Instruction Entries (actions) */ + +struct __packed acpi_wdat_entry { + u8 action; + u8 instruction; + u16 reserved; + struct acpi_generic_address register_region; + u32 value; /* Value used with Read/Write register */ + u32 mask; /* Bitmask required for this register instruction */ +}; + +/** + * struct wdat_instruction - Single ACPI WDAT instruction + * @entry: Copy of the ACPI table instruction + * @reg: Register the instruction is accessing + * @node: Next instruction in action sequence + */ +struct wdat_instruction { + struct acpi_wdat_entry entry; + void __iomem *reg; + struct list_head node; +}; + +/** + * struct wdat_wdt - ACPI WDAT watchdog device + * @dev: Parent platform device + * @wdd: Watchdog core device + * @period: How long is one watchdog period in ms + * @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S5 + * @stopped: Was the watchdog stopped by the driver in suspend + * @instructions: An array of instruction lists indexed by an action number from + * the WDAT table. There can be %NULL entries for not implemented + * actions. + */ +struct wdat_wdt { + struct watchdog wdd; + unsigned int period; + bool stopped_in_sleep; + bool stopped; + struct list_head *instructions[MAX_WDAT_ACTIONS]; +}; + +struct __packed acpi_table_wdat { + struct acpi_table_header header; /* Common ACPI table header */ + u32 header_length; /* Watchdog Header Length */ + u16 pci_segment; /* PCI Segment number */ + u8 pci_bus; /* PCI Bus number */ + u8 pci_device; /* PCI Device number */ + u8 pci_function; /* PCI Function number */ + u8 reserved[3]; + u32 timer_period; /* Period of one timer count (msec) */ + u32 max_count; /* Maximum counter value supported */ + u32 min_count; /* Minimum counter value */ + u8 flags; + u8 reserved2[3]; + u32 nr_entries; /* Number of watchdog entries that follow */ + struct acpi_wdat_entry entries[]; +}; + +#define ACPI_WDAT_ENABLED (1) +#define ACPI_WDAT_STOPPED 0x80 + +#define IO_COND(instr, is_pio, is_mmio) do { \ + const struct acpi_generic_address *gas = &instr->entry.register_region; \ + unsigned long port = (unsigned long __force)instr->reg; \ + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { \ + is_mmio; \ + } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { \ + is_pio; \ + } \ +} while (0) + +static unsigned int read8(const struct wdat_instruction *instr) +{ + IO_COND(instr, return inb(port), return readb(instr->reg)); + return 0xff; +} + +static unsigned int read16(const struct wdat_instruction *instr) +{ + IO_COND(instr, return inw(port), return readw(instr->reg)); + return 0xffff; +} + +static unsigned int read32(const struct wdat_instruction *instr) +{ + IO_COND(instr, return inl(port), return readl(instr->reg)); + return 0xffffffff; +} + +static void write8(u8 val, const struct wdat_instruction *instr) +{ + IO_COND(instr, outb(val,port), writeb(val, instr->reg)); +} + +static void write16(u16 val, const struct wdat_instruction *instr) +{ + IO_COND(instr, outw(val,port), writew(val, instr->reg)); +} + +static void write32(u32 val, const struct wdat_instruction *instr) +{ + IO_COND(instr, outl(val,port), writel(val, instr->reg)); +} + +static int wdat_wdt_read(struct wdat_wdt *wdat, + const struct wdat_instruction *instr, u32 *value) +{ + const struct acpi_generic_address *gas = &instr->entry.register_region; + + switch (gas->access_width) { + case 1: + *value = read8(instr); + break; + case 2: + *value = read16(instr); + break; + case 3: + *value = read32(instr); + break; + default: + return -EINVAL; + } + + dev_dbg(wdat->wdd.hwdev, "Read %#x from 0x%08llx\n", *value, + gas->address); + + return 0; +} + +static int wdat_wdt_write(struct wdat_wdt *wdat, + const struct wdat_instruction *instr, u32 value) +{ + const struct acpi_generic_address *gas = &instr->entry.register_region; + + switch (gas->access_width) { + case 1: + write8((u8)value, instr); + break; + case 2: + write16((u16)value, instr); + break; + case 3: + write32(value, instr); + break; + default: + return -EINVAL; + } + + dev_dbg(wdat->wdd.hwdev, "Wrote %#x to 0x%08llx\n", value, + gas->address); + + return 0; +} + +static int wdat_wdt_run_action(struct wdat_wdt *wdat, unsigned int action, + u32 param, u32 *retval) +{ + struct wdat_instruction *instr; + + if (action >= ARRAY_SIZE(wdat->instructions)) { + dev_dbg(wdat->wdd.hwdev, "Invalid action %#x\n", action); + return -EINVAL; + } + + if (!wdat->instructions[action]) { + dev_dbg(wdat->wdd.hwdev, "Unsupported action %#x\n", action); + return -EOPNOTSUPP; + } + + dev_dbg(wdat->wdd.hwdev, "Running action %#x\n", action); + + /* Run each instruction sequentially */ + list_for_each_entry(instr, wdat->instructions[action], node) { + const struct acpi_wdat_entry *entry = &instr->entry; + const struct acpi_generic_address *gas; + u32 flags, value, mask, x, y; + bool preserve; + int ret; + + gas = &entry->register_region; + + preserve = entry->instruction & ACPI_WDAT_PRESERVE_REGISTER; + flags = entry->instruction & ~ACPI_WDAT_PRESERVE_REGISTER; + value = entry->value; + mask = entry->mask; + + switch (flags) { + case ACPI_WDAT_READ_VALUE: + ret = wdat_wdt_read(wdat, instr, &x); + if (ret) + return ret; + x >>= gas->bit_offset; + x &= mask; + if (retval) + *retval = x == value; + break; + + case ACPI_WDAT_READ_COUNTDOWN: + ret = wdat_wdt_read(wdat, instr, &x); + if (ret) + return ret; + x >>= gas->bit_offset; + x &= mask; + if (retval) + *retval = x; + break; + + case ACPI_WDAT_WRITE_VALUE: + x = value & mask; + x <<= gas->bit_offset; + if (preserve) { + ret = wdat_wdt_read(wdat, instr, &y); + if (ret) + return ret; + y = y & ~(mask << gas->bit_offset); + x |= y; + } + ret = wdat_wdt_write(wdat, instr, x); + if (ret) + return ret; + break; + + case ACPI_WDAT_WRITE_COUNTDOWN: + x = param; + x &= mask; + x <<= gas->bit_offset; + if (preserve) { + ret = wdat_wdt_read(wdat, instr, &y); + if (ret) + return ret; + y = y & ~(mask << gas->bit_offset); + x |= y; + } + ret = wdat_wdt_write(wdat, instr, x); + if (ret) + return ret; + break; + + default: + dev_err(wdat->wdd.hwdev, "Unknown instruction: %u\n", + flags); + return -EINVAL; + } + } + + return 0; +} + +static void wdat_wdt_boot_status(struct wdat_wdt *wdat) +{ + u32 boot_status = 0; + int ret; + + ret = wdat_wdt_run_action(wdat, ACPI_WDAT_GET_STATUS, 0, &boot_status); + if (ret && ret != -EOPNOTSUPP) { + dev_err(wdat->wdd.hwdev, "Failed to read boot status\n"); + return; + } + + /* Clear the boot status in case BIOS did not do it */ + ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_STATUS, 0, NULL); + if (ret && ret != -EOPNOTSUPP) + dev_err(wdat->wdd.hwdev, "Failed to clear boot status\n"); +} + +static int wdat_wdt_start(struct watchdog *wdd) +{ + struct wdat_wdt *wdat = container_of(wdd, struct wdat_wdt, wdd); + + return wdat_wdt_run_action(wdat, ACPI_WDAT_SET_RUNNING_STATE, 0, NULL); +} + +static int wdat_wdt_stop(struct watchdog *wdd) +{ + struct wdat_wdt *wdat = container_of(wdd, struct wdat_wdt, wdd); + + return wdat_wdt_run_action(wdat, ACPI_WDAT_SET_STOPPED_STATE, 0, NULL); +} + +static void wdat_wdt_set_running(struct wdat_wdt *wdat) +{ + u32 running = 0; + int ret; + + ret = wdat_wdt_run_action(wdat, ACPI_WDAT_GET_RUNNING_STATE, 0, + &running); + if (ret && ret != -EOPNOTSUPP) + dev_err(wdat->wdd.hwdev, "Failed to read running state\n"); + + dev_dbg(wdat->wdd.hwdev, "Running state: %d\n", running); + + wdat->wdd.running = running ? WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING; +} + +static int wdat_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout) +{ + struct wdat_wdt *wdat = container_of(wdd, struct wdat_wdt, wdd); + unsigned int periods; + int ret; + + if (timeout == 0) + return wdat_wdt_stop(wdd); + + periods = timeout * 1000 / wdat->period; + ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_COUNTDOWN, periods, NULL); + if (ret) + return ret; + + if (wdat->wdd.running == WDOG_HW_NOT_RUNNING) { + wdat_wdt_start(wdd); + wdat->wdd.running = WDOG_HW_RUNNING; + } + + return wdat_wdt_run_action(wdat, ACPI_WDAT_RESET, 0, NULL); +} + +static int wdat_wdt_enable_reboot(struct wdat_wdt *wdat) +{ + int ret; + + /* + * WDAT specification says that the watchdog is required to reboot + * the system when it fires. However, it also states that it is + * recommeded to make it configurable through hardware register. We + * enable reboot now if it is configrable, just in case. + */ + ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_REBOOT, 0, NULL); + if (ret && ret != -EOPNOTSUPP) { + dev_err(wdat->wdd.hwdev, + "Failed to enable reboot when watchdog triggers\n"); + return ret; + } + + return 0; +} + +static int wdat_wdt_probe(struct device_d *const dev) +{ + const struct acpi_wdat_entry *entries; + struct acpi_table_wdat *tbl; + struct wdat_wdt *wdat; + int i, ret; + + dev_dbg(dev, "driver initializing...\n"); + + tbl = (struct acpi_table_wdat __force *)dev_request_mem_region_by_name(dev, "SDT"); + if (IS_ERR(tbl)) { + dev_err(dev, "no SDT resource available: %pe\n", tbl); + return PTR_ERR(tbl); + } + + dev_dbg(dev, "SDT is at 0x%p\n", tbl); + + wdat = xzalloc(sizeof(*wdat)); + + /* WDAT specification wants to have >= 1ms period */ + if (tbl->timer_period < 1) { + dev_dbg(dev, "timer_period is less than 1: %d\n", tbl->timer_period); + return -EINVAL; + } + if (tbl->min_count > tbl->max_count) { + dev_dbg(dev, "min_count must be greater than max_count\n"); + return -EINVAL; + } + + wdat->period = tbl->timer_period; + wdat->stopped_in_sleep = tbl->flags & ACPI_WDAT_STOPPED; + wdat->wdd.set_timeout = wdat_wdt_set_timeout; + wdat->wdd.hwdev = dev; + wdat->wdd.timeout_max = U32_MAX; + + entries = tbl->entries; + + for (i = 0; i < tbl->nr_entries; i++) { + const struct acpi_generic_address *gas; + struct wdat_instruction *instr; + struct list_head *instructions; + struct resource *res; + unsigned int action; + struct resource r; + + action = entries[i].action; + if (action >= MAX_WDAT_ACTIONS) { + dev_dbg(dev, "Skipping unknown action: %u\n", action); + continue; + } + + instr = xzalloc(sizeof(*instr)); + + INIT_LIST_HEAD(&instr->node); + instr->entry = entries[i]; + + gas = &entries[i].register_region; + + memset(&r, 0, sizeof(r)); + r.start = gas->address; + r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1; + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + res = request_iomem_region(dev_name(dev), r.start, r.end); + } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + res = request_ioport_region(dev_name(dev), r.start, r.end); + } else { + dev_dbg(dev, "Unsupported address space: %d\n", + gas->space_id); + continue; + } + + /* + * Some entries have the same gas->address. + * We want the action but can't request the region multiple times. + */ + if (IS_ERR(res) && (PTR_ERR(res) != -EBUSY)) + return PTR_ERR(res); + + instr->reg = IOMEM(r.start); + + instructions = wdat->instructions[action]; + if (!instructions) { + instructions = xzalloc(sizeof(*instructions)); + if (!instructions) + return -ENOMEM; + + INIT_LIST_HEAD(instructions); + wdat->instructions[action] = instructions; + } + + list_add_tail(&instr->node, instructions); + } + + wdat_wdt_boot_status(wdat); + wdat_wdt_set_running(wdat); + + ret = wdat_wdt_enable_reboot(wdat); + if (ret) + return ret; + + return watchdog_register(&wdat->wdd); +} + + +static struct acpi_driver wdat_wdt_driver = { + .signature = "WDAT", + .driver = { + .name = "wdat-wdt", + .probe = wdat_wdt_probe, + } +}; +device_acpi_driver(wdat_wdt_driver); |