X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fclk%2Fbcm%2Fclk-bcm2835.c;h=2b0ca6670ae6199b83d1a5281fc50f1b7fda42d8;hb=2aae4cc63e30f99dd152fc63cc4a67ca29e4647b;hp=141ce19bc57002bfabe6c2658118ff26a6eb0fec;hpb=4f5365f77018349d64386b202b37e8b737236556;p=platform%2Fkernel%2Flinux-rpi.git diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 141ce19..2b0ca66 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -36,6 +36,7 @@ #include #include #include +#include #define CM_PASSWORD 0x5a000000 @@ -296,6 +297,8 @@ #define SOC_BCM2711 BIT(1) #define SOC_ALL (SOC_BCM2835 | SOC_BCM2711) +#define VCMSG_ID_CORE_CLOCK 4 + /* * Names of clocks used within the driver that need to be replaced * with an external parent's name. This array is in the order that @@ -314,6 +317,7 @@ static const char *const cprman_parent_names[] = { struct bcm2835_cprman { struct device *dev; void __iomem *regs; + struct rpi_firmware *fw; spinlock_t regs_lock; /* spinlock for all clocks */ unsigned int soc; @@ -643,15 +647,17 @@ static int bcm2835_pll_on(struct clk_hw *hw) spin_unlock(&cprman->regs_lock); /* Wait for the PLL to lock. */ - timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); - while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { - if (ktime_after(ktime_get(), timeout)) { - dev_err(cprman->dev, "%s: couldn't lock PLL\n", - clk_hw_get_name(hw)); - return -ETIMEDOUT; + if (strcmp(data->name, "pllh")) { + timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); + while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { + if (ktime_after(ktime_get(), timeout)) { + dev_err(cprman->dev, "%s: couldn't lock PLL\n", + clk_hw_get_name(hw)); + return -ETIMEDOUT; + } + + cpu_relax(); } - - cpu_relax(); } cprman_write(cprman, data->a2w_ctrl_reg, @@ -1040,6 +1046,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, return rate; } +static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; + + if (cprman->fw) { + struct { + u32 id; + u32 val; + } packet; + + packet.id = VCMSG_ID_CORE_CLOCK; + packet.val = 0; + + if (!rpi_firmware_property(cprman->fw, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE, + &packet, sizeof(packet))) + return packet.val; + } + + return bcm2835_clock_get_rate(hw, parent_rate); +} + static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) { struct bcm2835_cprman *cprman = clock->cprman; @@ -1098,8 +1128,10 @@ static int bcm2835_clock_on(struct clk_hw *hw) return 0; } -static int bcm2835_clock_set_rate(struct clk_hw *hw, - unsigned long rate, unsigned long parent_rate) +static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 parent) { struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct bcm2835_cprman *cprman = clock->cprman; @@ -1109,15 +1141,24 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, spin_lock(&cprman->regs_lock); - /* - * Setting up frac support - * - * In principle it is recommended to stop/start the clock first, - * but as we set CLK_SET_RATE_GATE during registration of the - * clock this requirement should be take care of by the - * clk-framework. + ctl = cprman_read(cprman, data->ctl_reg); + + /* If the clock is running, we have to pause clock generation while + * updating the control and div regs. This is glitchless (no clock + * signals generated faster than the rate) but each reg access is two + * OSC cycles so the clock will slow down for a moment. */ - ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC; + if (ctl & CM_ENABLE) { + cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE); + bcm2835_clock_wait_busy(clock); + } + + if (parent != 0xff) { + ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT); + ctl |= parent << CM_SRC_SHIFT; + } + + ctl &= ~CM_FRAC; ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; cprman_write(cprman, data->ctl_reg, ctl); @@ -1128,6 +1169,12 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, return 0; } +static int bcm2835_clock_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff); +} + static bool bcm2835_clk_is_pllc(struct clk_hw *hw) { @@ -1311,6 +1358,7 @@ static const struct clk_ops bcm2835_clock_clk_ops = { .unprepare = bcm2835_clock_off, .recalc_rate = bcm2835_clock_get_rate, .set_rate = bcm2835_clock_set_rate, + .set_rate_and_parent = bcm2835_clock_set_rate_and_parent, .determine_rate = bcm2835_clock_determine_rate, .set_parent = bcm2835_clock_set_parent, .get_parent = bcm2835_clock_get_parent, @@ -1328,7 +1376,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) */ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { .is_prepared = bcm2835_vpu_clock_is_on, - .recalc_rate = bcm2835_clock_get_rate, + .recalc_rate = bcm2835_clock_get_rate_vpu, .set_rate = bcm2835_clock_set_rate, .determine_rate = bcm2835_clock_determine_rate, .set_parent = bcm2835_clock_set_parent, @@ -1336,6 +1384,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { .debug_init = bcm2835_clock_debug_init, }; +static bool bcm2835_clk_is_claimed(const char *name); + static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, const void *data) { @@ -1353,6 +1403,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, init.ops = &bcm2835_pll_clk_ops; init.flags = pll_data->flags | CLK_IGNORE_UNUSED; + if (!bcm2835_clk_is_claimed(pll_data->name)) + init.flags |= CLK_IS_CRITICAL; + pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return NULL; @@ -1408,6 +1461,13 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, divider->div.hw.init = &init; divider->div.table = NULL; + if (!(cprman_read(cprman, divider_data->cm_reg) & divider_data->hold_mask)) { + if (!bcm2835_clk_is_claimed(divider_data->source_pll)) + init.flags |= CLK_IS_CRITICAL; + if (!bcm2835_clk_is_claimed(divider_data->name)) + divider->div.flags |= CLK_IS_CRITICAL; + } + divider->cprman = cprman; divider->data = divider_data; @@ -1462,6 +1522,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, init.flags = clock_data->flags | CLK_IGNORE_UNUSED; /* + * Some GPIO clocks for ethernet/wifi PLLs are marked as + * critical (since some platforms use them), but if the + * firmware didn't have them turned on then they clearly + * aren't actually critical. + */ + if ((cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE) == 0) + init.flags &= ~CLK_IS_CRITICAL; + + /* * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate * rate changes on at least of the parents. */ @@ -1472,7 +1541,6 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, init.ops = &bcm2835_vpu_clock_clk_ops; } else { init.ops = &bcm2835_clock_clk_ops; - init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; /* If the clock wasn't actually enabled at boot, it's not * critical. @@ -1697,16 +1765,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .hold_mask = CM_PLLA_HOLDCORE, .fixed_divider = 1, .flags = CLK_SET_RATE_PARENT), - [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( - SOC_ALL, - .name = "plla_per", - .source_pll = "plla", - .cm_reg = CM_PLLA, - .a2w_reg = A2W_PLLA_PER, - .load_mask = CM_PLLA_LOADPER, - .hold_mask = CM_PLLA_HOLDPER, - .fixed_divider = 1, - .flags = CLK_SET_RATE_PARENT), + + /* + * PLLA_PER is used for gpu clocks. Controlled by firmware, see + * clk-raspberrypi.c. + */ + [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( SOC_ALL, .name = "plla_dsi0", @@ -2007,14 +2071,12 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .int_bits = 6, .frac_bits = 0, .tcnt_mux = 3), - [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( - SOC_ALL, - .name = "v3d", - .ctl_reg = CM_V3DCTL, - .div_reg = CM_V3DDIV, - .int_bits = 4, - .frac_bits = 8, - .tcnt_mux = 4), + + /* + * CLOCK_V3D is used for v3d clock. Controlled by firmware, see + * clk-raspberrypi.c. + */ + /* * VPU clock. This doesn't have an enable bit, since it drives * the bus for everything else, and is special so it doesn't need @@ -2177,21 +2239,6 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .tcnt_mux = 28, .round_up = true), - /* TV encoder clock. Only operating frequency is 108Mhz. */ - [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( - SOC_ALL, - .name = "vec", - .ctl_reg = CM_VECCTL, - .div_reg = CM_VECDIV, - .int_bits = 4, - .frac_bits = 0, - /* - * Allow rate change propagation only on PLLH_AUX which is - * assigned index 7 in the parent array. - */ - .set_rate_parent = BIT(7), - .tcnt_mux = 29), - /* dsi clocks */ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( SOC_ALL, @@ -2241,6 +2288,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .ctl_reg = CM_PERIICTL), }; +static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)]; + /* * Permanently take a reference on the parent of the SDRAM clock. * @@ -2260,6 +2309,21 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) return clk_prepare_enable(parent); } +static bool bcm2835_clk_is_claimed(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { + if (clk_desc_array[i].data) { + const char *clk_name = *(const char **)(clk_desc_array[i].data); + if (!strcmp(name, clk_name)) + return bcm2835_clk_claimed[i]; + } + } + + return false; +} + static int bcm2835_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2268,7 +2332,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev) const struct bcm2835_clk_desc *desc; const size_t asize = ARRAY_SIZE(clk_desc_array); const struct cprman_plat_data *pdata; + struct device_node *fw_node; size_t i; + u32 clk_id; int ret; pdata = of_device_get_match_data(&pdev->dev); @@ -2287,6 +2353,21 @@ static int bcm2835_clk_probe(struct platform_device *pdev) if (IS_ERR(cprman->regs)) return PTR_ERR(cprman->regs); + fw_node = of_parse_phandle(dev->of_node, "firmware", 0); + if (fw_node) { + struct rpi_firmware *fw = rpi_firmware_get(fw_node); + if (!fw) + return -EPROBE_DEFER; + cprman->fw = fw; + } + + memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); + for (i = 0; + !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", + i, &clk_id); + i++) + bcm2835_clk_claimed[clk_id]= true; + memcpy(cprman->real_parent_names, cprman_parent_names, sizeof(cprman_parent_names)); of_clk_parent_fill(dev->of_node, cprman->real_parent_names, @@ -2320,8 +2401,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev) if (ret) return ret; - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, &cprman->onecell); + if (ret) + return ret; + + /* note that we have registered all the clocks */ + dev_dbg(dev, "registered %zd clocks\n", asize); + + return 0; } static const struct cprman_plat_data cprman_bcm2835_plat_data = { @@ -2347,7 +2435,15 @@ static struct platform_driver bcm2835_clk_driver = { .probe = bcm2835_clk_probe, }; -builtin_platform_driver(bcm2835_clk_driver); +static int __init __bcm2835_clk_driver_init(void) +{ + return platform_driver_register(&bcm2835_clk_driver); +} +#ifdef CONFIG_IMA +subsys_initcall(__bcm2835_clk_driver_init); +#else +postcore_initcall(__bcm2835_clk_driver_init); +#endif MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("BCM2835 clock driver");