0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/clk-provider.h>
0012 #include <linux/err.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/mailbox_client.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018 #include <linux/regmap.h>
0019
0020
0021 #define HI6220_STUB_ACPU0 0
0022 #define HI6220_STUB_ACPU1 1
0023 #define HI6220_STUB_GPU 2
0024 #define HI6220_STUB_DDR 5
0025
0026
0027 #define HI6220_MBOX_MSG_LEN 8
0028
0029 #define HI6220_MBOX_FREQ 0xA
0030 #define HI6220_MBOX_CMD_SET 0x3
0031 #define HI6220_MBOX_OBJ_AP 0x0
0032
0033
0034 #define ACPU_DFS_FREQ_MAX 0x1724
0035 #define ACPU_DFS_CUR_FREQ 0x17CC
0036 #define ACPU_DFS_FLAG 0x1B30
0037 #define ACPU_DFS_FREQ_REQ 0x1B34
0038 #define ACPU_DFS_FREQ_LMT 0x1B38
0039 #define ACPU_DFS_LOCK_FLAG 0xAEAEAEAE
0040
0041 #define to_stub_clk(hw) container_of(hw, struct hi6220_stub_clk, hw)
0042
0043 struct hi6220_stub_clk {
0044 u32 id;
0045
0046 struct device *dev;
0047 struct clk_hw hw;
0048
0049 struct regmap *dfs_map;
0050 struct mbox_client cl;
0051 struct mbox_chan *mbox;
0052 };
0053
0054 struct hi6220_mbox_msg {
0055 unsigned char type;
0056 unsigned char cmd;
0057 unsigned char obj;
0058 unsigned char src;
0059 unsigned char para[4];
0060 };
0061
0062 union hi6220_mbox_data {
0063 unsigned int data[HI6220_MBOX_MSG_LEN];
0064 struct hi6220_mbox_msg msg;
0065 };
0066
0067 static unsigned int hi6220_acpu_get_freq(struct hi6220_stub_clk *stub_clk)
0068 {
0069 unsigned int freq;
0070
0071 regmap_read(stub_clk->dfs_map, ACPU_DFS_CUR_FREQ, &freq);
0072 return freq;
0073 }
0074
0075 static int hi6220_acpu_set_freq(struct hi6220_stub_clk *stub_clk,
0076 unsigned int freq)
0077 {
0078 union hi6220_mbox_data data;
0079
0080
0081 regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, freq);
0082
0083
0084 data.msg.type = HI6220_MBOX_FREQ;
0085 data.msg.cmd = HI6220_MBOX_CMD_SET;
0086 data.msg.obj = HI6220_MBOX_OBJ_AP;
0087 data.msg.src = HI6220_MBOX_OBJ_AP;
0088
0089 mbox_send_message(stub_clk->mbox, &data);
0090 return 0;
0091 }
0092
0093 static int hi6220_acpu_round_freq(struct hi6220_stub_clk *stub_clk,
0094 unsigned int freq)
0095 {
0096 unsigned int limit_flag, limit_freq = UINT_MAX;
0097 unsigned int max_freq;
0098
0099
0100 regmap_read(stub_clk->dfs_map, ACPU_DFS_FLAG, &limit_flag);
0101 if (limit_flag == ACPU_DFS_LOCK_FLAG)
0102 regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, &limit_freq);
0103
0104
0105 regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_MAX, &max_freq);
0106
0107
0108 max_freq = min(max_freq, limit_freq);
0109
0110 if (WARN_ON(freq > max_freq))
0111 freq = max_freq;
0112
0113 return freq;
0114 }
0115
0116 static unsigned long hi6220_stub_clk_recalc_rate(struct clk_hw *hw,
0117 unsigned long parent_rate)
0118 {
0119 u32 rate = 0;
0120 struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
0121
0122 switch (stub_clk->id) {
0123 case HI6220_STUB_ACPU0:
0124 rate = hi6220_acpu_get_freq(stub_clk);
0125
0126
0127 rate *= 1000;
0128 break;
0129
0130 default:
0131 dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
0132 __func__, stub_clk->id);
0133 break;
0134 }
0135
0136 return rate;
0137 }
0138
0139 static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
0140 unsigned long parent_rate)
0141 {
0142 struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
0143 unsigned long new_rate = rate / 1000;
0144 int ret = 0;
0145
0146 switch (stub_clk->id) {
0147 case HI6220_STUB_ACPU0:
0148 ret = hi6220_acpu_set_freq(stub_clk, new_rate);
0149 if (ret < 0)
0150 return ret;
0151
0152 break;
0153
0154 default:
0155 dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
0156 __func__, stub_clk->id);
0157 break;
0158 }
0159
0160 pr_debug("%s: set rate=%ldkHz\n", __func__, new_rate);
0161 return ret;
0162 }
0163
0164 static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
0165 unsigned long *parent_rate)
0166 {
0167 struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
0168 unsigned long new_rate = rate / 1000;
0169
0170 switch (stub_clk->id) {
0171 case HI6220_STUB_ACPU0:
0172 new_rate = hi6220_acpu_round_freq(stub_clk, new_rate);
0173
0174
0175 new_rate *= 1000;
0176 break;
0177
0178 default:
0179 dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
0180 __func__, stub_clk->id);
0181 break;
0182 }
0183
0184 return new_rate;
0185 }
0186
0187 static const struct clk_ops hi6220_stub_clk_ops = {
0188 .recalc_rate = hi6220_stub_clk_recalc_rate,
0189 .round_rate = hi6220_stub_clk_round_rate,
0190 .set_rate = hi6220_stub_clk_set_rate,
0191 };
0192
0193 static int hi6220_stub_clk_probe(struct platform_device *pdev)
0194 {
0195 struct device *dev = &pdev->dev;
0196 struct clk_init_data init;
0197 struct hi6220_stub_clk *stub_clk;
0198 struct clk *clk;
0199 struct device_node *np = pdev->dev.of_node;
0200 int ret;
0201
0202 stub_clk = devm_kzalloc(dev, sizeof(*stub_clk), GFP_KERNEL);
0203 if (!stub_clk)
0204 return -ENOMEM;
0205
0206 stub_clk->dfs_map = syscon_regmap_lookup_by_phandle(np,
0207 "hisilicon,hi6220-clk-sram");
0208 if (IS_ERR(stub_clk->dfs_map)) {
0209 dev_err(dev, "failed to get sram regmap\n");
0210 return PTR_ERR(stub_clk->dfs_map);
0211 }
0212
0213 stub_clk->hw.init = &init;
0214 stub_clk->dev = dev;
0215 stub_clk->id = HI6220_STUB_ACPU0;
0216
0217
0218 stub_clk->cl.dev = dev;
0219 stub_clk->cl.tx_done = NULL;
0220 stub_clk->cl.tx_block = true;
0221 stub_clk->cl.tx_tout = 500;
0222 stub_clk->cl.knows_txdone = false;
0223
0224
0225 stub_clk->mbox = mbox_request_channel(&stub_clk->cl, 0);
0226 if (IS_ERR(stub_clk->mbox)) {
0227 dev_err(dev, "failed get mailbox channel\n");
0228 return PTR_ERR(stub_clk->mbox);
0229 }
0230
0231 init.name = "acpu0";
0232 init.ops = &hi6220_stub_clk_ops;
0233 init.num_parents = 0;
0234 init.flags = 0;
0235
0236 clk = devm_clk_register(dev, &stub_clk->hw);
0237 if (IS_ERR(clk))
0238 return PTR_ERR(clk);
0239
0240 ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
0241 if (ret) {
0242 dev_err(dev, "failed to register OF clock provider\n");
0243 return ret;
0244 }
0245
0246
0247 regmap_write(stub_clk->dfs_map, ACPU_DFS_FLAG, 0x0);
0248 regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, 0x0);
0249 regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, 0x0);
0250
0251 dev_dbg(dev, "Registered clock '%s'\n", init.name);
0252 return 0;
0253 }
0254
0255 static const struct of_device_id hi6220_stub_clk_of_match[] = {
0256 { .compatible = "hisilicon,hi6220-stub-clk", },
0257 {}
0258 };
0259
0260 static struct platform_driver hi6220_stub_clk_driver = {
0261 .driver = {
0262 .name = "hi6220-stub-clk",
0263 .of_match_table = hi6220_stub_clk_of_match,
0264 },
0265 .probe = hi6220_stub_clk_probe,
0266 };
0267
0268 static int __init hi6220_stub_clk_init(void)
0269 {
0270 return platform_driver_register(&hi6220_stub_clk_driver);
0271 }
0272 subsys_initcall(hi6220_stub_clk_init);