Merge branches 'clk-socfpga', 'clk-toshiba', 'clk-st' and 'clk-bitmain' into clk-next

- Clock and reset driver for Toshiba Visconti SoCs

* clk-socfpga:
  clk: socfpga: s10: Make use of the helper function devm_platform_ioremap_resource()
  clk: socfpga: agilex: Make use of the helper function devm_platform_ioremap_resource()
  clk: socfpga: remove redundant assignment after a mask operation
  clk: socfpga: remove redundant assignment on division

* clk-toshiba:
  clk: visconti: Remove pointless NULL check in visconti_pll_add_lookup()
  MAINTAINERS: Add entries for Toshiba Visconti PLL and clock controller
  clk: visconti: Add support common clock driver and reset driver
  dt-bindings: clock: Add DT bindings for SMU of Toshiba Visconti TMPV770x SoC
  dt-bindings: clock: Add DT bindings for PLL of Toshiba Visconti TMPV770x SoC

* clk-st:
  clk: Drop unused COMMON_CLK_STM32MP157_SCMI config
  clk: st: clkgen-mux: search reg within node or parent
  clk: st: clkgen-fsyn: search reg within node or parent

* clk-bitmain:
  clk: bm1880: remove kfrees on static allocations
This commit is contained in:
Stephen Boyd 2022-01-11 18:30:50 -08:00
24 changed files with 1580 additions and 41 deletions

View File

@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/toshiba,tmpv770x-pipllct.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Toshiba Visconti5 TMPV770X PLL Controller Device Tree Bindings
maintainers:
- Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
description:
Toshia Visconti5 PLL controller which supports the PLLs on TMPV770X.
properties:
compatible:
const: toshiba,tmpv7708-pipllct
reg:
maxItems: 1
'#clock-cells':
const: 1
clocks:
description: External reference clock (OSC2)
maxItems: 1
required:
- compatible
- reg
- "#clock-cells"
- clocks
additionalProperties: false
examples:
- |
osc2_clk: osc2-clk {
compatible = "fixed-clock";
clock-frequency = <20000000>;
#clock-cells = <0>;
};
soc {
#address-cells = <2>;
#size-cells = <2>;
pipllct: clock-controller@24220000 {
compatible = "toshiba,tmpv7708-pipllct";
reg = <0 0x24220000 0 0x820>;
#clock-cells = <1>;
clocks = <&osc2_clk>;
};
};
...

View File

@ -0,0 +1,52 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/toshiba,tmpv770x-pismu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Toshiba Visconti5 TMPV770x SMU controller Device Tree Bindings
maintainers:
- Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
description:
Toshia Visconti5 SMU (System Management Unit) which supports the clock
and resets on TMPV770x.
properties:
compatible:
items:
- const: toshiba,tmpv7708-pismu
- const: syscon
reg:
maxItems: 1
'#clock-cells':
const: 1
'#reset-cells':
const: 1
required:
- compatible
- reg
- "#clock-cells"
- "#reset-cells"
additionalProperties: false
examples:
- |
soc {
#address-cells = <2>;
#size-cells = <2>;
pismu: syscon@24200000 {
compatible = "toshiba,tmpv7708-pismu", "syscon";
reg = <0 0x24200000 0 0x2140>;
#clock-cells = <1>;
#reset-cells = <1>;
};
};
...

View File

@ -2782,12 +2782,15 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu/linux-visconti.git
F: Documentation/devicetree/bindings/arm/toshiba.yaml
F: Documentation/devicetree/bindings/clock/toshiba,tmpv770x-pipllct.yaml
F: Documentation/devicetree/bindings/clock/toshiba,tmpv770x-pismu.yaml
F: Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml
F: Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml
F: Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
F: Documentation/devicetree/bindings/pinctrl/toshiba,visconti-pinctrl.yaml
F: Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml
F: arch/arm64/boot/dts/toshiba/
F: drivers/clk/visconti/
F: drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
F: drivers/gpio/gpio-visconti.c
F: drivers/pci/controller/dwc/pcie-visconti.c

View File

@ -354,16 +354,6 @@ config COMMON_CLK_STM32MP157
help
Support for stm32mp157 SoC family clocks
config COMMON_CLK_STM32MP157_SCMI
bool "stm32mp157 Clock driver with Trusted Firmware"
depends on COMMON_CLK_STM32MP157
select COMMON_CLK_SCMI
select ARM_SCMI_PROTOCOL
default y
help
Support for stm32mp157 SoC family clocks with Trusted Firmware using
SCMI protocol.
config COMMON_CLK_STM32F
def_bool COMMON_CLK && (MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746)
help
@ -432,6 +422,7 @@ source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/visconti/Kconfig"
source "drivers/clk/x86/Kconfig"
source "drivers/clk/xilinx/Kconfig"
source "drivers/clk/zynqmp/Kconfig"

View File

@ -118,6 +118,7 @@ obj-y += ti/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-y += versatile/
obj-$(CONFIG_COMMON_CLK_VISCONTI) += visconti/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_X86) += x86/
endif

View File

@ -522,14 +522,6 @@ static struct clk_hw *bm1880_clk_register_pll(struct bm1880_pll_hw_clock *pll_cl
return hw;
}
static void bm1880_clk_unregister_pll(struct clk_hw *hw)
{
struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw);
clk_hw_unregister(hw);
kfree(pll_hw);
}
static int bm1880_clk_register_plls(struct bm1880_pll_hw_clock *clks,
int num_clks,
struct bm1880_clock_data *data)
@ -555,7 +547,7 @@ static int bm1880_clk_register_plls(struct bm1880_pll_hw_clock *clks,
err_clk:
while (i--)
bm1880_clk_unregister_pll(data->hw_data.hws[clks[i].pll.id]);
clk_hw_unregister(data->hw_data.hws[clks[i].pll.id]);
return PTR_ERR(hw);
}
@ -695,14 +687,6 @@ static struct clk_hw *bm1880_clk_register_div(struct bm1880_div_hw_clock *div_cl
return hw;
}
static void bm1880_clk_unregister_div(struct clk_hw *hw)
{
struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
clk_hw_unregister(hw);
kfree(div_hw);
}
static int bm1880_clk_register_divs(struct bm1880_div_hw_clock *clks,
int num_clks,
struct bm1880_clock_data *data)
@ -729,7 +713,7 @@ static int bm1880_clk_register_divs(struct bm1880_div_hw_clock *clks,
err_clk:
while (i--)
bm1880_clk_unregister_div(data->hw_data.hws[clks[i].div.id]);
clk_hw_unregister(data->hw_data.hws[clks[i].div.id]);
return PTR_ERR(hw);
}

View File

@ -500,12 +500,10 @@ static int n5x_clkmgr_init(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct stratix10_clock_data *clk_data;
struct resource *res;
void __iomem *base;
int i, num_clks;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);

View File

@ -34,7 +34,7 @@ static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
if (streq(name, SOCFPGA_L4_MP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
return l4_src &= 0x1;
return l4_src & 0x1;
}
if (streq(name, SOCFPGA_L4_SP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
@ -43,7 +43,7 @@ static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
if (streq(name, SOCFPGA_MMC_CLK))
return perpll_src &= 0x3;
return perpll_src & 0x3;
if (streq(name, SOCFPGA_NAND_CLK) ||
streq(name, SOCFPGA_NAND_X_CLK))
return (perpll_src >> 2) & 3;

View File

@ -113,7 +113,7 @@ static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
SWCTRLBTCLKSEL_MASK) >>
SWCTRLBTCLKSEL_SHIFT);
div += 1;
return parent_rate /= div;
return parent_rate / div;
}

