Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,9 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o

View file

@ -0,0 +1,185 @@
/*
* r8a7790 Common Clock Framework support
*
* Copyright (C) 2013 Renesas Solutions Corp.
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#define CPG_DIV6_CKSTP BIT(8)
#define CPG_DIV6_DIV(d) ((d) & 0x3f)
#define CPG_DIV6_DIV_MASK 0x3f
/**
* struct div6_clock - CPG 6 bit divider clock
* @hw: handle between common and hardware-specific interfaces
* @reg: IO-remapped register
* @div: divisor value (1-64)
*/
struct div6_clock {
struct clk_hw hw;
void __iomem *reg;
unsigned int div;
};
#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
static int cpg_div6_clock_enable(struct clk_hw *hw)
{
struct div6_clock *clock = to_div6_clock(hw);
clk_writel(CPG_DIV6_DIV(clock->div - 1), clock->reg);
return 0;
}
static void cpg_div6_clock_disable(struct clk_hw *hw)
{
struct div6_clock *clock = to_div6_clock(hw);
/* DIV6 clocks require the divisor field to be non-zero when stopping
* the clock.
*/
clk_writel(CPG_DIV6_CKSTP | CPG_DIV6_DIV(CPG_DIV6_DIV_MASK),
clock->reg);
}
static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
{
struct div6_clock *clock = to_div6_clock(hw);
return !(clk_readl(clock->reg) & CPG_DIV6_CKSTP);
}
static unsigned long cpg_div6_clock_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct div6_clock *clock = to_div6_clock(hw);
unsigned int div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
return parent_rate / div;
}
static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
unsigned long parent_rate)
{
unsigned int div;
div = DIV_ROUND_CLOSEST(parent_rate, rate);
return clamp_t(unsigned int, div, 1, 64);
}
static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned int div = cpg_div6_clock_calc_div(rate, *parent_rate);
return *parent_rate / div;
}
static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct div6_clock *clock = to_div6_clock(hw);
unsigned int div = cpg_div6_clock_calc_div(rate, parent_rate);
clock->div = div;
/* Only program the new divisor if the clock isn't stopped. */
if (!(clk_readl(clock->reg) & CPG_DIV6_CKSTP))
clk_writel(CPG_DIV6_DIV(clock->div - 1), clock->reg);
return 0;
}
static const struct clk_ops cpg_div6_clock_ops = {
.enable = cpg_div6_clock_enable,
.disable = cpg_div6_clock_disable,
.is_enabled = cpg_div6_clock_is_enabled,
.recalc_rate = cpg_div6_clock_recalc_rate,
.round_rate = cpg_div6_clock_round_rate,
.set_rate = cpg_div6_clock_set_rate,
};
static void __init cpg_div6_clock_init(struct device_node *np)
{
struct clk_init_data init;
struct div6_clock *clock;
const char *parent_name;
const char *name;
struct clk *clk;
int ret;
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
if (!clock) {
pr_err("%s: failed to allocate %s DIV6 clock\n",
__func__, np->name);
return;
}
/* Remap the clock register and read the divisor. Disabling the
* clock overwrites the divisor, so we need to cache its value for the
* enable operation.
*/
clock->reg = of_iomap(np, 0);
if (clock->reg == NULL) {
pr_err("%s: failed to map %s DIV6 clock register\n",
__func__, np->name);
goto error;
}
clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
/* Parse the DT properties. */
ret = of_property_read_string(np, "clock-output-names", &name);
if (ret < 0) {
pr_err("%s: failed to get %s DIV6 clock output name\n",
__func__, np->name);
goto error;
}
parent_name = of_clk_get_parent_name(np, 0);
if (parent_name == NULL) {
pr_err("%s: failed to get %s DIV6 clock parent name\n",
__func__, np->name);
goto error;
}
/* Register the clock. */
init.name = name;
init.ops = &cpg_div6_clock_ops;
init.flags = CLK_IS_BASIC;
init.parent_names = &parent_name;
init.num_parents = 1;
clock->hw.init = &init;
clk = clk_register(NULL, &clock->hw);
if (IS_ERR(clk)) {
pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
__func__, np->name, PTR_ERR(clk));
goto error;
}
of_clk_add_provider(np, of_clk_src_simple_get, clk);
return;
error:
if (clock->reg)
iounmap(clock->reg);
kfree(clock);
}
CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);

