blob: 0fb48541b9b72fde11147d41ffb89781702e7c4f [file] [log] [blame]
Masahiro Yamadae4dfb052016-02-02 21:11:32 +09001/*
Masahiro Yamadafa1f73f2016-07-19 21:56:13 +09002 * Copyright (C) 2016 Socionext Inc.
3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
Masahiro Yamadae4dfb052016-02-02 21:11:32 +09004 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +09009#include <clk-uclass.h>
Simon Glass11c89f32017-05-17 17:18:03 -060010#include <dm.h>
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090011#include <linux/bitops.h>
12#include <linux/io.h>
Masahiro Yamada46a624f2016-03-24 22:32:39 +090013#include <linux/sizes.h>
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090014
15#include "clk-uniphier.h"
16
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090017/**
18 * struct uniphier_clk_priv - private data for UniPhier clock driver
19 *
20 * @base: base address of the clock provider
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090021 * @data: SoC specific data
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090022 */
23struct uniphier_clk_priv {
24 void __iomem *base;
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090025 const struct uniphier_clk_data *data;
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090026};
27
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090028static int uniphier_clk_enable(struct clk *clk)
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090029{
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090030 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
31 unsigned long id = clk->id;
32 const struct uniphier_clk_gate_data *p;
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090033
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090034 for (p = priv->data->gate; p->id != UNIPHIER_CLK_ID_END; p++) {
35 u32 val;
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090036
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090037 if (p->id != id)
38 continue;
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090039
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090040 val = readl(priv->base + p->reg);
41 val |= BIT(p->bit);
42 writel(val, priv->base + p->reg);
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090043
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090044 return 0;
45 }
46
47 dev_err(priv->dev, "clk_id=%lu was not handled\n", id);
48 return -EINVAL;
Masahiro Yamadaf18559e2016-09-22 07:42:21 +090049}
50
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090051static const struct uniphier_clk_mux_data *
52uniphier_clk_get_mux_data(struct uniphier_clk_priv *priv, unsigned long id)
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090053{
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090054 const struct uniphier_clk_mux_data *p;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090055
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090056 for (p = priv->data->mux; p->id != UNIPHIER_CLK_ID_END; p++) {
57 if (p->id == id)
58 return p;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090059 }
60
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090061 return NULL;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090062}
63
Stephen Warrena9622432016-06-17 09:44:00 -060064static ulong uniphier_clk_get_rate(struct clk *clk)
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090065{
Stephen Warrena9622432016-06-17 09:44:00 -060066 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090067 const struct uniphier_clk_mux_data *mux;
68 u32 val;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090069 int i;
70
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090071 mux = uniphier_clk_get_mux_data(priv, clk->id);
72 if (!mux)
73 return 0;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090074
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090075 if (!mux->nr_muxs) /* fixed-rate */
76 return mux->rates[0];
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090077
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090078 val = readl(priv->base + mux->reg);
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090079
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090080 for (i = 0; i < mux->nr_muxs; i++)
81 if ((mux->masks[i] & val) == mux->vals[i])
82 return mux->rates[i];
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090083
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090084 return -EINVAL;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090085}
86
Stephen Warrena9622432016-06-17 09:44:00 -060087static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090088{
Stephen Warrena9622432016-06-17 09:44:00 -060089 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090090 const struct uniphier_clk_mux_data *mux;
91 u32 val;
92 int i, best_rate_id = -1;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090093 ulong best_rate = 0;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090094
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090095 mux = uniphier_clk_get_mux_data(priv, clk->id);
96 if (!mux)
97 return 0;
Masahiro Yamadae4dfb052016-02-02 21:11:32 +090098
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +090099 if (!mux->nr_muxs) /* fixed-rate */
100 return mux->rates[0];
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900101
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +0900102 /* first, decide the best match rate */
103 for (i = 0; i < mux->nr_muxs; i++) {
104 if (mux->rates[i] > best_rate && mux->rates[i] <= rate) {
105 best_rate = mux->rates[i];
106 best_rate_id = i;
107 }
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900108 }
109
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +0900110 if (best_rate_id < 0)
111 return -EINVAL;
112
113 val = readl(priv->base + mux->reg);
114 val &= ~mux->masks[best_rate_id];
115 val |= mux->vals[best_rate_id];
116 writel(val, priv->base + mux->reg);
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900117
118 debug("%s: requested rate = %lu, set rate = %lu\n", __func__,
119 rate, best_rate);
120
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900121 return best_rate;
122}
123
Masahiro Yamada5e05c4d2017-06-22 16:42:04 +0900124static const struct clk_ops uniphier_clk_ops = {
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900125 .enable = uniphier_clk_enable,
Stephen Warrena9622432016-06-17 09:44:00 -0600126 .get_rate = uniphier_clk_get_rate,
127 .set_rate = uniphier_clk_set_rate,
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900128};
129
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +0900130static int uniphier_clk_probe(struct udevice *dev)
131{
132 struct uniphier_clk_priv *priv = dev_get_priv(dev);
133 fdt_addr_t addr;
134
Simon Glassba1dea42017-05-17 17:18:05 -0600135 addr = devfdt_get_addr(dev->parent);
Masahiro Yamada8bdfe0a2016-10-17 22:18:01 +0900136 if (addr == FDT_ADDR_T_NONE)
137 return -EINVAL;
138
139 priv->base = devm_ioremap(dev, addr, SZ_4K);
140 if (!priv->base)
141 return -ENOMEM;
142
143 priv->data = (void *)dev_get_driver_data(dev);
144
145 return 0;
146}
147
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900148static const struct udevice_id uniphier_clk_match[] = {
149 {
Masahiro Yamadac3a29fe2016-09-22 07:42:22 +0900150 .compatible = "socionext,uniphier-sld3-mio-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900151 .data = (ulong)&uniphier_mio_clk_data,
152 },
153 {
Masahiro Yamadac3a29fe2016-09-22 07:42:22 +0900154 .compatible = "socionext,uniphier-ld4-mio-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900155 .data = (ulong)&uniphier_mio_clk_data,
156 },
157 {
Masahiro Yamadac3a29fe2016-09-22 07:42:22 +0900158 .compatible = "socionext,uniphier-pro4-mio-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900159 .data = (ulong)&uniphier_mio_clk_data,
160 },
161 {
Masahiro Yamadac3a29fe2016-09-22 07:42:22 +0900162 .compatible = "socionext,uniphier-sld8-mio-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900163 .data = (ulong)&uniphier_mio_clk_data,
164 },
165 {
Masahiro Yamada9e34de52017-01-28 06:53:41 +0900166 .compatible = "socionext,uniphier-pro5-sd-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900167 .data = (ulong)&uniphier_mio_clk_data,
168 },
169 {
Masahiro Yamada9e34de52017-01-28 06:53:41 +0900170 .compatible = "socionext,uniphier-pxs2-sd-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900171 .data = (ulong)&uniphier_mio_clk_data,
172 },
173 {
Masahiro Yamadac3a29fe2016-09-22 07:42:22 +0900174 .compatible = "socionext,uniphier-ld11-mio-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900175 .data = (ulong)&uniphier_mio_clk_data,
176 },
177 {
Masahiro Yamada9e34de52017-01-28 06:53:41 +0900178 .compatible = "socionext,uniphier-ld20-sd-clock",
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900179 .data = (ulong)&uniphier_mio_clk_data,
180 },
181 { /* sentinel */ }
182};
Masahiro Yamadae4dfb052016-02-02 21:11:32 +0900183
Masahiro Yamadaf18559e2016-09-22 07:42:21 +0900184U_BOOT_DRIVER(uniphier_clk) = {
185 .name = "uniphier-clk",
186 .id = UCLASS_CLK,
187 .of_match = uniphier_clk_match,
188 .probe = uniphier_clk_probe,
189 .priv_auto_alloc_size = sizeof(struct uniphier_clk_priv),
190 .ops = &uniphier_clk_ops,
191};