View File

@ -388,12 +388,10 @@ static int s10_clkmgr_init(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct stratix10_clock_data *clk_data;
struct resource *res;
void __iomem *base;
int i, num_clks;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
pr_err("%s: failed to map clock registers\n", __func__);
return PTR_ERR(base);

View File

@ -988,9 +988,18 @@ static void __init st_of_quadfs_setup(struct device_node *np,
void __iomem *reg;
spinlock_t *lock;
/*
* First check for reg property within the node to keep backward
* compatibility, then if reg doesn't exist look at the parent node
*/
reg = of_iomap(np, 0);
if (!reg)
return;
if (!reg) {
reg = of_iomap(of_get_parent(np), 0);
if (!reg) {
pr_err("%s: Failed to get base address\n", __func__);
return;
}
}
clk_parent_name = of_clk_get_parent_name(np, 0);
if (!clk_parent_name)

View File

@ -57,10 +57,17 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np,
const char **parents;
int num_parents = 0;
/*
* First check for reg property within the node to keep backward
* compatibility, then if reg doesn't exist look at the parent node
*/
reg = of_iomap(np, 0);
if (!reg) {
pr_err("%s: Failed to get base address\n", __func__);
return;
reg = of_iomap(of_get_parent(np), 0);
if (!reg) {
pr_err("%s: Failed to get base address\n", __func__);
return;
}
}
parents = clkgen_mux_get_parents(np, &num_parents);

View File

@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
config COMMON_CLK_VISCONTI
bool "Support for Toshiba Visconti5 ARM SoC clock controllers"
depends on ARCH_VISCONTI || COMPILE_TEST
default ARCH_VISCONTI
help
Support for the Toshiba Visconti5 ARM SoC clock controller.
Say Y if you want to include clock support.

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
# Makefile for Toshiba Visconti clock
obj-y += clkc.o pll.o reset.o
obj-y += pll-tmpv770x.o clkc-tmpv770x.o

View File

@ -0,0 +1,291 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba Visconti clock controller
*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/toshiba,tmpv770x.h>
#include <dt-bindings/reset/toshiba,tmpv770x.h>
#include "clkc.h"
#include "reset.h"
static DEFINE_SPINLOCK(tmpv770x_clk_lock);
static DEFINE_SPINLOCK(tmpv770x_rst_lock);
static const struct clk_parent_data clks_parent_data[] = {
{ .fw_name = "pipll1", .name = "pipll1", },
};
static const struct clk_parent_data pietherplls_parent_data[] = {
{ .fw_name = "pietherpll", .name = "pietherpll", },
};
static const struct visconti_fixed_clk fixed_clk_tables[] = {
/* PLL1 */
/* PICMPT0/1, PITSC, PIUWDT, PISWDT, PISBUS, PIPMU, PIGPMU, PITMU */
/* PIEMM, PIMISC, PIGCOMM, PIDCOMM, PIMBUS, PIGPIO, PIPGM */
{ TMPV770X_CLK_PIPLL1_DIV4, "pipll1_div4", "pipll1", 0, 1, 4, },
/* PISBUS */
{ TMPV770X_CLK_PIPLL1_DIV2, "pipll1_div2", "pipll1", 0, 1, 2, },
/* PICOBUS_CLK */
{ TMPV770X_CLK_PIPLL1_DIV1, "pipll1_div1", "pipll1", 0, 1, 1, },
/* PIDNNPLL */
/* CONN_CLK, PIMBUS, PICRC0/1 */
{ TMPV770X_CLK_PIDNNPLL_DIV1, "pidnnpll_div1", "pidnnpll", 0, 1, 1, },
{ TMPV770X_CLK_PIREFCLK, "pirefclk", "osc2-clk", 0, 1, 1, },
{ TMPV770X_CLK_WDTCLK, "wdtclk", "osc2-clk", 0, 1, 1, },
};
static const struct visconti_clk_gate_table pietherpll_clk_gate_tables[] = {
/* pietherpll */
{ TMPV770X_CLK_PIETHER_2P5M, "piether_2p5m",
pietherplls_parent_data, ARRAY_SIZE(pietherplls_parent_data),
CLK_SET_RATE_PARENT, 0x34, 0x134, 4, 200,
TMPV770X_RESET_PIETHER_2P5M, },
{ TMPV770X_CLK_PIETHER_25M, "piether_25m",
pietherplls_parent_data, ARRAY_SIZE(pietherplls_parent_data),
CLK_SET_RATE_PARENT, 0x34, 0x134, 5, 20,
TMPV770X_RESET_PIETHER_25M, },
{ TMPV770X_CLK_PIETHER_50M, "piether_50m",
pietherplls_parent_data, ARRAY_SIZE(pietherplls_parent_data),
CLK_SET_RATE_PARENT, 0x34, 0x134, 6, 10,
TMPV770X_RESET_PIETHER_50M, },
{ TMPV770X_CLK_PIETHER_125M, "piether_125m",
pietherplls_parent_data, ARRAY_SIZE(pietherplls_parent_data),
CLK_SET_RATE_PARENT, 0x34, 0x134, 7, 4,
TMPV770X_RESET_PIETHER_125M, },
};
static const struct visconti_clk_gate_table clk_gate_tables[] = {
{ TMPV770X_CLK_HOX, "hox",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x4c, 0x14c, 0, 1,
TMPV770X_RESET_HOX, },
{ TMPV770X_CLK_PCIE_MSTR, "pcie_mstr",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x38, 0x138, 0, 1,
TMPV770X_RESET_PCIE_MSTR, },
{ TMPV770X_CLK_PCIE_AUX, "pcie_aux",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x38, 0x138, 1, 24,
TMPV770X_RESET_PCIE_AUX, },
{ TMPV770X_CLK_PIINTC, "piintc",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
CLK_IGNORE_UNUSED, 0x8, 0x108, 0, 2, //FIX!!
TMPV770X_RESET_PIINTC,},
{ TMPV770X_CLK_PIETHER_BUS, "piether_bus",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x34, 0x134, 0, 2,
TMPV770X_RESET_PIETHER_BUS, }, /* BUS_CLK */
{ TMPV770X_CLK_PISPI0, "pispi0",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 0, 2,
TMPV770X_RESET_PISPI0, },
{ TMPV770X_CLK_PISPI1, "pispi1",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 1, 2,
TMPV770X_RESET_PISPI1, },
{ TMPV770X_CLK_PISPI2, "pispi2",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 2, 2,
TMPV770X_RESET_PISPI2, },
{ TMPV770X_CLK_PISPI3, "pispi3",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 3, 2,
TMPV770X_RESET_PISPI3,},
{ TMPV770X_CLK_PISPI4, "pispi4",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 4, 2,
TMPV770X_RESET_PISPI4, },
{ TMPV770X_CLK_PISPI5, "pispi5",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 5, 2,
TMPV770X_RESET_PISPI5},
{ TMPV770X_CLK_PISPI6, "pispi6",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x28, 0x128, 6, 2,
TMPV770X_RESET_PISPI6,},
{ TMPV770X_CLK_PIUART0, "piuart0",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
//CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2c, 0x12c, 0, 4,
0, 0x2c, 0x12c, 0, 4,
TMPV770X_RESET_PIUART0,},
{ TMPV770X_CLK_PIUART1, "piuart1",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
//CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2c, 0x12c, 1, 4,
0, 0x2c, 0x12c, 1, 4,
TMPV770X_RESET_PIUART1, },
{ TMPV770X_CLK_PIUART2, "piuart2",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x2c, 0x12c, 2, 4,
TMPV770X_RESET_PIUART2, },
{ TMPV770X_CLK_PIUART3, "piuart3",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x2c, 0x12c, 3, 4,
TMPV770X_RESET_PIUART3, },
{ TMPV770X_CLK_PII2C0, "pii2c0",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 0, 4,
TMPV770X_RESET_PII2C0, },
{ TMPV770X_CLK_PII2C1, "pii2c1",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 1, 4,
TMPV770X_RESET_PII2C1, },
{ TMPV770X_CLK_PII2C2, "pii2c2",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 2, 4,
TMPV770X_RESET_PII2C2, },
{ TMPV770X_CLK_PII2C3, "pii2c3",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 3, 4,
TMPV770X_RESET_PII2C3,},
{ TMPV770X_CLK_PII2C4, "pii2c4",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 4, 4,
TMPV770X_RESET_PII2C4, },
{ TMPV770X_CLK_PII2C5, "pii2c5",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 5, 4,
TMPV770X_RESET_PII2C5, },
{ TMPV770X_CLK_PII2C6, "pii2c6",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 6, 4,
TMPV770X_RESET_PII2C6, },
{ TMPV770X_CLK_PII2C7, "pii2c7",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 7, 4,
TMPV770X_RESET_PII2C7, },
{ TMPV770X_CLK_PII2C8, "pii2c8",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x30, 0x130, 8, 4,
TMPV770X_RESET_PII2C8, },
/* PIPCMIF */
{ TMPV770X_CLK_PIPCMIF, "pipcmif",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x64, 0x164, 0, 4,
TMPV770X_RESET_PIPCMIF, },
/* PISYSTEM */
{ TMPV770X_CLK_WRCK, "wrck",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x68, 0x168, 9, 32,
-1, }, /* No reset */
{ TMPV770X_CLK_PICKMON, "pickmon",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x10, 0x110, 8, 4,
TMPV770X_RESET_PICKMON, },
{ TMPV770X_CLK_SBUSCLK, "sbusclk",
clks_parent_data, ARRAY_SIZE(clks_parent_data),
0, 0x14, 0x114, 0, 4,
TMPV770X_RESET_SBUSCLK, },
};
static const struct visconti_reset_data clk_reset_data[] = {
[TMPV770X_RESET_PIETHER_2P5M] = { 0x434, 0x534, 4, },
[TMPV770X_RESET_PIETHER_25M] = { 0x434, 0x534, 5, },
[TMPV770X_RESET_PIETHER_50M] = { 0x434, 0x534, 6, },
[TMPV770X_RESET_PIETHER_125M] = { 0x434, 0x534, 7, },
[TMPV770X_RESET_HOX] = { 0x44c, 0x54c, 0, },
[TMPV770X_RESET_PCIE_MSTR] = { 0x438, 0x538, 0, },
[TMPV770X_RESET_PCIE_AUX] = { 0x438, 0x538, 1, },
[TMPV770X_RESET_PIINTC] = { 0x408, 0x508, 0, },
[TMPV770X_RESET_PIETHER_BUS] = { 0x434, 0x534, 0, },
[TMPV770X_RESET_PISPI0] = { 0x428, 0x528, 0, },
[TMPV770X_RESET_PISPI1] = { 0x428, 0x528, 1, },
[TMPV770X_RESET_PISPI2] = { 0x428, 0x528, 2, },
[TMPV770X_RESET_PISPI3] = { 0x428, 0x528, 3, },
[TMPV770X_RESET_PISPI4] = { 0x428, 0x528, 4, },
[TMPV770X_RESET_PISPI5] = { 0x428, 0x528, 5, },
[TMPV770X_RESET_PISPI6] = { 0x428, 0x528, 6, },
[TMPV770X_RESET_PIUART0] = { 0x42c, 0x52c, 0, },
[TMPV770X_RESET_PIUART1] = { 0x42c, 0x52c, 1, },
[TMPV770X_RESET_PIUART2] = { 0x42c, 0x52c, 2, },
[TMPV770X_RESET_PIUART3] = { 0x42c, 0x52c, 3, },
[TMPV770X_RESET_PII2C0] = { 0x430, 0x530, 0, },
[TMPV770X_RESET_PII2C1] = { 0x430, 0x530, 1, },
[TMPV770X_RESET_PII2C2] = { 0x430, 0x530, 2, },
[TMPV770X_RESET_PII2C3] = { 0x430, 0x530, 3, },
[TMPV770X_RESET_PII2C4] = { 0x430, 0x530, 4, },
[TMPV770X_RESET_PII2C5] = { 0x430, 0x530, 5, },
[TMPV770X_RESET_PII2C6] = { 0x430, 0x530, 6, },
[TMPV770X_RESET_PII2C7] = { 0x430, 0x530, 7, },
[TMPV770X_RESET_PII2C8] = { 0x430, 0x530, 8, },
[TMPV770X_RESET_PIPCMIF] = { 0x464, 0x564, 0, },
[TMPV770X_RESET_PICKMON] = { 0x410, 0x510, 8, },
[TMPV770X_RESET_SBUSCLK] = { 0x414, 0x514, 0, },
};
static int visconti_clk_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct visconti_clk_provider *ctx;
struct device *dev = &pdev->dev;
struct regmap *regmap;
int ret, i;
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
ctx = visconti_init_clk(dev, regmap, TMPV770X_NR_CLK);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ret = visconti_register_reset_controller(dev, regmap, clk_reset_data,
TMPV770X_NR_RESET,
&visconti_reset_ops,
&tmpv770x_rst_lock);
if (ret) {
dev_err(dev, "Failed to register reset controller: %d\n", ret);
return ret;
}
for (i = 0; i < (ARRAY_SIZE(fixed_clk_tables)); i++)
ctx->clk_data.hws[fixed_clk_tables[i].id] =
clk_hw_register_fixed_factor(NULL,
fixed_clk_tables[i].name,
fixed_clk_tables[i].parent,
fixed_clk_tables[i].flag,
fixed_clk_tables[i].mult,
fixed_clk_tables[i].div);
ret = visconti_clk_register_gates(ctx, clk_gate_tables,
ARRAY_SIZE(clk_gate_tables), clk_reset_data,
&tmpv770x_clk_lock);
if (ret) {
dev_err(dev, "Failed to register main clock gate: %d\n", ret);
return ret;
}
ret = visconti_clk_register_gates(ctx, pietherpll_clk_gate_tables,
ARRAY_SIZE(pietherpll_clk_gate_tables),
clk_reset_data, &tmpv770x_clk_lock);
if (ret) {
dev_err(dev, "Failed to register pietherpll clock gate: %d\n", ret);
return ret;
}
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &ctx->clk_data);
}
static const struct of_device_id visconti_clk_ids[] = {
{ .compatible = "toshiba,tmpv7708-pismu", },
{ }
};
static struct platform_driver visconti_clk_driver = {
.probe = visconti_clk_probe,
.driver = {
.name = "visconti-clk",
.of_match_table = visconti_clk_ids,
},
};
builtin_platform_driver(visconti_clk_driver);