View file

@ -0,0 +1,104 @@
/*
* EMMA Mobile EV2 common clock framework support
*
* Copyright (C) 2013 Takashi Yoshii <takashi.yoshii.ze@renesas.com>
* Copyright (C) 2012 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
/* EMEV2 SMU registers */
#define USIAU0_RSTCTRL 0x094
#define USIBU1_RSTCTRL 0x0ac
#define USIBU2_RSTCTRL 0x0b0
#define USIBU3_RSTCTRL 0x0b4
#define STI_RSTCTRL 0x124
#define STI_CLKSEL 0x688
static DEFINE_SPINLOCK(lock);
/* not pretty, but hey */
void __iomem *smu_base;
static void __init emev2_smu_write(unsigned long value, int offs)
{
BUG_ON(!smu_base || (offs >= PAGE_SIZE));
writel_relaxed(value, smu_base + offs);
}
static const struct of_device_id smu_id[] __initconst = {
{ .compatible = "renesas,emev2-smu", },
{},
};
static void __init emev2_smu_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, smu_id);
BUG_ON(!np);
smu_base = of_iomap(np, 0);
BUG_ON(!smu_base);
of_node_put(np);
/* setup STI timer to run on 32.768 kHz and deassert reset */
emev2_smu_write(0, STI_CLKSEL);
emev2_smu_write(1, STI_RSTCTRL);
/* deassert reset for UART0->UART3 */
emev2_smu_write(2, USIAU0_RSTCTRL);
emev2_smu_write(2, USIBU1_RSTCTRL);
emev2_smu_write(2, USIBU2_RSTCTRL);
emev2_smu_write(2, USIBU3_RSTCTRL);
}
static void __init emev2_smu_clkdiv_init(struct device_node *np)
{
u32 reg[2];
struct clk *clk;
const char *parent_name = of_clk_get_parent_name(np, 0);
if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2)))
return;
if (!smu_base)
emev2_smu_init();
clk = clk_register_divider(NULL, np->name, parent_name, 0,
smu_base + reg[0], reg[1], 8, 0, &lock);
of_clk_add_provider(np, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, np->name, NULL);
pr_debug("## %s %s %p\n", __func__, np->name, clk);
}
CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv",
emev2_smu_clkdiv_init);
static void __init emev2_smu_gclk_init(struct device_node *np)
{
u32 reg[2];
struct clk *clk;
const char *parent_name = of_clk_get_parent_name(np, 0);
if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2)))
return;
if (!smu_base)
emev2_smu_init();
clk = clk_register_gate(NULL, np->name, parent_name, 0,
smu_base + reg[0], reg[1], 0, &lock);
of_clk_add_provider(np, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, np->name, NULL);
pr_debug("## %s %s %p\n", __func__, np->name, clk);
}
CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init);

View file

