Lines Matching +full:reference +full:- +full:div +full:- +full:factor
1 // SPDX-License-Identifier: GPL-2.0-only
6 * - Read-only PLLs, all derived from the same main crystal clock.
7 * - It also exposes divider clocks, those are children to PLLs.
8 * - Fixed factor clocks, children to PLLs.
11 * shared region called OLB. Some PLLs and fixed-factors are initialised early
14 * We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter.
23 #define pr_fmt(fmt) "clk-eyeq: " fmt
29 #include <linux/clk-provider.h>
34 #include <linux/io-64-nonatomic-hi-lo.h>
47 #include <dt-bindings/clock/mobileye,eyeq5-clk.h>
69 /* Down-spread or center-spread */
96 unsigned int div; member
131 * Both factors (mult and div) must fit in 32 bits. When an operation overflows,
134 * Precision loss depends on amplitude of mult and div. Worst theorical
135 * loss is: (UINT_MAX+1) / UINT_MAX - 1 = 2.3e-10.
138 static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *div) in eqc_pll_downshift_factors() argument
143 /* This function can be removed if mult/div switch to unsigned long. */ in eqc_pll_downshift_factors()
145 static_assert(sizeof_field(struct clk_fixed_factor, div) == sizeof(unsigned int)); in eqc_pll_downshift_factors()
148 if (*mult <= UINT_MAX && *div <= UINT_MAX) in eqc_pll_downshift_factors()
152 * Compute the shift required to bring the biggest factor into unsigned in eqc_pll_downshift_factors()
156 biggest = max(*mult, *div); in eqc_pll_downshift_factors()
157 shift = __fls(biggest) - (BITS_PER_BYTE * sizeof(unsigned int)) + 1; in eqc_pll_downshift_factors()
160 *div >>= shift; in eqc_pll_downshift_factors()
164 unsigned long *div, unsigned long *acc) in eqc_pll_parse_registers() argument
170 *div = 1; in eqc_pll_parse_registers()
176 return -EINVAL; in eqc_pll_parse_registers()
179 *div = FIELD_GET(PCSR0_REF_DIV, r0); in eqc_pll_parse_registers()
181 *div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0); in eqc_pll_parse_registers()
185 *div *= (1ULL << 20); in eqc_pll_parse_registers()
189 if (!*mult || !*div) in eqc_pll_parse_registers()
190 return -EINVAL; in eqc_pll_parse_registers()
215 *mult *= 2000 - spread; in eqc_pll_parse_registers()
216 *div *= 2000; in eqc_pll_parse_registers()
222 eqc_pll_downshift_factors(mult, div); in eqc_pll_parse_registers()
231 unsigned long mult, div, acc; in eqc_probe_init_plls() local
239 for (i = 0; i < data->pll_count; i++) { in eqc_probe_init_plls()
240 pll = &data->plls[i]; in eqc_probe_init_plls()
242 val = readq(base + pll->reg64); in eqc_probe_init_plls()
246 ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc); in eqc_probe_init_plls()
248 dev_warn(dev, "failed parsing state of %s\n", pll->name); in eqc_probe_init_plls()
249 cells->hws[pll->index] = ERR_PTR(ret); in eqc_probe_init_plls()
254 dev->of_node, pll->name, "ref", 0, mult, div, acc); in eqc_probe_init_plls()
255 cells->hws[pll->index] = hw; in eqc_probe_init_plls()
257 dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw); in eqc_probe_init_plls()
265 const struct eqc_div *div; in eqc_probe_init_divs() local
271 for (i = 0; i < data->div_count; i++) { in eqc_probe_init_divs()
272 div = &data->divs[i]; in eqc_probe_init_divs()
273 reg = base + div->reg; in eqc_probe_init_divs()
274 parent = cells->hws[div->parent]; in eqc_probe_init_divs()
278 parent_data.index = div->parent; in eqc_probe_init_divs()
281 /* Avoid clock lookup when we already have the hw reference. */ in eqc_probe_init_divs()
286 hw = clk_hw_register_divider_table_parent_data(dev, div->name, in eqc_probe_init_divs()
287 &parent_data, 0, reg, div->shift, div->width, in eqc_probe_init_divs()
289 cells->hws[div->index] = hw; in eqc_probe_init_divs()
292 div->name, hw); in eqc_probe_init_divs()
304 for (i = 0; i < data->fixed_factor_count; i++) { in eqc_probe_init_fixed_factors()
305 ff = &data->fixed_factors[i]; in eqc_probe_init_fixed_factors()
306 parent_hw = cells->hws[ff->parent]; in eqc_probe_init_fixed_factors()
310 hw = clk_hw_register_fixed_factor_index(dev, ff->name, in eqc_probe_init_fixed_factors()
311 ff->parent, 0, ff->mult, ff->div); in eqc_probe_init_fixed_factors()
313 /* Avoid clock lookup when we already have the hw reference. */ in eqc_probe_init_fixed_factors()
314 hw = clk_hw_register_fixed_factor_parent_hw(dev, ff->name, in eqc_probe_init_fixed_factors()
315 parent_hw, 0, ff->mult, ff->div); in eqc_probe_init_fixed_factors()
318 cells->hws[ff->index] = hw; in eqc_probe_init_fixed_factors()
321 ff->name, hw); in eqc_probe_init_fixed_factors()
340 return -ENOMEM; in eqc_auxdev_create()
342 adev->name = name; in eqc_auxdev_create()
343 adev->dev.parent = dev; in eqc_auxdev_create()
344 adev->dev.platform_data = (void __force *)base; in eqc_auxdev_create()
345 adev->dev.release = eqc_auxdev_release; in eqc_auxdev_create()
346 adev->id = id; in eqc_auxdev_create()
361 struct device *dev = &pdev->dev; in eqc_probe()
362 struct device_node *np = dev->of_node; in eqc_probe()
376 return -ENODEV; in eqc_probe()
378 base = ioremap(res->start, resource_size(res)); in eqc_probe()
380 return -ENOMEM; in eqc_probe()
383 if (data->reset_auxdev_name) { in eqc_probe()
384 ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0); in eqc_probe()
387 KBUILD_MODNAME, data->reset_auxdev_name, ret); in eqc_probe()
391 if (data->pinctrl_auxdev_name) { in eqc_probe()
392 ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0); in eqc_probe()
395 KBUILD_MODNAME, data->pinctrl_auxdev_name, ret); in eqc_probe()
398 if (data->pll_count + data->div_count + data->fixed_factor_count == 0) in eqc_probe()
401 clk_count = data->pll_count + data->div_count + in eqc_probe()
402 data->fixed_factor_count + data->early_clk_count; in eqc_probe()
405 return -ENOMEM; in eqc_probe()
407 cells->num = clk_count; in eqc_probe()
411 cells->hws[i] = ERR_PTR(-EINVAL); in eqc_probe()
422 /* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */
424 { .index = EQ5C_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
425 { .index = EQ5C_PLL_PER, .name = "pll-per", .reg64 = 0x05C },
429 { .index = EQ5C_PLL_VMP, .name = "pll-vmp", .reg64 = 0x034 },
430 { .index = EQ5C_PLL_PMA, .name = "pll-pma", .reg64 = 0x03C },
431 { .index = EQ5C_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
432 { .index = EQ5C_PLL_DDR0, .name = "pll-ddr0", .reg64 = 0x04C },
433 { .index = EQ5C_PLL_PCI, .name = "pll-pci", .reg64 = 0x054 },
434 { .index = EQ5C_PLL_PMAC, .name = "pll-pmac", .reg64 = 0x064 },
435 { .index = EQ5C_PLL_MPC, .name = "pll-mpc", .reg64 = 0x06C },
436 { .index = EQ5C_PLL_DDR1, .name = "pll-ddr1", .reg64 = 0x074 },
442 * EQ5C_PER_OCC_PCI is the last clock exposed in dt-bindings.
478 { EQ5C_CPU_OCC, "occ-cpu", 1, 1, EQ5C_PLL_CPU },
479 { EQ5C_CPU_SI_CSS0, "si-css0", 1, 1, EQ5C_CPU_OCC },
486 { EQ5C_PER_OCC, "occ-periph", 1, 16, EQ5C_PLL_PER },
495 { EQ5C_CPU_OCC_ISRAM, "occ-isram", 1, 2, EQ5C_PLL_CPU },
497 { EQ5C_CPU_OCC_DBU, "occ-dbu", 1, 10, EQ5C_PLL_CPU },
498 { EQ5C_CPU_SI_DBU_TP, "si-dbu-tp", 1, 1, EQ5C_CPU_OCC_DBU },
501 { EQ5C_VDI_OCC_VDI, "occ-vdi", 1, 2, EQ5C_PLL_VDI },
503 { EQ5C_VDI_OCC_CAN_SER, "occ-can-ser", 1, 16, EQ5C_PLL_VDI },
504 { EQ5C_VDI_CAN_SER, "can-ser", 1, 1, EQ5C_VDI_OCC_CAN_SER },
505 { EQ5C_VDI_I2C_SER, "i2c-ser", 1, 20, EQ5C_PLL_VDI },
514 { EQ5C_PER_EMMC, "emmc-sys", 1, 10, EQ5C_PLL_PER },
515 { EQ5C_PER_CCF, "ccf-ctrl", 1, 4, EQ5C_PLL_PER },
516 { EQ5C_PER_OCC_MJPEG, "occ-mjpeg", 1, 2, EQ5C_PLL_PER },
519 { EQ5C_PER_FCMU_A, "fcmu-a", 1, 20, EQ5C_PLL_PER },
520 { EQ5C_PER_OCC_PCI, "occ-pci-sys", 1, 8, EQ5C_PLL_PER },
526 .name = "div-ospi",
563 { .index = EQ6LC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x02C },
564 { .index = EQ6LC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x034 }, /* also acc */
565 { .index = EQ6LC_PLL_PER, .name = "pll-per", .reg64 = 0x03C },
566 { .index = EQ6LC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
581 { .index = 0, .name = "pll-east", .reg64 = 0x074 },
592 { .index = EQ6HC_SOUTH_PLL_VDI, .name = "pll-vdi", .reg64 = 0x000 },
593 { .index = EQ6HC_SOUTH_PLL_PCIE, .name = "pll-pcie", .reg64 = 0x008 },
594 { .index = EQ6HC_SOUTH_PLL_PER, .name = "pll-per", .reg64 = 0x010 },
595 { .index = EQ6HC_SOUTH_PLL_ISP, .name = "pll-isp", .reg64 = 0x018 },
601 .name = "div-emmc",
609 .name = "div-ospi-ref",
617 .name = "div-ospi-sys",
625 .name = "div-tsu",
642 { .index = 0, .name = "pll-ddr0", .reg64 = 0x074 },
651 { .index = 0, .name = "pll-ddr1", .reg64 = 0x074 },
660 { .index = EQ6HC_ACC_PLL_XNN, .name = "pll-xnn", .reg64 = 0x040 },
661 { .index = EQ6HC_ACC_PLL_VMP, .name = "pll-vmp", .reg64 = 0x050 },
662 { .index = EQ6HC_ACC_PLL_PMA, .name = "pll-pma", .reg64 = 0x05C },
663 { .index = EQ6HC_ACC_PLL_MPC, .name = "pll-mpc", .reg64 = 0x068 },
664 { .index = EQ6HC_ACC_PLL_NOC, .name = "pll-noc", .reg64 = 0x070 },
675 { .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data },
676 { .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data },
677 { .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data },
678 { .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data },
679 { .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data },
680 { .compatible = "mobileye,eyeq6h-ddr0-olb", .data = &eqc_eyeq6h_ddr0_match_data },
681 { .compatible = "mobileye,eyeq6h-ddr1-olb", .data = &eqc_eyeq6h_ddr1_match_data },
682 { .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqc_eyeq6h_acc_match_data },
689 .name = "clk-eyeq",
698 { .index = EQ6HC_CENTRAL_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
702 { EQ6HC_CENTRAL_CPU_OCC, "occ-cpu", 1, 1, EQ6HC_CENTRAL_PLL_CPU },
715 { .index = EQ6HC_WEST_PLL_PER, .name = "pll-west", .reg64 = 0x074 },
719 { EQ6HC_WEST_PER_OCC, "west-per-occ", 1, 10, EQ6HC_WEST_PLL_PER },
720 { EQ6HC_WEST_PER_UART, "west-per-uart", 1, 1, EQ6HC_WEST_PER_OCC },
739 clk_count = early_data->early_pll_count + early_data->early_fixed_factor_count + in eqc_early_init()
740 early_data->late_clk_count; in eqc_early_init()
743 ret = -ENOMEM; in eqc_early_init()
747 cells->num = clk_count; in eqc_early_init()
757 cells->hws[i] = ERR_PTR(-EPROBE_DEFER); in eqc_early_init()
762 ret = -ENODEV; in eqc_early_init()
766 for (i = 0; i < early_data->early_pll_count; i++) { in eqc_early_init()
767 const struct eqc_pll *pll = &early_data->early_plls[i]; in eqc_early_init()
768 unsigned long mult, div, acc; in eqc_early_init() local
773 val = readq(base + pll->reg64); in eqc_early_init()
777 ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc); in eqc_early_init()
779 pr_err("failed parsing state of %s\n", pll->name); in eqc_early_init()
784 np, pll->name, "ref", 0, mult, div, acc); in eqc_early_init()
785 cells->hws[pll->index] = hw; in eqc_early_init()
787 pr_err("failed registering %s: %pe\n", pll->name, hw); in eqc_early_init()
793 for (i = 0; i < early_data->early_fixed_factor_count; i++) { in eqc_early_init()
794 const struct eqc_fixed_factor *ff = &early_data->early_fixed_factors[i]; in eqc_early_init()
795 struct clk_hw *parent_hw = cells->hws[ff->parent]; in eqc_early_init()
798 hw = clk_hw_register_fixed_factor_parent_hw(NULL, ff->name, in eqc_early_init()
799 parent_hw, 0, ff->mult, ff->div); in eqc_early_init()
800 cells->hws[ff->index] = hw; in eqc_early_init()
802 pr_err("failed registering %s: %pe\n", ff->name, hw); in eqc_early_init()
829 for (i = 0; i < early_data->early_pll_count; i++) { in eqc_early_init()
830 const struct eqc_pll *pll = &early_data->early_plls[i]; in eqc_early_init()
831 struct clk_hw *hw = cells->hws[pll->index]; in eqc_early_init()
845 CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-olb", eqc_eyeq5_early_init);
851 CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-olb",
858 CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb",