cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ap806-system-controller.c (6744B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Marvell Armada AP806 System Controller
      4 *
      5 * Copyright (C) 2016 Marvell
      6 *
      7 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
      8 *
      9 */
     10
     11#define pr_fmt(fmt) "ap806-system-controller: " fmt
     12
     13#include "armada_ap_cp_helper.h"
     14#include <linux/clk-provider.h>
     15#include <linux/mfd/syscon.h>
     16#include <linux/init.h>
     17#include <linux/of.h>
     18#include <linux/platform_device.h>
     19#include <linux/regmap.h>
     20
     21#define AP806_SAR_REG			0x400
     22#define AP806_SAR_CLKFREQ_MODE_MASK	0x1f
     23
     24#define AP806_CLK_NUM			6
     25
     26static struct clk *ap806_clks[AP806_CLK_NUM];
     27
     28static struct clk_onecell_data ap806_clk_data = {
     29	.clks = ap806_clks,
     30	.clk_num = AP806_CLK_NUM,
     31};
     32
     33static int ap806_get_sar_clocks(unsigned int freq_mode,
     34				unsigned int *cpuclk_freq,
     35				unsigned int *dclk_freq)
     36{
     37	switch (freq_mode) {
     38	case 0x0:
     39		*cpuclk_freq = 2000;
     40		*dclk_freq = 600;
     41		break;
     42	case 0x1:
     43		*cpuclk_freq = 2000;
     44		*dclk_freq = 525;
     45		break;
     46	case 0x6:
     47		*cpuclk_freq = 1800;
     48		*dclk_freq = 600;
     49		break;
     50	case 0x7:
     51		*cpuclk_freq = 1800;
     52		*dclk_freq = 525;
     53		break;
     54	case 0x4:
     55		*cpuclk_freq = 1600;
     56		*dclk_freq = 400;
     57		break;
     58	case 0xB:
     59		*cpuclk_freq = 1600;
     60		*dclk_freq = 450;
     61		break;
     62	case 0xD:
     63		*cpuclk_freq = 1600;
     64		*dclk_freq = 525;
     65		break;
     66	case 0x1a:
     67		*cpuclk_freq = 1400;
     68		*dclk_freq = 400;
     69		break;
     70	case 0x14:
     71		*cpuclk_freq = 1300;
     72		*dclk_freq = 400;
     73		break;
     74	case 0x17:
     75		*cpuclk_freq = 1300;
     76		*dclk_freq = 325;
     77		break;
     78	case 0x19:
     79		*cpuclk_freq = 1200;
     80		*dclk_freq = 400;
     81		break;
     82	case 0x13:
     83		*cpuclk_freq = 1000;
     84		*dclk_freq = 325;
     85		break;
     86	case 0x1d:
     87		*cpuclk_freq = 1000;
     88		*dclk_freq = 400;
     89		break;
     90	case 0x1c:
     91		*cpuclk_freq = 800;
     92		*dclk_freq = 400;
     93		break;
     94	case 0x1b:
     95		*cpuclk_freq = 600;
     96		*dclk_freq = 400;
     97		break;
     98	default:
     99		return -EINVAL;
    100	}
    101
    102	return 0;
    103}
    104
    105static int ap807_get_sar_clocks(unsigned int freq_mode,
    106				unsigned int *cpuclk_freq,
    107				unsigned int *dclk_freq)
    108{
    109	switch (freq_mode) {
    110	case 0x0:
    111		*cpuclk_freq = 2000;
    112		*dclk_freq = 1200;
    113		break;
    114	case 0x6:
    115		*cpuclk_freq = 2200;
    116		*dclk_freq = 1200;
    117		break;
    118	case 0xD:
    119		*cpuclk_freq = 1600;
    120		*dclk_freq = 1200;
    121		break;
    122	default:
    123		return -EINVAL;
    124	}
    125
    126	return 0;
    127}
    128
    129static int ap806_syscon_common_probe(struct platform_device *pdev,
    130				     struct device_node *syscon_node)
    131{
    132	unsigned int freq_mode, cpuclk_freq, dclk_freq;
    133	const char *name, *fixedclk_name;
    134	struct device *dev = &pdev->dev;
    135	struct device_node *np = dev->of_node;
    136	struct regmap *regmap;
    137	u32 reg;
    138	int ret;
    139
    140	regmap = syscon_node_to_regmap(syscon_node);
    141	if (IS_ERR(regmap)) {
    142		dev_err(dev, "cannot get regmap\n");
    143		return PTR_ERR(regmap);
    144	}
    145
    146	ret = regmap_read(regmap, AP806_SAR_REG, &reg);
    147	if (ret) {
    148		dev_err(dev, "cannot read from regmap\n");
    149		return ret;
    150	}
    151
    152	freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK;
    153
    154	if (of_device_is_compatible(pdev->dev.of_node,
    155				    "marvell,ap806-clock")) {
    156		ret = ap806_get_sar_clocks(freq_mode, &cpuclk_freq, &dclk_freq);
    157	} else if (of_device_is_compatible(pdev->dev.of_node,
    158					   "marvell,ap807-clock")) {
    159		ret = ap807_get_sar_clocks(freq_mode, &cpuclk_freq, &dclk_freq);
    160	} else {
    161		dev_err(dev, "compatible not supported\n");
    162		return -EINVAL;
    163	}
    164
    165	if (ret) {
    166		dev_err(dev, "invalid Sample at Reset value\n");
    167		return ret;
    168	}
    169
    170	/* Convert to hertz */
    171	cpuclk_freq *= 1000 * 1000;
    172	dclk_freq *= 1000 * 1000;
    173
    174	/* CPU clocks depend on the Sample At Reset configuration */
    175	name = ap_cp_unique_name(dev, syscon_node, "pll-cluster-0");
    176	ap806_clks[0] = clk_register_fixed_rate(dev, name, NULL,
    177						0, cpuclk_freq);
    178	if (IS_ERR(ap806_clks[0])) {
    179		ret = PTR_ERR(ap806_clks[0]);
    180		goto fail0;
    181	}
    182
    183	name = ap_cp_unique_name(dev, syscon_node, "pll-cluster-1");
    184	ap806_clks[1] = clk_register_fixed_rate(dev, name, NULL, 0,
    185						cpuclk_freq);
    186	if (IS_ERR(ap806_clks[1])) {
    187		ret = PTR_ERR(ap806_clks[1]);
    188		goto fail1;
    189	}
    190
    191	/* Fixed clock is always 1200 Mhz */
    192	fixedclk_name = ap_cp_unique_name(dev, syscon_node, "fixed");
    193	ap806_clks[2] = clk_register_fixed_rate(dev, fixedclk_name, NULL,
    194						0, 1200 * 1000 * 1000);
    195	if (IS_ERR(ap806_clks[2])) {
    196		ret = PTR_ERR(ap806_clks[2]);
    197		goto fail2;
    198	}
    199
    200	/* MSS Clock is fixed clock divided by 6 */
    201	name = ap_cp_unique_name(dev, syscon_node, "mss");
    202	ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name,
    203						  0, 1, 6);
    204	if (IS_ERR(ap806_clks[3])) {
    205		ret = PTR_ERR(ap806_clks[3]);
    206		goto fail3;
    207	}
    208
    209	/* SDIO(/eMMC) Clock is fixed clock divided by 3 */
    210	name = ap_cp_unique_name(dev, syscon_node, "sdio");
    211	ap806_clks[4] = clk_register_fixed_factor(NULL, name,
    212						  fixedclk_name,
    213						  0, 1, 3);
    214	if (IS_ERR(ap806_clks[4])) {
    215		ret = PTR_ERR(ap806_clks[4]);
    216		goto fail4;
    217	}
    218
    219	/* AP-DCLK(HCLK) Clock is DDR clock divided by 2 */
    220	name = ap_cp_unique_name(dev, syscon_node, "ap-dclk");
    221	ap806_clks[5] = clk_register_fixed_rate(dev, name, NULL, 0, dclk_freq);
    222	if (IS_ERR(ap806_clks[5])) {
    223		ret = PTR_ERR(ap806_clks[5]);
    224		goto fail5;
    225	}
    226
    227	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
    228	if (ret)
    229		goto fail_clk_add;
    230
    231	return 0;
    232
    233fail_clk_add:
    234	clk_unregister_fixed_factor(ap806_clks[5]);
    235fail5:
    236	clk_unregister_fixed_factor(ap806_clks[4]);
    237fail4:
    238	clk_unregister_fixed_factor(ap806_clks[3]);
    239fail3:
    240	clk_unregister_fixed_rate(ap806_clks[2]);
    241fail2:
    242	clk_unregister_fixed_rate(ap806_clks[1]);
    243fail1:
    244	clk_unregister_fixed_rate(ap806_clks[0]);
    245fail0:
    246	return ret;
    247}
    248
    249static int ap806_syscon_legacy_probe(struct platform_device *pdev)
    250{
    251	dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");
    252	dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");
    253	dev_warn(&pdev->dev, FW_WARN
    254		 "This binding won't be supported in future kernel\n");
    255
    256	return ap806_syscon_common_probe(pdev, pdev->dev.of_node);
    257
    258}
    259
    260static int ap806_clock_probe(struct platform_device *pdev)
    261{
    262	return ap806_syscon_common_probe(pdev, pdev->dev.of_node->parent);
    263}
    264
    265static const struct of_device_id ap806_syscon_legacy_of_match[] = {
    266	{ .compatible = "marvell,ap806-system-controller", },
    267	{ }
    268};
    269
    270static struct platform_driver ap806_syscon_legacy_driver = {
    271	.probe = ap806_syscon_legacy_probe,
    272	.driver		= {
    273		.name	= "marvell-ap806-system-controller",
    274		.of_match_table = ap806_syscon_legacy_of_match,
    275		.suppress_bind_attrs = true,
    276	},
    277};
    278builtin_platform_driver(ap806_syscon_legacy_driver);
    279
    280static const struct of_device_id ap806_clock_of_match[] = {
    281	{ .compatible = "marvell,ap806-clock", },
    282	{ .compatible = "marvell,ap807-clock", },
    283	{ }
    284};
    285
    286static struct platform_driver ap806_clock_driver = {
    287	.probe = ap806_clock_probe,
    288	.driver		= {
    289		.name	= "marvell-ap806-clock",
    290		.of_match_table = ap806_clock_of_match,
    291		.suppress_bind_attrs = true,
    292	},
    293};
    294builtin_platform_driver(ap806_clock_driver);