@ -0,0 +1,238 @@
/*
* R-Car MSTP clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
/*
* MSTP clocks. We can't use standard gate clocks as we need to poll on the
* status register when enabling the clock.
*/
#define MSTP_MAX_CLOCKS 32
/**
* struct mstp_clock_group - MSTP gating clocks group
*
* @data: clocks in this group
* @smstpcr: module stop control register
* @mstpsr: module stop status register (optional)
* @lock: protects writes to SMSTPCR
*/
struct mstp_clock_group {
struct clk_onecell_data data;
void __iomem *smstpcr;
void __iomem *mstpsr;
spinlock_t lock;
};
/**
* struct mstp_clock - MSTP gating clock
* @hw: handle between common and hardware-specific interfaces
* @bit_index: control bit index
* @group: MSTP clocks group
*/
struct mstp_clock {
struct clk_hw hw;
u32 bit_index;
struct mstp_clock_group *group;
};
#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
{
struct mstp_clock *clock = to_mstp_clock(hw);
struct mstp_clock_group *group = clock->group;
u32 bitmask = BIT(clock->bit_index);
unsigned long flags;
unsigned int i;
u32 value;
spin_lock_irqsave(&group->lock, flags);
value = clk_readl(group->smstpcr);
if (enable)
value &= ~bitmask;
else
value |= bitmask;
clk_writel(value, group->smstpcr);
spin_unlock_irqrestore(&group->lock, flags);
if (!enable || !group->mstpsr)
return 0;
for (i = 1000; i > 0; --i) {
if (!(clk_readl(group->mstpsr) & bitmask))
break;
cpu_relax();
}
if (!i) {
pr_err("%s: failed to enable %p[%d]\n", __func__,
group->smstpcr, clock->bit_index);
return -ETIMEDOUT;
}
return 0;
}
static int cpg_mstp_clock_enable(struct clk_hw *hw)
{
return cpg_mstp_clock_endisable(hw, true);
}
static void cpg_mstp_clock_disable(struct clk_hw *hw)
{
cpg_mstp_clock_endisable(hw, false);
}
static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
{
struct mstp_clock *clock = to_mstp_clock(hw);
struct mstp_clock_group *group = clock->group;
u32 value;
if (group->mstpsr)
value = clk_readl(group->mstpsr);
else
value = clk_readl(group->smstpcr);
return !(value & BIT(clock->bit_index));
}
static const struct clk_ops cpg_mstp_clock_ops = {
.enable = cpg_mstp_clock_enable,
.disable = cpg_mstp_clock_disable,
.is_enabled = cpg_mstp_clock_is_enabled,
};
static struct clk * __init
cpg_mstp_clock_register(const char *name, const char *parent_name,
unsigned int index, struct mstp_clock_group *group)
{
struct clk_init_data init;
struct mstp_clock *clock;
struct clk *clk;
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
if (!clock) {
pr_err("%s: failed to allocate MSTP clock.\n", __func__);
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &cpg_mstp_clock_ops;
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
clock->bit_index = index;
clock->group = group;
clock->hw.init = &init;
clk = clk_register(NULL, &clock->hw);
if (IS_ERR(clk))
kfree(clock);
return clk;
}
static void __init cpg_mstp_clocks_init(struct device_node *np)
{
struct mstp_clock_group *group;
const char *idxname;
struct clk **clks;
unsigned int i;
group = kzalloc(sizeof(*group), GFP_KERNEL);
clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL);
if (group == NULL || clks == NULL) {
kfree(group);
kfree(clks);
pr_err("%s: failed to allocate group\n", __func__);
return;
}
spin_lock_init(&group->lock);
group->data.clks = clks;
group->smstpcr = of_iomap(np, 0);
group->mstpsr = of_iomap(np, 1);
if (group->smstpcr == NULL) {
pr_err("%s: failed to remap SMSTPCR\n", __func__);
kfree(group);
kfree(clks);
return;
}
for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
clks[i] = ERR_PTR(-ENOENT);
if (of_find_property(np, "clock-indices", &i))
idxname = "clock-indices";
else
idxname = "renesas,clock-indices";
for (i = 0; i < MSTP_MAX_CLOCKS; ++i) {
const char *parent_name;
const char *name;
u32 clkidx;
int ret;
/* Skip clocks with no name. */
ret = of_property_read_string_index(np, "clock-output-names",
i, &name);
if (ret < 0 || strlen(name) == 0)
continue;
parent_name = of_clk_get_parent_name(np, i);
ret = of_property_read_u32_index(np, idxname, i, &clkidx);
if (parent_name == NULL || ret < 0)
break;
if (clkidx >= MSTP_MAX_CLOCKS) {
pr_err("%s: invalid clock %s %s index %u)\n",
__func__, np->name, name, clkidx);
continue;
}
clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
clkidx, group);
if (!IS_ERR(clks[clkidx])) {
group->data.clk_num = max(group->data.clk_num,
clkidx + 1);
/*
* Register a clkdev to let board code retrieve the
* clock by name and register aliases for non-DT
* devices.
*
* FIXME: Remove this when all devices that require a
* clock will be instantiated from DT.
*/
clk_register_clkdev(clks[clkidx], name, NULL);
} else {
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clks[clkidx]));
}
}
of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
}
CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init);

View file

