Commit 3db385ea authored by Stephen Boyd's avatar Stephen Boyd

Merge tag 'clk-v4.9-samsung' of git://linuxtv.org/snawrocki/samsung into clk-next

Pull samsung clk driver updates from Sylwester Nawrocki:

In addition to a few clean up and code consolidation patches this
includes:
- addition of sound subsystem related clocks for Exynos5410 SoC
  (EPLL, PDMA) and support for "samsung,exynos5410-audss-clock"
  compatible in the clk-exynos-audss driver,
- addition of DRAM controller related clocks for exynos5420,
- MAINTAINERS update adding Chanwoo Choi as the Samsung SoC
  clock drivers co-maintainer.

* tag 'clk-v4.9-samsung' of git://linuxtv.org/snawrocki/samsung:
  clk: samsung: Add support for EPLL on exynos5410
  clk: samsung: clk-exynos-audss: Whitespace and debug trace cleanup
  clk: samsung: clk-exynos-audss: Add exynos5410 compatible
  clk: samsung: clk-exynos-audss: controller variant handling rework
  clk: samsung: Use common registration function for pll2550x
  clk: samsung: exynos5410: Expose the peripheral DMA gate clocks
  clk: samsung: exynos5420: Add clocks for CMU_CDREX domain
  clk: samsung: exynos5410: Use samsung_cmu_register_one() to simplify code
  clk: samsung: exynos5260: Move struct samsung_cmu_info to init section
  MAINTAINERS: Add myself as Samsung SoC clock drivers co-maintainer
  clk: samsung: exynos5410: Add clock IDs for PDMA and EPLL clocks
  clk: samsung: Add clock IDs for the CMU_CDREX (DRAM Express Controller)
