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

omap_cf.c (8105B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * omap_cf.c -- OMAP 16xx CompactFlash controller driver
      4 *
      5 * Copyright (c) 2005 David Brownell
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/kernel.h>
     10#include <linux/platform_device.h>
     11#include <linux/errno.h>
     12#include <linux/init.h>
     13#include <linux/delay.h>
     14#include <linux/interrupt.h>
     15#include <linux/slab.h>
     16
     17#include <pcmcia/ss.h>
     18
     19#include <asm/io.h>
     20#include <linux/sizes.h>
     21
     22#include <linux/soc/ti/omap1-io.h>
     23#include <linux/soc/ti/omap1-soc.h>
     24#include <linux/soc/ti/omap1-mux.h>
     25
     26/* NOTE:  don't expect this to support many I/O cards.  The 16xx chips have
     27 * hard-wired timings to support Compact Flash memory cards; they won't work
     28 * with various other devices (like WLAN adapters) without some external
     29 * logic to help out.
     30 *
     31 * NOTE:  CF controller docs disagree with address space docs as to where
     32 * CF_BASE really lives; this is a doc erratum.
     33 */
     34#define	CF_BASE	0xfffe2800
     35
     36/* status; read after IRQ */
     37#define CF_STATUS			(CF_BASE + 0x00)
     38#	define	CF_STATUS_BAD_READ	(1 << 2)
     39#	define	CF_STATUS_BAD_WRITE	(1 << 1)
     40#	define	CF_STATUS_CARD_DETECT	(1 << 0)
     41
     42/* which chipselect (CS0..CS3) is used for CF (active low) */
     43#define CF_CFG				(CF_BASE + 0x02)
     44
     45/* card reset */
     46#define CF_CONTROL			(CF_BASE + 0x04)
     47#	define	CF_CONTROL_RESET	(1 << 0)
     48
     49#define omap_cf_present() (!(omap_readw(CF_STATUS) & CF_STATUS_CARD_DETECT))
     50
     51/*--------------------------------------------------------------------------*/
     52
     53static const char driver_name[] = "omap_cf";
     54
     55struct omap_cf_socket {
     56	struct pcmcia_socket	socket;
     57
     58	struct timer_list	timer;
     59	unsigned		present:1;
     60	unsigned		active:1;
     61
     62	struct platform_device	*pdev;
     63	unsigned long		phys_cf;
     64	u_int			irq;
     65	struct resource		iomem;
     66};
     67
     68#define	POLL_INTERVAL		(2 * HZ)
     69
     70/*--------------------------------------------------------------------------*/
     71
     72static int omap_cf_ss_init(struct pcmcia_socket *s)
     73{
     74	return 0;
     75}
     76
     77/* the timer is primarily to kick this socket's pccardd */
     78static void omap_cf_timer(struct timer_list *t)
     79{
     80	struct omap_cf_socket	*cf = from_timer(cf, t, timer);
     81	unsigned		present = omap_cf_present();
     82
     83	if (present != cf->present) {
     84		cf->present = present;
     85		pr_debug("%s: card %s\n", driver_name,
     86			present ? "present" : "gone");
     87		pcmcia_parse_events(&cf->socket, SS_DETECT);
     88	}
     89
     90	if (cf->active)
     91		mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
     92}
     93
     94/* This irq handler prevents "irqNNN: nobody cared" messages as drivers
     95 * claim the card's IRQ.  It may also detect some card insertions, but
     96 * not removals; it can't always eliminate timer irqs.
     97 */
     98static irqreturn_t omap_cf_irq(int irq, void *_cf)
     99{
    100	struct omap_cf_socket *cf = (struct omap_cf_socket *)_cf;
    101
    102	omap_cf_timer(&cf->timer);
    103	return IRQ_HANDLED;
    104}
    105
    106static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp)
    107{
    108	if (!sp)
    109		return -EINVAL;
    110
    111	/* NOTE CF is always 3VCARD */
    112	if (omap_cf_present()) {
    113		struct omap_cf_socket	*cf;
    114
    115		*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
    116		cf = container_of(s, struct omap_cf_socket, socket);
    117		s->pcmcia_irq = 0;
    118		s->pci_irq = cf->irq;
    119	} else
    120		*sp = 0;
    121	return 0;
    122}
    123
    124static int
    125omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
    126{
    127	u16		control;
    128
    129	/* REVISIT some non-OSK boards may support power switching */
    130	switch (s->Vcc) {
    131	case 0:
    132	case 33:
    133		break;
    134	default:
    135		return -EINVAL;
    136	}
    137
    138	control = omap_readw(CF_CONTROL);
    139	if (s->flags & SS_RESET)
    140		omap_writew(CF_CONTROL_RESET, CF_CONTROL);
    141	else
    142		omap_writew(0, CF_CONTROL);
    143
    144	pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
    145		driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
    146
    147	return 0;
    148}
    149
    150static int omap_cf_ss_suspend(struct pcmcia_socket *s)
    151{
    152	pr_debug("%s: %s\n", driver_name, __func__);
    153	return omap_cf_set_socket(s, &dead_socket);
    154}
    155
    156/* regions are 2K each:  mem, attrib, io (and reserved-for-ide) */
    157
    158static int
    159omap_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
    160{
    161	struct omap_cf_socket	*cf;
    162
    163	cf = container_of(s, struct omap_cf_socket, socket);
    164	io->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
    165	io->start = cf->phys_cf + SZ_4K;
    166	io->stop = io->start + SZ_2K - 1;
    167	return 0;
    168}
    169
    170static int
    171omap_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
    172{
    173	struct omap_cf_socket	*cf;
    174
    175	if (map->card_start)
    176		return -EINVAL;
    177	cf = container_of(s, struct omap_cf_socket, socket);
    178	map->static_start = cf->phys_cf;
    179	map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
    180	if (map->flags & MAP_ATTRIB)
    181		map->static_start += SZ_2K;
    182	return 0;
    183}
    184
    185static struct pccard_operations omap_cf_ops = {
    186	.init			= omap_cf_ss_init,
    187	.suspend		= omap_cf_ss_suspend,
    188	.get_status		= omap_cf_get_status,
    189	.set_socket		= omap_cf_set_socket,
    190	.set_io_map		= omap_cf_set_io_map,
    191	.set_mem_map		= omap_cf_set_mem_map,
    192};
    193
    194/*--------------------------------------------------------------------------*/
    195
    196/*
    197 * NOTE:  right now the only board-specific platform_data is
    198 * "what chipselect is used".  Boards could want more.
    199 */
    200
    201static int __init omap_cf_probe(struct platform_device *pdev)
    202{
    203	unsigned		seg;
    204	struct omap_cf_socket	*cf;
    205	int			irq;
    206	int			status;
    207	struct resource		*res;
    208	struct resource		iospace = DEFINE_RES_IO(SZ_64, SZ_4K);
    209
    210	seg = (int) pdev->dev.platform_data;
    211	if (seg == 0 || seg > 3)
    212		return -ENODEV;
    213
    214	/* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
    215	irq = platform_get_irq(pdev, 0);
    216	if (irq < 0)
    217		return -EINVAL;
    218
    219	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    220
    221	cf = kzalloc(sizeof *cf, GFP_KERNEL);
    222	if (!cf)
    223		return -ENOMEM;
    224	timer_setup(&cf->timer, omap_cf_timer, 0);
    225
    226	cf->pdev = pdev;
    227	platform_set_drvdata(pdev, cf);
    228
    229	/* this primarily just shuts up irq handling noise */
    230	status = request_irq(irq, omap_cf_irq, IRQF_SHARED,
    231			driver_name, cf);
    232	if (status < 0)
    233		goto fail0;
    234	cf->irq = irq;
    235	cf->socket.pci_irq = irq;
    236	cf->phys_cf = res->start;
    237
    238	/* pcmcia layer only remaps "real" memory */
    239	cf->socket.io_offset = iospace.start;
    240	status = pci_remap_iospace(&iospace, cf->phys_cf + SZ_4K);
    241	if (status) {
    242		status = -ENOMEM;
    243		goto fail1;
    244	}
    245
    246	if (!request_mem_region(cf->phys_cf, SZ_8K, driver_name)) {
    247		status = -ENXIO;
    248		goto fail1;
    249	}
    250
    251	/* NOTE:  CF conflicts with MMC1 */
    252	omap_cfg_reg(W11_1610_CF_CD1);
    253	omap_cfg_reg(P11_1610_CF_CD2);
    254	omap_cfg_reg(R11_1610_CF_IOIS16);
    255	omap_cfg_reg(V10_1610_CF_IREQ);
    256	omap_cfg_reg(W10_1610_CF_RESET);
    257
    258	omap_writew(~(1 << seg), CF_CFG);
    259
    260	pr_info("%s: cs%d on irq %d\n", driver_name, seg, irq);
    261
    262	/* CF uses armxor_ck, which is "always" available */
    263
    264	pr_debug("%s: sts %04x cfg %04x control %04x %s\n", driver_name,
    265		omap_readw(CF_STATUS), omap_readw(CF_CFG),
    266		omap_readw(CF_CONTROL),
    267		omap_cf_present() ? "present" : "(not present)");
    268
    269	cf->socket.owner = THIS_MODULE;
    270	cf->socket.dev.parent = &pdev->dev;
    271	cf->socket.ops = &omap_cf_ops;
    272	cf->socket.resource_ops = &pccard_static_ops;
    273	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
    274				| SS_CAP_MEM_ALIGN;
    275	cf->socket.map_size = SZ_2K;
    276	cf->socket.io[0].res = &cf->iomem;
    277
    278	status = pcmcia_register_socket(&cf->socket);
    279	if (status < 0)
    280		goto fail2;
    281
    282	cf->active = 1;
    283	mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
    284	return 0;
    285
    286fail2:
    287	release_mem_region(cf->phys_cf, SZ_8K);
    288fail1:
    289	free_irq(irq, cf);
    290fail0:
    291	kfree(cf);
    292	return status;
    293}
    294
    295static int __exit omap_cf_remove(struct platform_device *pdev)
    296{
    297	struct omap_cf_socket *cf = platform_get_drvdata(pdev);
    298
    299	cf->active = 0;
    300	pcmcia_unregister_socket(&cf->socket);
    301	del_timer_sync(&cf->timer);
    302	release_mem_region(cf->phys_cf, SZ_8K);
    303	free_irq(cf->irq, cf);
    304	kfree(cf);
    305	return 0;
    306}
    307
    308static struct platform_driver omap_cf_driver = {
    309	.driver = {
    310		.name	= driver_name,
    311	},
    312	.remove		= __exit_p(omap_cf_remove),
    313};
    314
    315static int __init omap_cf_init(void)
    316{
    317	if (cpu_is_omap16xx())
    318		return platform_driver_probe(&omap_cf_driver, omap_cf_probe);
    319	return -ENODEV;
    320}
    321
    322static void __exit omap_cf_exit(void)
    323{
    324	if (cpu_is_omap16xx())
    325		platform_driver_unregister(&omap_cf_driver);
    326}
    327
    328module_init(omap_cf_init);
    329module_exit(omap_cf_exit);
    330
    331MODULE_DESCRIPTION("OMAP CF Driver");
    332MODULE_LICENSE("GPL");
    333MODULE_ALIAS("platform:omap_cf");