206
drivers/clk/visconti/clkc.c Normal file
View File

@ -0,0 +1,206 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba Visconti clock controller
*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "clkc.h"
static inline struct visconti_clk_gate *to_visconti_clk_gate(struct clk_hw *hw)
{
return container_of(hw, struct visconti_clk_gate, hw);
}
static int visconti_gate_clk_is_enabled(struct clk_hw *hw)
{
struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
u32 clk = BIT(gate->ck_idx);
u32 val;
regmap_read(gate->regmap, gate->ckon_offset, &val);
return (val & clk) ? 1 : 0;
}
static void visconti_gate_clk_disable(struct clk_hw *hw)
{
struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
u32 clk = BIT(gate->ck_idx);
unsigned long flags;
spin_lock_irqsave(gate->lock, flags);
if (!visconti_gate_clk_is_enabled(hw)) {
spin_unlock_irqrestore(gate->lock, flags);
return;
}
regmap_update_bits(gate->regmap, gate->ckoff_offset, clk, clk);
spin_unlock_irqrestore(gate->lock, flags);
}
static int visconti_gate_clk_enable(struct clk_hw *hw)
{
struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
u32 clk = BIT(gate->ck_idx);
unsigned long flags;
spin_lock_irqsave(gate->lock, flags);
regmap_update_bits(gate->regmap, gate->ckon_offset, clk, clk);
spin_unlock_irqrestore(gate->lock, flags);
return 0;
}
static const struct clk_ops visconti_clk_gate_ops = {
.enable = visconti_gate_clk_enable,
.disable = visconti_gate_clk_disable,
.is_enabled = visconti_gate_clk_is_enabled,
};
static struct clk_hw *visconti_clk_register_gate(struct device *dev,
const char *name,
const char *parent_name,
struct regmap *regmap,
const struct visconti_clk_gate_table *clks,
u32 rson_offset,
u32 rsoff_offset,
u8 rs_idx,
spinlock_t *lock)
{
struct visconti_clk_gate *gate;
struct clk_parent_data *pdata;
struct clk_init_data init;
struct clk_hw *hw;
int ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->name = pdata->fw_name = parent_name;
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
if (!gate)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &visconti_clk_gate_ops;
init.flags = clks->flags;
init.parent_data = pdata;
init.num_parents = 1;
gate->regmap = regmap;
gate->ckon_offset = clks->ckon_offset;
gate->ckoff_offset = clks->ckoff_offset;
gate->ck_idx = clks->ck_idx;
gate->rson_offset = rson_offset;
gate->rsoff_offset = rsoff_offset;
gate->rs_idx = rs_idx;
gate->lock = lock;
gate->hw.init = &init;
hw = &gate->hw;
ret = devm_clk_hw_register(dev, hw);
if (ret)
hw = ERR_PTR(ret);
return hw;
}
int visconti_clk_register_gates(struct visconti_clk_provider *ctx,
const struct visconti_clk_gate_table *clks,
int num_gate,
const struct visconti_reset_data *reset,
spinlock_t *lock)
{
struct device *dev = ctx->dev;
int i;
for (i = 0; i < num_gate; i++) {
const char *parent_div_name = clks[i].parent_data[0].name;
struct clk_parent_data *pdata;
u32 rson_offset, rsoff_offset;
struct clk_hw *gate_clk;
struct clk_hw *div_clk;
char *dev_name;
u8 rs_idx;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s_div", clks[i].name);
if (!dev_name)
return -ENOMEM;
if (clks[i].rs_id >= 0) {
rson_offset = reset[clks[i].rs_id].rson_offset;
rsoff_offset = reset[clks[i].rs_id].rsoff_offset;
rs_idx = reset[clks[i].rs_id].rs_idx;
} else {
rson_offset = rsoff_offset = rs_idx = -1;
}
div_clk = devm_clk_hw_register_fixed_factor(dev,
dev_name,
parent_div_name,
0, 1,
clks[i].div);
if (IS_ERR(div_clk))
return PTR_ERR(div_clk);
gate_clk = visconti_clk_register_gate(dev,
clks[i].name,
dev_name,
ctx->regmap,
&clks[i],
rson_offset,
rsoff_offset,
rs_idx,
lock);
if (IS_ERR(gate_clk)) {
dev_err(dev, "%s: failed to register clock %s\n",
__func__, clks[i].name);
return PTR_ERR(gate_clk);
}
ctx->clk_data.hws[clks[i].id] = gate_clk;
}
return 0;
}
struct visconti_clk_provider *visconti_init_clk(struct device *dev,
struct regmap *regmap,
unsigned long nr_clks)
{
struct visconti_clk_provider *ctx;
int i;
ctx = devm_kzalloc(dev, struct_size(ctx, clk_data.hws, nr_clks), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_clks; ++i)
ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
ctx->clk_data.num = nr_clks;
ctx->dev = dev;
ctx->regmap = regmap;
return ctx;
}

View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Toshiba Visconti clock controller
*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#ifndef _VISCONTI_CLKC_H_
#define _VISCONTI_CLKC_H_
#include <linux/mfd/syscon.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include "reset.h"
struct visconti_clk_provider {
struct device *dev;
struct regmap *regmap;
struct clk_hw_onecell_data clk_data;
};
struct visconti_clk_gate_table {
unsigned int id;
const char *name;
const struct clk_parent_data *parent_data;
u8 num_parents;
u8 flags;
u32 ckon_offset;
u32 ckoff_offset;
u8 ck_idx;
unsigned int div;
u8 rs_id;
};
struct visconti_fixed_clk {
unsigned int id;
const char *name;
const char *parent;
unsigned long flag;
unsigned int mult;
unsigned int div;
};
struct visconti_clk_gate {
struct clk_hw hw;
struct regmap *regmap;
u32 ckon_offset;
u32 ckoff_offset;
u8 ck_idx;
u8 flags;
u32 rson_offset;
u32 rsoff_offset;
u8 rs_idx;
spinlock_t *lock;
};
struct visconti_clk_provider *visconti_init_clk(struct device *dev,
struct regmap *regmap,
unsigned long nr_clks);
int visconti_clk_register_gates(struct visconti_clk_provider *data,
const struct visconti_clk_gate_table *clks,
int num_gate,
const struct visconti_reset_data *reset,
spinlock_t *lock);
#endif /* _VISCONTI_CLKC_H_ */

View File

