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

ingenic-sysost.c (13465B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Ingenic XBurst SoCs SYSOST clocks driver
      4 * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
      5 */
      6
      7#include <linux/bitfield.h>
      8#include <linux/bitops.h>
      9#include <linux/clk.h>
     10#include <linux/clk-provider.h>
     11#include <linux/clockchips.h>
     12#include <linux/clocksource.h>
     13#include <linux/interrupt.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/of_address.h>
     16#include <linux/of_irq.h>
     17#include <linux/sched_clock.h>
     18#include <linux/slab.h>
     19#include <linux/syscore_ops.h>
     20
     21#include <dt-bindings/clock/ingenic,sysost.h>
     22
     23/* OST register offsets */
     24#define OST_REG_OSTCCR			0x00
     25#define OST_REG_OSTCR			0x08
     26#define OST_REG_OSTFR			0x0c
     27#define OST_REG_OSTMR			0x10
     28#define OST_REG_OST1DFR			0x14
     29#define OST_REG_OST1CNT			0x18
     30#define OST_REG_OST2CNTL		0x20
     31#define OST_REG_OSTCNT2HBUF		0x24
     32#define OST_REG_OSTESR			0x34
     33#define OST_REG_OSTECR			0x38
     34
     35/* bits within the OSTCCR register */
     36#define OSTCCR_PRESCALE1_MASK	0x3
     37#define OSTCCR_PRESCALE2_MASK	0xc
     38
     39/* bits within the OSTCR register */
     40#define OSTCR_OST1CLR			BIT(0)
     41#define OSTCR_OST2CLR			BIT(1)
     42
     43/* bits within the OSTFR register */
     44#define OSTFR_FFLAG				BIT(0)
     45
     46/* bits within the OSTMR register */
     47#define OSTMR_FMASK				BIT(0)
     48
     49/* bits within the OSTESR register */
     50#define OSTESR_OST1ENS			BIT(0)
     51#define OSTESR_OST2ENS			BIT(1)
     52
     53/* bits within the OSTECR register */
     54#define OSTECR_OST1ENC			BIT(0)
     55#define OSTECR_OST2ENC			BIT(1)
     56
     57struct ingenic_soc_info {
     58	unsigned int num_channels;
     59};
     60
     61struct ingenic_ost_clk_info {
     62	struct clk_init_data init_data;
     63	u8 ostccr_reg;
     64};
     65
     66struct ingenic_ost_clk {
     67	struct clk_hw hw;
     68	unsigned int idx;
     69	struct ingenic_ost *ost;
     70	const struct ingenic_ost_clk_info *info;
     71};
     72
     73struct ingenic_ost {
     74	void __iomem *base;
     75	const struct ingenic_soc_info *soc_info;
     76	struct clk *clk, *percpu_timer_clk, *global_timer_clk;
     77	struct clock_event_device cevt;
     78	struct clocksource cs;
     79	char name[20];
     80
     81	struct clk_hw_onecell_data *clocks;
     82};
     83
     84static struct ingenic_ost *ingenic_ost;
     85
     86static inline struct ingenic_ost_clk *to_ost_clk(struct clk_hw *hw)
     87{
     88	return container_of(hw, struct ingenic_ost_clk, hw);
     89}
     90
     91static unsigned long ingenic_ost_percpu_timer_recalc_rate(struct clk_hw *hw,
     92		unsigned long parent_rate)
     93{
     94	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
     95	const struct ingenic_ost_clk_info *info = ost_clk->info;
     96	unsigned int prescale;
     97
     98	prescale = readl(ost_clk->ost->base + info->ostccr_reg);
     99
    100	prescale = FIELD_GET(OSTCCR_PRESCALE1_MASK, prescale);
    101
    102	return parent_rate >> (prescale * 2);
    103}
    104
    105static unsigned long ingenic_ost_global_timer_recalc_rate(struct clk_hw *hw,
    106		unsigned long parent_rate)
    107{
    108	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
    109	const struct ingenic_ost_clk_info *info = ost_clk->info;
    110	unsigned int prescale;
    111
    112	prescale = readl(ost_clk->ost->base + info->ostccr_reg);
    113
    114	prescale = FIELD_GET(OSTCCR_PRESCALE2_MASK, prescale);
    115
    116	return parent_rate >> (prescale * 2);
    117}
    118
    119static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate)
    120{
    121	u8 prescale;
    122
    123	for (prescale = 0; prescale < 2; prescale++)
    124		if ((rate >> (prescale * 2)) <= req_rate)
    125			return prescale;
    126
    127	return 2; /* /16 divider */
    128}
    129
    130static long ingenic_ost_round_rate(struct clk_hw *hw, unsigned long req_rate,
    131		unsigned long *parent_rate)
    132{
    133	unsigned long rate = *parent_rate;
    134	u8 prescale;
    135
    136	if (req_rate > rate)
    137		return rate;
    138
    139	prescale = ingenic_ost_get_prescale(rate, req_rate);
    140
    141	return rate >> (prescale * 2);
    142}
    143
    144static int ingenic_ost_percpu_timer_set_rate(struct clk_hw *hw, unsigned long req_rate,
    145		unsigned long parent_rate)
    146{
    147	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
    148	const struct ingenic_ost_clk_info *info = ost_clk->info;
    149	u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
    150	int val;
    151
    152	val = readl(ost_clk->ost->base + info->ostccr_reg);
    153	val &= ~OSTCCR_PRESCALE1_MASK;
    154	val |= FIELD_PREP(OSTCCR_PRESCALE1_MASK, prescale);
    155	writel(val, ost_clk->ost->base + info->ostccr_reg);
    156
    157	return 0;
    158}
    159
    160static int ingenic_ost_global_timer_set_rate(struct clk_hw *hw, unsigned long req_rate,
    161		unsigned long parent_rate)
    162{
    163	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
    164	const struct ingenic_ost_clk_info *info = ost_clk->info;
    165	u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
    166	int val;
    167
    168	val = readl(ost_clk->ost->base + info->ostccr_reg);
    169	val &= ~OSTCCR_PRESCALE2_MASK;
    170	val |= FIELD_PREP(OSTCCR_PRESCALE2_MASK, prescale);
    171	writel(val, ost_clk->ost->base + info->ostccr_reg);
    172
    173	return 0;
    174}
    175
    176static const struct clk_ops ingenic_ost_percpu_timer_ops = {
    177	.recalc_rate	= ingenic_ost_percpu_timer_recalc_rate,
    178	.round_rate		= ingenic_ost_round_rate,
    179	.set_rate		= ingenic_ost_percpu_timer_set_rate,
    180};
    181
    182static const struct clk_ops ingenic_ost_global_timer_ops = {
    183	.recalc_rate	= ingenic_ost_global_timer_recalc_rate,
    184	.round_rate		= ingenic_ost_round_rate,
    185	.set_rate		= ingenic_ost_global_timer_set_rate,
    186};
    187
    188static const char * const ingenic_ost_clk_parents[] = { "ext" };
    189
    190static const struct ingenic_ost_clk_info x1000_ost_clk_info[] = {
    191	[OST_CLK_PERCPU_TIMER] = {
    192		.init_data = {
    193			.name = "percpu timer",
    194			.parent_names = ingenic_ost_clk_parents,
    195			.num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),
    196			.ops = &ingenic_ost_percpu_timer_ops,
    197			.flags = CLK_SET_RATE_UNGATE,
    198		},
    199		.ostccr_reg = OST_REG_OSTCCR,
    200	},
    201
    202	[OST_CLK_GLOBAL_TIMER] = {
    203		.init_data = {
    204			.name = "global timer",
    205			.parent_names = ingenic_ost_clk_parents,
    206			.num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),
    207			.ops = &ingenic_ost_global_timer_ops,
    208			.flags = CLK_SET_RATE_UNGATE,
    209		},
    210		.ostccr_reg = OST_REG_OSTCCR,
    211	},
    212};
    213
    214static u64 notrace ingenic_ost_global_timer_read_cntl(void)
    215{
    216	struct ingenic_ost *ost = ingenic_ost;
    217	unsigned int count;
    218
    219	count = readl(ost->base + OST_REG_OST2CNTL);
    220
    221	return count;
    222}
    223
    224static u64 notrace ingenic_ost_clocksource_read(struct clocksource *cs)
    225{
    226	return ingenic_ost_global_timer_read_cntl();
    227}
    228
    229static inline struct ingenic_ost *to_ingenic_ost(struct clock_event_device *evt)
    230{
    231	return container_of(evt, struct ingenic_ost, cevt);
    232}
    233
    234static int ingenic_ost_cevt_set_state_shutdown(struct clock_event_device *evt)
    235{
    236	struct ingenic_ost *ost = to_ingenic_ost(evt);
    237
    238	writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
    239
    240	return 0;
    241}
    242
    243static int ingenic_ost_cevt_set_next(unsigned long next,
    244				     struct clock_event_device *evt)
    245{
    246	struct ingenic_ost *ost = to_ingenic_ost(evt);
    247
    248	writel((u32)~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
    249	writel(next, ost->base + OST_REG_OST1DFR);
    250	writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR);
    251	writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR);
    252	writel((u32)~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
    253
    254	return 0;
    255}
    256
    257static irqreturn_t ingenic_ost_cevt_cb(int irq, void *dev_id)
    258{
    259	struct clock_event_device *evt = dev_id;
    260	struct ingenic_ost *ost = to_ingenic_ost(evt);
    261
    262	writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
    263
    264	if (evt->event_handler)
    265		evt->event_handler(evt);
    266
    267	return IRQ_HANDLED;
    268}
    269
    270static int __init ingenic_ost_register_clock(struct ingenic_ost *ost,
    271			unsigned int idx, const struct ingenic_ost_clk_info *info,
    272			struct clk_hw_onecell_data *clocks)
    273{
    274	struct ingenic_ost_clk *ost_clk;
    275	int val, err;
    276
    277	ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL);
    278	if (!ost_clk)
    279		return -ENOMEM;
    280
    281	ost_clk->hw.init = &info->init_data;
    282	ost_clk->idx = idx;
    283	ost_clk->info = info;
    284	ost_clk->ost = ost;
    285
    286	/* Reset clock divider */
    287	val = readl(ost->base + info->ostccr_reg);
    288	val &= ~(OSTCCR_PRESCALE1_MASK | OSTCCR_PRESCALE2_MASK);
    289	writel(val, ost->base + info->ostccr_reg);
    290
    291	err = clk_hw_register(NULL, &ost_clk->hw);
    292	if (err) {
    293		kfree(ost_clk);
    294		return err;
    295	}
    296
    297	clocks->hws[idx] = &ost_clk->hw;
    298
    299	return 0;
    300}
    301
    302static struct clk * __init ingenic_ost_get_clock(struct device_node *np, int id)
    303{
    304	struct of_phandle_args args;
    305
    306	args.np = np;
    307	args.args_count = 1;
    308	args.args[0] = id;
    309
    310	return of_clk_get_from_provider(&args);
    311}
    312
    313static int __init ingenic_ost_percpu_timer_init(struct device_node *np,
    314					 struct ingenic_ost *ost)
    315{
    316	unsigned int timer_virq, channel = OST_CLK_PERCPU_TIMER;
    317	unsigned long rate;
    318	int err;
    319
    320	ost->percpu_timer_clk = ingenic_ost_get_clock(np, channel);
    321	if (IS_ERR(ost->percpu_timer_clk))
    322		return PTR_ERR(ost->percpu_timer_clk);
    323
    324	err = clk_prepare_enable(ost->percpu_timer_clk);
    325	if (err)
    326		goto err_clk_put;
    327
    328	rate = clk_get_rate(ost->percpu_timer_clk);
    329	if (!rate) {
    330		err = -EINVAL;
    331		goto err_clk_disable;
    332	}
    333
    334	timer_virq = of_irq_get(np, 0);
    335	if (!timer_virq) {
    336		err = -EINVAL;
    337		goto err_clk_disable;
    338	}
    339
    340	snprintf(ost->name, sizeof(ost->name), "OST percpu timer");
    341
    342	err = request_irq(timer_virq, ingenic_ost_cevt_cb, IRQF_TIMER,
    343			  ost->name, &ost->cevt);
    344	if (err)
    345		goto err_irq_dispose_mapping;
    346
    347	ost->cevt.cpumask = cpumask_of(smp_processor_id());
    348	ost->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
    349	ost->cevt.name = ost->name;
    350	ost->cevt.rating = 400;
    351	ost->cevt.set_state_shutdown = ingenic_ost_cevt_set_state_shutdown;
    352	ost->cevt.set_next_event = ingenic_ost_cevt_set_next;
    353
    354	clockevents_config_and_register(&ost->cevt, rate, 4, 0xffffffff);
    355
    356	return 0;
    357
    358err_irq_dispose_mapping:
    359	irq_dispose_mapping(timer_virq);
    360err_clk_disable:
    361	clk_disable_unprepare(ost->percpu_timer_clk);
    362err_clk_put:
    363	clk_put(ost->percpu_timer_clk);
    364	return err;
    365}
    366
    367static int __init ingenic_ost_global_timer_init(struct device_node *np,
    368					       struct ingenic_ost *ost)
    369{
    370	unsigned int channel = OST_CLK_GLOBAL_TIMER;
    371	struct clocksource *cs = &ost->cs;
    372	unsigned long rate;
    373	int err;
    374
    375	ost->global_timer_clk = ingenic_ost_get_clock(np, channel);
    376	if (IS_ERR(ost->global_timer_clk))
    377		return PTR_ERR(ost->global_timer_clk);
    378
    379	err = clk_prepare_enable(ost->global_timer_clk);
    380	if (err)
    381		goto err_clk_put;
    382
    383	rate = clk_get_rate(ost->global_timer_clk);
    384	if (!rate) {
    385		err = -EINVAL;
    386		goto err_clk_disable;
    387	}
    388
    389	/* Clear counter CNT registers */
    390	writel(OSTCR_OST2CLR, ost->base + OST_REG_OSTCR);
    391
    392	/* Enable OST channel */
    393	writel(OSTESR_OST2ENS, ost->base + OST_REG_OSTESR);
    394
    395	cs->name = "ingenic-ost";
    396	cs->rating = 400;
    397	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
    398	cs->mask = CLOCKSOURCE_MASK(32);
    399	cs->read = ingenic_ost_clocksource_read;
    400
    401	err = clocksource_register_hz(cs, rate);
    402	if (err)
    403		goto err_clk_disable;
    404
    405	return 0;
    406
    407err_clk_disable:
    408	clk_disable_unprepare(ost->global_timer_clk);
    409err_clk_put:
    410	clk_put(ost->global_timer_clk);
    411	return err;
    412}
    413
    414static const struct ingenic_soc_info x1000_soc_info = {
    415	.num_channels = 2,
    416};
    417
    418static const struct of_device_id __maybe_unused ingenic_ost_of_matches[] __initconst = {
    419	{ .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info },
    420	{ /* sentinel */ }
    421};
    422
    423static int __init ingenic_ost_probe(struct device_node *np)
    424{
    425	const struct of_device_id *id = of_match_node(ingenic_ost_of_matches, np);
    426	struct ingenic_ost *ost;
    427	unsigned int i;
    428	int ret;
    429
    430	ost = kzalloc(sizeof(*ost), GFP_KERNEL);
    431	if (!ost)
    432		return -ENOMEM;
    433
    434	ost->base = of_io_request_and_map(np, 0, of_node_full_name(np));
    435	if (IS_ERR(ost->base)) {
    436		pr_err("%s: Failed to map OST registers\n", __func__);
    437		ret = PTR_ERR(ost->base);
    438		goto err_free_ost;
    439	}
    440
    441	ost->clk = of_clk_get_by_name(np, "ost");
    442	if (IS_ERR(ost->clk)) {
    443		ret = PTR_ERR(ost->clk);
    444		pr_crit("%s: Cannot get OST clock\n", __func__);
    445		goto err_free_ost;
    446	}
    447
    448	ret = clk_prepare_enable(ost->clk);
    449	if (ret) {
    450		pr_crit("%s: Unable to enable OST clock\n", __func__);
    451		goto err_put_clk;
    452	}
    453
    454	ost->soc_info = id->data;
    455
    456	ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels),
    457			      GFP_KERNEL);
    458	if (!ost->clocks) {
    459		ret = -ENOMEM;
    460		goto err_clk_disable;
    461	}
    462
    463	ost->clocks->num = ost->soc_info->num_channels;
    464
    465	for (i = 0; i < ost->clocks->num; i++) {
    466		ret = ingenic_ost_register_clock(ost, i, &x1000_ost_clk_info[i], ost->clocks);
    467		if (ret) {
    468			pr_crit("%s: Cannot register clock %d\n", __func__, i);
    469			goto err_unregister_ost_clocks;
    470		}
    471	}
    472
    473	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ost->clocks);
    474	if (ret) {
    475		pr_crit("%s: Cannot add OF clock provider\n", __func__);
    476		goto err_unregister_ost_clocks;
    477	}
    478
    479	ingenic_ost = ost;
    480
    481	return 0;
    482
    483err_unregister_ost_clocks:
    484	for (i = 0; i < ost->clocks->num; i++)
    485		if (ost->clocks->hws[i])
    486			clk_hw_unregister(ost->clocks->hws[i]);
    487	kfree(ost->clocks);
    488err_clk_disable:
    489	clk_disable_unprepare(ost->clk);
    490err_put_clk:
    491	clk_put(ost->clk);
    492err_free_ost:
    493	kfree(ost);
    494	return ret;
    495}
    496
    497static int __init ingenic_ost_init(struct device_node *np)
    498{
    499	struct ingenic_ost *ost;
    500	unsigned long rate;
    501	int ret;
    502
    503	ret = ingenic_ost_probe(np);
    504	if (ret) {
    505		pr_crit("%s: Failed to initialize OST clocks: %d\n", __func__, ret);
    506		return ret;
    507	}
    508
    509	of_node_clear_flag(np, OF_POPULATED);
    510
    511	ost = ingenic_ost;
    512	if (IS_ERR(ost))
    513		return PTR_ERR(ost);
    514
    515	ret = ingenic_ost_global_timer_init(np, ost);
    516	if (ret) {
    517		pr_crit("%s: Unable to init global timer: %x\n", __func__, ret);
    518		goto err_free_ingenic_ost;
    519	}
    520
    521	ret = ingenic_ost_percpu_timer_init(np, ost);
    522	if (ret)
    523		goto err_ost_global_timer_cleanup;
    524
    525	/* Register the sched_clock at the end as there's no way to undo it */
    526	rate = clk_get_rate(ost->global_timer_clk);
    527	sched_clock_register(ingenic_ost_global_timer_read_cntl, 32, rate);
    528
    529	return 0;
    530
    531err_ost_global_timer_cleanup:
    532	clocksource_unregister(&ost->cs);
    533	clk_disable_unprepare(ost->global_timer_clk);
    534	clk_put(ost->global_timer_clk);
    535err_free_ingenic_ost:
    536	kfree(ost);
    537	return ret;
    538}
    539
    540TIMER_OF_DECLARE(x1000_ost,  "ingenic,x1000-ost",  ingenic_ost_init);