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

t7l66xb.c (10739B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 * Toshiba T7L66XB core mfd support
      5 *
      6 * Copyright (c) 2005, 2007, 2008 Ian Molton
      7 * Copyright (c) 2008 Dmitry Baryshkov
      8 *
      9 * T7L66 features:
     10 *
     11 * Supported in this driver:
     12 * SD/MMC
     13 * SM/NAND flash controller
     14 *
     15 * As yet not supported
     16 * GPIO interface (on NAND pins)
     17 * Serial interface
     18 * TFT 'interface converter'
     19 * PCMCIA interface logic
     20 */
     21
     22#include <linux/kernel.h>
     23#include <linux/module.h>
     24#include <linux/err.h>
     25#include <linux/io.h>
     26#include <linux/slab.h>
     27#include <linux/irq.h>
     28#include <linux/clk.h>
     29#include <linux/platform_device.h>
     30#include <linux/mfd/core.h>
     31#include <linux/mfd/tmio.h>
     32#include <linux/mfd/t7l66xb.h>
     33
     34enum {
     35	T7L66XB_CELL_NAND,
     36	T7L66XB_CELL_MMC,
     37};
     38
     39static const struct resource t7l66xb_mmc_resources[] = {
     40	DEFINE_RES_MEM(0x800, 0x200),
     41	DEFINE_RES_IRQ(IRQ_T7L66XB_MMC)
     42};
     43
     44#define SCR_REVID	0x08		/* b Revision ID	*/
     45#define SCR_IMR		0x42		/* b Interrupt Mask	*/
     46#define SCR_DEV_CTL	0xe0		/* b Device control	*/
     47#define SCR_ISR		0xe1		/* b Interrupt Status	*/
     48#define SCR_GPO_OC	0xf0		/* b GPO output control	*/
     49#define SCR_GPO_OS	0xf1		/* b GPO output enable	*/
     50#define SCR_GPI_S	0xf2		/* w GPI status		*/
     51#define SCR_APDC	0xf8		/* b Active pullup down ctrl */
     52
     53#define SCR_DEV_CTL_USB		BIT(0)	/* USB enable		*/
     54#define SCR_DEV_CTL_MMC		BIT(1)	/* MMC enable		*/
     55
     56/*--------------------------------------------------------------------------*/
     57
     58struct t7l66xb {
     59	void __iomem		*scr;
     60	/* Lock to protect registers requiring read/modify/write ops. */
     61	raw_spinlock_t		lock;
     62
     63	struct resource		rscr;
     64	struct clk		*clk48m;
     65	struct clk		*clk32k;
     66	int			irq;
     67	int			irq_base;
     68};
     69
     70/*--------------------------------------------------------------------------*/
     71
     72static int t7l66xb_mmc_enable(struct platform_device *mmc)
     73{
     74	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
     75	unsigned long flags;
     76	u8 dev_ctl;
     77	int ret;
     78
     79	ret = clk_prepare_enable(t7l66xb->clk32k);
     80	if (ret)
     81		return ret;
     82
     83	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
     84
     85	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
     86	dev_ctl |= SCR_DEV_CTL_MMC;
     87	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
     88
     89	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
     90
     91	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
     92		t7l66xb_mmc_resources[0].start & 0xfffe);
     93
     94	return 0;
     95}
     96
     97static int t7l66xb_mmc_disable(struct platform_device *mmc)
     98{
     99	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
    100	unsigned long flags;
    101	u8 dev_ctl;
    102
    103	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
    104
    105	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
    106	dev_ctl &= ~SCR_DEV_CTL_MMC;
    107	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
    108
    109	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
    110
    111	clk_disable_unprepare(t7l66xb->clk32k);
    112
    113	return 0;
    114}
    115
    116static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
    117{
    118	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
    119
    120	tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
    121}
    122
    123static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
    124{
    125	struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
    126
    127	tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
    128}
    129
    130/*--------------------------------------------------------------------------*/
    131
    132static struct tmio_mmc_data t7166xb_mmc_data = {
    133	.hclk = 24000000,
    134	.set_pwr = t7l66xb_mmc_pwr,
    135	.set_clk_div = t7l66xb_mmc_clk_div,
    136};
    137
    138static const struct resource t7l66xb_nand_resources[] = {
    139	{
    140		.start	= 0xc00,
    141		.end	= 0xc07,
    142		.flags	= IORESOURCE_MEM,
    143	},
    144	{
    145		.start	= 0x0100,
    146		.end	= 0x01ff,
    147		.flags	= IORESOURCE_MEM,
    148	},
    149	{
    150		.start	= IRQ_T7L66XB_NAND,
    151		.end	= IRQ_T7L66XB_NAND,
    152		.flags	= IORESOURCE_IRQ,
    153	},
    154};
    155
    156static struct mfd_cell t7l66xb_cells[] = {
    157	[T7L66XB_CELL_MMC] = {
    158		.name = "tmio-mmc",
    159		.enable = t7l66xb_mmc_enable,
    160		.disable = t7l66xb_mmc_disable,
    161		.platform_data = &t7166xb_mmc_data,
    162		.pdata_size    = sizeof(t7166xb_mmc_data),
    163		.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
    164		.resources = t7l66xb_mmc_resources,
    165	},
    166	[T7L66XB_CELL_NAND] = {
    167		.name = "tmio-nand",
    168		.num_resources = ARRAY_SIZE(t7l66xb_nand_resources),
    169		.resources = t7l66xb_nand_resources,
    170	},
    171};
    172
    173/*--------------------------------------------------------------------------*/
    174
    175/* Handle the T7L66XB interrupt mux */
    176static void t7l66xb_irq(struct irq_desc *desc)
    177{
    178	struct t7l66xb *t7l66xb = irq_desc_get_handler_data(desc);
    179	unsigned int isr;
    180	unsigned int i, irq_base;
    181
    182	irq_base = t7l66xb->irq_base;
    183
    184	while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) &
    185				~tmio_ioread8(t7l66xb->scr + SCR_IMR)))
    186		for (i = 0; i < T7L66XB_NR_IRQS; i++)
    187			if (isr & (1 << i))
    188				generic_handle_irq(irq_base + i);
    189}
    190
    191static void t7l66xb_irq_mask(struct irq_data *data)
    192{
    193	struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
    194	unsigned long			flags;
    195	u8 imr;
    196
    197	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
    198	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
    199	imr |= 1 << (data->irq - t7l66xb->irq_base);
    200	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
    201	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
    202}
    203
    204static void t7l66xb_irq_unmask(struct irq_data *data)
    205{
    206	struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
    207	unsigned long flags;
    208	u8 imr;
    209
    210	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
    211	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
    212	imr &= ~(1 << (data->irq - t7l66xb->irq_base));
    213	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
    214	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
    215}
    216
    217static struct irq_chip t7l66xb_chip = {
    218	.name		= "t7l66xb",
    219	.irq_ack	= t7l66xb_irq_mask,
    220	.irq_mask	= t7l66xb_irq_mask,
    221	.irq_unmask	= t7l66xb_irq_unmask,
    222};
    223
    224/*--------------------------------------------------------------------------*/
    225
    226/* Install the IRQ handler */
    227static void t7l66xb_attach_irq(struct platform_device *dev)
    228{
    229	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
    230	unsigned int irq, irq_base;
    231
    232	irq_base = t7l66xb->irq_base;
    233
    234	for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
    235		irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq);
    236		irq_set_chip_data(irq, t7l66xb);
    237	}
    238
    239	irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING);
    240	irq_set_chained_handler_and_data(t7l66xb->irq, t7l66xb_irq, t7l66xb);
    241}
    242
    243static void t7l66xb_detach_irq(struct platform_device *dev)
    244{
    245	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
    246	unsigned int irq, irq_base;
    247
    248	irq_base = t7l66xb->irq_base;
    249
    250	irq_set_chained_handler_and_data(t7l66xb->irq, NULL, NULL);
    251
    252	for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) {
    253		irq_set_chip(irq, NULL);
    254		irq_set_chip_data(irq, NULL);
    255	}
    256}
    257
    258/*--------------------------------------------------------------------------*/
    259
    260#ifdef CONFIG_PM
    261static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
    262{
    263	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
    264	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
    265
    266	if (pdata && pdata->suspend)
    267		pdata->suspend(dev);
    268	clk_disable_unprepare(t7l66xb->clk48m);
    269
    270	return 0;
    271}
    272
    273static int t7l66xb_resume(struct platform_device *dev)
    274{
    275	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
    276	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
    277	int ret;
    278
    279	ret = clk_prepare_enable(t7l66xb->clk48m);
    280	if (ret)
    281		return ret;
    282
    283	if (pdata && pdata->resume)
    284		pdata->resume(dev);
    285
    286	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
    287		t7l66xb_mmc_resources[0].start & 0xfffe);
    288
    289	return 0;
    290}
    291#else
    292#define t7l66xb_suspend NULL
    293#define t7l66xb_resume	NULL
    294#endif
    295
    296/*--------------------------------------------------------------------------*/
    297
    298static int t7l66xb_probe(struct platform_device *dev)
    299{
    300	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
    301	struct t7l66xb *t7l66xb;
    302	struct resource *iomem, *rscr;
    303	int ret;
    304
    305	if (!pdata)
    306		return -EINVAL;
    307
    308	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
    309	if (!iomem)
    310		return -EINVAL;
    311
    312	t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL);
    313	if (!t7l66xb)
    314		return -ENOMEM;
    315
    316	raw_spin_lock_init(&t7l66xb->lock);
    317
    318	platform_set_drvdata(dev, t7l66xb);
    319
    320	ret = platform_get_irq(dev, 0);
    321	if (ret >= 0)
    322		t7l66xb->irq = ret;
    323	else
    324		goto err_noirq;
    325
    326	t7l66xb->irq_base = pdata->irq_base;
    327
    328	t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K");
    329	if (IS_ERR(t7l66xb->clk32k)) {
    330		ret = PTR_ERR(t7l66xb->clk32k);
    331		goto err_clk32k_get;
    332	}
    333
    334	t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
    335	if (IS_ERR(t7l66xb->clk48m)) {
    336		ret = PTR_ERR(t7l66xb->clk48m);
    337		goto err_clk48m_get;
    338	}
    339
    340	rscr = &t7l66xb->rscr;
    341	rscr->name = "t7l66xb-core";
    342	rscr->start = iomem->start;
    343	rscr->end = iomem->start + 0xff;
    344	rscr->flags = IORESOURCE_MEM;
    345
    346	ret = request_resource(iomem, rscr);
    347	if (ret)
    348		goto err_request_scr;
    349
    350	t7l66xb->scr = ioremap(rscr->start, resource_size(rscr));
    351	if (!t7l66xb->scr) {
    352		ret = -ENOMEM;
    353		goto err_ioremap;
    354	}
    355
    356	ret = clk_prepare_enable(t7l66xb->clk48m);
    357	if (ret)
    358		goto err_clk_enable;
    359
    360	if (pdata->enable)
    361		pdata->enable(dev);
    362
    363	/* Mask all interrupts */
    364	tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR);
    365
    366	printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n",
    367		dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID),
    368		(unsigned long)iomem->start, t7l66xb->irq);
    369
    370	t7l66xb_attach_irq(dev);
    371
    372	t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
    373	t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
    374
    375	ret = mfd_add_devices(&dev->dev, dev->id,
    376			      t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
    377			      iomem, t7l66xb->irq_base, NULL);
    378
    379	if (!ret)
    380		return 0;
    381
    382	t7l66xb_detach_irq(dev);
    383	clk_disable_unprepare(t7l66xb->clk48m);
    384err_clk_enable:
    385	iounmap(t7l66xb->scr);
    386err_ioremap:
    387	release_resource(&t7l66xb->rscr);
    388err_request_scr:
    389	clk_put(t7l66xb->clk48m);
    390err_clk48m_get:
    391	clk_put(t7l66xb->clk32k);
    392err_clk32k_get:
    393err_noirq:
    394	kfree(t7l66xb);
    395	return ret;
    396}
    397
    398static int t7l66xb_remove(struct platform_device *dev)
    399{
    400	struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
    401	struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
    402	int ret;
    403
    404	ret = pdata->disable(dev);
    405	clk_disable_unprepare(t7l66xb->clk48m);
    406	clk_put(t7l66xb->clk48m);
    407	clk_disable_unprepare(t7l66xb->clk32k);
    408	clk_put(t7l66xb->clk32k);
    409	t7l66xb_detach_irq(dev);
    410	iounmap(t7l66xb->scr);
    411	release_resource(&t7l66xb->rscr);
    412	mfd_remove_devices(&dev->dev);
    413	kfree(t7l66xb);
    414
    415	return ret;
    416
    417}
    418
    419static struct platform_driver t7l66xb_platform_driver = {
    420	.driver = {
    421		.name	= "t7l66xb",
    422	},
    423	.suspend	= t7l66xb_suspend,
    424	.resume		= t7l66xb_resume,
    425	.probe		= t7l66xb_probe,
    426	.remove		= t7l66xb_remove,
    427};
    428
    429/*--------------------------------------------------------------------------*/
    430
    431module_platform_driver(t7l66xb_platform_driver);
    432
    433MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
    434MODULE_LICENSE("GPL v2");
    435MODULE_AUTHOR("Ian Molton");
    436MODULE_ALIAS("platform:t7l66xb");