@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba Visconti PLL controller
*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <dt-bindings/clock/toshiba,tmpv770x.h>
#include "pll.h"
static DEFINE_SPINLOCK(tmpv770x_pll_lock);
static const struct visconti_pll_rate_table pipll0_rates[] __initconst = {
VISCONTI_PLL_RATE(840000000, 0x1, 0x0, 0x1, 0x54, 0x000000, 0x2, 0x1),
VISCONTI_PLL_RATE(780000000, 0x1, 0x0, 0x1, 0x4e, 0x000000, 0x2, 0x1),
VISCONTI_PLL_RATE(600000000, 0x1, 0x0, 0x1, 0x3c, 0x000000, 0x2, 0x1),
{ /* sentinel */ },
};
static const struct visconti_pll_rate_table piddrcpll_rates[] __initconst = {
VISCONTI_PLL_RATE(780000000, 0x1, 0x0, 0x1, 0x4e, 0x000000, 0x2, 0x1),
VISCONTI_PLL_RATE(760000000, 0x1, 0x0, 0x1, 0x4c, 0x000000, 0x2, 0x1),
{ /* sentinel */ },
};
static const struct visconti_pll_rate_table pivoifpll_rates[] __initconst = {
VISCONTI_PLL_RATE(165000000, 0x1, 0x0, 0x1, 0x42, 0x000000, 0x4, 0x2),
VISCONTI_PLL_RATE(148500000, 0x1, 0x1, 0x1, 0x3b, 0x666666, 0x4, 0x2),
VISCONTI_PLL_RATE(96000000, 0x1, 0x0, 0x1, 0x30, 0x000000, 0x5, 0x2),
VISCONTI_PLL_RATE(74250000, 0x1, 0x1, 0x1, 0x3b, 0x666666, 0x4, 0x4),
VISCONTI_PLL_RATE(54000000, 0x1, 0x0, 0x1, 0x36, 0x000000, 0x5, 0x4),
VISCONTI_PLL_RATE(48000000, 0x1, 0x0, 0x1, 0x30, 0x000000, 0x5, 0x4),
VISCONTI_PLL_RATE(35750000, 0x1, 0x1, 0x1, 0x32, 0x0ccccc, 0x7, 0x4),
{ /* sentinel */ },
};
static const struct visconti_pll_rate_table piimgerpll_rates[] __initconst = {
VISCONTI_PLL_RATE(165000000, 0x1, 0x0, 0x1, 0x42, 0x000000, 0x4, 0x2),
VISCONTI_PLL_RATE(96000000, 0x1, 0x0, 0x1, 0x30, 0x000000, 0x5, 0x2),
VISCONTI_PLL_RATE(54000000, 0x1, 0x0, 0x1, 0x36, 0x000000, 0x5, 0x4),
VISCONTI_PLL_RATE(48000000, 0x1, 0x0, 0x1, 0x30, 0x000000, 0x5, 0x4),
{ /* sentinel */ },
};
static const struct visconti_pll_info pll_info[] __initconst = {
{ TMPV770X_PLL_PIPLL0, "pipll0", "osc2-clk", 0x0, pipll0_rates },
{ TMPV770X_PLL_PIDDRCPLL, "piddrcpll", "osc2-clk", 0x500, piddrcpll_rates },
{ TMPV770X_PLL_PIVOIFPLL, "pivoifpll", "osc2-clk", 0x600, pivoifpll_rates },
{ TMPV770X_PLL_PIIMGERPLL, "piimgerpll", "osc2-clk", 0x700, piimgerpll_rates },
};
static void __init tmpv770x_setup_plls(struct device_node *np)
{
struct visconti_pll_provider *ctx;
void __iomem *reg_base;
reg_base = of_iomap(np, 0);
if (!reg_base)
return;
ctx = visconti_init_pll(np, reg_base, TMPV770X_NR_PLL);
if (IS_ERR(ctx)) {
iounmap(reg_base);
return;
}
ctx->clk_data.hws[TMPV770X_PLL_PIPLL1] =
clk_hw_register_fixed_rate(NULL, "pipll1", NULL, 0, 600000000);
ctx->clk_data.hws[TMPV770X_PLL_PIDNNPLL] =
clk_hw_register_fixed_rate(NULL, "pidnnpll", NULL, 0, 500000000);
ctx->clk_data.hws[TMPV770X_PLL_PIETHERPLL] =
clk_hw_register_fixed_rate(NULL, "pietherpll", NULL, 0, 500000000);
visconti_register_plls(ctx, pll_info, ARRAY_SIZE(pll_info), &tmpv770x_pll_lock);
}
CLK_OF_DECLARE(tmpv770x_plls, "toshiba,tmpv7708-pipllct", tmpv770x_setup_plls);

340
drivers/clk/visconti/pll.c Normal file
View File

