117be2d2bSAdrian McMenamin /* 217be2d2bSAdrian McMenamin * Core maple bus functionality 317be2d2bSAdrian McMenamin * 4b233b28eSAdrian McMenamin * Copyright (C) 2007 - 2009 Adrian McMenamin 563870295SPaul Mundt * Copyright (C) 2001 - 2008 Paul Mundt 617be2d2bSAdrian McMenamin * Copyright (C) 2000 - 2001 YAEGASHI Takeshi 717be2d2bSAdrian McMenamin * Copyright (C) 2001 M. R. Brown 817be2d2bSAdrian McMenamin * 917be2d2bSAdrian McMenamin * This file is subject to the terms and conditions of the GNU General Public 1017be2d2bSAdrian McMenamin * License. See the file "COPYING" in the main directory of this archive 1117be2d2bSAdrian McMenamin * for more details. 1217be2d2bSAdrian McMenamin */ 1317be2d2bSAdrian McMenamin #include <linux/init.h> 1417be2d2bSAdrian McMenamin #include <linux/kernel.h> 1517be2d2bSAdrian McMenamin #include <linux/device.h> 1617be2d2bSAdrian McMenamin #include <linux/interrupt.h> 1717be2d2bSAdrian McMenamin #include <linux/list.h> 1817be2d2bSAdrian McMenamin #include <linux/io.h> 1917be2d2bSAdrian McMenamin #include <linux/slab.h> 2017be2d2bSAdrian McMenamin #include <linux/maple.h> 2117be2d2bSAdrian McMenamin #include <linux/dma-mapping.h> 221795cf48SAdrian McMenamin #include <linux/delay.h> 23db4e8395SPaul Gortmaker #include <linux/module.h> 2417be2d2bSAdrian McMenamin #include <asm/cacheflush.h> 2517be2d2bSAdrian McMenamin #include <asm/dma.h> 2617be2d2bSAdrian McMenamin #include <asm/io.h> 271795cf48SAdrian McMenamin #include <mach/dma.h> 281795cf48SAdrian McMenamin #include <mach/sysasic.h> 2917be2d2bSAdrian McMenamin 30b233b28eSAdrian McMenamin MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); 3117be2d2bSAdrian McMenamin MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); 3217be2d2bSAdrian McMenamin MODULE_LICENSE("GPL v2"); 3317be2d2bSAdrian McMenamin 3417be2d2bSAdrian McMenamin static void maple_dma_handler(struct work_struct *work); 3517be2d2bSAdrian McMenamin static void maple_vblank_handler(struct work_struct *work); 3617be2d2bSAdrian McMenamin 3717be2d2bSAdrian McMenamin static DECLARE_WORK(maple_dma_process, maple_dma_handler); 3817be2d2bSAdrian McMenamin static DECLARE_WORK(maple_vblank_process, maple_vblank_handler); 3917be2d2bSAdrian McMenamin 4017be2d2bSAdrian McMenamin static LIST_HEAD(maple_waitq); 4117be2d2bSAdrian McMenamin static LIST_HEAD(maple_sentq); 4217be2d2bSAdrian McMenamin 431795cf48SAdrian McMenamin /* mutex to protect queue of waiting packets */ 441795cf48SAdrian McMenamin static DEFINE_MUTEX(maple_wlist_lock); 4517be2d2bSAdrian McMenamin 46b233b28eSAdrian McMenamin static struct maple_driver maple_unsupported_device; 4717be2d2bSAdrian McMenamin static struct device maple_bus; 4817be2d2bSAdrian McMenamin static int subdevice_map[MAPLE_PORTS]; 4917be2d2bSAdrian McMenamin static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; 5017be2d2bSAdrian McMenamin static unsigned long maple_pnp_time; 511795cf48SAdrian McMenamin static int started, scanning, fullscan; 5217be2d2bSAdrian McMenamin static struct kmem_cache *maple_queue_cache; 5317be2d2bSAdrian McMenamin 5417be2d2bSAdrian McMenamin struct maple_device_specify { 5517be2d2bSAdrian McMenamin int port; 5617be2d2bSAdrian McMenamin int unit; 5717be2d2bSAdrian McMenamin }; 5817be2d2bSAdrian McMenamin 59b233b28eSAdrian McMenamin static bool checked[MAPLE_PORTS]; 60b233b28eSAdrian McMenamin static bool empty[MAPLE_PORTS]; 61b233b28eSAdrian McMenamin static struct maple_device *baseunits[MAPLE_PORTS]; 62bd496669SAdrian McMenamin 6317be2d2bSAdrian McMenamin /** 6463870295SPaul Mundt * maple_driver_register - register a maple driver 6563870295SPaul Mundt * @drv: maple driver to be registered. 6663870295SPaul Mundt * 6763870295SPaul Mundt * Registers the passed in @drv, while updating the bus type. 6863870295SPaul Mundt * Devices with matching function IDs will be automatically probed. 6917be2d2bSAdrian McMenamin */ 7063870295SPaul Mundt int maple_driver_register(struct maple_driver *drv) 7117be2d2bSAdrian McMenamin { 7217be2d2bSAdrian McMenamin if (!drv) 7317be2d2bSAdrian McMenamin return -EINVAL; 7463870295SPaul Mundt 7563870295SPaul Mundt drv->drv.bus = &maple_bus_type; 7663870295SPaul Mundt 7763870295SPaul Mundt return driver_register(&drv->drv); 7817be2d2bSAdrian McMenamin } 7917be2d2bSAdrian McMenamin EXPORT_SYMBOL_GPL(maple_driver_register); 8017be2d2bSAdrian McMenamin 8163870295SPaul Mundt /** 8263870295SPaul Mundt * maple_driver_unregister - unregister a maple driver. 8363870295SPaul Mundt * @drv: maple driver to unregister. 8463870295SPaul Mundt * 8563870295SPaul Mundt * Cleans up after maple_driver_register(). To be invoked in the exit 8663870295SPaul Mundt * path of any module drivers. 8763870295SPaul Mundt */ 8863870295SPaul Mundt void maple_driver_unregister(struct maple_driver *drv) 8963870295SPaul Mundt { 9063870295SPaul Mundt driver_unregister(&drv->drv); 9163870295SPaul Mundt } 9261787063SPaul Mundt EXPORT_SYMBOL_GPL(maple_driver_unregister); 9363870295SPaul Mundt 9417be2d2bSAdrian McMenamin /* set hardware registers to enable next round of dma */ 95b233b28eSAdrian McMenamin static void maple_dma_reset(void) 9617be2d2bSAdrian McMenamin { 97c0537844SPaul Mundt __raw_writel(MAPLE_MAGIC, MAPLE_RESET); 9817be2d2bSAdrian McMenamin /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ 99c0537844SPaul Mundt __raw_writel(1, MAPLE_TRIGTYPE); 100b233b28eSAdrian McMenamin /* 101b233b28eSAdrian McMenamin * Maple system register 102b233b28eSAdrian McMenamin * bits 31 - 16 timeout in units of 20nsec 103b233b28eSAdrian McMenamin * bit 12 hard trigger - set 0 to keep responding to VBLANK 104b233b28eSAdrian McMenamin * bits 9 - 8 set 00 for 2 Mbps, 01 for 1 Mbps 105b233b28eSAdrian McMenamin * bits 3 - 0 delay (in 1.3ms) between VBLANK and start of DMA 106b233b28eSAdrian McMenamin * max delay is 11 107b233b28eSAdrian McMenamin */ 108c0537844SPaul Mundt __raw_writel(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED); 109c0537844SPaul Mundt __raw_writel(virt_to_phys(maple_sendbuf), MAPLE_DMAADDR); 110c0537844SPaul Mundt __raw_writel(1, MAPLE_ENABLE); 11117be2d2bSAdrian McMenamin } 11217be2d2bSAdrian McMenamin 11317be2d2bSAdrian McMenamin /** 11417be2d2bSAdrian McMenamin * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND 11517be2d2bSAdrian McMenamin * @dev: device responding 11617be2d2bSAdrian McMenamin * @callback: handler callback 11717be2d2bSAdrian McMenamin * @interval: interval in jiffies between callbacks 11817be2d2bSAdrian McMenamin * @function: the function code for the device 11917be2d2bSAdrian McMenamin */ 12017be2d2bSAdrian McMenamin void maple_getcond_callback(struct maple_device *dev, 12117be2d2bSAdrian McMenamin void (*callback) (struct mapleq *mq), 12217be2d2bSAdrian McMenamin unsigned long interval, unsigned long function) 12317be2d2bSAdrian McMenamin { 12417be2d2bSAdrian McMenamin dev->callback = callback; 12517be2d2bSAdrian McMenamin dev->interval = interval; 12617be2d2bSAdrian McMenamin dev->function = cpu_to_be32(function); 12717be2d2bSAdrian McMenamin dev->when = jiffies; 12817be2d2bSAdrian McMenamin } 12917be2d2bSAdrian McMenamin EXPORT_SYMBOL_GPL(maple_getcond_callback); 13017be2d2bSAdrian McMenamin 13117be2d2bSAdrian McMenamin static int maple_dma_done(void) 13217be2d2bSAdrian McMenamin { 133c0537844SPaul Mundt return (__raw_readl(MAPLE_STATE) & 1) == 0; 13417be2d2bSAdrian McMenamin } 13517be2d2bSAdrian McMenamin 13617be2d2bSAdrian McMenamin static void maple_release_device(struct device *dev) 13717be2d2bSAdrian McMenamin { 138b3c69e24SAdrian McMenamin struct maple_device *mdev; 139b3c69e24SAdrian McMenamin struct mapleq *mq; 140b233b28eSAdrian McMenamin 141b3c69e24SAdrian McMenamin mdev = to_maple_dev(dev); 142b3c69e24SAdrian McMenamin mq = mdev->mq; 143b233b28eSAdrian McMenamin kmem_cache_free(maple_queue_cache, mq->recvbuf); 144b3c69e24SAdrian McMenamin kfree(mq); 145b3c69e24SAdrian McMenamin kfree(mdev); 14617be2d2bSAdrian McMenamin } 14717be2d2bSAdrian McMenamin 1486a9545bdSPaul Mundt /** 149b233b28eSAdrian McMenamin * maple_add_packet - add a single instruction to the maple bus queue 1506a9545bdSPaul Mundt * @mdev: maple device 1516a9545bdSPaul Mundt * @function: function on device being queried 1526a9545bdSPaul Mundt * @command: maple command to add 1536a9545bdSPaul Mundt * @length: length of command string (in 32 bit words) 1546a9545bdSPaul Mundt * @data: remainder of command string 15517be2d2bSAdrian McMenamin */ 1561795cf48SAdrian McMenamin int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, 1571795cf48SAdrian McMenamin size_t length, void *data) 15817be2d2bSAdrian McMenamin { 159b233b28eSAdrian McMenamin int ret = 0; 1601795cf48SAdrian McMenamin void *sendbuf = NULL; 1611795cf48SAdrian McMenamin 1621795cf48SAdrian McMenamin if (length) { 1636396bb22SKees Cook sendbuf = kcalloc(length, 4, GFP_KERNEL); 1641795cf48SAdrian McMenamin if (!sendbuf) { 1651795cf48SAdrian McMenamin ret = -ENOMEM; 1661795cf48SAdrian McMenamin goto out; 1671795cf48SAdrian McMenamin } 1681795cf48SAdrian McMenamin ((__be32 *)sendbuf)[0] = cpu_to_be32(function); 1691795cf48SAdrian McMenamin } 1701795cf48SAdrian McMenamin 1711795cf48SAdrian McMenamin mdev->mq->command = command; 1721795cf48SAdrian McMenamin mdev->mq->length = length; 1731795cf48SAdrian McMenamin if (length > 1) 1741795cf48SAdrian McMenamin memcpy(sendbuf + 4, data, (length - 1) * 4); 1751795cf48SAdrian McMenamin mdev->mq->sendbuf = sendbuf; 1761795cf48SAdrian McMenamin 177b233b28eSAdrian McMenamin mutex_lock(&maple_wlist_lock); 178b233b28eSAdrian McMenamin list_add_tail(&mdev->mq->list, &maple_waitq); 1791795cf48SAdrian McMenamin mutex_unlock(&maple_wlist_lock); 180b233b28eSAdrian McMenamin out: 1811795cf48SAdrian McMenamin return ret; 18217be2d2bSAdrian McMenamin } 18317be2d2bSAdrian McMenamin EXPORT_SYMBOL_GPL(maple_add_packet); 18417be2d2bSAdrian McMenamin 185b3c69e24SAdrian McMenamin static struct mapleq *maple_allocq(struct maple_device *mdev) 18617be2d2bSAdrian McMenamin { 18717be2d2bSAdrian McMenamin struct mapleq *mq; 18817be2d2bSAdrian McMenamin 189b233b28eSAdrian McMenamin mq = kzalloc(sizeof(*mq), GFP_KERNEL); 19017be2d2bSAdrian McMenamin if (!mq) 1911795cf48SAdrian McMenamin goto failed_nomem; 19217be2d2bSAdrian McMenamin 193b233b28eSAdrian McMenamin INIT_LIST_HEAD(&mq->list); 194b3c69e24SAdrian McMenamin mq->dev = mdev; 195b233b28eSAdrian McMenamin mq->recvbuf = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); 1961795cf48SAdrian McMenamin if (!mq->recvbuf) 1971795cf48SAdrian McMenamin goto failed_p2; 198b233b28eSAdrian McMenamin mq->recvbuf->buf = &((mq->recvbuf->bufx)[0]); 19917be2d2bSAdrian McMenamin 20017be2d2bSAdrian McMenamin return mq; 2011795cf48SAdrian McMenamin 2021795cf48SAdrian McMenamin failed_p2: 2031795cf48SAdrian McMenamin kfree(mq); 2041795cf48SAdrian McMenamin failed_nomem: 205b233b28eSAdrian McMenamin dev_err(&mdev->dev, "could not allocate memory for device (%d, %d)\n", 206b233b28eSAdrian McMenamin mdev->port, mdev->unit); 2071795cf48SAdrian McMenamin return NULL; 20817be2d2bSAdrian McMenamin } 20917be2d2bSAdrian McMenamin 21017be2d2bSAdrian McMenamin static struct maple_device *maple_alloc_dev(int port, int unit) 21117be2d2bSAdrian McMenamin { 212b3c69e24SAdrian McMenamin struct maple_device *mdev; 21317be2d2bSAdrian McMenamin 214b233b28eSAdrian McMenamin /* zero this out to avoid kobj subsystem 215b233b28eSAdrian McMenamin * thinking it has already been registered */ 216b233b28eSAdrian McMenamin 217b3c69e24SAdrian McMenamin mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 218b3c69e24SAdrian McMenamin if (!mdev) 21917be2d2bSAdrian McMenamin return NULL; 22017be2d2bSAdrian McMenamin 221b3c69e24SAdrian McMenamin mdev->port = port; 222b3c69e24SAdrian McMenamin mdev->unit = unit; 223b233b28eSAdrian McMenamin 224b3c69e24SAdrian McMenamin mdev->mq = maple_allocq(mdev); 22517be2d2bSAdrian McMenamin 226b3c69e24SAdrian McMenamin if (!mdev->mq) { 227b3c69e24SAdrian McMenamin kfree(mdev); 22817be2d2bSAdrian McMenamin return NULL; 22917be2d2bSAdrian McMenamin } 230b3c69e24SAdrian McMenamin mdev->dev.bus = &maple_bus_type; 231b3c69e24SAdrian McMenamin mdev->dev.parent = &maple_bus; 232b233b28eSAdrian McMenamin init_waitqueue_head(&mdev->maple_wait); 233b3c69e24SAdrian McMenamin return mdev; 23417be2d2bSAdrian McMenamin } 23517be2d2bSAdrian McMenamin 23617be2d2bSAdrian McMenamin static void maple_free_dev(struct maple_device *mdev) 23717be2d2bSAdrian McMenamin { 238b233b28eSAdrian McMenamin kmem_cache_free(maple_queue_cache, mdev->mq->recvbuf); 23917be2d2bSAdrian McMenamin kfree(mdev->mq); 24017be2d2bSAdrian McMenamin kfree(mdev); 24117be2d2bSAdrian McMenamin } 24217be2d2bSAdrian McMenamin 24317be2d2bSAdrian McMenamin /* process the command queue into a maple command block 24417be2d2bSAdrian McMenamin * terminating command has bit 32 of first long set to 0 24517be2d2bSAdrian McMenamin */ 24617be2d2bSAdrian McMenamin static void maple_build_block(struct mapleq *mq) 24717be2d2bSAdrian McMenamin { 24817be2d2bSAdrian McMenamin int port, unit, from, to, len; 24917be2d2bSAdrian McMenamin unsigned long *lsendbuf = mq->sendbuf; 25017be2d2bSAdrian McMenamin 25117be2d2bSAdrian McMenamin port = mq->dev->port & 3; 25217be2d2bSAdrian McMenamin unit = mq->dev->unit; 25317be2d2bSAdrian McMenamin len = mq->length; 25417be2d2bSAdrian McMenamin from = port << 6; 25517be2d2bSAdrian McMenamin to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); 25617be2d2bSAdrian McMenamin 25717be2d2bSAdrian McMenamin *maple_lastptr &= 0x7fffffff; 25817be2d2bSAdrian McMenamin maple_lastptr = maple_sendptr; 25917be2d2bSAdrian McMenamin 26017be2d2bSAdrian McMenamin *maple_sendptr++ = (port << 16) | len | 0x80000000; 261913df445SPaul Mundt *maple_sendptr++ = virt_to_phys(mq->recvbuf->buf); 26217be2d2bSAdrian McMenamin *maple_sendptr++ = 26317be2d2bSAdrian McMenamin mq->command | (to << 8) | (from << 16) | (len << 24); 26417be2d2bSAdrian McMenamin while (len-- > 0) 26517be2d2bSAdrian McMenamin *maple_sendptr++ = *lsendbuf++; 26617be2d2bSAdrian McMenamin } 26717be2d2bSAdrian McMenamin 26817be2d2bSAdrian McMenamin /* build up command queue */ 26917be2d2bSAdrian McMenamin static void maple_send(void) 27017be2d2bSAdrian McMenamin { 2711795cf48SAdrian McMenamin int i, maple_packets = 0; 27217be2d2bSAdrian McMenamin struct mapleq *mq, *nmq; 27317be2d2bSAdrian McMenamin 274b233b28eSAdrian McMenamin if (!maple_dma_done()) 275b233b28eSAdrian McMenamin return; 276b233b28eSAdrian McMenamin 277b233b28eSAdrian McMenamin /* disable DMA */ 278c0537844SPaul Mundt __raw_writel(0, MAPLE_ENABLE); 279b233b28eSAdrian McMenamin 28017be2d2bSAdrian McMenamin if (!list_empty(&maple_sentq)) 281b233b28eSAdrian McMenamin goto finish; 282b233b28eSAdrian McMenamin 2831795cf48SAdrian McMenamin mutex_lock(&maple_wlist_lock); 284b233b28eSAdrian McMenamin if (list_empty(&maple_waitq)) { 2851795cf48SAdrian McMenamin mutex_unlock(&maple_wlist_lock); 286b233b28eSAdrian McMenamin goto finish; 2871795cf48SAdrian McMenamin } 288b233b28eSAdrian McMenamin 2891795cf48SAdrian McMenamin maple_lastptr = maple_sendbuf; 2901795cf48SAdrian McMenamin maple_sendptr = maple_sendbuf; 291b233b28eSAdrian McMenamin 29217be2d2bSAdrian McMenamin list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { 29317be2d2bSAdrian McMenamin maple_build_block(mq); 294b233b28eSAdrian McMenamin list_del_init(&mq->list); 295b233b28eSAdrian McMenamin list_add_tail(&mq->list, &maple_sentq); 29617be2d2bSAdrian McMenamin if (maple_packets++ > MAPLE_MAXPACKETS) 29717be2d2bSAdrian McMenamin break; 29817be2d2bSAdrian McMenamin } 2991795cf48SAdrian McMenamin mutex_unlock(&maple_wlist_lock); 30017be2d2bSAdrian McMenamin if (maple_packets > 0) { 30117be2d2bSAdrian McMenamin for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) 30247fcae0dSChristoph Hellwig __flush_purge_region(maple_sendbuf + i * PAGE_SIZE, 30347fcae0dSChristoph Hellwig PAGE_SIZE); 30417be2d2bSAdrian McMenamin } 305b233b28eSAdrian McMenamin 306b233b28eSAdrian McMenamin finish: 307b233b28eSAdrian McMenamin maple_dma_reset(); 30817be2d2bSAdrian McMenamin } 30917be2d2bSAdrian McMenamin 3101795cf48SAdrian McMenamin /* check if there is a driver registered likely to match this device */ 311b233b28eSAdrian McMenamin static int maple_check_matching_driver(struct device_driver *driver, 31217be2d2bSAdrian McMenamin void *devptr) 31317be2d2bSAdrian McMenamin { 31417be2d2bSAdrian McMenamin struct maple_driver *maple_drv; 31517be2d2bSAdrian McMenamin struct maple_device *mdev; 31617be2d2bSAdrian McMenamin 31717be2d2bSAdrian McMenamin mdev = devptr; 31817be2d2bSAdrian McMenamin maple_drv = to_maple_driver(driver); 3191795cf48SAdrian McMenamin if (mdev->devinfo.function & cpu_to_be32(maple_drv->function)) 32017be2d2bSAdrian McMenamin return 1; 32117be2d2bSAdrian McMenamin return 0; 32217be2d2bSAdrian McMenamin } 32317be2d2bSAdrian McMenamin 32417be2d2bSAdrian McMenamin static void maple_detach_driver(struct maple_device *mdev) 32517be2d2bSAdrian McMenamin { 32617be2d2bSAdrian McMenamin device_unregister(&mdev->dev); 32717be2d2bSAdrian McMenamin } 32817be2d2bSAdrian McMenamin 32917be2d2bSAdrian McMenamin /* process initial MAPLE_COMMAND_DEVINFO for each device or port */ 330b3c69e24SAdrian McMenamin static void maple_attach_driver(struct maple_device *mdev) 33117be2d2bSAdrian McMenamin { 332b3c69e24SAdrian McMenamin char *p, *recvbuf; 33317be2d2bSAdrian McMenamin unsigned long function; 334b233b28eSAdrian McMenamin int matched, error; 33517be2d2bSAdrian McMenamin 336b233b28eSAdrian McMenamin recvbuf = mdev->mq->recvbuf->buf; 337b3c69e24SAdrian McMenamin /* copy the data as individual elements in 338b3c69e24SAdrian McMenamin * case of memory optimisation */ 339b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.function, recvbuf + 4, 4); 340b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.function_data[0], recvbuf + 8, 12); 341b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1); 342b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1); 343b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30); 344b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2); 345b3c69e24SAdrian McMenamin memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2); 346b3c69e24SAdrian McMenamin memcpy(mdev->product_name, mdev->devinfo.product_name, 30); 347b3c69e24SAdrian McMenamin mdev->product_name[30] = '\0'; 348b3c69e24SAdrian McMenamin memcpy(mdev->product_licence, mdev->devinfo.product_licence, 60); 349b3c69e24SAdrian McMenamin mdev->product_licence[60] = '\0'; 35017be2d2bSAdrian McMenamin 351b3c69e24SAdrian McMenamin for (p = mdev->product_name + 29; mdev->product_name <= p; p--) 352b3c69e24SAdrian McMenamin if (*p == ' ') 353b3c69e24SAdrian McMenamin *p = '\0'; 354b3c69e24SAdrian McMenamin else 355b3c69e24SAdrian McMenamin break; 356b3c69e24SAdrian McMenamin for (p = mdev->product_licence + 59; mdev->product_licence <= p; p--) 35717be2d2bSAdrian McMenamin if (*p == ' ') 35817be2d2bSAdrian McMenamin *p = '\0'; 35917be2d2bSAdrian McMenamin else 36017be2d2bSAdrian McMenamin break; 36117be2d2bSAdrian McMenamin 362b3c69e24SAdrian McMenamin function = be32_to_cpu(mdev->devinfo.function); 36317be2d2bSAdrian McMenamin 364b233b28eSAdrian McMenamin dev_info(&mdev->dev, "detected %s: function 0x%lX: at (%d, %d)\n", 365b233b28eSAdrian McMenamin mdev->product_name, function, mdev->port, mdev->unit); 366b233b28eSAdrian McMenamin 36717be2d2bSAdrian McMenamin if (function > 0x200) { 36817be2d2bSAdrian McMenamin /* Do this silently - as not a real device */ 36917be2d2bSAdrian McMenamin function = 0; 370b233b28eSAdrian McMenamin mdev->driver = &maple_unsupported_device; 37193fde774SKay Sievers dev_set_name(&mdev->dev, "%d:0.port", mdev->port); 37217be2d2bSAdrian McMenamin } else { 37317be2d2bSAdrian McMenamin matched = 374b3c69e24SAdrian McMenamin bus_for_each_drv(&maple_bus_type, NULL, mdev, 375b233b28eSAdrian McMenamin maple_check_matching_driver); 37617be2d2bSAdrian McMenamin 37717be2d2bSAdrian McMenamin if (matched == 0) { 37817be2d2bSAdrian McMenamin /* Driver does not exist yet */ 379b233b28eSAdrian McMenamin dev_info(&mdev->dev, "no driver found\n"); 380b233b28eSAdrian McMenamin mdev->driver = &maple_unsupported_device; 38117be2d2bSAdrian McMenamin } 38293fde774SKay Sievers dev_set_name(&mdev->dev, "%d:0%d.%lX", mdev->port, 383b3c69e24SAdrian McMenamin mdev->unit, function); 38417be2d2bSAdrian McMenamin } 385b233b28eSAdrian McMenamin 386b3c69e24SAdrian McMenamin mdev->function = function; 387b3c69e24SAdrian McMenamin mdev->dev.release = &maple_release_device; 388b233b28eSAdrian McMenamin 389b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 390b233b28eSAdrian McMenamin error = device_register(&mdev->dev); 391b233b28eSAdrian McMenamin if (error) { 392b233b28eSAdrian McMenamin dev_warn(&mdev->dev, "could not register device at" 393b233b28eSAdrian McMenamin " (%d, %d), with error 0x%X\n", mdev->unit, 394b233b28eSAdrian McMenamin mdev->port, error); 395b3c69e24SAdrian McMenamin maple_free_dev(mdev); 396b3c69e24SAdrian McMenamin mdev = NULL; 397b3c69e24SAdrian McMenamin return; 39817be2d2bSAdrian McMenamin } 39917be2d2bSAdrian McMenamin } 40017be2d2bSAdrian McMenamin 40117be2d2bSAdrian McMenamin /* 40217be2d2bSAdrian McMenamin * if device has been registered for the given 40317be2d2bSAdrian McMenamin * port and unit then return 1 - allows identification 40417be2d2bSAdrian McMenamin * of which devices need to be attached or detached 40517be2d2bSAdrian McMenamin */ 406b233b28eSAdrian McMenamin static int check_maple_device(struct device *device, void *portptr) 40717be2d2bSAdrian McMenamin { 40817be2d2bSAdrian McMenamin struct maple_device_specify *ds; 40917be2d2bSAdrian McMenamin struct maple_device *mdev; 41017be2d2bSAdrian McMenamin 41117be2d2bSAdrian McMenamin ds = portptr; 41217be2d2bSAdrian McMenamin mdev = to_maple_dev(device); 41317be2d2bSAdrian McMenamin if (mdev->port == ds->port && mdev->unit == ds->unit) 41417be2d2bSAdrian McMenamin return 1; 41517be2d2bSAdrian McMenamin return 0; 41617be2d2bSAdrian McMenamin } 41717be2d2bSAdrian McMenamin 41817be2d2bSAdrian McMenamin static int setup_maple_commands(struct device *device, void *ignored) 41917be2d2bSAdrian McMenamin { 4201795cf48SAdrian McMenamin int add; 421b233b28eSAdrian McMenamin struct maple_device *mdev = to_maple_dev(device); 422b233b28eSAdrian McMenamin if (mdev->interval > 0 && atomic_read(&mdev->busy) == 0 && 423b233b28eSAdrian McMenamin time_after(jiffies, mdev->when)) { 424b233b28eSAdrian McMenamin /* bounce if we cannot add */ 425b233b28eSAdrian McMenamin add = maple_add_packet(mdev, 426b233b28eSAdrian McMenamin be32_to_cpu(mdev->devinfo.function), 4271795cf48SAdrian McMenamin MAPLE_COMMAND_GETCOND, 1, NULL); 4281795cf48SAdrian McMenamin if (!add) 429b233b28eSAdrian McMenamin mdev->when = jiffies + mdev->interval; 43017be2d2bSAdrian McMenamin } else { 4311795cf48SAdrian McMenamin if (time_after(jiffies, maple_pnp_time)) 432b233b28eSAdrian McMenamin /* Ensure we don't have block reads and devinfo 433b233b28eSAdrian McMenamin * calls interfering with one another - so flag the 434b233b28eSAdrian McMenamin * device as busy */ 435b233b28eSAdrian McMenamin if (atomic_read(&mdev->busy) == 0) { 436b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 1); 437b233b28eSAdrian McMenamin maple_add_packet(mdev, 0, 4381795cf48SAdrian McMenamin MAPLE_COMMAND_DEVINFO, 0, NULL); 43917be2d2bSAdrian McMenamin } 440b233b28eSAdrian McMenamin } 44117be2d2bSAdrian McMenamin return 0; 44217be2d2bSAdrian McMenamin } 44317be2d2bSAdrian McMenamin 44417be2d2bSAdrian McMenamin /* VBLANK bottom half - implemented via workqueue */ 44517be2d2bSAdrian McMenamin static void maple_vblank_handler(struct work_struct *work) 44617be2d2bSAdrian McMenamin { 447b233b28eSAdrian McMenamin int x, locking; 448b233b28eSAdrian McMenamin struct maple_device *mdev; 449b233b28eSAdrian McMenamin 450b233b28eSAdrian McMenamin if (!maple_dma_done()) 45117be2d2bSAdrian McMenamin return; 4521795cf48SAdrian McMenamin 453c0537844SPaul Mundt __raw_writel(0, MAPLE_ENABLE); 4541795cf48SAdrian McMenamin 455b233b28eSAdrian McMenamin if (!list_empty(&maple_sentq)) 456b233b28eSAdrian McMenamin goto finish; 457b233b28eSAdrian McMenamin 458b233b28eSAdrian McMenamin /* 459b233b28eSAdrian McMenamin * Set up essential commands - to fetch data and 460b233b28eSAdrian McMenamin * check devices are still present 461b233b28eSAdrian McMenamin */ 46217be2d2bSAdrian McMenamin bus_for_each_dev(&maple_bus_type, NULL, NULL, 46317be2d2bSAdrian McMenamin setup_maple_commands); 4641795cf48SAdrian McMenamin 465b233b28eSAdrian McMenamin if (time_after(jiffies, maple_pnp_time)) { 466b233b28eSAdrian McMenamin /* 467b233b28eSAdrian McMenamin * Scan the empty ports - bus is flakey and may have 468b233b28eSAdrian McMenamin * mis-reported emptyness 469b233b28eSAdrian McMenamin */ 470b233b28eSAdrian McMenamin for (x = 0; x < MAPLE_PORTS; x++) { 471b233b28eSAdrian McMenamin if (checked[x] && empty[x]) { 472b233b28eSAdrian McMenamin mdev = baseunits[x]; 473b233b28eSAdrian McMenamin if (!mdev) 474b233b28eSAdrian McMenamin break; 475b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 1); 476b233b28eSAdrian McMenamin locking = maple_add_packet(mdev, 0, 477b233b28eSAdrian McMenamin MAPLE_COMMAND_DEVINFO, 0, NULL); 478b233b28eSAdrian McMenamin if (!locking) 479b233b28eSAdrian McMenamin break; 480b233b28eSAdrian McMenamin } 48117be2d2bSAdrian McMenamin } 4821795cf48SAdrian McMenamin 483b233b28eSAdrian McMenamin maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; 484b233b28eSAdrian McMenamin } 485b233b28eSAdrian McMenamin 486b233b28eSAdrian McMenamin finish: 487b233b28eSAdrian McMenamin maple_send(); 48817be2d2bSAdrian McMenamin } 48917be2d2bSAdrian McMenamin 49017be2d2bSAdrian McMenamin /* handle devices added via hotplugs - placing them on queue for DEVINFO */ 49117be2d2bSAdrian McMenamin static void maple_map_subunits(struct maple_device *mdev, int submask) 49217be2d2bSAdrian McMenamin { 49317be2d2bSAdrian McMenamin int retval, k, devcheck; 49417be2d2bSAdrian McMenamin struct maple_device *mdev_add; 49517be2d2bSAdrian McMenamin struct maple_device_specify ds; 49617be2d2bSAdrian McMenamin 49717be2d2bSAdrian McMenamin ds.port = mdev->port; 4981795cf48SAdrian McMenamin for (k = 0; k < 5; k++) { 49917be2d2bSAdrian McMenamin ds.unit = k + 1; 50017be2d2bSAdrian McMenamin retval = 50117be2d2bSAdrian McMenamin bus_for_each_dev(&maple_bus_type, NULL, &ds, 502b233b28eSAdrian McMenamin check_maple_device); 50317be2d2bSAdrian McMenamin if (retval) { 50417be2d2bSAdrian McMenamin submask = submask >> 1; 50517be2d2bSAdrian McMenamin continue; 50617be2d2bSAdrian McMenamin } 50717be2d2bSAdrian McMenamin devcheck = submask & 0x01; 50817be2d2bSAdrian McMenamin if (devcheck) { 50917be2d2bSAdrian McMenamin mdev_add = maple_alloc_dev(mdev->port, k + 1); 51017be2d2bSAdrian McMenamin if (!mdev_add) 51117be2d2bSAdrian McMenamin return; 512b233b28eSAdrian McMenamin atomic_set(&mdev_add->busy, 1); 5131795cf48SAdrian McMenamin maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO, 5141795cf48SAdrian McMenamin 0, NULL); 5151795cf48SAdrian McMenamin /* mark that we are checking sub devices */ 51617be2d2bSAdrian McMenamin scanning = 1; 51717be2d2bSAdrian McMenamin } 51817be2d2bSAdrian McMenamin submask = submask >> 1; 51917be2d2bSAdrian McMenamin } 52017be2d2bSAdrian McMenamin } 52117be2d2bSAdrian McMenamin 52217be2d2bSAdrian McMenamin /* mark a device as removed */ 52317be2d2bSAdrian McMenamin static void maple_clean_submap(struct maple_device *mdev) 52417be2d2bSAdrian McMenamin { 52517be2d2bSAdrian McMenamin int killbit; 52617be2d2bSAdrian McMenamin 52717be2d2bSAdrian McMenamin killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); 52817be2d2bSAdrian McMenamin killbit = ~killbit; 52917be2d2bSAdrian McMenamin killbit &= 0xFF; 53017be2d2bSAdrian McMenamin subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; 53117be2d2bSAdrian McMenamin } 53217be2d2bSAdrian McMenamin 53317be2d2bSAdrian McMenamin /* handle empty port or hotplug removal */ 534b233b28eSAdrian McMenamin static void maple_response_none(struct maple_device *mdev) 53517be2d2bSAdrian McMenamin { 53617be2d2bSAdrian McMenamin maple_clean_submap(mdev); 537b233b28eSAdrian McMenamin 538b233b28eSAdrian McMenamin if (likely(mdev->unit != 0)) { 539b233b28eSAdrian McMenamin /* 540b233b28eSAdrian McMenamin * Block devices play up 541b233b28eSAdrian McMenamin * and give the impression they have 542b233b28eSAdrian McMenamin * been removed even when still in place or 543b233b28eSAdrian McMenamin * trip the mtd layer when they have 544b233b28eSAdrian McMenamin * really gone - this code traps that eventuality 545b233b28eSAdrian McMenamin * and ensures we aren't overloaded with useless 546b233b28eSAdrian McMenamin * error messages 547b233b28eSAdrian McMenamin */ 548b233b28eSAdrian McMenamin if (mdev->can_unload) { 549b233b28eSAdrian McMenamin if (!mdev->can_unload(mdev)) { 550b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 2); 551b233b28eSAdrian McMenamin wake_up(&mdev->maple_wait); 552b233b28eSAdrian McMenamin return; 553b233b28eSAdrian McMenamin } 554b233b28eSAdrian McMenamin } 555b233b28eSAdrian McMenamin 556b233b28eSAdrian McMenamin dev_info(&mdev->dev, "detaching device at (%d, %d)\n", 55717be2d2bSAdrian McMenamin mdev->port, mdev->unit); 55817be2d2bSAdrian McMenamin maple_detach_driver(mdev); 55917be2d2bSAdrian McMenamin return; 560b233b28eSAdrian McMenamin } else { 561bd496669SAdrian McMenamin if (!started || !fullscan) { 562bd496669SAdrian McMenamin if (checked[mdev->port] == false) { 563bd496669SAdrian McMenamin checked[mdev->port] = true; 564b233b28eSAdrian McMenamin empty[mdev->port] = true; 565b233b28eSAdrian McMenamin dev_info(&mdev->dev, "no devices" 566bd496669SAdrian McMenamin " to port %d\n", mdev->port); 567bd496669SAdrian McMenamin } 56817be2d2bSAdrian McMenamin return; 56917be2d2bSAdrian McMenamin } 570b233b28eSAdrian McMenamin } 571b233b28eSAdrian McMenamin /* Some hardware devices generate false detach messages on unit 0 */ 572b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 57317be2d2bSAdrian McMenamin } 57417be2d2bSAdrian McMenamin 57517be2d2bSAdrian McMenamin /* preprocess hotplugs or scans */ 57617be2d2bSAdrian McMenamin static void maple_response_devinfo(struct maple_device *mdev, 57717be2d2bSAdrian McMenamin char *recvbuf) 57817be2d2bSAdrian McMenamin { 57917be2d2bSAdrian McMenamin char submask; 580bd496669SAdrian McMenamin if (!started || (scanning == 2) || !fullscan) { 581bd496669SAdrian McMenamin if ((mdev->unit == 0) && (checked[mdev->port] == false)) { 582bd496669SAdrian McMenamin checked[mdev->port] = true; 58317be2d2bSAdrian McMenamin maple_attach_driver(mdev); 584bd496669SAdrian McMenamin } else { 585bd496669SAdrian McMenamin if (mdev->unit != 0) 586bd496669SAdrian McMenamin maple_attach_driver(mdev); 587b233b28eSAdrian McMenamin if (mdev->unit == 0) { 588b233b28eSAdrian McMenamin empty[mdev->port] = false; 589b233b28eSAdrian McMenamin maple_attach_driver(mdev); 590bd496669SAdrian McMenamin } 591b233b28eSAdrian McMenamin } 59217be2d2bSAdrian McMenamin } 59317be2d2bSAdrian McMenamin if (mdev->unit == 0) { 59417be2d2bSAdrian McMenamin submask = recvbuf[2] & 0x1F; 59517be2d2bSAdrian McMenamin if (submask ^ subdevice_map[mdev->port]) { 59617be2d2bSAdrian McMenamin maple_map_subunits(mdev, submask); 59717be2d2bSAdrian McMenamin subdevice_map[mdev->port] = submask; 59817be2d2bSAdrian McMenamin } 59917be2d2bSAdrian McMenamin } 60017be2d2bSAdrian McMenamin } 60117be2d2bSAdrian McMenamin 602b233b28eSAdrian McMenamin static void maple_response_fileerr(struct maple_device *mdev, void *recvbuf) 603b233b28eSAdrian McMenamin { 604b233b28eSAdrian McMenamin if (mdev->fileerr_handler) { 605b233b28eSAdrian McMenamin mdev->fileerr_handler(mdev, recvbuf); 606b233b28eSAdrian McMenamin return; 607b233b28eSAdrian McMenamin } else 608b233b28eSAdrian McMenamin dev_warn(&mdev->dev, "device at (%d, %d) reports" 609b233b28eSAdrian McMenamin "file error 0x%X\n", mdev->port, mdev->unit, 610b233b28eSAdrian McMenamin ((int *)recvbuf)[1]); 611b233b28eSAdrian McMenamin } 612b233b28eSAdrian McMenamin 6131795cf48SAdrian McMenamin static void maple_port_rescan(void) 6141795cf48SAdrian McMenamin { 6151795cf48SAdrian McMenamin int i; 6161795cf48SAdrian McMenamin struct maple_device *mdev; 6171795cf48SAdrian McMenamin 6181795cf48SAdrian McMenamin fullscan = 1; 6191795cf48SAdrian McMenamin for (i = 0; i < MAPLE_PORTS; i++) { 6201795cf48SAdrian McMenamin if (checked[i] == false) { 6211795cf48SAdrian McMenamin fullscan = 0; 6221795cf48SAdrian McMenamin mdev = baseunits[i]; 6231795cf48SAdrian McMenamin maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO, 6241795cf48SAdrian McMenamin 0, NULL); 6251795cf48SAdrian McMenamin } 6261795cf48SAdrian McMenamin } 6271795cf48SAdrian McMenamin } 6281795cf48SAdrian McMenamin 62917be2d2bSAdrian McMenamin /* maple dma end bottom half - implemented via workqueue */ 63017be2d2bSAdrian McMenamin static void maple_dma_handler(struct work_struct *work) 63117be2d2bSAdrian McMenamin { 63217be2d2bSAdrian McMenamin struct mapleq *mq, *nmq; 633b233b28eSAdrian McMenamin struct maple_device *mdev; 63417be2d2bSAdrian McMenamin char *recvbuf; 63517be2d2bSAdrian McMenamin enum maple_code code; 63617be2d2bSAdrian McMenamin 63717be2d2bSAdrian McMenamin if (!maple_dma_done()) 63817be2d2bSAdrian McMenamin return; 639c0537844SPaul Mundt __raw_writel(0, MAPLE_ENABLE); 64017be2d2bSAdrian McMenamin if (!list_empty(&maple_sentq)) { 64117be2d2bSAdrian McMenamin list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { 642b233b28eSAdrian McMenamin mdev = mq->dev; 643b233b28eSAdrian McMenamin recvbuf = mq->recvbuf->buf; 64447fcae0dSChristoph Hellwig __flush_invalidate_region(sh_cacheop_vaddr(recvbuf), 64547fcae0dSChristoph Hellwig 0x400); 64617be2d2bSAdrian McMenamin code = recvbuf[0]; 6471795cf48SAdrian McMenamin kfree(mq->sendbuf); 6481795cf48SAdrian McMenamin list_del_init(&mq->list); 64917be2d2bSAdrian McMenamin switch (code) { 65017be2d2bSAdrian McMenamin case MAPLE_RESPONSE_NONE: 651b233b28eSAdrian McMenamin maple_response_none(mdev); 65217be2d2bSAdrian McMenamin break; 65317be2d2bSAdrian McMenamin 65417be2d2bSAdrian McMenamin case MAPLE_RESPONSE_DEVINFO: 655b233b28eSAdrian McMenamin maple_response_devinfo(mdev, recvbuf); 656b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 65717be2d2bSAdrian McMenamin break; 65817be2d2bSAdrian McMenamin 65917be2d2bSAdrian McMenamin case MAPLE_RESPONSE_DATATRF: 660b233b28eSAdrian McMenamin if (mdev->callback) 661b233b28eSAdrian McMenamin mdev->callback(mq); 662b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 663b233b28eSAdrian McMenamin wake_up(&mdev->maple_wait); 66417be2d2bSAdrian McMenamin break; 66517be2d2bSAdrian McMenamin 66617be2d2bSAdrian McMenamin case MAPLE_RESPONSE_FILEERR: 667b233b28eSAdrian McMenamin maple_response_fileerr(mdev, recvbuf); 668b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 669b233b28eSAdrian McMenamin wake_up(&mdev->maple_wait); 670b233b28eSAdrian McMenamin break; 671b233b28eSAdrian McMenamin 67217be2d2bSAdrian McMenamin case MAPLE_RESPONSE_AGAIN: 67317be2d2bSAdrian McMenamin case MAPLE_RESPONSE_BADCMD: 67417be2d2bSAdrian McMenamin case MAPLE_RESPONSE_BADFUNC: 675b233b28eSAdrian McMenamin dev_warn(&mdev->dev, "non-fatal error" 676b233b28eSAdrian McMenamin " 0x%X at (%d, %d)\n", code, 677b233b28eSAdrian McMenamin mdev->port, mdev->unit); 678b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 67917be2d2bSAdrian McMenamin break; 68017be2d2bSAdrian McMenamin 68117be2d2bSAdrian McMenamin case MAPLE_RESPONSE_ALLINFO: 682b233b28eSAdrian McMenamin dev_notice(&mdev->dev, "extended" 683b233b28eSAdrian McMenamin " device information request for (%d, %d)" 684b233b28eSAdrian McMenamin " but call is not supported\n", mdev->port, 685b233b28eSAdrian McMenamin mdev->unit); 686b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 68717be2d2bSAdrian McMenamin break; 68817be2d2bSAdrian McMenamin 68917be2d2bSAdrian McMenamin case MAPLE_RESPONSE_OK: 690b233b28eSAdrian McMenamin atomic_set(&mdev->busy, 0); 691b233b28eSAdrian McMenamin wake_up(&mdev->maple_wait); 69217be2d2bSAdrian McMenamin break; 69317be2d2bSAdrian McMenamin 69417be2d2bSAdrian McMenamin default: 69517be2d2bSAdrian McMenamin break; 69617be2d2bSAdrian McMenamin } 69717be2d2bSAdrian McMenamin } 6981795cf48SAdrian McMenamin /* if scanning is 1 then we have subdevices to check */ 69917be2d2bSAdrian McMenamin if (scanning == 1) { 70017be2d2bSAdrian McMenamin maple_send(); 70117be2d2bSAdrian McMenamin scanning = 2; 70217be2d2bSAdrian McMenamin } else 70317be2d2bSAdrian McMenamin scanning = 0; 7041795cf48SAdrian McMenamin /*check if we have actually tested all ports yet */ 7051795cf48SAdrian McMenamin if (!fullscan) 7061795cf48SAdrian McMenamin maple_port_rescan(); 7071795cf48SAdrian McMenamin /* mark that we have been through the first scan */ 70817be2d2bSAdrian McMenamin started = 1; 70917be2d2bSAdrian McMenamin } 710b233b28eSAdrian McMenamin maple_send(); 71117be2d2bSAdrian McMenamin } 71217be2d2bSAdrian McMenamin 713b233b28eSAdrian McMenamin static irqreturn_t maple_dma_interrupt(int irq, void *dev_id) 71417be2d2bSAdrian McMenamin { 71517be2d2bSAdrian McMenamin /* Load everything into the bottom half */ 71617be2d2bSAdrian McMenamin schedule_work(&maple_dma_process); 71717be2d2bSAdrian McMenamin return IRQ_HANDLED; 71817be2d2bSAdrian McMenamin } 71917be2d2bSAdrian McMenamin 720b233b28eSAdrian McMenamin static irqreturn_t maple_vblank_interrupt(int irq, void *dev_id) 72117be2d2bSAdrian McMenamin { 72217be2d2bSAdrian McMenamin schedule_work(&maple_vblank_process); 72317be2d2bSAdrian McMenamin return IRQ_HANDLED; 72417be2d2bSAdrian McMenamin } 72517be2d2bSAdrian McMenamin 72617be2d2bSAdrian McMenamin static int maple_set_dma_interrupt_handler(void) 72717be2d2bSAdrian McMenamin { 728b233b28eSAdrian McMenamin return request_irq(HW_EVENT_MAPLE_DMA, maple_dma_interrupt, 729b233b28eSAdrian McMenamin IRQF_SHARED, "maple bus DMA", &maple_unsupported_device); 73017be2d2bSAdrian McMenamin } 73117be2d2bSAdrian McMenamin 73217be2d2bSAdrian McMenamin static int maple_set_vblank_interrupt_handler(void) 73317be2d2bSAdrian McMenamin { 734b233b28eSAdrian McMenamin return request_irq(HW_EVENT_VSYNC, maple_vblank_interrupt, 735b233b28eSAdrian McMenamin IRQF_SHARED, "maple bus VBLANK", &maple_unsupported_device); 73617be2d2bSAdrian McMenamin } 73717be2d2bSAdrian McMenamin 73817be2d2bSAdrian McMenamin static int maple_get_dma_buffer(void) 73917be2d2bSAdrian McMenamin { 74017be2d2bSAdrian McMenamin maple_sendbuf = 74117be2d2bSAdrian McMenamin (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, 74217be2d2bSAdrian McMenamin MAPLE_DMA_PAGES); 74317be2d2bSAdrian McMenamin if (!maple_sendbuf) 74417be2d2bSAdrian McMenamin return -ENOMEM; 74517be2d2bSAdrian McMenamin return 0; 74617be2d2bSAdrian McMenamin } 74717be2d2bSAdrian McMenamin 748b233b28eSAdrian McMenamin static int maple_match_bus_driver(struct device *devptr, 74917be2d2bSAdrian McMenamin struct device_driver *drvptr) 75017be2d2bSAdrian McMenamin { 75163870295SPaul Mundt struct maple_driver *maple_drv = to_maple_driver(drvptr); 75263870295SPaul Mundt struct maple_device *maple_dev = to_maple_dev(devptr); 75317be2d2bSAdrian McMenamin 75417be2d2bSAdrian McMenamin /* Trap empty port case */ 75517be2d2bSAdrian McMenamin if (maple_dev->devinfo.function == 0xFFFFFFFF) 75617be2d2bSAdrian McMenamin return 0; 75717be2d2bSAdrian McMenamin else if (maple_dev->devinfo.function & 7581795cf48SAdrian McMenamin cpu_to_be32(maple_drv->function)) 75917be2d2bSAdrian McMenamin return 1; 76017be2d2bSAdrian McMenamin return 0; 76117be2d2bSAdrian McMenamin } 76217be2d2bSAdrian McMenamin 763b9482378SAdrian McMenamin static int maple_bus_uevent(struct device *dev, 764b9482378SAdrian McMenamin struct kobj_uevent_env *env) 76517be2d2bSAdrian McMenamin { 76617be2d2bSAdrian McMenamin return 0; 76717be2d2bSAdrian McMenamin } 76817be2d2bSAdrian McMenamin 76917be2d2bSAdrian McMenamin static void maple_bus_release(struct device *dev) 77017be2d2bSAdrian McMenamin { 77117be2d2bSAdrian McMenamin } 77217be2d2bSAdrian McMenamin 773b233b28eSAdrian McMenamin static struct maple_driver maple_unsupported_device = { 77417be2d2bSAdrian McMenamin .drv = { 775b233b28eSAdrian McMenamin .name = "maple_unsupported_device", 77617be2d2bSAdrian McMenamin .bus = &maple_bus_type, 77717be2d2bSAdrian McMenamin }, 77817be2d2bSAdrian McMenamin }; 779ee665eccSRandy Dunlap /* 780b233b28eSAdrian McMenamin * maple_bus_type - core maple bus structure 781b233b28eSAdrian McMenamin */ 78217be2d2bSAdrian McMenamin struct bus_type maple_bus_type = { 78317be2d2bSAdrian McMenamin .name = "maple", 784b233b28eSAdrian McMenamin .match = maple_match_bus_driver, 78517be2d2bSAdrian McMenamin .uevent = maple_bus_uevent, 78617be2d2bSAdrian McMenamin }; 78717be2d2bSAdrian McMenamin EXPORT_SYMBOL_GPL(maple_bus_type); 78817be2d2bSAdrian McMenamin 78917be2d2bSAdrian McMenamin static struct device maple_bus = { 79093fde774SKay Sievers .init_name = "maple", 79117be2d2bSAdrian McMenamin .release = maple_bus_release, 79217be2d2bSAdrian McMenamin }; 79317be2d2bSAdrian McMenamin 79417be2d2bSAdrian McMenamin static int __init maple_bus_init(void) 79517be2d2bSAdrian McMenamin { 79617be2d2bSAdrian McMenamin int retval, i; 79717be2d2bSAdrian McMenamin struct maple_device *mdev[MAPLE_PORTS]; 798b233b28eSAdrian McMenamin 799c0537844SPaul Mundt __raw_writel(0, MAPLE_ENABLE); 80017be2d2bSAdrian McMenamin 80117be2d2bSAdrian McMenamin retval = device_register(&maple_bus); 80217be2d2bSAdrian McMenamin if (retval) 80317be2d2bSAdrian McMenamin goto cleanup; 80417be2d2bSAdrian McMenamin 80517be2d2bSAdrian McMenamin retval = bus_register(&maple_bus_type); 80617be2d2bSAdrian McMenamin if (retval) 80717be2d2bSAdrian McMenamin goto cleanup_device; 80817be2d2bSAdrian McMenamin 809b233b28eSAdrian McMenamin retval = driver_register(&maple_unsupported_device.drv); 81017be2d2bSAdrian McMenamin if (retval) 81117be2d2bSAdrian McMenamin goto cleanup_bus; 81217be2d2bSAdrian McMenamin 81317be2d2bSAdrian McMenamin /* allocate memory for maple bus dma */ 81417be2d2bSAdrian McMenamin retval = maple_get_dma_buffer(); 81517be2d2bSAdrian McMenamin if (retval) { 816b233b28eSAdrian McMenamin dev_err(&maple_bus, "failed to allocate DMA buffers\n"); 81717be2d2bSAdrian McMenamin goto cleanup_basic; 81817be2d2bSAdrian McMenamin } 81917be2d2bSAdrian McMenamin 82017be2d2bSAdrian McMenamin /* set up DMA interrupt handler */ 82117be2d2bSAdrian McMenamin retval = maple_set_dma_interrupt_handler(); 82217be2d2bSAdrian McMenamin if (retval) { 823b233b28eSAdrian McMenamin dev_err(&maple_bus, "bus failed to grab maple " 824b233b28eSAdrian McMenamin "DMA IRQ\n"); 82517be2d2bSAdrian McMenamin goto cleanup_dma; 82617be2d2bSAdrian McMenamin } 82717be2d2bSAdrian McMenamin 82817be2d2bSAdrian McMenamin /* set up VBLANK interrupt handler */ 82917be2d2bSAdrian McMenamin retval = maple_set_vblank_interrupt_handler(); 83017be2d2bSAdrian McMenamin if (retval) { 831b233b28eSAdrian McMenamin dev_err(&maple_bus, "bus failed to grab VBLANK IRQ\n"); 83217be2d2bSAdrian McMenamin goto cleanup_irq; 83317be2d2bSAdrian McMenamin } 83417be2d2bSAdrian McMenamin 835b233b28eSAdrian McMenamin maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN); 83617be2d2bSAdrian McMenamin 837*bde82ee3SLu Wei if (!maple_queue_cache) { 838*bde82ee3SLu Wei retval = -ENOMEM; 83917be2d2bSAdrian McMenamin goto cleanup_bothirqs; 840*bde82ee3SLu Wei } 84117be2d2bSAdrian McMenamin 8421795cf48SAdrian McMenamin INIT_LIST_HEAD(&maple_waitq); 8431795cf48SAdrian McMenamin INIT_LIST_HEAD(&maple_sentq); 8441795cf48SAdrian McMenamin 84517be2d2bSAdrian McMenamin /* setup maple ports */ 84617be2d2bSAdrian McMenamin for (i = 0; i < MAPLE_PORTS; i++) { 847bd496669SAdrian McMenamin checked[i] = false; 848b233b28eSAdrian McMenamin empty[i] = false; 84917be2d2bSAdrian McMenamin mdev[i] = maple_alloc_dev(i, 0); 85017be2d2bSAdrian McMenamin if (!mdev[i]) { 85117be2d2bSAdrian McMenamin while (i-- > 0) 85217be2d2bSAdrian McMenamin maple_free_dev(mdev[i]); 853*bde82ee3SLu Wei retval = -ENOMEM; 85417be2d2bSAdrian McMenamin goto cleanup_cache; 85517be2d2bSAdrian McMenamin } 856b233b28eSAdrian McMenamin baseunits[i] = mdev[i]; 857b233b28eSAdrian McMenamin atomic_set(&mdev[i]->busy, 1); 8581795cf48SAdrian McMenamin maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL); 85917be2d2bSAdrian McMenamin subdevice_map[i] = 0; 86017be2d2bSAdrian McMenamin } 86117be2d2bSAdrian McMenamin 862b233b28eSAdrian McMenamin maple_pnp_time = jiffies + HZ; 863b233b28eSAdrian McMenamin /* prepare initial queue */ 86417be2d2bSAdrian McMenamin maple_send(); 865b233b28eSAdrian McMenamin dev_info(&maple_bus, "bus core now registered\n"); 86617be2d2bSAdrian McMenamin 86717be2d2bSAdrian McMenamin return 0; 86817be2d2bSAdrian McMenamin 86917be2d2bSAdrian McMenamin cleanup_cache: 87017be2d2bSAdrian McMenamin kmem_cache_destroy(maple_queue_cache); 87117be2d2bSAdrian McMenamin 87217be2d2bSAdrian McMenamin cleanup_bothirqs: 87317be2d2bSAdrian McMenamin free_irq(HW_EVENT_VSYNC, 0); 87417be2d2bSAdrian McMenamin 87517be2d2bSAdrian McMenamin cleanup_irq: 87617be2d2bSAdrian McMenamin free_irq(HW_EVENT_MAPLE_DMA, 0); 87717be2d2bSAdrian McMenamin 87817be2d2bSAdrian McMenamin cleanup_dma: 87917be2d2bSAdrian McMenamin free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); 88017be2d2bSAdrian McMenamin 88117be2d2bSAdrian McMenamin cleanup_basic: 882b233b28eSAdrian McMenamin driver_unregister(&maple_unsupported_device.drv); 88317be2d2bSAdrian McMenamin 88417be2d2bSAdrian McMenamin cleanup_bus: 88517be2d2bSAdrian McMenamin bus_unregister(&maple_bus_type); 88617be2d2bSAdrian McMenamin 88717be2d2bSAdrian McMenamin cleanup_device: 88817be2d2bSAdrian McMenamin device_unregister(&maple_bus); 88917be2d2bSAdrian McMenamin 89017be2d2bSAdrian McMenamin cleanup: 891b233b28eSAdrian McMenamin printk(KERN_ERR "Maple bus registration failed\n"); 89217be2d2bSAdrian McMenamin return retval; 89317be2d2bSAdrian McMenamin } 894b3c69e24SAdrian McMenamin /* Push init to later to ensure hardware gets detected */ 895b3c69e24SAdrian McMenamin fs_initcall(maple_bus_init); 896