Commit 270bbc72 authored by Stephen Boyd's avatar Stephen Boyd

Merge branches 'clk-doc', 'clk-renesas', 'clk-at91', 'clk-cleanup' and 'clk-debugfs' into clk-next

* clk-doc:
  clk: Gemini: fix struct name in kernel-doc
  clk: zynq: pll: Fix kernel-doc warnings
  clk: imx: pllv1: fix kernel-doc notation for struct clk_pllv1

* clk-renesas: (31 commits)
  clk: renesas: r9a07g044: Add GPU clock and reset entries
  clk: renesas: r9a07g044: Add mux and divider for G clock
  clk: renesas: r9a07g044: Rename CLK_PLL3_DIV4 macro
  clk: renesas: cpg-mssr: Add support for R-Car S4-8
  clk: renesas: rcar-gen4: Introduce R-Car Gen4 CPG driver
  dt-bindings: clock: Add r8a779f0 CPG Core Clock Definitions
  dt-bindings: power: Add r8a779f0 SYSC power domain definitions
  clk: renesas: r9a07g044: Add TSU clock and reset entry
  mmc: renesas_sdhi: Simplify an expression
  mmc: renesas_sdhi: Use devm_clk_get_optional() to obtain CD clock
  dt-bindings: clock: renesas,cpg-mssr: Document r8a779f0
  clk: renesas: cpg-mssr: propagate return value of_genpd_add_provider_simple()
  clk: renesas: cpg-mssr: Check return value of pm_genpd_init()
  clk: renesas: rzg2l: propagate return value of_genpd_add_provider_simple()
  clk: renesas: rzg2l: Check return value of pm_genpd_init()
  clk: renesas: r9a07g044: Add RSPI clock and reset entries
  clk: renesas: r9a07g044: Change core clock "I" from DEF_FIXED->DEF_DIV
  clk: renesas: rzg2l: Add CPG_PL1_DDIV macro
  mmc: renesas_sdhi: Parse DT for SDnH
  mmc: renesas_sdhi: Use dev_err_probe when getting clock fails
  ...

* clk-at91:
  clk: lan966x: Extend lan966x clock driver for clock gating support
  dt-bindings: clock: lan966x: Extend includes with clock gates
  dt-bindings: clock: lan966x: Extend for clock gate support
  clk: gate: Add devm_clk_hw_register_gate()
  clk: lan966x: Add lan966x SoC clock driver
  dt-bindings: clock: lan966x: Add LAN966X Clock Controller
  dt-bindings: clock: lan966x: Add binding includes for lan966x SoC clock IDs

* clk-cleanup:
  clk: stm32mp1: remove redundant assignment to pointer data
  clk: __clk_core_init() never takes NULL
  clk: clk_core_get() can also return NULL
  clk/ti/adpll: Make const pointer error a static const array