@ -0,0 +1,340 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba Visconti PLL driver
*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "pll.h"
struct visconti_pll {
struct clk_hw hw;
void __iomem *pll_base;
spinlock_t *lock;
unsigned long flags;
const struct visconti_pll_rate_table *rate_table;
size_t rate_count;
struct visconti_pll_provider *ctx;
};
#define PLL_CONF_REG 0x0000
#define PLL_CTRL_REG 0x0004
#define PLL_FRACMODE_REG 0x0010
#define PLL_INTIN_REG 0x0014
#define PLL_FRACIN_REG 0x0018
#define PLL_REFDIV_REG 0x001c
#define PLL_POSTDIV_REG 0x0020
#define PLL_CONFIG_SEL BIT(0)
#define PLL_PLLEN BIT(4)
#define PLL_BYPASS BIT(16)
#define PLL_INTIN_MASK GENMASK(11, 0)
#define PLL_FRACIN_MASK GENMASK(23, 0)
#define PLL_REFDIV_MASK GENMASK(5, 0)
#define PLL_POSTDIV_MASK GENMASK(2, 0)
#define PLL0_FRACMODE_DACEN BIT(4)
#define PLL0_FRACMODE_DSMEN BIT(0)
#define PLL_CREATE_FRACMODE(table) (table->dacen << 4 | table->dsmen)
#define PLL_CREATE_OSTDIV(table) (table->postdiv2 << 4 | table->postdiv1)
static inline struct visconti_pll *to_visconti_pll(struct clk_hw *hw)
{
return container_of(hw, struct visconti_pll, hw);
}
static void visconti_pll_get_params(struct visconti_pll *pll,
struct visconti_pll_rate_table *rate_table)
{
u32 postdiv, val;
val = readl(pll->pll_base + PLL_FRACMODE_REG);
rate_table->dacen = FIELD_GET(PLL0_FRACMODE_DACEN, val);
rate_table->dsmen = FIELD_GET(PLL0_FRACMODE_DSMEN, val);
rate_table->fracin = readl(pll->pll_base + PLL_FRACIN_REG) & PLL_FRACIN_MASK;
rate_table->intin = readl(pll->pll_base + PLL_INTIN_REG) & PLL_INTIN_MASK;
rate_table->refdiv = readl(pll->pll_base + PLL_REFDIV_REG) & PLL_REFDIV_MASK;
postdiv = readl(pll->pll_base + PLL_POSTDIV_REG);
rate_table->postdiv1 = postdiv & PLL_POSTDIV_MASK;
rate_table->postdiv2 = (postdiv >> 4) & PLL_POSTDIV_MASK;
}
static const struct visconti_pll_rate_table *visconti_get_pll_settings(struct visconti_pll *pll,
unsigned long rate)
{
const struct visconti_pll_rate_table *rate_table = pll->rate_table;
int i;
for (i = 0; i < pll->rate_count; i++)
if (rate == rate_table[i].rate)
return &rate_table[i];
return NULL;
}
static unsigned long visconti_get_pll_rate_from_data(struct visconti_pll *pll,
const struct visconti_pll_rate_table *rate)
{
const struct visconti_pll_rate_table *rate_table = pll->rate_table;
int i;
for (i = 0; i < pll->rate_count; i++)
if (memcmp(&rate_table[i].dacen, &rate->dacen,
sizeof(*rate) - sizeof(unsigned long)) == 0)
return rate_table[i].rate;
/* set default */
return rate_table[0].rate;
}
static long visconti_pll_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *prate)
{
struct visconti_pll *pll = to_visconti_pll(hw);
const struct visconti_pll_rate_table *rate_table = pll->rate_table;
int i;
/* Assumming rate_table is in descending order */
for (i = 0; i < pll->rate_count; i++)
if (rate >= rate_table[i].rate)
return rate_table[i].rate;
/* return minimum supported value */
return rate_table[i - 1].rate;
}
static unsigned long visconti_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct visconti_pll *pll = to_visconti_pll(hw);
struct visconti_pll_rate_table rate_table;
memset(&rate_table, 0, sizeof(rate_table));
visconti_pll_get_params(pll, &rate_table);
return visconti_get_pll_rate_from_data(pll, &rate_table);
}
static int visconti_pll_set_params(struct visconti_pll *pll,
const struct visconti_pll_rate_table *rate_table)
{
writel(PLL_CREATE_FRACMODE(rate_table), pll->pll_base + PLL_FRACMODE_REG);
writel(PLL_CREATE_OSTDIV(rate_table), pll->pll_base + PLL_POSTDIV_REG);
writel(rate_table->intin, pll->pll_base + PLL_INTIN_REG);
writel(rate_table->fracin, pll->pll_base + PLL_FRACIN_REG);
writel(rate_table->refdiv, pll->pll_base + PLL_REFDIV_REG);
return 0;
}
static int visconti_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct visconti_pll *pll = to_visconti_pll(hw);
const struct visconti_pll_rate_table *rate_table;
rate_table = visconti_get_pll_settings(pll, rate);
if (!rate_table)
return -EINVAL;
return visconti_pll_set_params(pll, rate_table);
}
static int visconti_pll_is_enabled(struct clk_hw *hw)
{
struct visconti_pll *pll = to_visconti_pll(hw);
u32 reg;
reg = readl(pll->pll_base + PLL_CTRL_REG);
return (reg & PLL_PLLEN);
}
static int visconti_pll_enable(struct clk_hw *hw)
{
struct visconti_pll *pll = to_visconti_pll(hw);
const struct visconti_pll_rate_table *rate_table = pll->rate_table;
unsigned long flags;
u32 reg;
if (visconti_pll_is_enabled(hw))
return 0;
spin_lock_irqsave(pll->lock, flags);
writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG);
reg = readl(pll->pll_base + PLL_CTRL_REG);
reg |= PLL_BYPASS;
writel(reg, pll->pll_base + PLL_CTRL_REG);
visconti_pll_set_params(pll, &rate_table[0]);
reg = readl(pll->pll_base + PLL_CTRL_REG);
reg &= ~PLL_PLLEN;
writel(reg, pll->pll_base + PLL_CTRL_REG);
udelay(1);
reg = readl(pll->pll_base + PLL_CTRL_REG);
reg |= PLL_PLLEN;
writel(reg, pll->pll_base + PLL_CTRL_REG);
udelay(40);
reg = readl(pll->pll_base + PLL_CTRL_REG);
reg &= ~PLL_BYPASS;
writel(reg, pll->pll_base + PLL_CTRL_REG);
spin_unlock_irqrestore(pll->lock, flags);
return 0;
}
static void visconti_pll_disable(struct clk_hw *hw)
{
struct visconti_pll *pll = to_visconti_pll(hw);
unsigned long flags;
u32 reg;
if (!visconti_pll_is_enabled(hw))
return;
spin_lock_irqsave(pll->lock, flags);
writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG);
reg = readl(pll->pll_base + PLL_CTRL_REG);
reg |= PLL_BYPASS;
writel(reg, pll->pll_base + PLL_CTRL_REG);
reg = readl(pll->pll_base + PLL_CTRL_REG);
reg &= ~PLL_PLLEN;
writel(reg, pll->pll_base + PLL_CTRL_REG);
spin_unlock_irqrestore(pll->lock, flags);
}
static const struct clk_ops visconti_pll_ops = {
.enable = visconti_pll_enable,
.disable = visconti_pll_disable,
.is_enabled = visconti_pll_is_enabled,
.round_rate = visconti_pll_round_rate,
.recalc_rate = visconti_pll_recalc_rate,
.set_rate = visconti_pll_set_rate,
};
static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
const char *name,
const char *parent_name,
int offset,
const struct visconti_pll_rate_table *rate_table,
spinlock_t *lock)
{
struct clk_init_data init;
struct visconti_pll *pll;
struct clk *pll_clk;
struct clk_hw *pll_hw_clk;
size_t len;
int ret;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = CLK_IGNORE_UNUSED;
init.parent_names = &parent_name;
init.num_parents = 1;
for (len = 0; rate_table[len].rate != 0; )
len++;
pll->rate_count = len;
pll->rate_table = kmemdup(rate_table,
pll->rate_count * sizeof(struct visconti_pll_rate_table),
GFP_KERNEL);
WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, name);
init.ops = &visconti_pll_ops;
pll->hw.init = &init;
pll->pll_base = ctx->reg_base + offset;
pll->lock = lock;
pll->ctx = ctx;
pll_hw_clk = &pll->hw;
ret = clk_hw_register(NULL, &pll->hw);
if (ret) {
pr_err("failed to register pll clock %s : %ld\n", name, PTR_ERR(pll_clk));
kfree(pll);
pll_hw_clk = ERR_PTR(ret);
}
return pll_hw_clk;
}
static void visconti_pll_add_lookup(struct visconti_pll_provider *ctx,
struct clk_hw *hw_clk,
unsigned int id)
{
if (id)
ctx->clk_data.hws[id] = hw_clk;
}
void __init visconti_register_plls(struct visconti_pll_provider *ctx,
const struct visconti_pll_info *list,
unsigned int nr_plls,
spinlock_t *lock)
{
int idx;
for (idx = 0; idx < nr_plls; idx++, list++) {
struct clk_hw *clk;
clk = visconti_register_pll(ctx,
list->name,
list->parent,
list->base_reg,
list->rate_table,
lock);
if (IS_ERR(clk)) {
pr_err("failed to register clock %s\n", list->name);
continue;
}
visconti_pll_add_lookup(ctx, clk, list->id);
}
}
struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np,
void __iomem *base,
unsigned long nr_plls)
{
struct visconti_pll_provider *ctx;
int i;
ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_plls), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_plls; ++i)
ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
ctx->node = np;
ctx->reg_base = base;
ctx->clk_data.num = nr_plls;
return ctx;
}

View File

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#ifndef _VISCONTI_PLL_H_
#define _VISCONTI_PLL_H_
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
struct visconti_pll_provider {
void __iomem *reg_base;
struct regmap *regmap;
struct clk_hw_onecell_data clk_data;
struct device_node *node;
};
#define VISCONTI_PLL_RATE(_rate, _dacen, _dsmen, \
_refdiv, _intin, _fracin, _postdiv1, _postdiv2) \
{ \
.rate = _rate, \
.dacen = _dacen, \
.dsmen = _dsmen, \
.refdiv = _refdiv, \
.intin = _intin, \
.fracin = _fracin, \
.postdiv1 = _postdiv1, \
.postdiv2 = _postdiv2 \
}
struct visconti_pll_rate_table {
unsigned long rate;
unsigned int dacen;
unsigned int dsmen;
unsigned int refdiv;
unsigned long intin;
unsigned long fracin;
unsigned int postdiv1;
unsigned int postdiv2;
};
struct visconti_pll_info {
unsigned int id;
const char *name;
const char *parent;
unsigned long base_reg;
const struct visconti_pll_rate_table *rate_table;
};
struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np,
void __iomem *base,
unsigned long nr_plls);
void visconti_register_plls(struct visconti_pll_provider *ctx,
const struct visconti_pll_info *list,
unsigned int nr_plls, spinlock_t *lock);
#endif /* _VISCONTI_PLL_H_ */

