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

mcp-sa11x0.c (7017B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  linux/drivers/mfd/mcp-sa11x0.c
      4 *
      5 *  Copyright (C) 2001-2005 Russell King
      6 *
      7 *  SA11x0 MCP (Multimedia Communications Port) driver.
      8 *
      9 *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
     10 */
     11#include <linux/module.h>
     12#include <linux/io.h>
     13#include <linux/errno.h>
     14#include <linux/kernel.h>
     15#include <linux/delay.h>
     16#include <linux/spinlock.h>
     17#include <linux/platform_device.h>
     18#include <linux/pm.h>
     19#include <linux/mfd/mcp.h>
     20
     21#include <mach/hardware.h>
     22#include <asm/mach-types.h>
     23#include <linux/platform_data/mfd-mcp-sa11x0.h>
     24
     25#define DRIVER_NAME "sa11x0-mcp"
     26
     27struct mcp_sa11x0 {
     28	void __iomem	*base0;
     29	void __iomem	*base1;
     30	u32		mccr0;
     31	u32		mccr1;
     32};
     33
     34/* Register offsets */
     35#define MCCR0(m)	((m)->base0 + 0x00)
     36#define MCDR0(m)	((m)->base0 + 0x08)
     37#define MCDR1(m)	((m)->base0 + 0x0c)
     38#define MCDR2(m)	((m)->base0 + 0x10)
     39#define MCSR(m)		((m)->base0 + 0x18)
     40#define MCCR1(m)	((m)->base1 + 0x00)
     41
     42#define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
     43
     44static void
     45mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
     46{
     47	struct mcp_sa11x0 *m = priv(mcp);
     48
     49	divisor /= 32;
     50
     51	m->mccr0 &= ~0x00007f00;
     52	m->mccr0 |= divisor << 8;
     53	writel_relaxed(m->mccr0, MCCR0(m));
     54}
     55
     56static void
     57mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
     58{
     59	struct mcp_sa11x0 *m = priv(mcp);
     60
     61	divisor /= 32;
     62
     63	m->mccr0 &= ~0x0000007f;
     64	m->mccr0 |= divisor;
     65	writel_relaxed(m->mccr0, MCCR0(m));
     66}
     67
     68/*
     69 * Write data to the device.  The bit should be set after 3 subframe
     70 * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
     71 * We really should try doing something more productive while we
     72 * wait.
     73 */
     74static void
     75mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
     76{
     77	struct mcp_sa11x0 *m = priv(mcp);
     78	int ret = -ETIME;
     79	int i;
     80
     81	writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
     82
     83	for (i = 0; i < 2; i++) {
     84		udelay(mcp->rw_timeout);
     85		if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
     86			ret = 0;
     87			break;
     88		}
     89	}
     90
     91	if (ret < 0)
     92		printk(KERN_WARNING "mcp: write timed out\n");
     93}
     94
     95/*
     96 * Read data from the device.  The bit should be set after 3 subframe
     97 * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
     98 * We really should try doing something more productive while we
     99 * wait.
    100 */
    101static unsigned int
    102mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
    103{
    104	struct mcp_sa11x0 *m = priv(mcp);
    105	int ret = -ETIME;
    106	int i;
    107
    108	writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
    109
    110	for (i = 0; i < 2; i++) {
    111		udelay(mcp->rw_timeout);
    112		if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
    113			ret = readl_relaxed(MCDR2(m)) & 0xffff;
    114			break;
    115		}
    116	}
    117
    118	if (ret < 0)
    119		printk(KERN_WARNING "mcp: read timed out\n");
    120
    121	return ret;
    122}
    123
    124static void mcp_sa11x0_enable(struct mcp *mcp)
    125{
    126	struct mcp_sa11x0 *m = priv(mcp);
    127
    128	writel(-1, MCSR(m));
    129	m->mccr0 |= MCCR0_MCE;
    130	writel_relaxed(m->mccr0, MCCR0(m));
    131}
    132
    133static void mcp_sa11x0_disable(struct mcp *mcp)
    134{
    135	struct mcp_sa11x0 *m = priv(mcp);
    136
    137	m->mccr0 &= ~MCCR0_MCE;
    138	writel_relaxed(m->mccr0, MCCR0(m));
    139}
    140
    141/*
    142 * Our methods.
    143 */
    144static struct mcp_ops mcp_sa11x0 = {
    145	.set_telecom_divisor	= mcp_sa11x0_set_telecom_divisor,
    146	.set_audio_divisor	= mcp_sa11x0_set_audio_divisor,
    147	.reg_write		= mcp_sa11x0_write,
    148	.reg_read		= mcp_sa11x0_read,
    149	.enable			= mcp_sa11x0_enable,
    150	.disable		= mcp_sa11x0_disable,
    151};
    152
    153static int mcp_sa11x0_probe(struct platform_device *dev)
    154{
    155	struct mcp_plat_data *data = dev_get_platdata(&dev->dev);
    156	struct resource *mem0, *mem1;
    157	struct mcp_sa11x0 *m;
    158	struct mcp *mcp;
    159	int ret;
    160
    161	if (!data)
    162		return -ENODEV;
    163
    164	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
    165	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
    166	if (!mem0 || !mem1)
    167		return -ENXIO;
    168
    169	if (!request_mem_region(mem0->start, resource_size(mem0),
    170				DRIVER_NAME)) {
    171		ret = -EBUSY;
    172		goto err_mem0;
    173	}
    174
    175	if (!request_mem_region(mem1->start, resource_size(mem1),
    176				DRIVER_NAME)) {
    177		ret = -EBUSY;
    178		goto err_mem1;
    179	}
    180
    181	mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
    182	if (!mcp) {
    183		ret = -ENOMEM;
    184		goto err_alloc;
    185	}
    186
    187	mcp->owner		= THIS_MODULE;
    188	mcp->ops		= &mcp_sa11x0;
    189	mcp->sclk_rate		= data->sclk_rate;
    190
    191	m = priv(mcp);
    192	m->mccr0 = data->mccr0 | 0x7f7f;
    193	m->mccr1 = data->mccr1;
    194
    195	m->base0 = ioremap(mem0->start, resource_size(mem0));
    196	m->base1 = ioremap(mem1->start, resource_size(mem1));
    197	if (!m->base0 || !m->base1) {
    198		ret = -ENOMEM;
    199		goto err_ioremap;
    200	}
    201
    202	platform_set_drvdata(dev, mcp);
    203
    204	/*
    205	 * Initialise device.  Note that we initially
    206	 * set the sampling rate to minimum.
    207	 */
    208	writel_relaxed(-1, MCSR(m));
    209	writel_relaxed(m->mccr1, MCCR1(m));
    210	writel_relaxed(m->mccr0, MCCR0(m));
    211
    212	/*
    213	 * Calculate the read/write timeout (us) from the bit clock
    214	 * rate.  This is the period for 3 64-bit frames.  Always
    215	 * round this time up.
    216	 */
    217	mcp->rw_timeout = DIV_ROUND_UP(64 * 3 * 1000000, mcp->sclk_rate);
    218
    219	ret = mcp_host_add(mcp, data->codec_pdata);
    220	if (ret == 0)
    221		return 0;
    222
    223 err_ioremap:
    224	iounmap(m->base1);
    225	iounmap(m->base0);
    226	mcp_host_free(mcp);
    227 err_alloc:
    228	release_mem_region(mem1->start, resource_size(mem1));
    229 err_mem1:
    230	release_mem_region(mem0->start, resource_size(mem0));
    231 err_mem0:
    232	return ret;
    233}
    234
    235static int mcp_sa11x0_remove(struct platform_device *dev)
    236{
    237	struct mcp *mcp = platform_get_drvdata(dev);
    238	struct mcp_sa11x0 *m = priv(mcp);
    239	struct resource *mem0, *mem1;
    240
    241	if (m->mccr0 & MCCR0_MCE)
    242		dev_warn(&dev->dev,
    243			 "device left active (missing disable call?)\n");
    244
    245	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
    246	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
    247
    248	mcp_host_del(mcp);
    249	iounmap(m->base1);
    250	iounmap(m->base0);
    251	mcp_host_free(mcp);
    252	release_mem_region(mem1->start, resource_size(mem1));
    253	release_mem_region(mem0->start, resource_size(mem0));
    254
    255	return 0;
    256}
    257
    258#ifdef CONFIG_PM_SLEEP
    259static int mcp_sa11x0_suspend(struct device *dev)
    260{
    261	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
    262
    263	if (m->mccr0 & MCCR0_MCE)
    264		dev_warn(dev, "device left active (missing disable call?)\n");
    265
    266	writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
    267
    268	return 0;
    269}
    270
    271static int mcp_sa11x0_resume(struct device *dev)
    272{
    273	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
    274
    275	writel_relaxed(m->mccr1, MCCR1(m));
    276	writel_relaxed(m->mccr0, MCCR0(m));
    277
    278	return 0;
    279}
    280#endif
    281
    282static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
    283#ifdef CONFIG_PM_SLEEP
    284	.suspend = mcp_sa11x0_suspend,
    285	.freeze = mcp_sa11x0_suspend,
    286	.poweroff = mcp_sa11x0_suspend,
    287	.resume_noirq = mcp_sa11x0_resume,
    288	.thaw_noirq = mcp_sa11x0_resume,
    289	.restore_noirq = mcp_sa11x0_resume,
    290#endif
    291};
    292
    293static struct platform_driver mcp_sa11x0_driver = {
    294	.probe		= mcp_sa11x0_probe,
    295	.remove		= mcp_sa11x0_remove,
    296	.driver		= {
    297		.name	= DRIVER_NAME,
    298		.pm	= &mcp_sa11x0_pm_ops,
    299	},
    300};
    301
    302/*
    303 * This needs re-working
    304 */
    305module_platform_driver(mcp_sa11x0_driver);
    306
    307MODULE_ALIAS("platform:" DRIVER_NAME);
    308MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
    309MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
    310MODULE_LICENSE("GPL");