@ -0,0 +1,199 @@
/*
* r8a7740 Core CPG Clocks
*
* Copyright (C) 2014 Ulrich Hecht
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
struct r8a7740_cpg {
struct clk_onecell_data data;
spinlock_t lock;
void __iomem *reg;
};
#define CPG_FRQCRA 0x00
#define CPG_FRQCRB 0x04
#define CPG_PLLC2CR 0x2c
#define CPG_USBCKCR 0x8c
#define CPG_FRQCRC 0xe0
#define CLK_ENABLE_ON_INIT BIT(0)
struct div4_clk {
const char *name;
unsigned int reg;
unsigned int shift;
int flags;
};
static struct div4_clk div4_clks[] = {
{ "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT },
{ "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT },
{ "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT },
{ "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT },
{ "hp", CPG_FRQCRB, 4, 0 },
{ "hpp", CPG_FRQCRC, 20, 0 },
{ "usbp", CPG_FRQCRC, 16, 0 },
{ "s", CPG_FRQCRC, 12, 0 },
{ "zb", CPG_FRQCRC, 8, 0 },
{ "m3", CPG_FRQCRC, 4, 0 },
{ "cp", CPG_FRQCRC, 0, 0 },
{ NULL, 0, 0, 0 },
};
static const struct clk_div_table div4_div_table[] = {
{ 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
{ 6, 16 }, { 7, 18 }, { 8, 24 }, { 9, 32 }, { 10, 36 }, { 11, 48 },
{ 13, 72 }, { 14, 96 }, { 0, 0 }
};
static u32 cpg_mode __initdata;
static struct clk * __init
r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
const char *name)
{
const struct clk_div_table *table = NULL;
const char *parent_name;
unsigned int shift, reg;
unsigned int mult = 1;
unsigned int div = 1;
if (!strcmp(name, "r")) {
switch (cpg_mode & (BIT(2) | BIT(1))) {
case BIT(1) | BIT(2):
/* extal1 */
parent_name = of_clk_get_parent_name(np, 0);
div = 2048;
break;
case BIT(2):
/* extal1 */
parent_name = of_clk_get_parent_name(np, 0);
div = 1024;
break;
default:
/* extalr */
parent_name = of_clk_get_parent_name(np, 2);
break;
}
} else if (!strcmp(name, "system")) {
parent_name = of_clk_get_parent_name(np, 0);
if (cpg_mode & BIT(1))
div = 2;
} else if (!strcmp(name, "pllc0")) {
/* PLLC0/1 are configurable multiplier clocks. Register them as
* fixed factor clocks for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
parent_name = "system";
mult = ((value >> 24) & 0x7f) + 1;
} else if (!strcmp(name, "pllc1")) {
u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
parent_name = "system";
mult = ((value >> 24) & 0x7f) + 1;
div = 2;
} else if (!strcmp(name, "pllc2")) {
u32 value = clk_readl(cpg->reg + CPG_PLLC2CR);
parent_name = "system";
mult = ((value >> 24) & 0x3f) + 1;
} else if (!strcmp(name, "usb24s")) {
u32 value = clk_readl(cpg->reg + CPG_USBCKCR);
if (value & BIT(7))
/* extal2 */
parent_name = of_clk_get_parent_name(np, 1);
else
parent_name = "system";
if (!(value & BIT(6)))
div = 2;
} else {
struct div4_clk *c;
for (c = div4_clks; c->name; c++) {
if (!strcmp(name, c->name)) {
parent_name = "pllc1";
table = div4_div_table;
reg = c->reg;
shift = c->shift;
break;
}
}
if (!c->name)
return ERR_PTR(-EINVAL);
}
if (!table) {
return clk_register_fixed_factor(NULL, name, parent_name, 0,
mult, div);
} else {
return clk_register_divider_table(NULL, name, parent_name, 0,
cpg->reg + reg, shift, 4, 0,
table, &cpg->lock);
}
}
static void __init r8a7740_cpg_clocks_init(struct device_node *np)
{
struct r8a7740_cpg *cpg;
struct clk **clks;
unsigned int i;
int num_clks;
if (of_property_read_u32(np, "renesas,mode", &cpg_mode))
pr_warn("%s: missing renesas,mode property\n", __func__);
num_clks = of_property_count_strings(np, "clock-output-names");
if (num_clks < 0) {
pr_err("%s: failed to count clocks\n", __func__);
return;
}
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
if (cpg == NULL || clks == NULL) {
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won't boot anyway.
*/
return;
}
spin_lock_init(&cpg->lock);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
cpg->reg = of_iomap(np, 0);
if (WARN_ON(cpg->reg == NULL))
return;
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i,
&name);
clk = r8a7740_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
r8a7740_cpg_clocks_init);