View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba Visconti ARM SoC reset controller
*
* Copyright (c) 2021 TOSHIBA CORPORATION
* Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include "reset.h"
static inline struct visconti_reset *to_visconti_reset(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct visconti_reset, rcdev);
}
static int visconti_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
struct visconti_reset *reset = to_visconti_reset(rcdev);
const struct visconti_reset_data *data = &reset->resets[id];
u32 rst = BIT(data->rs_idx);
unsigned long flags;
int ret;
spin_lock_irqsave(reset->lock, flags);
ret = regmap_update_bits(reset->regmap, data->rson_offset, rst, rst);
spin_unlock_irqrestore(reset->lock, flags);
return ret;
}
static int visconti_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
struct visconti_reset *reset = to_visconti_reset(rcdev);
const struct visconti_reset_data *data = &reset->resets[id];
u32 rst = BIT(data->rs_idx);
unsigned long flags;
int ret;
spin_lock_irqsave(reset->lock, flags);
ret = regmap_update_bits(reset->regmap, data->rsoff_offset, rst, rst);
spin_unlock_irqrestore(reset->lock, flags);
return ret;
}
static int visconti_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
{
visconti_reset_assert(rcdev, id);
udelay(1);
visconti_reset_deassert(rcdev, id);
return 0;
}
static int visconti_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
{
struct visconti_reset *reset = to_visconti_reset(rcdev);
const struct visconti_reset_data *data = &reset->resets[id];
unsigned long flags;
u32 reg;
int ret;
spin_lock_irqsave(reset->lock, flags);
ret = regmap_read(reset->regmap, data->rson_offset, &reg);
spin_unlock_irqrestore(reset->lock, flags);
if (ret)
return ret;
return !(reg & data->rs_idx);
}
const struct reset_control_ops visconti_reset_ops = {
.assert = visconti_reset_assert,
.deassert = visconti_reset_deassert,
.reset = visconti_reset_reset,
.status = visconti_reset_status,
};
int visconti_register_reset_controller(struct device *dev,
struct regmap *regmap,
const struct visconti_reset_data *resets,
unsigned int num_resets,
const struct reset_control_ops *reset_ops,
spinlock_t *lock)
{
struct visconti_reset *reset;
reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
if (!reset)
return -ENOMEM;
reset->regmap = regmap;
reset->resets = resets;
reset->rcdev.ops = reset_ops;
reset->rcdev.nr_resets = num_resets;
reset->rcdev.of_node = dev->of_node;
reset->lock = lock;
return devm_reset_controller_register(dev, &reset->rcdev);
}

View File

@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Toshiba ARM SoC reset controller driver
*
* Copyright (c) 2021 TOSHIBA CORPORATION
*
* Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
*/
#ifndef _VISCONTI_RESET_H_
#define _VISCONTI_RESET_H_
#include <linux/reset-controller.h>
struct visconti_reset_data {
u32 rson_offset;
u32 rsoff_offset;
u8 rs_idx;
};
struct visconti_reset {
struct reset_controller_dev rcdev;
struct regmap *regmap;
const struct visconti_reset_data *resets;
spinlock_t *lock;
};
extern const struct reset_control_ops visconti_reset_ops;
int visconti_register_reset_controller(struct device *dev,
struct regmap *regmap,
const struct visconti_reset_data *resets,
unsigned int num_resets,
const struct reset_control_ops *reset_ops,
spinlock_t *lock);
#endif /* _VISCONTI_RESET_H_ */

View File

@ -0,0 +1,181 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
#ifndef _DT_BINDINGS_CLOCK_TOSHIBA_TMPV770X_H_
#define _DT_BINDINGS_CLOCK_TOSHIBA_TMPV770X_H_
/* PLL */
#define TMPV770X_PLL_PIPLL0 0
#define TMPV770X_PLL_PIPLL1 1
#define TMPV770X_PLL_PIDNNPLL 2
#define TMPV770X_PLL_PIETHERPLL 3
#define TMPV770X_PLL_PIDDRCPLL 4
#define TMPV770X_PLL_PIVOIFPLL 5
#define TMPV770X_PLL_PIIMGERPLL 6
#define TMPV770X_NR_PLL 7
/* Clocks */
#define TMPV770X_CLK_PIPLL1_DIV1 0
#define TMPV770X_CLK_PIPLL1_DIV2 1
#define TMPV770X_CLK_PIPLL1_DIV4 2
#define TMPV770X_CLK_PIDNNPLL_DIV1 3
#define TMPV770X_CLK_DDRC_PHY_PLL0 4
#define TMPV770X_CLK_DDRC_PHY_PLL1 5
#define TMPV770X_CLK_D_PHYPLL 6
#define TMPV770X_CLK_PHY_PCIEPLL 7
#define TMPV770X_CLK_CA53CL0 8
#define TMPV770X_CLK_CA53CL1 9
#define TMPV770X_CLK_PISDMAC 10
#define TMPV770X_CLK_PIPDMAC0 11
#define TMPV770X_CLK_PIPDMAC1 12
#define TMPV770X_CLK_PIWRAM 13
#define TMPV770X_CLK_DDRC0 14
#define TMPV770X_CLK_DDRC0_SCLK 15
#define TMPV770X_CLK_DDRC0_NCLK 16
#define TMPV770X_CLK_DDRC0_MCLK 17
#define TMPV770X_CLK_DDRC0_APBCLK 18
#define TMPV770X_CLK_DDRC1 19
#define TMPV770X_CLK_DDRC1_SCLK 20
#define TMPV770X_CLK_DDRC1_NCLK 21
#define TMPV770X_CLK_DDRC1_MCLK 22
#define TMPV770X_CLK_DDRC1_APBCLK 23
#define TMPV770X_CLK_HOX 24
#define TMPV770X_CLK_PCIE_MSTR 25
#define TMPV770X_CLK_PCIE_AUX 26
#define TMPV770X_CLK_PIINTC 27
#define TMPV770X_CLK_PIETHER_BUS 28
#define TMPV770X_CLK_PISPI0 29
#define TMPV770X_CLK_PISPI1 30
#define TMPV770X_CLK_PISPI2 31
#define TMPV770X_CLK_PISPI3 32
#define TMPV770X_CLK_PISPI4 33
#define TMPV770X_CLK_PISPI5 34
#define TMPV770X_CLK_PISPI6 35
#define TMPV770X_CLK_PIUART0 36
#define TMPV770X_CLK_PIUART1 37
#define TMPV770X_CLK_PIUART2 38
#define TMPV770X_CLK_PIUART3 39
#define TMPV770X_CLK_PII2C0 40
#define TMPV770X_CLK_PII2C1 41
#define TMPV770X_CLK_PII2C2 42
#define TMPV770X_CLK_PII2C3 43
#define TMPV770X_CLK_PII2C4 44
#define TMPV770X_CLK_PII2C5 45
#define TMPV770X_CLK_PII2C6 46
#define TMPV770X_CLK_PII2C7 47
#define TMPV770X_CLK_PII2C8 48
#define TMPV770X_CLK_PIGPIO 49
#define TMPV770X_CLK_PIPGM 50
#define TMPV770X_CLK_PIPCMIF 51
#define TMPV770X_CLK_PIPCMIF_AUDIO_O 52
#define TMPV770X_CLK_PIPCMIF_AUDIO_I 53
#define TMPV770X_CLK_PICMPT0 54
#define TMPV770X_CLK_PICMPT1 55
#define TMPV770X_CLK_PITSC 56
#define TMPV770X_CLK_PIUWDT 57
#define TMPV770X_CLK_PISWDT 58
#define TMPV770X_CLK_WDTCLK 59
#define TMPV770X_CLK_PISUBUS_150M 60
#define TMPV770X_CLK_PISUBUS_300M 61
#define TMPV770X_CLK_PIPMU 62
#define TMPV770X_CLK_PIGPMU 63
#define TMPV770X_CLK_PITMU 64
#define TMPV770X_CLK_WRCK 65
#define TMPV770X_CLK_PIEMM 66
#define TMPV770X_CLK_PIMISC 67
#define TMPV770X_CLK_PIGCOMM 68
#define TMPV770X_CLK_PIDCOMM 69
#define TMPV770X_CLK_PICKMON 70
#define TMPV770X_CLK_PIMBUS 71
#define TMPV770X_CLK_SBUSCLK 72
#define TMPV770X_CLK_DDR0_APBCLKCLK 73
#define TMPV770X_CLK_DDR1_APBCLKCLK 74
#define TMPV770X_CLK_DSP0_PBCLK 75
#define TMPV770X_CLK_DSP1_PBCLK 76
#define TMPV770X_CLK_DSP2_PBCLK 77
#define TMPV770X_CLK_DSP3_PBCLK 78
#define TMPV770X_CLK_DSVIIF0_APBCLK 79
#define TMPV770X_CLK_VIIF0_APBCLK 80
#define TMPV770X_CLK_VIIF0_CFGCLK 81
#define TMPV770X_CLK_VIIF1_APBCLK 82
#define TMPV770X_CLK_VIIF1_CFGCLK 83
#define TMPV770X_CLK_VIIF2_APBCLK 84
#define TMPV770X_CLK_VIIF2_CFGCLK 85
#define TMPV770X_CLK_VIIF3_APBCLK 86
#define TMPV770X_CLK_VIIF3_CFGCLK 87
#define TMPV770X_CLK_VIIF4_APBCLK 88
#define TMPV770X_CLK_VIIF4_CFGCLK 89
#define TMPV770X_CLK_VIIF5_APBCLK 90
#define TMPV770X_CLK_VIIF5_CFGCLK 91
#define TMPV770X_CLK_VOIF_SBUSCLK 92
#define TMPV770X_CLK_VOIF_PROCCLK 93
#define TMPV770X_CLK_VOIF_DPHYCFGCLK 94
#define TMPV770X_CLK_DNN0 95
#define TMPV770X_CLK_STMAT 96
#define TMPV770X_CLK_HWA0 97
#define TMPV770X_CLK_AFFINE0 98
#define TMPV770X_CLK_HAMAT 99
#define TMPV770X_CLK_SMLDB 100
#define TMPV770X_CLK_HWA0_ASYNC 101
#define TMPV770X_CLK_HWA2 102
#define TMPV770X_CLK_FLMAT 103
#define TMPV770X_CLK_PYRAMID 104
#define TMPV770X_CLK_HWA2_ASYNC 105
#define TMPV770X_CLK_DSP0 106
#define TMPV770X_CLK_VIIFBS0 107
#define TMPV770X_CLK_VIIFBS0_L2ISP 108
#define TMPV770X_CLK_VIIFBS0_L1ISP 109
#define TMPV770X_CLK_VIIFBS0_PROC 110
#define TMPV770X_CLK_VIIFBS1 111
#define TMPV770X_CLK_VIIFBS2 112
#define TMPV770X_CLK_VIIFOP_MBUS 113
#define TMPV770X_CLK_VIIFOP0_PROC 114
#define TMPV770X_CLK_PIETHER_2P5M 115
#define TMPV770X_CLK_PIETHER_25M 116
#define TMPV770X_CLK_PIETHER_50M 117
#define TMPV770X_CLK_PIETHER_125M 118
#define TMPV770X_CLK_VOIF0_DPHYCFG 119
#define TMPV770X_CLK_VOIF0_PROC 120
#define TMPV770X_CLK_VOIF0_SBUS 121
#define TMPV770X_CLK_VOIF0_DSIREF 122
#define TMPV770X_CLK_VOIF0_PIXEL 123
#define TMPV770X_CLK_PIREFCLK 124
#define TMPV770X_CLK_SBUS 125
#define TMPV770X_CLK_BUSLCK 126
#define TMPV770X_NR_CLK 127
/* Reset */
#define TMPV770X_RESET_PIETHER_2P5M 0
#define TMPV770X_RESET_PIETHER_25M 1
#define TMPV770X_RESET_PIETHER_50M 2
#define TMPV770X_RESET_PIETHER_125M 3
#define TMPV770X_RESET_HOX 4
#define TMPV770X_RESET_PCIE_MSTR 5
#define TMPV770X_RESET_PCIE_AUX 6
#define TMPV770X_RESET_PIINTC 7
#define TMPV770X_RESET_PIETHER_BUS 8
#define TMPV770X_RESET_PISPI0 9
#define TMPV770X_RESET_PISPI1 10
#define TMPV770X_RESET_PISPI2 11
#define TMPV770X_RESET_PISPI3 12
#define TMPV770X_RESET_PISPI4 13
#define TMPV770X_RESET_PISPI5 14
#define TMPV770X_RESET_PISPI6 15
#define TMPV770X_RESET_PIUART0 16
#define TMPV770X_RESET_PIUART1 17
#define TMPV770X_RESET_PIUART2 18
#define TMPV770X_RESET_PIUART3 19
#define TMPV770X_RESET_PII2C0 20
#define TMPV770X_RESET_PII2C1 21
#define TMPV770X_RESET_PII2C2 22
#define TMPV770X_RESET_PII2C3 23
#define TMPV770X_RESET_PII2C4 24
#define TMPV770X_RESET_PII2C5 25
#define TMPV770X_RESET_PII2C6 26
#define TMPV770X_RESET_PII2C7 27
#define TMPV770X_RESET_PII2C8 28
#define TMPV770X_RESET_PIPCMIF 29
#define TMPV770X_RESET_PICKMON 30
#define TMPV770X_RESET_SBUSCLK 31
#define TMPV770X_NR_RESET 32
#endif /*_DT_BINDINGS_CLOCK_TOSHIBA_TMPV770X_H_ */

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
#ifndef _DT_BINDINGS_RESET_TOSHIBA_TMPV770X_H_
#define _DT_BINDINGS_RESET_TOSHIBA_TMPV770X_H_
/* Reset */
#define TMPV770X_RESET_PIETHER_2P5M 0
#define TMPV770X_RESET_PIETHER_25M 1
#define TMPV770X_RESET_PIETHER_50M 2
#define TMPV770X_RESET_PIETHER_125M 3
#define TMPV770X_RESET_HOX 4
#define TMPV770X_RESET_PCIE_MSTR 5
#define TMPV770X_RESET_PCIE_AUX 6
#define TMPV770X_RESET_PIINTC 7
#define TMPV770X_RESET_PIETHER_BUS 8
#define TMPV770X_RESET_PISPI0 9
#define TMPV770X_RESET_PISPI1 10
#define TMPV770X_RESET_PISPI2 11
#define TMPV770X_RESET_PISPI3 12
#define TMPV770X_RESET_PISPI4 13
#define TMPV770X_RESET_PISPI5 14
#define TMPV770X_RESET_PISPI6 15
#define TMPV770X_RESET_PIUART0 16
#define TMPV770X_RESET_PIUART1 17
#define TMPV770X_RESET_PIUART2 18
#define TMPV770X_RESET_PIUART3 19
#define TMPV770X_RESET_PII2C0 20
#define TMPV770X_RESET_PII2C1 21
#define TMPV770X_RESET_PII2C2 22
#define TMPV770X_RESET_PII2C3 23
#define TMPV770X_RESET_PII2C4 24
#define TMPV770X_RESET_PII2C5 25
#define TMPV770X_RESET_PII2C6 26
#define TMPV770X_RESET_PII2C7 27
#define TMPV770X_RESET_PII2C8 28
#define TMPV770X_RESET_PIPCMIF 29
#define TMPV770X_RESET_PICKMON 30
#define TMPV770X_RESET_SBUSCLK 31
#define TMPV770X_NR_RESET 32
#endif /*_DT_BINDINGS_RESET_TOSHIBA_TMPV770X_H_ */