parents 7348b6ce be95d2c7
......@@ -10,6 +10,8 @@ Required Properties:
- "samsung,exynos4210-audss-clock" - controller compatible with all Exynos4 SoCs.
- "samsung,exynos5250-audss-clock" - controller compatible with Exynos5250
SoCs.
- "samsung,exynos5410-audss-clock" - controller compatible with Exynos5410
SoCs.
- "samsung,exynos5420-audss-clock" - controller compatible with Exynos5420
SoCs.
- reg: physical base address and length of the controller's register set.
......@@ -91,5 +93,5 @@ i2s0: i2s@03830000 {
<&clock_audss EXYNOS_MOUT_AUDSS>,
<&clock_audss EXYNOS_MOUT_I2S>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1",
"mout_audss", "mout_i2s";
"mout_audss", "mout_i2s";
};
......@@ -12,24 +12,29 @@ Required Properties:
- #clock-cells: should be 1.
- clocks: should contain an entry specifying the root clock from external
oscillator supplied through XXTI or XusbXTI pin. This clock should be
defined using standard clock bindings with "fin_pll" clock-output-name.
That clock is being passed internally to the 9 PLLs.
All available clocks are defined as preprocessor macros in
dt-bindings/clock/exynos5410.h header and can be used in device
tree sources.
External clock:
There is clock that is generated outside the SoC. It
is expected that it is defined using standard clock bindings
with following clock-output-name:
- "fin_pll" - PLL input clock from XXTI
Example 1: An example of a clock controller node is listed below.
fin_pll: xxti {
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "fin_pll";
#clock-cells = <0>;
};
clock: clock-controller@0x10010000 {
compatible = "samsung,exynos5410-clock";
reg = <0x10010000 0x30000>;
#clock-cells = <1>;
clocks = <&fin_pll>;
};
Example 2: UART controller node that consumes the clock generated by the clock
......
......@@ -10240,9 +10240,12 @@ F: drivers/nfc/s3fwrn5
SAMSUNG SOC CLOCK DRIVERS
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
M: Tomasz Figa <tomasz.figa@gmail.com>
M: Chanwoo Choi <cw00.choi@samsung.com>
S: Supported
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
F: drivers/clk/samsung/
F: include/dt-bindings/clock/exynos*.h
F: Documentation/devicetree/bindings/clock/exynos*.txt
SAMSUNG SXGBE DRIVERS
M: Byungho An <bh74.an@samsung.com>
......
......@@ -14,18 +14,13 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/syscore_ops.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/exynos-audss-clk.h>
enum exynos_audss_clk_type {
TYPE_EXYNOS4210,
TYPE_EXYNOS5250,
TYPE_EXYNOS5420,
};
static DEFINE_SPINLOCK(lock);
static struct clk **clk_table;
static void __iomem *reg_base;
......@@ -44,9 +39,9 @@ static struct clk *epll;
#ifdef CONFIG_PM_SLEEP
static unsigned long reg_save[][2] = {
{ASS_CLK_SRC, 0},
{ASS_CLK_DIV, 0},
{ASS_CLK_GATE, 0},
{ ASS_CLK_SRC, 0 },
{ ASS_CLK_DIV, 0 },
{ ASS_CLK_GATE, 0 },
};
static int exynos_audss_clk_suspend(void)
......@@ -73,14 +68,43 @@ static struct syscore_ops exynos_audss_clk_syscore_ops = {
};
#endif /* CONFIG_PM_SLEEP */
struct exynos_audss_clk_drvdata {
unsigned int has_adma_clk:1;
unsigned int has_mst_clk:1;
unsigned int enable_epll:1;
unsigned int num_clks;
};
static const struct exynos_audss_clk_drvdata exynos4210_drvdata = {
.num_clks = EXYNOS_AUDSS_MAX_CLKS - 1,
};
static const struct exynos_audss_clk_drvdata exynos5410_drvdata = {
.num_clks = EXYNOS_AUDSS_MAX_CLKS - 1,
.has_mst_clk = 1,
};
static const struct exynos_audss_clk_drvdata exynos5420_drvdata = {
.num_clks = EXYNOS_AUDSS_MAX_CLKS,
.has_adma_clk = 1,
.enable_epll = 1,
};
static const struct of_device_id exynos_audss_clk_of_match[] = {
{ .compatible = "samsung,exynos4210-audss-clock",
.data = (void *)TYPE_EXYNOS4210, },
{ .compatible = "samsung,exynos5250-audss-clock",
.data = (void *)TYPE_EXYNOS5250, },
{ .compatible = "samsung,exynos5420-audss-clock",
.data = (void *)TYPE_EXYNOS5420, },
{},
{
.compatible = "samsung,exynos4210-audss-clock",
.data = &exynos4210_drvdata,
}, {
.compatible = "samsung,exynos5250-audss-clock",
.data = &exynos4210_drvdata,
}, {
.compatible = "samsung,exynos5410-audss-clock",
.data = &exynos5410_drvdata,
}, {
.compatible = "samsung,exynos5420-audss-clock",
.data = &exynos5420_drvdata,
},
{ },
};
static void exynos_audss_clk_teardown(void)
......@@ -106,19 +130,17 @@ static void exynos_audss_clk_teardown(void)
/* register exynos_audss clocks */
static int exynos_audss_clk_probe(struct platform_device *pdev)
{
int i, ret = 0;
struct resource *res;
const char *mout_audss_p[] = {"fin_pll", "fout_epll"};
const char *mout_i2s_p[] = {"mout_audss", "cdclk0", "sclk_audio0"};
const char *sclk_pcm_p = "sclk_pcm0";
struct clk *pll_ref, *pll_in, *cdclk, *sclk_audio, *sclk_pcm_in;
const struct of_device_id *match;
enum exynos_audss_clk_type variant;
const struct exynos_audss_clk_drvdata *variant;
struct resource *res;
int i, ret = 0;
match = of_match_node(exynos_audss_clk_of_match, pdev->dev.of_node);
if (!match)
variant = of_device_get_match_data(&pdev->dev);
if (!variant)
return -EINVAL;
variant = (enum exynos_audss_clk_type)match->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg_base = devm_ioremap_resource(&pdev->dev, res);
......@@ -126,7 +148,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to map audss registers\n");
return PTR_ERR(reg_base);
}
/* EPLL don't have to be enabled for boards other than Exynos5420 */
epll = ERR_PTR(-ENODEV);
clk_table = devm_kzalloc(&pdev->dev,
......@@ -136,10 +158,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
return -ENOMEM;
clk_data.clks = clk_table;
if (variant == TYPE_EXYNOS5420)
clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS;
else
clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS - 1;
clk_data.clk_num = variant->num_clks;
pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
pll_in = devm_clk_get(&pdev->dev, "pll_in");
......@@ -148,13 +167,13 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
if (!IS_ERR(pll_in)) {
mout_audss_p[1] = __clk_get_name(pll_in);
if (variant == TYPE_EXYNOS5420) {
if (variant->enable_epll) {
epll = pll_in;
ret = clk_prepare_enable(epll);
if (ret) {
dev_err(&pdev->dev,
"failed to prepare the epll clock\n");
"failed to prepare the epll clock\n");
return ret;
}
}
......@@ -210,7 +229,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
sclk_pcm_p, CLK_SET_RATE_PARENT,
reg_base + ASS_CLK_GATE, 5, 0, &lock);
if (variant == TYPE_EXYNOS5420) {
if (variant->has_adma_clk) {
clk_table[EXYNOS_ADMA] = clk_register_gate(NULL, "adma",
"dout_srp", CLK_SET_RATE_PARENT,
reg_base + ASS_CLK_GATE, 9, 0, &lock);
......@@ -234,9 +253,6 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
register_syscore_ops(&exynos_audss_clk_syscore_ops);
#endif
dev_info(&pdev->dev, "setup completed\n");
return 0;
unregister:
......
This diff is collapsed.
......@@ -14,6 +14,7 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk.h>
#include "clk.h"
......@@ -21,6 +22,8 @@
#define APLL_CON0 0x100
#define CPLL_LOCK 0x10020
#define CPLL_CON0 0x10120
#define EPLL_LOCK 0x10040
#define EPLL_CON0 0x10130
#define MPLL_LOCK 0x4000
#define MPLL_CON0 0x4100
#define BPLL_LOCK 0x20010
......@@ -58,7 +61,7 @@
/* list of PLLs */
enum exynos5410_plls {
apll, cpll, mpll,
apll, cpll, epll, mpll,
bpll, kpll,
nr_plls /* number of PLLs */
};
......@@ -67,6 +70,7 @@ enum exynos5410_plls {
PNAME(apll_p) = { "fin_pll", "fout_apll", };
PNAME(bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(cpll_p) = { "fin_pll", "fout_cpll" };
PNAME(epll_p) = { "fin_pll", "fout_epll" };
PNAME(mpll_p) = { "fin_pll", "fout_mpll", };
PNAME(kpll_p) = { "fin_pll", "fout_kpll", };
......@@ -95,6 +99,8 @@ static const struct samsung_mux_clock exynos5410_mux_clks[] __initconst = {
MUX(0, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1),
MUX(0, "sclk_bpll_muxed", bpll_user_p, SRC_TOP2, 24, 1),
MUX(0, "sclk_epll", epll_p, SRC_TOP2, 12, 1),
MUX(0, "sclk_cpll", cpll_p, SRC_TOP2, 8, 1),
MUX(0, "sclk_mpll_bpll", mpll_bpll_p, SRC_TOP1, 20, 1),
......@@ -176,6 +182,8 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = {
GATE(CLK_MMC0, "sdmmc0", "aclk200", GATE_BUS_FSYS0, 12, 0, 0),
GATE(CLK_MMC1, "sdmmc1", "aclk200", GATE_BUS_FSYS0, 13, 0, 0),
GATE(CLK_MMC2, "sdmmc2", "aclk200", GATE_BUS_FSYS0, 14, 0, 0),
GATE(CLK_PDMA1, "pdma1", "aclk200", GATE_BUS_FSYS0, 2, 0, 0),
GATE(CLK_PDMA0, "pdma0", "aclk200", GATE_BUS_FSYS0, 1, 0, 0),
GATE(CLK_SCLK_USBPHY301, "sclk_usbphy301", "dout_usbphy301",
GATE_TOP_SCLK_FSYS, 7, CLK_SET_RATE_PARENT, 0),
......@@ -217,11 +225,26 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = {
GATE(CLK_USBD301, "usbd301", "aclk200_fsys", GATE_IP_FSYS, 20, 0, 0),
};
static const struct samsung_pll_clock exynos5410_plls[nr_plls] __initconst = {
static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = {
PLL_36XX_RATE(400000000U, 200, 3, 2, 0),
PLL_36XX_RATE(333000000U, 111, 2, 2, 0),
PLL_36XX_RATE(300000000U, 100, 2, 2, 0),
PLL_36XX_RATE(266000000U, 266, 3, 3, 0),
PLL_36XX_RATE(200000000U, 200, 3, 3, 0),
PLL_36XX_RATE(192000000U, 192, 3, 3, 0),
PLL_36XX_RATE(166000000U, 166, 3, 3, 0),
PLL_36XX_RATE(133000000U, 266, 3, 4, 0),
PLL_36XX_RATE(100000000U, 200, 3, 4, 0),
PLL_36XX_RATE(66000000U, 176, 2, 5, 0),
};
static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = {
[apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK,
APLL_CON0, NULL),
[cpll] = PLL(pll_35xx, CLK_FOUT_CPLL, "fout_cpll", "fin_pll", CPLL_LOCK,
CPLL_CON0, NULL),
[epll] = PLL(pll_2650x, CLK_FOUT_EPLL, "fout_epll", "fin_pll", EPLL_LOCK,
EPLL_CON0, NULL),
[mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", MPLL_LOCK,
MPLL_CON0, NULL),
[bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", BPLL_LOCK,
......@@ -230,29 +253,27 @@ static const struct samsung_pll_clock exynos5410_plls[nr_plls] __initconst = {
KPLL_CON0, NULL),
};
static const struct samsung_cmu_info cmu __initconst = {
.pll_clks = exynos5410_plls,
.nr_pll_clks = ARRAY_SIZE(exynos5410_plls),
.mux_clks = exynos5410_mux_clks,
.nr_mux_clks = ARRAY_SIZE(exynos5410_mux_clks),
.div_clks = exynos5410_div_clks,
.nr_div_clks = ARRAY_SIZE(exynos5410_div_clks),
.gate_clks = exynos5410_gate_clks,
.nr_gate_clks = ARRAY_SIZE(exynos5410_gate_clks),
.nr_clk_ids = CLK_NR_CLKS,
};
/* register exynos5410 clocks */
static void __init exynos5410_clk_init(struct device_node *np)
{
struct samsung_clk_provider *ctx;
void __iomem *reg_base;
reg_base = of_iomap(np, 0);
if (!reg_base)
panic("%s: failed to map registers\n", __func__);
ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
samsung_clk_register_pll(ctx, exynos5410_plls,
ARRAY_SIZE(exynos5410_plls), reg_base);
struct clk *xxti = of_clk_get(np, 0);
samsung_clk_register_mux(ctx, exynos5410_mux_clks,
ARRAY_SIZE(exynos5410_mux_clks));
samsung_clk_register_div(ctx, exynos5410_div_clks,
ARRAY_SIZE(exynos5410_div_clks));
samsung_clk_register_gate(ctx, exynos5410_gate_clks,
ARRAY_SIZE(exynos5410_gate_clks));
if (!IS_ERR(xxti) && clk_get_rate(xxti) == 24 * MHZ)
exynos5410_plls[epll].rate_table = exynos5410_pll2550x_24mhz_tbl;
samsung_clk_of_add_provider(np, ctx);
samsung_cmu_register_one(np, &cmu);
pr_debug("Exynos5410: clock setup completed.\n");
}
......
......@@ -131,6 +131,9 @@
#define TOP_SPARE2 0x10b08
#define BPLL_LOCK 0x20010
#define BPLL_CON0 0x20110
#define SRC_CDREX 0x20200
#define DIV_CDREX0 0x20500
#define DIV_CDREX1 0x20504
#define KPLL_LOCK 0x28000
#define KPLL_CON0 0x28100
#define SRC_KFC 0x28200
......@@ -244,6 +247,9 @@ static const unsigned long exynos5x_clk_regs[] __initconst = {
GATE_TOP_SCLK_FSYS,
GATE_TOP_SCLK_PERIC,
TOP_SPARE2,
SRC_CDREX,
DIV_CDREX0,
DIV_CDREX1,
SRC_KFC,
DIV_KFC0,
};
......@@ -448,6 +454,8 @@ PNAME(mout_maudio0_p) = {"fin_pll", "maudio_clk", "mout_sclk_dpll",
"mout_sclk_epll", "mout_sclk_rpll"};
PNAME(mout_mau_epll_clk_p) = {"mout_sclk_epll", "mout_sclk_dpll",
"mout_sclk_mpll", "mout_sclk_spll"};
PNAME(mout_mclk_cdrex_p) = {"mout_bpll", "mout_mx_mspll_ccore"};
/* List of parents specific to exynos5800 */
PNAME(mout_epll2_5800_p) = { "mout_sclk_epll", "ff_dout_epll2" };
PNAME(mout_group1_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
......@@ -465,6 +473,9 @@ PNAME(mout_group6_5800_p) = { "mout_sclk_ipll", "mout_sclk_dpll",
PNAME(mout_group7_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
"mout_sclk_mpll", "mout_sclk_spll",
"mout_epll2", "mout_sclk_ipll" };
PNAME(mout_mx_mspll_ccore_p) = {"sclk_bpll", "mout_sclk_dpll",
"mout_sclk_mpll", "ff_dout_spll2",
"mout_sclk_spll", "mout_sclk_epll"};
PNAME(mout_mau_epll_clk_5800_p) = { "mout_sclk_epll", "mout_sclk_dpll",
"mout_sclk_mpll",
"ff_dout_spll2" };
......@@ -523,6 +534,8 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
MUX(0, "mout_aclk300_disp1", mout_group5_5800_p, SRC_TOP2, 24, 2),
MUX(0, "mout_aclk300_gscl", mout_group5_5800_p, SRC_TOP2, 28, 2),
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2),
MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, SRC_TOP7,
20, 2),
MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
......@@ -601,6 +614,8 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
MUX(0, "mout_aclk300_disp1", mout_group1_p, SRC_TOP2, 24, 2),
MUX(0, "mout_aclk300_gscl", mout_group1_p, SRC_TOP2, 28, 2),
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
mout_group5_5800_p, SRC_TOP7, 16, 2),
MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2),
MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1),
......@@ -744,6 +759,12 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
MUX(0, "mout_fimd1_final", mout_fimd1_final_p, TOP_SPARE2, 8, 1),
/* CDREX block */
MUX_F(CLK_MOUT_MCLK_CDREX, "mout_mclk_cdrex", mout_mclk_cdrex_p,
SRC_CDREX, 4, 1, CLK_SET_RATE_PARENT, 0),
MUX_F(CLK_MOUT_BPLL, "mout_bpll", mout_bpll_p, SRC_CDREX, 0, 1,
CLK_SET_RATE_PARENT, 0),
/* MAU Block */
MUX(CLK_MOUT_MAUDIO0, "mout_maudio0", mout_maudio0_p, SRC_MAU, 28, 3),
......@@ -836,6 +857,21 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1",
"mout_aclk400_disp1", DIV_TOP2, 4, 3),
/* CDREX Block */
DIV(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
DIV_CDREX0, 28, 3),
DIV_F(CLK_DOUT_SCLK_CDREX, "dout_sclk_cdrex", "mout_mclk_cdrex",
DIV_CDREX0, 24, 3, CLK_SET_RATE_PARENT, 0),
DIV(CLK_DOUT_ACLK_CDREX1, "dout_aclk_cdrex1", "dout_clk2x_phy0",
DIV_CDREX0, 16, 3),
DIV(CLK_DOUT_CCLK_DREX0, "dout_cclk_drex0", "dout_clk2x_phy0",
DIV_CDREX0, 8, 3),
DIV(CLK_DOUT_CLK2X_PHY0, "dout_clk2x_phy0", "dout_sclk_cdrex",
DIV_CDREX0, 3, 5),
DIV(CLK_DOUT_PCLK_CORE_MEM, "dout_pclk_core_mem", "mout_mclk_cdrex",
DIV_CDREX1, 8, 3),
/* Audio Block */
DIV(0, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4),
DIV(0, "dout_maupcm0", "dout_maudio0", DIV_MAU, 24, 8),
......@@ -1364,6 +1400,7 @@ static void __init exynos5x_clk_init(struct device_node *np,
if (_get_rate("fin_pll") == 24 * MHZ) {
exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl;
exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
}
samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls),
......
......@@ -112,6 +112,11 @@ static struct notifier_block exynos5440_clk_restart_handler = {
.priority = 128,
};
static const struct samsung_pll_clock exynos5440_plls[] __initconst = {
PLL(pll_2550x, CLK_CPLLA, "cplla", "xtal", 0, 0x4c, NULL),
PLL(pll_2550x, CLK_CPLLB, "cpllb", "xtal", 0, 0x50, NULL),
};
/* register exynos5440 clocks */
static void __init exynos5440_clk_init(struct device_node *np)
{
......@@ -129,8 +134,8 @@ static void __init exynos5440_clk_init(struct device_node *np)
samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
samsung_clk_register_pll2550x("cplla", "xtal", reg_base + 0x1c, 0x10);
samsung_clk_register_pll2550x("cpllb", "xtal", reg_base + 0x20, 0x10);
samsung_clk_register_pll(ctx, exynos5440_plls,
ARRAY_SIZE(exynos5440_plls), ctx->reg_base);
samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks,
ARRAY_SIZE(exynos5440_fixed_rate_clks));
......
......@@ -890,22 +890,14 @@ static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
#define PLL2550X_M_SHIFT (4)
#define PLL2550X_S_SHIFT (0)
struct samsung_clk_pll2550x {
struct clk_hw hw;
const void __iomem *reg_base;
unsigned long offset;
};
#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
struct samsung_clk_pll *pll = to_clk_pll(hw);
u32 r, p, m, s, pll_stat;
u64 fvco = parent_rate;
pll_stat = readl_relaxed(pll->reg_base + pll->offset * 3);
pll_stat = readl_relaxed(pll->con_reg);
r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
if (!r)
return 0;
......@@ -923,43 +915,6 @@ static const struct clk_ops samsung_pll2550x_clk_ops = {
.recalc_rate = samsung_pll2550x_recalc_rate,
};
struct clk * __init samsung_clk_register_pll2550x(const char *name,
const char *pname, const void __iomem *reg_base,
const unsigned long offset)
{
struct samsung_clk_pll2550x *pll;
struct clk *clk;
struct clk_init_data init;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll) {
pr_err("%s: could not allocate pll clk %s\n", __func__, name);
return NULL;
}
init.name = name;
init.ops = &samsung_pll2550x_clk_ops;
init.flags = CLK_GET_RATE_NOCACHE;
init.parent_names = &pname;
init.num_parents = 1;
pll->hw.init = &init;
pll->reg_base = reg_base;
pll->offset = offset;
clk = clk_register(NULL, &pll->hw);
if (IS_ERR(clk)) {
pr_err("%s: failed to register pll clock %s\n", __func__,
name);
kfree(pll);
}
if (clk_register_clkdev(clk, name, NULL))
pr_err("%s: failed to register lookup for %s", __func__, name);
return clk;
}
/*
* PLL2550xx Clock Type
*/
......@@ -1062,6 +1017,102 @@ static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
.recalc_rate = samsung_pll2550xx_recalc_rate,
};
/*
* PLL2650x Clock Type
*/
/* Maximum lock time can be 3000 * PDIV cycles */
#define PLL2650X_LOCK_FACTOR 3000
#define PLL2650X_M_MASK 0x1ff
#define PLL2650X_P_MASK 0x3f
#define PLL2650X_S_MASK 0x7
#define PLL2650X_K_MASK 0xffff
#define PLL2650X_LOCK_STAT_MASK 0x1
#define PLL2650X_M_SHIFT 16
#define PLL2650X_P_SHIFT 8
#define PLL2650X_S_SHIFT 0
#define PLL2650X_K_SHIFT 0
#define PLL2650X_LOCK_STAT_SHIFT 29
#define PLL2650X_PLL_ENABLE_SHIFT 31
static unsigned long samsung_pll2650x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct samsung_clk_pll *pll = to_clk_pll(hw);
u64 fout = parent_rate;
u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
s16 kdiv;
pll_con0 = readl_relaxed(pll->con_reg);
mdiv = (pll_con0 >> PLL2650X_M_SHIFT) & PLL2650X_M_MASK;
pdiv = (pll_con0 >> PLL2650X_P_SHIFT) & PLL2650X_P_MASK;
sdiv = (pll_con0 >> PLL2650X_S_SHIFT) & PLL2650X_S_MASK;
pll_con1 = readl_relaxed(pll->con_reg + 4);
kdiv = (s16)((pll_con1 >> PLL2650X_K_SHIFT) & PLL2650X_K_MASK);
fout *= (mdiv << 16) + kdiv;
do_div(fout, (pdiv << sdiv));
fout >>= 16;
return (unsigned long)fout;
}
static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct samsung_clk_pll *pll = to_clk_pll(hw);
const struct samsung_pll_rate_table *rate;
u32 con0, con1;
/* Get required rate settings from table */
rate = samsung_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
drate, clk_hw_get_name(hw));
return -EINVAL;
}
con0 = readl_relaxed(pll->con_reg);
con1 = readl_relaxed(pll->con_reg + 4);
/* Set PLL lock time. */
writel_relaxed(rate->pdiv * PLL2650X_LOCK_FACTOR, pll->lock_reg);
/* Change PLL PMS values */
con0 &= ~((PLL2650X_M_MASK << PLL2650X_M_SHIFT) |
(PLL2650X_P_MASK << PLL2650X_P_SHIFT) |
(PLL2650X_S_MASK << PLL2650X_S_SHIFT));
con0 |= (rate->mdiv << PLL2650X_M_SHIFT) |
(rate->pdiv << PLL2650X_P_SHIFT) |
(rate->sdiv << PLL2650X_S_SHIFT);
con0 |= (1 << PLL2650X_PLL_ENABLE_SHIFT);
writel_relaxed(con0, pll->con_reg);
con1 &= ~(PLL2650X_K_MASK << PLL2650X_K_SHIFT);
con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
writel_relaxed(con1, pll->con_reg + 4);
do {
cpu_relax();
con0 = readl_relaxed(pll->con_reg);
} while (!(con0 & (PLL2650X_LOCK_STAT_MASK
<< PLL2650X_LOCK_STAT_SHIFT)));
return 0;
}
static const struct clk_ops samsung_pll2650x_clk_ops = {
.recalc_rate = samsung_pll2650x_recalc_rate,
.round_rate = samsung_pll_round_rate,
.set_rate = samsung_pll2650x_set_rate,
};
static const struct clk_ops samsung_pll2650x_clk_min_ops = {
.recalc_rate = samsung_pll2650x_recalc_rate,
};
/*
* PLL2650XX Clock Type
*/
......@@ -1263,12 +1314,21 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
else
init.ops = &samsung_s3c2440_mpll_clk_ops;
break;
case pll_2550x:
init.ops = &samsung_pll2550x_clk_ops;
break;
case pll_2550xx:
if (!pll->rate_table)
init.ops = &samsung_pll2550xx_clk_min_ops;
else
init.ops = &samsung_pll2550xx_clk_ops;
break;
case pll_2650x:
if (!pll->rate_table)
init.ops = &samsung_pll2650x_clk_min_ops;
else
init.ops = &samsung_pll2650x_clk_ops;
break;
case pll_2650xx:
if (!pll->rate_table)
init.ops = &samsung_pll2650xx_clk_min_ops;
......
......@@ -31,7 +31,9 @@ enum samsung_pll_type {
pll_s3c2410_mpll,
pll_s3c2410_upll,
pll_s3c2440_mpll,
pll_2550x,
pll_2550xx,
pll_2650x,
pll_2650xx,
pll_1450x,
pll_1451x,
......
......@@ -19,6 +19,7 @@
#define CLK_FOUT_MPLL 4
#define CLK_FOUT_BPLL 5
#define CLK_FOUT_KPLL 6
#define CLK_FOUT_EPLL 7
/* gate for special clocks (sclk) */
#define CLK_SCLK_UART0 128
......@@ -55,6 +56,8 @@
#define CLK_MMC0 351
#define CLK_MMC1 352
#define CLK_MMC2 353
#define CLK_PDMA0 362
#define CLK_PDMA1 363
#define CLK_USBH20 365
#define CLK_USBD300 366
#define CLK_USBD301 367
......
......@@ -214,6 +214,9 @@
#define CLK_MOUT_SW_ACLK400 651
#define CLK_MOUT_USER_ACLK300_GSCL 652
#define CLK_MOUT_SW_ACLK300_GSCL 653
#define CLK_MOUT_MCLK_CDREX 654
#define CLK_MOUT_BPLL 655
#define CLK_MOUT_MX_MSPLL_CCORE 656
/* divider clocks */
#define CLK_DOUT_PIXEL 768
......@@ -239,8 +242,14 @@
#define CLK_DOUT_ACLK300_DISP1 788
#define CLK_DOUT_ACLK300_GSCL 789
#define CLK_DOUT_ACLK400_DISP1 790
#define CLK_DOUT_PCLK_CDREX 791
#define CLK_DOUT_SCLK_CDREX 792
#define CLK_DOUT_ACLK_CDREX1 793
#define CLK_DOUT_CCLK_DREX0 794
#define CLK_DOUT_CLK2X_PHY0 795
#define CLK_DOUT_PCLK_CORE_MEM 796
/* must be greater than maximal clock id */
#define CLK_NR_CLKS 791
#define CLK_NR_CLKS 797
#endif /* _DT_BINDINGS_CLOCK_EXYNOS_5420_H */
......@@ -14,6 +14,8 @@
#define CLK_XTAL 1
#define CLK_ARM_CLK 2
#define CLK_CPLLA 3
#define CLK_CPLLB 4
#define CLK_SPI_BAUD 16
#define CLK_PB0_250 17
#define CLK_PR0_250 18
......
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