View file

@ -0,0 +1,180 @@
/*
* r8a7779 Core CPG Clocks
*
* Copyright (C) 2013, 2014 Horms Solutions Ltd.
*
* Contact: Simon Horman <horms@verge.net.au>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/r8a7779-clock.h>
#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1)
struct r8a7779_cpg {
struct clk_onecell_data data;
spinlock_t lock;
void __iomem *reg;
};
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
/*
* MD1 = 1 MD1 = 0
* (PLLA = 1500) (PLLA = 1600)
* (MHz) (MHz)
*------------------------------------------------+--------------------
* clkz 1000 (2/3) 800 (1/2)
* clkzs 250 (1/6) 200 (1/8)
* clki 750 (1/2) 800 (1/2)
* clks 250 (1/6) 200 (1/8)
* clks1 125 (1/12) 100 (1/16)
* clks3 187.5 (1/8) 200 (1/8)
* clks4 93.7 (1/16) 100 (1/16)
* clkp 62.5 (1/24) 50 (1/32)
* clkg 62.5 (1/24) 66.6 (1/24)
* clkb, CLKOUT
* (MD2 = 0) 62.5 (1/24) 66.6 (1/24)
* (MD2 = 1) 41.6 (1/36) 50 (1/32)
*/
#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1)
struct cpg_clk_config {
unsigned int z_mult;
unsigned int z_div;
unsigned int zs_and_s_div;
unsigned int s1_div;
unsigned int p_div;
unsigned int b_and_out_div;
};
static const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
{ 1, 2, 8, 16, 32, 24 },
{ 2, 3, 6, 12, 24, 24 },
{ 1, 2, 8, 16, 32, 32 },
{ 2, 3, 6, 12, 24, 36 },
};
/*
* MD PLLA Ratio
* 12 11
*------------------------
* 0 0 x42
* 0 1 x48
* 1 0 x56
* 1 1 x64
*/
#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11)
static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
/* -----------------------------------------------------------------------------
* Initialization
*/
static u32 cpg_mode __initdata;
static struct clk * __init
r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
const struct cpg_clk_config *config,
unsigned int plla_mult, const char *name)
{
const char *parent_name = "plla";
unsigned int mult = 1;
unsigned int div = 1;
if (!strcmp(name, "plla")) {
parent_name = of_clk_get_parent_name(np, 0);
mult = plla_mult;
} else if (!strcmp(name, "z")) {
div = config->z_div;
mult = config->z_mult;
} else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
div = config->zs_and_s_div;
} else if (!strcmp(name, "s1")) {
div = config->s1_div;
} else if (!strcmp(name, "p")) {
div = config->p_div;
} else if (!strcmp(name, "b") || !strcmp(name, "out")) {
div = config->b_and_out_div;
} else {
return ERR_PTR(-EINVAL);
}
return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
}
static void __init r8a7779_cpg_clocks_init(struct device_node *np)
{
const struct cpg_clk_config *config;
struct r8a7779_cpg *cpg;
struct clk **clks;
unsigned int i, plla_mult;
int num_clks;
num_clks = of_property_count_strings(np, "clock-output-names");
if (num_clks < 0) {
pr_err("%s: failed to count clocks\n", __func__);
return;
}
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL);
if (cpg == NULL || clks == NULL) {
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won't boot anyway.
*/
return;
}
spin_lock_init(&cpg->lock);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i,
&name);
clk = r8a7779_cpg_register_clock(np, cpg, config,
plla_mult, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
r8a7779_cpg_clocks_init);
void __init r8a7779_clocks_init(u32 mode)
{
cpg_mode = mode;
of_clk_init(NULL);
}

View file

@ -0,0 +1,339 @@
/*
* rcar_gen2 Core CPG Clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
struct rcar_gen2_cpg {
struct clk_onecell_data data;
spinlock_t lock;
void __iomem *reg;
};
#define CPG_FRQCRB 0x00000004
#define CPG_FRQCRB_KICK BIT(31)
#define CPG_SDCKCR 0x00000074
#define CPG_PLL0CR 0x000000d8
#define CPG_FRQCRC 0x000000e0
#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
#define CPG_FRQCRC_ZFC_SHIFT 8
/* -----------------------------------------------------------------------------
* Z Clock
*
* Traits of this clock:
* prepare - clk_prepare only ensures that parents are prepared
* enable - clk_enable only ensures that parents are enabled
* rate - rate is adjustable. clk->rate = parent->rate * mult / 32
* parent - fixed parent. No clk_set_parent support
*/
struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
void __iomem *kick_reg;
};
#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;
unsigned int val;
val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK)
>> CPG_FRQCRC_ZFC_SHIFT;
mult = 32 - val;
return div_u64((u64)parent_rate * mult, 32);
}
static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long prate = *parent_rate;
unsigned int mult;
if (!prate)
prate = 1;
mult = div_u64((u64)rate * 32, prate);
mult = clamp(mult, 1U, 32U);
return *parent_rate / 32 * mult;
}
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;
u32 val, kick;
unsigned int i;
mult = div_u64((u64)rate * 32, parent_rate);
mult = clamp(mult, 1U, 32U);
if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
return -EBUSY;
val = clk_readl(zclk->reg);
val &= ~CPG_FRQCRC_ZFC_MASK;
val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
clk_writel(val, zclk->reg);
/*
* Set KICK bit in FRQCRB to update hardware setting and wait for
* clock change completion.
*/
kick = clk_readl(zclk->kick_reg);
kick |= CPG_FRQCRB_KICK;
clk_writel(kick, zclk->kick_reg);
/*
* 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 dependant of 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 (!(clk_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,
.round_rate = cpg_z_clk_round_rate,
.set_rate = cpg_z_clk_set_rate,
};
static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
{
static const char *parent_name = "pll0";
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 = "z";
init.ops = &cpg_z_clk_ops;
init.flags = 0;
init.parent_names = &parent_name;
init.num_parents = 1;
zclk->reg = cpg->reg + CPG_FRQCRC;
zclk->kick_reg = cpg->reg + CPG_FRQCRB;
zclk->hw.init = &init;
clk = clk_register(NULL, &zclk->hw);
if (IS_ERR(clk))
kfree(zclk);
return clk;
}
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
/*
* MD EXTAL PLL0 PLL1 PLL3
* 14 13 19 (MHz) *1 *1
*---------------------------------------------------
* 0 0 0 15 x 1 x172/2 x208/2 x106
* 0 0 1 15 x 1 x172/2 x208/2 x88
* 0 1 0 20 x 1 x130/2 x156/2 x80
* 0 1 1 20 x 1 x130/2 x156/2 x66
* 1 0 0 26 / 2 x200/2 x240/2 x122
* 1 0 1 26 / 2 x200/2 x240/2 x102
* 1 1 0 30 / 2 x172/2 x208/2 x106
* 1 1 1 30 / 2 x172/2 x208/2 x88
*
* *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2)
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
(((md) & BIT(13)) >> 12) | \
(((md) & BIT(19)) >> 19))
struct cpg_pll_config {
unsigned int extal_div;
unsigned int pll1_mult;
unsigned int pll3_mult;
};
static const struct cpg_pll_config cpg_pll_configs[8] __initconst = {
{ 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 },
{ 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 },
};
/* SDHI divisors */
static const struct clk_div_table cpg_sdh_div_table[] = {
{ 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 },
{ 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 },
{ 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 },
};
static const struct clk_div_table cpg_sd01_div_table[] = {
{ 4, 8 },
{ 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
{ 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 },
};
/* -----------------------------------------------------------------------------
* Initialization
*/
static u32 cpg_mode __initdata;
static struct clk * __init
rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
const struct cpg_pll_config *config,
const char *name)
{
const struct clk_div_table *table = NULL;
const char *parent_name;
unsigned int shift;
unsigned int mult = 1;
unsigned int div = 1;
if (!strcmp(name, "main")) {
parent_name = of_clk_get_parent_name(np, 0);
div = config->extal_div;
} else if (!strcmp(name, "pll0")) {
/* PLL0 is a configurable multiplier clock. Register it as a
* fixed factor clock for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
parent_name = "main";
mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
} else if (!strcmp(name, "pll1")) {
parent_name = "main";
mult = config->pll1_mult / 2;
} else if (!strcmp(name, "pll3")) {
parent_name = "main";
mult = config->pll3_mult;
} else if (!strcmp(name, "lb")) {
parent_name = "pll1";
div = cpg_mode & BIT(18) ? 36 : 24;
} else if (!strcmp(name, "qspi")) {
parent_name = "pll1_div2";
div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
? 8 : 10;
} else if (!strcmp(name, "sdh")) {
parent_name = "pll1";
table = cpg_sdh_div_table;
shift = 8;
} else if (!strcmp(name, "sd0")) {
parent_name = "pll1";
table = cpg_sd01_div_table;
shift = 4;
} else if (!strcmp(name, "sd1")) {
parent_name = "pll1";
table = cpg_sd01_div_table;
shift = 0;
} else if (!strcmp(name, "z")) {
return cpg_z_clk_register(cpg);
} else {
return ERR_PTR(-EINVAL);
}
if (!table)
return clk_register_fixed_factor(NULL, name, parent_name, 0,
mult, div);
else
return clk_register_divider_table(NULL, name, parent_name, 0,
cpg->reg + CPG_SDCKCR, shift,
4, 0, table, &cpg->lock);
}
static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
{
const struct cpg_pll_config *config;
struct rcar_gen2_cpg *cpg;
struct clk **clks;
unsigned int i;
int num_clks;
num_clks = of_property_count_strings(np, "clock-output-names");
if (num_clks < 0) {
pr_err("%s: failed to count clocks\n", __func__);
return;
}
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
if (cpg == NULL || clks == NULL) {
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won't boot anyway.
*/
pr_err("%s: failed to allocate cpg\n", __func__);
return;
}
spin_lock_init(&cpg->lock);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
cpg->reg = of_iomap(np, 0);
if (WARN_ON(cpg->reg == NULL))
return;
config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i,
&name);
clk = rcar_gen2_cpg_register_clock(np, cpg, config, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks",
rcar_gen2_cpg_clocks_init);
void __init rcar_gen2_clocks_init(u32 mode)
{
cpg_mode = mode;
of_clk_init(NULL);
}