* clk-debugfs:
  clk: Enable/Disable runtime PM for clk_summary
  clk: Emit a stern warning with writable debugfs enabled
  clk: Add write operation for clk_parent debugfs node
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/microchip,lan966x-gck.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip LAN966X Generic Clock Controller
maintainers:
- Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
description: |
The LAN966X Generic clock controller contains 3 PLLs - cpu_clk,
ddr_clk and sys_clk. This clock controller generates and supplies
clock to various peripherals within the SoC.
properties:
compatible:
const: microchip,lan966x-gck
reg:
minItems: 1
items:
- description: Generic clock registers
- description: Optional gate clock registers
clocks:
items:
- description: CPU clock source
- description: DDR clock source
- description: System clock source
clock-names:
items:
- const: cpu
- const: ddr
- const: sys
'#clock-cells':
const: 1
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
additionalProperties: false
examples:
- |
clks: clock-controller@e00c00a8 {
compatible = "microchip,lan966x-gck";
#clock-cells = <1>;
clocks = <&cpu_clk>, <&ddr_clk>, <&sys_clk>;
clock-names = "cpu", "ddr", "sys";
reg = <0xe00c00a8 0x38>;
};
...
......@@ -48,6 +48,7 @@ properties:
- renesas,r8a77990-cpg-mssr # R-Car E3
- renesas,r8a77995-cpg-mssr # R-Car D3
- renesas,r8a779a0-cpg-mssr # R-Car V3U
- renesas,r8a779f0-cpg-mssr # R-Car S4-8
reg:
maxItems: 1
......
......@@ -221,6 +221,13 @@ config COMMON_CLK_GEMINI
This driver supports the SoC clocks on the Cortina Systems Gemini
platform, also known as SL3516 or CS3516.
config COMMON_CLK_LAN966X
bool "Generic Clock Controller driver for LAN966X SoC"
help
This driver provides support for Generic Clock Controller(GCK) on
LAN966X SoC. GCK generates and supplies clock to various peripherals
within the SoC.
config COMMON_CLK_ASPEED
bool "Clock driver for Aspeed BMC SoCs"
depends on ARCH_ASPEED || COMPILE_TEST
......
......@@ -37,6 +37,7 @@ obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o
obj-$(CONFIG_LMK04832) += clk-lmk04832.o
obj-$(CONFIG_COMMON_CLK_LAN966X) += clk-lan966x.o
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
......
......@@ -7,6 +7,7 @@
*/
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
......@@ -222,3 +223,37 @@ void clk_hw_unregister_gate(struct clk_hw *hw)
kfree(gate);
}
EXPORT_SYMBOL_GPL(clk_hw_unregister_gate);
static void devm_clk_hw_release_gate(struct device *dev, void *res)
{
clk_hw_unregister_gate(*(struct clk_hw **)res);
}
struct clk_hw *__devm_clk_hw_register_gate(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data,
unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock)
{
struct clk_hw **ptr, *hw;
ptr = devres_alloc(devm_clk_hw_release_gate, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
hw = __clk_hw_register_gate(dev, np, name, parent_name, parent_hw,
parent_data, flags, reg, bit_idx,
clk_gate_flags, lock);
if (!IS_ERR(hw)) {
*ptr = hw;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return hw;
}
EXPORT_SYMBOL_GPL(__devm_clk_hw_register_gate);
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Microchip LAN966x SoC Clock driver.
*
* Copyright (C) 2021 Microchip Technology, Inc. and its subsidiaries
*
* Author: Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
*/
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <dt-bindings/clock/microchip,lan966x.h>
#define GCK_ENA BIT(0)
#define GCK_SRC_SEL GENMASK(9, 8)
#define GCK_PRESCALER GENMASK(23, 16)
#define DIV_MAX 255
static const char *clk_names[N_CLOCKS] = {
"qspi0", "qspi1", "qspi2", "sdmmc0",
"pi", "mcan0", "mcan1", "flexcom0",
"flexcom1", "flexcom2", "flexcom3",
"flexcom4", "timer1", "usb_refclk",
};
struct lan966x_gck {
struct clk_hw hw;
void __iomem *reg;
};
#define to_lan966x_gck(hw) container_of(hw, struct lan966x_gck, hw)
static const struct clk_parent_data lan966x_gck_pdata[] = {
{ .fw_name = "cpu", },
{ .fw_name = "ddr", },
{ .fw_name = "sys", },
};
static struct clk_init_data init = {
.parent_data = lan966x_gck_pdata,
.num_parents = ARRAY_SIZE(lan966x_gck_pdata),
};
struct clk_gate_soc_desc {
const char *name;
int bit_idx;
};
static const struct clk_gate_soc_desc clk_gate_desc[] = {
{ "uhphs", 11 },
{ "udphs", 10 },
{ "mcramc", 9 },
{ "hmatrix", 8 },
{ }
};
static DEFINE_SPINLOCK(clk_gate_lock);
static void __iomem *base;
static int lan966x_gck_enable(struct clk_hw *hw)
{
struct lan966x_gck *gck = to_lan966x_gck(hw);
u32 val = readl(gck->reg);
val |= GCK_ENA;
writel(val, gck->reg);
return 0;
}
static void lan966x_gck_disable(struct clk_hw *hw)
{
struct lan966x_gck *gck = to_lan966x_gck(hw);
u32 val = readl(gck->reg);
val &= ~GCK_ENA;
writel(val, gck->reg);
}
static int lan966x_gck_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct lan966x_gck *gck = to_lan966x_gck(hw);
u32 div, val = readl(gck->reg);
if (rate == 0 || parent_rate == 0)
return -EINVAL;
/* Set Prescalar */
div = parent_rate / rate;
val &= ~GCK_PRESCALER;
val |= FIELD_PREP(GCK_PRESCALER, (div - 1));
writel(val, gck->reg);
return 0;
}
static long lan966x_gck_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned int div;
if (rate == 0 || *parent_rate == 0)
return -EINVAL;
if (rate >= *parent_rate)
return *parent_rate;
div = DIV_ROUND_CLOSEST(*parent_rate, rate);
return *parent_rate / div;
}
static unsigned long lan966x_gck_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct lan966x_gck *gck = to_lan966x_gck(hw);
u32 div, val = readl(gck->reg);
div = FIELD_GET(GCK_PRESCALER, val);
return parent_rate / (div + 1);
}
static int lan966x_gck_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_hw *parent;
int i;
for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
/* Allowed prescaler divider range is 0-255 */
if (clk_hw_get_rate(parent) / req->rate <= DIV_MAX) {
req->best_parent_hw = parent;
req->best_parent_rate = clk_hw_get_rate(parent);
return 0;
}
}
return -EINVAL;
}
static u8 lan966x_gck_get_parent(struct clk_hw *hw)
{
struct lan966x_gck *gck = to_lan966x_gck(hw);
u32 val = readl(gck->reg);
return FIELD_GET(GCK_SRC_SEL, val);
}
static int lan966x_gck_set_parent(struct clk_hw *hw, u8 index)
{
struct lan966x_gck *gck = to_lan966x_gck(hw);
u32 val = readl(gck->reg);
val &= ~GCK_SRC_SEL;
val |= FIELD_PREP(GCK_SRC_SEL, index);
writel(val, gck->reg);
return 0;
}
static const struct clk_ops lan966x_gck_ops = {
.enable = lan966x_gck_enable,
.disable = lan966x_gck_disable,
.set_rate = lan966x_gck_set_rate,
.round_rate = lan966x_gck_round_rate,
.recalc_rate = lan966x_gck_recalc_rate,
.determine_rate = lan966x_gck_determine_rate,
.set_parent = lan966x_gck_set_parent,
.get_parent = lan966x_gck_get_parent,
};
static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i)
{
struct lan966x_gck *priv;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
priv->reg = base + (i * 4);
priv->hw.init = &init;
ret = devm_clk_hw_register(dev, &priv->hw);
if (ret)
return ERR_PTR(ret);
return &priv->hw;
};
static int lan966x_gate_clk_register(struct device *dev,
struct clk_hw_onecell_data *hw_data,
void __iomem *gate_base)
{
int i;
for (i = GCK_GATE_UHPHS; i < N_CLOCKS; ++i) {
int idx = i - GCK_GATE_UHPHS;
hw_data->hws[i] =
devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name,
"lan966x", 0, base,
clk_gate_desc[idx].bit_idx,
0, &clk_gate_lock);
if (IS_ERR(hw_data->hws[i]))
return dev_err_probe(dev, PTR_ERR(hw_data->hws[i]),
"failed to register %s clock\n",
clk_gate_desc[idx].name);
}
return 0;
}
static int lan966x_clk_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *hw_data;
struct device *dev = &pdev->dev;
void __iomem *gate_base;
struct resource *res;
int i, ret;
hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, N_CLOCKS),
GFP_KERNEL);
if (!hw_data)
return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
init.ops = &lan966x_gck_ops;
hw_data->num = GCK_GATE_UHPHS;
for (i = 0; i < GCK_GATE_UHPHS; i++) {
init.name = clk_names[i];
hw_data->hws[i] = lan966x_gck_clk_register(dev, i);
if (IS_ERR(hw_data->hws[i])) {
dev_err(dev, "failed to register %s clock\n",
init.name);
return PTR_ERR(hw_data->hws[i]);
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
gate_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gate_base))
return PTR_ERR(gate_base);
hw_data->num = N_CLOCKS;
ret = lan966x_gate_clk_register(dev, hw_data, gate_base);
if (ret)
return ret;
}
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
}
static const struct of_device_id lan966x_clk_dt_ids[] = {
{ .compatible = "microchip,lan966x-gck", },
{ }
};
MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids);
static struct platform_driver lan966x_clk_driver = {
.probe = lan966x_clk_probe,
.driver = {
.name = "lan966x-clk",
.of_match_table = lan966x_clk_dt_ids,
},
};
builtin_platform_driver(lan966x_clk_driver);
MODULE_AUTHOR("Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>");
MODULE_DESCRIPTION("LAN966X clock driver");
MODULE_LICENSE("GPL v2");
......@@ -2253,8 +2253,6 @@ static int stm32_rcc_reset_init(struct device *dev, void __iomem *base,
const struct stm32_rcc_match_data *data = match->data;
struct stm32_reset_data *reset_data = NULL;
data = match->data;
reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
if (!reset_data)
return -ENOMEM;
......
......@@ -424,19 +424,20 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
if (entry->hw) {
parent = entry->hw->core;
/*
* We have a direct reference but it isn't registered yet?
* Orphan it and let clk_reparent() update the orphan status
* when the parent is registered.
*/
if (!parent)
parent = ERR_PTR(-EPROBE_DEFER);
} else {
parent = clk_core_get(core, index);
if (PTR_ERR(parent) == -ENOENT && entry->name)
parent = clk_core_lookup(entry->name);
}
/*
* We have a direct reference but it isn't registered yet?
* Orphan it and let clk_reparent() update the orphan status
* when the parent is registered.
*/
if (!parent)
parent = ERR_PTR(-EPROBE_DEFER);
/* Only cache it if it's not an error */
if (!IS_ERR(parent))
entry->core = parent;
......@@ -2965,7 +2966,9 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
{
struct clk_core *child;
clk_pm_runtime_get(c);
clk_summary_show_one(s, c, level);
clk_pm_runtime_put(c);
hlist_for_each_entry(child, &c->children, child_node)
clk_summary_show_subtree(s, child, level + 1);
......@@ -3217,6 +3220,42 @@ static int current_parent_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(current_parent);
#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
static ssize_t current_parent_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct clk_core *core = s->private;
struct clk_core *parent;
u8 idx;
int err;
err = kstrtou8_from_user(ubuf, count, 0, &idx);
if (err < 0)
return err;
parent = clk_core_get_parent_by_index(core, idx);
if (!parent)
return -ENOENT;
clk_prepare_lock();
err = clk_core_set_parent_nolock(core, parent);
clk_prepare_unlock();
if (err)
return err;
return count;
}
static const struct file_operations current_parent_rw_fops = {
.open = current_parent_open,
.write = current_parent_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
static int clk_duty_cycle_show(struct seq_file *s, void *data)
{
struct clk_core *core = s->private;
......@@ -3282,8 +3321,12 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
debugfs_create_file("clk_prepare_enable", 0644, root, core,
&clk_prepare_enable_fops);
#endif
if (core->num_parents > 1)
debugfs_create_file("clk_parent", 0644, root, core,
&current_parent_rw_fops);
else
#endif
if (core->num_parents > 0)
debugfs_create_file("clk_parent", 0444, root, core,
&current_parent_fops);
......@@ -3343,6 +3386,24 @@ static int __init clk_debug_init(void)
{
struct clk_core *core;
#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
pr_warn("\n");
pr_warn("********************************************************************\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("** **\n");
pr_warn("** WRITEABLE clk DebugFS SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n");
pr_warn("** **\n");
pr_warn("** This means that this kernel is built to expose clk operations **\n");
pr_warn("** such as parent or rate setting, enabling, disabling, etc. **\n");
pr_warn("** to userspace, which may compromise security on your system. **\n");
pr_warn("** **\n");
pr_warn("** If you see this message and you are not debugging the **\n");
pr_warn("** kernel, report this immediately to your vendor! **\n");
pr_warn("** **\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("********************************************************************\n");
#endif
rootdir = debugfs_create_dir("clk", NULL);
debugfs_create_file("clk_summary", 0444, rootdir, &all_lists,
......@@ -3413,9 +3474,6 @@ static int __clk_core_init(struct clk_core *core)
unsigned long rate;
int phase;
if (!core)
return -EINVAL;
clk_prepare_lock();
ret = clk_pm_runtime_get(core);
......
......@@ -31,6 +31,7 @@ config CLK_RENESAS
select CLK_R8A77990 if ARCH_R8A77990
select CLK_R8A77995 if ARCH_R8A77995
select CLK_R8A779A0 if ARCH_R8A779A0
select CLK_R8A779F0 if ARCH_R8A779F0
select CLK_R9A06G032 if ARCH_R9A06G032
select CLK_R9A07G044 if ARCH_R9A07G044
select CLK_SH73A0 if ARCH_SH73A0
......@@ -149,8 +150,11 @@ config CLK_R8A77995
config CLK_R8A779A0
bool "R-Car V3U clock support" if COMPILE_TEST
select CLK_RCAR_CPG_LIB
select CLK_RENESAS_CPG_MSSR
select CLK_RCAR_GEN4_CPG
config CLK_R8A779F0
bool "R-Car S4-8 clock support" if COMPILE_TEST
select CLK_RCAR_GEN4_CPG
config CLK_R9A06G032
bool "RZ/N1D clock support" if COMPILE_TEST
......@@ -178,6 +182,11 @@ config CLK_RCAR_GEN3_CPG
select CLK_RCAR_CPG_LIB
select CLK_RENESAS_CPG_MSSR
config CLK_RCAR_GEN4_CPG
bool "R-Car Gen4 clock support" if COMPILE_TEST
select CLK_RCAR_CPG_LIB
select CLK_RENESAS_CPG_MSSR
config CLK_RCAR_USB2_CLOCK_SEL
bool "Renesas R-Car USB2 clock selector support"
depends on ARCH_RENESAS || COMPILE_TEST
......
......@@ -28,6 +28,7 @@ obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77990) += r8a77990-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o
obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o
obj-$(CONFIG_CLK_R8A779F0) += r8a779f0-cpg-mssr.o
obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o
obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o
obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o
......@@ -36,6 +37,7 @@ obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o
obj-$(CONFIG_CLK_RCAR_CPG_LIB) += rcar-cpg-lib.o
obj-$(CONFIG_CLK_RCAR_GEN2_CPG) += rcar-gen2-cpg.o
obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o
obj-$(CONFIG_CLK_RCAR_GEN4_CPG) += rcar-gen4-cpg.o
obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o
obj-$(CONFIG_CLK_RZG2L) += rzg2l-cpg.o
......
......@@ -100,10 +100,14 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A774A1_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A774A1_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A774A1_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A774A1_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A774A1_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A774A1_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_GEN3_SDH("sd0h", R8A774A1_CLK_SD0H, CLK_SDSRC, 0x074),
DEF_GEN3_SDH("sd1h", R8A774A1_CLK_SD1H, CLK_SDSRC, 0x078),
DEF_GEN3_SDH("sd2h", R8A774A1_CLK_SD2H, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd3h", R8A774A1_CLK_SD3H, CLK_SDSRC, 0x26c),
DEF_GEN3_SD("sd0", R8A774A1_CLK_SD0, R8A774A1_CLK_SD0H, 0x074),
DEF_GEN3_SD("sd1", R8A774A1_CLK_SD1, R8A774A1_CLK_SD1H, 0x078),
DEF_GEN3_SD("sd2", R8A774A1_CLK_SD2, R8A774A1_CLK_SD2H, 0x268),
DEF_GEN3_SD("sd3", R8A774A1_CLK_SD3, R8A774A1_CLK_SD3H, 0x26c),
DEF_FIXED("cl", R8A774A1_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A774A1_CLK_CP, CLK_EXTAL, 2, 1),
......
......@@ -97,10 +97,14 @@ static const struct cpg_core_clk r8a774b1_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A774B1_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A774B1_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A774B1_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A774B1_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A774B1_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A774B1_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_GEN3_SDH("sd0h", R8A774B1_CLK_SD0H, CLK_SDSRC, 0x074),
DEF_GEN3_SDH("sd1h", R8A774B1_CLK_SD1H, CLK_SDSRC, 0x078),
DEF_GEN3_SDH("sd2h", R8A774B1_CLK_SD2H, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd3h", R8A774B1_CLK_SD3H, CLK_SDSRC, 0x26c),
DEF_GEN3_SD("sd0", R8A774B1_CLK_SD0, R8A774B1_CLK_SD0H, 0x074),
DEF_GEN3_SD("sd1", R8A774B1_CLK_SD1, R8A774B1_CLK_SD1H, 0x078),
DEF_GEN3_SD("sd2", R8A774B1_CLK_SD2, R8A774B1_CLK_SD2H, 0x268),
DEF_GEN3_SD("sd3", R8A774B1_CLK_SD3, R8A774B1_CLK_SD3H, 0x26c),
DEF_FIXED("cl", R8A774B1_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A774B1_CLK_CP, CLK_EXTAL, 2, 1),
......
......@@ -108,9 +108,12 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A774C0_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A774C0_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A774C0_CLK_SD0, CLK_SDSRC, 0x0074),
DEF_GEN3_SD("sd1", R8A774C0_CLK_SD1, CLK_SDSRC, 0x0078),
DEF_GEN3_SD("sd3", R8A774C0_CLK_SD3, CLK_SDSRC, 0x026c),
DEF_GEN3_SDH("sd0h", R8A774C0_CLK_SD0H, CLK_SDSRC, 0x0074),
DEF_GEN3_SDH("sd1h", R8A774C0_CLK_SD1H, CLK_SDSRC, 0x0078),
DEF_GEN3_SDH("sd3h", R8A774C0_CLK_SD3H, CLK_SDSRC, 0x026c),
DEF_GEN3_SD("sd0", R8A774C0_CLK_SD0, R8A774C0_CLK_SD0H, 0x0074),
DEF_GEN3_SD("sd1", R8A774C0_CLK_SD1, R8A774C0_CLK_SD1H, 0x0078),
DEF_GEN3_SD("sd3", R8A774C0_CLK_SD3, R8A774C0_CLK_SD3H, 0x026c),
DEF_FIXED("cl", R8A774C0_CLK_CL, CLK_PLL1, 48, 1),
DEF_FIXED("cp", R8A774C0_CLK_CP, CLK_EXTAL, 2, 1),
......
......@@ -100,10 +100,14 @@ static const struct cpg_core_clk r8a774e1_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A774E1_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A774E1_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A774E1_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A774E1_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A774E1_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A774E1_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_GEN3_SDH("sd0h", R8A774E1_CLK_SD0H, CLK_SDSRC, 0x074),
DEF_GEN3_SDH("sd1h", R8A774E1_CLK_SD1H, CLK_SDSRC, 0x078),
DEF_GEN3_SDH("sd2h", R8A774E1_CLK_SD2H, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd3h", R8A774E1_CLK_SD3H, CLK_SDSRC, 0x26c),
DEF_GEN3_SD("sd0", R8A774E1_CLK_SD0, R8A774E1_CLK_SD0H, 0x074),
DEF_GEN3_SD("sd1", R8A774E1_CLK_SD1, R8A774E1_CLK_SD1H, 0x078),
DEF_GEN3_SD("sd2", R8A774E1_CLK_SD2, R8A774E1_CLK_SD2H, 0x268),
DEF_GEN3_SD("sd3", R8A774E1_CLK_SD3, R8A774E1_CLK_SD3H, 0x26c),
DEF_FIXED("cl", R8A774E1_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A774E1_CLK_CR, CLK_PLL1_DIV4, 2, 1),
......
......@@ -104,10 +104,14 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A7795_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A7795_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A7795_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_GEN3_SDH("sd0h", R8A7795_CLK_SD0H, CLK_SDSRC, 0x074),
DEF_GEN3_SDH("sd1h", R8A7795_CLK_SD1H, CLK_SDSRC, 0x078),
DEF_GEN3_SDH("sd2h", R8A7795_CLK_SD2H, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd3h", R8A7795_CLK_SD3H, CLK_SDSRC, 0x26c),
DEF_GEN3_SD("sd0", R8A7795_CLK_SD0, R8A7795_CLK_SD0H, 0x074),
DEF_GEN3_SD("sd1", R8A7795_CLK_SD1, R8A7795_CLK_SD1H, 0x078),
DEF_GEN3_SD("sd2", R8A7795_CLK_SD2, R8A7795_CLK_SD2H, 0x268),
DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, R8A7795_CLK_SD3H, 0x26c),
DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A7795_CLK_CR, CLK_PLL1_DIV4, 2, 1),
......
......@@ -106,10 +106,14 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A7796_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A7796_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A7796_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A7796_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A7796_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_GEN3_SDH("sd0h", R8A7796_CLK_SD0H, CLK_SDSRC, 0x074),
DEF_GEN3_SDH("sd1h", R8A7796_CLK_SD1H, CLK_SDSRC, 0x078),
DEF_GEN3_SDH("sd2h", R8A7796_CLK_SD2H, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd3h", R8A7796_CLK_SD3H, CLK_SDSRC, 0x26c),
DEF_GEN3_SD("sd0", R8A7796_CLK_SD0, R8A7796_CLK_SD0H, 0x074),
DEF_GEN3_SD("sd1", R8A7796_CLK_SD1, R8A7796_CLK_SD1H, 0x078),
DEF_GEN3_SD("sd2", R8A7796_CLK_SD2, R8A7796_CLK_SD2H, 0x268),
DEF_GEN3_SD("sd3", R8A7796_CLK_SD3, R8A7796_CLK_SD3H, 0x26c),
DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A7796_CLK_CR, CLK_PLL1_DIV4, 2, 1),
......
......@@ -101,10 +101,14 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A77965_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A77965_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A77965_CLK_SD0, CLK_SDSRC, 0x074),
DEF_GEN3_SD("sd1", R8A77965_CLK_SD1, CLK_SDSRC, 0x078),
DEF_GEN3_SD("sd2", R8A77965_CLK_SD2, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd3", R8A77965_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_GEN3_SDH("sd0h", R8A77965_CLK_SD0H, CLK_SDSRC, 0x074),
DEF_GEN3_SDH("sd1h", R8A77965_CLK_SD1H, CLK_SDSRC, 0x078),
DEF_GEN3_SDH("sd2h", R8A77965_CLK_SD2H, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd3h", R8A77965_CLK_SD3H, CLK_SDSRC, 0x26c),
DEF_GEN3_SD("sd0", R8A77965_CLK_SD0, R8A77965_CLK_SD0H, 0x074),
DEF_GEN3_SD("sd1", R8A77965_CLK_SD1, R8A77965_CLK_SD1H, 0x078),
DEF_GEN3_SD("sd2", R8A77965_CLK_SD2, R8A77965_CLK_SD2H, 0x268),
DEF_GEN3_SD("sd3", R8A77965_CLK_SD3, R8A77965_CLK_SD3H, 0x26c),
DEF_FIXED("cl", R8A77965_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A77965_CLK_CR, CLK_PLL1_DIV4, 2, 1),
......
......@@ -96,7 +96,8 @@ static const struct cpg_core_clk r8a77980_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A77980_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A77980_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A77980_CLK_SD0, CLK_SDSRC, 0x0074),
DEF_GEN3_SDH("sd0h", R8A77980_CLK_SD0H, CLK_SDSRC, 0x0074),
DEF_GEN3_SD("sd0", R8A77980_CLK_SD0, R8A77980_CLK_SD0H, 0x0074),
DEF_FIXED("cl", R8A77980_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A77980_CLK_CP, CLK_EXTAL, 2, 1),
......
......@@ -100,9 +100,12 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = {
DEF_FIXED("s3d2", R8A77990_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A77990_CLK_S3D4, CLK_S3, 4, 1),
DEF_GEN3_SD("sd0", R8A77990_CLK_SD0, CLK_SDSRC, 0x0074),
DEF_GEN3_SD("sd1", R8A77990_CLK_SD1, CLK_SDSRC, 0x0078),
DEF_GEN3_SD("sd3", R8A77990_CLK_SD3, CLK_SDSRC, 0x026c),
DEF_GEN3_SDH("sd0h", R8A77990_CLK_SD0H, CLK_SDSRC, 0x0074),
DEF_GEN3_SDH("sd1h", R8A77990_CLK_SD1H, CLK_SDSRC, 0x0078),
DEF_GEN3_SDH("sd3h", R8A77990_CLK_SD3H, CLK_SDSRC, 0x026c),
DEF_GEN3_SD("sd0", R8A77990_CLK_SD0, R8A77990_CLK_SD0H, 0x0074),
DEF_GEN3_SD("sd1", R8A77990_CLK_SD1, R8A77990_CLK_SD1H, 0x0078),
DEF_GEN3_SD("sd3", R8A77990_CLK_SD3, R8A77990_CLK_SD3H, 0x026c),
DEF_FIXED("cl", R8A77990_CLK_CL, CLK_PLL1, 48, 1),
DEF_FIXED("cr", R8A77990_CLK_CR, CLK_PLL1D2, 2, 1),
......
......@@ -103,7 +103,8 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
DEF_GEN3_PE("s3d2c", R8A77995_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2),
DEF_GEN3_PE("s3d4c", R8A77995_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4),
DEF_GEN3_SD("sd0", R8A77995_CLK_SD0, CLK_SDSRC, 0x268),
DEF_GEN3_SDH("sd0h", R8A77995_CLK_SD0H, CLK_SDSRC, 0x268),
DEF_GEN3_SD("sd0", R8A77995_CLK_SD0, R8A77995_CLK_SD0H, 0x268),
DEF_DIV6P1("canfd", R8A77995_CLK_CANFD, CLK_PLL0D3, 0x244),
DEF_DIV6P1("mso", R8A77995_CLK_MSO, CLK_PLL1D2, 0x014),
......
......@@ -10,46 +10,19 @@
* Copyright (C) 2015 Renesas Electronics Corp.
*/
#include <linux/bug.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/soc/renesas/rcar-rst.h>
#include <dt-bindings/clock/r8a779a0-cpg-mssr.h>
#include "rcar-cpg-lib.h"
#include "renesas-cpg-mssr.h"
enum rcar_r8a779a0_clk_types {
CLK_TYPE_R8A779A0_MAIN = CLK_TYPE_CUSTOM,
CLK_TYPE_R8A779A0_PLL1,
CLK_TYPE_R8A779A0_PLL2X_3X, /* PLL[23][01] */
CLK_TYPE_R8A779A0_PLL5,
CLK_TYPE_R8A779A0_Z,
CLK_TYPE_R8A779A0_SD,
CLK_TYPE_R8A779A0_MDSEL, /* Select parent/divider using mode pin */
CLK_TYPE_R8A779A0_OSC, /* OSC EXTAL predivider and fixed divider */
CLK_TYPE_R8A779A0_RPCSRC,
CLK_TYPE_R8A779A0_RPC,
CLK_TYPE_R8A779A0_RPCD2,
};
struct rcar_r8a779a0_cpg_pll_config {
u8 extal_div;
u8 pll1_mult;
u8 pll1_div;
u8 pll5_mult;
u8 pll5_div;
u8 osc_prediv;
};
#include "rcar-gen4-cpg.h"
enum clk_ids {
/* Core Clock Outputs exported to DT */
......@@ -85,33 +58,18 @@ enum clk_ids {
};
#define DEF_PLL(_name, _id, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_PLL2X_3X, CLK_MAIN, \
DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL2X_3X, CLK_MAIN, \
.offset = _offset)
#define DEF_Z(_name, _id, _parent, _div, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_Z, _parent, .div = _div, \
.offset = _offset)
#define DEF_SD(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_SD, _parent, .offset = _offset)
#define DEF_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_MDSEL, \
(_parent0) << 16 | (_parent1), \
.div = (_div0) << 16 | (_div1), .offset = _md)
#define DEF_OSC(_name, _id, _parent, _div) \
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_OSC, _parent, .div = _div)
static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("extalr", CLK_EXTALR),
/* Internal Core Clocks */
DEF_BASE(".main", CLK_MAIN, CLK_TYPE_R8A779A0_MAIN, CLK_EXTAL),
DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_R8A779A0_PLL1, CLK_MAIN),
DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_R8A779A0_PLL5, CLK_MAIN),
DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL),
DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN),
DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN),
DEF_PLL(".pll20", CLK_PLL20, 0x0834),
DEF_PLL(".pll21", CLK_PLL21, 0x0838),
DEF_PLL(".pll30", CLK_PLL30, 0x083c),
......@@ -128,14 +86,14 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL5_DIV4, 1, 1),
DEF_RATE(".oco", CLK_OCO, 32768),
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_R8A779A0_RPCSRC, CLK_PLL5),
DEF_BASE("rpc", R8A779A0_CLK_RPC, CLK_TYPE_R8A779A0_RPC, CLK_RPCSRC),
DEF_BASE("rpcd2", R8A779A0_CLK_RPCD2, CLK_TYPE_R8A779A0_RPCD2,
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN4_RPCSRC, CLK_PLL5),
DEF_BASE("rpc", R8A779A0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC),
DEF_BASE("rpcd2", R8A779A0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2,
R8A779A0_CLK_RPC),
/* Core Clock Outputs */
DEF_Z("z0", R8A779A0_CLK_Z0, CLK_PLL20, 2, 0),
DEF_Z("z1", R8A779A0_CLK_Z1, CLK_PLL21, 2, 8),
DEF_GEN4_Z("z0", R8A779A0_CLK_Z0, CLK_TYPE_GEN4_Z, CLK_PLL20, 2, 0),
DEF_GEN4_Z("z1", R8A779A0_CLK_Z1, CLK_TYPE_GEN4_Z, CLK_PLL21, 2, 8),
DEF_FIXED("zx", R8A779A0_CLK_ZX, CLK_PLL20_DIV2, 2, 1),
DEF_FIXED("s1d1", R8A779A0_CLK_S1D1, CLK_S1, 1, 1),
DEF_FIXED("s1d2", R8A779A0_CLK_S1D2, CLK_S1, 2, 1),
......@@ -159,15 +117,16 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
DEF_FIXED("cp", R8A779A0_CLK_CP, CLK_EXTAL, 2, 1),
DEF_FIXED("cl16mck", R8A779A0_CLK_CL16MCK, CLK_PLL1_DIV2, 64, 1),
DEF_SD("sd0", R8A779A0_CLK_SD0, CLK_SDSRC, 0x870),
DEF_GEN4_SDH("sdh0", R8A779A0_CLK_SD0H, CLK_SDSRC, 0x870),
DEF_GEN4_SD("sd0", R8A779A0_CLK_SD0, R8A779A0_CLK_SD0H, 0x870),
DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, 0x87c),
DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878),
DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, 0x880),
DEF_DIV6P1("dsi", R8A779A0_CLK_DSI, CLK_PLL5_DIV4, 0x884),
DEF_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8),
DEF_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
DEF_GEN4_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8),
DEF_GEN4_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
};
static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
......@@ -271,256 +230,6 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
DEF_MOD("vspx3", 1031, R8A779A0_CLK_S1D1),
};
static const struct rcar_r8a779a0_cpg_pll_config *cpg_pll_config __initdata;
static unsigned int cpg_clk_extalr __initdata;
static u32 cpg_mode __initdata;
/*
* Z0 Clock & Z1 Clock
*/
#define CPG_FRQCRB 0x00000804
#define CPG_FRQCRB_KICK BIT(31)
#define CPG_FRQCRC 0x00000808
struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
void __iomem *kick_reg;
unsigned long max_rate; /* Maximum rate for normal mode */
unsigned int fixed_div;
u32 mask;
};
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult;
u32 val;
val = readl(zclk->reg) & zclk->mask;
mult = 32 - (val >> __ffs(zclk->mask));
return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult,
32 * zclk->fixed_div);
}
static int cpg_z_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int min_mult, max_mult, mult;
unsigned long rate, prate;
rate = min(req->rate, req->max_rate);
if (rate <= zclk->max_rate) {
/* Set parent rate to initial value for normal modes */
prate = zclk->max_rate;
} else {
/* Set increased parent rate for boost modes */
prate = rate;
}
req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
prate * zclk->fixed_div);
prate = req->best_parent_rate / zclk->fixed_div;
min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL);
max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL);
if (max_mult < min_mult)
return -EINVAL;
mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL, prate);
mult = clamp(mult, min_mult, max_mult);
req->rate = DIV_ROUND_CLOSEST_ULL((u64)prate * mult, 32);
return 0;
}
static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult;
unsigned int i;
mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div,
parent_rate);
mult = clamp(mult, 1U, 32U);
if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
return -EBUSY;
cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask));
/*
* Set KICK bit in FRQCRB to update hardware setting and wait for
* clock change completion.
*/
cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK);
/*
* Note: There is no HW information about the worst case latency.
*
* Using experimental measurements, it seems that no more than
* ~10 iterations are needed, independently of the CPU rate.
* Since this value might be dependent on external xtal rate, pll1
* rate or even the other emulation clocks rate, use 1000 as a
* "super" safe value.
*/
for (i = 1000; i; i--) {
if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
return 0;
cpu_relax();
}
return -ETIMEDOUT;
}
static const struct clk_ops cpg_z_clk_ops = {
.recalc_rate = cpg_z_clk_recalc_rate,
.determine_rate = cpg_z_clk_determine_rate,
.set_rate = cpg_z_clk_set_rate,
};
static struct clk * __init cpg_z_clk_register(const char *name,
const char *parent_name,
void __iomem *reg,
unsigned int div,
unsigned int offset)
{
struct clk_init_data init = {};
struct cpg_z_clk *zclk;
struct clk *clk;
zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
if (!zclk)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &cpg_z_clk_ops;
init.flags = CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
zclk->reg = reg + CPG_FRQCRC;
zclk->kick_reg = reg + CPG_FRQCRB;
zclk->hw.init = &init;
zclk->mask = GENMASK(offset + 4, offset);
zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */
clk = clk_register(NULL, &zclk->hw);
if (IS_ERR(clk)) {
kfree(zclk);
return clk;
}
zclk->max_rate = clk_hw_get_rate(clk_hw_get_parent(&zclk->hw)) /
zclk->fixed_div;
return clk;
}
/*
* RPC Clocks
*/
#define CPG_RPCCKCR 0x874
static const struct clk_div_table cpg_rpcsrc_div_table[] = {
{ 0, 4 }, { 1, 6 }, { 2, 5 }, { 3, 6 }, { 0, 0 },
};
static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
{
const struct clk *parent;
unsigned int mult = 1;
unsigned int div = 1;
u32 value;
parent = clks[core->parent & 0xffff]; /* some types use high bits */
if (IS_ERR(parent))
return ERR_CAST(parent);
switch (core->type) {
case CLK_TYPE_R8A779A0_MAIN:
div = cpg_pll_config->extal_div;
break;
case CLK_TYPE_R8A779A0_PLL1:
mult = cpg_pll_config->pll1_mult;
div = cpg_pll_config->pll1_div;
break;
case CLK_TYPE_R8A779A0_PLL2X_3X:
value = readl(base + core->offset);
mult = (((value >> 24) & 0x7f) + 1) * 2;
break;
case CLK_TYPE_R8A779A0_PLL5:
mult = cpg_pll_config->pll5_mult;
div = cpg_pll_config->pll5_div;
break;
case CLK_TYPE_R8A779A0_Z:
return cpg_z_clk_register(core->name, __clk_get_name(parent),
base, core->div, core->offset);
case CLK_TYPE_R8A779A0_SD:
return cpg_sd_clk_register(core->name, base, core->offset,
__clk_get_name(parent), notifiers,
false);
break;
case CLK_TYPE_R8A779A0_MDSEL:
/*
* Clock selectable between two parents and two fixed dividers
* using a mode pin
*/
if (cpg_mode & BIT(core->offset)) {
div = core->div & 0xffff;
} else {
parent = clks[core->parent >> 16];
if (IS_ERR(parent))
return ERR_CAST(parent);
div = core->div >> 16;
}
mult = 1;
break;
case CLK_TYPE_R8A779A0_OSC:
/*
* Clock combining OSC EXTAL predivider and a fixed divider
*/
div = cpg_pll_config->osc_prediv * core->div;
break;
case CLK_TYPE_R8A779A0_RPCSRC:
return clk_register_divider_table(NULL, core->name,
__clk_get_name(parent), 0,
base + CPG_RPCCKCR, 3, 2, 0,
cpg_rpcsrc_div_table,
&cpg_lock);
case CLK_TYPE_R8A779A0_RPC:
return cpg_rpc_clk_register(core->name, base + CPG_RPCCKCR,
__clk_get_name(parent), notifiers);
case CLK_TYPE_R8A779A0_RPCD2:
return cpg_rpcd2_clk_register(core->name, base + CPG_RPCCKCR,
__clk_get_name(parent));
default:
return ERR_PTR(-EINVAL);
}
return clk_register_fixed_factor(NULL, core->name,
__clk_get_name(parent), 0, mult, div);
}
static const unsigned int r8a779a0_crit_mod_clks[] __initconst = {
MOD_CLK_ID(907), /* RWDT */
};
......@@ -539,17 +248,19 @@ static const unsigned int r8a779a0_crit_mod_clks[] __initconst = {
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \
(((md) & BIT(13)) >> 13))
static const struct rcar_r8a779a0_cpg_pll_config cpg_pll_configs[4] = {
/* EXTAL div PLL1 mult/div PLL5 mult/div OSC prediv */
{ 1, 128, 1, 192, 1, 16, },
{ 1, 106, 1, 160, 1, 19, },
{ 0, 0, 0, 0, 0, 0, },
{ 2, 128, 1, 192, 1, 32, },
static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = {
/* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */
{ 1, 128, 1, 0, 0, 0, 0, 192, 1, 0, 0, 16, },
{ 1, 106, 1, 0, 0, 0, 0, 160, 1, 0, 0, 19, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 2, 128, 1, 0, 0, 0, 0, 192, 1, 0, 0, 32, },
};
static int __init r8a779a0_cpg_mssr_init(struct device *dev)
{
const struct rcar_gen4_cpg_pll_config *cpg_pll_config;
u32 cpg_mode;
int error;
error = rcar_rst_read_mode_pins(&cpg_mode);
......@@ -557,10 +268,8 @@ static int __init r8a779a0_cpg_mssr_init(struct device *dev)
return error;
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
cpg_clk_extalr = CLK_EXTALR;
spin_lock_init(&cpg_lock);
return 0;
return rcar_gen4_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode);
}
const struct cpg_mssr_info r8a779a0_cpg_mssr_info __initconst = {
......@@ -581,7 +290,7 @@ const struct cpg_mssr_info r8a779a0_cpg_mssr_info __initconst = {
/* Callbacks */
.init = r8a779a0_cpg_mssr_init,
.cpg_clk_register = rcar_r8a779a0_cpg_clk_register,
.cpg_clk_register = rcar_gen4_cpg_clk_register,
.reg_layout = CLK_REG_LAYOUT_RCAR_V3U,
.reg_layout = CLK_REG_LAYOUT_RCAR_GEN4,
};
// SPDX-License-Identifier: GPL-2.0
/*
* r8a779f0 Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2021 Renesas Electronics Corp.
*
* Based on r8a779a0-cpg-mssr.c
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/soc/renesas/rcar-rst.h>
#include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
#include "renesas-cpg-mssr.h"
#include "rcar-gen4-cpg.h"
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R8A779F0_CLK_R,
/* External Input Clocks */
CLK_EXTAL,
CLK_EXTALR,
/* Internal Core Clocks */
CLK_MAIN,
CLK_PLL1,
CLK_PLL2,
CLK_PLL3,
CLK_PLL5,
CLK_PLL6,
CLK_PLL1_DIV2,
CLK_PLL2_DIV2,
CLK_PLL3_DIV2,
CLK_PLL5_DIV2,
CLK_PLL5_DIV4,
CLK_PLL6_DIV2,
CLK_S0,
CLK_SDSRC,
CLK_RPCSRC,
CLK_OCO,
/* Module Clocks */
MOD_CLK_BASE
};
static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("extalr", CLK_EXTALR),
/* Internal Core Clocks */
DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL),
DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN),
DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN4_PLL2, CLK_MAIN),
DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN4_PLL3, CLK_MAIN),
DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN),
DEF_BASE(".pll6", CLK_PLL6, CLK_TYPE_GEN4_PLL6, CLK_MAIN),
DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1),
DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 2, 1),
DEF_FIXED(".pll5_div2", CLK_PLL5_DIV2, CLK_PLL5, 2, 1),
DEF_FIXED(".pll5_div4", CLK_PLL5_DIV4, CLK_PLL5_DIV2, 2, 1),
DEF_FIXED(".pll6_div2", CLK_PLL6_DIV2, CLK_PLL6, 2, 1),
DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
DEF_BASE(".sdsrc", CLK_SDSRC, CLK_TYPE_GEN4_SDSRC, CLK_PLL5),
DEF_RATE(".oco", CLK_OCO, 32768),
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN4_RPCSRC, CLK_PLL5),
DEF_BASE(".rpc", R8A779F0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC),
DEF_BASE("rpcd2", R8A779F0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779F0_CLK_RPC),
/* Core Clock Outputs */
DEF_FIXED("s0d2", R8A779F0_CLK_S0D2, CLK_S0, 2, 1),
DEF_FIXED("s0d3", R8A779F0_CLK_S0D3, CLK_S0, 3, 1),
DEF_FIXED("s0d4", R8A779F0_CLK_S0D4, CLK_S0, 4, 1),
DEF_FIXED("cl16m", R8A779F0_CLK_CL16M, CLK_S0, 48, 1),
DEF_FIXED("s0d2_mm", R8A779F0_CLK_S0D2_MM, CLK_S0, 2, 1),
DEF_FIXED("s0d3_mm", R8A779F0_CLK_S0D3_MM, CLK_S0, 3, 1),
DEF_FIXED("s0d4_mm", R8A779F0_CLK_S0D4_MM, CLK_S0, 4, 1),
DEF_FIXED("cl16m_mm", R8A779F0_CLK_CL16M_MM, CLK_S0, 48, 1),
DEF_FIXED("s0d2_rt", R8A779F0_CLK_S0D2_RT, CLK_S0, 2, 1),
DEF_FIXED("s0d3_rt", R8A779F0_CLK_S0D3_RT, CLK_S0, 3, 1),
DEF_FIXED("s0d4_rt", R8A779F0_CLK_S0D4_RT, CLK_S0, 4, 1),
DEF_FIXED("s0d6_rt", R8A779F0_CLK_S0D6_RT, CLK_S0, 6, 1),
DEF_FIXED("cl16m_rt", R8A779F0_CLK_CL16M_RT, CLK_S0, 48, 1),
DEF_FIXED("s0d3_per", R8A779F0_CLK_S0D3_PER, CLK_S0, 3, 1),
DEF_FIXED("s0d6_per", R8A779F0_CLK_S0D6_PER, CLK_S0, 6, 1),
DEF_FIXED("s0d12_per", R8A779F0_CLK_S0D12_PER, CLK_S0, 12, 1),
DEF_FIXED("s0d24_per", R8A779F0_CLK_S0D24_PER, CLK_S0, 24, 1),
DEF_FIXED("cl16m_per", R8A779F0_CLK_CL16M_PER, CLK_S0, 48, 1),
DEF_FIXED("s0d2_hsc", R8A779F0_CLK_S0D2_HSC, CLK_S0, 2, 1),
DEF_FIXED("s0d3_hsc", R8A779F0_CLK_S0D3_HSC, CLK_S0, 3, 1),
DEF_FIXED("s0d4_hsc", R8A779F0_CLK_S0D4_HSC, CLK_S0, 4, 1),
DEF_FIXED("s0d6_hsc", R8A779F0_CLK_S0D6_HSC, CLK_S0, 6, 1),
DEF_FIXED("s0d12_hsc", R8A779F0_CLK_S0D12_HSC, CLK_S0, 12, 1),
DEF_FIXED("cl16m_hsc", R8A779F0_CLK_CL16M_HSC, CLK_S0, 48, 1),
DEF_FIXED("s0d2_cc", R8A779F0_CLK_S0D2_CC, CLK_S0, 2, 1),
DEF_FIXED("rsw2", R8A779F0_CLK_RSW2, CLK_PLL5, 2, 1),
DEF_FIXED("cbfusa", R8A779F0_CLK_CBFUSA, CLK_EXTAL, 2, 1),
DEF_FIXED("cpex", R8A779F0_CLK_CPEX, CLK_EXTAL, 2, 1),
DEF_GEN4_SD("sd0", R8A779F0_CLK_SD0, CLK_SDSRC, 0x870),
DEF_DIV6P1("mso", R8A779F0_CLK_MSO, CLK_PLL5_DIV4, 0x87c),
DEF_GEN4_OSC("osc", R8A779F0_CLK_OSC, CLK_EXTAL, 8),
DEF_GEN4_MDSEL("r", R8A779F0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
};
static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = {
DEF_MOD("scif0", 702, R8A779F0_CLK_S0D12_PER),
DEF_MOD("scif1", 703, R8A779F0_CLK_S0D12_PER),
DEF_MOD("scif3", 704, R8A779F0_CLK_S0D12_PER),
DEF_MOD("scif4", 705, R8A779F0_CLK_S0D12_PER),
};
/*
* CPG Clock Data
*/
/*
* MD EXTAL PLL1 PLL2 PLL3 PLL5 PLL6 OSC
* 14 13 (MHz)
* ----------------------------------------------------------------
* 0 0 16 / 1 x200 x150 x200 x200 x134 /15
* 0 1 20 / 1 x160 x120 x160 x160 x106 /19
* 1 0 Prohibited setting
* 1 1 40 / 2 x160 x120 x160 x160 x106 /38
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \
(((md) & BIT(13)) >> 13))
static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = {
/* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */
{ 1, 200, 1, 150, 1, 200, 1, 200, 1, 134, 1, 15, },
{ 1, 160, 1, 120, 1, 160, 1, 160, 1, 106, 1, 19, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 2, 160, 1, 120, 1, 160, 1, 160, 1, 106, 1, 38, },
};
static int __init r8a779f0_cpg_mssr_init(struct device *dev)
{
const struct rcar_gen4_cpg_pll_config *cpg_pll_config;
u32 cpg_mode;
int error;
error = rcar_rst_read_mode_pins(&cpg_mode);
if (error)
return error;
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
if (!cpg_pll_config->extal_div) {
dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
return -EINVAL;
}
return rcar_gen4_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode);
}
const struct cpg_mssr_info r8a779f0_cpg_mssr_info __initconst = {
/* Core Clocks */
.core_clks = r8a779f0_core_clks,
.num_core_clks = ARRAY_SIZE(r8a779f0_core_clks),
.last_dt_core_clk = LAST_DT_CORE_CLK,
.num_total_core_clks = MOD_CLK_BASE,
/* Module Clocks */
.mod_clks = r8a779f0_mod_clks,
.num_mod_clks = ARRAY_SIZE(r8a779f0_mod_clks),
.num_hw_mod_clks = 28 * 32,
/* Callbacks */
.init = r8a779f0_cpg_mssr_init,
.cpg_clk_register = rcar_gen4_cpg_clk_register,
.reg_layout = CLK_REG_LAYOUT_RCAR_GEN4,
};
......@@ -26,15 +26,15 @@ enum clk_ids {
CLK_PLL1,
CLK_PLL2,
CLK_PLL2_DIV2,
CLK_PLL2_DIV16,
CLK_PLL2_DIV20,
CLK_PLL2_DIV2_8,
CLK_PLL2_DIV2_10,
CLK_PLL3,
CLK_PLL3_400,
CLK_PLL3_533,
CLK_PLL3_DIV2,
CLK_PLL3_DIV2_2,
CLK_PLL3_DIV2_4,
CLK_PLL3_DIV2_4_2,
CLK_PLL3_DIV4,
CLK_SEL_PLL3_3,
CLK_DIV_PLL3_C,
CLK_PLL4,
......@@ -50,12 +50,21 @@ enum clk_ids {
CLK_PLL2_SDHI_266,
CLK_SD0_DIV4,
CLK_SD1_DIV4,
CLK_SEL_GPU2,
/* Module Clocks */
MOD_CLK_BASE,
};
/* Divider tables */
static const struct clk_div_table dtable_1_8[] = {
{0, 1},
{1, 2},
{2, 4},
{3, 8},
{0, 0},
};
static const struct clk_div_table dtable_1_32[] = {
{0, 1},
{1, 2},
......@@ -69,6 +78,7 @@ static const struct clk_div_table dtable_1_32[] = {
static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" };
static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" };
static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" };
static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" };
static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
/* External Clock Inputs */
......@@ -94,13 +104,13 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
DEF_FIXED(".clk_400", CLK_PLL2_SDHI_400, CLK_PLL2_800, 1, 2),
DEF_FIXED(".clk_266", CLK_PLL2_SDHI_266, CLK_PLL2_SDHI_533, 1, 2),
DEF_FIXED(".pll2_div16", CLK_PLL2_DIV16, CLK_PLL2, 1, 16),
DEF_FIXED(".pll2_div20", CLK_PLL2_DIV20, CLK_PLL2, 1, 20),
DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8),
DEF_FIXED(".pll2_div2_10", CLK_PLL2_DIV2_10, CLK_PLL2_DIV2, 1, 10),
DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2),
DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4),
DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2),
DEF_FIXED(".pll3_div4", CLK_PLL3_DIV4, CLK_PLL3, 1, 4),
DEF_MUX(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3,
sel_pll3_3, ARRAY_SIZE(sel_pll3_3), 0, CLK_MUX_READ_ONLY),
DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3,
......@@ -108,13 +118,16 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2),
DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2),
DEF_MUX(".sel_gpu2", CLK_SEL_GPU2, SEL_GPU2,
sel_gpu2, ARRAY_SIZE(sel_gpu2), 0, CLK_MUX_READ_ONLY),
/* Core output clk */
DEF_FIXED("I", R9A07G044_CLK_I, CLK_PLL1, 1, 1),
DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV16, DIVPL2A,
DEF_DIV("I", R9A07G044_CLK_I, CLK_PLL1, DIVPL1A, dtable_1_8,
CLK_DIVIDER_HIWORD_MASK),
DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV2_8, DIVPL2A,
dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2),
DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV20, 1, 1),
DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1),
DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4,
DIVPL3B, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2),
......@@ -132,6 +145,8 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
sel_shdi, ARRAY_SIZE(sel_shdi)),
DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4),
DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4),
DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8,
CLK_DIVIDER_HIWORD_MASK),
};
static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
......@@ -145,6 +160,24 @@ static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
0x52c, 0),
DEF_MOD("dmac_pclk", R9A07G044_DMAC_PCLK, CLK_P1_DIV2,
0x52c, 1),
DEF_MOD("ostm0_pclk", R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0,
0x534, 0),
DEF_MOD("ostm1_clk", R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0,
0x534, 1),
DEF_MOD("ostm2_pclk", R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0,
0x534, 2),
DEF_MOD("wdt0_pclk", R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0,
0x548, 0),
DEF_MOD("wdt0_clk", R9A07G044_WDT0_CLK, R9A07G044_OSCCLK,
0x548, 1),
DEF_MOD("wdt1_pclk", R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0,
0x548, 2),
DEF_MOD("wdt1_clk", R9A07G044_WDT1_CLK, R9A07G044_OSCCLK,
0x548, 3),
DEF_MOD("wdt2_pclk", R9A07G044_WDT2_PCLK, R9A07G044_CLK_P0,
0x548, 4),
DEF_MOD("wdt2_clk", R9A07G044_WDT2_CLK, R9A07G044_OSCCLK,
0x548, 5),
DEF_MOD("spi_clk2", R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1,
0x550, 0),
DEF_MOD("spi_clk", R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0,
......@@ -165,6 +198,12 @@ static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
0x554, 6),
DEF_MOD("sdhi1_aclk", R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1,
0x554, 7),
DEF_MOD("gpu_clk", R9A07G044_GPU_CLK, R9A07G044_CLK_G,
0x558, 0),
DEF_MOD("gpu_axi_clk", R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1,
0x558, 1),
DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1,
0x558, 2),
DEF_MOD("ssi0_pclk", R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0,
0x570, 0),
DEF_MOD("ssi0_sfr", R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0,
......@@ -217,6 +256,14 @@ static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
0x584, 4),
DEF_MOD("sci0", R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0,
0x588, 0),
DEF_MOD("sci1", R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0,
0x588, 1),
DEF_MOD("rspi0", R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0,
0x590, 0),
DEF_MOD("rspi1", R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0,
0x590, 1),
DEF_MOD("rspi2", R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0,
0x590, 2),
DEF_MOD("canfd", R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0,
0x594, 0),
DEF_MOD("gpio", R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK,
......@@ -225,6 +272,8 @@ static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
0x5a8, 0),
DEF_MOD("adc_pclk", R9A07G044_ADC_PCLK, R9A07G044_CLK_P0,
0x5a8, 1),
DEF_MOD("tsu_pclk", R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU,
0x5ac, 0),
};
static struct rzg2l_reset r9a07g044_resets[] = {
......@@ -233,9 +282,18 @@ static struct rzg2l_reset r9a07g044_resets[] = {
DEF_RST(R9A07G044_IA55_RESETN, 0x818, 0),
DEF_RST(R9A07G044_DMAC_ARESETN, 0x82c, 0),
DEF_RST(R9A07G044_DMAC_RST_ASYNC, 0x82c, 1),
DEF_RST(R9A07G044_OSTM0_PRESETZ, 0x834, 0),
DEF_RST(R9A07G044_OSTM1_PRESETZ, 0x834, 1),
DEF_RST(R9A07G044_OSTM2_PRESETZ, 0x834, 2),
DEF_RST(R9A07G044_WDT0_PRESETN, 0x848, 0),
DEF_RST(R9A07G044_WDT1_PRESETN, 0x848, 1),
DEF_RST(R9A07G044_WDT2_PRESETN, 0x848, 2),
DEF_RST(R9A07G044_SPI_RST, 0x850, 0),
DEF_RST(R9A07G044_SDHI0_IXRST, 0x854, 0),
DEF_RST(R9A07G044_SDHI1_IXRST, 0x854, 1),
DEF_RST(R9A07G044_GPU_RESETN, 0x858, 0),
DEF_RST(R9A07G044_GPU_AXI_RESETN, 0x858, 1),
DEF_RST(R9A07G044_GPU_ACE_RESETN, 0x858, 2),
DEF_RST(R9A07G044_SSI0_RST_M2_REG, 0x870, 0),
DEF_RST(R9A07G044_SSI1_RST_M2_REG, 0x870, 1),
DEF_RST(R9A07G044_SSI2_RST_M2_REG, 0x870, 2),
......@@ -256,6 +314,10 @@ static struct rzg2l_reset r9a07g044_resets[] = {
DEF_RST(R9A07G044_SCIF3_RST_SYSTEM_N, 0x884, 3),
DEF_RST(R9A07G044_SCIF4_RST_SYSTEM_N, 0x884, 4),
DEF_RST(R9A07G044_SCI0_RST, 0x888, 0),
DEF_RST(R9A07G044_SCI1_RST, 0x888, 1),
DEF_RST(R9A07G044_RSPI0_RST, 0x890, 0),
DEF_RST(R9A07G044_RSPI1_RST, 0x890, 1),
DEF_RST(R9A07G044_RSPI2_RST, 0x890, 2),
DEF_RST(R9A07G044_CANFD_RSTP_N, 0x894, 0),
DEF_RST(R9A07G044_CANFD_RSTC_N, 0x894, 1),
DEF_RST(R9A07G044_GPIO_RSTN, 0x898, 0),
......@@ -263,6 +325,7 @@ static struct rzg2l_reset r9a07g044_resets[] = {
DEF_RST(R9A07G044_GPIO_SPARE_RESETN, 0x898, 2),
DEF_RST(R9A07G044_ADC_PRESETN, 0x8a8, 0),
DEF_RST(R9A07G044_ADC_ADRST_N, 0x8a8, 1),
DEF_RST(R9A07G044_TSU_PRESETN, 0x8ac, 0),
};
static const unsigned int r9a07g044_crit_mod_clks[] __initconst = {
......
......@@ -65,206 +65,49 @@ void cpg_simple_notifier_register(struct raw_notifier_head *notifiers,
/*
* SDn Clock
*/
#define CPG_SD_STP_HCK BIT(9)
#define CPG_SD_STP_CK BIT(8)
#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \
{ \
.val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
((sd_srcfc) << 2) | \
((sd_fc) << 0), \
.div = (sd_div), \
}
struct sd_div_table {
u32 val;
unsigned int div;
};
#define SDnSRCFC_SHIFT 2
#define STPnHCK BIT(9 - SDnSRCFC_SHIFT)
struct sd_clock {
struct clk_hw hw;
const struct sd_div_table *div_table;
struct cpg_simple_notifier csn;
unsigned int div_num;
unsigned int cur_div_idx;
};
/* SDn divider
* sd_srcfc sd_fc div
* stp_hck (div) (div) = sd_srcfc x sd_fc
*---------------------------------------------------------
* 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP)
* 0 1 (2) 1 (4) 8 : SDR50
* 1 2 (4) 1 (4) 16 : HS / SDR25
* 1 3 (8) 1 (4) 32 : NS / SDR12
* 1 4 (16) 1 (4) 64
* 0 0 (1) 0 (2) 2
* 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP)
* 1 2 (4) 0 (2) 8
* 1 3 (8) 0 (2) 16
* 1 4 (16) 0 (2) 32
*
* NOTE: There is a quirk option to ignore the first row of the dividers
* table when searching for suitable settings. This is because HS400 on
* early ES versions of H3 and M3-W requires a specific setting to work.
*/
static const struct sd_div_table cpg_sd_div_table[] = {
/* CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) */
CPG_SD_DIV_TABLE_DATA(0, 0, 1, 4),
CPG_SD_DIV_TABLE_DATA(0, 1, 1, 8),
CPG_SD_DIV_TABLE_DATA(1, 2, 1, 16),
CPG_SD_DIV_TABLE_DATA(1, 3, 1, 32),
CPG_SD_DIV_TABLE_DATA(1, 4, 1, 64),
CPG_SD_DIV_TABLE_DATA(0, 0, 0, 2),
CPG_SD_DIV_TABLE_DATA(0, 1, 0, 4),
CPG_SD_DIV_TABLE_DATA(1, 2, 0, 8),
CPG_SD_DIV_TABLE_DATA(1, 3, 0, 16),
CPG_SD_DIV_TABLE_DATA(1, 4, 0, 32),
static const struct clk_div_table cpg_sdh_div_table[] = {
{ 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 },
{ STPnHCK | 4, 16 }, { 0, 0 },
};
#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
static int cpg_sd_clock_enable(struct clk_hw *hw)
{
struct sd_clock *clock = to_sd_clock(hw);
cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK,
clock->div_table[clock->cur_div_idx].val &
CPG_SD_STP_MASK);
return 0;
}
static void cpg_sd_clock_disable(struct clk_hw *hw)
{
struct sd_clock *clock = to_sd_clock(hw);
cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK);
}
static int cpg_sd_clock_is_enabled(struct clk_hw *hw)
struct clk * __init cpg_sdh_clk_register(const char *name,
void __iomem *sdnckcr, const char *parent_name,
struct raw_notifier_head *notifiers)
{
struct sd_clock *clock = to_sd_clock(hw);
return !(readl(clock->csn.reg) & CPG_SD_STP_MASK);
}
struct cpg_simple_notifier *csn;
struct clk *clk;
static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sd_clock *clock = to_sd_clock(hw);
csn = kzalloc(sizeof(*csn), GFP_KERNEL);
if (!csn)
return ERR_PTR(-ENOMEM);
return DIV_ROUND_CLOSEST(parent_rate,
clock->div_table[clock->cur_div_idx].div);
}
csn->reg = sdnckcr;
static int cpg_sd_clock_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
unsigned long best_rate = ULONG_MAX, diff_min = ULONG_MAX;
struct sd_clock *clock = to_sd_clock(hw);
unsigned long calc_rate, diff;
unsigned int i;
for (i = 0; i < clock->div_num; i++) {
calc_rate = DIV_ROUND_CLOSEST(req->best_parent_rate,
clock->div_table[i].div);
if (calc_rate < req->min_rate || calc_rate > req->max_rate)
continue;
diff = calc_rate > req->rate ? calc_rate - req->rate
: req->rate - calc_rate;
if (diff < diff_min) {
best_rate = calc_rate;
diff_min = diff;
}
clk = clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr,
SDnSRCFC_SHIFT, 8, 0, cpg_sdh_div_table,
&cpg_lock);
if (IS_ERR(clk)) {
kfree(csn);
return clk;
}
if (best_rate == ULONG_MAX)
return -EINVAL;
req->rate = best_rate;
return 0;
}
static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct sd_clock *clock = to_sd_clock(hw);
unsigned int i;
for (i = 0; i < clock->div_num; i++)
if (rate == DIV_ROUND_CLOSEST(parent_rate,
clock->div_table[i].div))
break;
if (i >= clock->div_num)
return -EINVAL;
clock->cur_div_idx = i;
cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK,
clock->div_table[i].val &
(CPG_SD_STP_MASK | CPG_SD_FC_MASK));
return 0;
cpg_simple_notifier_register(notifiers, csn);
return clk;
}
static const struct clk_ops cpg_sd_clock_ops = {
.enable = cpg_sd_clock_enable,
.disable = cpg_sd_clock_disable,
.is_enabled = cpg_sd_clock_is_enabled,
.recalc_rate = cpg_sd_clock_recalc_rate,
.determine_rate = cpg_sd_clock_determine_rate,
.set_rate = cpg_sd_clock_set_rate,
static const struct clk_div_table cpg_sd_div_table[] = {
{ 0, 2 }, { 1, 4 }, { 0, 0 },
};
struct clk * __init cpg_sd_clk_register(const char *name,
void __iomem *base, unsigned int offset, const char *parent_name,
struct raw_notifier_head *notifiers, bool skip_first)
void __iomem *sdnckcr, const char *parent_name)
{
struct clk_init_data init = {};
struct sd_clock *clock;
struct clk *clk;
u32 val;
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
if (!clock)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &cpg_sd_clock_ops;
init.flags = CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
clock->csn.reg = base + offset;
clock->hw.init = &init;
clock->div_table = cpg_sd_div_table;
clock->div_num = ARRAY_SIZE(cpg_sd_div_table);
if (skip_first) {
clock->div_table++;
clock->div_num--;
}
val = readl(clock->csn.reg) & ~CPG_SD_FC_MASK;
val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK);
writel(val, clock->csn.reg);
clk = clk_register(NULL, &clock->hw);
if (IS_ERR(clk))
goto free_clock;
cpg_simple_notifier_register(notifiers, &clock->csn);
return clk;
free_clock:
kfree(clock);
return clk;
return clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr,
0, 2, 0, cpg_sd_div_table, &cpg_lock);
}
struct rpc_clock {
......
......@@ -26,9 +26,12 @@ void cpg_simple_notifier_register(struct raw_notifier_head *notifiers,
void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set);
struct clk * __init cpg_sdh_clk_register(const char *name,
void __iomem *sdnckcr, const char *parent_name,
struct raw_notifier_head *notifiers);
struct clk * __init cpg_sd_clk_register(const char *name,
void __iomem *base, unsigned int offset, const char *parent_name,
struct raw_notifier_head *notifiers, bool skip_first);
void __iomem *sdnckcr, const char *parent_name);
struct clk * __init cpg_rpc_clk_register(const char *name,
void __iomem *rpcckcr, const char *parent_name,
......
......@@ -312,29 +312,20 @@ static u32 cpg_quirks __initdata;
#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */
#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */
#define SD_SKIP_FIRST BIT(2) /* Skip first clock in SD table */
static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
{
.soc_id = "r8a7795", .revision = "ES1.0",
.data = (void *)(PLL_ERRATA | RCKCR_CKSEL | SD_SKIP_FIRST),
.data = (void *)(PLL_ERRATA | RCKCR_CKSEL),
},
{
.soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)(RCKCR_CKSEL | SD_SKIP_FIRST),
},
{
.soc_id = "r8a7795", .revision = "ES2.0",
.data = (void *)SD_SKIP_FIRST,
.data = (void *)(RCKCR_CKSEL),
},
{
.soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)(RCKCR_CKSEL | SD_SKIP_FIRST),
},
{
.soc_id = "r8a7796", .revision = "ES1.1",
.data = (void *)SD_SKIP_FIRST,
.data = (void *)(RCKCR_CKSEL),
},
{ /* sentinel */ }
};
......@@ -401,10 +392,13 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
mult *= 2;
break;
case CLK_TYPE_GEN3_SDH:
return cpg_sdh_clk_register(core->name, base + core->offset,
__clk_get_name(parent), notifiers);
case CLK_TYPE_GEN3_SD:
return cpg_sd_clk_register(core->name, base, core->offset,
__clk_get_name(parent), notifiers,
cpg_quirks & SD_SKIP_FIRST);
return cpg_sd_clk_register(core->name, base + core->offset,
__clk_get_name(parent));
case CLK_TYPE_GEN3_R:
if (cpg_quirks & RCKCR_CKSEL) {
......
......@@ -17,6 +17,7 @@ enum rcar_gen3_clk_types {
CLK_TYPE_GEN3_PLL2,
CLK_TYPE_GEN3_PLL3,
CLK_TYPE_GEN3_PLL4,
CLK_TYPE_GEN3_SDH,
CLK_TYPE_GEN3_SD,
CLK_TYPE_GEN3_R,
CLK_TYPE_GEN3_MDSEL, /* Select parent/divider using mode pin */
......@@ -32,6 +33,9 @@ enum rcar_gen3_clk_types {
CLK_TYPE_GEN3_SOC_BASE,
};
#define DEF_GEN3_SDH(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_GEN3_SDH, _parent, .offset = _offset)
#define DEF_GEN3_SD(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
......
// SPDX-License-Identifier: GPL-2.0
/*
* R-Car Gen4 Clock Pulse Generator
*
* Copyright (C) 2021 Renesas Electronics Corp.
*
* Based on rcar-gen3-cpg.c
*
* Copyright (C) 2015-2018 Glider bvba
* Copyright (C) 2019 Renesas Electronics Corp.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/slab.h>
#include "renesas-cpg-mssr.h"
#include "rcar-gen4-cpg.h"
#include "rcar-cpg-lib.h"
static const struct rcar_gen4_cpg_pll_config *cpg_pll_config __initconst;
static unsigned int cpg_clk_extalr __initdata;
static u32 cpg_mode __initdata;
/*
* Z0 Clock & Z1 Clock
*/
#define CPG_FRQCRB 0x00000804
#define CPG_FRQCRB_KICK BIT(31)
#define CPG_FRQCRC 0x00000808
struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
void __iomem *kick_reg;
unsigned long max_rate; /* Maximum rate for normal mode */
unsigned int fixed_div;
u32 mask;
};
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult;
u32 val;
val = readl(zclk->reg) & zclk->mask;
mult = 32 - (val >> __ffs(zclk->mask));
return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult,
32 * zclk->fixed_div);
}
static int cpg_z_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int min_mult, max_mult, mult;
unsigned long rate, prate;
rate = min(req->rate, req->max_rate);
if (rate <= zclk->max_rate) {
/* Set parent rate to initial value for normal modes */
prate = zclk->max_rate;
} else {
/* Set increased parent rate for boost modes */
prate = rate;
}
req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
prate * zclk->fixed_div);
prate = req->best_parent_rate / zclk->fixed_div;
min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL);
max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL);
if (max_mult < min_mult)
return -EINVAL;
mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL, prate);
mult = clamp(mult, min_mult, max_mult);
req->rate = DIV_ROUND_CLOSEST_ULL((u64)prate * mult, 32);
return 0;
}
static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult;
unsigned int i;
mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div,
parent_rate);
mult = clamp(mult, 1U, 32U);
if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
return -EBUSY;
cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask));
/*
* Set KICK bit in FRQCRB to update hardware setting and wait for
* clock change completion.
*/
cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK);
/*
* Note: There is no HW information about the worst case latency.
*
* Using experimental measurements, it seems that no more than
* ~10 iterations are needed, independently of the CPU rate.
* Since this value might be dependent on external xtal rate, pll1
* rate or even the other emulation clocks rate, use 1000 as a
* "super" safe value.
*/
for (i = 1000; i; i--) {
if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
return 0;
cpu_relax();
}
return -ETIMEDOUT;
}
static const struct clk_ops cpg_z_clk_ops = {
.recalc_rate = cpg_z_clk_recalc_rate,
.determine_rate = cpg_z_clk_determine_rate,
.set_rate = cpg_z_clk_set_rate,
};
static struct clk * __init cpg_z_clk_register(const char *name,
const char *parent_name,
void __iomem *reg,
unsigned int div,
unsigned int offset)
{
struct clk_init_data init = {};
struct cpg_z_clk *zclk;
struct clk *clk;
zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
if (!zclk)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &cpg_z_clk_ops;
init.flags = CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
zclk->reg = reg + CPG_FRQCRC;
zclk->kick_reg = reg + CPG_FRQCRB;
zclk->hw.init = &init;
zclk->mask = GENMASK(offset + 4, offset);
zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */
clk = clk_register(NULL, &zclk->hw);
if (IS_ERR(clk)) {
kfree(zclk);
return clk;
}
zclk->max_rate = clk_hw_get_rate(clk_hw_get_parent(&zclk->hw)) /
zclk->fixed_div;
return clk;
}
/*
* RPC Clocks
*/
static const struct clk_div_table cpg_rpcsrc_div_table[] = {
{ 0, 4 }, { 1, 6 }, { 2, 5 }, { 3, 6 }, { 0, 0 },
};
struct clk * __init rcar_gen4_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers)
{
const struct clk *parent;
unsigned int mult = 1;
unsigned int div = 1;
u32 value;
parent = clks[core->parent & 0xffff]; /* some types use high bits */
if (IS_ERR(parent))
return ERR_CAST(parent);
switch (core->type) {
case CLK_TYPE_GEN4_MAIN:
div = cpg_pll_config->extal_div;
break;
case CLK_TYPE_GEN4_PLL1:
mult = cpg_pll_config->pll1_mult;
div = cpg_pll_config->pll1_div;
break;
case CLK_TYPE_GEN4_PLL2:
mult = cpg_pll_config->pll2_mult;
div = cpg_pll_config->pll2_div;
break;
case CLK_TYPE_GEN4_PLL3:
mult = cpg_pll_config->pll3_mult;
div = cpg_pll_config->pll3_div;
break;
case CLK_TYPE_GEN4_PLL5:
mult = cpg_pll_config->pll5_mult;
div = cpg_pll_config->pll5_div;
break;
case CLK_TYPE_GEN4_PLL6:
mult = cpg_pll_config->pll6_mult;
div = cpg_pll_config->pll6_div;
break;
case CLK_TYPE_GEN4_PLL2X_3X:
value = readl(base + core->offset);
mult = (((value >> 24) & 0x7f) + 1) * 2;
break;
case CLK_TYPE_GEN4_Z:
return cpg_z_clk_register(core->name, __clk_get_name(parent),
base, core->div, core->offset);
case CLK_TYPE_GEN4_SDSRC:
div = ((readl(base + SD0CKCR1) >> 29) & 0x03) + 4;
break;
case CLK_TYPE_GEN4_SDH:
return cpg_sdh_clk_register(core->name, base + core->offset,
__clk_get_name(parent), notifiers);
case CLK_TYPE_GEN4_SD:
return cpg_sd_clk_register(core->name, base + core->offset,
__clk_get_name(parent));
case CLK_TYPE_GEN4_MDSEL:
/*
* Clock selectable between two parents and two fixed dividers
* using a mode pin
*/
if (cpg_mode & BIT(core->offset)) {
div = core->div & 0xffff;
} else {
parent = clks[core->parent >> 16];
if (IS_ERR(parent))
return ERR_CAST(parent);
div = core->div >> 16;
}
mult = 1;
break;
case CLK_TYPE_GEN4_OSC:
/*
* Clock combining OSC EXTAL predivider and a fixed divider
*/
div = cpg_pll_config->osc_prediv * core->div;
break;
case CLK_TYPE_GEN4_RPCSRC:
return clk_register_divider_table(NULL, core->name,
__clk_get_name(parent), 0,
base + CPG_RPCCKCR, 3, 2, 0,
cpg_rpcsrc_div_table,
&cpg_lock);
case CLK_TYPE_GEN4_RPC:
return cpg_rpc_clk_register(core->name, base + CPG_RPCCKCR,
__clk_get_name(parent), notifiers);
case CLK_TYPE_GEN4_RPCD2:
return cpg_rpcd2_clk_register(core->name, base + CPG_RPCCKCR,
__clk_get_name(parent));
default:
return ERR_PTR(-EINVAL);
}
return clk_register_fixed_factor(NULL, core->name,
__clk_get_name(parent), 0, mult, div);
}
int __init rcar_gen4_cpg_init(const struct rcar_gen4_cpg_pll_config *config,
unsigned int clk_extalr, u32 mode)
{
cpg_pll_config = config;
cpg_clk_extalr = clk_extalr;
cpg_mode = mode;
spin_lock_init(&cpg_lock);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* R-Car Gen4 Clock Pulse Generator
*
* Copyright (C) 2021 Renesas Electronics Corp.
*
*/
#ifndef __CLK_RENESAS_RCAR_GEN4_CPG_H__
#define __CLK_RENESAS_RCAR_GEN4_CPG_H__
enum rcar_gen4_clk_types {
CLK_TYPE_GEN4_MAIN = CLK_TYPE_CUSTOM,
CLK_TYPE_GEN4_PLL1,
CLK_TYPE_GEN4_PLL2,
CLK_TYPE_GEN4_PLL2X_3X, /* r8a779a0 only */
CLK_TYPE_GEN4_PLL3,
CLK_TYPE_GEN4_PLL5,
CLK_TYPE_GEN4_PLL6,
CLK_TYPE_GEN4_SDSRC,
CLK_TYPE_GEN4_SDH,
CLK_TYPE_GEN4_SD,
CLK_TYPE_GEN4_MDSEL, /* Select parent/divider using mode pin */
CLK_TYPE_GEN4_Z,
CLK_TYPE_GEN4_OSC, /* OSC EXTAL predivider and fixed divider */
CLK_TYPE_GEN4_RPCSRC,
CLK_TYPE_GEN4_RPC,
CLK_TYPE_GEN4_RPCD2,
/* SoC specific definitions start here */
CLK_TYPE_GEN4_SOC_BASE,
};
#define DEF_GEN4_SDH(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_GEN4_SDH, _parent, .offset = _offset)
#define DEF_GEN4_SD(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_GEN4_SD, _parent, .offset = _offset)
#define DEF_GEN4_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \
DEF_BASE(_name, _id, CLK_TYPE_GEN4_MDSEL, \
(_parent0) << 16 | (_parent1), \
.div = (_div0) << 16 | (_div1), .offset = _md)
#define DEF_GEN4_OSC(_name, _id, _parent, _div) \
DEF_BASE(_name, _id, CLK_TYPE_GEN4_OSC, _parent, .div = _div)
#define DEF_GEN4_Z(_name, _id, _type, _parent, _div, _offset) \
DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset)
struct rcar_gen4_cpg_pll_config {
u8 extal_div;
u8 pll1_mult;
u8 pll1_div;
u8 pll2_mult;
u8 pll2_div;
u8 pll3_mult;
u8 pll3_div;
u8 pll5_mult;
u8 pll5_div;
u8 pll6_mult;
u8 pll6_div;
u8 osc_prediv;
};
#define CPG_RPCCKCR 0x874
#define SD0CKCR1 0x8a4
struct clk *rcar_gen4_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base,
struct raw_notifier_head *notifiers);
int rcar_gen4_cpg_init(const struct rcar_gen4_cpg_pll_config *config,
unsigned int clk_extalr, u32 mode);
#endif
......@@ -57,9 +57,11 @@ static const u16 mstpsr[] = {
0x9A0, 0x9A4, 0x9A8, 0x9AC,
};
static const u16 mstpsr_for_v3u[] = {
static const u16 mstpsr_for_gen4[] = {
0x2E00, 0x2E04, 0x2E08, 0x2E0C, 0x2E10, 0x2E14, 0x2E18, 0x2E1C,
0x2E20, 0x2E24, 0x2E28, 0x2E2C, 0x2E30, 0x2E34, 0x2E38,
0x2E20, 0x2E24, 0x2E28, 0x2E2C, 0x2E30, 0x2E34, 0x2E38, 0x2E3C,
0x2E40, 0x2E44, 0x2E48, 0x2E4C, 0x2E50, 0x2E54, 0x2E58, 0x2E5C,
0x2E60, 0x2E64, 0x2E68, 0x2E6C,
};
/*
......@@ -71,9 +73,11 @@ static const u16 smstpcr[] = {
0x990, 0x994, 0x998, 0x99C,
};
static const u16 mstpcr_for_v3u[] = {
static const u16 mstpcr_for_gen4[] = {
0x2D00, 0x2D04, 0x2D08, 0x2D0C, 0x2D10, 0x2D14, 0x2D18, 0x2D1C,
0x2D20, 0x2D24, 0x2D28, 0x2D2C, 0x2D30, 0x2D34, 0x2D38,
0x2D20, 0x2D24, 0x2D28, 0x2D2C, 0x2D30, 0x2D34, 0x2D38, 0x2D3C,
0x2D40, 0x2D44, 0x2D48, 0x2D4C, 0x2D50, 0x2D54, 0x2D58, 0x2D5C,
0x2D60, 0x2D64, 0x2D68, 0x2D6C,
};
/*
......@@ -95,9 +99,11 @@ static const u16 srcr[] = {
0x920, 0x924, 0x928, 0x92C,
};
static const u16 srcr_for_v3u[] = {
static const u16 srcr_for_gen4[] = {
0x2C00, 0x2C04, 0x2C08, 0x2C0C, 0x2C10, 0x2C14, 0x2C18, 0x2C1C,
0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38,
0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38, 0x2C3C,
0x2C40, 0x2C44, 0x2C48, 0x2C4C, 0x2C50, 0x2C54, 0x2C58, 0x2C5C,
0x2C60, 0x2C64, 0x2C68, 0x2C6C,
};
/*
......@@ -109,9 +115,11 @@ static const u16 srstclr[] = {
0x960, 0x964, 0x968, 0x96C,
};
static const u16 srstclr_for_v3u[] = {
static const u16 srstclr_for_gen4[] = {
0x2C80, 0x2C84, 0x2C88, 0x2C8C, 0x2C90, 0x2C94, 0x2C98, 0x2C9C,
0x2CA0, 0x2CA4, 0x2CA8, 0x2CAC, 0x2CB0, 0x2CB4, 0x2CB8,
0x2CA0, 0x2CA4, 0x2CA8, 0x2CAC, 0x2CB0, 0x2CB4, 0x2CB8, 0x2CBC,
0x2CC0, 0x2CC4, 0x2CC8, 0x2CCC, 0x2CD0, 0x2CD4, 0x2CD8, 0x2CDC,
0x2CE0, 0x2CE4, 0x2CE8, 0x2CEC,
};
/**
......@@ -158,7 +166,7 @@ struct cpg_mssr_priv {
struct {
u32 mask;
u32 val;
} smstpcr_saved[ARRAY_SIZE(mstpsr_for_v3u)];
} smstpcr_saved[ARRAY_SIZE(mstpsr_for_gen4)];
struct clk *clks[];
};
......@@ -552,6 +560,11 @@ void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev)
pm_clk_destroy(dev);
}
static void cpg_mssr_genpd_remove(void *data)
{
pm_genpd_remove(data);
}
static int __init cpg_mssr_add_clk_domain(struct device *dev,
const unsigned int *core_pm_clks,
unsigned int num_core_pm_clks)
......@@ -560,6 +573,7 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev,
struct generic_pm_domain *genpd;
struct cpg_mssr_clk_domain *pd;
size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
int ret;
pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
if (!pd)
......@@ -574,11 +588,17 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev,
GENPD_FLAG_ACTIVE_WAKEUP;
genpd->attach_dev = cpg_mssr_attach_dev;
genpd->detach_dev = cpg_mssr_detach_dev;
pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
ret = pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, cpg_mssr_genpd_remove, genpd);
if (ret)
return ret;
cpg_mssr_clk_domain = pd;
of_genpd_add_provider_simple(np, genpd);
return 0;
return of_genpd_add_provider_simple(np, genpd);
}
#ifdef CONFIG_RESET_CONTROLLER
......@@ -827,6 +847,12 @@ static const struct of_device_id cpg_mssr_match[] = {
.compatible = "renesas,r8a779a0-cpg-mssr",
.data = &r8a779a0_cpg_mssr_info,
},
#endif
#ifdef CONFIG_CLK_R8A779F0
{
.compatible = "renesas,r8a779f0-cpg-mssr",
.data = &r8a779f0_cpg_mssr_info,
},
#endif
{ /* sentinel */ }
};
......@@ -970,11 +996,11 @@ static int __init cpg_mssr_common_init(struct device *dev,
priv->reset_clear_regs = srstclr;
} else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
priv->control_regs = stbcr;
} else if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_V3U) {
priv->status_regs = mstpsr_for_v3u;
priv->control_regs = mstpcr_for_v3u;
priv->reset_regs = srcr_for_v3u;
priv->reset_clear_regs = srstclr_for_v3u;
} else if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_GEN4) {
priv->status_regs = mstpsr_for_gen4;
priv->control_regs = mstpcr_for_gen4;
priv->reset_regs = srcr_for_gen4;
priv->reset_clear_regs = srstclr_for_gen4;
} else {
error = -EINVAL;
goto out_err;
......
......@@ -88,7 +88,7 @@ struct device_node;
enum clk_reg_layout {
CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3 = 0,
CLK_REG_LAYOUT_RZ_A,
CLK_REG_LAYOUT_RCAR_V3U,
CLK_REG_LAYOUT_RCAR_GEN4,
};
/**
......@@ -178,6 +178,7 @@ extern const struct cpg_mssr_info r8a77980_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77990_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77995_cpg_mssr_info;
extern const struct cpg_mssr_info r8a779a0_cpg_mssr_info;
extern const struct cpg_mssr_info r8a779f0_cpg_mssr_info;
void __init cpg_mssr_early_init(struct device_node *np,
const struct cpg_mssr_info *info);
......
......@@ -74,6 +74,7 @@ struct sd_hw_data {
* @clks: Array containing all Core and Module Clocks
* @num_core_clks: Number of Core Clocks in clks[]
* @num_mod_clks: Number of Module Clocks in clks[]
* @num_resets: Number of Module Resets in info->resets[]
* @last_dt_core_clk: ID of the last Core Clock exported to DT
* @notifiers: Notifier chain to save/restore clock state for system resume
* @info: Pointer to platform data
......@@ -850,10 +851,16 @@ static void rzg2l_cpg_detach_dev(struct generic_pm_domain *unused, struct device
pm_clk_destroy(dev);
}
static void rzg2l_cpg_genpd_remove(void *data)
{
pm_genpd_remove(data);
}
static int __init rzg2l_cpg_add_clk_domain(struct device *dev)
{
struct device_node *np = dev->of_node;
struct generic_pm_domain *genpd;
int ret;
genpd = devm_kzalloc(dev, sizeof(*genpd), GFP_KERNEL);
if (!genpd)
......@@ -864,10 +871,15 @@ static int __init rzg2l_cpg_add_clk_domain(struct device *dev)
GENPD_FLAG_ACTIVE_WAKEUP;
genpd->attach_dev = rzg2l_cpg_attach_dev;
genpd->detach_dev = rzg2l_cpg_detach_dev;
pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
ret = pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
if (ret)
return ret;
of_genpd_add_provider_simple(np, genpd);
return 0;
ret = devm_add_action_or_reset(dev, rzg2l_cpg_genpd_remove, genpd);
if (ret)
return ret;
return of_genpd_add_provider_simple(np, genpd);
}
static int __init rzg2l_cpg_probe(struct platform_device *pdev)
......
......@@ -9,11 +9,14 @@
#ifndef __RENESAS_RZG2L_CPG_H__
#define __RENESAS_RZG2L_CPG_H__
#define CPG_PL1_DDIV (0x200)
#define CPG_PL2_DDIV (0x204)
#define CPG_PL3A_DDIV (0x208)
#define CPG_PL6_DDIV (0x210)
#define CPG_PL2SDHI_DSEL (0x218)
#define CPG_CLKSTATUS (0x280)
#define CPG_PL3_SSEL (0x408)
#define CPG_PL6_SSEL (0x414)
#define CPG_PL6_ETH_SSEL (0x418)
#define CPG_CLKSTATUS_SELSDHI0_STS BIT(28)
......@@ -29,16 +32,19 @@
#define DDIV_PACK(offset, bitpos, size) \
(((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
#define DIVPL1A DDIV_PACK(CPG_PL1_DDIV, 0, 2)
#define DIVPL2A DDIV_PACK(CPG_PL2_DDIV, 0, 3)
#define DIVPL3A DDIV_PACK(CPG_PL3A_DDIV, 0, 3)
#define DIVPL3B DDIV_PACK(CPG_PL3A_DDIV, 4, 3)
#define DIVPL3C DDIV_PACK(CPG_PL3A_DDIV, 8, 3)
#define DIVGPU DDIV_PACK(CPG_PL6_DDIV, 0, 2)
#define SEL_PLL_PACK(offset, bitpos, size) \
(((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
#define SEL_PLL3_3 SEL_PLL_PACK(CPG_PL3_SSEL, 8, 1)
#define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1)
#define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1)
#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2)
#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2)
......@@ -168,6 +174,9 @@ struct rzg2l_reset {
* @num_mod_clks: Number of entries in mod_clks[]
* @num_hw_mod_clks: Number of Module Clocks supported by the hardware
*
* @resets: Array of Module Reset definitions
* @num_resets: Number of entries in resets[]
*
* @crit_mod_clks: Array with Module Clock IDs of critical clocks that
* should not be disabled without a knowledgeable driver
* @num_crit_mod_clks: Number of entries in crit_mod_clks[]
......
......@@ -807,7 +807,7 @@ static int ti_adpll_init_registers(struct ti_adpll_data *d)
static int ti_adpll_init_inputs(struct ti_adpll_data *d)
{
const char *error = "need at least %i inputs";
static const char error[] = "need at least %i inputs";
struct clk *clock;
int nr_inputs;
......
......@@ -18,6 +18,8 @@ struct renesas_sdhi_scc {
u32 tap_hs400_4tap; /* sampling clock position for HS400 (4 TAP) */
};
#define SDHI_FLAG_NEED_CLKH_FALLBACK BIT(0)
struct renesas_sdhi_of_data {
unsigned long tmio_flags;
u32 tmio_ocr_mask;
......@@ -31,6 +33,7 @@ struct renesas_sdhi_of_data {
int taps_num;
unsigned int max_blk_count;
unsigned short max_segs;
unsigned long sdhi_flags;
};
#define SDHI_CALIB_TABLE_MAX 32
......@@ -57,6 +60,7 @@ struct tmio_mmc_dma {
struct renesas_sdhi {
struct clk *clk;
struct clk *clkh;
struct clk *clk_cd;
struct tmio_mmc_data mmc_data;
struct tmio_mmc_dma dma_priv;
......
......@@ -127,10 +127,12 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
}
static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
unsigned int new_clock)
unsigned int wanted_clock)
{
struct renesas_sdhi *priv = host_to_priv(host);
struct clk *ref_clk = priv->clk;
unsigned int freq, diff, best_freq = 0, diff_min = ~0;
unsigned int new_clock, clkh_shift = 0;
int i;
/*
......@@ -141,6 +143,16 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc))
return clk_get_rate(priv->clk);
if (priv->clkh) {
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
bool need_slow_clkh = (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) ||
(host->mmc->ios.timing == MMC_TIMING_MMC_HS400);
clkh_shift = use_4tap && need_slow_clkh ? 1 : 2;
ref_clk = priv->clkh;
}
new_clock = wanted_clock << clkh_shift;
/*
* We want the bus clock to be as close as possible to, but no
* greater than, new_clock. As we can divide by 1 << i for
......@@ -148,11 +160,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
* possible, but no greater than, new_clock << i.
*/
for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
freq = clk_round_rate(priv->clk, new_clock << i);
freq = clk_round_rate(ref_clk, new_clock << i);
if (freq > (new_clock << i)) {
/* Too fast; look for a slightly slower option */
freq = clk_round_rate(priv->clk,
(new_clock << i) / 4 * 3);
freq = clk_round_rate(ref_clk, (new_clock << i) / 4 * 3);
if (freq > (new_clock << i))
continue;
}
......@@ -164,7 +175,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
}
}
clk_set_rate(priv->clk, best_freq);
clk_set_rate(ref_clk, best_freq);
if (priv->clkh)
clk_set_rate(priv->clk, best_freq >> clkh_shift);
return clk_get_rate(priv->clk);
}
......@@ -904,11 +918,12 @@ int renesas_sdhi_probe(struct platform_device *pdev,
dma_priv = &priv->dma_priv;
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
return ret;
}
if (IS_ERR(priv->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), "cannot get clock");
priv->clkh = devm_clk_get_optional(&pdev->dev, "clkh");
if (IS_ERR(priv->clkh))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clkh), "cannot get clkh");
/*
* Some controllers provide a 2nd clock just to run the internal card
......@@ -921,9 +936,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
* to the card detect circuit. That leaves us with if separate clocks
* are presented, we must treat them both as virtually 1 clock.
*/
priv->clk_cd = devm_clk_get(&pdev->dev, "cd");
priv->clk_cd = devm_clk_get_optional(&pdev->dev, "cd");
if (IS_ERR(priv->clk_cd))
priv->clk_cd = NULL;
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cd), "cannot get cd clock");
priv->pinctrl = devm_pinctrl_get(&pdev->dev);
if (!IS_ERR(priv->pinctrl)) {
......@@ -947,6 +962,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->max_segs = of_data->max_segs;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
/* Fallback for old DTs */
if (!priv->clkh && of_data->sdhi_flags & SDHI_FLAG_NEED_CLKH_FALLBACK)
priv->clkh = clk_get_parent(clk_get_parent(priv->clk));
}
host->write16_hook = renesas_sdhi_write16_hook;
......@@ -1044,7 +1063,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR |
MMC_CAP2_HS400_1_8V))) {
const struct renesas_sdhi_scc *taps = of_data->taps;
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
bool use_4tap = quirks && quirks->hs400_4taps;
bool hit = false;
for (i = 0; i < of_data->taps_num; i++) {
......
......@@ -125,6 +125,22 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3 = {
/* DMAC can handle 32bit blk count but only 1 segment */
.max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE,
.max_segs = 1,
.sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK,
};
static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_fallback = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
.bus_shift = 2,
.scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
/* DMAC can handle 32bit blk count but only 1 segment */
.max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE,
.max_segs = 1,
};
static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = {
......@@ -214,6 +230,10 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77965_compatible = {
.quirks = &sdhi_quirks_r8a77965,
};
static const struct renesas_sdhi_of_data_with_quirks of_r8a77970_compatible = {
.of_data = &of_data_rcar_gen3_no_fallback,
};
static const struct renesas_sdhi_of_data_with_quirks of_r8a77980_compatible = {
.of_data = &of_data_rcar_gen3,
.quirks = &sdhi_quirks_nohs400,
......@@ -235,6 +255,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, },
{ .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, },
{ .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, },
{ .compatible = "renesas,sdhi-r8a77980", .data = &of_r8a77980_compatible, },
{ .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
......
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Copyright (c) 2021 Microchip Inc.
*
* Author: Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
*/
#ifndef _DT_BINDINGS_CLK_LAN966X_H
#define _DT_BINDINGS_CLK_LAN966X_H
#define GCK_ID_QSPI0 0
#define GCK_ID_QSPI1 1
#define GCK_ID_QSPI2 2
#define GCK_ID_SDMMC0 3
#define GCK_ID_PI 4
#define GCK_ID_MCAN0 5
#define GCK_ID_MCAN1 6
#define GCK_ID_FLEXCOM0 7
#define GCK_ID_FLEXCOM1 8
#define GCK_ID_FLEXCOM2 9
#define GCK_ID_FLEXCOM3 10
#define GCK_ID_FLEXCOM4 11
#define GCK_ID_TIMER 12
#define GCK_ID_USB_REFCLK 13
/* Gate clocks */
#define GCK_GATE_UHPHS 14
#define GCK_GATE_UDPHS 15
#define GCK_GATE_MCRAMC 16
#define GCK_GATE_HMATRIX 17
#define N_CLOCKS 18
#endif
/* SPDX-License-Identifier: (GPL-2.0 or MIT) */
/*
* Copyright (C) 2021 Renesas Electronics Corp.
*/
#ifndef __DT_BINDINGS_CLOCK_R8A779F0_CPG_MSSR_H__
#define __DT_BINDINGS_CLOCK_R8A779F0_CPG_MSSR_H__
#include <dt-bindings/clock/renesas-cpg-mssr.h>
/* r8a779f0 CPG Core Clocks */
#define R8A779F0_CLK_ZX 0
#define R8A779F0_CLK_ZS 1
#define R8A779F0_CLK_ZT 2
#define R8A779F0_CLK_ZTR 3
#define R8A779F0_CLK_S0D2 4
#define R8A779F0_CLK_S0D3 5
#define R8A779F0_CLK_S0D4 6
#define R8A779F0_CLK_S0D2_MM 7
#define R8A779F0_CLK_S0D3_MM 8
#define R8A779F0_CLK_S0D4_MM 9
#define R8A779F0_CLK_S0D2_RT 10
#define R8A779F0_CLK_S0D3_RT 11
#define R8A779F0_CLK_S0D4_RT 12
#define R8A779F0_CLK_S0D6_RT 13
#define R8A779F0_CLK_S0D3_PER 14
#define R8A779F0_CLK_S0D6_PER 15
#define R8A779F0_CLK_S0D12_PER 16
#define R8A779F0_CLK_S0D24_PER 17
#define R8A779F0_CLK_S0D2_HSC 18
#define R8A779F0_CLK_S0D3_HSC 19
#define R8A779F0_CLK_S0D4_HSC 20
#define R8A779F0_CLK_S0D6_HSC 21
#define R8A779F0_CLK_S0D12_HSC 22
#define R8A779F0_CLK_S0D2_CC 23
#define R8A779F0_CLK_CL 24
#define R8A779F0_CLK_CL16M 25
#define R8A779F0_CLK_CL16M_MM 26
#define R8A779F0_CLK_CL16M_RT 27
#define R8A779F0_CLK_CL16M_PER 28
#define R8A779F0_CLK_CL16M_HSC 29
#define R8A779F0_CLK_Z0 30
#define R8A779F0_CLK_Z1 31
#define R8A779F0_CLK_ZB3 32
#define R8A779F0_CLK_ZB3D2 33
#define R8A779F0_CLK_ZB3D4 34
#define R8A779F0_CLK_SD0H 35
#define R8A779F0_CLK_SD0 36
#define R8A779F0_CLK_RPC 37
#define R8A779F0_CLK_RPCD2 38
#define R8A779F0_CLK_MSO 39
#define R8A779F0_CLK_SASYNCRT 40
#define R8A779F0_CLK_SASYNCPERD1 41
#define R8A779F0_CLK_SASYNCPERD2 42
#define R8A779F0_CLK_SASYNCPERD4 43
#define R8A779F0_CLK_DBGSOC_HSC 44
#define R8A779F0_CLK_RSW2 45
#define R8A779F0_CLK_OSC 46
#define R8A779F0_CLK_ZR 47
#define R8A779F0_CLK_CPEX 48
#define R8A779F0_CLK_CBFUSA 49
#define R8A779F0_CLK_R 50
#endif /* __DT_BINDINGS_CLOCK_R8A779F0_CPG_MSSR_H__ */
/* SPDX-License-Identifier: (GPL-2.0 or MIT) */
/*
* Copyright (C) 2021 Renesas Electronics Corp.
*/
#ifndef __DT_BINDINGS_POWER_R8A779F0_SYSC_H__
#define __DT_BINDINGS_POWER_R8A779F0_SYSC_H__
/*
* These power domain indices match the Power Domain Register Numbers (PDR)
*/
#define R8A779F0_PD_A1E0D0C0 0
#define R8A779F0_PD_A1E0D0C1 1
#define R8A779F0_PD_A1E0D1C0 2
#define R8A779F0_PD_A1E0D1C1 3
#define R8A779F0_PD_A1E1D0C0 4
#define R8A779F0_PD_A1E1D0C1 5
#define R8A779F0_PD_A1E1D1C0 6
#define R8A779F0_PD_A1E1D1C1 7
#define R8A779F0_PD_A2E0D0 16
#define R8A779F0_PD_A2E0D1 17
#define R8A779F0_PD_A2E1D0 18
#define R8A779F0_PD_A2E1D1 19
#define R8A779F0_PD_A3E0 20
#define R8A779F0_PD_A3E1 21
/* Always-on power area */
#define R8A779F0_PD_ALWAYS_ON 64
#endif /* __DT_BINDINGS_POWER_R8A779A0_SYSC_H__*/
......@@ -490,6 +490,13 @@ struct clk_hw *__clk_hw_register_gate(struct device *dev,
unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock);
struct clk_hw *__devm_clk_hw_register_gate(struct device *dev,
struct device_node *np, const char *name,
const char *parent_name, const struct clk_hw *parent_hw,
const struct clk_parent_data *parent_data,
unsigned long flags,
void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock);
struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx,
......@@ -544,6 +551,22 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
__clk_hw_register_gate((dev), NULL, (name), NULL, NULL, (parent_data), \
(flags), (reg), (bit_idx), \
(clk_gate_flags), (lock))
/**
* devm_clk_hw_register_gate - register a gate 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
* @flags: framework-specific flags for this clock
* @reg: register address to control gating of this clock
* @bit_idx: which bit in the register controls gating of this clock
* @clk_gate_flags: gate-specific flags for this clock
* @lock: shared register lock for this clock
*/
#define devm_clk_hw_register_gate(dev, name, parent_name, flags, reg, bit_idx,\
clk_gate_flags, lock) \
__devm_clk_hw_register_gate((dev), NULL, (name), (parent_name), NULL, \
NULL, (flags), (reg), (bit_idx), \
(clk_gate_flags), (lock))
void clk_unregister_gate(struct clk *clk);
void clk_hw_unregister_gate(struct clk_hw *hw);
int clk_gate_is_enabled(struct clk_hw *hw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment