diff options
123 files changed, 4098 insertions, 3389 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt index f463bdc..5c4bc4d 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -71,12 +71,8 @@ the operations defined in clk.h: long (*round_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); - long (*determine_rate)(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); + int (*determine_rate)(struct clk_hw *hw, + struct clk_rate_request *req); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, diff --git a/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt b/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt new file mode 100644 index 0000000..2be1e03 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt @@ -0,0 +1,19 @@ +Binding for simple gpio clock multiplexer. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "gpio-mux-clock". +- clocks: list of two references to parent clocks. +- #clock-cells : from common clock binding; shall be set to 0. +- select-gpios : GPIO reference for selecting the parent clock. + +Example: + clock { + compatible = "gpio-mux-clock"; + clocks = <&parentclk1>, <&parentclk2>; + #clock-cells = <0>; + select-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt new file mode 100644 index 0000000..7c8bbcf --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3368-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3368 Clock and Reset Unit + +The RK3368 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3368-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing, pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3368-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_gmac" - external GMAC clock - optional + - "ext_hsadc" - external HSADC clock - optional, + - "ext_isp" - external ISP clock - optional, + - "ext_jtag" - external JTAG clock - optional + - "ext_vip" - external VIP clock - optional, + - "usbotg_out" - output clock of the pll in the otg phy + +Example: Clock controller node: + + cru: clock-controller@ff760000 { + compatible = "rockchip,rk3368-cru"; + reg = <0x0 0xff760000 0x0 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 903c85b..7892c7d 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -12,8 +12,7 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \ hwmod-common = omap_hwmod.o omap_hwmod_reset.o \ omap_hwmod_common_data.o -clock-common = clock.o clock_common_data.o \ - clkt_dpll.o clkt_clksel.o +clock-common = clock.o secure-common = omap-smc.o omap-secure.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) @@ -182,24 +181,17 @@ obj-$(CONFIG_SOC_DRA7XX) += $(clockdomain-common) obj-$(CONFIG_SOC_DRA7XX) += clockdomains7xx_data.o # Clock framework -obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o +obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o -obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o clkt_iclk.o -obj-$(CONFIG_SOC_OMAP2430) += clock2430.o -obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o -obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o -obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o -obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o -obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o +obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) +obj-$(CONFIG_ARCH_OMAP3) += clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) -obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o -obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o +obj-$(CONFIG_SOC_AM33XX) += $(clock-common) obj-$(CONFIG_SOC_OMAP5) += $(clock-common) -obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clock-common) -obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o -obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o +obj-$(CONFIG_SOC_AM43XX) += $(clock-common) # OMAP2 clock rate set data (old "OPP" data) obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c index eb69acf..07e1956 100644 --- a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c +++ b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c @@ -23,12 +23,13 @@ #include "clock.h" #include "clock3xxx.h" -#include "clock34xx.h" #include "sdrc.h" #include "sram.h" #define CYCLES_PER_MHZ 1000000 +struct clk *sdrc_ick_p, *arm_fck_p; + /* * CORE DPLL (DPLL3) M2 divider rate programming functions * @@ -60,7 +61,9 @@ int omap3_core_dpll_m2_set_rate(struct clk_hw *hw, unsigned long rate, if (!clk || !rate) return -EINVAL; - validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); + new_div = DIV_ROUND_UP(parent_rate, rate); + validrate = parent_rate / new_div; + if (validrate != rate) return -EINVAL; diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c deleted file mode 100644 index 7ee2610..0000000 --- a/arch/arm/mach-omap2/clkt_clksel.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * clkt_clksel.c - OMAP2/3/4 clksel clock functions - * - * Copyright (C) 2005-2008 Texas Instruments, Inc. - * Copyright (C) 2004-2010 Nokia Corporation - * - * Contacts: - * Richard Woodruff <r-woodruff2@ti.com> - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - * clksel clocks are clocks that do not have a fixed parent, or that - * can divide their parent's rate, or possibly both at the same time, based - * on the contents of a hardware register bitfield. - * - * All of the various mux and divider settings can be encoded into - * struct clksel* data structures, and then these can be autogenerated - * from some hardware database for each new chip generation. This - * should avoid the need to write, review, and validate a lot of new - * clock code for each new chip, since it can be exported from the SoC - * design flow. This is now done on OMAP4. - * - * The fusion of mux and divider clocks is a software creation. In - * hardware reality, the multiplexer (parent selection) and the - * divider exist separately. XXX At some point these clksel clocks - * should be split into "divider" clocks and "mux" clocks to better - * match the hardware. - * - * (The name "clksel" comes from the name of the corresponding - * register field in the OMAP2/3 family of SoCs.) - * - * XXX Currently these clocks are only used in the OMAP2/3/4 code, but - * many of the OMAP1 clocks should be convertible to use this - * mechanism. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/clk-provider.h> -#include <linux/io.h> -#include <linux/bug.h> - -#include "clock.h" - -/* Private functions */ - -/** - * _get_clksel_by_parent() - return clksel struct for a given clk & parent - * @clk: OMAP struct clk ptr to inspect - * @src_clk: OMAP struct clk ptr of the parent clk to search for - * - * Scan the struct clksel array associated with the clock to find - * the element associated with the supplied parent clock address. - * Returns a pointer to the struct clksel on success or NULL on error. - */ -static const struct clksel *_get_clksel_by_parent(struct clk_hw_omap *clk, - struct clk *src_clk) -{ - const struct clksel *clks; - - if (!src_clk) - return NULL; - - for (clks = clk->clksel; clks->parent; clks++) - if (clks->parent == src_clk) - break; /* Found the requested parent */ - - if (!clks->parent) { - /* This indicates a data problem */ - WARN(1, "clock: %s: could not find parent clock %s in clksel array\n", - __clk_get_name(clk->hw.clk), __clk_get_name(src_clk)); - return NULL; - } - - return clks; -} - -/** - * _write_clksel_reg() - program a clock's clksel register in hardware - * @clk: struct clk * to program - * @v: clksel bitfield value to program (with LSB at bit 0) - * - * Shift the clksel register bitfield value @v to its appropriate - * location in the clksel register and write it in. This function - * will ensure that the write to the clksel_reg reaches its - * destination before returning -- important since PRM and CM register - * accesses can be quite slow compared to ARM cycles -- but does not - * take into account any time the hardware might take to switch the - * clock source. - */ -static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val) -{ - u32 v; - - v = omap2_clk_readl(clk, clk->clksel_reg); - v &= ~clk->clksel_mask; - v |= field_val << __ffs(clk->clksel_mask); - omap2_clk_writel(v, clk, clk->clksel_reg); - - v = omap2_clk_readl(clk, clk->clksel_reg); /* OCP barrier */ -} - -/** - * _clksel_to_divisor() - turn clksel field value into integer divider - * @clk: OMAP struct clk to use - * @field_val: register field value to find - * - * Given a struct clk of a rate-selectable clksel clock, and a register field - * value to search for, find the corresponding clock divisor. The register - * field value should be pre-masked and shifted down so the LSB is at bit 0 - * before calling. Returns 0 on error or returns the actual integer divisor - * upon success. - */ -static u32 _clksel_to_divisor(struct clk_hw_omap *clk, u32 field_val) -{ - const struct clksel *clks; - const struct clksel_rate *clkr; - struct clk *parent; - - parent = __clk_get_parent(clk->hw.clk); - - clks = _get_clksel_by_parent(clk, parent); - if (!clks) - return 0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if (!(clkr->flags & cpu_mask)) - continue; - - if (clkr->val == field_val) - break; - } - - if (!clkr->div) { - /* This indicates a data error */ - WARN(1, "clock: %s: could not find fieldval %d for parent %s\n", - __clk_get_name(clk->hw.clk), field_val, - __clk_get_name(parent)); - return 0; - } - - return clkr->div; -} - -/** - * _divisor_to_clksel() - turn clksel integer divisor into a field value - * @clk: OMAP struct clk to use - * @div: integer divisor to search for - * - * Given a struct clk of a rate-selectable clksel clock, and a clock - * divisor, find the corresponding register field value. Returns the - * register field value _before_ left-shifting (i.e., LSB is at bit - * 0); or returns 0xFFFFFFFF (~0) upon error. - */ -static u32 _divisor_to_clksel(struct clk_hw_omap *clk, u32 div) -{ - const struct clksel *clks; - const struct clksel_rate *clkr; - struct clk *parent; - - /* should never happen */ - WARN_ON(div == 0); - - parent = __clk_get_parent(clk->hw.clk); - clks = _get_clksel_by_parent(clk, parent); - if (!clks) - return ~0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if (!(clkr->flags & cpu_mask)) - continue; - - if (clkr->div == div) - break; - } - - if (!clkr->div) { - pr_err("clock: %s: could not find divisor %d for parent %s\n", - __clk_get_name(clk->hw.clk), div, - __clk_get_name(parent)); - return ~0; - } - - return clkr->val; -} - -/** - * _read_divisor() - get current divisor applied to parent clock (from hdwr) - * @clk: OMAP struct clk to use. - * - * Read the current divisor register value for @clk that is programmed - * into the hardware, convert it into the actual divisor value, and - * return it; or return 0 on error. - */ -static u32 _read_divisor(struct clk_hw_omap *clk) -{ - u32 v; - - if (!clk->clksel || !clk->clksel_mask) - return 0; - - v = omap2_clk_readl(clk, clk->clksel_reg); - v &= clk->clksel_mask; - v >>= __ffs(clk->clksel_mask); - - return _clksel_to_divisor(clk, v); -} - -/* Public functions */ - -/** - * omap2_clksel_round_rate_div() - find divisor for the given clock and rate - * @clk: OMAP struct clk to use - * @target_rate: desired clock rate - * @new_div: ptr to where we should store the divisor - * - * Finds 'best' divider value in an array based on the source and target - * rates. The divider array must be sorted with smallest divider first. - * This function is also used by the DPLL3 M2 divider code. - * - * Returns the rounded clock rate or returns 0xffffffff on error. - */ -u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk, - unsigned long target_rate, - u32 *new_div) -{ - unsigned long test_rate; - const struct clksel *clks; - const struct clksel_rate *clkr; - u32 last_div = 0; - struct clk *parent; - unsigned long parent_rate; - const char *clk_name; - - parent = __clk_get_parent(clk->hw.clk); - clk_name = __clk_get_name(clk->hw.clk); - parent_rate = __clk_get_rate(parent); - - if (!clk->clksel || !clk->clksel_mask) - return ~0; - - pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", - clk_name, target_rate); - - *new_div = 1; - - clks = _get_clksel_by_parent(clk, parent); - if (!clks) - return ~0; - - for (clkr = clks->rates; clkr->div; clkr++) { - if (!(clkr->flags & cpu_mask)) - continue; - - /* Sanity check */ - if (clkr->div <= last_div) - pr_err("clock: %s: clksel_rate table not sorted\n", - clk_name); - - last_div = clkr->div; - - test_rate = parent_rate / clkr->div; - - if (test_rate <= target_rate) - break; /* found it */ - } - - if (!clkr->div) { - pr_err("clock: %s: could not find divisor for target rate %ld for parent %s\n", - clk_name, target_rate, __clk_get_name(parent)); - return ~0; - } - - *new_div = clkr->div; - - pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, - (parent_rate / clkr->div)); - - return parent_rate / clkr->div; -} - -/* - * Clocktype interface functions to the OMAP clock code - * (i.e., those used in struct clk field function pointers, etc.) - */ - -/** - * omap2_clksel_find_parent_index() - return the array index of the current - * hardware parent of @hw - * @hw: struct clk_hw * to find the current hardware parent of - * - * Given a struct clk_hw pointer @hw to the 'hw' member of a struct - * clk_hw_omap record representing a source-selectable hardware clock, - * read the hardware register and determine what its parent is - * currently set to. Intended to be called only by the common clock - * framework struct clk_hw_ops.get_parent function pointer. Return - * the array index of this parent clock upon success -- there is no - * way to return an error, so if we encounter an error, just WARN() - * and pretend that we know that we're doing. - */ -u8 omap2_clksel_find_parent_index(struct clk_hw *hw) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - const struct clksel *clks; - const struct clksel_rate *clkr; - u32 r, found = 0; - struct clk *parent; - const char *clk_name; - int ret = 0, f = 0; - - parent = __clk_get_parent(hw->clk); - clk_name = __clk_get_name(hw->clk); - - /* XXX should be able to return an error */ - WARN((!clk->clksel || !clk->clksel_mask), - "clock: %s: attempt to call on a non-clksel clock", clk_name); - - r = omap2_clk_readl(clk, clk->clksel_reg) & clk->clksel_mask; - r >>= __ffs(clk->clksel_mask); - - for (clks = clk->clksel; clks->parent && !found; clks++) { - for (clkr = clks->rates; clkr->div && !found; clkr++) { - if (!(clkr->flags & cpu_mask)) - continue; - - if (clkr->val == r) { - found = 1; - ret = f; - } - } - f++; - } - - /* This indicates a data error */ - WARN(!found, "clock: %s: init parent: could not find regval %0x\n", - clk_name, r); - - return ret; -} - - -/** - * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field - * @clk: struct clk * - * - * This function is intended to be called only by the clock framework. - * Each clksel clock should have its struct clk .recalc field set to this - * function. Returns the clock's current rate, based on its parent's rate - * and its current divisor setting in the hardware. - */ -unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate) -{ - unsigned long rate; - u32 div = 0; - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - - if (!parent_rate) - return 0; - - div = _read_divisor(clk); - if (!div) - rate = parent_rate; - else - rate = parent_rate / div; - - pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__, - __clk_get_name(hw->clk), rate, div); - - return rate; -} - -/** - * omap2_clksel_round_rate() - find rounded rate for the given clock and rate - * @clk: OMAP struct clk to use - * @target_rate: desired clock rate - * - * This function is intended to be called only by the clock framework. - * Finds best target rate based on the source clock and possible dividers. - * rates. The divider array must be sorted with smallest divider first. - * - * Returns the rounded clock rate or returns 0xffffffff on error. - */ -long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - u32 new_div; - - return omap2_clksel_round_rate_div(clk, target_rate, &new_div); -} - -/** - * omap2_clksel_set_rate() - program clock rate in hardware - * @clk: struct clk * to program rate - * @rate: target rate to program - * - * This function is intended to be called only by the clock framework. - * Program @clk's rate to @rate in the hardware. The clock can be - * either enabled or disabled when this happens, although if the clock - * is enabled, some downstream devices may glitch or behave - * unpredictably when the clock rate is changed - this depends on the - * hardware. This function does not currently check the usecount of - * the clock, so if multiple drivers are using the clock, and the rate - * is changed, they will all be affected without any notification. - * Returns -EINVAL upon error, or 0 upon success. - */ -int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - u32 field_val, validrate, new_div = 0; - - if (!clk->clksel || !clk->clksel_mask) - return -EINVAL; - - validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); - if (validrate != rate) - return -EINVAL; - - field_val = _divisor_to_clksel(clk, new_div); - if (field_val == ~0) - return -EINVAL; - - _write_clksel_reg(clk, field_val); - - pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(hw->clk), - __clk_get_rate(hw->clk)); - - return 0; -} - -/* - * Clksel parent setting function - not passed in struct clk function - * pointer - instead, the OMAP clock code currently assumes that any - * parent-setting clock is a clksel clock, and calls - * omap2_clksel_set_parent() by default - */ - -/** - * omap2_clksel_set_parent() - change a clock's parent clock - * @clk: struct clk * of the child clock - * @new_parent: struct clk * of the new parent clock - * - * This function is intended to be called only by the clock framework. - * Change the parent clock of clock @clk to @new_parent. This is - * intended to be used while @clk is disabled. This function does not - * currently check the usecount of the clock, so if multiple drivers - * are using the clock, and the parent is changed, they will all be - * affected without any notification. Returns -EINVAL upon error, or - * 0 upon success. - */ -int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - - if (!clk->clksel || !clk->clksel_mask) - return -EINVAL; - - _write_clksel_reg(clk, field_val); - return 0; -} diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c deleted file mode 100644 index 55eb579..0000000 --- a/arch/arm/mach-omap2/clkt_iclk.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * OMAP2/3 interface clock control - * - * Copyright (C) 2011 Nokia Corporation - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/clk-provider.h> -#include <linux/io.h> - -#include "clock.h" - -/* Register offsets */ -#define CM_AUTOIDLE 0x30 -#define CM_ICLKEN 0x10 - -/* Private functions */ - -/* XXX */ -void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) -{ - u32 v; - void __iomem *r; - - r = (__force void __iomem *) - ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - - v = omap2_clk_readl(clk, r); - v |= (1 << clk->enable_bit); - omap2_clk_writel(v, clk, r); -} - -/* XXX */ -void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) -{ - u32 v; - void __iomem *r; - - r = (__force void __iomem *) - ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - - v = omap2_clk_readl(clk, r); - v &= ~(1 << clk->enable_bit); - omap2_clk_writel(v, clk, r); -} - -/* Public data */ - -const struct clk_hw_omap_ops clkhwops_iclk = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, -}; - -const struct clk_hw_omap_ops clkhwops_iclk_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap2_clk_dflt_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - - - diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index f664dc6..acb60ed 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -24,9 +24,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/bitops.h> -#include <linux/regmap.h> #include <linux/of_address.h> -#include <linux/bootmem.h> #include <asm/cpu.h> #include <trace/events/power.h> @@ -41,19 +39,8 @@ #include "cm-regbits-34xx.h" #include "common.h" -/* - * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait - * for a module to indicate that it is no longer in idle - */ -#define MAX_MODULE_ENABLE_WAIT 100000 - u16 cpu_mask; -/* - * Clock features setup. Used instead of CPU type checks. - */ -struct ti_clk_features ti_clk_features; - /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ #define OMAP3430_DPLL_FINT_BAND1_MIN 750000 #define OMAP3430_DPLL_FINT_BAND1_MAX 2100000 @@ -67,119 +54,24 @@ struct ti_clk_features ti_clk_features; #define OMAP3PLUS_DPLL_FINT_MIN 32000 #define OMAP3PLUS_DPLL_FINT_MAX 52000000 -/* - * clkdm_control: if true, then when a clock is enabled in the - * hardware, its clockdomain will first be enabled; and when a clock - * is disabled in the hardware, its clockdomain will be disabled - * afterwards. - */ -static bool clkdm_control = true; - -static LIST_HEAD(clk_hw_omap_clocks); - -struct clk_iomap { - struct regmap *regmap; - void __iomem *mem; -}; - -static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS]; - -static void clk_memmap_writel(u32 val, void __iomem *reg) -{ - struct clk_omap_reg *r = (struct clk_omap_reg *)® - struct clk_iomap *io = clk_memmaps[r->index]; - - if (io->regmap) - regmap_write(io->regmap, r->offset, val); - else - writel_relaxed(val, io->mem + r->offset); -} - -static u32 clk_memmap_readl(void __iomem *reg) -{ - u32 val; - struct clk_omap_reg *r = (struct clk_omap_reg *)® - struct clk_iomap *io = clk_memmaps[r->index]; - - if (io->regmap) - regmap_read(io->regmap, r->offset, &val); - else - val = readl_relaxed(io->mem + r->offset); - - return val; -} - -void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg) -{ - if (WARN_ON_ONCE(!(clk->flags & MEMMAP_ADDRESSING))) - writel_relaxed(val, reg); - else - clk_memmap_writel(val, reg); -} - -u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg) -{ - if (WARN_ON_ONCE(!(clk->flags & MEMMAP_ADDRESSING))) - return readl_relaxed(reg); - else - return clk_memmap_readl(reg); -} - static struct ti_clk_ll_ops omap_clk_ll_ops = { - .clk_readl = clk_memmap_readl, - .clk_writel = clk_memmap_writel, + .clkdm_clk_enable = clkdm_clk_enable, + .clkdm_clk_disable = clkdm_clk_disable, + .cm_wait_module_ready = omap_cm_wait_module_ready, + .cm_split_idlest_reg = cm_split_idlest_reg, }; /** - * omap2_clk_provider_init - initialize a clock provider - * @match_table: DT device table to match for devices to init - * @np: device node pointer for the this clock provider - * @index: index for the clock provider - + @syscon: syscon regmap pointer - * @mem: iomem pointer for the clock provider memory area, only used if - * syscon is not provided + * omap2_clk_setup_ll_ops - setup clock driver low-level ops * - * Initializes a clock provider module (CM/PRM etc.), registering - * the memory mapping at specified index and initializing the - * low level driver infrastructure. Returns 0 in success. + * Sets up clock driver low-level platform ops. These are needed + * for register accesses and various other misc platform operations. + * Returns 0 on success, -EBUSY if low level ops have been registered + * already. */ -int __init omap2_clk_provider_init(struct device_node *np, int index, - struct regmap *syscon, void __iomem *mem) +int __init omap2_clk_setup_ll_ops(void) { - struct clk_iomap *io; - - ti_clk_ll_ops = &omap_clk_ll_ops; - - io = kzalloc(sizeof(*io), GFP_KERNEL); - - io->regmap = syscon; - io->mem = mem; - - clk_memmaps[index] = io; - - ti_dt_clk_init_provider(np, index); - - return 0; -} - -/** - * omap2_clk_legacy_provider_init - initialize a legacy clock provider - * @index: index for the clock provider - * @mem: iomem pointer for the clock provider memory area - * - * Initializes a legacy clock provider memory mapping. - */ -void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) -{ - struct clk_iomap *io; - - ti_clk_ll_ops = &omap_clk_ll_ops; - - io = memblock_virt_alloc(sizeof(*io), 0); - - io->mem = mem; - - clk_memmaps[index] = io; + return ti_clk_setup_ll_ops(&omap_clk_ll_ops); } /* @@ -188,77 +80,6 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) /* Private functions */ - -/** - * _wait_idlest_generic - wait for a module to leave the idle state - * @clk: module clock to wait for (needed for register offsets) - * @reg: virtual address of module IDLEST register - * @mask: value to mask against to determine if the module is active - * @idlest: idle state indicator (0 or 1) for the clock - * @name: name of the clock (for printk) - * - * Wait for a module to leave idle, where its idle-status register is - * not inside the CM module. Returns 1 if the module left idle - * promptly, or 0 if the module did not leave idle before the timeout - * elapsed. XXX Deprecated - should be moved into drivers for the - * individual IP block that the IDLEST register exists in. - */ -static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, - u32 mask, u8 idlest, const char *name) -{ - int i = 0, ena = 0; - - ena = (idlest) ? 0 : mask; - - omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena), - MAX_MODULE_ENABLE_WAIT, i); - - if (i < MAX_MODULE_ENABLE_WAIT) - pr_debug("omap clock: module associated with clock %s ready after %d loops\n", - name, i); - else - pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", - name, MAX_MODULE_ENABLE_WAIT); - - return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; -}; - -/** - * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE - * @clk: struct clk * belonging to the module - * - * If the necessary clocks for the OMAP hardware IP block that - * corresponds to clock @clk are enabled, then wait for the module to - * indicate readiness (i.e., to leave IDLE). This code does not - * belong in the clock code and will be moved in the medium term to - * module-dependent code. No return value. - */ -static void _omap2_module_wait_ready(struct clk_hw_omap *clk) -{ - void __iomem *companion_reg, *idlest_reg; - u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; - s16 prcm_mod; - int r; - - /* Not all modules have multiple clocks that their IDLEST depends on */ - if (clk->ops->find_companion) { - clk->ops->find_companion(clk, &companion_reg, &other_bit); - if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit))) - return; - } - - clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); - r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id); - if (r) { - /* IDLEST register not in the CM module */ - _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), - idlest_val, __clk_get_name(clk->hw.clk)); - } else { - omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id, - idlest_bit); - }; -} - /* Public functions */ /** @@ -291,279 +112,6 @@ void omap2_init_clk_clkdm(struct clk_hw *hw) } } -/** - * omap2_clk_disable_clkdm_control - disable clkdm control on clk enable/disable - * - * Prevent the OMAP clock code from calling into the clockdomain code - * when a hardware clock in that clockdomain is enabled or disabled. - * Intended to be called at init time from omap*_clk_init(). No - * return value. - */ -void __init omap2_clk_disable_clkdm_control(void) -{ - clkdm_control = false; -} - -/** - * omap2_clk_dflt_find_companion - find companion clock to @clk - * @clk: struct clk * to find the companion clock of - * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in - * @other_bit: u8 ** to return the companion clock bit shift in - * - * Note: We don't need special code here for INVERT_ENABLE for the - * time being since INVERT_ENABLE only applies to clocks enabled by - * CM_CLKEN_PLL - * - * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's - * just a matter of XORing the bits. - * - * Some clocks don't have companion clocks. For example, modules with - * only an interface clock (such as MAILBOXES) don't have a companion - * clock. Right now, this code relies on the hardware exporting a bit - * in the correct companion register that indicates that the - * nonexistent 'companion clock' is active. Future patches will - * associate this type of code with per-module data structures to - * avoid this issue, and remove the casts. No return value. - */ -void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, u8 *other_bit) -{ - u32 r; - - /* - * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes - * it's just a matter of XORing the bits. - */ - r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); - - *other_reg = (__force void __iomem *)r; - *other_bit = clk->enable_bit; -} - -/** - * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk - * @clk: struct clk * to find IDLEST info for - * @idlest_reg: void __iomem ** to return the CM_IDLEST va in - * @idlest_bit: u8 * to return the CM_IDLEST bit shift in - * @idlest_val: u8 * to return the idle status indicator - * - * Return the CM_IDLEST register address and bit shift corresponding - * to the module that "owns" this clock. This default code assumes - * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that - * the IDLEST register address ID corresponds to the CM_*CLKEN - * register address ID (e.g., that CM_FCLKEN2 corresponds to - * CM_IDLEST2). This is not true for all modules. No return value. - */ -void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = clk->enable_bit; - - /* - * 24xx uses 0 to indicate not ready, and 1 to indicate ready. - * 34xx reverses this, just to keep us on our toes - * AM35xx uses both, depending on the module. - */ - *idlest_val = ti_clk_features.cm_idlest_val; -} - -/** - * omap2_dflt_clk_enable - enable a clock in the hardware - * @hw: struct clk_hw * of the clock to enable - * - * Enable the clock @hw in the hardware. We first call into the OMAP - * clockdomain code to "enable" the corresponding clockdomain if this - * is the first enabled user of the clockdomain. Then program the - * hardware to enable the clock. Then wait for the IP block that uses - * this clock to leave idle (if applicable). Returns the error value - * from clkdm_clk_enable() if it terminated with an error, or -EINVAL - * if @hw has a null clock enable_reg, or zero upon success. - */ -int omap2_dflt_clk_enable(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - u32 v; - int ret = 0; - - clk = to_clk_hw_omap(hw); - - if (clkdm_control && clk->clkdm) { - ret = clkdm_clk_enable(clk->clkdm, hw->clk); - if (ret) { - WARN(1, "%s: could not enable %s's clockdomain %s: %d\n", - __func__, __clk_get_name(hw->clk), - clk->clkdm->name, ret); - return ret; - } - } - - if (unlikely(clk->enable_reg == NULL)) { - pr_err("%s: %s missing enable_reg\n", __func__, - __clk_get_name(hw->clk)); - ret = -EINVAL; - goto err; - } - - /* FIXME should not have INVERT_ENABLE bit here */ - v = omap2_clk_readl(clk, clk->enable_reg); - if (clk->flags & INVERT_ENABLE) - v &= ~(1 << clk->enable_bit); - else - v |= (1 << clk->enable_bit); - omap2_clk_writel(v, clk, clk->enable_reg); - v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */ - - if (clk->ops && clk->ops->find_idlest) - _omap2_module_wait_ready(clk); - - return 0; - -err: - if (clkdm_control && clk->clkdm) - clkdm_clk_disable(clk->clkdm, hw->clk); - return ret; -} - -/** - * omap2_dflt_clk_disable - disable a clock in the hardware - * @hw: struct clk_hw * of the clock to disable - * - * Disable the clock @hw in the hardware, and call into the OMAP - * clockdomain code to "disable" the corresponding clockdomain if all - * clocks/hwmods in that clockdomain are now disabled. No return - * value. - */ -void omap2_dflt_clk_disable(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - u32 v; - - clk = to_clk_hw_omap(hw); - if (!clk->enable_reg) { - /* - * 'independent' here refers to a clock which is not - * controlled by its parent. - */ - pr_err("%s: independent clock %s has no enable_reg\n", - __func__, __clk_get_name(hw->clk)); - return; - } - - v = omap2_clk_readl(clk, clk->enable_reg); - if (clk->flags & INVERT_ENABLE) - v |= (1 << clk->enable_bit); - else - v &= ~(1 << clk->enable_bit); - omap2_clk_writel(v, clk, clk->enable_reg); - /* No OCP barrier needed here since it is a disable operation */ - - if (clkdm_control && clk->clkdm) - clkdm_clk_disable(clk->clkdm, hw->clk); -} - -/** - * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw - * @hw: struct clk_hw * of the clock being enabled - * - * Increment the usecount of the clockdomain of the clock pointed to - * by @hw; if the usecount is 1, the clockdomain will be "enabled." - * Only needed for clocks that don't use omap2_dflt_clk_enable() as - * their enable function pointer. Passes along the return value of - * clkdm_clk_enable(), -EINVAL if @hw is not associated with a - * clockdomain, or 0 if clock framework-based clockdomain control is - * not implemented. - */ -int omap2_clkops_enable_clkdm(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - int ret = 0; - - clk = to_clk_hw_omap(hw); - - if (unlikely(!clk->clkdm)) { - pr_err("%s: %s: no clkdm set ?!\n", __func__, - __clk_get_name(hw->clk)); - return -EINVAL; - } - - if (unlikely(clk->enable_reg)) - pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__, - __clk_get_name(hw->clk)); - - if (!clkdm_control) { - pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", - __func__, __clk_get_name(hw->clk)); - return 0; - } - - ret = clkdm_clk_enable(clk->clkdm, hw->clk); - WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n", - __func__, __clk_get_name(hw->clk), clk->clkdm->name, ret); - - return ret; -} - -/** - * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw - * @hw: struct clk_hw * of the clock being disabled - * - * Decrement the usecount of the clockdomain of the clock pointed to - * by @hw; if the usecount is 0, the clockdomain will be "disabled." - * Only needed for clocks that don't use omap2_dflt_clk_disable() as their - * disable function pointer. No return value. - */ -void omap2_clkops_disable_clkdm(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - - clk = to_clk_hw_omap(hw); - - if (unlikely(!clk->clkdm)) { - pr_err("%s: %s: no clkdm set ?!\n", __func__, - __clk_get_name(hw->clk)); - return; - } - - if (unlikely(clk->enable_reg)) - pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__, - __clk_get_name(hw->clk)); - - if (!clkdm_control) { - pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", - __func__, __clk_get_name(hw->clk)); - return; - } - - clkdm_clk_disable(clk->clkdm, hw->clk); -} - -/** - * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? - * @hw: struct clk_hw * to check - * - * Return 1 if the clock represented by @hw is enabled in the - * hardware, or 0 otherwise. Intended for use in the struct - * clk_ops.is_enabled function pointer. - */ -int omap2_dflt_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - u32 v; - - v = omap2_clk_readl(clk, clk->enable_reg); - - if (clk->flags & INVERT_ENABLE) - v ^= BIT(clk->enable_bit); - - v &= BIT(clk->enable_bit); - - return v ? 1 : 0; -} - static int __initdata mpurate; /* @@ -585,178 +133,6 @@ static int __init omap_clk_setup(char *str) __setup("mpurate=", omap_clk_setup); /** - * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock - * @clk: struct clk * to initialize - * - * Add an OMAP clock @clk to the internal list of OMAP clocks. Used - * temporarily for autoidle handling, until this support can be - * integrated into the common clock framework code in some way. No - * return value. - */ -void omap2_init_clk_hw_omap_clocks(struct clk *clk) -{ - struct clk_hw_omap *c; - - if (__clk_get_flags(clk) & CLK_IS_BASIC) - return; - - c = to_clk_hw_omap(__clk_get_hw(clk)); - list_add(&c->node, &clk_hw_omap_clocks); -} - -/** - * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that - * support it - * - * Enable clock autoidle on all OMAP clocks that have allow_idle - * function pointers associated with them. This function is intended - * to be temporary until support for this is added to the common clock - * code. Returns 0. - */ -int omap2_clk_enable_autoidle_all(void) -{ - struct clk_hw_omap *c; - - list_for_each_entry(c, &clk_hw_omap_clocks, node) - if (c->ops && c->ops->allow_idle) - c->ops->allow_idle(c); - - of_ti_clk_allow_autoidle_all(); - - return 0; -} - -/** - * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that - * support it - * - * Disable clock autoidle on all OMAP clocks that have allow_idle - * function pointers associated with them. This function is intended - * to be temporary until support for this is added to the common clock - * code. Returns 0. - */ -int omap2_clk_disable_autoidle_all(void) -{ - struct clk_hw_omap *c; - - list_for_each_entry(c, &clk_hw_omap_clocks, node) - if (c->ops && c->ops->deny_idle) - c->ops->deny_idle(c); - - of_ti_clk_deny_autoidle_all(); - - return 0; -} - -/** - * omap2_clk_deny_idle - disable autoidle on an OMAP clock - * @clk: struct clk * to disable autoidle for - * - * Disable autoidle on an OMAP clock. - */ -int omap2_clk_deny_idle(struct clk *clk) -{ - struct clk_hw_omap *c; - - if (__clk_get_flags(clk) & CLK_IS_BASIC) - return -EINVAL; - - c = to_clk_hw_omap(__clk_get_hw(clk)); - if (c->ops && c->ops->deny_idle) - c->ops->deny_idle(c); - return 0; -} - -/** - * omap2_clk_allow_idle - enable autoidle on an OMAP clock - * @clk: struct clk * to enable autoidle for - * - * Enable autoidle on an OMAP clock. - */ -int omap2_clk_allow_idle(struct clk *clk) -{ - struct clk_hw_omap *c; - - if (__clk_get_flags(clk) & CLK_IS_BASIC) - return -EINVAL; - - c = to_clk_hw_omap(__clk_get_hw(clk)); - if (c->ops && c->ops->allow_idle) - c->ops->allow_idle(c); - return 0; -} - -/** - * omap2_clk_enable_init_clocks - prepare & enable a list of clocks - * @clk_names: ptr to an array of strings of clock names to enable - * @num_clocks: number of clock names in @clk_names - * - * Prepare and enable a list of clocks, named by @clk_names. No - * return value. XXX Deprecated; only needed until these clocks are - * properly claimed and enabled by the drivers or core code that uses - * them. XXX What code disables & calls clk_put on these clocks? - */ -void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks) -{ - struct clk *init_clk; - int i; - - for (i = 0; i < num_clocks; i++) { - init_clk = clk_get(NULL, clk_names[i]); - if (WARN(IS_ERR(init_clk), "could not find init clock %s\n", - clk_names[i])) - continue; - clk_prepare_enable(init_clk); - } -} - -const struct clk_hw_omap_ops clkhwops_wait = { - .find_idlest = omap2_clk_dflt_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -/** - * omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument - * @mpurate_ck_name: clk name of the clock to change rate - * - * Change the ARM MPU clock rate to the rate specified on the command - * line, if one was specified. @mpurate_ck_name should be - * "virt_prcm_set" on OMAP2xxx and "dpll1_ck" on OMAP34xx/OMAP36xx. - * XXX Does not handle voltage scaling - on OMAP2xxx this is currently - * handled by the virt_prcm_set clock, but this should be handled by - * the OPP layer. XXX This is intended to be handled by the OPP layer - * code in the near future and should be removed from the clock code. - * Returns -EINVAL if 'mpurate' is zero or if clk_set_rate() rejects - * the rate, -ENOENT if the struct clk referred to by @mpurate_ck_name - * cannot be found, or 0 upon success. - */ -int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name) -{ - struct clk *mpurate_ck; - int r; - - if (!mpurate) - return -EINVAL; - - mpurate_ck = clk_get(NULL, mpurate_ck_name); - if (WARN(IS_ERR(mpurate_ck), "Failed to get %s.\n", mpurate_ck_name)) - return -ENOENT; - - r = clk_set_rate(mpurate_ck, mpurate); - if (r < 0) { - WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n", - mpurate_ck_name, mpurate, r); - clk_put(mpurate_ck); - return -EINVAL; - } - - calibrate_delay(); - clk_put(mpurate_ck); - - return 0; -} - -/** * omap2_clk_print_new_rates - print summary of current clock tree rates * @hfclkin_ck_name: clk name for the off-chip HF oscillator * @core_ck_name: clk name for the on-chip CORE_CLK @@ -802,29 +178,30 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name, */ void __init ti_clk_init_features(void) { + struct ti_clk_features features = { 0 }; /* Fint setup for DPLLs */ if (cpu_is_omap3430()) { - ti_clk_features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN; - ti_clk_features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX; - ti_clk_features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX; - ti_clk_features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN; + features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN; + features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX; + features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX; + features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN; } else { - ti_clk_features.fint_min = OMAP3PLUS_DPLL_FINT_MIN; - ti_clk_features.fint_max = OMAP3PLUS_DPLL_FINT_MAX; + features.fint_min = OMAP3PLUS_DPLL_FINT_MIN; + features.fint_max = OMAP3PLUS_DPLL_FINT_MAX; } /* Bypass value setup for DPLLs */ if (cpu_is_omap24xx()) { - ti_clk_features.dpll_bypass_vals |= + features.dpll_bypass_vals |= (1 << OMAP2XXX_EN_DPLL_LPBYPASS) | (1 << OMAP2XXX_EN_DPLL_FRBYPASS); } else if (cpu_is_omap34xx()) { - ti_clk_features.dpll_bypass_vals |= + features.dpll_bypass_vals |= (1 << OMAP3XXX_EN_DPLL_LPBYPASS) | (1 << OMAP3XXX_EN_DPLL_FRBYPASS); } else if (soc_is_am33xx() || cpu_is_omap44xx() || soc_is_am43xx() || soc_is_omap54xx() || soc_is_dra7xx()) { - ti_clk_features.dpll_bypass_vals |= + features.dpll_bypass_vals |= (1 << OMAP4XXX_EN_DPLL_LPBYPASS) | (1 << OMAP4XXX_EN_DPLL_FRBYPASS) | (1 << OMAP4XXX_EN_DPLL_MNBYPASS); @@ -832,7 +209,7 @@ void __init ti_clk_init_features(void) /* Jitter correction only available on OMAP343X */ if (cpu_is_omap343x()) - ti_clk_features.flags |= TI_CLK_DPLL_HAS_FREQSEL; + features.flags |= TI_CLK_DPLL_HAS_FREQSEL; /* Idlest value for interface clocks. * 24xx uses 0 to indicate not ready, and 1 to indicate ready. @@ -840,11 +217,13 @@ void __init ti_clk_init_features(void) * AM35xx uses both, depending on the module. */ if (cpu_is_omap24xx()) - ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; + features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; else if (cpu_is_omap34xx()) - ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; + features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */ if (omap_rev() == OMAP3430_REV_ES1_0) - ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; + features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; + + ti_clk_setup_features(&features); } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 652ed0a..67da640 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -23,90 +23,6 @@ #include <linux/clk-provider.h> #include <linux/clk/ti.h> -struct omap_clk { - u16 cpu; - struct clk_lookup lk; -}; - -#define CLK(dev, con, ck) \ - { \ - .lk = { \ - .dev_id = dev, \ - .con_id = con, \ - .clk = ck, \ - }, \ - } - -struct clockdomain; - -#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \ - static struct clk_core _name##_core = { \ - .name = #_name, \ - .hw = &_name##_hw.hw, \ - .parent_names = _parent_array_name, \ - .num_parents = ARRAY_SIZE(_parent_array_name), \ - .ops = &_clkops_name, \ - }; \ - static struct clk _name = { \ - .core = &_name##_core, \ - }; - -#define DEFINE_STRUCT_CLK_FLAGS(_name, _parent_array_name, \ - _clkops_name, _flags) \ - static struct clk_core _name##_core = { \ - .name = #_name, \ - .hw = &_name##_hw.hw, \ - .parent_names = _parent_array_name, \ - .num_parents = ARRAY_SIZE(_parent_array_name), \ - .ops = &_clkops_name, \ - .flags = _flags, \ - }; \ - static struct clk _name = { \ - .core = &_name##_core, \ - }; - -#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name) \ - static struct clk_hw_omap _name##_hw = { \ - .hw = { \ - .clk = &_name, \ - }, \ - .clkdm_name = _clkdm_name, \ - }; - -#define DEFINE_CLK_OMAP_MUX(_name, _clkdm_name, _clksel, \ - _clksel_reg, _clksel_mask, \ - _parent_names, _ops) \ - static struct clk _name; \ - static struct clk_hw_omap _name##_hw = { \ - .hw = { \ - .clk = &_name, \ - }, \ - .clksel = _clksel, \ - .clksel_reg = _clksel_reg, \ - .clksel_mask = _clksel_mask, \ - .clkdm_name = _clkdm_name, \ - }; \ - DEFINE_STRUCT_CLK(_name, _parent_names, _ops); - -#define DEFINE_CLK_OMAP_MUX_GATE(_name, _clkdm_name, _clksel, \ - _clksel_reg, _clksel_mask, \ - _enable_reg, _enable_bit, \ - _hwops, _parent_names, _ops) \ - static struct clk _name; \ - static struct clk_hw_omap _name##_hw = { \ - .hw = { \ - .clk = &_name, \ - }, \ - .ops = _hwops, \ - .enable_reg = _enable_reg, \ - .enable_bit = _enable_bit, \ - .clksel = _clksel, \ - .clksel_reg = _clksel_reg, \ - .clksel_mask = _clksel_mask, \ - .clkdm_name = _clkdm_name, \ - }; \ - DEFINE_STRUCT_CLK(_name, _parent_names, _ops); - /* struct clksel_rate.flags possibilities */ #define RATE_IN_242X (1 << 0) #define RATE_IN_243X (1 << 1) @@ -127,38 +43,6 @@ struct clockdomain; /* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */ #define RATE_IN_3430ES2PLUS_36XX (RATE_IN_3430ES2PLUS | RATE_IN_36XX) - -/** - * struct clksel_rate - register bitfield values corresponding to clk divisors - * @val: register bitfield value (shifted to bit 0) - * @div: clock divisor corresponding to @val - * @flags: (see "struct clksel_rate.flags possibilities" above) - * - * @val should match the value of a read from struct clk.clksel_reg - * AND'ed with struct clk.clksel_mask, shifted right to bit 0. - * - * @div is the divisor that should be applied to the parent clock's rate - * to produce the current clock's rate. - */ -struct clksel_rate { - u32 val; - u8 div; - u16 flags; -}; - -/** - * struct clksel - available parent clocks, and a pointer to their divisors - * @parent: struct clk * to a possible parent clock - * @rates: available divisors for this parent clock - * - * A struct clksel is always associated with one or more struct clks - * and one or more struct clksel_rates. - */ -struct clksel { - struct clk *parent; - const struct clksel_rate *rates; -}; - /* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */ #define CORE_CLK_SRC_32K 0x0 #define CORE_CLK_SRC_DPLL 0x1 @@ -180,105 +64,18 @@ struct clksel { #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 #define OMAP4XXX_EN_DPLL_LOCKED 0x7 -u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); -void omap3_dpll_allow_idle(struct clk_hw_omap *clk); -void omap3_dpll_deny_idle(struct clk_hw_omap *clk); -void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); -void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); - -void __init omap2_clk_disable_clkdm_control(void); - -/* clkt_clksel.c public functions */ -u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk, - unsigned long target_rate, - u32 *new_div); -u8 omap2_clksel_find_parent_index(struct clk_hw *hw); -unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate); -long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate); -int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); - -/* clkt_iclk.c public functions */ -extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); -extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); - -unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); - -void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, - u8 *other_bit); -void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, u8 *idlest_val); -int omap2_clk_enable_autoidle_all(void); -int omap2_clk_allow_idle(struct clk *clk); -int omap2_clk_deny_idle(struct clk *clk); -int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name); void omap2_clk_print_new_rates(const char *hfclkin_ck_name, const char *core_ck_name, const char *mpu_ck_name); -u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg); -void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg); - extern u16 cpu_mask; -/* - * Clock features setup. Used instead of CPU type checks. - */ -struct ti_clk_features { - u32 flags; - long fint_min; - long fint_max; - long fint_band1_max; - long fint_band2_min; - u8 dpll_bypass_vals; - u8 cm_idlest_val; -}; - -#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) -#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1) - -extern struct ti_clk_features ti_clk_features; - extern const struct clkops clkops_omap2_dflt_wait; extern const struct clkops clkops_omap2_dflt; extern struct clk_functions omap2_clk_functions; -extern const struct clksel_rate gpt_32k_rates[]; -extern const struct clksel_rate gpt_sys_rates[]; -extern const struct clksel_rate gfx_l3_rates[]; -extern const struct clksel_rate dsp_ick_rates[]; - -extern const struct clk_hw_omap_ops clkhwops_iclk_wait; -extern const struct clk_hw_omap_ops clkhwops_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -extern const struct clk_hw_omap_ops clkhwops_apll54; -extern const struct clk_hw_omap_ops clkhwops_apll96; - -/* clksel_rate blocks shared between OMAP44xx and AM33xx */ -extern const struct clksel_rate div_1_0_rates[]; -extern const struct clksel_rate div3_1to4_rates[]; -extern const struct clksel_rate div_1_1_rates[]; -extern const struct clksel_rate div_1_2_rates[]; -extern const struct clksel_rate div_1_3_rates[]; -extern const struct clksel_rate div_1_4_rates[]; -extern const struct clksel_rate div31_1to31_rates[]; - -extern int omap2_clkops_enable_clkdm(struct clk_hw *hw); -extern void omap2_clkops_disable_clkdm(struct clk_hw *hw); - -struct regmap; - -int __init omap2_clk_provider_init(struct device_node *np, int index, - struct regmap *syscon, void __iomem *mem); -void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem); +int __init omap2_clk_setup_ll_ops(void); void __init ti_clk_init_features(void); #endif diff --git a/arch/arm/mach-omap2/clock2430.c b/arch/arm/mach-omap2/clock2430.c deleted file mode 100644 index cef0c8d..0000000 --- a/arch/arm/mach-omap2/clock2430.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * clock2430.c - OMAP2430-specific clock integration code - * - * Copyright (C) 2005-2008 Texas Instruments, Inc. - * Copyright (C) 2004-2010 Nokia Corporation - * - * Contacts: - * Richard Woodruff <r-woodruff2@ti.com> - * Paul Walmsley - * - * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, - * Gordon McNutt and RidgeRun, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include "soc.h" -#include "iomap.h" -#include "clock.h" -#include "clock2xxx.h" -#include "cm2xxx.h" -#include "cm-regbits-24xx.h" - -/** - * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the - * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function - * passes back the correct CM_IDLEST register address for I2CHS - * modules. No return value. - */ -static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - *idlest_reg = OMAP2430_CM_REGADDR(CORE_MOD, CM_IDLEST); - *idlest_bit = clk->enable_bit; - *idlest_val = OMAP24XX_CM_IDLEST_VAL; -} - -/* 2430 I2CHS has non-standard IDLEST register */ -const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = { - .find_idlest = omap2430_clk_i2chs_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c deleted file mode 100644 index b870f6a..0000000 --- a/arch/arm/mach-omap2/clock2xxx.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * clock2xxx.c - OMAP2xxx-specific clock integration code - * - * Copyright (C) 2005-2008 Texas Instruments, Inc. - * Copyright (C) 2004-2010 Nokia Corporation - * - * Contacts: - * Richard Woodruff <r-woodruff2@ti.com> - * Paul Walmsley - * - * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, - * Gordon McNutt and RidgeRun, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include "soc.h" -#include "clock.h" -#include "clock2xxx.h" -#include "cm.h" -#include "cm-regbits-24xx.h" - -struct clk_hw *dclk_hw; -/* - * Omap24xx specific clock functions - */ - -/* - * Switch the MPU rate if specified on cmdline. We cannot do this - * early until cmdline is parsed. XXX This should be removed from the - * clock code and handled by the OPP layer code in the near future. - */ -static int __init omap2xxx_clk_arch_init(void) -{ - int ret; - - if (!cpu_is_omap24xx()) - return 0; - - ret = omap2_clk_switch_mpurate_at_boot("virt_prcm_set"); - if (!ret) - omap2_clk_print_new_rates("sys_ck", "dpll_ck", "mpu_ck"); - - return ret; -} - -omap_arch_initcall(omap2xxx_clk_arch_init); - - diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c deleted file mode 100644 index 4596468..0000000 --- a/arch/arm/mach-omap2/clock34xx.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * OMAP3-specific clock framework functions - * - * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2011 Nokia Corporation - * - * Paul Walmsley - * Jouni Högander - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu, - * Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include "clock.h" -#include "clock34xx.h" -#include "cm3xxx.h" -#include "cm-regbits-34xx.h" - -/** - * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift - * from the CM_{I,F}CLKEN bit. Pass back the correct info via - * @idlest_reg and @idlest_bit. No return value. - */ -static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} -const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = { - .find_idlest = omap3430es2_clk_ssi_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap3430es2_clk_ssi_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -/** - * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * Some OMAP modules on OMAP3 ES2+ chips have both initiator and - * target IDLEST bits. For our purposes, we are concerned with the - * target IDLEST bits, which exist at a different bit position than - * the *CLKEN bit position for these modules (DSS and USBHOST) (The - * default find_idlest code assumes that they are at the same - * position.) No return value. - */ -static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - /* USBHOST_IDLE has same shift */ - *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} - -const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = { - .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -/** - * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different - * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via - * @idlest_reg and @idlest_bit. No return value. - */ -static void omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} - -const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = { - .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h deleted file mode 100644 index 084ba71..0000000 --- a/arch/arm/mach-omap2/clock34xx.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * OMAP34xx clock function prototypes and macros - * - * Copyright (C) 2007-2010 Texas Instruments, Inc. - * Copyright (C) 2007-2011 Nokia Corporation - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H -#define __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H - -extern const struct clkops clkops_omap3430es2_ssi_wait; -extern const struct clkops clkops_omap3430es2_iclk_ssi_wait; -extern const struct clkops clkops_omap3430es2_hsotgusb_wait; -extern const struct clkops clkops_omap3430es2_iclk_hsotgusb_wait; -extern const struct clkops clkops_omap3430es2_dss_usbhost_wait; -extern const struct clkops clkops_omap3430es2_iclk_dss_usbhost_wait; - -#endif diff --git a/arch/arm/mach-omap2/clock3517.c b/arch/arm/mach-omap2/clock3517.c deleted file mode 100644 index 4d79ae2..0000000 --- a/arch/arm/mach-omap2/clock3517.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * OMAP3517/3505-specific clock framework functions - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Copyright (C) 2011 Nokia Corporation - * - * Ranjith Lohithakshan - * Paul Walmsley - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu, - * Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include "clock.h" -#include "clock3517.h" -#include "cm3xxx.h" -#include "cm-regbits-34xx.h" - -/* - * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported - * in the same register at a bit offset of 0x8. The EN_ACK for ICK is - * at an offset of 4 from ICK enable bit. - */ -#define AM35XX_IPSS_ICK_MASK 0xF -#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4 -#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8 -#define AM35XX_IPSS_CLK_IDLEST_VAL 0 - -/** - * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The interface clocks on AM35xx IPSS reflects the clock idle status - * in the enable register itsel at a bit offset of 4 from the enable - * bit. A value of 1 indicates that clock is enabled. - */ -static void am35xx_clk_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - *idlest_reg = (__force void __iomem *)(clk->enable_reg); - *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET; - *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL; -} - -/** - * am35xx_clk_find_companion - find companion clock to @clk - * @clk: struct clk * to find the companion clock of - * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in - * @other_bit: u8 ** to return the companion clock bit shift in - * - * Some clocks don't have companion clocks. For example, modules with - * only an interface clock (such as HECC) don't have a companion - * clock. Right now, this code relies on the hardware exporting a bit - * in the correct companion register that indicates that the - * nonexistent 'companion clock' is active. Future patches will - * associate this type of code with per-module data structures to - * avoid this issue, and remove the casts. No return value. - */ -static void am35xx_clk_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, - u8 *other_bit) -{ - *other_reg = (__force void __iomem *)(clk->enable_reg); - if (clk->enable_bit & AM35XX_IPSS_ICK_MASK) - *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET; - else - *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET; -} -const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = { - .find_idlest = am35xx_clk_find_idlest, - .find_companion = am35xx_clk_find_companion, -}; - -/** - * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The IPSS target CM_IDLEST bit is at a different shift from the - * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg - * and @idlest_bit. No return value. - */ -static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = AM35XX_ST_IPSS_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} - -const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = am35xx_clk_ipss_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; diff --git a/arch/arm/mach-omap2/clock3517.h b/arch/arm/mach-omap2/clock3517.h deleted file mode 100644 index ca5e5a6..0000000 --- a/arch/arm/mach-omap2/clock3517.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * OMAP3517/3505 clock function prototypes and macros - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Copyright (C) 2010 Nokia Corporation - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK3517_H -#define __ARCH_ARM_MACH_OMAP2_CLOCK3517_H - -extern const struct clkops clkops_am35xx_ipss_module_wait; -extern const struct clkops clkops_am35xx_ipss_wait; - -#endif diff --git a/arch/arm/mach-omap2/clock36xx.c b/arch/arm/mach-omap2/clock36xx.c deleted file mode 100644 index 91ccb96..0000000 --- a/arch/arm/mach-omap2/clock36xx.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * OMAP36xx-specific clkops - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Copyright (C) 2010 Nokia Corporation - * - * Mike Turquette - * Vijaykumar GN - * Paul Walmsley - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu, - * Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/io.h> - -#include "clock.h" -#include "clock36xx.h" -#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) - -/** - * omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering - * from HSDivider PWRDN problem Implements Errata ID: i556. - * @clk: DPLL output struct clk - * - * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, - * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset - * valueafter their respective PWRDN bits are set. Any dummy write - * (Any other value different from the Read value) to the - * corresponding CM_CLKSEL register will refresh the dividers. - */ -int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk) -{ - struct clk_divider *parent; - struct clk_hw *parent_hw; - u32 dummy_v, orig_v; - struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk); - int ret; - - /* Clear PWRDN bit of HSDIVIDER */ - ret = omap2_dflt_clk_enable(clk); - - parent_hw = __clk_get_hw(__clk_get_parent(clk->clk)); - parent = to_clk_divider(parent_hw); - - /* Restore the dividers */ - if (!ret) { - orig_v = omap2_clk_readl(omap_clk, parent->reg); - dummy_v = orig_v; - - /* Write any other value different from the Read value */ - dummy_v ^= (1 << parent->shift); - omap2_clk_writel(dummy_v, omap_clk, parent->reg); - - /* Write the original divider */ - omap2_clk_writel(orig_v, omap_clk, parent->reg); - } - - return ret; -} diff --git a/arch/arm/mach-omap2/clock36xx.h b/arch/arm/mach-omap2/clock36xx.h deleted file mode 100644 index 945bb7f..0000000 --- a/arch/arm/mach-omap2/clock36xx.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * OMAP36xx clock function prototypes and macros - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Copyright (C) 2010 Nokia Corporation - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK36XX_H -#define __ARCH_ARM_MACH_OMAP2_CLOCK36XX_H - -extern int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *hw); - -#endif diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c deleted file mode 100644 index a9e86db..0000000 --- a/arch/arm/mach-omap2/clock3xxx.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * OMAP3-specific clock framework functions - * - * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2010 Nokia Corporation - * - * Paul Walmsley - * Jouni Högander - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include "soc.h" -#include "clock.h" -#include "clock3xxx.h" -#include "prm2xxx_3xxx.h" -#include "prm-regbits-34xx.h" -#include "cm2xxx_3xxx.h" -#include "cm-regbits-34xx.h" - -/* - * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks - * that are sourced by DPLL5, and both of these require this clock - * to be at 120 MHz for proper operation. - */ -#define DPLL5_FREQ_FOR_USBHOST 120000000 - -/* needed by omap3_core_dpll_m2_set_rate() */ -struct clk *sdrc_ick_p, *arm_fck_p; - -/** - * omap3_dpll4_set_rate - set rate for omap3 per-dpll - * @hw: clock to change - * @rate: target rate for clock - * @parent_rate: rate of the parent clock - * - * Check if the current SoC supports the per-dpll reprogram operation - * or not, and then do the rate change if supported. Returns -EINVAL - * if not supported, 0 for success, and potential error codes from the - * clock rate change. - */ -int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - /* - * According to the 12-5 CDP code from TI, "Limitation 2.5" - * on 3430ES1 prevents us from changing DPLL multipliers or dividers - * on DPLL4. - */ - if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { - pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); - return -EINVAL; - } - - return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); -} - -/** - * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll - * @hw: clock to change - * @rate: target rate for clock - * @parent_rate: rate of the parent clock - * @index: parent index, 0 - reference clock, 1 - bypass clock - * - * Check if the current SoC support the per-dpll reprogram operation - * or not, and then do the rate + parent change if supported. Returns - * -EINVAL if not supported, 0 for success, and potential error codes - * from the clock rate change. - */ -int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate, u8 index) -{ - if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { - pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); - return -EINVAL; - } - - return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, - index); -} - -void __init omap3_clk_lock_dpll5(void) -{ - struct clk *dpll5_clk; - struct clk *dpll5_m2_clk; - - dpll5_clk = clk_get(NULL, "dpll5_ck"); - clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); - clk_prepare_enable(dpll5_clk); - - /* Program dpll5_m2_clk divider for no division */ - dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); - clk_prepare_enable(dpll5_m2_clk); - clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST); - - clk_disable_unprepare(dpll5_m2_clk); - clk_disable_unprepare(dpll5_clk); - return; -} - -/* Common clock code */ - -/* - * Switch the MPU rate if specified on cmdline. We cannot do this - * early until cmdline is parsed. XXX This should be removed from the - * clock code and handled by the OPP layer code in the near future. - */ -static int __init omap3xxx_clk_arch_init(void) -{ - int ret; - - if (!cpu_is_omap34xx()) - return 0; - - ret = omap2_clk_switch_mpurate_at_boot("dpll1_ck"); - if (!ret) - omap2_clk_print_new_rates("osc_sys_ck", "core_ck", "arm_fck"); - - return ret; -} - -omap_arch_initcall(omap3xxx_clk_arch_init); - - diff --git a/arch/arm/mach-omap2/clock44xx.h b/arch/arm/mach-omap2/clock44xx.h deleted file mode 100644 index 287a46f..0000000 --- a/arch/arm/mach-omap2/clock44xx.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * OMAP4 clock function prototypes and macros - * - * Copyright (C) 2009 Texas Instruments, Inc. - * Copyright (C) 2010 Nokia Corporation - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H -#define __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H - -/* - * OMAP4430_REGM4XEN_MULT: If the CM_CLKMODE_DPLL_ABE.DPLL_REGM4XEN bit is - * set, then the DPLL's lock frequency is multiplied by 4 (OMAP4430 TRM - * vV Section 3.6.3.3.1 "DPLLs Output Clocks Parameters") - */ -#define OMAP4430_REGM4XEN_MULT 4 - -int omap4xxx_clk_init(void); - -#endif diff --git a/arch/arm/mach-omap2/clock_common_data.c b/arch/arm/mach-omap2/clock_common_data.c deleted file mode 100644 index 61b60df..0000000 --- a/arch/arm/mach-omap2/clock_common_data.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * linux/arch/arm/mach-omap2/clock_common_data.c - * - * Copyright (C) 2005-2009 Texas Instruments, Inc. - * Copyright (C) 2004-2009 Nokia Corporation - * - * Contacts: - * Richard Woodruff <r-woodruff2@ti.com> - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This file contains clock data that is common to both the OMAP2xxx and - * OMAP3xxx clock definition files. - */ - -#include "clock.h" - -/* clksel_rate data common to 24xx/343x */ -const struct clksel_rate gpt_32k_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_24XX | RATE_IN_3XXX }, - { .div = 0 } -}; - -const struct clksel_rate gpt_sys_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_24XX | RATE_IN_3XXX }, - { .div = 0 } -}; - -const struct clksel_rate gfx_l3_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_24XX | RATE_IN_3XXX }, - { .div = 2, .val = 2, .flags = RATE_IN_24XX | RATE_IN_3XXX }, - { .div = 3, .val = 3, .flags = RATE_IN_243X | RATE_IN_3XXX }, - { .div = 4, .val = 4, .flags = RATE_IN_243X | RATE_IN_3XXX }, - { .div = 0 } -}; - -const struct clksel_rate dsp_ick_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_24XX }, - { .div = 2, .val = 2, .flags = RATE_IN_24XX }, - { .div = 3, .val = 3, .flags = RATE_IN_243X }, - { .div = 0 }, -}; - - -/* clksel_rate blocks shared between OMAP44xx and AM33xx */ - -const struct clksel_rate div_1_0_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 0 }, -}; - -const struct clksel_rate div3_1to4_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 }, - { .div = 2, .val = 1, .flags = RATE_IN_4430 }, - { .div = 4, .val = 2, .flags = RATE_IN_4430 }, - { .div = 0 }, -}; - -const struct clksel_rate div_1_1_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 0 }, -}; - -const struct clksel_rate div_1_2_rates[] = { - { .div = 1, .val = 2, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 0 }, -}; - -const struct clksel_rate div_1_3_rates[] = { - { .div = 1, .val = 3, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 0 }, -}; - -const struct clksel_rate div_1_4_rates[] = { - { .div = 1, .val = 4, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 0 }, -}; - -const struct clksel_rate div31_1to31_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 2, .val = 2, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 3, .val = 3, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 4, .val = 4, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 5, .val = 5, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 6, .val = 6, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 7, .val = 7, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 8, .val = 8, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 9, .val = 9, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 10, .val = 10, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 11, .val = 11, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 12, .val = 12, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 13, .val = 13, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 14, .val = 14, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 15, .val = 15, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 16, .val = 16, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 17, .val = 17, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 18, .val = 18, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 19, .val = 19, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 20, .val = 20, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 21, .val = 21, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 22, .val = 22, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 23, .val = 23, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 24, .val = 24, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 25, .val = 25, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 26, .val = 26, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 27, .val = 27, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 28, .val = 28, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 29, .val = 29, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 30, .val = 30, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 31, .val = 31, .flags = RATE_IN_4430 | RATE_IN_AM33XX }, - { .div = 0 }, -}; diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 820dde8..a253aaf 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -37,7 +37,6 @@ #include "clock.h" #include "clock2xxx.h" #include "clock3xxx.h" -#include "clock44xx.h" #include "omap-pm.h" #include "sdrc.h" #include "control.h" @@ -723,6 +722,8 @@ int __init omap_clk_init(void) ti_clk_init_features(); + omap2_clk_setup_ll_ops(); + if (of_have_populated_dt()) { ret = omap_control_init(); if (ret) diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index 5168c4d..5a62b18 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -390,10 +390,9 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate, return div1; } -static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk, - int scale, int maxdiv) +static int alchemy_clk_fgcs_detr(struct clk_hw *hw, + struct clk_rate_request *req, + int scale, int maxdiv) { struct clk *pc, *bpc, *free; long tdv, tpr, pr, nr, br, bpr, diff, lastdiff; @@ -423,14 +422,14 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } pr = clk_get_rate(pc); - if (pr < rate) + if (pr < req->rate) continue; /* what can hardware actually provide */ - tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL); nr = pr / tdv; - diff = rate - nr; - if (nr > rate) + diff = req->rate - nr; + if (nr > req->rate) continue; if (diff < lastdiff) { @@ -449,15 +448,16 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, */ if (lastdiff && free) { for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) { - tpr = rate * j; + tpr = req->rate * j; if (tpr < 0) break; pr = clk_round_rate(free, tpr); - tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, + NULL); nr = pr / tdv; - diff = rate - nr; - if (nr > rate) + diff = req->rate - nr; + if (nr > req->rate) continue; if (diff < lastdiff) { lastdiff = diff; @@ -470,9 +470,14 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } } - *best_parent_rate = bpr; - *best_parent_clk = __clk_get_hw(bpc); - return br; + if (br < 0) + return br; + + req->best_parent_rate = bpr; + req->best_parent_hw = __clk_get_hw(bpc); + req->rate = br; + + return 0; } static int alchemy_clk_fgv1_en(struct clk_hw *hw) @@ -563,14 +568,10 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw, return parent_rate / v; } -static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_fgv1_detr(struct clk_hw *hw, + struct clk_rate_request *req) { - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, 2, 512); + return alchemy_clk_fgcs_detr(hw, req, 2, 512); } /* Au1000, Au1100, Au15x0, Au12x0 */ @@ -697,11 +698,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw, return t; } -static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_fgv2_detr(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale, maxdiv; @@ -714,8 +712,7 @@ static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, maxdiv = 512; } - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, scale, maxdiv); + return alchemy_clk_fgcs_detr(hw, req, scale, maxdiv); } /* Au1300 larger input mux, no separate disable bit, flexible divider */ @@ -918,17 +915,13 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, return 0; } -static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_csrc_detr(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */ - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, scale, 4); + return alchemy_clk_fgcs_detr(hw, req, scale, 4); } static struct clk_ops alchemy_clkops_csrc = { diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index c4cf075..d08b3e5 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o -obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o +obj-$(CONFIG_COMMON_CLK) += clk-gpio.o ifeq ($(CONFIG_OF), y) obj-$(CONFIG_COMMON_CLK) += clk-conf.o endif diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 152dcb3..61566bc 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -116,8 +116,10 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, h32mxclk->pmc = pmc; clk = clk_register(NULL, &h32mxclk->hw); - if (!clk) + if (!clk) { + kfree(h32mxclk); return; + } of_clk_add_provider(np, of_clk_src_simple_get, clk); } diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index c240045..fd7247d 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -171,8 +171,10 @@ at91_clk_register_main_osc(struct at91_pmc *pmc, irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); ret = request_irq(osc->irq, clk_main_osc_irq_handler, IRQF_TRIGGER_HIGH, name, osc); - if (ret) + if (ret) { + kfree(osc); return ERR_PTR(ret); + } if (bypass) pmc_write(pmc, AT91_CKGR_MOR, @@ -612,17 +614,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np, int num_parents; unsigned int irq; const char *name = np->name; - int i; num_parents = of_clk_get_parent_count(np); if (num_parents <= 0 || num_parents > 2) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index f98eafe..620ea32 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -165,12 +165,16 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, irq_set_status_flags(master->irq, IRQ_NOAUTOEN); ret = request_irq(master->irq, clk_master_irq_handler, IRQF_TRIGGER_HIGH, "clk-master", master); - if (ret) + if (ret) { + kfree(master); return ERR_PTR(ret); + } clk = clk_register(NULL, &master->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(master->irq, master); kfree(master); + } return clk; } @@ -218,7 +222,6 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, { struct clk *clk; int num_parents; - int i; unsigned int irq; const char *parent_names[MASTER_SOURCE_MAX]; const char *name = np->name; @@ -228,11 +231,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index cbbe403..18b60f4 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -346,12 +346,16 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, id ? "clk-pllb" : "clk-plla", pll); - if (ret) + if (ret) { + kfree(pll); return ERR_PTR(ret); + } clk = clk_register(NULL, &pll->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(pll->irq, pll); kfree(pll); + } return clk; } diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 8c86c0f7..ce9c3b9 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -54,12 +54,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, return parent_rate >> pres; } -static long clk_programmable_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int clk_programmable_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -76,24 +72,29 @@ static long clk_programmable_determine_rate(struct clk_hw *hw, parent_rate = __clk_get_rate(parent); for (shift = 0; shift < PROG_PRES_MASK; shift++) { tmp_rate = parent_rate >> shift; - if (tmp_rate <= rate) + if (tmp_rate <= req->rate) break; } - if (tmp_rate > rate) + if (tmp_rate > req->rate) continue; - if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) { + if (best_rate < 0 || + (req->rate - tmp_rate) < (req->rate - best_rate)) { best_rate = tmp_rate; - *best_parent_rate = parent_rate; - *best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); } if (!best_rate) break; } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; } static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) @@ -230,7 +231,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, { int num; u32 id; - int i; struct clk *clk; int num_parents; const char *parent_names[PROG_SOURCE_MAX]; @@ -241,11 +241,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); num = of_get_child_count(np); if (!num || num > (PROG_ID_MAX + 1)) diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index 0a7aef3..d0d5076 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -373,17 +373,12 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, const char *parent_names[2]; int num_parents; const char *name = np->name; - int i; num_parents = of_clk_get_parent_count(np); if (num_parents <= 0 || num_parents > 2) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); @@ -451,17 +446,12 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np, const char *parent_names[2]; int num_parents; const char *name = np->name; - int i; num_parents = of_clk_get_parent_count(np); if (num_parents != 2) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c index 3817ea8..a7f8501 100644 --- a/drivers/clk/at91/clk-smd.c +++ b/drivers/clk/at91/clk-smd.c @@ -145,7 +145,6 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, struct at91_pmc *pmc) { struct clk *clk; - int i; int num_parents; const char *parent_names[SMD_SOURCE_MAX]; const char *name = np->name; @@ -154,11 +153,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) return; - for (i = 0; i < num_parents; i++) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index a76d03f..58008b3 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c @@ -130,13 +130,17 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, irq_set_status_flags(sys->irq, IRQ_NOAUTOEN); ret = request_irq(sys->irq, clk_system_irq_handler, IRQF_TRIGGER_HIGH, name, sys); - if (ret) + if (ret) { + kfree(sys); return ERR_PTR(ret); + } } clk = clk_register(NULL, &sys->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(sys->irq, sys); kfree(sys); + } return clk; } diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index b0cbd2b..1fdf0e3 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -56,12 +56,8 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); } -static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -80,23 +76,23 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) { unsigned long tmp_parent_rate; - tmp_parent_rate = rate * div; + tmp_parent_rate = req->rate * div; tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); - if (tmp_rate < rate) - tmp_diff = rate - tmp_rate; + if (tmp_rate < req->rate) + tmp_diff = req->rate - tmp_rate; else - tmp_diff = tmp_rate - rate; + tmp_diff = tmp_rate - req->rate; if (best_diff < 0 || best_diff > tmp_diff) { best_rate = tmp_rate; best_diff = tmp_diff; - *best_parent_rate = tmp_parent_rate; - *best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = tmp_parent_rate; + req->best_parent_hw = __clk_get_hw(parent); } - if (!best_diff || tmp_rate < rate) + if (!best_diff || tmp_rate < req->rate) break; } @@ -104,7 +100,11 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, break; } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; } static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) @@ -373,7 +373,6 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, struct at91_pmc *pmc) { struct clk *clk; - int i; int num_parents; const char *parent_names[USB_SOURCE_MAX]; const char *name = np->name; @@ -382,11 +381,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) return; - for (i = 0; i < num_parents; i++) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index ae3263b..30dd697 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -118,12 +118,16 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); ret = request_irq(utmi->irq, clk_utmi_irq_handler, IRQF_TRIGGER_HIGH, "clk-utmi", utmi); - if (ret) + if (ret) { + kfree(utmi); return ERR_PTR(ret); + } clk = clk_register(NULL, &utmi->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(utmi->irq, utmi); kfree(utmi); + } return clk; } diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index eb8e5dc..8b87771 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -59,71 +59,63 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) int of_at91_get_clk_range(struct device_node *np, const char *propname, struct clk_range *range); -extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_sama5d3_clk_pll_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_master_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, - struct at91_pmc *pmc); - -#if defined(CONFIG_HAVE_AT91_UTMI) -extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif - -#if defined(CONFIG_HAVE_AT91_USB_CLK) -extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif - -#if defined(CONFIG_HAVE_AT91_SMD) -extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif - -#if defined(CONFIG_HAVE_AT91_H32MX) -extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif +void of_at91sam9260_clk_slow_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_main_osc_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91rm9200_clk_main_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_main_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9g45_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9g20_clk_pllb_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_sama5d3_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_plldiv_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_sys_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9g45_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91sam9x5_clk_utmi_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9n12_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91sam9x5_clk_smd_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_sama5d4_clk_h32mx_setup(struct device_node *np, + struct at91_pmc *pmc); #endif /* __PMC_H_ */ diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index e19c09c..f630e1b 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -222,10 +222,6 @@ void __init iproc_asiu_setup(struct device_node *node, struct iproc_asiu_clk *asiu_clk; const char *clk_name; - clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL); - if (WARN_ON(!clk_name)) - goto err_clk_register; - ret = of_property_read_string_index(node, "clock-output-names", i, &clk_name); if (WARN_ON(ret)) @@ -259,7 +255,7 @@ void __init iproc_asiu_setup(struct device_node *node, err_clk_register: for (i = 0; i < num_clks; i++) - kfree(asiu->clks[i].name); + clk_unregister(asiu->clk_data.clks[i]); iounmap(asiu->gate_base); err_iomap_gate: diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 46fb84b..2dda4e8 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -366,7 +366,7 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, val = readl(pll->pll_base + ctrl->ndiv_int.offset); ndiv_int = (val >> ctrl->ndiv_int.shift) & bit_mask(ctrl->ndiv_int.width); - ndiv = ndiv_int << ctrl->ndiv_int.shift; + ndiv = (u64)ndiv_int << ctrl->ndiv_int.shift; if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { val = readl(pll->pll_base + ctrl->ndiv_frac.offset); @@ -374,7 +374,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, bit_mask(ctrl->ndiv_frac.width); if (ndiv_frac != 0) - ndiv = (ndiv_int << ctrl->ndiv_int.shift) | ndiv_frac; + ndiv = ((u64)ndiv_int << ctrl->ndiv_int.shift) | + ndiv_frac; } val = readl(pll->pll_base + ctrl->pdiv.offset); @@ -655,10 +656,6 @@ void __init iproc_pll_clk_setup(struct device_node *node, memset(&init, 0, sizeof(init)); parent_name = node->name; - clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL); - if (WARN_ON(!clk_name)) - goto err_clk_register; - ret = of_property_read_string_index(node, "clock-output-names", i, &clk_name); if (WARN_ON(ret)) @@ -690,10 +687,8 @@ void __init iproc_pll_clk_setup(struct device_node *node, return; err_clk_register: - for (i = 0; i < num_clks; i++) { - kfree(pll->clks[i].name); + for (i = 0; i < num_clks; i++) clk_unregister(pll->clk_data.clks[i]); - } err_pll_register: if (pll->asiu_base) diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 5638de8..05fa322 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1018,10 +1018,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, rate ? rate : 1, *parent_rate, NULL); } -static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, struct clk_hw **best_parent) +static int kona_peri_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct kona_clk *bcm_clk = to_kona_clk(hw); struct clk *clk = hw->clk; @@ -1030,6 +1028,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long best_delta; unsigned long best_rate; u32 parent_count; + long rate; u32 which; /* @@ -1038,14 +1037,21 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, */ WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); parent_count = (u32)bcm_clk->init_data.num_parents; - if (parent_count < 2) - return kona_peri_clk_round_rate(hw, rate, best_parent_rate); + if (parent_count < 2) { + rate = kona_peri_clk_round_rate(hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; + } /* Unless we can do better, stick with current parent */ current_parent = clk_get_parent(clk); parent_rate = __clk_get_rate(current_parent); - best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); - best_delta = abs(best_rate - rate); + best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate); + best_delta = abs(best_rate - req->rate); /* Check whether any other parent clock can produce a better result */ for (which = 0; which < parent_count; which++) { @@ -1059,17 +1065,19 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, /* We don't support CLK_SET_RATE_PARENT */ parent_rate = __clk_get_rate(parent); - other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); - delta = abs(other_rate - rate); + other_rate = kona_peri_clk_round_rate(hw, req->rate, + &parent_rate); + delta = abs(other_rate - req->rate); if (delta < best_delta) { best_delta = delta; best_rate = other_rate; - *best_parent = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; } } - return best_rate; + req->rate = best_rate; + return 0; } static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 616f5ae..35ac062 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -55,11 +55,8 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, return rate_ops->recalc_rate(rate_hw, parent_rate); } -static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int clk_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; @@ -71,25 +68,28 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, long tmp_rate, best_rate = 0; unsigned long rate_diff; unsigned long best_rate_diff = ULONG_MAX; + long rate; int i; if (rate_hw && rate_ops && rate_ops->determine_rate) { __clk_hw_set_clk(rate_hw, hw); - return rate_ops->determine_rate(rate_hw, rate, min_rate, - max_rate, - best_parent_rate, - best_parent_p); + return rate_ops->determine_rate(rate_hw, req); } else if (rate_hw && rate_ops && rate_ops->round_rate && mux_hw && mux_ops && mux_ops->set_parent) { - *best_parent_p = NULL; + req->best_parent_hw = NULL; if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { parent = clk_get_parent(mux_hw->clk); - *best_parent_p = __clk_get_hw(parent); - *best_parent_rate = __clk_get_rate(parent); + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = __clk_get_rate(parent); - return rate_ops->round_rate(rate_hw, rate, - best_parent_rate); + rate = rate_ops->round_rate(rate_hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; } for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) { @@ -99,34 +99,33 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, parent_rate = __clk_get_rate(parent); - tmp_rate = rate_ops->round_rate(rate_hw, rate, + tmp_rate = rate_ops->round_rate(rate_hw, req->rate, &parent_rate); if (tmp_rate < 0) continue; - rate_diff = abs(rate - tmp_rate); + rate_diff = abs(req->rate - tmp_rate); - if (!rate_diff || !*best_parent_p + if (!rate_diff || !req->best_parent_hw || best_rate_diff > rate_diff) { - *best_parent_p = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; } if (!rate_diff) - return rate; + return 0; } - return best_rate; + req->rate = best_rate; + return 0; } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); - return mux_ops->determine_rate(mux_hw, rate, min_rate, - max_rate, best_parent_rate, - best_parent_p); + return mux_ops->determine_rate(mux_hw, req); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); - return 0; + return -EINVAL; } } diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c deleted file mode 100644 index f564e62..0000000 --- a/drivers/clk/clk-gpio-gate.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com - * Author: Jyri Sarha <jsarha@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Gpio gated clock implementation - */ - -#include <linux/clk-provider.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h> -#include <linux/of_gpio.h> -#include <linux/err.h> -#include <linux/device.h> - -/** - * DOC: basic gpio gated clock which can be enabled and disabled - * with gpio output - * Traits of this clock: - * prepare - clk_(un)prepare only ensures parent is (un)prepared - * enable - clk_enable and clk_disable are functional & control gpio - * rate - inherits rate from parent. No clk_set_rate support - * parent - fixed parent. No clk_set_parent support - */ - -#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) - -static int clk_gpio_gate_enable(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - gpiod_set_value(clk->gpiod, 1); - - return 0; -} - -static void clk_gpio_gate_disable(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - gpiod_set_value(clk->gpiod, 0); -} - -static int clk_gpio_gate_is_enabled(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - return gpiod_get_value(clk->gpiod); -} - -const struct clk_ops clk_gpio_gate_ops = { - .enable = clk_gpio_gate_enable, - .disable = clk_gpio_gate_disable, - .is_enabled = clk_gpio_gate_is_enabled, -}; -EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); - -/** - * clk_register_gpio - register a gpip clock with the clock framework - * @dev: device that is registering this clock - * @name: name of this clock - * @parent_name: name of this clock's parent - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock - * @flags: clock flags - */ -struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, - unsigned long flags) -{ - struct clk_gpio *clk_gpio = NULL; - struct clk *clk = ERR_PTR(-EINVAL); - struct clk_init_data init = { NULL }; - unsigned long gpio_flags; - int err; - - if (active_low) - gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; - else - gpio_flags = GPIOF_OUT_INIT_LOW; - - if (dev) - err = devm_gpio_request_one(dev, gpio, gpio_flags, name); - else - err = gpio_request_one(gpio, gpio_flags, name); - - if (err) { - pr_err("%s: %s: Error requesting clock control gpio %u\n", - __func__, name, gpio); - return ERR_PTR(err); - } - - if (dev) - clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio), - GFP_KERNEL); - else - clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL); - - if (!clk_gpio) { - clk = ERR_PTR(-ENOMEM); - goto clk_register_gpio_gate_err; - } - - init.name = name; - init.ops = &clk_gpio_gate_ops; - init.flags = flags | CLK_IS_BASIC; - init.parent_names = (parent_name ? &parent_name : NULL); - init.num_parents = (parent_name ? 1 : 0); - - clk_gpio->gpiod = gpio_to_desc(gpio); - clk_gpio->hw.init = &init; - - clk = clk_register(dev, &clk_gpio->hw); - - if (!IS_ERR(clk)) - return clk; - - if (!dev) - kfree(clk_gpio); - -clk_register_gpio_gate_err: - if (!dev) - gpio_free(gpio); - - return clk; -} -EXPORT_SYMBOL_GPL(clk_register_gpio_gate); - -#ifdef CONFIG_OF -/** - * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER - * can not be handled properly at of_clk_init() call time. - */ - -struct clk_gpio_gate_delayed_register_data { - struct device_node *node; - struct mutex lock; - struct clk *clk; -}; - -static struct clk *of_clk_gpio_gate_delayed_register_get( - struct of_phandle_args *clkspec, - void *_data) -{ - struct clk_gpio_gate_delayed_register_data *data = _data; - struct clk *clk; - const char *clk_name = data->node->name; - const char *parent_name; - int gpio; - enum of_gpio_flags of_flags; - - mutex_lock(&data->lock); - - if (data->clk) { - mutex_unlock(&data->lock); - return data->clk; - } - - gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, - &of_flags); - if (gpio < 0) { - mutex_unlock(&data->lock); - if (gpio != -EPROBE_DEFER) - pr_err("%s: %s: Can't get 'enable-gpios' DT property\n", - __func__, clk_name); - return ERR_PTR(gpio); - } - - parent_name = of_clk_get_parent_name(data->node, 0); - - clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio, - of_flags & OF_GPIO_ACTIVE_LOW, 0); - if (IS_ERR(clk)) { - mutex_unlock(&data->lock); - return clk; - } - - data->clk = clk; - mutex_unlock(&data->lock); - - return clk; -} - -/** - * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock - */ -static void __init of_gpio_gate_clk_setup(struct device_node *node) -{ - struct clk_gpio_gate_delayed_register_data *data; - - data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data), - GFP_KERNEL); - if (!data) - return; - - data->node = node; - mutex_init(&data->lock); - - of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data); -} -CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); -#endif diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c new file mode 100644 index 0000000..41277a1 --- /dev/null +++ b/drivers/clk/clk-gpio.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: + * Jyri Sarha <jsarha@ti.com> + * Sergej Sawazki <ce3a@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Gpio controlled clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/of_gpio.h> +#include <linux/err.h> +#include <linux/device.h> + +/** + * DOC: basic gpio gated clock which can be enabled and disabled + * with gpio output + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parent is (un)prepared + * enable - clk_enable and clk_disable are functional & control gpio + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) + +static int clk_gpio_gate_enable(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, 1); + + return 0; +} + +static void clk_gpio_gate_disable(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, 0); +} + +static int clk_gpio_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value(clk->gpiod); +} + +const struct clk_ops clk_gpio_gate_ops = { + .enable = clk_gpio_gate_enable, + .disable = clk_gpio_gate_disable, + .is_enabled = clk_gpio_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); + +/** + * DOC: basic clock multiplexer which can be controlled with a gpio output + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * rate - rate is only affected by parent switching. No clk_set_rate support + * parent - parent is adjustable through clk_set_parent + */ + +static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value(clk->gpiod); +} + +static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, index); + + return 0; +} + +const struct clk_ops clk_gpio_mux_ops = { + .get_parent = clk_gpio_mux_get_parent, + .set_parent = clk_gpio_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); + +static struct clk *clk_register_gpio(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags, + const struct clk_ops *clk_gpio_ops) +{ + struct clk_gpio *clk_gpio; + struct clk *clk; + struct clk_init_data init = {}; + unsigned long gpio_flags; + int err; + + if (dev) + clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL); + else + clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL); + + if (!clk_gpio) + return ERR_PTR(-ENOMEM); + + if (active_low) + gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; + else + gpio_flags = GPIOF_OUT_INIT_LOW; + + if (dev) + err = devm_gpio_request_one(dev, gpio, gpio_flags, name); + else + err = gpio_request_one(gpio, gpio_flags, name); + if (err) { + if (err != -EPROBE_DEFER) + pr_err("%s: %s: Error requesting clock control gpio %u\n", + __func__, name, gpio); + if (!dev) + kfree(clk_gpio); + + return ERR_PTR(err); + } + + init.name = name; + init.ops = clk_gpio_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + clk_gpio->gpiod = gpio_to_desc(gpio); + clk_gpio->hw.init = &init; + + if (dev) + clk = devm_clk_register(dev, &clk_gpio->hw); + else + clk = clk_register(NULL, &clk_gpio->hw); + + if (!IS_ERR(clk)) + return clk; + + if (!dev) { + gpiod_put(clk_gpio->gpiod); + kfree(clk_gpio); + } + + return clk; +} + +/** + * clk_register_gpio_gate - register a gpio clock gate with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_gate(struct device *dev, const char *name, + const char *parent_name, unsigned gpio, bool active_low, + unsigned long flags) +{ + return clk_register_gpio(dev, name, + (parent_name ? &parent_name : NULL), + (parent_name ? 1 : 0), gpio, active_low, flags, + &clk_gpio_gate_ops); +} +EXPORT_SYMBOL_GPL(clk_register_gpio_gate); + +/** + * clk_register_gpio_mux - register a gpio clock mux with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_names: names of this clock's parents + * @num_parents: number of parents listed in @parent_names + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags) +{ + if (num_parents != 2) { + pr_err("mux-clock %s must have 2 parents\n", name); + return ERR_PTR(-EINVAL); + } + + return clk_register_gpio(dev, name, parent_names, num_parents, + gpio, active_low, flags, &clk_gpio_mux_ops); +} +EXPORT_SYMBOL_GPL(clk_register_gpio_mux); + +#ifdef CONFIG_OF +/** + * clk_register_get() has to be delayed, because -EPROBE_DEFER + * can not be handled properly at of_clk_init() call time. + */ + +struct clk_gpio_delayed_register_data { + const char *gpio_name; + struct device_node *node; + struct mutex lock; + struct clk *clk; + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low); +}; + +static struct clk *of_clk_gpio_delayed_register_get( + struct of_phandle_args *clkspec, void *_data) +{ + struct clk_gpio_delayed_register_data *data = _data; + struct clk *clk; + const char **parent_names; + int i, num_parents; + int gpio; + enum of_gpio_flags of_flags; + + mutex_lock(&data->lock); + + if (data->clk) { + mutex_unlock(&data->lock); + return data->clk; + } + + gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0, + &of_flags); + if (gpio < 0) { + mutex_unlock(&data->lock); + if (gpio == -EPROBE_DEFER) + pr_debug("%s: %s: GPIOs not yet available, retry later\n", + data->node->name, __func__); + else + pr_err("%s: %s: Can't get '%s' DT property\n", + data->node->name, __func__, + data->gpio_name); + return ERR_PTR(gpio); + } + + num_parents = of_clk_get_parent_count(data->node); + + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) { + clk = ERR_PTR(-ENOMEM); + goto out; + } + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(data->node, i); + + clk = data->clk_register_get(data->node->name, parent_names, + num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + if (IS_ERR(clk)) + goto out; + + data->clk = clk; +out: + mutex_unlock(&data->lock); + kfree(parent_names); + + return clk; +} + +static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low) +{ + return clk_register_gpio_gate(NULL, name, parent_names[0], + gpio, active_low, 0); +} + +static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low) +{ + return clk_register_gpio_mux(NULL, name, parent_names, num_parents, + gpio, active_low, 0); +} + +static void __init of_gpio_clk_setup(struct device_node *node, + const char *gpio_name, + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low)) +{ + struct clk_gpio_delayed_register_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return; + + data->node = node; + data->gpio_name = gpio_name; + data->clk_register_get = clk_register_get; + mutex_init(&data->lock); + + of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data); +} + +static void __init of_gpio_gate_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "enable-gpios", + of_clk_gpio_gate_delayed_register_get); +} +CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); + +void __init of_gpio_mux_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "select-gpios", + of_clk_gpio_mux_delayed_register_get); +} +CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup); +#endif diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 9b13a30..ba7fb1b 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -246,7 +246,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) s2mps11_name(s2mps11_clk), NULL); if (!s2mps11_clk->lookup) { ret = -ENOMEM; - goto err_lup; + goto err_reg; } } @@ -265,16 +265,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s2mps11_clks); return ret; -err_lup: - devm_clk_unregister(&pdev->dev, s2mps11_clk->clk); + err_reg: - while (s2mps11_clk > s2mps11_clks) { - if (s2mps11_clk->lookup) { - clkdev_drop(s2mps11_clk->lookup); - devm_clk_unregister(&pdev->dev, s2mps11_clk->clk); - } - s2mps11_clk--; - } + while (--i >= 0) + clkdev_drop(s2mps11_clks[i].lookup); return ret; } diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index b9b12a7..3f6f7ad 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -268,7 +268,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) memcpy(table, stm32f42xx_gate_map, sizeof(table)); /* only bits set in table can be used as indices */ - if (WARN_ON(secondary > 8 * sizeof(table) || + if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) || 0 == (table[BIT_ULL_WORD(secondary)] & BIT_ULL_MASK(secondary)))) return -EINVAL; diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 3094b10..8e5ed64 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -90,7 +90,7 @@ static int twl6040_clk_probe(struct platform_device *pdev) clkdata->twl6040 = twl6040; clkdata->mcpdm_fclk.init = &wm831x_clkout_init; - clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk); + clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk); if (IS_ERR(clkdata->clk)) return PTR_ERR(clkdata->clk); @@ -99,21 +99,11 @@ static int twl6040_clk_probe(struct platform_device *pdev) return 0; } -static int twl6040_clk_remove(struct platform_device *pdev) -{ - struct twl6040_clk *clkdata = platform_get_drvdata(pdev); - - clk_unregister(clkdata->clk); - - return 0; -} - static struct platform_driver twl6040_clk_driver = { .driver = { .name = "twl6040-clk", }, .probe = twl6040_clk_probe, - .remove = twl6040_clk_remove, }; module_platform_driver(twl6040_clk_driver); diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index f26b3ac..4caee93 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -60,7 +60,6 @@ enum xgene_pll_type { struct xgene_clk_pll { struct clk_hw hw; - const char *name; void __iomem *reg; spinlock_t *lock; u32 pll_offset; @@ -75,7 +74,7 @@ static int xgene_clk_pll_is_enabled(struct clk_hw *hw) u32 data; data = xgene_clk_read(pllclk->reg + pllclk->pll_offset); - pr_debug("%s pll %s\n", pllclk->name, + pr_debug("%s pll %s\n", __clk_get_name(hw->clk), data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled"); return data & REGSPEC_RESET_F1_MASK ? 0 : 1; @@ -113,7 +112,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw, fref = parent_rate / nref; fvco = fref * nfb; } - pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name, + pr_debug("%s pll recalc rate %ld parent %ld\n", __clk_get_name(hw->clk), fvco / nout, parent_rate); return fvco / nout; @@ -146,7 +145,6 @@ static struct clk *xgene_register_clk_pll(struct device *dev, init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; - apmclk->name = name; apmclk->reg = reg; apmclk->lock = lock; apmclk->pll_offset = pll_offset; @@ -210,7 +208,6 @@ struct xgene_dev_parameters { struct xgene_clk { struct clk_hw hw; - const char *name; spinlock_t *lock; struct xgene_dev_parameters param; }; @@ -228,7 +225,7 @@ static int xgene_clk_enable(struct clk_hw *hw) spin_lock_irqsave(pclk->lock, flags); if (pclk->param.csr_reg != NULL) { - pr_debug("%s clock enabled\n", pclk->name); + pr_debug("%s clock enabled\n", __clk_get_name(hw->clk)); reg = __pa(pclk->param.csr_reg); /* First enable the clock */ data = xgene_clk_read(pclk->param.csr_reg + @@ -237,7 +234,7 @@ static int xgene_clk_enable(struct clk_hw *hw) xgene_clk_write(data, pclk->param.csr_reg + pclk->param.reg_clk_offset); pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n", - pclk->name, ®, + __clk_get_name(hw->clk), ®, pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, data); @@ -248,7 +245,7 @@ static int xgene_clk_enable(struct clk_hw *hw) xgene_clk_write(data, pclk->param.csr_reg + pclk->param.reg_csr_offset); pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n", - pclk->name, ®, + __clk_get_name(hw->clk), ®, pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, data); } @@ -269,7 +266,7 @@ static void xgene_clk_disable(struct clk_hw *hw) spin_lock_irqsave(pclk->lock, flags); if (pclk->param.csr_reg != NULL) { - pr_debug("%s clock disabled\n", pclk->name); + pr_debug("%s clock disabled\n", __clk_get_name(hw->clk)); /* First put the CSR in reset */ data = xgene_clk_read(pclk->param.csr_reg + pclk->param.reg_csr_offset); @@ -295,10 +292,10 @@ static int xgene_clk_is_enabled(struct clk_hw *hw) u32 data = 0; if (pclk->param.csr_reg != NULL) { - pr_debug("%s clock checking\n", pclk->name); + pr_debug("%s clock checking\n", __clk_get_name(hw->clk)); data = xgene_clk_read(pclk->param.csr_reg + pclk->param.reg_clk_offset); - pr_debug("%s clock is %s\n", pclk->name, + pr_debug("%s clock is %s\n", __clk_get_name(hw->clk), data & pclk->param.reg_clk_mask ? "enabled" : "disabled"); } @@ -321,11 +318,13 @@ static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw, data &= (1 << pclk->param.reg_divider_width) - 1; pr_debug("%s clock recalc rate %ld parent %ld\n", - pclk->name, parent_rate / data, parent_rate); + __clk_get_name(hw->clk), + parent_rate / data, parent_rate); + return parent_rate / data; } else { pr_debug("%s clock recalc rate %ld parent %ld\n", - pclk->name, parent_rate, parent_rate); + __clk_get_name(hw->clk), parent_rate, parent_rate); return parent_rate; } } @@ -357,7 +356,7 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate, data |= divider; xgene_clk_write(data, pclk->param.divider_reg + pclk->param.reg_divider_offset); - pr_debug("%s clock set rate %ld\n", pclk->name, + pr_debug("%s clock set rate %ld\n", __clk_get_name(hw->clk), parent_rate / divider_save); } else { divider_save = 1; @@ -419,7 +418,6 @@ static struct clk *xgene_register_clk(struct device *dev, init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; - apmclk->name = name; apmclk->lock = lock; apmclk->hw.init = &init; apmclk->param = *parameters; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 89e531a..819ffa6 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -59,6 +59,8 @@ struct clk_core { unsigned long flags; unsigned int enable_count; unsigned int prepare_count; + unsigned long min_rate; + unsigned long max_rate; unsigned long accuracy; int phase; struct hlist_head children; @@ -437,28 +439,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now, return now <= rate && now > best; } -static long -clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p, +static int +clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req, unsigned long flags) { struct clk_core *core = hw->core, *parent, *best_parent = NULL; - int i, num_parents; - unsigned long parent_rate, best = 0; + int i, num_parents, ret; + unsigned long best = 0; + struct clk_rate_request parent_req = *req; /* if NO_REPARENT flag set, pass through to current parent */ if (core->flags & CLK_SET_RATE_NO_REPARENT) { parent = core->parent; - if (core->flags & CLK_SET_RATE_PARENT) - best = __clk_determine_rate(parent ? parent->hw : NULL, - rate, min_rate, max_rate); - else if (parent) + if (core->flags & CLK_SET_RATE_PARENT) { + ret = __clk_determine_rate(parent ? parent->hw : NULL, + &parent_req); + if (ret) + return ret; + + best = parent_req.rate; + } else if (parent) { best = clk_core_get_rate_nolock(parent); - else + } else { best = clk_core_get_rate_nolock(core); + } + goto out; } @@ -468,24 +473,33 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, parent = clk_core_get_parent_by_index(core, i); if (!parent) continue; - if (core->flags & CLK_SET_RATE_PARENT) - parent_rate = __clk_determine_rate(parent->hw, rate, - min_rate, - max_rate); - else - parent_rate = clk_core_get_rate_nolock(parent); - if (mux_is_better_rate(rate, parent_rate, best, flags)) { + + if (core->flags & CLK_SET_RATE_PARENT) { + parent_req = *req; + ret = __clk_determine_rate(parent->hw, &parent_req); + if (ret) + continue; + } else { + parent_req.rate = clk_core_get_rate_nolock(parent); + } + + if (mux_is_better_rate(req->rate, parent_req.rate, + best, flags)) { best_parent = parent; - best = parent_rate; + best = parent_req.rate; } } + if (!best_parent) + return -EINVAL; + out: if (best_parent) - *best_parent_p = best_parent->hw; - *best_parent_rate = best; + req->best_parent_hw = best_parent->hw; + req->best_parent_rate = best; + req->rate = best; - return best; + return 0; } struct clk *__clk_lookup(const char *name) @@ -501,8 +515,8 @@ static void clk_core_get_boundaries(struct clk_core *core, { struct clk *clk_user; - *min_rate = 0; - *max_rate = ULONG_MAX; + *min_rate = core->min_rate; + *max_rate = core->max_rate; hlist_for_each_entry(clk_user, &core->clks, clks_node) *min_rate = max(*min_rate, clk_user->min_rate); @@ -511,33 +525,30 @@ static void clk_core_get_boundaries(struct clk_core *core, *max_rate = min(*max_rate, clk_user->max_rate); } +void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, + unsigned long max_rate) +{ + hw->core->min_rate = min_rate; + hw->core->max_rate = max_rate; +} +EXPORT_SYMBOL_GPL(clk_hw_set_rate_range); + /* * Helper for finding best parent to provide a given frequency. This can be used * directly as a determine_rate callback (e.g. for a mux), or from a more * complex clock that may combine a mux with other operations. */ -long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +int __clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate, - best_parent_rate, - best_parent_p, 0); + return clk_mux_determine_rate_flags(hw, req, 0); } EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); -long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +int __clk_mux_determine_rate_closest(struct clk_hw *hw, + struct clk_rate_request *req) { - return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate, - best_parent_rate, - best_parent_p, - CLK_MUX_ROUND_CLOSEST); + return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST); } EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest); @@ -760,14 +771,11 @@ int clk_enable(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_enable); -static unsigned long clk_core_round_rate_nolock(struct clk_core *core, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate) +static int clk_core_round_rate_nolock(struct clk_core *core, + struct clk_rate_request *req) { - unsigned long parent_rate = 0; struct clk_core *parent; - struct clk_hw *parent_hw; + long rate; lockdep_assert_held(&prepare_lock); @@ -775,21 +783,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core, return 0; parent = core->parent; - if (parent) - parent_rate = parent->rate; + if (parent) { + req->best_parent_hw = parent->hw; + req->best_parent_rate = parent->rate; + } else { + req->best_parent_hw = NULL; + req->best_parent_rate = 0; + } if (core->ops->determine_rate) { - parent_hw = parent ? parent->hw : NULL; - return core->ops->determine_rate(core->hw, rate, - min_rate, max_rate, - &parent_rate, &parent_hw); - } else if (core->ops->round_rate) - return core->ops->round_rate(core->hw, rate, &parent_rate); - else if (core->flags & CLK_SET_RATE_PARENT) - return clk_core_round_rate_nolock(core->parent, rate, min_rate, - max_rate); - else - return core->rate; + return core->ops->determine_rate(core->hw, req); + } else if (core->ops->round_rate) { + rate = core->ops->round_rate(core->hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + } else if (core->flags & CLK_SET_RATE_PARENT) { + return clk_core_round_rate_nolock(parent, req); + } else { + req->rate = core->rate; + } + + return 0; } /** @@ -801,15 +818,14 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core, * * Useful for clk_ops such as .set_rate and .determine_rate. */ -unsigned long __clk_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate) +int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - if (!hw) + if (!hw) { + req->rate = 0; return 0; + } - return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate); + return clk_core_round_rate_nolock(hw->core, req); } EXPORT_SYMBOL_GPL(__clk_determine_rate); @@ -822,15 +838,20 @@ EXPORT_SYMBOL_GPL(__clk_determine_rate); */ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { - unsigned long min_rate; - unsigned long max_rate; + struct clk_rate_request req; + int ret; if (!clk) return 0; - clk_core_get_boundaries(clk->core, &min_rate, &max_rate); + clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate); + req.rate = rate; - return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate); + ret = clk_core_round_rate_nolock(clk->core, &req); + if (ret) + return 0; + + return req.rate; } EXPORT_SYMBOL_GPL(__clk_round_rate); @@ -1250,7 +1271,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, { struct clk_core *top = core; struct clk_core *old_parent, *parent; - struct clk_hw *parent_hw; unsigned long best_parent_rate = 0; unsigned long new_rate; unsigned long min_rate; @@ -1271,20 +1291,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, /* find the closest rate and parent clk/rate */ if (core->ops->determine_rate) { - parent_hw = parent ? parent->hw : NULL; - ret = core->ops->determine_rate(core->hw, rate, - min_rate, - max_rate, - &best_parent_rate, - &parent_hw); + struct clk_rate_request req; + + req.rate = rate; + req.min_rate = min_rate; + req.max_rate = max_rate; + if (parent) { + req.best_parent_hw = parent->hw; + req.best_parent_rate = parent->rate; + } else { + req.best_parent_hw = NULL; + req.best_parent_rate = 0; + } + + ret = core->ops->determine_rate(core->hw, &req); if (ret < 0) return NULL; - new_rate = ret; - parent = parent_hw ? parent_hw->core : NULL; + best_parent_rate = req.best_parent_rate; + new_rate = req.rate; + parent = req.best_parent_hw ? req.best_parent_hw->core : NULL; } else if (core->ops->round_rate) { ret = core->ops->round_rate(core->hw, rate, - &best_parent_rate); + &best_parent_rate); if (ret < 0) return NULL; @@ -2480,6 +2509,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) core->hw = hw; core->flags = hw->init->flags; core->num_parents = hw->init->num_parents; + core->min_rate = 0; + core->max_rate = ULONG_MAX; hw->core = core; /* allocate local copy in case parent_names is __initdata */ @@ -3055,8 +3086,6 @@ struct clock_provider { struct list_head node; }; -static LIST_HEAD(clk_provider_list); - /* * This function looks for a parent clock. If there is one, then it * checks that the provider for this parent clock was initialized, in @@ -3107,14 +3136,24 @@ void __init of_clk_init(const struct of_device_id *matches) struct clock_provider *clk_provider, *next; bool is_init_done; bool force = false; + LIST_HEAD(clk_provider_list); if (!matches) matches = &__clk_of_table; /* First prepare the list of the clocks providers */ for_each_matching_node_and_match(np, matches, &match) { - struct clock_provider *parent = - kzalloc(sizeof(struct clock_provider), GFP_KERNEL); + struct clock_provider *parent; + + parent = kzalloc(sizeof(*parent), GFP_KERNEL); + if (!parent) { + list_for_each_entry_safe(clk_provider, next, + &clk_provider_list, node) { + list_del(&clk_provider->node); + kfree(clk_provider); + } + return; + } parent->clk_init_cb = match->data; parent->np = np; diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 1aaf75e..1dd5d14 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -13,7 +13,7 @@ static DEFINE_SPINLOCK(clklock); static void __init h8300_div_clk_setup(struct device_node *node) { - unsigned int num_parents; + int num_parents; struct clk *clk; const char *clk_name = node->name; const char *parent_name; diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index 44aa45f..2a38eb4 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -26,7 +26,7 @@ static unsigned long pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct pll_clock *pll_clock = to_pll_clock(hw); - int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3); + int mul = 1 << (readb(pll_clock->pllcr) & 3); return parent_rate * mul; } @@ -63,13 +63,13 @@ static int pll_set_rate(struct clk_hw *hw, unsigned long rate, pll = ((rate / parent_rate) / 2) & 0x03; spin_lock_irqsave(&clklock, flags); - val = ctrl_inb((unsigned long)pll_clock->sckcr); + val = readb(pll_clock->sckcr); val |= 0x08; - ctrl_outb(val, (unsigned long)pll_clock->sckcr); - val = ctrl_inb((unsigned long)pll_clock->pllcr); + writeb(val, pll_clock->sckcr); + val = readb(pll_clock->pllcr); val &= ~0x03; val |= pll; - ctrl_outb(val, (unsigned long)pll_clock->pllcr); + writeb(val, pll_clock->pllcr); spin_unlock_irqrestore(&clklock, flags); return 0; } @@ -82,7 +82,7 @@ static const struct clk_ops pll_ops = { static void __init h8s2678_pll_clk_setup(struct device_node *node) { - unsigned int num_parents; + int num_parents; struct clk *clk; const char *clk_name = node->name; const char *parent_name; @@ -96,11 +96,9 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) } - pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL); - if (!pll_clock) { - pr_err("%s: failed to alloc memory", clk_name); + pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL); + if (!pll_clock) return; - } pll_clock->sckcr = of_iomap(node, 0); if (pll_clock->sckcr == NULL) { diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 5502803..7d03fe1 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -292,34 +292,29 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, } } -static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int mmc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_mmc *mclk = to_mmc(hw); - unsigned long best = 0; - if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { - rate = 13000000; - best = 26000000; - } else if (rate <= 26000000) { - rate = 25000000; - best = 180000000; - } else if (rate <= 52000000) { - rate = 50000000; - best = 360000000; - } else if (rate <= 100000000) { - rate = 100000000; - best = 720000000; + if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { + req->rate = 13000000; + req->best_parent_rate = 26000000; + } else if (req->rate <= 26000000) { + req->rate = 25000000; + req->best_parent_rate = 180000000; + } else if (req->rate <= 52000000) { + req->rate = 50000000; + req->best_parent_rate = 360000000; + } else if (req->rate <= 100000000) { + req->rate = 100000000; + req->best_parent_rate = 720000000; } else { /* max is 180M */ - rate = 180000000; - best = 1440000000; + req->rate = 180000000; + req->best_parent_rate = 1440000000; } - *best_parent_rate = best; - return rate; + return -EINVAL; } static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len) diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index 25443e4..3f553d0 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -308,8 +308,7 @@ static void __init of_pll_mux_clk_init(struct device_node *node) return; } - parents[0] = of_clk_get_parent_name(node, 0); - parents[1] = of_clk_get_parent_name(node, 1); + of_clk_parent_fill(node, parents, 2); if (!parents[0] || !parents[1]) { pr_err("%s: missing parent clocks\n", __func__); return; diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 2e0f17b..90eff85 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -701,6 +701,22 @@ static const struct mtk_composite peri_clks[] __initconst = { MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1), }; +static struct clk_onecell_data *mt8173_top_clk_data __initdata; +static struct clk_onecell_data *mt8173_pll_clk_data __initdata; + +static void __init mtk_clk_enable_critical(void) +{ + if (!mt8173_top_clk_data || !mt8173_pll_clk_data) + return; + + clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA15PLL]); + clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA7PLL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_MEM_SEL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_CCI400_SEL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_RTC_SEL]); +} + static void __init mtk_topckgen_init(struct device_node *node) { struct clk_onecell_data *clk_data; @@ -713,19 +729,19 @@ static void __init mtk_topckgen_init(struct device_node *node) return; } - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + mt8173_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data); mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, &mt8173_clk_lock, clk_data); - clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]); - r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); if (r) pr_err("%s(): could not register clock provider: %d\n", __func__, r); + + mtk_clk_enable_critical(); } CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init); @@ -780,8 +796,9 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init); #define CON0_MT8173_RST_BAR BIT(24) -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \ - _tuner_reg, _pcw_reg, _pcw_shift) { \ +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table) { \ .id = _id, \ .name = _name, \ .reg = _reg, \ @@ -796,14 +813,31 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init); .tuner_reg = _tuner_reg, \ .pcw_reg = _pcw_reg, \ .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ } +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL) + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT8173_PLL_FMAX }, + { .div = 1, .freq = 1000000000 }, + { .div = 2, .freq = 702000000 }, + { .div = 3, .freq = 253500000 }, + { .div = 4, .freq = 126750000 }, + { } /* sentinel */ +}; + static const struct mtk_pll_data plls[] = { PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0), PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0), PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0), PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14), - PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0, mmpll_div_table), PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0), PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0), PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0), @@ -819,13 +853,13 @@ static void __init mtk_apmixedsys_init(struct device_node *node) { struct clk_onecell_data *clk_data; - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + mt8173_pll_clk_data = clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); if (!clk_data) return; mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]); + mtk_clk_enable_critical(); } CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys", mtk_apmixedsys_init); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 624716c..c5cbecb 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -135,6 +135,11 @@ struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); #define HAVE_RST_BAR BIT(0) +struct mtk_pll_div_table { + u32 div; + unsigned long freq; +}; + struct mtk_pll_data { int id; const char *name; @@ -151,6 +156,7 @@ struct mtk_pll_data { int pcwbits; uint32_t pcw_reg; int pcw_shift; + const struct mtk_pll_div_table *div_table; }; void __init mtk_clk_register_plls(struct device_node *node, diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 44409e9..622e7b6 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -90,20 +90,23 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, int postdiv) { - u32 con1, pd, val; + u32 con1, val; int pll_en; - /* set postdiv */ - pd = readl(pll->pd_addr); - pd &= ~(POSTDIV_MASK << pll->data->pd_shift); - pd |= (ffs(postdiv) - 1) << pll->data->pd_shift; - writel(pd, pll->pd_addr); - pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN; - /* set pcw */ - val = readl(pll->pcw_addr); + /* set postdiv */ + val = readl(pll->pd_addr); + val &= ~(POSTDIV_MASK << pll->data->pd_shift); + val |= (ffs(postdiv) - 1) << pll->data->pd_shift; + + /* postdiv and pcw need to set at the same time if on same register */ + if (pll->pd_addr != pll->pcw_addr) { + writel(val, pll->pd_addr); + val = readl(pll->pcw_addr); + } + /* set pcw */ val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1, pll->data->pcw_shift); val |= pcw << pll->data->pcw_shift; @@ -135,16 +138,28 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, u32 freq, u32 fin) { unsigned long fmin = 1000 * MHZ; + const struct mtk_pll_div_table *div_table = pll->data->div_table; u64 _pcw; u32 val; if (freq > pll->data->fmax) freq = pll->data->fmax; - for (val = 0; val < 4; val++) { + if (div_table) { + if (freq > div_table[0].freq) + freq = div_table[0].freq; + + for (val = 0; div_table[val + 1].freq != 0; val++) { + if (freq > div_table[val + 1].freq) + break; + } *postdiv = 1 << val; - if (freq * *postdiv >= fmin) - break; + } else { + for (val = 0; val < 5; val++) { + *postdiv = 1 << val; + if ((u64)freq * *postdiv >= fmin) + break; + } } /* _pcw = freq * postdiv / fin * 2^pcwfbits */ diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index de6a873..665cb67 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -201,11 +201,8 @@ error: return ret; } -static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int mmp_clk_mix_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct mmp_clk_mix *mix = to_clk_mix(hw); struct mmp_clk_mix_clk_table *item; @@ -221,7 +218,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, parent = NULL; mix_rate_best = 0; parent_rate_best = 0; - gap_best = rate; + gap_best = ULONG_MAX; parent_best = NULL; if (mix->table) { @@ -233,7 +230,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, item->parent_index); parent_rate = __clk_get_rate(parent); mix_rate = parent_rate / item->divisor; - gap = abs(mix_rate - rate); + gap = abs(mix_rate - req->rate); if (parent_best == NULL || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; @@ -251,7 +248,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, for (j = 0; j < div_val_max; j++) { div = _get_div(mix, j); mix_rate = parent_rate / div; - gap = abs(mix_rate - rate); + gap = abs(mix_rate - req->rate); if (parent_best == NULL || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; @@ -265,10 +262,14 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, } found: - *best_parent_rate = parent_rate_best; - *best_parent_clk = __clk_get_hw(parent_best); + if (!parent_best) + return -EINVAL; + + req->best_parent_rate = parent_rate_best; + req->best_parent_hw = __clk_get_hw(parent_best); + req->rate = mix_rate_best; - return mix_rate_best; + return 0; } static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw, diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 245d506..a34656b 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -135,19 +135,23 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) return NULL; } -static long -clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int +clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { + struct clk *parent = __clk_get_parent(hw->clk); struct clk_pll *pll = to_clk_pll(hw); const struct pll_freq_tbl *f; - f = find_freq(pll->freq_tbl, rate); + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = __clk_get_rate(parent); + + f = find_freq(pll->freq_tbl, req->rate); if (!f) - return clk_pll_recalc_rate(hw, *p_rate); + req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate); + else + req->rate = f->freq; - return f->freq; + return 0; } static int @@ -292,3 +296,78 @@ void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap, clk_pll_set_fsm_mode(pll, regmap, 0); } EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp); + +static int clk_pll_sr2_enable(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + int ret; + u32 mode; + + ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); + if (ret) + return ret; + + /* Disable PLL bypass mode. */ + ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL, + PLL_BYPASSNL); + if (ret) + return ret; + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + udelay(10); + + /* De-assert active-low PLL reset. */ + ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N, + PLL_RESET_N); + if (ret) + return ret; + + ret = wait_for_pll(pll); + if (ret) + return ret; + + /* Enable PLL output. */ + return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL, + PLL_OUTCTRL); +} + +static int +clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) +{ + struct clk_pll *pll = to_clk_pll(hw); + const struct pll_freq_tbl *f; + bool enabled; + u32 mode; + u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N; + + f = find_freq(pll->freq_tbl, rate); + if (!f) + return -EINVAL; + + regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); + enabled = (mode & enable_mask) == enable_mask; + + if (enabled) + clk_pll_disable(hw); + + regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l); + regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m); + regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n); + + if (enabled) + clk_pll_sr2_enable(hw); + + return 0; +} + +const struct clk_ops clk_pll_sr2_ops = { + .enable = clk_pll_sr2_enable, + .disable = clk_pll_disable, + .set_rate = clk_pll_sr2_set_rate, + .recalc_rate = clk_pll_recalc_rate, + .determine_rate = clk_pll_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_pll_sr2_ops); diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h index c9c0cda..ffd0c63 100644 --- a/drivers/clk/qcom/clk-pll.h +++ b/drivers/clk/qcom/clk-pll.h @@ -62,6 +62,7 @@ struct clk_pll { extern const struct clk_ops clk_pll_ops; extern const struct clk_ops clk_pll_vote_ops; +extern const struct clk_ops clk_pll_sr2_ops; #define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr) diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index 7b3d626..2bc42bb 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -404,13 +404,11 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return calc_rate(parent_rate, m, n, mode, pre_div); } -static long _freq_tbl_determine_rate(struct clk_hw *hw, - const struct freq_tbl *f, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw, +static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, + struct clk_rate_request *req, const struct parent_map *parent_map) { - unsigned long clk_flags; + unsigned long clk_flags, rate = req->rate; struct clk *p; int index; @@ -435,25 +433,24 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, } else { rate = __clk_get_rate(p); } - *p_hw = __clk_get_hw(p); - *p_rate = rate; + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = rate; + req->rate = f->freq; - return f->freq; + return 0; } -static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_rcg_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg *rcg = to_clk_rcg(hw); - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate, - max_rate, p_rate, p, rcg->s.parent_map); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, + rcg->s.parent_map); } -static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_dyn_rcg_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); u32 reg; @@ -464,13 +461,11 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, bank = reg_to_bank(rcg, reg); s = &rcg->s[bank]; - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate, - max_rate, p_rate, p, s->parent_map); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map); } -static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int clk_rcg_bypass_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg *rcg = to_clk_rcg(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -478,10 +473,11 @@ static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src); p = clk_get_parent_by_index(hw->clk, index); - *p_hw = __clk_get_hw(p); - *p_rate = __clk_round_rate(p, rate); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = __clk_round_rate(p, req->rate); + req->rate = req->best_parent_rate; - return *p_rate; + return 0; } static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index b95d17f..db3471e 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -176,11 +176,10 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return calc_rate(parent_rate, m, n, mode, hid_div); } -static long _freq_tbl_determine_rate(struct clk_hw *hw, - const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int _freq_tbl_determine_rate(struct clk_hw *hw, + const struct freq_tbl *f, struct clk_rate_request *req) { - unsigned long clk_flags; + unsigned long clk_flags, rate = req->rate; struct clk *p; struct clk_rcg2 *rcg = to_clk_rcg2(hw); int index; @@ -210,19 +209,19 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, } else { rate = __clk_get_rate(p); } - *p_hw = __clk_get_hw(p); - *p_rate = rate; + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = rate; + req->rate = f->freq; - return f->freq; + return 0; } -static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_rcg2_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req); } static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) @@ -374,35 +373,34 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, return clk_edp_pixel_set_rate(hw, rate, parent_rate); } -static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_edp_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; const struct frac_entry *frac; int delta = 100000; - s64 src_rate = *p_rate; s64 request; u32 mask = BIT(rcg->hid_width) - 1; u32 hid_div; int index = qcom_find_src_index(hw, rcg->parent_map, f->src); + struct clk *p = clk_get_parent_by_index(hw->clk, index); /* Force the correct parent */ - *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, index)); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = __clk_get_rate(p); - if (src_rate == 810000000) + if (req->best_parent_rate == 810000000) frac = frac_table_810m; else frac = frac_table_675m; for (; frac->num; frac++) { - request = rate; + request = req->rate; request *= frac->den; request = div_s64(request, frac->num); - if ((src_rate < (request - delta)) || - (src_rate > (request + delta))) + if ((req->best_parent_rate < (request - delta)) || + (req->best_parent_rate > (request + delta))) continue; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, @@ -410,8 +408,10 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, hid_div >>= CFG_SRC_DIV_SHIFT; hid_div &= mask; - return calc_rate(src_rate, frac->num, frac->den, !!frac->den, - hid_div); + req->rate = calc_rate(req->best_parent_rate, + frac->num, frac->den, + !!frac->den, hid_div); + return 0; } return -EINVAL; @@ -428,9 +428,8 @@ const struct clk_ops clk_edp_pixel_ops = { }; EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); -static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int clk_byte_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -439,17 +438,19 @@ static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, u32 mask = BIT(rcg->hid_width) - 1; struct clk *p; - if (rate == 0) + if (req->rate == 0) return -EINVAL; p = clk_get_parent_by_index(hw->clk, index); - *p_hw = __clk_get_hw(p); - *p_rate = parent_rate = __clk_round_rate(p, rate); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = parent_rate = __clk_round_rate(p, req->rate); - div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1; div = min_t(u32, div, mask); - return calc_rate(parent_rate, 0, 0, 0, div); + req->rate = calc_rate(parent_rate, 0, 0, 0, div); + + return 0; } static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate, @@ -494,10 +495,8 @@ static const struct frac_entry frac_table_pixel[] = { { } }; -static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long request, src_rate; @@ -507,18 +506,19 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, int index = qcom_find_src_index(hw, rcg->parent_map, f->src); struct clk *parent = clk_get_parent_by_index(hw->clk, index); - *p = __clk_get_hw(parent); + req->best_parent_hw = __clk_get_hw(parent); for (; frac->num; frac++) { - request = (rate * frac->den) / frac->num; + request = (req->rate * frac->den) / frac->num; src_rate = __clk_round_rate(parent, request); if ((src_rate < (request - delta)) || (src_rate > (request + delta))) continue; - *p_rate = src_rate; - return (src_rate * frac->num) / frac->den; + req->best_parent_rate = src_rate; + req->rate = (src_rate * frac->num) / frac->den; + return 0; } return -EINVAL; @@ -530,19 +530,16 @@ static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_rcg2 *rcg = to_clk_rcg2(hw); struct freq_tbl f = *rcg->freq_tbl; const struct frac_entry *frac = frac_table_pixel; - unsigned long request, src_rate; + unsigned long request; int delta = 100000; u32 mask = BIT(rcg->hid_width) - 1; u32 hid_div; - int index = qcom_find_src_index(hw, rcg->parent_map, f.src); - struct clk *parent = clk_get_parent_by_index(hw->clk, index); for (; frac->num; frac++) { request = (rate * frac->den) / frac->num; - src_rate = __clk_round_rate(parent, request); - if ((src_rate < (request - delta)) || - (src_rate > (request + delta))) + if ((parent_rate < (request - delta)) || + (parent_rate > (request + delta))) continue; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index 54a756b9..3563019 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -48,7 +48,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = { { P_GPLL0, 1 } }; -static const char *gcc_xo_gpll0[] = { +static const char * const gcc_xo_gpll0[] = { "xo", "gpll0_vote", }; @@ -59,7 +59,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { { P_GPLL4, 5 } }; -static const char *gcc_xo_gpll0_gpll4[] = { +static const char * const gcc_xo_gpll0_gpll4[] = { "xo", "gpll0_vote", "gpll4_vote", @@ -70,7 +70,7 @@ static const struct parent_map gcc_xo_sata_asic0_map[] = { { P_SATA_ASIC0_CLK, 2 } }; -static const char *gcc_xo_sata_asic0[] = { +static const char * const gcc_xo_sata_asic0[] = { "xo", "sata_asic0_clk", }; @@ -80,7 +80,7 @@ static const struct parent_map gcc_xo_sata_rx_map[] = { { P_SATA_RX_CLK, 2} }; -static const char *gcc_xo_sata_rx[] = { +static const char * const gcc_xo_sata_rx[] = { "xo", "sata_rx_clk", }; @@ -90,7 +90,7 @@ static const struct parent_map gcc_xo_pcie_map[] = { { P_PCIE_0_1_PIPE_CLK, 2 } }; -static const char *gcc_xo_pcie[] = { +static const char * const gcc_xo_pcie[] = { "xo", "pcie_pipe", }; @@ -100,7 +100,7 @@ static const struct parent_map gcc_xo_pcie_sleep_map[] = { { P_SLEEP_CLK, 6 } }; -static const char *gcc_xo_pcie_sleep[] = { +static const char * const gcc_xo_pcie_sleep[] = { "xo", "sleep_clk_src", }; @@ -2105,6 +2105,7 @@ static struct clk_branch gcc_ce1_clk = { "ce1_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 5639699..40e4802 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -188,7 +188,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = { { P_PLL8, 3 } }; -static const char *gcc_pxo_pll8[] = { +static const char * const gcc_pxo_pll8[] = { "pxo", "pll8_vote", }; @@ -199,7 +199,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = { { P_CXO, 5 } }; -static const char *gcc_pxo_pll8_cxo[] = { +static const char * const gcc_pxo_pll8_cxo[] = { "pxo", "pll8_vote", "cxo", @@ -215,7 +215,7 @@ static const struct parent_map gcc_pxo_pll3_sata_map[] = { { P_PLL3, 6 } }; -static const char *gcc_pxo_pll3[] = { +static const char * const gcc_pxo_pll3[] = { "pxo", "pll3", }; @@ -226,7 +226,7 @@ static const struct parent_map gcc_pxo_pll8_pll0[] = { { P_PLL0, 2 } }; -static const char *gcc_pxo_pll8_pll0_map[] = { +static const char * const gcc_pxo_pll8_pll0_map[] = { "pxo", "pll8_vote", "pll0_vote", @@ -240,7 +240,7 @@ static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = { { P_PLL18, 1 } }; -static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = { +static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = { "pxo", "pll8_vote", "pll0_vote", diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index fc6b12d..b02826e 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -70,7 +70,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = { { P_PLL8, 3 } }; -static const char *gcc_pxo_pll8[] = { +static const char * const gcc_pxo_pll8[] = { "pxo", "pll8_vote", }; @@ -81,7 +81,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = { { P_CXO, 5 } }; -static const char *gcc_pxo_pll8_cxo[] = { +static const char * const gcc_pxo_pll8_cxo[] = { "pxo", "pll8_vote", "cxo", @@ -1917,7 +1917,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = { } }; -static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; +static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; static struct clk_branch usb_fs1_xcvr_fs_clk = { .halt_reg = 0x2fcc, @@ -1984,7 +1984,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = { } }; -static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; +static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; static struct clk_branch usb_fs2_xcvr_fs_clk = { .halt_reg = 0x2fcc, diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index c66f7bc..3bf4fb3 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -51,7 +51,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = { { P_GPLL0, 1 }, }; -static const char *gcc_xo_gpll0[] = { +static const char * const gcc_xo_gpll0[] = { "xo", "gpll0_vote", }; @@ -62,7 +62,7 @@ static const struct parent_map gcc_xo_gpll0_bimc_map[] = { { P_BIMC, 2 }, }; -static const char *gcc_xo_gpll0_bimc[] = { +static const char * const gcc_xo_gpll0_bimc[] = { "xo", "gpll0_vote", "bimc_pll_vote", @@ -75,7 +75,7 @@ static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2a_map[] = { { P_GPLL2_AUX, 2 }, }; -static const char *gcc_xo_gpll0a_gpll1_gpll2a[] = { +static const char * const gcc_xo_gpll0a_gpll1_gpll2a[] = { "xo", "gpll0_vote", "gpll1_vote", @@ -88,7 +88,7 @@ static const struct parent_map gcc_xo_gpll0_gpll2_map[] = { { P_GPLL2, 2 }, }; -static const char *gcc_xo_gpll0_gpll2[] = { +static const char * const gcc_xo_gpll0_gpll2[] = { "xo", "gpll0_vote", "gpll2_vote", @@ -99,7 +99,7 @@ static const struct parent_map gcc_xo_gpll0a_map[] = { { P_GPLL0_AUX, 2 }, }; -static const char *gcc_xo_gpll0a[] = { +static const char * const gcc_xo_gpll0a[] = { "xo", "gpll0_vote", }; @@ -111,7 +111,7 @@ static const struct parent_map gcc_xo_gpll0_gpll1a_sleep_map[] = { { P_SLEEP_CLK, 6 }, }; -static const char *gcc_xo_gpll0_gpll1a_sleep[] = { +static const char * const gcc_xo_gpll0_gpll1a_sleep[] = { "xo", "gpll0_vote", "gpll1_vote", @@ -124,7 +124,7 @@ static const struct parent_map gcc_xo_gpll0_gpll1a_map[] = { { P_GPLL1_AUX, 2 }, }; -static const char *gcc_xo_gpll0_gpll1a[] = { +static const char * const gcc_xo_gpll0_gpll1a[] = { "xo", "gpll0_vote", "gpll1_vote", @@ -135,7 +135,7 @@ static const struct parent_map gcc_xo_dsibyte_map[] = { { P_DSI0_PHYPLL_BYTE, 2 }, }; -static const char *gcc_xo_dsibyte[] = { +static const char * const gcc_xo_dsibyte[] = { "xo", "dsi0pllbyte", }; @@ -146,7 +146,7 @@ static const struct parent_map gcc_xo_gpll0a_dsibyte_map[] = { { P_DSI0_PHYPLL_BYTE, 1 }, }; -static const char *gcc_xo_gpll0a_dsibyte[] = { +static const char * const gcc_xo_gpll0a_dsibyte[] = { "xo", "gpll0_vote", "dsi0pllbyte", @@ -158,7 +158,7 @@ static const struct parent_map gcc_xo_gpll0_dsiphy_map[] = { { P_DSI0_PHYPLL_DSI, 2 }, }; -static const char *gcc_xo_gpll0_dsiphy[] = { +static const char * const gcc_xo_gpll0_dsiphy[] = { "xo", "gpll0_vote", "dsi0pll", @@ -170,7 +170,7 @@ static const struct parent_map gcc_xo_gpll0a_dsiphy_map[] = { { P_DSI0_PHYPLL_DSI, 1 }, }; -static const char *gcc_xo_gpll0a_dsiphy[] = { +static const char * const gcc_xo_gpll0a_dsiphy[] = { "xo", "gpll0_vote", "dsi0pll", @@ -183,7 +183,7 @@ static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2_map[] = { { P_GPLL2, 2 }, }; -static const char *gcc_xo_gpll0a_gpll1_gpll2[] = { +static const char * const gcc_xo_gpll0a_gpll1_gpll2[] = { "xo", "gpll0_vote", "gpll1_vote", diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index eb6a4f9..aa294b1 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -125,7 +125,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = { { P_PLL8, 3 } }; -static const char *gcc_pxo_pll8[] = { +static const char * const gcc_pxo_pll8[] = { "pxo", "pll8_vote", }; @@ -136,7 +136,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = { { P_CXO, 5 } }; -static const char *gcc_pxo_pll8_cxo[] = { +static const char * const gcc_pxo_pll8_cxo[] = { "pxo", "pll8_vote", "cxo", @@ -148,7 +148,7 @@ static const struct parent_map gcc_pxo_pll8_pll3_map[] = { { P_PLL3, 6 } }; -static const char *gcc_pxo_pll8_pll3[] = { +static const char * const gcc_pxo_pll8_pll3[] = { "pxo", "pll8_vote", "pll3", @@ -2085,7 +2085,7 @@ static struct clk_rcg usb_hsic_xcvr_fs_src = { } }; -static const char *usb_hsic_xcvr_fs_src_p[] = { "usb_hsic_xcvr_fs_src" }; +static const char * const usb_hsic_xcvr_fs_src_p[] = { "usb_hsic_xcvr_fs_src" }; static struct clk_branch usb_hsic_xcvr_fs_clk = { .halt_reg = 0x2fc8, @@ -2181,7 +2181,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = { } }; -static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; +static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; static struct clk_branch usb_fs1_xcvr_fs_clk = { .halt_reg = 0x2fcc, @@ -2248,7 +2248,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = { } }; -static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; +static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; static struct clk_branch usb_fs2_xcvr_fs_clk = { .halt_reg = 0x2fcc, diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index c39d098..2bcf875 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -44,7 +44,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = { { P_GPLL0, 1 } }; -static const char *gcc_xo_gpll0[] = { +static const char * const gcc_xo_gpll0[] = { "xo", "gpll0_vote", }; @@ -55,7 +55,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { { P_GPLL4, 5 } }; -static const char *gcc_xo_gpll0_gpll4[] = { +static const char * const gcc_xo_gpll0_gpll4[] = { "xo", "gpll0_vote", "gpll4_vote", @@ -1783,6 +1783,7 @@ static struct clk_branch gcc_ce1_clk = { "ce1_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c index 47f0ac1..93ad42b1 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -71,7 +71,7 @@ static const struct parent_map lcc_pxo_pll4_map[] = { { P_PLL4, 2 } }; -static const char *lcc_pxo_pll4[] = { +static const char * const lcc_pxo_pll4[] = { "pxo", "pll4_vote", }; @@ -146,7 +146,7 @@ static struct clk_rcg mi2s_osr_src = { }, }; -static const char *lcc_mi2s_parents[] = { +static const char * const lcc_mi2s_parents[] = { "mi2s_osr_src", }; @@ -340,7 +340,7 @@ static struct clk_rcg spdif_src = { }, }; -static const char *lcc_spdif_parents[] = { +static const char * const lcc_spdif_parents[] = { "spdif_src", }; diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index d0df9d5..ecb96c2 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -57,7 +57,7 @@ static const struct parent_map lcc_pxo_pll4_map[] = { { P_PLL4, 2 } }; -static const char *lcc_pxo_pll4[] = { +static const char * const lcc_pxo_pll4[] = { "pxo", "pll4_vote", }; @@ -127,7 +127,7 @@ static struct clk_rcg mi2s_osr_src = { }, }; -static const char *lcc_mi2s_parents[] = { +static const char * const lcc_mi2s_parents[] = { "mi2s_osr_src", }; @@ -233,7 +233,7 @@ static struct clk_rcg prefix##_osr_src = { \ }, \ }; \ \ -static const char *lcc_##prefix##_parents[] = { \ +static const char * const lcc_##prefix##_parents[] = { \ #prefix "_osr_src", \ }; \ \ @@ -445,7 +445,7 @@ static struct clk_rcg slimbus_src = { }, }; -static const char *lcc_slimbus_parents[] = { +static const char * const lcc_slimbus_parents[] = { "slimbus_src", }; diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 1b17df2..f0ee6bd 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -53,7 +53,7 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { { P_GPLL0, 5 } }; -static const char *mmcc_xo_mmpll0_mmpll1_gpll0[] = { +static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -69,7 +69,7 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = { { P_DSI1PLL, 3 } }; -static const char *mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { +static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { "xo", "mmpll0_vote", "hdmipll", @@ -86,7 +86,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = { { P_MMPLL2, 3 } }; -static const char *mmcc_xo_mmpll0_1_2_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -102,7 +102,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = { { P_MMPLL3, 3 } }; -static const char *mmcc_xo_mmpll0_1_3_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -119,7 +119,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp[] = { +static const char * const mmcc_xo_dsi_hdmi_edp[] = { "xo", "edp_link_clk", "hdmipll", @@ -137,7 +137,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", @@ -155,7 +155,7 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = { { P_DSI1PLL_BYTE, 2 } }; -static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", @@ -172,7 +172,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll0_map[] = { { P_MMPLL4, 3 } }; -static const char *mmcc_xo_mmpll0_1_4_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_4_gpll0[] = { "xo", "mmpll0", "mmpll1", @@ -189,7 +189,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_map[] = { { P_GPLL1, 4 } }; -static const char *mmcc_xo_mmpll0_1_4_gpll1_0[] = { +static const char * const mmcc_xo_mmpll0_1_4_gpll1_0[] = { "xo", "mmpll0", "mmpll1", @@ -208,7 +208,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_sleep_map[] = { { P_MMSLEEP, 6 } }; -static const char *mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = { +static const char * const mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = { "xo", "mmpll0", "mmpll1", diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 2de05e3..70316a3 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -51,7 +51,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_map[] = { { P_PLL2, 1 } }; -static const char *mmcc_pxo_pll8_pll2[] = { +static const char * const mmcc_pxo_pll8_pll2[] = { "pxo", "pll8_vote", "pll2", @@ -64,7 +64,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_pll3_map[] = { { P_PLL3, 3 } }; -static const char *mmcc_pxo_pll8_pll2_pll15[] = { +static const char * const mmcc_pxo_pll8_pll2_pll15[] = { "pxo", "pll8_vote", "pll2", @@ -78,7 +78,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_pll15_map[] = { { P_PLL15, 3 } }; -static const char *mmcc_pxo_pll8_pll2_pll3[] = { +static const char * const mmcc_pxo_pll8_pll2_pll3[] = { "pxo", "pll8_vote", "pll2", @@ -580,7 +580,7 @@ static const struct clk_ops clk_ops_pix_rdi = { .determine_rate = __clk_mux_determine_rate, }; -static const char *pix_rdi_parents[] = { +static const char * const pix_rdi_parents[] = { "csi0_clk", "csi1_clk", "csi2_clk", @@ -710,7 +710,7 @@ static struct clk_rcg csiphytimer_src = { }, }; -static const char *csixphy_timer_src[] = { "csiphytimer_src" }; +static const char * const csixphy_timer_src[] = { "csiphytimer_src" }; static struct clk_branch csiphy0_timer_clk = { .halt_reg = 0x01e8, @@ -1386,7 +1386,7 @@ static const struct parent_map mmcc_pxo_hdmi_map[] = { { P_HDMI_PLL, 3 } }; -static const char *mmcc_pxo_hdmi[] = { +static const char * const mmcc_pxo_hdmi[] = { "pxo", "hdmi_pll", }; @@ -1429,7 +1429,7 @@ static struct clk_rcg tv_src = { }, }; -static const char *tv_src_name[] = { "tv_src" }; +static const char * const tv_src_name[] = { "tv_src" }; static struct clk_branch tv_enc_clk = { .halt_reg = 0x01d4, diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index 07f4cc1..0987bf4 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -56,7 +56,7 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { { P_GPLL0, 5 } }; -static const char *mmcc_xo_mmpll0_mmpll1_gpll0[] = { +static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -72,7 +72,7 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = { { P_DSI1PLL, 3 } }; -static const char *mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { +static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { "xo", "mmpll0_vote", "hdmipll", @@ -89,7 +89,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = { { P_MMPLL2, 3 } }; -static const char *mmcc_xo_mmpll0_1_2_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -105,7 +105,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = { { P_MMPLL3, 3 } }; -static const char *mmcc_xo_mmpll0_1_3_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -121,7 +121,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_gpll1_0_map[] = { { P_GPLL1, 4 } }; -static const char *mmcc_xo_mmpll0_1_gpll1_0[] = { +static const char * const mmcc_xo_mmpll0_1_gpll1_0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -138,7 +138,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp[] = { +static const char * const mmcc_xo_dsi_hdmi_edp[] = { "xo", "edp_link_clk", "hdmipll", @@ -156,7 +156,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", @@ -174,7 +174,7 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = { { P_DSI1PLL_BYTE, 2 } }; -static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 2714097..b27edd6 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -6,8 +6,10 @@ obj-y += clk-rockchip.o obj-y += clk.o obj-y += clk-pll.o obj-y += clk-cpu.o +obj-y += clk-inverter.o obj-y += clk-mmc-phase.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-y += clk-rk3188.o obj-y += clk-rk3288.o +obj-y += clk-rk3368.o diff --git a/drivers/clk/rockchip/clk-inverter.c b/drivers/clk/rockchip/clk-inverter.c new file mode 100644 index 0000000..8054fdb --- /dev/null +++ b/drivers/clk/rockchip/clk-inverter.c @@ -0,0 +1,116 @@ +/* + * Copyright 2015 Heiko Stuebner <heiko@sntech.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/slab.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/kernel.h> +#include "clk.h" + +struct rockchip_inv_clock { + struct clk_hw hw; + void __iomem *reg; + int shift; + int flags; + spinlock_t *lock; +}; + +#define to_inv_clock(_hw) container_of(_hw, struct rockchip_inv_clock, hw) + +#define INVERTER_MASK 0x1 + +static int rockchip_inv_get_phase(struct clk_hw *hw) +{ + struct rockchip_inv_clock *inv_clock = to_inv_clock(hw); + u32 val; + + val = readl(inv_clock->reg) >> inv_clock->shift; + val &= INVERTER_MASK; + return val ? 180 : 0; +} + +static int rockchip_inv_set_phase(struct clk_hw *hw, int degrees) +{ + struct rockchip_inv_clock *inv_clock = to_inv_clock(hw); + u32 val; + + if (degrees % 180 == 0) { + val = !!degrees; + } else { + pr_err("%s: unsupported phase %d for %s\n", + __func__, degrees, __clk_get_name(hw->clk)); + return -EINVAL; + } + + if (inv_clock->flags & ROCKCHIP_INVERTER_HIWORD_MASK) { + writel(HIWORD_UPDATE(val, INVERTER_MASK, inv_clock->shift), + inv_clock->reg); + } else { + unsigned long flags; + u32 reg; + + spin_lock_irqsave(inv_clock->lock, flags); + + reg = readl(inv_clock->reg); + reg &= ~BIT(inv_clock->shift); + reg |= val; + writel(reg, inv_clock->reg); + + spin_unlock_irqrestore(inv_clock->lock, flags); + } + + return 0; +} + +static const struct clk_ops rockchip_inv_clk_ops = { + .get_phase = rockchip_inv_get_phase, + .set_phase = rockchip_inv_set_phase, +}; + +struct clk *rockchip_clk_register_inverter(const char *name, + const char *const *parent_names, u8 num_parents, + void __iomem *reg, int shift, int flags, + spinlock_t *lock) +{ + struct clk_init_data init; + struct rockchip_inv_clock *inv_clock; + struct clk *clk; + + inv_clock = kmalloc(sizeof(*inv_clock), GFP_KERNEL); + if (!inv_clock) + return NULL; + + init.name = name; + init.num_parents = num_parents; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent_names; + init.ops = &rockchip_inv_clk_ops; + + inv_clock->hw.init = &init; + inv_clock->reg = reg; + inv_clock->shift = shift; + inv_clock->flags = flags; + inv_clock->lock = lock; + + clk = clk_register(NULL, &inv_clock->hw); + if (IS_ERR(clk)) + goto err_free; + + return clk; + +err_free: + kfree(inv_clock); + return NULL; +} diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 3244c6e..77e1909 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -16,6 +16,8 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/kernel.h> #include "clk.h" struct rockchip_mmc_clock { @@ -132,6 +134,7 @@ struct clk *rockchip_clk_register_mmc(const char *name, if (!mmc_clock) return NULL; + init.name = name; init.num_parents = num_parents; init.parent_names = parent_names; init.ops = &rockchip_mmc_clk_ops; @@ -140,9 +143,6 @@ struct clk *rockchip_clk_register_mmc(const char *name, mmc_clock->reg = reg; mmc_clock->shift = shift; - if (name) - init.name = name; - clk = clk_register(NULL, &mmc_clock->hw); if (IS_ERR(clk)) goto err_free; diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 91ea848..edbafbc 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -236,6 +236,7 @@ static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = { #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 /* 2 ^ (val + 1) */ static struct clk_div_table div_core_peri_t[] = { @@ -311,6 +312,8 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { GATE(0, "pclkin_cif0", "ext_cif0", 0, RK2928_CLKGATE_CON(3), 3, GFLAGS), + INVERTER(0, "pclk_cif0", "pclkin_cif0", + RK2928_CLKSEL_CON(30), 8, IFLAGS), /* * the 480m are generated inside the usb block from these clocks, @@ -335,8 +338,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0, RK2928_CLKSEL_CON(23), 0, RK2928_CLKGATE_CON(2), 7, GFLAGS), - MUX(SCLK_HSADC, "sclk_hsadc", mux_sclk_hsadc_p, 0, + MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0, RK2928_CLKSEL_CON(22), 4, 2, MFLAGS), + INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out", + RK2928_CLKSEL_CON(22), 7, IFLAGS), COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, RK2928_CLKSEL_CON(24), 8, 8, DFLAGS, @@ -558,6 +563,8 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { GATE(0, "pclkin_cif1", "ext_cif1", 0, RK2928_CLKGATE_CON(3), 4, GFLAGS), + INVERTER(0, "pclk_cif1", "pclkin_cif1", + RK2928_CLKSEL_CON(30), 12, IFLAGS), COMPOSITE(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(33), 8, 1, MFLAGS, 0, 5, DFLAGS, diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 4f817ed..a8bad7d 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -189,7 +189,7 @@ PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; -PNAME(mux_cif_out_p) = { "cif_src", "xin24m" }; +PNAME(mux_vip_out_p) = { "vip_src", "xin24m" }; PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" }; PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; @@ -223,6 +223,7 @@ static struct clk_div_table div_hclk_cpu_t[] = { #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 rk3288_clk_branches[] __initdata = { /* @@ -434,7 +435,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(26), 8, 1, MFLAGS, RK3288_CLKGATE_CON(3), 7, GFLAGS), - COMPOSITE_NOGATE(0, "sclk_vip_out", mux_cif_out_p, 0, + COMPOSITE_NOGATE(0, "sclk_vip_out", mux_vip_out_p, 0, RK3288_CLKSEL_CON(26), 15, 1, MFLAGS, 9, 5, DFLAGS), DIV(0, "pclk_pd_alive", "gpll", 0, @@ -578,7 +579,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0, RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(2), 5, GFLAGS), - MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0, + MUX(SCLK_MAC, "mac_clk", mux_mac_p, CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(21), 4, 1, MFLAGS), GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0, RK3288_CLKGATE_CON(5), 3, GFLAGS), @@ -592,8 +593,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS, RK3288_CLKGATE_CON(2), 6, GFLAGS), - MUX(SCLK_HSADC, "sclk_hsadc_out", mux_hsadcout_p, 0, + MUX(0, "sclk_hsadc_out", mux_hsadcout_p, 0, RK3288_CLKSEL_CON(22), 4, 1, MFLAGS), + INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out", + RK3288_CLKSEL_CON(22), 7, IFLAGS), GATE(0, "jtag", "ext_jtag", 0, RK3288_CLKGATE_CON(4), 14, GFLAGS), @@ -768,7 +771,9 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { */ GATE(0, "pclk_vip_in", "ext_vip", 0, RK3288_CLKGATE_CON(16), 0, GFLAGS), + INVERTER(0, "pclk_vip", "pclk_vip_in", RK3288_CLKSEL_CON(29), 4, IFLAGS), GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), + INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS), }; static const char *const rk3288_critical_clocks[] __initconst = { diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c new file mode 100644 index 0000000..9c5d61e --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2015 Heiko Stuebner <heiko@sntech.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <dt-bindings/clock/rk3368-cru.h> +#include "clk.h" + +#define RK3368_GRF_SOC_STATUS0 0x480 + +enum rk3368_plls { + apllb, aplll, dpll, cpll, gpll, npll, +}; + +static struct rockchip_pll_rate_table rk3368_pll_rates[] = { + RK3066_PLL_RATE(2208000000, 1, 92, 1), + RK3066_PLL_RATE(2184000000, 1, 91, 1), + RK3066_PLL_RATE(2160000000, 1, 90, 1), + RK3066_PLL_RATE(2136000000, 1, 89, 1), + RK3066_PLL_RATE(2112000000, 1, 88, 1), + RK3066_PLL_RATE(2088000000, 1, 87, 1), + RK3066_PLL_RATE(2064000000, 1, 86, 1), + RK3066_PLL_RATE(2040000000, 1, 85, 1), + RK3066_PLL_RATE(2016000000, 1, 84, 1), + RK3066_PLL_RATE(1992000000, 1, 83, 1), + RK3066_PLL_RATE(1968000000, 1, 82, 1), + RK3066_PLL_RATE(1944000000, 1, 81, 1), + RK3066_PLL_RATE(1920000000, 1, 80, 1), + RK3066_PLL_RATE(1896000000, 1, 79, 1), + RK3066_PLL_RATE(1872000000, 1, 78, 1), + RK3066_PLL_RATE(1848000000, 1, 77, 1), + RK3066_PLL_RATE(1824000000, 1, 76, 1), + RK3066_PLL_RATE(1800000000, 1, 75, 1), + RK3066_PLL_RATE(1776000000, 1, 74, 1), + RK3066_PLL_RATE(1752000000, 1, 73, 1), + RK3066_PLL_RATE(1728000000, 1, 72, 1), + RK3066_PLL_RATE(1704000000, 1, 71, 1), + RK3066_PLL_RATE(1680000000, 1, 70, 1), + RK3066_PLL_RATE(1656000000, 1, 69, 1), + RK3066_PLL_RATE(1632000000, 1, 68, 1), + RK3066_PLL_RATE(1608000000, 1, 67, 1), + RK3066_PLL_RATE(1560000000, 1, 65, 1), + RK3066_PLL_RATE(1512000000, 1, 63, 1), + RK3066_PLL_RATE(1488000000, 1, 62, 1), + RK3066_PLL_RATE(1464000000, 1, 61, 1), + RK3066_PLL_RATE(1440000000, 1, 60, 1), + RK3066_PLL_RATE(1416000000, 1, 59, 1), + RK3066_PLL_RATE(1392000000, 1, 58, 1), + RK3066_PLL_RATE(1368000000, 1, 57, 1), + RK3066_PLL_RATE(1344000000, 1, 56, 1), + RK3066_PLL_RATE(1320000000, 1, 55, 1), + RK3066_PLL_RATE(1296000000, 1, 54, 1), + RK3066_PLL_RATE(1272000000, 1, 53, 1), + RK3066_PLL_RATE(1248000000, 1, 52, 1), + RK3066_PLL_RATE(1224000000, 1, 51, 1), + RK3066_PLL_RATE(1200000000, 1, 50, 1), + RK3066_PLL_RATE(1176000000, 1, 49, 1), + RK3066_PLL_RATE(1128000000, 1, 47, 1), + RK3066_PLL_RATE(1104000000, 1, 46, 1), + RK3066_PLL_RATE(1008000000, 1, 84, 2), + RK3066_PLL_RATE( 912000000, 1, 76, 2), + RK3066_PLL_RATE( 888000000, 1, 74, 2), + RK3066_PLL_RATE( 816000000, 1, 68, 2), + RK3066_PLL_RATE( 792000000, 1, 66, 2), + RK3066_PLL_RATE( 696000000, 1, 58, 2), + RK3066_PLL_RATE( 672000000, 1, 56, 2), + RK3066_PLL_RATE( 648000000, 1, 54, 2), + RK3066_PLL_RATE( 624000000, 1, 52, 2), + RK3066_PLL_RATE( 600000000, 1, 50, 2), + RK3066_PLL_RATE( 576000000, 1, 48, 2), + RK3066_PLL_RATE( 552000000, 1, 46, 2), + RK3066_PLL_RATE( 528000000, 1, 88, 4), + RK3066_PLL_RATE( 504000000, 1, 84, 4), + RK3066_PLL_RATE( 480000000, 1, 80, 4), + RK3066_PLL_RATE( 456000000, 1, 76, 4), + RK3066_PLL_RATE( 408000000, 1, 68, 4), + RK3066_PLL_RATE( 312000000, 1, 52, 4), + RK3066_PLL_RATE( 252000000, 1, 84, 8), + RK3066_PLL_RATE( 216000000, 1, 72, 8), + RK3066_PLL_RATE( 126000000, 2, 84, 8), + RK3066_PLL_RATE( 48000000, 2, 32, 8), + { /* sentinel */ }, +}; + +PNAME(mux_pll_p) = { "xin24m", "xin32k" }; +PNAME(mux_armclkb_p) = { "apllb_core", "gpllb_core" }; +PNAME(mux_armclkl_p) = { "aplll_core", "gplll_core" }; +PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +PNAME(mux_cs_src_p) = { "apllb_cs", "aplll_cs", "gpll_cs"}; +PNAME(mux_aclk_bus_src_p) = { "cpll_aclk_bus", "gpll_aclk_bus" }; + +PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; +PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_usb_p) = { "cpll", "gpll", "usbphy_480m" }; +PNAME(mux_pll_src_cpll_gpll_usb_usb_p) = { "cpll", "gpll", "usbphy_480m", + "usbphy_480m" }; +PNAME(mux_pll_src_cpll_gpll_usb_npll_p) = { "cpll", "gpll", "usbphy_480m", + "npll" }; +PNAME(mux_pll_src_cpll_gpll_npll_npll_p) = { "cpll", "gpll", "npll", "npll" }; +PNAME(mux_pll_src_cpll_gpll_npll_usb_p) = { "cpll", "gpll", "npll", + "usbphy_480m" }; + +PNAME(mux_i2s_8ch_pre_p) = { "i2s_8ch_src", "i2s_8ch_frac", + "ext_i2s", "xin12m" }; +PNAME(mux_i2s_8ch_clkout_p) = { "i2s_8ch_pre", "xin12m" }; +PNAME(mux_i2s_2ch_p) = { "i2s_2ch_src", "i2s_2ch_frac", + "dummy", "xin12m" }; +PNAME(mux_spdif_8ch_p) = { "spdif_8ch_pre", "spdif_8ch_frac", + "ext_i2s", "xin12m" }; +PNAME(mux_edp_24m_p) = { "dummy", "xin24m" }; +PNAME(mux_vip_out_p) = { "vip_src", "xin24m" }; +PNAME(mux_usbphy480m_p) = { "usbotg_out", "xin24m" }; +PNAME(mux_hsic_usbphy480m_p) = { "usbotg_out", "dummy" }; +PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy_480m" }; +PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" }; +PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; +PNAME(mux_uart2_p) = { "uart2_src", "xin24m" }; +PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; +PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; +PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" }; +PNAME(mux_mmc_src_p) = { "cpll", "gpll", "usbphy_480m", "xin24m" }; + +static struct rockchip_pll_clock rk3368_pll_clks[] __initdata = { + [apllb] = PLL(pll_rk3066, PLL_APLLB, "apllb", mux_pll_p, 0, RK3368_PLL_CON(0), + RK3368_PLL_CON(3), 8, 1, 0, rk3368_pll_rates), + [aplll] = PLL(pll_rk3066, PLL_APLLL, "aplll", mux_pll_p, 0, RK3368_PLL_CON(4), + RK3368_PLL_CON(7), 8, 0, 0, rk3368_pll_rates), + [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3368_PLL_CON(8), + RK3368_PLL_CON(11), 8, 2, 0, NULL), + [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3368_PLL_CON(12), + RK3368_PLL_CON(15), 8, 3, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates), + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3368_PLL_CON(16), + RK3368_PLL_CON(19), 8, 4, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3368_PLL_CON(20), + RK3368_PLL_CON(23), 8, 5, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates), +}; + +static struct clk_div_table div_ddrphy_t[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 3, .div = 4 }, + { /* sentinel */ }, +}; + +#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 const struct rockchip_cpuclk_reg_data rk3368_cpuclkb_data = { + .core_reg = RK3368_CLKSEL_CON(0), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_shift = 15, +}; + +static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = { + .core_reg = RK3368_CLKSEL_CON(2), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_shift = 7, +}; + +#define RK3368_DIV_ACLKM_MASK 0x1f +#define RK3368_DIV_ACLKM_SHIFT 8 +#define RK3368_DIV_ATCLK_MASK 0x1f +#define RK3368_DIV_ATCLK_SHIFT 0 +#define RK3368_DIV_PCLK_DBG_MASK 0x1f +#define RK3368_DIV_PCLK_DBG_SHIFT 8 + +#define RK3368_CLKSEL0(_offs, _aclkm) \ + { \ + .reg = RK3288_CLKSEL_CON(0 + _offs), \ + .val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \ + RK3368_DIV_ACLKM_SHIFT), \ + } +#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \ + { \ + .reg = RK3288_CLKSEL_CON(1 + _offs), \ + .val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \ + RK3368_DIV_ATCLK_SHIFT) | \ + HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \ + RK3368_DIV_PCLK_DBG_SHIFT), \ + } + +/* cluster_b: aclkm in clksel0, rest in clksel1 */ +#define RK3368_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate, \ + .divs = { \ + RK3368_CLKSEL0(0, _aclkm), \ + RK3368_CLKSEL1(0, _atclk, _pdbg), \ + }, \ + } + +/* cluster_l: aclkm in clksel2, rest in clksel3 */ +#define RK3368_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate, \ + .divs = { \ + RK3368_CLKSEL0(2, _aclkm), \ + RK3368_CLKSEL1(2, _atclk, _pdbg), \ + }, \ + } + +static struct rockchip_cpuclk_rate_table rk3368_cpuclkb_rates[] __initdata = { + RK3368_CPUCLKB_RATE(1512000000, 2, 6, 6), + RK3368_CPUCLKB_RATE(1488000000, 2, 5, 5), + RK3368_CPUCLKB_RATE(1416000000, 2, 5, 5), + RK3368_CPUCLKB_RATE(1200000000, 2, 4, 4), + RK3368_CPUCLKB_RATE(1008000000, 2, 4, 4), + RK3368_CPUCLKB_RATE( 816000000, 2, 3, 3), + RK3368_CPUCLKB_RATE( 696000000, 2, 3, 3), + RK3368_CPUCLKB_RATE( 600000000, 2, 2, 2), + RK3368_CPUCLKB_RATE( 408000000, 2, 2, 2), + RK3368_CPUCLKB_RATE( 312000000, 2, 2, 2), +}; + +static struct rockchip_cpuclk_rate_table rk3368_cpuclkl_rates[] __initdata = { + RK3368_CPUCLKL_RATE(1512000000, 2, 7, 7), + RK3368_CPUCLKL_RATE(1488000000, 2, 6, 6), + RK3368_CPUCLKL_RATE(1416000000, 2, 6, 6), + RK3368_CPUCLKL_RATE(1200000000, 2, 5, 5), + RK3368_CPUCLKL_RATE(1008000000, 2, 5, 5), + RK3368_CPUCLKL_RATE( 816000000, 2, 4, 4), + RK3368_CPUCLKL_RATE( 696000000, 2, 3, 3), + RK3368_CPUCLKL_RATE( 600000000, 2, 3, 3), + RK3368_CPUCLKL_RATE( 408000000, 2, 2, 2), + RK3368_CPUCLKL_RATE( 312000000, 2, 2, 2), +}; + +static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { + /* + * Clock-Architecture Diagram 2 + */ + + MUX(SCLK_USBPHY480M, "usbphy_480m", mux_usbphy480m_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(13), 8, 1, MFLAGS), + + GATE(0, "apllb_core", "apllb", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 0, GFLAGS), + GATE(0, "gpllb_core", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 1, GFLAGS), + + GATE(0, "aplll_core", "aplll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 4, GFLAGS), + GATE(0, "gplll_core", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 5, GFLAGS), + + DIV(0, "aclkm_core_b", "armclkb", 0, + RK3368_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "atclk_core_b", "armclkb", 0, + RK3368_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "pclk_dbg_b", "armclkb", 0, + RK3368_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + + DIV(0, "aclkm_core_l", "armclkl", 0, + RK3368_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "atclk_core_l", "armclkl", 0, + RK3368_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "pclk_dbg_l", "armclkl", 0, + RK3368_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + + GATE(0, "apllb_cs", "apllb", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 9, GFLAGS), + GATE(0, "aplll_cs", "aplll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 10, GFLAGS), + GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 8, GFLAGS), + COMPOSITE_NOGATE(0, "sclk_cs_pre", mux_cs_src_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(0, "clkin_trace", "sclk_cs_pre", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(4), 8, 5, DFLAGS, + RK3368_CLKGATE_CON(0), 13, GFLAGS), + + COMPOSITE(0, "aclk_cci_pre", mux_pll_src_cpll_gpll_usb_npll_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(0), 12, GFLAGS), + GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3368_CLKGATE_CON(7), 10, GFLAGS), + + GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 8, GFLAGS), + GATE(0, "gpll_ddr", "gpll", 0, + RK3368_CLKGATE_CON(1), 9, GFLAGS), + COMPOSITE_NOGATE_DIVTBL(0, "ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(13), 4, 1, MFLAGS, 0, 2, DFLAGS, div_ddrphy_t), + + GATE(0, "sclk_ddr", "ddrphy_div4", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(6), 14, GFLAGS), + GATE(0, "sclk_ddr4x", "ddrphy_src", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(6), 15, GFLAGS), + + GATE(0, "gpll_aclk_bus", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 10, GFLAGS), + GATE(0, "cpll_aclk_bus", "cpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 11, GFLAGS), + COMPOSITE_NOGATE(0, "aclk_bus_src", mux_aclk_bus_src_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(8), 7, 1, MFLAGS, 0, 5, DFLAGS), + + GATE(ACLK_BUS, "aclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 0, GFLAGS), + COMPOSITE_NOMUX(PCLK_BUS, "pclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(8), 12, 3, DFLAGS, + RK3368_CLKGATE_CON(1), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_BUS, "hclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(8), 8, 2, DFLAGS, + RK3368_CLKGATE_CON(1), 1, GFLAGS), + COMPOSITE_NOMUX(0, "sclk_crypto", "aclk_bus_src", 0, + RK3368_CLKSEL_CON(10), 14, 2, DFLAGS, + RK3368_CLKGATE_CON(7), 2, GFLAGS), + + COMPOSITE(0, "fclk_mcu_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(12), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(1), 3, GFLAGS), + /* + * stclk_mcu is listed as child of fclk_mcu_src in diagram 5, + * but stclk_mcu has an additional own divider in diagram 2 + */ + COMPOSITE_NOMUX(0, "stclk_mcu", "fclk_mcu_src", 0, + RK3368_CLKSEL_CON(12), 8, 3, DFLAGS, + RK3368_CLKGATE_CON(13), 13, GFLAGS), + + COMPOSITE(0, "i2s_8ch_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(27), 12, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(6), 1, GFLAGS), + COMPOSITE_FRAC(0, "i2s_8ch_frac", "i2s_8ch_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(28), 0, + RK3368_CLKGATE_CON(6), 2, GFLAGS), + MUX(0, "i2s_8ch_pre", mux_i2s_8ch_pre_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(27), 8, 2, MFLAGS), + COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "i2s_8ch_clkout", mux_i2s_8ch_clkout_p, 0, + RK3368_CLKSEL_CON(27), 15, 1, MFLAGS, + RK3368_CLKGATE_CON(6), 0, GFLAGS), + GATE(SCLK_I2S_8CH, "sclk_i2s_8ch", "i2s_8ch_pre", CLK_SET_RATE_PARENT, + RK3368_CLKGATE_CON(6), 3, GFLAGS), + COMPOSITE(0, "spdif_8ch_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(31), 12, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(6), 4, GFLAGS), + COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(32), 0, + RK3368_CLKGATE_CON(6), 5, GFLAGS), + COMPOSITE_NODIV(SCLK_SPDIF_8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0, + RK3368_CLKSEL_CON(31), 8, 2, MFLAGS, + RK3368_CLKGATE_CON(6), 6, GFLAGS), + COMPOSITE(0, "i2s_2ch_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(53), 12, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(5), 13, GFLAGS), + COMPOSITE_FRAC(0, "i2s_2ch_frac", "i2s_2ch_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(54), 0, + RK3368_CLKGATE_CON(5), 14, GFLAGS), + COMPOSITE_NODIV(SCLK_I2S_2CH, "sclk_i2s_2ch", mux_i2s_2ch_p, 0, + RK3368_CLKSEL_CON(53), 8, 2, MFLAGS, + RK3368_CLKGATE_CON(5), 15, GFLAGS), + + COMPOSITE(0, "sclk_tsp", mux_pll_src_cpll_gpll_npll_p, 0, + RK3368_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(6), 12, GFLAGS), + GATE(0, "sclk_hsadc_tsp", "ext_hsadc_tsp", 0, + RK3368_CLKGATE_CON(13), 7, GFLAGS), + + MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(35), 12, 1, MFLAGS), + COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0, + RK3368_CLKSEL_CON(37), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 4, GFLAGS), + MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(37), 8, 1, MFLAGS), + + /* + * Clock-Architecture Diagram 3 + */ + + COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(15), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 6, GFLAGS), + COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(15), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 7, GFLAGS), + + /* + * We introduce a virtual node of hclk_vodec_pre_v to split one clock + * struct with a gate and a fix divider into two node in software. + */ + GATE(0, "hclk_video_pre_v", "aclk_vdpu", 0, + RK3368_CLKGATE_CON(4), 8, GFLAGS), + + COMPOSITE(0, "sclk_hevc_cabac_src", mux_pll_src_cpll_gpll_npll_usb_p, 0, + RK3368_CLKSEL_CON(17), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 1, GFLAGS), + COMPOSITE(0, "sclk_hevc_core_src", mux_pll_src_cpll_gpll_npll_usb_p, 0, + RK3368_CLKSEL_CON(17), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 2, GFLAGS), + + COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(19), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 0, GFLAGS), + DIV(0, "hclk_vio", "aclk_vio0", 0, + RK3368_CLKSEL_CON(21), 0, 5, DFLAGS), + + COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(18), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 3, GFLAGS), + COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(18), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 4, GFLAGS), + + COMPOSITE(DCLK_VOP, "dclk_vop", mux_pll_src_cpll_gpll_npll_p, 0, + RK3368_CLKSEL_CON(20), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3368_CLKGATE_CON(4), 1, GFLAGS), + + GATE(SCLK_VOP0_PWM, "sclk_vop0_pwm", "xin24m", 0, + RK3368_CLKGATE_CON(4), 2, GFLAGS), + + COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cpll_gpll_npll_npll_p, 0, + RK3368_CLKSEL_CON(22), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3368_CLKGATE_CON(4), 9, GFLAGS), + + GATE(0, "pclk_isp_in", "ext_isp", 0, + RK3368_CLKGATE_CON(17), 2, GFLAGS), + INVERTER(PCLK_ISP, "pclk_isp", "pclk_isp_in", + RK3368_CLKSEL_CON(21), 6, IFLAGS), + + GATE(0, "pclk_vip_in", "ext_vip", 0, + RK3368_CLKGATE_CON(16), 13, GFLAGS), + INVERTER(PCLK_VIP, "pclk_vip", "pclk_vip_in", + RK3368_CLKSEL_CON(21), 13, IFLAGS), + + GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0, + RK3368_CLKGATE_CON(4), 13, GFLAGS), + GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0, + RK3368_CLKGATE_CON(5), 12, GFLAGS), + + COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(21), 15, 1, MFLAGS, + RK3368_CLKGATE_CON(4), 5, GFLAGS), + COMPOSITE_NOGATE(0, "sclk_vip_out", mux_vip_out_p, 0, + RK3368_CLKSEL_CON(21), 14, 1, MFLAGS, 8, 5, DFLAGS), + + COMPOSITE_NODIV(SCLK_EDP_24M, "sclk_edp_24m", mux_edp_24m_p, 0, + RK3368_CLKSEL_CON(23), 8, 1, MFLAGS, + RK3368_CLKGATE_CON(5), 4, GFLAGS), + COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cpll_gpll_npll_npll_p, 0, + RK3368_CLKSEL_CON(23), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3368_CLKGATE_CON(5), 3, GFLAGS), + + COMPOSITE(SCLK_HDCP, "sclk_hdcp", mux_pll_src_cpll_gpll_npll_npll_p, 0, + RK3368_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3368_CLKGATE_CON(5), 5, GFLAGS), + + DIV(0, "pclk_pd_alive", "gpll", 0, + RK3368_CLKSEL_CON(10), 8, 5, DFLAGS), + + /* sclk_timer has a gate in the sgrf */ + + COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(10), 0, 5, DFLAGS, + RK3368_CLKGATE_CON(7), 9, GFLAGS), + GATE(SCLK_PVTM_PMU, "sclk_pvtm_pmu", "xin24m", 0, + RK3368_CLKGATE_CON(7), 3, GFLAGS), + COMPOSITE(0, "sclk_gpu_core_src", mux_pll_src_cpll_gpll_usb_npll_p, 0, + RK3368_CLKSEL_CON(14), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 11, GFLAGS), + MUX(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(14), 14, 1, MFLAGS), + COMPOSITE_NOMUX(0, "aclk_gpu_mem_pre", "aclk_gpu_src", 0, + RK3368_CLKSEL_CON(14), 8, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 8, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_gpu_cfg_pre", "aclk_gpu_src", 0, + RK3368_CLKSEL_CON(16), 8, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 9, GFLAGS), + GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, + RK3368_CLKGATE_CON(7), 11, GFLAGS), + + COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(9), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(3), 0, GFLAGS), + COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, + RK3368_CLKSEL_CON(9), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3368_CLKGATE_CON(3), 3, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(9), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3368_CLKGATE_CON(3), 2, GFLAGS), + GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(3), 1, GFLAGS), + + GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3368_CLKGATE_CON(4), 14, GFLAGS), + + /* + * Clock-Architecture Diagram 4 + */ + + COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(3), 7, GFLAGS), + COMPOSITE(SCLK_SPI1, "sclk_spi1", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(45), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3368_CLKGATE_CON(3), 8, GFLAGS), + COMPOSITE(SCLK_SPI2, "sclk_spi2", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(46), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3368_CLKGATE_CON(3), 9, GFLAGS), + + + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, + RK3368_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(7), 12, GFLAGS), + COMPOSITE(SCLK_SDIO0, "sclk_sdio0", mux_mmc_src_p, 0, + RK3368_CLKSEL_CON(48), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(7), 13, GFLAGS), + COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0, + RK3368_CLKSEL_CON(51), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(7), 15, GFLAGS), + + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3368_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3368_SDMMC_CON1, 0), + + MMC(SCLK_SDIO0_DRV, "sdio0_drv", "sclk_sdio0", RK3368_SDIO0_CON0, 1), + MMC(SCLK_SDIO0_SAMPLE, "sdio0_sample", "sclk_sdio0", RK3368_SDIO0_CON1, 0), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3368_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3368_EMMC_CON1, 0), + + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin24m", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(8), 1, GFLAGS), + + /* pmu_grf_soc_con0[6] allows to select between xin32k and pvtm_pmu */ + GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(8), 4, GFLAGS), + + /* pmu_grf_soc_con0[6] allows to select between xin32k and pvtm_pmu */ + COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin32k", 0, + RK3368_CLKSEL_CON(25), 0, 6, DFLAGS, + RK3368_CLKGATE_CON(3), 5, GFLAGS), + + COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, + RK3368_CLKSEL_CON(25), 8, 8, DFLAGS, + RK3368_CLKGATE_CON(3), 6, GFLAGS), + + COMPOSITE(SCLK_NANDC0, "sclk_nandc0", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(47), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(7), 8, GFLAGS), + + COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(52), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(6), 7, GFLAGS), + + COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gpll_usb_usb_p, 0, + RK3368_CLKSEL_CON(33), 12, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 0, GFLAGS), + COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(34), 0, + RK3368_CLKGATE_CON(2), 1, GFLAGS), + MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(33), 8, 2, MFLAGS), + + COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0, + RK3368_CLKSEL_CON(35), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 2, GFLAGS), + COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(36), 0, + RK3368_CLKGATE_CON(2), 3, GFLAGS), + MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(35), 8, 2, MFLAGS), + + COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0, + RK3368_CLKSEL_CON(39), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(40), 0, + RK3368_CLKGATE_CON(2), 7, GFLAGS), + MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(39), 8, 2, MFLAGS), + + COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0, + RK3368_CLKSEL_CON(41), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 8, GFLAGS), + COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(42), 0, + RK3368_CLKGATE_CON(2), 9, GFLAGS), + MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(41), 8, 2, MFLAGS), + + COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(43), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(3), 4, GFLAGS), + MUX(SCLK_MAC, "mac_clk", mux_mac_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(43), 8, 1, MFLAGS), + GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 7, GFLAGS), + GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 6, GFLAGS), + GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 4, GFLAGS), + GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 5, GFLAGS), + + GATE(0, "jtag", "ext_jtag", 0, + RK3368_CLKGATE_CON(7), 0, GFLAGS), + + COMPOSITE_NODIV(0, "hsic_usbphy_480m", mux_hsic_usbphy480m_p, 0, + RK3368_CLKSEL_CON(26), 8, 2, MFLAGS, + RK3368_CLKGATE_CON(8), 0, GFLAGS), + COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0, + RK3368_CLKSEL_CON(26), 12, 2, MFLAGS, + RK3368_CLKGATE_CON(8), 7, GFLAGS), + GATE(SCLK_HSICPHY12M, "sclk_hsicphy12m", "xin12m", 0, + RK3368_CLKGATE_CON(8), 6, GFLAGS), + + /* + * Clock-Architecture Diagram 5 + */ + + /* aclk_cci_pre gates */ + GATE(0, "aclk_core_niu_cpup", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 4, GFLAGS), + GATE(0, "aclk_core_niu_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 3, GFLAGS), + GATE(0, "aclk_cci400", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 2, GFLAGS), + GATE(0, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 1, GFLAGS), + GATE(0, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 0, GFLAGS), + + /* aclkm_core_* gates */ + GATE(0, "aclk_adb400s_pd_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(10), 0, GFLAGS), + GATE(0, "aclk_adb400s_pd_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(9), 0, GFLAGS), + + /* armclk* gates */ + GATE(0, "sclk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(10), 1, GFLAGS), + GATE(0, "sclk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(9), 1, GFLAGS), + + /* sclk_cs_pre gates */ + GATE(0, "sclk_dbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 7, GFLAGS), + GATE(0, "pclk_core_niu_sdbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 6, GFLAGS), + GATE(0, "hclk_core_niu_dbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 5, GFLAGS), + + /* aclk_bus gates */ + GATE(0, "aclk_strc_sys", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 12, GFLAGS), + GATE(ACLK_DMAC_BUS, "aclk_dmac_bus", "aclk_bus", 0, RK3368_CLKGATE_CON(12), 11, GFLAGS), + GATE(0, "sclk_intmem1", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 6, GFLAGS), + GATE(0, "sclk_intmem0", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 5, GFLAGS), + GATE(0, "aclk_intmem", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 4, GFLAGS), + GATE(0, "aclk_gic400", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(13), 9, GFLAGS), + + /* sclk_ddr gates */ + GATE(0, "nclk_ddrupctl", "sclk_ddr", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(13), 2, GFLAGS), + + /* clk_hsadc_tsp is part of diagram2 */ + + /* fclk_mcu_src gates */ + GATE(0, "hclk_noc_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 14, GFLAGS), + GATE(0, "fclk_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 12, GFLAGS), + GATE(0, "hclk_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* hclk_cpu gates */ + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 10, GFLAGS), + GATE(HCLK_ROM, "hclk_rom", "hclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 9, GFLAGS), + GATE(HCLK_I2S_2CH, "hclk_i2s_2ch", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 8, GFLAGS), + GATE(HCLK_I2S_8CH, "hclk_i2s_8ch", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 7, GFLAGS), + GATE(HCLK_TSP, "hclk_tsp", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 10, GFLAGS), + GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 4, GFLAGS), + GATE(MCLK_CRYPTO, "mclk_crypto", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 3, GFLAGS), + + /* pclk_cpu gates */ + GATE(PCLK_DDRPHY, "pclk_ddrphy", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 14, GFLAGS), + GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 13, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 3, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 2, GFLAGS), + GATE(PCLK_MAILBOX, "pclk_mailbox", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 1, GFLAGS), + GATE(PCLK_PWM0, "pclk_pwm0", "pclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 0, GFLAGS), + GATE(PCLK_SIM, "pclk_sim", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 8, GFLAGS), + GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 6, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 5, GFLAGS), + GATE(0, "pclk_efuse_256", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 1, GFLAGS), + GATE(0, "pclk_efuse_1024", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 0, GFLAGS), + + /* + * video clk gates + * aclk_video(_pre) can actually select between parents of aclk_vdpu + * and aclk_vepu by setting bit GRF_SOC_CON0[7]. + */ + GATE(ACLK_VIDEO, "aclk_video", "aclk_vdpu", 0, RK3368_CLKGATE_CON(15), 0, GFLAGS), + GATE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", "sclk_hevc_cabac_src", 0, RK3368_CLKGATE_CON(15), 3, GFLAGS), + GATE(SCLK_HEVC_CORE, "sclk_hevc_core", "sclk_hevc_core_src", 0, RK3368_CLKGATE_CON(15), 2, GFLAGS), + GATE(HCLK_VIDEO, "hclk_video", "hclk_video_pre", 0, RK3368_CLKGATE_CON(15), 1, GFLAGS), + + /* aclk_rga_pre gates */ + GATE(ACLK_VIO1_NOC, "aclk_vio1_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 10, GFLAGS), + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3368_CLKGATE_CON(16), 0, GFLAGS), + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_rga_pre", 0, RK3368_CLKGATE_CON(17), 10, GFLAGS), + + /* aclk_vio0 gates */ + GATE(ACLK_VIP, "aclk_vip", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 11, GFLAGS), + GATE(ACLK_VIO0_NOC, "aclk_vio0_noc", "aclk_vio0", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 9, GFLAGS), + GATE(ACLK_VOP, "aclk_vop", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 5, GFLAGS), + GATE(ACLK_VOP_IEP, "aclk_vop_iep", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 4, GFLAGS), + GATE(ACLK_IEP, "aclk_iep", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 2, GFLAGS), + + /* sclk_isp gates */ + GATE(HCLK_ISP, "hclk_isp", "sclk_isp", 0, RK3368_CLKGATE_CON(16), 14, GFLAGS), + GATE(ACLK_ISP, "aclk_isp", "sclk_isp", 0, RK3368_CLKGATE_CON(17), 0, GFLAGS), + + /* hclk_vio gates */ + GATE(HCLK_VIP, "hclk_vip", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 12, GFLAGS), + GATE(HCLK_VIO_NOC, "hclk_vio_noc", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 8, GFLAGS), + GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 7, GFLAGS), + GATE(HCLK_VOP, "hclk_vop", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 6, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 3, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 1, GFLAGS), + GATE(HCLK_VIO_HDCPMMU, "hclk_hdcpmmu", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 12, GFLAGS), + GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 7, GFLAGS), + + /* + * pclk_vio gates + * pclk_vio comes from the exactly same source as hclk_vio + */ + GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 11, GFLAGS), + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 9, GFLAGS), + GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 8, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 6, GFLAGS), + GATE(PCLK_MIPI_CSI, "pclk_mipi_csi", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS), + GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 3, GFLAGS), + + /* ext_vip gates in diagram3 */ + + /* gpu gates */ + GATE(SCLK_GPU_CORE, "sclk_gpu_core", "sclk_gpu_core_src", 0, RK3368_CLKGATE_CON(18), 2, GFLAGS), + GATE(ACLK_GPU_MEM, "aclk_gpu_mem", "aclk_gpu_mem_pre", 0, RK3368_CLKGATE_CON(18), 1, GFLAGS), + GATE(ACLK_GPU_CFG, "aclk_gpu_cfg", "aclk_gpu_cfg_pre", 0, RK3368_CLKGATE_CON(18), 0, GFLAGS), + + /* aclk_peri gates */ + GATE(ACLK_DMAC_PERI, "aclk_dmac_peri", "aclk_peri", 0, RK3368_CLKGATE_CON(19), 3, GFLAGS), + GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 2, GFLAGS), + GATE(HCLK_SFC, "hclk_sfc", "aclk_peri", 0, RK3368_CLKGATE_CON(20), 15, GFLAGS), + GATE(ACLK_GMAC, "aclk_gmac", "aclk_peri", 0, RK3368_CLKGATE_CON(20), 13, GFLAGS), + GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 8, GFLAGS), + GATE(ACLK_PERI_MMU, "aclk_peri_mmu", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(21), 4, GFLAGS), + + /* hclk_peri gates */ + GATE(0, "hclk_peri_axi_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 0, GFLAGS), + GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 11, GFLAGS), + GATE(0, "hclk_mmc_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 10, GFLAGS), + GATE(0, "hclk_emem_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 9, GFLAGS), + GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 7, GFLAGS), + GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 6, GFLAGS), + GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 5, GFLAGS), + GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 4, GFLAGS), + GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 3, GFLAGS), + GATE(0, "pmu_hclk_otg0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 2, GFLAGS), + GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 1, GFLAGS), + GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 3, GFLAGS), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 2, GFLAGS), + GATE(HCLK_SDIO0, "hclk_sdio0", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 1, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 0, GFLAGS), + + /* pclk_peri gates */ + GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 15, GFLAGS), + GATE(PCLK_I2C5, "pclk_i2c5", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 14, GFLAGS), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 13, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 12, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 11, GFLAGS), + GATE(PCLK_UART4, "pclk_uart4", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 10, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 9, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 8, GFLAGS), + GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 7, GFLAGS), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 6, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 5, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 4, GFLAGS), + GATE(0, "pclk_peri_axi_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 1, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 14, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 0, GFLAGS), + + /* pclk_pd_alive gates */ + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 8, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 7, GFLAGS), + GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 12, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 11, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 3, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 2, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 1, GFLAGS), + + /* + * pclk_vio gates + * pclk_vio comes from the exactly same source as hclk_vio + */ + GATE(0, "pclk_dphyrx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS), + GATE(0, "pclk_dphytx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS), + + /* pclk_pd_pmu gates */ + GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 0, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 3, GFLAGS), + GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS), + GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 1, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS), + + /* timer gates */ + GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS), + GATE(0, "sclk_timer14", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 10, GFLAGS), + GATE(0, "sclk_timer13", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 9, GFLAGS), + GATE(0, "sclk_timer12", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 8, GFLAGS), + GATE(0, "sclk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 7, GFLAGS), + GATE(0, "sclk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 6, GFLAGS), + GATE(0, "sclk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 5, GFLAGS), + GATE(0, "sclk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 4, GFLAGS), + GATE(0, "sclk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 3, GFLAGS), + GATE(0, "sclk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 2, GFLAGS), + GATE(0, "sclk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 1, GFLAGS), + GATE(0, "sclk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 0, GFLAGS), +}; + +static void __init rk3368_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + struct clk *clk; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + + /* xin12m is created by a cru-internal divider */ + clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock xin12m: %ld\n", + __func__, PTR_ERR(clk)); + + /* ddrphy_div4 is created by a cru-internal divider */ + clk = clk_register_fixed_factor(NULL, "ddrphy_div4", "ddrphy_src", 0, 1, 4); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock xin12m: %ld\n", + __func__, PTR_ERR(clk)); + + clk = clk_register_fixed_factor(NULL, "hclk_video_pre", + "hclk_video_pre_v", 0, 1, 4); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", + __func__, PTR_ERR(clk)); + + /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */ + clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock pclk_wdt: %ld\n", + __func__, PTR_ERR(clk)); + else + rockchip_clk_add_lookup(clk, PCLK_WDT); + + rockchip_clk_register_plls(rk3368_pll_clks, + ARRAY_SIZE(rk3368_pll_clks), + RK3368_GRF_SOC_STATUS0); + rockchip_clk_register_branches(rk3368_clk_branches, + ARRAY_SIZE(rk3368_clk_branches)); + + rockchip_clk_register_armclk(ARMCLKB, "armclkb", + mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p), + &rk3368_cpuclkb_data, rk3368_cpuclkb_rates, + ARRAY_SIZE(rk3368_cpuclkb_rates)); + + rockchip_clk_register_armclk(ARMCLKL, "armclkl", + mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p), + &rk3368_cpuclkl_data, rk3368_cpuclkl_rates, + ARRAY_SIZE(rk3368_cpuclkl_rates)); + + rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(RK3368_GLB_SRST_FST); +} +CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 052b94d..2493881 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -277,6 +277,13 @@ void __init rockchip_clk_register_branches( list->div_shift ); break; + case branch_inverter: + clk = rockchip_clk_register_inverter( + list->name, list->parent_names, + list->num_parents, + reg_base + list->muxdiv_offset, + list->div_shift, list->div_flags, &clk_lock); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 1b16781..93ea335 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -31,22 +31,22 @@ struct clk; ((val) << (shift) | (mask) << ((shift) + 16)) /* register positions shared by RK2928, RK3066 and RK3188 */ -#define RK2928_PLL_CON(x) (x * 0x4) +#define RK2928_PLL_CON(x) ((x) * 0x4) #define RK2928_MODE_CON 0x40 -#define RK2928_CLKSEL_CON(x) (x * 0x4 + 0x44) -#define RK2928_CLKGATE_CON(x) (x * 0x4 + 0xd0) +#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) +#define RK2928_CLKGATE_CON(x) ((x) * 0x4 + 0xd0) #define RK2928_GLB_SRST_FST 0x100 #define RK2928_GLB_SRST_SND 0x104 -#define RK2928_SOFTRST_CON(x) (x * 0x4 + 0x110) +#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110) #define RK2928_MISC_CON 0x134 #define RK3288_PLL_CON(x) RK2928_PLL_CON(x) #define RK3288_MODE_CON 0x50 -#define RK3288_CLKSEL_CON(x) (x * 0x4 + 0x60) -#define RK3288_CLKGATE_CON(x) (x * 0x4 + 0x160) +#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60) +#define RK3288_CLKGATE_CON(x) ((x) * 0x4 + 0x160) #define RK3288_GLB_SRST_FST 0x1b0 #define RK3288_GLB_SRST_SND 0x1b4 -#define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8) +#define RK3288_SOFTRST_CON(x) ((x) * 0x4 + 0x1b8) #define RK3288_MISC_CON 0x1e8 #define RK3288_SDMMC_CON0 0x200 #define RK3288_SDMMC_CON1 0x204 @@ -57,6 +57,22 @@ struct clk; #define RK3288_EMMC_CON0 0x218 #define RK3288_EMMC_CON1 0x21c +#define RK3368_PLL_CON(x) RK2928_PLL_CON(x) +#define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100) +#define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200) +#define RK3368_GLB_SRST_FST 0x280 +#define RK3368_GLB_SRST_SND 0x284 +#define RK3368_SOFTRST_CON(x) ((x) * 0x4 + 0x300) +#define RK3368_MISC_CON 0x380 +#define RK3368_SDMMC_CON0 0x400 +#define RK3368_SDMMC_CON1 0x404 +#define RK3368_SDIO0_CON0 0x408 +#define RK3368_SDIO0_CON1 0x40c +#define RK3368_SDIO1_CON0 0x410 +#define RK3368_SDIO1_CON1 0x414 +#define RK3368_EMMC_CON0 0x418 +#define RK3368_EMMC_CON1 0x41c + enum rockchip_pll_type { pll_rk3066, }; @@ -67,7 +83,7 @@ enum rockchip_pll_type { .nr = _nr, \ .nf = _nf, \ .no = _no, \ - .bwadj = (_nf >> 1), \ + .bwadj = ((_nf) >> 1), \ } #define RK3066_PLL_RATE_BWADJ(_rate, _nr, _nf, _no, _bw) \ @@ -182,6 +198,13 @@ struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *reg, int shift); +#define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0) + +struct clk *rockchip_clk_register_inverter(const char *name, + const char *const *parent_names, u8 num_parents, + void __iomem *reg, int shift, int flags, + spinlock_t *lock); + #define PNAME(x) static const char *const x[] __initconst enum rockchip_clk_branch_type { @@ -191,6 +214,7 @@ enum rockchip_clk_branch_type { branch_fraction_divider, branch_gate, branch_mmc, + branch_inverter, }; struct rockchip_clk_branch { @@ -308,6 +332,26 @@ struct rockchip_clk_branch { .gate_offset = -1, \ } +#define COMPOSITE_NOGATE_DIVTBL(_id, cname, pnames, f, mo, ms, \ + mw, mf, ds, dw, df, dt) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .div_table = dt, \ + .gate_offset = -1, \ + } + #define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\ { \ .id = _id, \ @@ -394,6 +438,18 @@ struct rockchip_clk_branch { .div_shift = shift, \ } +#define INVERTER(_id, cname, pname, io, is, if) \ + { \ + .id = _id, \ + .branch_type = branch_inverter, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .muxdiv_offset = io, \ + .div_shift = is, \ + .div_flags = if, \ + } + void rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); struct regmap *rockchip_clk_get_grf(void); diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c index 036a692..6810bfb 100644 --- a/drivers/clk/shmobile/clk-div6.c +++ b/drivers/clk/shmobile/clk-div6.c @@ -11,12 +11,12 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/slab.h> #define CPG_DIV6_CKSTP BIT(8) #define CPG_DIV6_DIV(d) ((d) & 0x3f) diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c index 29b9a0b0..9326204 100644 --- a/drivers/clk/shmobile/clk-r8a73a4.c +++ b/drivers/clk/shmobile/clk-r8a73a4.c @@ -9,10 +9,10 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/clk/shmobile.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/spinlock.h> diff --git a/drivers/clk/shmobile/clk-r8a7740.c b/drivers/clk/shmobile/clk-r8a7740.c index 1e2eaae..1e6b1da 100644 --- a/drivers/clk/shmobile/clk-r8a7740.c +++ b/drivers/clk/shmobile/clk-r8a7740.c @@ -9,10 +9,10 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/clk/shmobile.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/spinlock.h> diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c index cb33b57..e97e28f 100644 --- a/drivers/clk/shmobile/clk-r8a7778.c +++ b/drivers/clk/shmobile/clk-r8a7778.c @@ -9,9 +9,9 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/clk/shmobile.h> #include <linux/of_address.h> +#include <linux/slab.h> struct r8a7778_cpg { struct clk_onecell_data data; diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c index 652ecac..af29796 100644 --- a/drivers/clk/shmobile/clk-r8a7779.c +++ b/drivers/clk/shmobile/clk-r8a7779.c @@ -11,12 +11,12 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/clk/shmobile.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <dt-bindings/clock/r8a7779-clock.h> diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index acfb6d7..9233ebf 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c @@ -11,13 +11,13 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/clk/shmobile.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/math64.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/slab.h> #include <linux/spinlock.h> struct rcar_gen2_cpg { diff --git a/drivers/clk/shmobile/clk-sh73a0.c b/drivers/clk/shmobile/clk-sh73a0.c index cd529cf..8966f8b 100644 --- a/drivers/clk/shmobile/clk-sh73a0.c +++ b/drivers/clk/shmobile/clk-sh73a0.c @@ -9,12 +9,12 @@ */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/clk/shmobile.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/slab.h> #include <linux/spinlock.h> struct sh73a0_cpg { diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 8e0dbb1f..ec20a2c 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -191,7 +191,7 @@ static struct clk *clk_register_flexgen(const char *name, init.name = name; init.ops = &flexgen_ops; - init.flags = CLK_IS_BASIC | flexgen_flags; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE | flexgen_flags; init.parent_names = parent_names; init.num_parents = num_parents; @@ -244,7 +244,7 @@ static const char ** __init flexgen_get_parents(struct device_node *np, int *num_parents) { const char **parents; - int nparents, i; + int nparents; nparents = of_clk_get_parent_count(np); if (WARN_ON(nparents <= 0)) @@ -254,10 +254,8 @@ static const char ** __init flexgen_get_parents(struct device_node *np, if (!parents) return NULL; - for (i = 0; i < nparents; i++) - parents[i] = of_clk_get_parent_name(np, i); + *num_parents = of_clk_parent_fill(np, parents, nparents); - *num_parents = nparents; return parents; } @@ -304,6 +302,8 @@ static void __init st_of_flexgen_setup(struct device_node *np) if (!rlock) goto err; + spin_lock_init(rlock); + for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; const char *clk_name; diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 90c2071..aa3117d 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -341,7 +341,7 @@ static const struct clkgen_quadfs_data st_fs660c32_C_407 = { CLKGEN_FIELD(0x30c, 0xf, 20), CLKGEN_FIELD(0x310, 0xf, 20) }, .lockstatus_present = true, - .lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24), + .lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24), .powerup_polarity = 1, .standby_polarity = 1, .pll_ops = &st_quadfs_pll_c32_ops, @@ -490,7 +490,7 @@ static int quadfs_pll_is_enabled(struct clk_hw *hw) struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); u32 npda = CLKGEN_READ(pll, npda); - return !!npda; + return pll->data->powerup_polarity ? !npda : !!npda; } static int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs, @@ -636,7 +636,7 @@ static struct clk * __init st_clk_register_quadfs_pll( init.name = name; init.ops = quadfs->pll_ops; - init.flags = CLK_IS_BASIC; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; init.parent_names = &parent_name; init.num_parents = 1; @@ -775,7 +775,7 @@ static void quadfs_fsynth_disable(struct clk_hw *hw) if (fs->lock) spin_lock_irqsave(fs->lock, flags); - CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); + CLKGEN_WRITE(fs, nsb[fs->chan], fs->data->standby_polarity); if (fs->lock) spin_unlock_irqrestore(fs->lock, flags); @@ -1083,10 +1083,6 @@ static const struct of_device_id quadfs_of_match[] = { .compatible = "st,stih407-quadfs660-D", .data = &st_fs660c32_D_407 }, - { - .compatible = "st,stih407-quadfs660-D", - .data = (void *)&st_fs660c32_D_407 - }, {} }; diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index 4fc95d5..81f2372 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -25,20 +25,17 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np, int *num_parents) { const char **parents; - int nparents, i; + int nparents; nparents = of_clk_get_parent_count(np); if (WARN_ON(nparents <= 0)) return ERR_PTR(-EINVAL); - parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL); + parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL); if (!parents) return ERR_PTR(-ENOMEM); - for (i = 0; i < nparents; i++) - parents[i] = of_clk_get_parent_name(np, i); - - *num_parents = nparents; + *num_parents = of_clk_parent_fill(np, parents, nparents); return parents; } @@ -216,7 +213,7 @@ static const struct clk_ops clkgena_divmux_ops = { /** * clk_register_genamux - register a genamux clock with the clock framework */ -static struct clk *clk_register_genamux(const char *name, +static struct clk * __init clk_register_genamux(const char *name, const char **parent_names, u8 num_parents, void __iomem *reg, const struct clkgena_divmux_data *muxdata, @@ -238,7 +235,7 @@ static struct clk *clk_register_genamux(const char *name, init.name = name; init.ops = &clkgena_divmux_ops; - init.flags = CLK_IS_BASIC; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; init.parent_names = parent_names; init.num_parents = num_parents; @@ -370,11 +367,10 @@ static const struct of_device_id clkgena_divmux_of_match[] = { {} }; -static void __iomem * __init clkgen_get_register_base( - struct device_node *np) +static void __iomem * __init clkgen_get_register_base(struct device_node *np) { struct device_node *pnode; - void __iomem *reg = NULL; + void __iomem *reg; pnode = of_get_parent(np); if (!pnode) @@ -399,7 +395,7 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np) if (WARN_ON(!match)) return; - data = (struct clkgena_divmux_data *)match->data; + data = match->data; reg = clkgen_get_register_base(np); if (!reg) @@ -407,18 +403,18 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np) parents = clkgen_mux_get_parents(np, &num_parents); if (IS_ERR(parents)) - return; + goto err_parents; clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); if (!clk_data) - goto err; + goto err_alloc; clk_data->clk_num = data->num_outputs; - clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), + clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) - goto err; + goto err_alloc_clks; for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; @@ -448,11 +444,13 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); return; err: - if (clk_data) - kfree(clk_data->clks); - + kfree(clk_data->clks); +err_alloc_clks: kfree(clk_data); +err_alloc: kfree(parents); +err_parents: + iounmap(reg); } CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup); @@ -492,7 +490,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) void __iomem *reg; const char *parent_name, *clk_name; struct clk *clk; - struct clkgena_prediv_data *data; + const struct clkgena_prediv_data *data; match = of_match_node(clkgena_prediv_of_match, np); if (!match) { @@ -500,7 +498,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) return; } - data = (struct clkgena_prediv_data *)match->data; + data = match->data; reg = clkgen_get_register_base(np); if (!reg) @@ -508,17 +506,18 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) parent_name = of_clk_get_parent_name(np, 0); if (!parent_name) - return; + goto err; if (of_property_read_string_index(np, "clock-output-names", 0, &clk_name)) - return; + goto err; - clk = clk_register_divider_table(NULL, clk_name, parent_name, 0, + clk = clk_register_divider_table(NULL, clk_name, parent_name, + CLK_GET_RATE_NOCACHE, reg + data->offset, data->shift, 1, 0, data->table, NULL); if (IS_ERR(clk)) - return; + goto err; of_clk_add_provider(np, of_clk_src_simple_get, clk); pr_debug("%s: parent %s rate %u\n", @@ -527,6 +526,8 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) (unsigned int)clk_get_rate(clk)); return; +err: + iounmap(reg); } CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup); @@ -583,7 +584,7 @@ static struct clkgen_mux_data stih416_a9_mux_data = { }; static struct clkgen_mux_data stih407_a9_mux_data = { .offset = 0x1a4, - .shift = 1, + .shift = 0, .width = 2, }; @@ -630,7 +631,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) void __iomem *reg; const char **parents; int num_parents; - struct clkgen_mux_data *data; + const struct clkgen_mux_data *data; match = of_match_node(mux_of_match, np); if (!match) { @@ -638,7 +639,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) return; } - data = (struct clkgen_mux_data *)match->data; + data = match->data; reg = of_iomap(np, 0); if (!reg) { @@ -650,7 +651,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) if (IS_ERR(parents)) { pr_err("%s: Failed to get parents (%ld)\n", __func__, PTR_ERR(parents)); - return; + goto err_parents; } clk = clk_register_mux(NULL, np->name, parents, num_parents, @@ -666,12 +667,14 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) __clk_get_name(clk_get_parent(clk)), (unsigned int)clk_get_rate(clk)); + kfree(parents); of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; err: kfree(parents); - - return; +err_parents: + iounmap(reg); } CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup); @@ -707,12 +710,12 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) const char **parents; int num_parents, i; struct clk_onecell_data *clk_data; - struct clkgen_vcc_data *data; + const struct clkgen_vcc_data *data; match = of_match_node(vcc_of_match, np); if (WARN_ON(!match)) return; - data = (struct clkgen_vcc_data *)match->data; + data = match->data; reg = of_iomap(np, 0); if (!reg) @@ -720,18 +723,18 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) parents = clkgen_mux_get_parents(np, &num_parents); if (IS_ERR(parents)) - return; + goto err_parents; clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); if (!clk_data) - goto err; + goto err_alloc; clk_data->clk_num = VCC_MAX_CHANNELS; - clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), + clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) - goto err; + goto err_alloc_clks; for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; @@ -750,21 +753,21 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) if (*clk_name == '\0') continue; - gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) - break; + goto err; - div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); + div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) { kfree(gate); - break; + goto err; } - mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); + mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) { kfree(gate); kfree(div); - break; + goto err; } gate->reg = reg + VCC_GATE_OFFSET; @@ -787,7 +790,8 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) &mux->hw, &clk_mux_ops, &div->hw, &clk_divider_ops, &gate->hw, &clk_gate_ops, - data->clk_flags); + data->clk_flags | + CLK_GET_RATE_NOCACHE); if (IS_ERR(clk)) { kfree(gate); kfree(div); @@ -822,10 +826,12 @@ err: kfree(container_of(composite->mux_hw, struct clk_mux, hw)); } - if (clk_data) - kfree(clk_data->clks); - + kfree(clk_data->clks); +err_alloc_clks: kfree(clk_data); +err_alloc: kfree(parents); +err_parents: + iounmap(reg); } CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup); diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index cdb14b9..cc2b52e 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -407,7 +407,7 @@ static struct clk * __init clkgen_pll_register(const char *parent_name, init.name = clk_name; init.ops = pll_data->ops; - init.flags = CLK_IS_BASIC; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; init.parent_names = &parent_name; init.num_parents = 1; diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c index 0dcf4f2..1611b03 100644 --- a/drivers/clk/sunxi/clk-a20-gmac.c +++ b/drivers/clk/sunxi/clk-a20-gmac.c @@ -80,9 +80,7 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) goto free_mux; /* gmac clock requires exactly 2 parents */ - parents[0] = of_clk_get_parent_name(node, 0); - parents[1] = of_clk_get_parent_name(node, 1); - if (!parents[0] || !parents[1]) + if (of_clk_parent_fill(node, parents, 2) != 2) goto free_gate; reg = of_iomap(node, 0); diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 8c20190..a650eae 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -79,11 +79,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, return rate; } -static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int clk_factors_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -96,24 +93,28 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, if (!parent) continue; if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) - parent_rate = __clk_round_rate(parent, rate); + parent_rate = __clk_round_rate(parent, req->rate); else parent_rate = __clk_get_rate(parent); - child_rate = clk_factors_round_rate(hw, rate, &parent_rate); + child_rate = clk_factors_round_rate(hw, req->rate, + &parent_rate); - if (child_rate <= rate && child_rate > best_child_rate) { + if (child_rate <= req->rate && child_rate > best_child_rate) { best_parent = parent; best = parent_rate; best_child_rate = child_rate; } } - if (best_parent) - *best_parent_p = __clk_get_hw(best_parent); - *best_parent_rate = best; + if (!best_parent) + return -EINVAL; - return best_child_rate; + req->best_parent_hw = __clk_get_hw(best_parent); + req->best_parent_rate = best; + req->rate = best_child_rate; + + return 0; } static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, @@ -174,9 +175,7 @@ struct clk *sunxi_factors_register(struct device_node *node, int i = 0; /* if we have a mux, we will have >1 parents */ - while (i < FACTORS_MAX_PARENTS && - (parents[i] = of_clk_get_parent_name(node, i)) != NULL) - i++; + i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS); /* * some factor clocks, such as pll5 and pll6, may have multiple diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index 63cf149..3a2ea01 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -44,17 +44,14 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw, return (parent_rate >> shift) / (div + 1); } -static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int ar100_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int nparents = __clk_get_num_parents(hw->clk); long best_rate = -EINVAL; int i; - *best_parent_clk = NULL; + req->best_parent_hw = NULL; for (i = 0; i < nparents; i++) { unsigned long parent_rate; @@ -65,7 +62,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, parent = clk_get_parent_by_index(hw->clk, i); parent_rate = __clk_get_rate(parent); - div = DIV_ROUND_UP(parent_rate, rate); + div = DIV_ROUND_UP(parent_rate, req->rate); /* * The AR100 clk contains 2 divisors: @@ -101,14 +98,19 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, continue; tmp_rate = (parent_rate >> shift) / div; - if (!*best_parent_clk || tmp_rate > best_rate) { - *best_parent_clk = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + if (!req->best_parent_hw || tmp_rate > best_rate) { + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; best_rate = tmp_rate; } } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + + return 0; } static int ar100_set_parent(struct clk_hw *hw, u8 index) @@ -180,7 +182,6 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) struct resource *r; struct clk *clk; int nparents; - int i; ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL); if (!ar100) @@ -195,8 +196,7 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) if (nparents > SUN6I_AR100_MAX_PARENTS) nparents = SUN6I_AR100_MAX_PARENTS; - for (i = 0; i < nparents; i++) - parents[i] = of_clk_get_parent_name(np, i); + of_clk_parent_fill(np, parents, nparents); of_property_read_string(np, "clock-output-names", &clk_name); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 4ac2612..1c5b136 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -120,11 +120,8 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp, return (parent_rate / calcm) >> calcp; } -static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -137,25 +134,28 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, if (!parent) continue; if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) - parent_rate = __clk_round_rate(parent, rate); + parent_rate = __clk_round_rate(parent, req->rate); else parent_rate = __clk_get_rate(parent); - child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i, + child_rate = sun6i_ahb1_clk_round(req->rate, NULL, NULL, i, parent_rate); - if (child_rate <= rate && child_rate > best_child_rate) { + if (child_rate <= req->rate && child_rate > best_child_rate) { best_parent = parent; best = parent_rate; best_child_rate = child_rate; } } - if (best_parent) - *best_parent_clk = __clk_get_hw(best_parent); - *best_parent_rate = best; + if (!best_parent) + return -EINVAL; - return best_child_rate; + req->best_parent_hw = __clk_get_hw(best_parent); + req->best_parent_rate = best; + req->rate = best_child_rate; + + return 0; } static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -197,17 +197,14 @@ static void __init sun6i_ahb1_clk_setup(struct device_node *node) const char *clk_name = node->name; const char *parents[SUN6I_AHB1_MAX_PARENTS]; void __iomem *reg; - int i = 0; + int i; reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) return; /* we have a mux, we will have >1 parents */ - while (i < SUN6I_AHB1_MAX_PARENTS && - (parents[i] = of_clk_get_parent_name(node, i)) != NULL) - i++; - + i = of_clk_parent_fill(node, parents, SUN6I_AHB1_MAX_PARENTS); of_property_read_string(node, "clock-output-names", &clk_name); ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL); @@ -788,14 +785,11 @@ static void __init sunxi_mux_clk_setup(struct device_node *node, const char *clk_name = node->name; const char *parents[SUNXI_MAX_PARENTS]; void __iomem *reg; - int i = 0; + int i; reg = of_iomap(node, 0); - while (i < SUNXI_MAX_PARENTS && - (parents[i] = of_clk_get_parent_name(node, i)) != NULL) - i++; - + i = of_clk_parent_fill(node, parents, SUNXI_MAX_PARENTS); of_property_read_string(node, "clock-output-names", &clk_name); clk = clk_register_mux(NULL, clk_name, parents, i, diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 7649685..08ae518 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -116,11 +116,7 @@ static unsigned long emc_recalc_rate(struct clk_hw *hw, * safer since things have EMC rate floors. Also don't touch parent_rate * since we don't want the CCF to play with our parent clocks. */ -static long emc_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct tegra_clk_emc *tegra; u8 ram_code = tegra_read_ram_code(); @@ -135,22 +131,28 @@ static long emc_determine_rate(struct clk_hw *hw, unsigned long rate, timing = tegra->timings + i; - if (timing->rate > max_rate) { + if (timing->rate > req->max_rate) { i = min(i, 1); - return tegra->timings[i - 1].rate; + req->rate = tegra->timings[i - 1].rate; + return 0; } - if (timing->rate < min_rate) + if (timing->rate < req->min_rate) continue; - if (timing->rate >= rate) - return timing->rate; + if (timing->rate >= req->rate) { + req->rate = timing->rate; + return 0; + } } - if (timing) - return timing->rate; + if (timing) { + req->rate = timing->rate; + return 0; + } - return __clk_get_rate(hw->clk); + req->rate = __clk_get_rate(hw->clk); + return 0; } static u8 emc_get_parent(struct clk_hw *hw) diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 105ffd0..9b93e69 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -1,16 +1,19 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ - fixed-factor.o mux.o apll.o -obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o + fixed-factor.o mux.o apll.o \ + clkt_dpll.o clkt_iclk.o clkt_dflt.o +obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \ - clk-3xxx.o -obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o -obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o + clk-3xxx.o dpll3xxx.o +obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o \ + dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o \ + dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ - clk-dra7-atl.o -obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o + clk-dra7-atl.o dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o ifdef CONFIG_ATAGS obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 671f4d8..24febd4 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -28,6 +28,8 @@ #include <linux/clk/ti.h> #include <linux/delay.h> +#include "clock.h" + #define APLL_FORCE_LOCK 0x1 #define APLL_AUTO_IDLE 0x2 #define MAX_APLL_WAIT_TRIES 1000000 @@ -171,7 +173,6 @@ static void __init of_dra7_apll_setup(struct device_node *node) struct clk_hw_omap *clk_hw = NULL; struct clk_init_data *init = NULL; const char **parent_names = NULL; - int i; ad = kzalloc(sizeof(*ad), GFP_KERNEL); clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); @@ -196,8 +197,7 @@ static void __init of_dra7_apll_setup(struct device_node *node) if (!parent_names) goto cleanup; - for (i = 0; i < init->num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, init->num_parents); init->parent_names = parent_names; diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index e75c64c9..94f0dcd 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -22,6 +22,8 @@ #include <linux/of_address.h> #include <linux/clk/ti.h> +#include "clock.h" + struct clk_ti_autoidle { void __iomem *reg; u8 shift; @@ -33,8 +35,47 @@ struct clk_ti_autoidle { #define AUTOIDLE_LOW 0x1 static LIST_HEAD(autoidle_clks); +static LIST_HEAD(clk_hw_omap_clocks); -static void ti_allow_autoidle(struct clk_ti_autoidle *clk) +/** + * omap2_clk_deny_idle - disable autoidle on an OMAP clock + * @clk: struct clk * to disable autoidle for + * + * Disable autoidle on an OMAP clock. + */ +int omap2_clk_deny_idle(struct clk *clk) +{ + struct clk_hw_omap *c; + + if (__clk_get_flags(clk) & CLK_IS_BASIC) + return -EINVAL; + + c = to_clk_hw_omap(__clk_get_hw(clk)); + if (c->ops && c->ops->deny_idle) + c->ops->deny_idle(c); + return 0; +} + +/** + * omap2_clk_allow_idle - enable autoidle on an OMAP clock + * @clk: struct clk * to enable autoidle for + * + * Enable autoidle on an OMAP clock. + */ +int omap2_clk_allow_idle(struct clk *clk) +{ + struct clk_hw_omap *c; + + if (__clk_get_flags(clk) & CLK_IS_BASIC) + return -EINVAL; + + c = to_clk_hw_omap(__clk_get_hw(clk)); + if (c->ops && c->ops->allow_idle) + c->ops->allow_idle(c); + return 0; +} + +static void _allow_autoidle(struct clk_ti_autoidle *clk) { u32 val; @@ -48,7 +89,7 @@ static void ti_allow_autoidle(struct clk_ti_autoidle *clk) ti_clk_ll_ops->clk_writel(val, clk->reg); } -static void ti_deny_autoidle(struct clk_ti_autoidle *clk) +static void _deny_autoidle(struct clk_ti_autoidle *clk) { u32 val; @@ -63,31 +104,31 @@ static void ti_deny_autoidle(struct clk_ti_autoidle *clk) } /** - * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks + * _clk_generic_allow_autoidle_all - enable autoidle for all clocks * * Enables hardware autoidle for all registered DT clocks, which have * the feature. */ -void of_ti_clk_allow_autoidle_all(void) +static void _clk_generic_allow_autoidle_all(void) { struct clk_ti_autoidle *c; list_for_each_entry(c, &autoidle_clks, node) - ti_allow_autoidle(c); + _allow_autoidle(c); } /** - * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks + * _clk_generic_deny_autoidle_all - disable autoidle for all clocks * * Disables hardware autoidle for all registered DT clocks, which have * the feature. */ -void of_ti_clk_deny_autoidle_all(void) +static void _clk_generic_deny_autoidle_all(void) { struct clk_ti_autoidle *c; list_for_each_entry(c, &autoidle_clks, node) - ti_deny_autoidle(c); + _deny_autoidle(c); } /** @@ -131,3 +172,67 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node) return 0; } + +/** + * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock + * @clk: struct clk * to initialize + * + * Add an OMAP clock @clk to the internal list of OMAP clocks. Used + * temporarily for autoidle handling, until this support can be + * integrated into the common clock framework code in some way. No + * return value. + */ +void omap2_init_clk_hw_omap_clocks(struct clk *clk) +{ + struct clk_hw_omap *c; + + if (__clk_get_flags(clk) & CLK_IS_BASIC) + return; + + c = to_clk_hw_omap(__clk_get_hw(clk)); + list_add(&c->node, &clk_hw_omap_clocks); +} + +/** + * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that + * support it + * + * Enable clock autoidle on all OMAP clocks that have allow_idle + * function pointers associated with them. This function is intended + * to be temporary until support for this is added to the common clock + * code. Returns 0. + */ +int omap2_clk_enable_autoidle_all(void) +{ + struct clk_hw_omap *c; + + list_for_each_entry(c, &clk_hw_omap_clocks, node) + if (c->ops && c->ops->allow_idle) + c->ops->allow_idle(c); + + _clk_generic_allow_autoidle_all(); + + return 0; +} + +/** + * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that + * support it + * + * Disable clock autoidle on all OMAP clocks that have allow_idle + * function pointers associated with them. This function is intended + * to be temporary until support for this is added to the common clock + * code. Returns 0. + */ +int omap2_clk_disable_autoidle_all(void) +{ + struct clk_hw_omap *c; + + list_for_each_entry(c, &clk_hw_omap_clocks, node) + if (c->ops && c->ops->deny_idle) + c->ops->deny_idle(c); + + _clk_generic_deny_autoidle_all(); + + return 0; +} diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c index 20cf5ee..657c4fe 100644 --- a/drivers/clk/ti/clk-2xxx.c +++ b/drivers/clk/ti/clk-2xxx.c @@ -19,6 +19,8 @@ #include <linux/clk.h> #include <linux/clk/ti.h> +#include "clock.h" + static struct ti_dt_clk omap2xxx_clks[] = { DT_CLK(NULL, "func_32k_ck", "func_32k_ck"), DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"), diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c index 9616bcd..ef2ec64 100644 --- a/drivers/clk/ti/clk-33xx.c +++ b/drivers/clk/ti/clk-33xx.c @@ -20,6 +20,8 @@ #include <linux/clk-provider.h> #include <linux/clk/ti.h> +#include "clock.h" + static struct ti_dt_clk am33xx_clks[] = { DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 5df21b2..676ee8f 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -20,6 +20,216 @@ #include <linux/clk-provider.h> #include <linux/clk/ti.h> +#include "clock.h" + +/* + * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks + * that are sourced by DPLL5, and both of these require this clock + * to be at 120 MHz for proper operation. + */ +#define DPLL5_FREQ_FOR_USBHOST 120000000 + +#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1 +#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5 +#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8 + +#define OMAP34XX_CM_IDLEST_VAL 1 + +/* + * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported + * in the same register at a bit offset of 0x8. The EN_ACK for ICK is + * at an offset of 4 from ICK enable bit. + */ +#define AM35XX_IPSS_ICK_MASK 0xF +#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4 +#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8 +#define AM35XX_IPSS_CLK_IDLEST_VAL 0 + +#define AM35XX_ST_IPSS_SHIFT 5 + +/** + * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift + * from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap3430es2_clk_ssi_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +/** + * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * Some OMAP modules on OMAP3 ES2+ chips have both initiator and + * target IDLEST bits. For our purposes, we are concerned with the + * target IDLEST bits, which exist at a different bit position than + * the *CLKEN bit position for these modules (DSS and USBHOST) (The + * default find_idlest code assumes that they are at the same + * position.) No return value. + */ +static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + /* USBHOST_IDLE has same shift */ + *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = { + .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +/** + * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different + * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +/** + * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The interface clocks on AM35xx IPSS reflects the clock idle status + * in the enable register itsel at a bit offset of 4 from the enable + * bit. A value of 1 indicates that clock is enabled. + */ +static void am35xx_clk_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + *idlest_reg = (__force void __iomem *)(clk->enable_reg); + *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET; + *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL; +} + +/** + * am35xx_clk_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as HECC) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. + */ +static void am35xx_clk_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, + u8 *other_bit) +{ + *other_reg = (__force void __iomem *)(clk->enable_reg); + if (clk->enable_bit & AM35XX_IPSS_ICK_MASK) + *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET; + else + *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET; +} + +const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = { + .find_idlest = am35xx_clk_find_idlest, + .find_companion = am35xx_clk_find_companion, +}; + +/** + * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The IPSS target CM_IDLEST bit is at a different shift from the + * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg + * and @idlest_bit. No return value. + */ +static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = AM35XX_ST_IPSS_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = am35xx_clk_ipss_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; static struct ti_dt_clk omap3xxx_clks[] = { DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), @@ -325,6 +535,30 @@ enum { OMAP3_SOC_OMAP3630, }; +/** + * omap3_clk_lock_dpll5 - locks DPLL5 + * + * Locks DPLL5 to a pre-defined frequency. This is required for proper + * operation of USB. + */ +void __init omap3_clk_lock_dpll5(void) +{ + struct clk *dpll5_clk; + struct clk *dpll5_m2_clk; + + dpll5_clk = clk_get(NULL, "dpll5_ck"); + clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); + clk_prepare_enable(dpll5_clk); + + /* Program dpll5_m2_clk divider for no division */ + dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); + clk_prepare_enable(dpll5_m2_clk); + clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST); + + clk_disable_unprepare(dpll5_m2_clk); + clk_disable_unprepare(dpll5_clk); +} + static int __init omap3xxx_dt_clk_init(int soc_type) { if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 39a594c..72411fb 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -20,6 +20,8 @@ #include <linux/clk-provider.h> #include <linux/clk/ti.h> +#include "clock.h" + static struct ti_dt_clk am43xx_clks[] = { DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c index 581db77..7a8b51b 100644 --- a/drivers/clk/ti/clk-44xx.c +++ b/drivers/clk/ti/clk-44xx.c @@ -16,6 +16,8 @@ #include <linux/clkdev.h> #include <linux/clk/ti.h> +#include "clock.h" + /* * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 96c69a3..59ce2fa 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -17,6 +17,8 @@ #include <linux/io.h> #include <linux/clk/ti.h> +#include "clock.h" + #define OMAP5_DPLL_ABE_DEFFREQ 98304000 /* diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index 63b8323..9b5b289 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -16,11 +16,12 @@ #include <linux/clkdev.h> #include <linux/clk/ti.h> +#include "clock.h" + #define DRA7_DPLL_ABE_DEFFREQ 180633600 #define DRA7_DPLL_GMAC_DEFFREQ 1000000000 #define DRA7_DPLL_USB_DEFFREQ 960000000 - static struct ti_dt_clk dra7xx_clks[] = { DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 9451e65..c69352b 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -14,6 +14,8 @@ #include <linux/clk-provider.h> #include <linux/clk/ti.h> +#include "clock.h" + static struct ti_dt_clk dm816x_clks[] = { DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 7132cec..ace3504 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -22,6 +22,8 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/list.h> +#include <linux/regmap.h> +#include <linux/bootmem.h> #include "clock.h" @@ -31,6 +33,63 @@ struct ti_clk_ll_ops *ti_clk_ll_ops; static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; +static struct ti_clk_features ti_clk_features; + +struct clk_iomap { + struct regmap *regmap; + void __iomem *mem; +}; + +static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS]; + +static void clk_memmap_writel(u32 val, void __iomem *reg) +{ + struct clk_omap_reg *r = (struct clk_omap_reg *)® + struct clk_iomap *io = clk_memmaps[r->index]; + + if (io->regmap) + regmap_write(io->regmap, r->offset, val); + else + writel_relaxed(val, io->mem + r->offset); +} + +static u32 clk_memmap_readl(void __iomem *reg) +{ + u32 val; + struct clk_omap_reg *r = (struct clk_omap_reg *)® + struct clk_iomap *io = clk_memmaps[r->index]; + + if (io->regmap) + regmap_read(io->regmap, r->offset, &val); + else + val = readl_relaxed(io->mem + r->offset); + + return val; +} + +/** + * ti_clk_setup_ll_ops - setup low level clock operations + * @ops: low level clock ops descriptor + * + * Sets up low level clock operations for TI clock driver. This is used + * to provide various callbacks for the clock driver towards platform + * specific code. Returns 0 on success, -EBUSY if ll_ops have been + * registered already. + */ +int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) +{ + if (ti_clk_ll_ops) { + pr_err("Attempt to register ll_ops multiple times.\n"); + return -EBUSY; + } + + ti_clk_ll_ops = ops; + ops->clk_readl = clk_memmap_readl; + ops->clk_writel = clk_memmap_writel; + + return 0; +} + /** * ti_dt_clocks_register - register DT alias clocks during boot * @oclks: list of clocks to register @@ -135,32 +194,67 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) reg->offset = val; - return (void __iomem *)tmp; + return (__force void __iomem *)tmp; } /** - * ti_dt_clk_init_provider - init master clock provider + * omap2_clk_provider_init - init master clock provider * @parent: master node * @index: internal index for clk_reg_ops + * @syscon: syscon regmap pointer for accessing clock registers + * @mem: iomem pointer for the clock provider memory area, only used if + * syscon is not provided * * Initializes a master clock IP block. This basically sets up the * mapping from clocks node to the memory map index. All the clocks * are then initialized through the common of_clk_init call, and the * clocks will access their memory maps based on the node layout. + * Returns 0 in success. */ -void ti_dt_clk_init_provider(struct device_node *parent, int index) +int __init omap2_clk_provider_init(struct device_node *parent, int index, + struct regmap *syscon, void __iomem *mem) { struct device_node *clocks; + struct clk_iomap *io; /* get clocks for this parent */ clocks = of_get_child_by_name(parent, "clocks"); if (!clocks) { pr_err("%s missing 'clocks' child node.\n", parent->name); - return; + return -EINVAL; } /* add clocks node info */ clocks_node_ptr[index] = clocks; + + io = kzalloc(sizeof(*io), GFP_KERNEL); + if (!io) + return -ENOMEM; + + io->regmap = syscon; + io->mem = mem; + + clk_memmaps[index] = io; + + return 0; +} + +/** + * omap2_clk_legacy_provider_init - initialize a legacy clock provider + * @index: index for the clock provider + * @mem: iomem pointer for the clock provider memory area + * + * Initializes a legacy clock provider memory mapping. + */ +void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) +{ + struct clk_iomap *io; + + io = memblock_virt_alloc(sizeof(*io), 0); + + io->mem = mem; + + clk_memmaps[index] = io; } /** @@ -312,3 +406,50 @@ int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks) return 0; } #endif + +/** + * ti_clk_setup_features - setup clock features flags + * @features: features definition to use + * + * Initializes the clock driver features flags based on platform + * provided data. No return value. + */ +void __init ti_clk_setup_features(struct ti_clk_features *features) +{ + memcpy(&ti_clk_features, features, sizeof(*features)); +} + +/** + * ti_clk_get_features - get clock driver features flags + * + * Get TI clock driver features description. Returns a pointer + * to the current feature setup. + */ +const struct ti_clk_features *ti_clk_get_features(void) +{ + return &ti_clk_features; +} + +/** + * omap2_clk_enable_init_clocks - prepare & enable a list of clocks + * @clk_names: ptr to an array of strings of clock names to enable + * @num_clocks: number of clock names in @clk_names + * + * Prepare and enable a list of clocks, named by @clk_names. No + * return value. XXX Deprecated; only needed until these clocks are + * properly claimed and enabled by the drivers or core code that uses + * them. XXX What code disables & calls clk_put on these clocks? + */ +void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks) +{ + struct clk *init_clk; + int i; + + for (i = 0; i < num_clocks; i++) { + init_clk = clk_get(NULL, clk_names[i]); + if (WARN(IS_ERR(init_clk), "could not find init clock %s\n", + clk_names[i])) + continue; + clk_prepare_enable(init_clk); + } +} diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c new file mode 100644 index 0000000..a176b8a --- /dev/null +++ b/drivers/clk/ti/clkt_dflt.c @@ -0,0 +1,316 @@ +/* + * Default clock type + * + * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/clk/ti.h> +#include <linux/delay.h> + +#include "clock.h" + +/* + * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait + * for a module to indicate that it is no longer in idle + */ +#define MAX_MODULE_ENABLE_WAIT 100000 + +/* + * CM module register offsets, used for calculating the companion + * register addresses. + */ +#define CM_FCLKEN 0x0000 +#define CM_ICLKEN 0x0010 + +/** + * _wait_idlest_generic - wait for a module to leave the idle state + * @clk: module clock to wait for (needed for register offsets) + * @reg: virtual address of module IDLEST register + * @mask: value to mask against to determine if the module is active + * @idlest: idle state indicator (0 or 1) for the clock + * @name: name of the clock (for printk) + * + * Wait for a module to leave idle, where its idle-status register is + * not inside the CM module. Returns 1 if the module left idle + * promptly, or 0 if the module did not leave idle before the timeout + * elapsed. XXX Deprecated - should be moved into drivers for the + * individual IP block that the IDLEST register exists in. + */ +static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, + u32 mask, u8 idlest, const char *name) +{ + int i = 0, ena = 0; + + ena = (idlest) ? 0 : mask; + + /* Wait until module enters enabled state */ + for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { + if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena) + break; + udelay(1); + } + + if (i < MAX_MODULE_ENABLE_WAIT) + pr_debug("omap clock: module associated with clock %s ready after %d loops\n", + name, i); + else + pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", + name, MAX_MODULE_ENABLE_WAIT); + + return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; +} + +/** + * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE + * @clk: struct clk * belonging to the module + * + * If the necessary clocks for the OMAP hardware IP block that + * corresponds to clock @clk are enabled, then wait for the module to + * indicate readiness (i.e., to leave IDLE). This code does not + * belong in the clock code and will be moved in the medium term to + * module-dependent code. No return value. + */ +static void _omap2_module_wait_ready(struct clk_hw_omap *clk) +{ + void __iomem *companion_reg, *idlest_reg; + u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; + s16 prcm_mod; + int r; + + /* Not all modules have multiple clocks that their IDLEST depends on */ + if (clk->ops->find_companion) { + clk->ops->find_companion(clk, &companion_reg, &other_bit); + if (!(ti_clk_ll_ops->clk_readl(companion_reg) & + (1 << other_bit))) + return; + } + + clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); + r = ti_clk_ll_ops->cm_split_idlest_reg(idlest_reg, &prcm_mod, + &idlest_reg_id); + if (r) { + /* IDLEST register not in the CM module */ + _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), + idlest_val, __clk_get_name(clk->hw.clk)); + } else { + ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id, + idlest_bit); + } +} + +/** + * omap2_clk_dflt_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Note: We don't need special code here for INVERT_ENABLE for the + * time being since INVERT_ENABLE only applies to clocks enabled by + * CM_CLKEN_PLL + * + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's + * just a matter of XORing the bits. + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as MAILBOXES) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. + */ +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, u8 *other_bit) +{ + u32 r; + + /* + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes + * it's just a matter of XORing the bits. + */ + r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); + + *other_reg = (__force void __iomem *)r; + *other_bit = clk->enable_bit; +} + +/** + * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk + * @clk: struct clk * to find IDLEST info for + * @idlest_reg: void __iomem ** to return the CM_IDLEST va in + * @idlest_bit: u8 * to return the CM_IDLEST bit shift in + * @idlest_val: u8 * to return the idle status indicator + * + * Return the CM_IDLEST register address and bit shift corresponding + * to the module that "owns" this clock. This default code assumes + * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that + * the IDLEST register address ID corresponds to the CM_*CLKEN + * register address ID (e.g., that CM_FCLKEN2 corresponds to + * CM_IDLEST2). This is not true for all modules. No return value. + */ +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; + + /* + * 24xx uses 0 to indicate not ready, and 1 to indicate ready. + * 34xx reverses this, just to keep us on our toes + * AM35xx uses both, depending on the module. + */ + *idlest_val = ti_clk_get_features()->cm_idlest_val; +} + +/** + * omap2_dflt_clk_enable - enable a clock in the hardware + * @hw: struct clk_hw * of the clock to enable + * + * Enable the clock @hw in the hardware. We first call into the OMAP + * clockdomain code to "enable" the corresponding clockdomain if this + * is the first enabled user of the clockdomain. Then program the + * hardware to enable the clock. Then wait for the IP block that uses + * this clock to leave idle (if applicable). Returns the error value + * from clkdm_clk_enable() if it terminated with an error, or -EINVAL + * if @hw has a null clock enable_reg, or zero upon success. + */ +int omap2_dflt_clk_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + u32 v; + int ret = 0; + bool clkdm_control; + + if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) + clkdm_control = false; + else + clkdm_control = true; + + clk = to_clk_hw_omap(hw); + + if (clkdm_control && clk->clkdm) { + ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); + if (ret) { + WARN(1, + "%s: could not enable %s's clockdomain %s: %d\n", + __func__, __clk_get_name(hw->clk), + clk->clkdm_name, ret); + return ret; + } + } + + if (unlikely(!clk->enable_reg)) { + pr_err("%s: %s missing enable_reg\n", __func__, + __clk_get_name(hw->clk)); + ret = -EINVAL; + goto err; + } + + /* FIXME should not have INVERT_ENABLE bit here */ + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v &= ~(1 << clk->enable_bit); + else + v |= (1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, clk->enable_reg); + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); /* OCP barrier */ + + if (clk->ops && clk->ops->find_idlest) + _omap2_module_wait_ready(clk); + + return 0; + +err: + if (clkdm_control && clk->clkdm) + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); + return ret; +} + +/** + * omap2_dflt_clk_disable - disable a clock in the hardware + * @hw: struct clk_hw * of the clock to disable + * + * Disable the clock @hw in the hardware, and call into the OMAP + * clockdomain code to "disable" the corresponding clockdomain if all + * clocks/hwmods in that clockdomain are now disabled. No return + * value. + */ +void omap2_dflt_clk_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + u32 v; + + clk = to_clk_hw_omap(hw); + if (!clk->enable_reg) { + /* + * 'independent' here refers to a clock which is not + * controlled by its parent. + */ + pr_err("%s: independent clock %s has no enable_reg\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v |= (1 << clk->enable_bit); + else + v &= ~(1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, clk->enable_reg); + /* No OCP barrier needed here since it is a disable operation */ + + if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) && + clk->clkdm) + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); +} + +/** + * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? + * @hw: struct clk_hw * to check + * + * Return 1 if the clock represented by @hw is enabled in the + * hardware, or 0 otherwise. Intended for use in the struct + * clk_ops.is_enabled function pointer. + */ +int omap2_dflt_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + u32 v; + + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); + + if (clk->flags & INVERT_ENABLE) + v ^= BIT(clk->enable_bit); + + v &= BIT(clk->enable_bit); + + return v ? 1 : 0; +} + +const struct clk_hw_omap_ops clkhwops_wait = { + .find_idlest = omap2_clk_dflt_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index f251a14..a01fc7f 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -18,6 +18,7 @@ #include <linux/errno.h> #include <linux/clk-provider.h> #include <linux/io.h> +#include <linux/clk/ti.h> #include <asm/div64.h> @@ -80,8 +81,8 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; } else { - fint_min = ti_clk_features.fint_min; - fint_max = ti_clk_features.fint_max; + fint_min = ti_clk_get_features()->fint_min; + fint_max = ti_clk_get_features()->fint_max; } if (!fint_min || !fint_max) { @@ -89,18 +90,18 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) return DPLL_FINT_INVALID; } - if (fint < ti_clk_features.fint_min) { + if (fint < ti_clk_get_features()->fint_min) { pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n", n); dd->max_divider = n; ret = DPLL_FINT_UNDERFLOW; - } else if (fint > ti_clk_features.fint_max) { + } else if (fint > ti_clk_get_features()->fint_max) { pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n", n); dd->min_divider = n; ret = DPLL_FINT_INVALID; - } else if (fint > ti_clk_features.fint_band1_max && - fint < ti_clk_features.fint_band2_min) { + } else if (fint > ti_clk_get_features()->fint_band1_max && + fint < ti_clk_get_features()->fint_band2_min) { pr_debug("rejecting n=%d due to Fint failure\n", n); ret = DPLL_FINT_INVALID; } @@ -183,7 +184,7 @@ static int _omap2_dpll_is_in_bypass(u32 v) { u8 mask, val; - mask = ti_clk_features.dpll_bypass_vals; + mask = ti_clk_get_features()->dpll_bypass_vals; /* * Each set bit in the mask corresponds to a bypass value equal @@ -211,7 +212,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw) if (!dd) return -EINVAL; - v = omap2_clk_readl(clk, dd->control_reg); + v = ti_clk_ll_ops->clk_readl(dd->control_reg); v &= dd->enable_mask; v >>= __ffs(dd->enable_mask); @@ -247,20 +248,20 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) return 0; /* Return bypass rate if DPLL is bypassed */ - v = omap2_clk_readl(clk, dd->control_reg); + v = ti_clk_ll_ops->clk_readl(dd->control_reg); v &= dd->enable_mask; v >>= __ffs(dd->enable_mask); if (_omap2_dpll_is_in_bypass(v)) return __clk_get_rate(dd->clk_bypass); - v = omap2_clk_readl(clk, dd->mult_div1_reg); + v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg); dpll_mult = v & dd->mult_mask; dpll_mult >>= __ffs(dd->mult_mask); dpll_div = v & dd->div1_mask; dpll_div >>= __ffs(dd->div1_mask); - dpll_clk = (long long) __clk_get_rate(dd->clk_ref) * dpll_mult; + dpll_clk = (long long)__clk_get_rate(dd->clk_ref) * dpll_mult; do_div(dpll_clk, dpll_div + 1); return dpll_clk; @@ -281,7 +282,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) * be rounded, or the rounded rate upon success. */ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate) + unsigned long *parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); int m, n, r, scaled_max_m; @@ -310,7 +311,6 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { - /* Is the (input clk, divider) pair valid for the DPLL? */ r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) @@ -367,4 +367,3 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, return dd->last_rounded_rate; } - diff --git a/drivers/clk/ti/clkt_iclk.c b/drivers/clk/ti/clkt_iclk.c new file mode 100644 index 0000000..38c3690 --- /dev/null +++ b/drivers/clk/ti/clkt_iclk.c @@ -0,0 +1,101 @@ +/* + * OMAP2/3 interface clock control + * + * Copyright (C) 2011 Nokia Corporation + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/clk/ti.h> + +#include "clock.h" + +/* Register offsets */ +#define OMAP24XX_CM_FCLKEN2 0x04 +#define CM_AUTOIDLE 0x30 +#define CM_ICLKEN 0x10 +#define CM_IDLEST 0x20 + +#define OMAP24XX_CM_IDLEST_VAL 0 + +/* Private functions */ + +/* XXX */ +void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) +{ + u32 v; + void __iomem *r; + + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = ti_clk_ll_ops->clk_readl(r); + v |= (1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, r); +} + +/* XXX */ +void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) +{ + u32 v; + void __iomem *r; + + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = ti_clk_ll_ops->clk_readl(r); + v &= ~(1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, r); +} + +/** + * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the + * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function + * passes back the correct CM_IDLEST register address for I2CHS + * modules. No return value. + */ +static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = ((__force u32)clk->enable_reg ^ (OMAP24XX_CM_FCLKEN2 ^ CM_IDLEST)); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; + *idlest_val = OMAP24XX_CM_IDLEST_VAL; +} + +/* Public data */ + +const struct clk_hw_omap_ops clkhwops_iclk = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clk_hw_omap_ops clkhwops_iclk_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap2_clk_dflt_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +/* 2430 I2CHS has non-standard IDLEST register */ +const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = { + .find_idlest = omap2430_clk_i2chs_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 404158d..d8aafd3 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -154,6 +154,35 @@ struct ti_clk_dpll { u8 recal_st_bit; }; +/* Composite clock component types */ +enum { + CLK_COMPONENT_TYPE_GATE = 0, + CLK_COMPONENT_TYPE_DIVIDER, + CLK_COMPONENT_TYPE_MUX, + CLK_COMPONENT_TYPE_MAX, +}; + +/** + * struct ti_dt_clk - OMAP DT clock alias declarations + * @lk: clock lookup definition + * @node_name: clock DT node to map to + */ +struct ti_dt_clk { + struct clk_lookup lk; + char *node_name; +}; + +#define DT_CLK(dev, con, name) \ + { \ + .lk = { \ + .dev_id = dev, \ + .con_id = con, \ + }, \ + .node_name = name, \ + } + +typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); + struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); @@ -169,4 +198,80 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch); struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); +void ti_dt_clocks_register(struct ti_dt_clk *oclks); +int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func); +int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); + +void omap2_init_clk_hw_omap_clocks(struct clk *clk); +int of_ti_clk_autoidle_setup(struct device_node *node); +void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); + +extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; +extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; +extern const struct clk_hw_omap_ops clkhwops_wait; +extern const struct clk_hw_omap_ops clkhwops_iclk; +extern const struct clk_hw_omap_ops clkhwops_iclk_wait; +extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; +extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; +extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; + +extern const struct clk_ops ti_clk_divider_ops; +extern const struct clk_ops ti_clk_mux_ops; + +int omap2_clkops_enable_clkdm(struct clk_hw *hw); +void omap2_clkops_disable_clkdm(struct clk_hw *hw); + +int omap2_dflt_clk_enable(struct clk_hw *hw); +void omap2_dflt_clk_disable(struct clk_hw *hw); +int omap2_dflt_clk_is_enabled(struct clk_hw *hw); +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val); + +void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); +void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); + +u8 omap2_init_dpll_parent(struct clk_hw *hw); +int omap3_noncore_dpll_enable(struct clk_hw *hw); +void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index); +int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); +long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); +unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, + unsigned long parent_rate); + +unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); +int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, + unsigned long parent_rate); +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index); +void omap3_clk_lock_dpll5(void); + +unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, + unsigned long parent_rate); +long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, + unsigned long target_rate, + unsigned long *parent_rate); +int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); + +extern struct ti_clk_ll_ops *ti_clk_ll_ops; + #endif diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 41eb5d1..08a38c9 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -22,9 +22,87 @@ #include <linux/of_address.h> #include <linux/clk/ti.h> +#include "clock.h" + #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ +/** + * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw + * @hw: struct clk_hw * of the clock being enabled + * + * Increment the usecount of the clockdomain of the clock pointed to + * by @hw; if the usecount is 1, the clockdomain will be "enabled." + * Only needed for clocks that don't use omap2_dflt_clk_enable() as + * their enable function pointer. Passes along the return value of + * clkdm_clk_enable(), -EINVAL if @hw is not associated with a + * clockdomain, or 0 if clock framework-based clockdomain control is + * not implemented. + */ +int omap2_clkops_enable_clkdm(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + int ret = 0; + + clk = to_clk_hw_omap(hw); + + if (unlikely(!clk->clkdm)) { + pr_err("%s: %s: no clkdm set ?!\n", __func__, + __clk_get_name(hw->clk)); + return -EINVAL; + } + + if (unlikely(clk->enable_reg)) + pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__, + __clk_get_name(hw->clk)); + + if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) { + pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", + __func__, __clk_get_name(hw->clk)); + return 0; + } + + ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); + WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n", + __func__, __clk_get_name(hw->clk), clk->clkdm_name, ret); + + return ret; +} + +/** + * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw + * @hw: struct clk_hw * of the clock being disabled + * + * Decrement the usecount of the clockdomain of the clock pointed to + * by @hw; if the usecount is 0, the clockdomain will be "disabled." + * Only needed for clocks that don't use omap2_dflt_clk_disable() as their + * disable function pointer. No return value. + */ +void omap2_clkops_disable_clkdm(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + + clk = to_clk_hw_omap(hw); + + if (unlikely(!clk->clkdm)) { + pr_err("%s: %s: no clkdm set ?!\n", __func__, + __clk_get_name(hw->clk)); + return; + } + + if (unlikely(clk->enable_reg)) + pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__, + __clk_get_name(hw->clk)); + + if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) { + pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); +} + static void __init of_ti_clockdomain_setup(struct device_node *node) { struct clk *clk; diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index 96f83ce..dbef218 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -276,7 +276,6 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int num_parents; const char **parent_names; struct component_clk *clk; - int i; num_parents = of_clk_get_parent_count(node); @@ -289,8 +288,7 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, if (!parent_names) return -ENOMEM; - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, num_parents); clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) { diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 74e94b9..3999894 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -342,7 +342,6 @@ static void __init of_ti_dpll_setup(struct device_node *node, struct clk_init_data *init = NULL; const char **parent_names = NULL; struct dpll_data *dd = NULL; - int i; u8 dpll_mode = 0; dd = kzalloc(sizeof(*dd), GFP_KERNEL); @@ -371,8 +370,7 @@ static void __init of_ti_dpll_setup(struct device_node *node, if (!parent_names) goto cleanup; - for (i = 0; i < init->num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, init->num_parents); init->parent_names = parent_names; diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c index 44e57ec..b0aa87b 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/drivers/clk/ti/dpll3xxx.c @@ -27,8 +27,8 @@ #include <linux/io.h> #include <linux/bitops.h> #include <linux/clkdev.h> +#include <linux/clk/ti.h> -#include "clockdomain.h" #include "clock.h" /* CM_AUTOIDLE_PLL*.AUTO_* bit values */ @@ -37,6 +37,13 @@ #define MAX_DPLL_WAIT_TRIES 1000000 +#define OMAP3XXX_EN_DPLL_LOCKED 0x7 + +/* Forward declarations */ +static u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); +static void omap3_dpll_deny_idle(struct clk_hw_omap *clk); +static void omap3_dpll_allow_idle(struct clk_hw_omap *clk); + /* Private functions */ /* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */ @@ -47,10 +54,10 @@ static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits) dd = clk->dpll_data; - v = omap2_clk_readl(clk, dd->control_reg); + v = ti_clk_ll_ops->clk_readl(dd->control_reg); v &= ~dd->enable_mask; v |= clken_bits << __ffs(dd->enable_mask); - omap2_clk_writel(v, clk, dd->control_reg); + ti_clk_ll_ops->clk_writel(v, dd->control_reg); } /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ @@ -66,14 +73,14 @@ static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state) state <<= __ffs(dd->idlest_mask); - while (((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) + while (((ti_clk_ll_ops->clk_readl(dd->idlest_reg) & dd->idlest_mask) != state) && i < MAX_DPLL_WAIT_TRIES) { i++; udelay(1); } if (i == MAX_DPLL_WAIT_TRIES) { - printk(KERN_ERR "clock: %s failed transition to '%s'\n", + pr_err("clock: %s failed transition to '%s'\n", clk_name, (state) ? "locked" : "bypassed"); } else { pr_debug("clock: %s transition to '%s' in %d loops\n", @@ -144,7 +151,8 @@ static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk) state <<= __ffs(dd->idlest_mask); /* Check if already locked */ - if ((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) == state) + if ((ti_clk_ll_ops->clk_readl(dd->idlest_reg) & dd->idlest_mask) == + state) goto done; ai = omap3_dpll_autoidle_read(clk); @@ -307,15 +315,15 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) * Set jitter correction. Jitter correction applicable for OMAP343X * only since freqsel field is no longer present on other devices. */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { - v = omap2_clk_readl(clk, dd->control_reg); + if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { + v = ti_clk_ll_ops->clk_readl(dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); - omap2_clk_writel(v, clk, dd->control_reg); + ti_clk_ll_ops->clk_writel(v, dd->control_reg); } /* Set DPLL multiplier, divider */ - v = omap2_clk_readl(clk, dd->mult_div1_reg); + v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg); /* Handle Duty Cycle Correction */ if (dd->dcc_mask) { @@ -342,11 +350,11 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) v |= sd_div << __ffs(dd->sddiv_mask); } - omap2_clk_writel(v, clk, dd->mult_div1_reg); + ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg); /* Set 4X multiplier and low-power mode */ if (dd->m4xen_mask || dd->lpmode_mask) { - v = omap2_clk_readl(clk, dd->control_reg); + v = ti_clk_ll_ops->clk_readl(dd->control_reg); if (dd->m4xen_mask) { if (dd->last_rounded_m4xen) @@ -362,7 +370,7 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) v &= ~dd->lpmode_mask; } - omap2_clk_writel(v, clk, dd->control_reg); + ti_clk_ll_ops->clk_writel(v, dd->control_reg); } /* We let the clock framework set the other output dividers later */ @@ -417,12 +425,12 @@ int omap3_noncore_dpll_enable(struct clk_hw *hw) return -EINVAL; if (clk->clkdm) { - r = clkdm_clk_enable(clk->clkdm, hw->clk); + r = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); if (r) { WARN(1, "%s: could not enable %s's clockdomain %s: %d\n", __func__, __clk_get_name(hw->clk), - clk->clkdm->name, r); + clk->clkdm_name, r); return r; } } @@ -453,52 +461,46 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) _omap3_noncore_dpll_stop(clk); if (clk->clkdm) - clkdm_clk_disable(clk->clkdm, hw->clk); + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); } - /* Non-CORE DPLL rate set code */ /** * omap3_noncore_dpll_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock + * @req: target rate request * * Determines which DPLL mode to use for reaching a desired target rate. * Checks whether the DPLL shall be in bypass or locked mode, and if * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. + * Returns a 0 on success, negative error value in failure. */ -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; - if (!hw || !rate) + if (!req->rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; - if (__clk_get_rate(dd->clk_bypass) == rate && + if (__clk_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = __clk_get_hw(dd->clk_bypass); } else { - rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); + req->rate = omap2_dpll_round_rate(hw, req->rate, + &req->best_parent_rate); + req->best_parent_hw = __clk_get_hw(dd->clk_ref); } - *best_parent_rate = rate; + req->best_parent_rate = req->rate; - return rate; + return 0; } /** @@ -559,7 +561,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; /* Freqsel is available only on OMAP343X devices */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { + if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); WARN_ON(!freqsel); } @@ -618,7 +620,7 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, * -EINVAL if passed a null pointer or if the struct clk does not * appear to refer to a DPLL. */ -u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) +static u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) { const struct dpll_data *dd; u32 v; @@ -631,7 +633,7 @@ u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) if (!dd->autoidle_reg) return -EINVAL; - v = omap2_clk_readl(clk, dd->autoidle_reg); + v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg); v &= dd->autoidle_mask; v >>= __ffs(dd->autoidle_mask); @@ -647,7 +649,7 @@ u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) * OMAP3430. The DPLL will enter low-power stop when its downstream * clocks are gated. No return value. */ -void omap3_dpll_allow_idle(struct clk_hw_omap *clk) +static void omap3_dpll_allow_idle(struct clk_hw_omap *clk) { const struct dpll_data *dd; u32 v; @@ -665,11 +667,10 @@ void omap3_dpll_allow_idle(struct clk_hw_omap *clk) * by writing 0x5 instead of 0x1. Add some mechanism to * optionally enter this mode. */ - v = omap2_clk_readl(clk, dd->autoidle_reg); + v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask); - omap2_clk_writel(v, clk, dd->autoidle_reg); - + ti_clk_ll_ops->clk_writel(v, dd->autoidle_reg); } /** @@ -678,7 +679,7 @@ void omap3_dpll_allow_idle(struct clk_hw_omap *clk) * * Disable DPLL automatic idle control. No return value. */ -void omap3_dpll_deny_idle(struct clk_hw_omap *clk) +static void omap3_dpll_deny_idle(struct clk_hw_omap *clk) { const struct dpll_data *dd; u32 v; @@ -691,11 +692,10 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk) if (!dd->autoidle_reg) return; - v = omap2_clk_readl(clk, dd->autoidle_reg); + v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg); v &= ~dd->autoidle_mask; v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask); - omap2_clk_writel(v, clk, dd->autoidle_reg); - + ti_clk_ll_ops->clk_writel(v, dd->autoidle_reg); } /* Clock control for DPLL outputs */ @@ -753,7 +753,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, WARN_ON(!dd->enable_mask); - v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask; + v = ti_clk_ll_ops->clk_readl(dd->control_reg) & dd->enable_mask; v >>= __ffs(dd->enable_mask); if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) rate = parent_rate; @@ -762,57 +762,59 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, return rate; } -int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - return 0; -} +/* OMAP3/4 non-CORE DPLL clkops */ +const struct clk_hw_omap_ops clkhwops_omap3_dpll = { + .allow_idle = omap3_dpll_allow_idle, + .deny_idle = omap3_dpll_deny_idle, +}; -long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +/** + * omap3_dpll4_set_rate - set rate for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * + * Check if the current SoC supports the per-dpll reprogram operation + * or not, and then do the rate change if supported. Returns -EINVAL + * if not supported, 0 for success, and potential error codes from the + * clock rate change. + */ +int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - const struct dpll_data *dd; - u32 v; - struct clk_hw_omap *pclk = NULL; - - if (!*prate) - return 0; - - pclk = omap3_find_clkoutx2_dpll(hw); - - if (!pclk) - return 0; - - dd = pclk->dpll_data; - - /* TYPE J does not have a clkoutx2 */ - if (dd->flags & DPLL_J_TYPE) { - *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate); - return *prate; + /* + * According to the 12-5 CDP code from TI, "Limitation 2.5" + * on 3430ES1 prevents us from changing DPLL multipliers or dividers + * on DPLL4. + */ + if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; } - WARN_ON(!dd->enable_mask); - - v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask; - v >>= __ffs(dd->enable_mask); - - /* If in bypass, the rate is fixed to the bypass rate*/ - if (v != OMAP3XXX_EN_DPLL_LOCKED) - return *prate; - - if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { - unsigned long best_parent; + return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); +} - best_parent = (rate / 2); - *prate = __clk_round_rate(__clk_get_parent(hw->clk), - best_parent); +/** + * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * @index: parent index, 0 - reference clock, 1 - bypass clock + * + * Check if the current SoC support the per-dpll reprogram operation + * or not, and then do the rate + parent change if supported. Returns + * -EINVAL if not supported, 0 for success, and potential error codes + * from the clock rate change. + */ +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; } - return *prate * 2; + return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, + index); } - -/* OMAP3/4 non-CORE DPLL clkops */ -const struct clk_hw_omap_ops clkhwops_omap3_dpll = { - .allow_idle = omap3_dpll_allow_idle, - .deny_idle = omap3_dpll_deny_idle, -}; diff --git a/arch/arm/mach-omap2/dpll44xx.c b/drivers/clk/ti/dpll44xx.c index f231be0..73af77a 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/drivers/clk/ti/dpll44xx.c @@ -14,6 +14,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/bitops.h> +#include <linux/clk/ti.h> #include "clock.h" @@ -29,14 +30,14 @@ /* * Bitfield declarations */ -#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK (1 << 8) -#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK (1 << 10) -#define OMAP4430_DPLL_REGM4XEN_MASK (1 << 11) +#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BIT(8) +#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BIT(10) +#define OMAP4430_DPLL_REGM4XEN_MASK BIT(11) /* Static rate multiplier for OMAP4 REGM4XEN clocks */ #define OMAP4430_REGM4XEN_MULT 4 -void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) +static void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) { u32 v; u32 mask; @@ -48,13 +49,13 @@ void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = omap2_clk_readl(clk, clk->clksel_reg); + v = ti_clk_ll_ops->clk_readl(clk->clksel_reg); /* Clear the bit to allow gatectrl */ v &= ~mask; - omap2_clk_writel(v, clk, clk->clksel_reg); + ti_clk_ll_ops->clk_writel(v, clk->clksel_reg); } -void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) +static void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) { u32 v; u32 mask; @@ -66,10 +67,10 @@ void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - v = omap2_clk_readl(clk, clk->clksel_reg); + v = ti_clk_ll_ops->clk_readl(clk->clksel_reg); /* Set the bit to deny gatectrl */ v |= mask; - omap2_clk_writel(v, clk, clk->clksel_reg); + ti_clk_ll_ops->clk_writel(v, clk->clksel_reg); } const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { @@ -112,7 +113,7 @@ static void omap4_dpll_lpmode_recalc(struct dpll_data *dd) * upon success, or 0 upon error. */ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); u32 v; @@ -127,7 +128,7 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, rate = omap2_get_dpll_rate(clk); /* regm4xen adds a multiplier of 4 to DPLL calculations */ - v = omap2_clk_readl(clk, dd->control_reg); + v = ti_clk_ll_ops->clk_readl(dd->control_reg); if (v & OMAP4430_DPLL_REGM4XEN_MASK) rate *= OMAP4430_REGM4XEN_MULT; @@ -191,42 +192,36 @@ out: /** * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock + * @req: target rate request * * Determines which DPLL mode to use for reaching a desired rate. * Checks whether the DPLL shall be in bypass or locked mode, and if * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. + * Returns 0 on success and a negative error value otherwise. */ -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; - if (!hw || !rate) + if (!req->rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; - if (__clk_get_rate(dd->clk_bypass) == rate && + if (__clk_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = __clk_get_hw(dd->clk_bypass); } else { - rate = omap4_dpll_regm4xen_round_rate(hw, rate, - best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); + req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate, + &req->best_parent_rate); + req->best_parent_hw = __clk_get_hw(dd->clk_ref); } - *best_parent_rate = rate; + req->best_parent_rate = req->rate; - return rate; + return 0; } diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index f158c2a..f4b2e98 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -559,8 +559,7 @@ static void __init ti_fapll_setup(struct device_node *node) goto free; } - parent_name[0] = of_clk_get_parent_name(node, 0); - parent_name[1] = of_clk_get_parent_name(node, 1); + of_clk_parent_fill(node, parent_name, 2); init->parent_names = parent_name; fd->clk_ref = of_clk_get(node, 0); diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c index c2c8a28..3cd4067 100644 --- a/drivers/clk/ti/fixed-factor.c +++ b/drivers/clk/ti/fixed-factor.c @@ -22,6 +22,8 @@ #include <linux/of_address.h> #include <linux/clk/ti.h> +#include "clock.h" + #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 5cdeed5..99fe27e 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -190,7 +190,6 @@ static void of_mux_clk_setup(struct device_node *node) void __iomem *reg; int num_parents; const char **parent_names; - int i; u8 clk_mux_flags = 0; u32 mask = 0; u32 shift = 0; @@ -205,8 +204,7 @@ static void of_mux_clk_setup(struct device_node *node) if (!parent_names) goto cleanup; - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, num_parents); reg = ti_clk_get_reg_addr(node, 0); diff --git a/include/dt-bindings/clock/rk3066a-cru.h b/include/dt-bindings/clock/rk3066a-cru.h index bc1ed1d..d3a9824 100644 --- a/include/dt-bindings/clock/rk3066a-cru.h +++ b/include/dt-bindings/clock/rk3066a-cru.h @@ -13,6 +13,9 @@ * GNU General Public License for more details. */ +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3066A_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3066A_H + #include <dt-bindings/clock/rk3188-cru-common.h> /* soft-reset indices */ @@ -33,3 +36,5 @@ #define SRST_HDMI 96 #define SRST_HDMI_APB 97 #define SRST_CIF1 111 + +#endif diff --git a/include/dt-bindings/clock/rk3188-cru-common.h b/include/dt-bindings/clock/rk3188-cru-common.h index 6a37050..8df77a7 100644 --- a/include/dt-bindings/clock/rk3188-cru-common.h +++ b/include/dt-bindings/clock/rk3188-cru-common.h @@ -13,6 +13,9 @@ * GNU General Public License for more details. */ +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3188_COMMON_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3188_COMMON_H + /* core clocks from */ #define PLL_APLL 1 #define PLL_DPLL 2 @@ -248,3 +251,5 @@ #define SRST_PTM1_ATB 141 #define SRST_CTM 142 #define SRST_TS 143 + +#endif diff --git a/include/dt-bindings/clock/rk3188-cru.h b/include/dt-bindings/clock/rk3188-cru.h index 9fac8ed..9f2e631 100644 --- a/include/dt-bindings/clock/rk3188-cru.h +++ b/include/dt-bindings/clock/rk3188-cru.h @@ -13,6 +13,9 @@ * GNU General Public License for more details. */ +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3188_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3188_H + #include <dt-bindings/clock/rk3188-cru-common.h> /* soft-reset indices */ @@ -49,3 +52,5 @@ #define SRST_GPU_BRIDGE 121 #define SRST_CTI3 123 #define SRST_CTI3_APB 124 + +#endif diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h index dea4197..c719aac 100644 --- a/include/dt-bindings/clock/rk3288-cru.h +++ b/include/dt-bindings/clock/rk3288-cru.h @@ -13,6 +13,9 @@ * GNU General Public License for more details. */ +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3288_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3288_H + /* core clocks */ #define PLL_APLL 1 #define PLL_DPLL 2 @@ -376,3 +379,5 @@ #define SRST_TSP_CLKIN0 189 #define SRST_TSP_CLKIN1 190 #define SRST_TSP_27M 191 + +#endif diff --git a/include/dt-bindings/clock/rk3368-cru.h b/include/dt-bindings/clock/rk3368-cru.h new file mode 100644 index 0000000..9c5dd9b --- /dev/null +++ b/include/dt-bindings/clock/rk3368-cru.h @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2015 Heiko Stuebner <heiko@sntech.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3368_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RK3368_H + +/* core clocks */ +#define PLL_APLLB 1 +#define PLL_APLLL 2 +#define PLL_DPLL 3 +#define PLL_CPLL 4 +#define PLL_GPLL 5 +#define PLL_NPLL 6 +#define ARMCLKB 7 +#define ARMCLKL 8 + +/* sclk gates (special clocks) */ +#define SCLK_GPU_CORE 64 +#define SCLK_SPI0 65 +#define SCLK_SPI1 66 +#define SCLK_SPI2 67 +#define SCLK_SDMMC 68 +#define SCLK_SDIO0 69 +#define SCLK_EMMC 71 +#define SCLK_TSADC 72 +#define SCLK_SARADC 73 +#define SCLK_NANDC0 75 +#define SCLK_UART0 77 +#define SCLK_UART1 78 +#define SCLK_UART2 79 +#define SCLK_UART3 80 +#define SCLK_UART4 81 +#define SCLK_I2S_8CH 82 +#define SCLK_SPDIF_8CH 83 +#define SCLK_I2S_2CH 84 +#define SCLK_TIMER0 85 +#define SCLK_TIMER1 86 +#define SCLK_TIMER2 87 +#define SCLK_TIMER3 88 +#define SCLK_TIMER4 89 +#define SCLK_TIMER5 90 +#define SCLK_TIMER6 91 +#define SCLK_OTGPHY0 93 +#define SCLK_OTG_ADP 96 +#define SCLK_HSICPHY480M 97 +#define SCLK_HSICPHY12M 98 +#define SCLK_MACREF 99 +#define SCLK_VOP0_PWM 100 +#define SCLK_MAC_RX 102 +#define SCLK_MAC_TX 103 +#define SCLK_EDP_24M 104 +#define SCLK_EDP 105 +#define SCLK_RGA 106 +#define SCLK_ISP 107 +#define SCLK_HDCP 108 +#define SCLK_HDMI_HDCP 109 +#define SCLK_HDMI_CEC 110 +#define SCLK_HEVC_CABAC 111 +#define SCLK_HEVC_CORE 112 +#define SCLK_I2S_8CH_OUT 113 +#define SCLK_SDMMC_DRV 114 +#define SCLK_SDIO0_DRV 115 +#define SCLK_EMMC_DRV 117 +#define SCLK_SDMMC_SAMPLE 118 +#define SCLK_SDIO0_SAMPLE 119 +#define SCLK_EMMC_SAMPLE 121 +#define SCLK_USBPHY480M 122 +#define SCLK_PVTM_CORE 123 +#define SCLK_PVTM_GPU 124 +#define SCLK_PVTM_PMU 125 +#define SCLK_SFC 126 +#define SCLK_MAC 127 +#define SCLK_MACREF_OUT 128 + +#define DCLK_VOP 190 +#define MCLK_CRYPTO 191 + +/* aclk gates */ +#define ACLK_GPU_MEM 192 +#define ACLK_GPU_CFG 193 +#define ACLK_DMAC_BUS 194 +#define ACLK_DMAC_PERI 195 +#define ACLK_PERI_MMU 196 +#define ACLK_GMAC 197 +#define ACLK_VOP 198 +#define ACLK_VOP_IEP 199 +#define ACLK_RGA 200 +#define ACLK_HDCP 201 +#define ACLK_IEP 202 +#define ACLK_VIO0_NOC 203 +#define ACLK_VIP 204 +#define ACLK_ISP 205 +#define ACLK_VIO1_NOC 206 +#define ACLK_VIDEO 208 +#define ACLK_BUS 209 +#define ACLK_PERI 210 + +/* pclk gates */ +#define PCLK_GPIO0 320 +#define PCLK_GPIO1 321 +#define PCLK_GPIO2 322 +#define PCLK_GPIO3 323 +#define PCLK_PMUGRF 324 +#define PCLK_MAILBOX 325 +#define PCLK_GRF 329 +#define PCLK_SGRF 330 +#define PCLK_PMU 331 +#define PCLK_I2C0 332 +#define PCLK_I2C1 333 +#define PCLK_I2C2 334 +#define PCLK_I2C3 335 +#define PCLK_I2C4 336 +#define PCLK_I2C5 337 +#define PCLK_SPI0 338 +#define PCLK_SPI1 339 +#define PCLK_SPI2 340 +#define PCLK_UART0 341 +#define PCLK_UART1 342 +#define PCLK_UART2 343 +#define PCLK_UART3 344 +#define PCLK_UART4 345 +#define PCLK_TSADC 346 +#define PCLK_SARADC 347 +#define PCLK_SIM 348 +#define PCLK_GMAC 349 +#define PCLK_PWM0 350 +#define PCLK_PWM1 351 +#define PCLK_TIMER0 353 +#define PCLK_TIMER1 354 +#define PCLK_EDP_CTRL 355 +#define PCLK_MIPI_DSI0 356 +#define PCLK_MIPI_CSI 358 +#define PCLK_HDCP 359 +#define PCLK_HDMI_CTRL 360 +#define PCLK_VIO_H2P 361 +#define PCLK_BUS 362 +#define PCLK_PERI 363 +#define PCLK_DDRUPCTL 364 +#define PCLK_DDRPHY 365 +#define PCLK_ISP 366 +#define PCLK_VIP 367 +#define PCLK_WDT 368 + +/* hclk gates */ +#define HCLK_SFC 448 +#define HCLK_OTG0 449 +#define HCLK_HOST0 450 +#define HCLK_HOST1 451 +#define HCLK_HSIC 452 +#define HCLK_NANDC0 453 +#define HCLK_TSP 455 +#define HCLK_SDMMC 456 +#define HCLK_SDIO0 457 +#define HCLK_EMMC 459 +#define HCLK_HSADC 460 +#define HCLK_CRYPTO 461 +#define HCLK_I2S_2CH 462 +#define HCLK_I2S_8CH 463 +#define HCLK_SPDIF 464 +#define HCLK_VOP 465 +#define HCLK_ROM 467 +#define HCLK_IEP 468 +#define HCLK_ISP 469 +#define HCLK_RGA 470 +#define HCLK_VIO_AHB_ARBI 471 +#define HCLK_VIO_NOC 472 +#define HCLK_VIP 473 +#define HCLK_VIO_H2P 474 +#define HCLK_VIO_HDCPMMU 475 +#define HCLK_VIDEO 476 +#define HCLK_BUS 477 +#define HCLK_PERI 478 + +#define CLK_NR_CLKS (HCLK_PERI + 1) + +/* soft-reset indices */ +#define SRST_CORE_B0 0 +#define SRST_CORE_B1 1 +#define SRST_CORE_B2 2 +#define SRST_CORE_B3 3 +#define SRST_CORE_B0_PO 4 +#define SRST_CORE_B1_PO 5 +#define SRST_CORE_B2_PO 6 +#define SRST_CORE_B3_PO 7 +#define SRST_L2_B 8 +#define SRST_ADB_B 9 +#define SRST_PD_CORE_B_NIU 10 +#define SRST_PDBUS_STRSYS 11 +#define SRST_SOCDBG_B 14 +#define SRST_CORE_B_DBG 15 + +#define SRST_DMAC1 18 +#define SRST_INTMEM 19 +#define SRST_ROM 20 +#define SRST_SPDIF8CH 21 +#define SRST_I2S8CH 23 +#define SRST_MAILBOX 24 +#define SRST_I2S2CH 25 +#define SRST_EFUSE_256 26 +#define SRST_MCU_SYS 28 +#define SRST_MCU_PO 29 +#define SRST_MCU_NOC 30 +#define SRST_EFUSE 31 + +#define SRST_GPIO0 32 +#define SRST_GPIO1 33 +#define SRST_GPIO2 34 +#define SRST_GPIO3 35 +#define SRST_GPIO4 36 +#define SRST_PMUGRF 41 +#define SRST_I2C0 42 +#define SRST_I2C1 43 +#define SRST_I2C2 44 +#define SRST_I2C3 45 +#define SRST_I2C4 46 +#define SRST_I2C5 47 + +#define SRST_DWPWM 48 +#define SRST_MMC_PERI 49 +#define SRST_PERIPH_MMU 50 +#define SRST_GRF 55 +#define SRST_PMU 56 +#define SRST_PERIPH_AXI 57 +#define SRST_PERIPH_AHB 58 +#define SRST_PERIPH_APB 59 +#define SRST_PERIPH_NIU 60 +#define SRST_PDPERI_AHB_ARBI 61 +#define SRST_EMEM 62 +#define SRST_USB_PERI 63 + +#define SRST_DMAC2 64 +#define SRST_MAC 66 +#define SRST_GPS 67 +#define SRST_RKPWM 69 +#define SRST_USBHOST0 72 +#define SRST_HSIC 73 +#define SRST_HSIC_AUX 74 +#define SRST_HSIC_PHY 75 +#define SRST_HSADC 76 +#define SRST_NANDC0 77 +#define SRST_SFC 79 + +#define SRST_SPI0 83 +#define SRST_SPI1 84 +#define SRST_SPI2 85 +#define SRST_SARADC 87 +#define SRST_PDALIVE_NIU 88 +#define SRST_PDPMU_INTMEM 89 +#define SRST_PDPMU_NIU 90 +#define SRST_SGRF 91 + +#define SRST_VIO_ARBI 96 +#define SRST_RGA_NIU 97 +#define SRST_VIO0_NIU_AXI 98 +#define SRST_VIO_NIU_AHB 99 +#define SRST_LCDC0_AXI 100 +#define SRST_LCDC0_AHB 101 +#define SRST_LCDC0_DCLK 102 +#define SRST_VIP 104 +#define SRST_RGA_CORE 105 +#define SRST_IEP_AXI 106 +#define SRST_IEP_AHB 107 +#define SRST_RGA_AXI 108 +#define SRST_RGA_AHB 109 +#define SRST_ISP 110 +#define SRST_EDP_24M 111 + +#define SRST_VIDEO_AXI 112 +#define SRST_VIDEO_AHB 113 +#define SRST_MIPIDPHYTX 114 +#define SRST_MIPIDSI0 115 +#define SRST_MIPIDPHYRX 116 +#define SRST_MIPICSI 117 +#define SRST_GPU 120 +#define SRST_HDMI 121 +#define SRST_EDP 122 +#define SRST_PMU_PVTM 123 +#define SRST_CORE_PVTM 124 +#define SRST_GPU_PVTM 125 +#define SRST_GPU_SYS 126 +#define SRST_GPU_MEM_NIU 127 + +#define SRST_MMC0 128 +#define SRST_SDIO0 129 +#define SRST_EMMC 131 +#define SRST_USBOTG_AHB 132 +#define SRST_USBOTG_PHY 133 +#define SRST_USBOTG_CON 134 +#define SRST_USBHOST0_AHB 135 +#define SRST_USBHOST0_PHY 136 +#define SRST_USBHOST0_CON 137 +#define SRST_USBOTG_UTMI 138 +#define SRST_USBHOST1_UTMI 139 +#define SRST_USB_ADP 141 + +#define SRST_CORESIGHT 144 +#define SRST_PD_CORE_AHB_NOC 145 +#define SRST_PD_CORE_APB_NOC 146 +#define SRST_GIC 148 +#define SRST_LCDC_PWM0 149 +#define SRST_RGA_H2P_BRG 153 +#define SRST_VIDEO 154 +#define SRST_GPU_CFG_NIU 157 +#define SRST_TSADC 159 + +#define SRST_DDRPHY0 160 +#define SRST_DDRPHY0_APB 161 +#define SRST_DDRCTRL0 162 +#define SRST_DDRCTRL0_APB 163 +#define SRST_VIDEO_NIU 165 +#define SRST_VIDEO_NIU_AHB 167 +#define SRST_DDRMSCH0 170 +#define SRST_PDBUS_AHB 173 +#define SRST_CRYPTO 174 + +#define SRST_UART0 179 +#define SRST_UART1 180 +#define SRST_UART2 181 +#define SRST_UART3 182 +#define SRST_UART4 183 +#define SRST_SIMC 186 +#define SRST_TSP 188 +#define SRST_TSP_CLKIN0 189 + +#define SRST_CORE_L0 192 +#define SRST_CORE_L1 193 +#define SRST_CORE_L2 194 +#define SRST_CORE_L3 195 +#define SRST_CORE_L0_PO 195 +#define SRST_CORE_L1_PO 197 +#define SRST_CORE_L2_PO 198 +#define SRST_CORE_L3_PO 199 +#define SRST_L2_L 200 +#define SRST_ADB_L 201 +#define SRST_PD_CORE_L_NIU 202 +#define SRST_CCI_SYS 203 +#define SRST_CCI_DDR 204 +#define SRST_CCI 205 +#define SRST_SOCDBG_L 206 +#define SRST_CORE_L_DBG 207 + +#define SRST_CORE_B0_NC 208 +#define SRST_CORE_B0_PO_NC 209 +#define SRST_L2_B_NC 210 +#define SRST_ADB_B_NC 211 +#define SRST_PD_CORE_B_NIU_NC 212 +#define SRST_PDBUS_STRSYS_NC 213 +#define SRST_CORE_L0_NC 214 +#define SRST_CORE_L0_PO_NC 215 +#define SRST_L2_L_NC 216 +#define SRST_ADB_L_NC 217 +#define SRST_PD_CORE_L_NIU_NC 218 +#define SRST_CCI_SYS_NC 219 +#define SRST_CCI_DDR_NC 220 +#define SRST_CCI_NC 221 +#define SRST_TRACE_NC 222 + +#define SRST_TIMER00 224 +#define SRST_TIMER01 225 +#define SRST_TIMER02 226 +#define SRST_TIMER03 227 +#define SRST_TIMER04 228 +#define SRST_TIMER05 229 +#define SRST_TIMER10 230 +#define SRST_TIMER11 231 +#define SRST_TIMER12 232 +#define SRST_TIMER13 233 +#define SRST_TIMER14 234 +#define SRST_TIMER15 235 +#define SRST_TIMER0_APB 236 +#define SRST_TIMER1_APB 237 + +#endif diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 36fa555..402478e 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -38,6 +38,28 @@ struct clk_core; struct dentry; /** + * struct clk_rate_request - Structure encoding the clk constraints that + * a clock user might require. + * + * @rate: Requested clock rate. This field will be adjusted by + * clock drivers according to hardware capabilities. + * @min_rate: Minimum rate imposed by clk users. + * @max_rate: Maximum rate a imposed by clk users. + * @best_parent_rate: The best parent rate a parent can provide to fulfill the + * requested constraints. + * @best_parent_hw: The most appropriate parent clock that fulfills the + * requested constraints. + * + */ +struct clk_rate_request { + unsigned long rate; + unsigned long min_rate; + unsigned long max_rate; + unsigned long best_parent_rate; + struct clk_hw *best_parent_hw; +}; + +/** * struct clk_ops - Callback operations for hardware clocks; these are to * be provided by the clock implementation, and will be called by drivers * through the clk_* api. @@ -176,12 +198,8 @@ struct clk_ops { unsigned long parent_rate); long (*round_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); - long (*determine_rate)(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw); + int (*determine_rate)(struct clk_hw *hw, + struct clk_rate_request *req); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, unsigned long rate, @@ -550,6 +568,23 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, void of_gpio_clk_gate_setup(struct device_node *node); /** + * struct clk_gpio_mux - gpio controlled clock multiplexer + * + * @hw: see struct clk_gpio + * @gpiod: gpio descriptor to select the parent of this clock multiplexer + * + * Clock with a gpio control for selecting the parent clock. + * Implements .get_parent, .set_parent and .determine_rate + */ + +extern const struct clk_ops clk_gpio_mux_ops; +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags); + +void of_gpio_mux_clk_setup(struct device_node *node); + +/** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock * @hw: link to hardware-specific clock data @@ -578,21 +613,14 @@ unsigned long __clk_get_flags(struct clk *clk); bool __clk_is_prepared(struct clk *clk); bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); -long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p); -unsigned long __clk_determine_rate(struct clk_hw *core, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate); -long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p); +int __clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); +int __clk_determine_rate(struct clk_hw *core, struct clk_rate_request *req); +int __clk_mux_determine_rate_closest(struct clk_hw *hw, + struct clk_rate_request *req); void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); +void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, + unsigned long max_rate); static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) { diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 79b76e1..9299222 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -188,33 +188,6 @@ struct clk_hw_omap { /* DPLL Type and DCO Selection Flags */ #define DPLL_J_TYPE 0x1 -/* Composite clock component types */ -enum { - CLK_COMPONENT_TYPE_GATE = 0, - CLK_COMPONENT_TYPE_DIVIDER, - CLK_COMPONENT_TYPE_MUX, - CLK_COMPONENT_TYPE_MAX, -}; - -/** - * struct ti_dt_clk - OMAP DT clock alias declarations - * @lk: clock lookup definition - * @node_name: clock DT node to map to - */ -struct ti_dt_clk { - struct clk_lookup lk; - char *node_name; -}; - -#define DT_CLK(dev, con, name) \ - { \ - .lk = { \ - .dev_id = dev, \ - .con_id = con, \ - }, \ - .node_name = name, \ - } - /* Static memmap indices */ enum { TI_CLKM_CM = 0, @@ -225,8 +198,6 @@ enum { CLK_MAX_MEMMAPS }; -typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); - /** * struct clk_omap_reg - OMAP register declaration * @offset: offset from the master IP module base address @@ -238,93 +209,56 @@ struct clk_omap_reg { }; /** - * struct ti_clk_ll_ops - low-level register access ops for a clock + * struct ti_clk_ll_ops - low-level ops for clocks * @clk_readl: pointer to register read function * @clk_writel: pointer to register write function + * @clkdm_clk_enable: pointer to clockdomain enable function + * @clkdm_clk_disable: pointer to clockdomain disable function + * @cm_wait_module_ready: pointer to CM module wait ready function + * @cm_split_idlest_reg: pointer to CM module function to split idlest reg * - * Low-level register access ops are generally used by the basic clock types - * (clk-gate, clk-mux, clk-divider etc.) to provide support for various - * low-level hardware interfaces (direct MMIO, regmap etc.), but can also be - * used by other hardware-specific clock drivers if needed. + * Low-level ops are generally used by the basic clock types (clk-gate, + * clk-mux, clk-divider etc.) to provide support for various low-level + * hadrware interfaces (direct MMIO, regmap etc.), and is initialized + * by board code. Low-level ops also contain some other platform specific + * operations not provided directly by clock drivers. */ struct ti_clk_ll_ops { u32 (*clk_readl)(void __iomem *reg); void (*clk_writel)(u32 val, void __iomem *reg); + int (*clkdm_clk_enable)(struct clockdomain *clkdm, struct clk *clk); + int (*clkdm_clk_disable)(struct clockdomain *clkdm, + struct clk *clk); + int (*cm_wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); + int (*cm_split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, + u8 *idlest_reg_id); }; -extern struct ti_clk_ll_ops *ti_clk_ll_ops; - -extern const struct clk_ops ti_clk_divider_ops; -extern const struct clk_ops ti_clk_mux_ops; - #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) -void omap2_init_clk_hw_omap_clocks(struct clk *clk); -int omap3_noncore_dpll_enable(struct clk_hw *hw); -void omap3_noncore_dpll_disable(struct clk_hw *hw); -int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate, - u8 index); -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); -unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, - unsigned long parent_rate); -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate); -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); -u8 omap2_init_dpll_parent(struct clk_hw *hw); -unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate); void omap2_init_clk_clkdm(struct clk_hw *clk); -unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, - unsigned long parent_rate); -int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate); -int omap2_clkops_enable_clkdm(struct clk_hw *hw); -void omap2_clkops_disable_clkdm(struct clk_hw *hw); int omap2_clk_disable_autoidle_all(void); -void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); -int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, - unsigned long parent_rate); -int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate, u8 index); -int omap2_dflt_clk_enable(struct clk_hw *hw); -void omap2_dflt_clk_disable(struct clk_hw *hw); -int omap2_dflt_clk_is_enabled(struct clk_hw *hw); -void omap3_clk_lock_dpll5(void); +int omap2_clk_enable_autoidle_all(void); +int omap2_clk_allow_idle(struct clk *clk); +int omap2_clk_deny_idle(struct clk *clk); unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, unsigned long parent_rate); int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); void omap2xxx_clkt_vps_init(void); +unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); -void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); -void ti_dt_clocks_register(struct ti_dt_clk *oclks); -void ti_dt_clk_init_provider(struct device_node *np, int index); void ti_dt_clk_init_retry_clks(void); void ti_dt_clockdomains_setup(void); -int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, - ti_of_clk_init_cb_t func); -int of_ti_clk_autoidle_setup(struct device_node *node); -int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); +int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops); + +struct regmap; + +int omap2_clk_provider_init(struct device_node *parent, int index, + struct regmap *syscon, void __iomem *mem); +void omap2_clk_legacy_provider_init(int index, void __iomem *mem); int omap3430_dt_clk_init(void); int omap3630_dt_clk_init(void); @@ -338,27 +272,24 @@ int am43xx_dt_clk_init(void); int omap2420_dt_clk_init(void); int omap2430_dt_clk_init(void); -#ifdef CONFIG_OF -void of_ti_clk_allow_autoidle_all(void); -void of_ti_clk_deny_autoidle_all(void); -#else -static inline void of_ti_clk_allow_autoidle_all(void) { } -static inline void of_ti_clk_deny_autoidle_all(void) { } -#endif +struct ti_clk_features { + u32 flags; + long fint_min; + long fint_max; + long fint_band1_max; + long fint_band2_min; + u8 dpll_bypass_vals; + u8 cm_idlest_val; +}; + +#define TI_CLK_DPLL_HAS_FREQSEL BIT(0) +#define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1) +#define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2) + +void ti_clk_setup_features(struct ti_clk_features *features); +const struct ti_clk_features *ti_clk_get_features(void); extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; -extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; -extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; -extern const struct clk_hw_omap_ops clkhwops_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; -extern const struct clk_hw_omap_ops clkhwops_iclk; -extern const struct clk_hw_omap_ops clkhwops_iclk_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; #ifdef CONFIG_ATAGS int omap3430_clk_legacy_init(void); |