View file

@ -0,0 +1,103 @@
/*
* rz Core CPG Clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
* Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
struct rz_cpg {
struct clk_onecell_data data;
void __iomem *reg;
};
#define CPG_FRQCR 0x10
#define CPG_FRQCR2 0x14
/* -----------------------------------------------------------------------------
* Initialization
*/
static struct clk * __init
rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name)
{
u32 val;
unsigned mult;
static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 };
if (strcmp(name, "pll") == 0) {
/* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */
unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */
const char *parent_name = of_clk_get_parent_name(np, cpg_mode);
mult = cpg_mode ? (32 / 4) : 30;
return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1);
}
/* If mapping regs failed, skip non-pll clocks. System will boot anyhow */
if (!cpg->reg)
return ERR_PTR(-ENXIO);
/* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3)
* and the constraint that always g <= i. To get the rz platform started,
* let them run at fixed current speed and implement the details later.
*/
if (strcmp(name, "i") == 0)
val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3;
else if (strcmp(name, "g") == 0)
val = clk_readl(cpg->reg + CPG_FRQCR2) & 3;
else
return ERR_PTR(-EINVAL);
mult = frqcr_tab[val];
return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3);
}
static void __init rz_cpg_clocks_init(struct device_node *np)
{
struct rz_cpg *cpg;
struct clk **clks;
unsigned i;
int num_clks;
num_clks = of_property_count_strings(np, "clock-output-names");
if (WARN(num_clks <= 0, "can't count CPG clocks\n"))
return;
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
BUG_ON(!cpg || !clks);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
cpg->reg = of_iomap(np, 0);
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i, &name);
clk = rz_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init);