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

gptu.c (4959B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 *  Copyright (C) 2012 John Crispin <john@phrozen.org>
      5 *  Copyright (C) 2012 Lantiq GmbH
      6 */
      7
      8#include <linux/interrupt.h>
      9#include <linux/ioport.h>
     10#include <linux/init.h>
     11#include <linux/of_platform.h>
     12#include <linux/of_irq.h>
     13
     14#include <lantiq_soc.h>
     15#include "../clk.h"
     16
     17/* the magic ID byte of the core */
     18#define GPTU_MAGIC	0x59
     19/* clock control register */
     20#define GPTU_CLC	0x00
     21/* id register */
     22#define GPTU_ID		0x08
     23/* interrupt node enable */
     24#define GPTU_IRNEN	0xf4
     25/* interrupt control register */
     26#define GPTU_IRCR	0xf8
     27/* interrupt capture register */
     28#define GPTU_IRNCR	0xfc
     29/* there are 3 identical blocks of 2 timers. calculate register offsets */
     30#define GPTU_SHIFT(x)	(x % 2 ? 4 : 0)
     31#define GPTU_BASE(x)	(((x >> 1) * 0x20) + 0x10)
     32/* timer control register */
     33#define GPTU_CON(x)	(GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00)
     34/* timer auto reload register */
     35#define GPTU_RUN(x)	(GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08)
     36/* timer manual reload register */
     37#define GPTU_RLD(x)	(GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10)
     38/* timer count register */
     39#define GPTU_CNT(x)	(GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18)
     40
     41/* GPTU_CON(x) */
     42#define CON_CNT		BIT(2)
     43#define CON_EDGE_ANY	(BIT(7) | BIT(6))
     44#define CON_SYNC	BIT(8)
     45#define CON_CLK_INT	BIT(10)
     46
     47/* GPTU_RUN(x) */
     48#define RUN_SEN		BIT(0)
     49#define RUN_RL		BIT(2)
     50
     51/* set clock to runmode */
     52#define CLC_RMC		BIT(8)
     53/* bring core out of suspend */
     54#define CLC_SUSPEND	BIT(4)
     55/* the disable bit */
     56#define CLC_DISABLE	BIT(0)
     57
     58#define gptu_w32(x, y)	ltq_w32((x), gptu_membase + (y))
     59#define gptu_r32(x)	ltq_r32(gptu_membase + (x))
     60
     61enum gptu_timer {
     62	TIMER1A = 0,
     63	TIMER1B,
     64	TIMER2A,
     65	TIMER2B,
     66	TIMER3A,
     67	TIMER3B
     68};
     69
     70static void __iomem *gptu_membase;
     71static struct resource irqres[6];
     72
     73static irqreturn_t timer_irq_handler(int irq, void *priv)
     74{
     75	int timer = irq - irqres[0].start;
     76	gptu_w32(1 << timer, GPTU_IRNCR);
     77	return IRQ_HANDLED;
     78}
     79
     80static void gptu_hwinit(void)
     81{
     82	gptu_w32(0x00, GPTU_IRNEN);
     83	gptu_w32(0xff, GPTU_IRNCR);
     84	gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC);
     85}
     86
     87static void gptu_hwexit(void)
     88{
     89	gptu_w32(0x00, GPTU_IRNEN);
     90	gptu_w32(0xff, GPTU_IRNCR);
     91	gptu_w32(CLC_DISABLE, GPTU_CLC);
     92}
     93
     94static int gptu_enable(struct clk *clk)
     95{
     96	int ret = request_irq(irqres[clk->bits].start, timer_irq_handler,
     97		IRQF_TIMER, "gtpu", NULL);
     98	if (ret) {
     99		pr_err("gptu: failed to request irq\n");
    100		return ret;
    101	}
    102
    103	gptu_w32(CON_CNT | CON_EDGE_ANY | CON_SYNC | CON_CLK_INT,
    104		GPTU_CON(clk->bits));
    105	gptu_w32(1, GPTU_RLD(clk->bits));
    106	gptu_w32(gptu_r32(GPTU_IRNEN) | BIT(clk->bits), GPTU_IRNEN);
    107	gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits));
    108	return 0;
    109}
    110
    111static void gptu_disable(struct clk *clk)
    112{
    113	gptu_w32(0, GPTU_RUN(clk->bits));
    114	gptu_w32(0, GPTU_CON(clk->bits));
    115	gptu_w32(0, GPTU_RLD(clk->bits));
    116	gptu_w32(gptu_r32(GPTU_IRNEN) & ~BIT(clk->bits), GPTU_IRNEN);
    117	free_irq(irqres[clk->bits].start, NULL);
    118}
    119
    120static inline void clkdev_add_gptu(struct device *dev, const char *con,
    121							unsigned int timer)
    122{
    123	struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
    124
    125	if (!clk)
    126		return;
    127	clk->cl.dev_id = dev_name(dev);
    128	clk->cl.con_id = con;
    129	clk->cl.clk = clk;
    130	clk->enable = gptu_enable;
    131	clk->disable = gptu_disable;
    132	clk->bits = timer;
    133	clkdev_add(&clk->cl);
    134}
    135
    136static int gptu_probe(struct platform_device *pdev)
    137{
    138	struct clk *clk;
    139	struct resource *res;
    140
    141	if (of_irq_to_resource_table(pdev->dev.of_node, irqres, 6) != 6) {
    142		dev_err(&pdev->dev, "Failed to get IRQ list\n");
    143		return -EINVAL;
    144	}
    145
    146	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    147
    148	/* remap gptu register range */
    149	gptu_membase = devm_ioremap_resource(&pdev->dev, res);
    150	if (IS_ERR(gptu_membase))
    151		return PTR_ERR(gptu_membase);
    152
    153	/* enable our clock */
    154	clk = clk_get(&pdev->dev, NULL);
    155	if (IS_ERR(clk)) {
    156		dev_err(&pdev->dev, "Failed to get clock\n");
    157		return -ENOENT;
    158	}
    159	clk_enable(clk);
    160
    161	/* power up the core */
    162	gptu_hwinit();
    163
    164	/* the gptu has a ID register */
    165	if (((gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) {
    166		dev_err(&pdev->dev, "Failed to find magic\n");
    167		gptu_hwexit();
    168		clk_disable(clk);
    169		clk_put(clk);
    170		return -ENAVAIL;
    171	}
    172
    173	/* register the clocks */
    174	clkdev_add_gptu(&pdev->dev, "timer1a", TIMER1A);
    175	clkdev_add_gptu(&pdev->dev, "timer1b", TIMER1B);
    176	clkdev_add_gptu(&pdev->dev, "timer2a", TIMER2A);
    177	clkdev_add_gptu(&pdev->dev, "timer2b", TIMER2B);
    178	clkdev_add_gptu(&pdev->dev, "timer3a", TIMER3A);
    179	clkdev_add_gptu(&pdev->dev, "timer3b", TIMER3B);
    180
    181	dev_info(&pdev->dev, "gptu: 6 timers loaded\n");
    182
    183	return 0;
    184}
    185
    186static const struct of_device_id gptu_match[] = {
    187	{ .compatible = "lantiq,gptu-xway" },
    188	{},
    189};
    190
    191static struct platform_driver dma_driver = {
    192	.probe = gptu_probe,
    193	.driver = {
    194		.name = "gptu-xway",
    195		.of_match_table = gptu_match,
    196	},
    197};
    198
    199int __init gptu_init(void)
    200{
    201	int ret = platform_driver_register(&dma_driver);
    202
    203	if (ret)
    204		pr_info("gptu: Error registering platform driver\n");
    205	return ret;
    206}
    207
    208arch_initcall(gptu_init);