diff options
Diffstat (limited to 'drivers')
321 files changed, 5424 insertions, 2942 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index f94d4c818fc..0230cb6cbb3 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1345,12 +1345,15 @@ static int acpi_video_bus_get_devices(struct acpi_video_bus *video, struct acpi_device *device) { - int status; + int status = 0; struct acpi_device *dev; - status = acpi_video_device_enumerate(video); - if (status) - return status; + /* + * There are systems where video module known to work fine regardless + * of broken _DOD and ignoring returned value here doesn't cause + * any issues later. + */ + acpi_video_device_enumerate(video); list_for_each_entry(dev, &device->children, node) { diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index 0b6f0b28a48..bd5de08ad6f 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/tegra-ahb.h> #define DRV_NAME "tegra-ahb" diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 8727e9c5eea..72c776f2a1f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -83,9 +83,16 @@ EXPORT_SYMBOL_GPL(platform_get_resource); */ int platform_get_irq(struct platform_device *dev, unsigned int num) { +#ifdef CONFIG_SPARC + /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ + if (!dev || num >= dev->archdata.num_irqs) + return -ENXIO; + return dev->archdata.irqs[num]; +#else struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); return r ? r->start : -ENXIO; +#endif } EXPORT_SYMBOL_GPL(platform_get_irq); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index f529407db93..824e09c4d0d 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -131,6 +131,7 @@ config BLK_CPQ_DA config BLK_CPQ_CISS_DA tristate "Compaq Smart Array 5xxx support" depends on PCI + select CHECK_SIGNATURE help This is the driver for Compaq Smart Array 5xxx controllers. Everyone using these boards should say Y here. @@ -166,8 +167,8 @@ config BLK_DEV_DAC960 module will be called DAC960. config BLK_DEV_UMEM - tristate "Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + tristate "Micro Memory MM5415 Battery Backed RAM support" + depends on PCI ---help--- Saying Y here will include support for the MM5415 family of battery backed (Non-volatile) RAM cards. @@ -430,8 +431,8 @@ config CDROM_PKTCDVD_BUFFERS a disc is opened for writing. config CDROM_PKTCDVD_WCACHE - bool "Enable write caching (EXPERIMENTAL)" - depends on CDROM_PKTCDVD && EXPERIMENTAL + bool "Enable write caching" + depends on CDROM_PKTCDVD help If enabled, write caching will be set for the CD-R/W device. For now this option is dangerous unless the CD-RW media is known good, as we @@ -508,8 +509,8 @@ config XEN_BLKDEV_BACKEND config VIRTIO_BLK - tristate "Virtio block driver (EXPERIMENTAL)" - depends on EXPERIMENTAL && VIRTIO + tristate "Virtio block driver" + depends on VIRTIO ---help--- This is the virtual block driver for virtio. It can be used with lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. @@ -528,7 +529,7 @@ config BLK_DEV_HD config BLK_DEV_RBD tristate "Rados block device (RBD)" - depends on INET && EXPERIMENTAL && BLOCK + depends on INET && BLOCK select CEPH_LIB select LIBCRC32C select CRYPTO_AES diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index b0f553b26d0..ca83f96756a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -5205,7 +5205,6 @@ static void cciss_shutdown(struct pci_dev *pdev) return; } /* write all data in the battery backed cache to disk */ - memset(flush_buf, 0, 4); return_code = sendcmd_withirq(h, CCISS_CACHE_FLUSH, flush_buf, 4, 0, CTLR_LUNID, TYPE_CMD); kfree(flush_buf); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 17c675c5229..1c49d717396 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4109,12 +4109,19 @@ static struct platform_driver floppy_driver = { static struct platform_device floppy_device[N_DRIVE]; +static bool floppy_available(int drive) +{ + if (!(allowed_drive_mask & (1 << drive))) + return false; + if (fdc_state[FDC(drive)].version == FDC_NONE) + return false; + return true; +} + static struct kobject *floppy_find(dev_t dev, int *part, void *data) { int drive = (*part & 3) | ((*part & 0x80) >> 5); - if (drive >= N_DRIVE || - !(allowed_drive_mask & (1 << drive)) || - fdc_state[FDC(drive)].version == FDC_NONE) + if (drive >= N_DRIVE || !floppy_available(drive)) return NULL; if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type)) return NULL; @@ -4124,8 +4131,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) static int __init do_floppy_init(void) { - int i, unit, drive; - int err, dr; + int i, unit, drive, err; set_debugt(); interruptjiffies = resultjiffies = jiffies; @@ -4137,34 +4143,32 @@ static int __init do_floppy_init(void) raw_cmd = NULL; - for (dr = 0; dr < N_DRIVE; dr++) { - disks[dr] = alloc_disk(1); - if (!disks[dr]) { - err = -ENOMEM; - goto out_put_disk; - } + floppy_wq = alloc_ordered_workqueue("floppy", 0); + if (!floppy_wq) + return -ENOMEM; - floppy_wq = alloc_ordered_workqueue("floppy", 0); - if (!floppy_wq) { + for (drive = 0; drive < N_DRIVE; drive++) { + disks[drive] = alloc_disk(1); + if (!disks[drive]) { err = -ENOMEM; goto out_put_disk; } - disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock); - if (!disks[dr]->queue) { + disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock); + if (!disks[drive]->queue) { err = -ENOMEM; - goto out_destroy_workq; + goto out_put_disk; } - blk_queue_max_hw_sectors(disks[dr]->queue, 64); - disks[dr]->major = FLOPPY_MAJOR; - disks[dr]->first_minor = TOMINOR(dr); - disks[dr]->fops = &floppy_fops; - sprintf(disks[dr]->disk_name, "fd%d", dr); + blk_queue_max_hw_sectors(disks[drive]->queue, 64); + disks[drive]->major = FLOPPY_MAJOR; + disks[drive]->first_minor = TOMINOR(drive); + disks[drive]->fops = &floppy_fops; + sprintf(disks[drive]->disk_name, "fd%d", drive); - init_timer(&motor_off_timer[dr]); - motor_off_timer[dr].data = dr; - motor_off_timer[dr].function = motor_off_callback; + init_timer(&motor_off_timer[drive]); + motor_off_timer[drive].data = drive; + motor_off_timer[drive].function = motor_off_callback; } err = register_blkdev(FLOPPY_MAJOR, "fd"); @@ -4282,9 +4286,7 @@ static int __init do_floppy_init(void) } for (drive = 0; drive < N_DRIVE; drive++) { - if (!(allowed_drive_mask & (1 << drive))) - continue; - if (fdc_state[FDC(drive)].version == FDC_NONE) + if (!floppy_available(drive)) continue; floppy_device[drive].name = floppy_device_name; @@ -4293,7 +4295,7 @@ static int __init do_floppy_init(void) err = platform_device_register(&floppy_device[drive]); if (err) - goto out_release_dma; + goto out_remove_drives; err = device_create_file(&floppy_device[drive].dev, &dev_attr_cmos); @@ -4311,29 +4313,34 @@ static int __init do_floppy_init(void) out_unreg_platform_dev: platform_device_unregister(&floppy_device[drive]); +out_remove_drives: + while (drive--) { + if (floppy_available(drive)) { + del_gendisk(disks[drive]); + device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos); + platform_device_unregister(&floppy_device[drive]); + } + } out_release_dma: if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); out_unreg_region: blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); platform_driver_unregister(&floppy_driver); -out_destroy_workq: - destroy_workqueue(floppy_wq); out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: - while (dr--) { - del_timer_sync(&motor_off_timer[dr]); - if (disks[dr]->queue) { - blk_cleanup_queue(disks[dr]->queue); - /* - * put_disk() is not paired with add_disk() and - * will put queue reference one extra time. fix it. - */ - disks[dr]->queue = NULL; + for (drive = 0; drive < N_DRIVE; drive++) { + if (!disks[drive]) + break; + if (disks[drive]->queue) { + del_timer_sync(&motor_off_timer[drive]); + blk_cleanup_queue(disks[drive]->queue); + disks[drive]->queue = NULL; } - put_disk(disks[dr]); + put_disk(disks[drive]); } + destroy_workqueue(floppy_wq); return err; } @@ -4551,8 +4558,7 @@ static void __exit floppy_module_exit(void) for (drive = 0; drive < N_DRIVE; drive++) { del_timer_sync(&motor_off_timer[drive]); - if ((allowed_drive_mask & (1 << drive)) && - fdc_state[FDC(drive)].version != FDC_NONE) { + if (floppy_available(drive)) { del_gendisk(disks[drive]); device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos); platform_device_unregister(&floppy_device[drive]); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index e9d594fd12c..54046e51160 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -976,8 +976,21 @@ static int loop_clr_fd(struct loop_device *lo) if (lo->lo_state != Lo_bound) return -ENXIO; - if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ - return -EBUSY; + /* + * If we've explicitly asked to tear down the loop device, + * and it has an elevated reference count, set it for auto-teardown when + * the last reference goes away. This stops $!~#$@ udev from + * preventing teardown because it decided that it needs to run blkid on + * the loopback device whenever they appear. xfstests is notorious for + * failing tests because blkid via udev races with a losetup + * <dev>/do something like mkfs/losetup -d <dev> causing the losetup -d + * command to fail with EBUSY. + */ + if (lo->lo_refcnt > 1) { + lo->lo_flags |= LO_FLAGS_AUTOCLEAR; + mutex_unlock(&lo->lo_ctl_mutex); + return 0; + } if (filp == NULL) return -EINVAL; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index f946d31d691..adc6f36564c 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -2035,8 +2035,9 @@ static unsigned int implicit_sector(unsigned char command, } return rv; } - -static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout) +static void mtip_set_timeout(struct driver_data *dd, + struct host_to_dev_fis *fis, + unsigned int *timeout, u8 erasemode) { switch (fis->command) { case ATA_CMD_DOWNLOAD_MICRO: @@ -2044,7 +2045,10 @@ static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout) break; case ATA_CMD_SEC_ERASE_UNIT: case 0xFC: - *timeout = 240000; /* 4 minutes */ + if (erasemode) + *timeout = ((*(dd->port->identify + 90) * 2) * 60000); + else + *timeout = ((*(dd->port->identify + 89) * 2) * 60000); break; case ATA_CMD_STANDBYNOW1: *timeout = 120000; /* 2 minutes */ @@ -2087,6 +2091,7 @@ static int exec_drive_taskfile(struct driver_data *dd, unsigned int transfer_size; unsigned long task_file_data; int intotal = outtotal + req_task->out_size; + int erasemode = 0; taskout = req_task->out_size; taskin = req_task->in_size; @@ -2212,7 +2217,13 @@ static int exec_drive_taskfile(struct driver_data *dd, fis.lba_hi, fis.device); - mtip_set_timeout(&fis, &timeout); + /* check for erase mode support during secure erase.*/ + if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) + && (outbuf[0] & MTIP_SEC_ERASE_MODE)) { + erasemode = 1; + } + + mtip_set_timeout(dd, &fis, &timeout, erasemode); /* Determine the correct transfer size.*/ if (force_single_sector) diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 18627a1d04c..5f4a917bd8b 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -33,6 +33,9 @@ /* offset of Device Control register in PCIe extended capabilites space */ #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 +/* check for erase mode support during secure erase */ +#define MTIP_SEC_ERASE_MODE 0x3 + /* # of times to retry timed out/failed IOs */ #define MTIP_MAX_RETRIES 2 diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 9ad3b5ec1dc..9a54623e52d 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -158,8 +158,8 @@ struct xen_vbd { struct block_device *bdev; /* Cached size parameter. */ sector_t size; - bool flush_support; - bool discard_secure; + unsigned int flush_support:1; + unsigned int discard_secure:1; }; struct backend_info; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 4f66171c668..f58434c2617 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -105,11 +105,10 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) { struct xen_blkif *blkif; - blkif = kmem_cache_alloc(xen_blkif_cachep, GFP_KERNEL); + blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL); if (!blkif) return ERR_PTR(-ENOMEM); - memset(blkif, 0, sizeof(*blkif)); blkif->domid = domid; spin_lock_init(&blkif->blk_ring_lock); atomic_set(&blkif->refcnt, 1); @@ -196,7 +195,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif) } } -void xen_blkif_free(struct xen_blkif *blkif) +static void xen_blkif_free(struct xen_blkif *blkif) { if (!atomic_dec_and_test(&blkif->refcnt)) BUG(); @@ -257,7 +256,7 @@ static struct attribute_group xen_vbdstat_group = { VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor); VBD_SHOW(mode, "%s\n", be->mode); -int xenvbd_sysfs_addif(struct xenbus_device *dev) +static int xenvbd_sysfs_addif(struct xenbus_device *dev) { int error; @@ -281,7 +280,7 @@ fail1: device_remove_file(&dev->dev, &dev_attr_physical_device); return error; } -void xenvbd_sysfs_delif(struct xenbus_device *dev) +static void xenvbd_sysfs_delif(struct xenbus_device *dev) { sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group); device_remove_file(&dev->dev, &dev_attr_mode); diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index fc2de5528dc..b00000e8aef 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -67,6 +67,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3304) }, { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0489, 0xE03D) }, + { USB_DEVICE(0x0489, 0xE027) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index debda27df9b..ee82f2fb65f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -124,6 +124,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index c8abce3d2d9..ed0fade46ae 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -270,15 +270,10 @@ static int hci_uart_send_frame(struct sk_buff *skb) */ static int hci_uart_tty_open(struct tty_struct *tty) { - struct hci_uart *hu = (void *) tty->disc_data; + struct hci_uart *hu; BT_DBG("tty %p", tty); - /* FIXME: This btw is bogus, nothing requires the old ldisc to clear - the pointer */ - if (hu) - return -EEXIST; - /* Error if the tty has no write op instead of leaving an exploitable hole */ if (tty->ops->write == NULL) diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c index ff63560b846..0c48b0e05ed 100644 --- a/drivers/bus/omap-ocp2scp.c +++ b/drivers/bus/omap-ocp2scp.c @@ -22,6 +22,26 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/platform_data/omap_ocp2scp.h> + +/** + * _count_resources - count for the number of resources + * @res: struct resource * + * + * Count and return the number of resources populated for the device that is + * connected to ocp2scp. + */ +static unsigned _count_resources(struct resource *res) +{ + int cnt = 0; + + while (res->start != res->end) { + cnt++; + res++; + } + + return cnt; +} static int ocp2scp_remove_devices(struct device *dev, void *c) { @@ -34,20 +54,62 @@ static int ocp2scp_remove_devices(struct device *dev, void *c) static int __devinit omap_ocp2scp_probe(struct platform_device *pdev) { - int ret; - struct device_node *np = pdev->dev.of_node; + int ret; + unsigned res_cnt, i; + struct device_node *np = pdev->dev.of_node; + struct platform_device *pdev_child; + struct omap_ocp2scp_platform_data *pdata = pdev->dev.platform_data; + struct omap_ocp2scp_dev *dev; if (np) { ret = of_platform_populate(np, NULL, NULL, &pdev->dev); if (ret) { - dev_err(&pdev->dev, "failed to add resources for ocp2scp child\n"); + dev_err(&pdev->dev, + "failed to add resources for ocp2scp child\n"); goto err0; } + } else if (pdata) { + for (i = 0, dev = *pdata->devices; i < pdata->dev_cnt; i++, + dev++) { + res_cnt = _count_resources(dev->res); + + pdev_child = platform_device_alloc(dev->drv_name, + PLATFORM_DEVID_AUTO); + if (!pdev_child) { + dev_err(&pdev->dev, + "failed to allocate mem for ocp2scp child\n"); + goto err0; + } + + ret = platform_device_add_resources(pdev_child, + dev->res, res_cnt); + if (ret) { + dev_err(&pdev->dev, + "failed to add resources for ocp2scp child\n"); + goto err1; + } + + pdev_child->dev.parent = &pdev->dev; + + ret = platform_device_add(pdev_child); + if (ret) { + dev_err(&pdev->dev, + "failed to register ocp2scp child device\n"); + goto err1; + } + } + } else { + dev_err(&pdev->dev, "OCP2SCP initialized without plat data\n"); + return -EINVAL; } + pm_runtime_enable(&pdev->dev); return 0; +err1: + platform_device_put(pdev_child); + err0: device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index a5effd813ab..45e467dcc8c 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -27,8 +27,6 @@ #include <asm/io.h> -#include <plat/cpu.h> - #define RNG_OUT_REG 0x00 /* Output register */ #define RNG_STAT_REG 0x04 /* Status register [0] = STAT_BUSY */ diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71a25b91de0..d35a34c5836 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -19,6 +19,7 @@ endif obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o +obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c new file mode 100644 index 00000000000..37a30514fd6 --- /dev/null +++ b/drivers/clk/clk-zynq.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2012 National Instruments + * + * Josh Cartwright <josh.cartwright@ni.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <linux/io.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/clk-provider.h> + +static void __iomem *slcr_base; + +struct zynq_pll_clk { + struct clk_hw hw; + void __iomem *pll_ctrl; + void __iomem *pll_cfg; +}; + +#define to_zynq_pll_clk(hw) container_of(hw, struct zynq_pll_clk, hw) + +#define CTRL_PLL_FDIV(x) ((x) >> 12) + +static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct zynq_pll_clk *pll = to_zynq_pll_clk(hw); + return parent_rate * CTRL_PLL_FDIV(ioread32(pll->pll_ctrl)); +} + +static const struct clk_ops zynq_pll_clk_ops = { + .recalc_rate = zynq_pll_recalc_rate, +}; + +static void __init zynq_pll_clk_setup(struct device_node *np) +{ + struct clk_init_data init; + struct zynq_pll_clk *pll; + const char *parent_name; + struct clk *clk; + u32 regs[2]; + int ret; + + ret = of_property_read_u32_array(np, "reg", regs, ARRAY_SIZE(regs)); + if (WARN_ON(ret)) + return; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (WARN_ON(!pll)) + return; + + pll->pll_ctrl = slcr_base + regs[0]; + pll->pll_cfg = slcr_base + regs[1]; + + of_property_read_string(np, "clock-output-names", &init.name); + + init.ops = &zynq_pll_clk_ops; + parent_name = of_clk_get_parent_name(np, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (WARN_ON(IS_ERR(clk))) + return; + + ret = of_clk_add_provider(np, of_clk_src_simple_get, clk); + if (WARN_ON(ret)) + return; +} + +struct zynq_periph_clk { + struct clk_hw hw; + struct clk_onecell_data onecell_data; + struct clk *gates[2]; + void __iomem *clk_ctrl; + spinlock_t clkact_lock; +}; + +#define to_zynq_periph_clk(hw) container_of(hw, struct zynq_periph_clk, hw) + +static const u8 periph_clk_parent_map[] = { + 0, 0, 1, 2 +}; +#define PERIPH_CLK_CTRL_SRC(x) (periph_clk_parent_map[((x) & 0x30) >> 4]) +#define PERIPH_CLK_CTRL_DIV(x) (((x) & 0x3F00) >> 8) + +static unsigned long zynq_periph_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct zynq_periph_clk *periph = to_zynq_periph_clk(hw); + return parent_rate / PERIPH_CLK_CTRL_DIV(ioread32(periph->clk_ctrl)); +} + +static u8 zynq_periph_get_parent(struct clk_hw *hw) +{ + struct zynq_periph_clk *periph = to_zynq_periph_clk(hw); + return PERIPH_CLK_CTRL_SRC(ioread32(periph->clk_ctrl)); +} + +static const struct clk_ops zynq_periph_clk_ops = { + .recalc_rate = zynq_periph_recalc_rate, + .get_parent = zynq_periph_get_parent, +}; + +static void __init zynq_periph_clk_setup(struct device_node *np) +{ + struct zynq_periph_clk *periph; + const char *parent_names[3]; + struct clk_init_data init; + int clk_num = 0, err; + const char *name; + struct clk *clk; + u32 reg; + int i; + + err = of_property_read_u32(np, "reg", ®); + if (WARN_ON(err)) + return; + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); + if (WARN_ON(!periph)) + return; + + periph->clk_ctrl = slcr_base + reg; + spin_lock_init(&periph->clkact_lock); + + init.name = np->name; + init.ops = &zynq_periph_clk_ops; + for (i = 0; i < ARRAY_SIZE(parent_names); i++) + parent_names[i] = of_clk_get_parent_name(np, i); + init.parent_names = parent_names; + init.num_parents = ARRAY_SIZE(parent_names); + + periph->hw.init = &init; + + clk = clk_register(NULL, &periph->hw); + if (WARN_ON(IS_ERR(clk))) + return; + + err = of_clk_add_provider(np, of_clk_src_simple_get, clk); + if (WARN_ON(err)) + return; + + err = of_property_read_string_index(np, "clock-output-names", 0, + &name); + if (WARN_ON(err)) + return; + + periph->gates[0] = clk_register_gate(NULL, name, np->name, 0, + periph->clk_ctrl, 0, 0, + &periph->clkact_lock); + if (WARN_ON(IS_ERR(periph->gates[0]))) + return; + clk_num++; + + /* some periph clks have 2 downstream gates */ + err = of_property_read_string_index(np, "clock-output-names", 1, + &name); + if (err != -ENODATA) { + periph->gates[1] = clk_register_gate(NULL, name, np->name, 0, + periph->clk_ctrl, 1, 0, + &periph->clkact_lock); + if (WARN_ON(IS_ERR(periph->gates[1]))) + return; + clk_num++; + } + + periph->onecell_data.clks = periph->gates; + periph->onecell_data.clk_num = clk_num; + + err = of_clk_add_provider(np, of_clk_src_onecell_get, + &periph->onecell_data); + if (WARN_ON(err)) + return; +} + +/* CPU Clock domain is modelled as a mux with 4 children subclks, whose + * derivative rates depend on CLK_621_TRUE + */ + +struct zynq_cpu_clk { + struct clk_hw hw; + struct clk_onecell_data onecell_data; + struct clk *subclks[4]; + void __iomem *clk_ctrl; + spinlock_t clkact_lock; +}; + +#define to_zynq_cpu_clk(hw) container_of(hw, struct zynq_cpu_clk, hw) + +static const u8 zynq_cpu_clk_parent_map[] = { + 1, 1, 2, 0 +}; +#define CPU_CLK_SRCSEL(x) (zynq_cpu_clk_parent_map[(((x) & 0x30) >> 4)]) +#define CPU_CLK_CTRL_DIV(x) (((x) & 0x3F00) >> 8) + +static u8 zynq_cpu_clk_get_parent(struct clk_hw *hw) +{ + struct zynq_cpu_clk *cpuclk = to_zynq_cpu_clk(hw); + return CPU_CLK_SRCSEL(ioread32(cpuclk->clk_ctrl)); +} + +static unsigned long zynq_cpu_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct zynq_cpu_clk *cpuclk = to_zynq_cpu_clk(hw); + return parent_rate / CPU_CLK_CTRL_DIV(ioread32(cpuclk->clk_ctrl)); +} + +static const struct clk_ops zynq_cpu_clk_ops = { + .get_parent = zynq_cpu_clk_get_parent, + .recalc_rate = zynq_cpu_clk_recalc_rate, +}; + +struct zynq_cpu_subclk { + struct clk_hw hw; + void __iomem *clk_621; + enum { + CPU_SUBCLK_6X4X, + CPU_SUBCLK_3X2X, + CPU_SUBCLK_2X, + CPU_SUBCLK_1X, + } which; +}; + +#define CLK_621_TRUE(x) ((x) & 1) + +#define to_zynq_cpu_subclk(hw) container_of(hw, struct zynq_cpu_subclk, hw); + +static unsigned long zynq_cpu_subclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned long uninitialized_var(rate); + struct zynq_cpu_subclk *subclk; + bool is_621; + + subclk = to_zynq_cpu_subclk(hw) + is_621 = CLK_621_TRUE(ioread32(subclk->clk_621)); + + switch (subclk->which) { + case CPU_SUBCLK_6X4X: + rate = parent_rate; + break; + case CPU_SUBCLK_3X2X: + rate = parent_rate / 2; + break; + case CPU_SUBCLK_2X: + rate = parent_rate / (is_621 ? 3 : 2); + break; + case CPU_SUBCLK_1X: + rate = parent_rate / (is_621 ? 6 : 4); + break; + }; + + return rate; +} + +static const struct clk_ops zynq_cpu_subclk_ops = { + .recalc_rate = zynq_cpu_subclk_recalc_rate, +}; + +static struct clk *zynq_cpu_subclk_setup(struct device_node *np, u8 which, + void __iomem *clk_621) +{ + struct zynq_cpu_subclk *subclk; + struct clk_init_data init; + struct clk *clk; + int err; + + err = of_property_read_string_index(np, "clock-output-names", + which, &init.name); + if (WARN_ON(err)) + goto err_read_output_name; + + subclk = kzalloc(sizeof(*subclk), GFP_KERNEL); + if (!subclk) + goto err_subclk_alloc; + + subclk->clk_621 = clk_621; + subclk->which = which; + + init.ops = &zynq_cpu_subclk_ops; + init.parent_names = &np->name; + init.num_parents = 1; + + subclk->hw.init = &init; + + clk = clk_register(NULL, &subclk->hw); + if (WARN_ON(IS_ERR(clk))) + goto err_clk_register; + + return clk; + +err_clk_register: + kfree(subclk); +err_subclk_alloc: +err_read_output_name: + return ERR_PTR(-EINVAL); +} + +static void __init zynq_cpu_clk_setup(struct device_node *np) +{ + struct zynq_cpu_clk *cpuclk; + const char *parent_names[3]; + struct clk_init_data init; + void __iomem *clk_621; + struct clk *clk; + u32 reg[2]; + int err; + int i; + + err = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg)); + if (WARN_ON(err)) + return; + + cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL); + if (WARN_ON(!cpuclk)) + return; + + cpuclk->clk_ctrl = slcr_base + reg[0]; + clk_621 = slcr_base + reg[1]; + spin_lock_init(&cpuclk->clkact_lock); + + init.name = np->name; + init.ops = &zynq_cpu_clk_ops; + for (i = 0; i < ARRAY_SIZE(parent_names); i++) + parent_names[i] = of_clk_get_parent_name(np, i); + init.parent_names = parent_names; + init.num_parents = ARRAY_SIZE(parent_names); + + cpuclk->hw.init = &init; + + clk = clk_register(NULL, &cpuclk->hw); + if (WARN_ON(IS_ERR(clk))) + return; + + err = of_clk_add_provider(np, of_clk_src_simple_get, clk); + if (WARN_ON(err)) + return; + + for (i = 0; i < 4; i++) { + cpuclk->subclks[i] = zynq_cpu_subclk_setup(np, i, clk_621); + if (WARN_ON(IS_ERR(cpuclk->subclks[i]))) + return; + } + + cpuclk->onecell_data.clks = cpuclk->subclks; + cpuclk->onecell_data.clk_num = i; + + err = of_clk_add_provider(np, of_clk_src_onecell_get, + &cpuclk->onecell_data); + if (WARN_ON(err)) + return; +} + +static const __initconst struct of_device_id zynq_clk_match[] = { + { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, + { .compatible = "xlnx,zynq-pll", .data = zynq_pll_clk_setup, }, + { .compatible = "xlnx,zynq-periph-clock", + .data = zynq_periph_clk_setup, }, + { .compatible = "xlnx,zynq-cpu-clock", .data = zynq_cpu_clk_setup, }, + {} +}; + +void __init xilinx_zynq_clocks_init(void __iomem *slcr) +{ + slcr_base = slcr; + of_clk_init(zynq_clk_match); +} diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index ca4a25ed844..e2c17d187d9 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c @@ -40,7 +40,7 @@ void u8500_clk_init(void) CLK_IS_ROOT|CLK_IGNORE_UNUSED, 32768); clk_register_clkdev(clk, "clk32k", NULL); - clk_register_clkdev(clk, NULL, "rtc-pl031"); + clk_register_clkdev(clk, "apb_pclk", "rtc-pl031"); /* PRCMU clocks */ fw_version = prcmu_get_fw_version(); @@ -228,10 +228,17 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE, BIT(2), 0); + clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1"); + clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE, BIT(3), 0); + clk_register_clkdev(clk, "apb_pclk", "msp0"); + clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.0"); + clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE, BIT(4), 0); + clk_register_clkdev(clk, "apb_pclk", "msp1"); + clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.1"); clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE, BIT(5), 0); @@ -239,6 +246,7 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE, BIT(6), 0); + clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2"); clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE, BIT(7), 0); @@ -246,6 +254,7 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE, BIT(8), 0); + clk_register_clkdev(clk, "apb_pclk", "slimbus0"); clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE, BIT(9), 0); @@ -255,11 +264,16 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE, BIT(10), 0); + clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4"); + clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE, BIT(11), 0); + clk_register_clkdev(clk, "apb_pclk", "msp3"); + clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.3"); clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE, BIT(0), 0); + clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3"); clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE, BIT(1), 0); @@ -279,12 +293,13 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE, BIT(5), 0); + clk_register_clkdev(clk, "apb_pclk", "msp2"); + clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.2"); clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE, BIT(6), 0); clk_register_clkdev(clk, "apb_pclk", "sdi1"); - clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE, BIT(7), 0); clk_register_clkdev(clk, "apb_pclk", "sdi3"); @@ -316,10 +331,15 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE, BIT(1), 0); + clk_register_clkdev(clk, "apb_pclk", "ssp0"); + clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE, BIT(2), 0); + clk_register_clkdev(clk, "apb_pclk", "ssp1"); + clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE, BIT(3), 0); + clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0"); clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE, BIT(4), 0); @@ -401,10 +421,17 @@ void u8500_clk_init(void) clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk", U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "nmk-i2c.1"); + clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk", U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "msp0"); + clk_register_clkdev(clk, NULL, "ux500-msp-i2s.0"); + clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk", U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "msp1"); + clk_register_clkdev(clk, NULL, "ux500-msp-i2s.1"); clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk", U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE); @@ -412,17 +439,25 @@ void u8500_clk_init(void) clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk", U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "nmk-i2c.2"); + clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk", - U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE); - /* FIXME: Redefinition of BIT(3). */ + U8500_CLKRST1_BASE, BIT(8), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "slimbus0"); + clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk", U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "nmk-i2c.4"); + clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk", U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "msp3"); + clk_register_clkdev(clk, NULL, "ux500-msp-i2s.3"); /* Periph2 */ clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk", U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "nmk-i2c.3"); clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk", U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE); @@ -430,6 +465,8 @@ void u8500_clk_init(void) clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk", U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "msp2"); + clk_register_clkdev(clk, NULL, "ux500-msp-i2s.2"); clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk", U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE); @@ -450,10 +487,15 @@ void u8500_clk_init(void) /* Periph3 */ clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk", U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "ssp0"); + clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk", U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "ssp1"); + clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk", U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "nmk-i2c.0"); clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk", U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE); diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index c16a3a593ba..e3ebb4fa2c3 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -5,7 +5,7 @@ * http://www.gnu.org/licenses/gpl.html * * Maintainer: - * Andreas Herrmann <andreas.herrmann3@amd.com> + * Andreas Herrmann <herrmann.der.user@googlemail.com> * * Based on the powernow-k7.c module written by Dave Jones. * (C) 2003 Dave Jones on behalf of SuSE Labs diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 093a8af59cb..649a146e138 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -29,8 +29,7 @@ #include <crypto/scatterwalk.h> #include <crypto/aes.h> -#include <plat/cpu.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> /* OMAP TRM gives bitfields as start:end, where start is the higher bit number. For example 7:0 */ @@ -941,11 +940,6 @@ static int __init omap_aes_mod_init(void) { pr_info("loading %s driver\n", "omap-aes"); - if (!cpu_class_is_omap2() || omap_type() != OMAP2_DEVICE_TYPE_SEC) { - pr_err("Unsupported cpu\n"); - return -ENODEV; - } - return platform_driver_register(&omap_aes_driver); } diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index a3fd6fc504b..d76fe06b941 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -37,8 +37,7 @@ #include <crypto/hash.h> #include <crypto/internal/hash.h> -#include <plat/cpu.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include <mach/irqs.h> #define SHA_REG_DIGEST(x) (0x00 + ((x) * 0x04)) @@ -1289,13 +1288,6 @@ static int __init omap_sham_mod_init(void) { pr_info("loading %s driver\n", "omap-sham"); - if (!cpu_class_is_omap2() || - (omap_type() != OMAP2_DEVICE_TYPE_SEC && - omap_type() != OMAP2_DEVICE_TYPE_EMU)) { - pr_err("Unsupported cpu\n"); - return -ENODEV; - } - return platform_driver_register(&omap_sham_driver); } diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c index 37185e6630c..e69f3bc473b 100644 --- a/drivers/crypto/tegra-aes.c +++ b/drivers/crypto/tegra-aes.c @@ -41,8 +41,6 @@ #include <linux/completion.h> #include <linux/workqueue.h> -#include <mach/clk.h> - #include <crypto/scatterwalk.h> #include <crypto/aes.h> #include <crypto/internal/rng.h> diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 7d9554cc497..dbf0e6f8de8 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -29,7 +29,6 @@ #include <asm/irq.h> #include <linux/platform_data/dma-imx.h> -#include <mach/hardware.h> #include "dmaengine.h" #define IMXDMA_MAX_CHAN_DESCRIPTORS 16 @@ -167,6 +166,12 @@ struct imxdma_channel { int slot_2d; }; +enum imx_dma_type { + IMX1_DMA, + IMX21_DMA, + IMX27_DMA, +}; + struct imxdma_engine { struct device *dev; struct device_dma_parameters dma_parms; @@ -177,7 +182,39 @@ struct imxdma_engine { spinlock_t lock; struct imx_dma_2d_config slots_2d[IMX_DMA_2D_SLOTS]; struct imxdma_channel channel[IMX_DMA_CHANNELS]; + enum imx_dma_type devtype; +}; + +static struct platform_device_id imx_dma_devtype[] = { + { + .name = "imx1-dma", + .driver_data = IMX1_DMA, + }, { + .name = "imx21-dma", + .driver_data = IMX21_DMA, + }, { + .name = "imx27-dma", + .driver_data = IMX27_DMA, + }, { + /* sentinel */ + } }; +MODULE_DEVICE_TABLE(platform, imx_dma_devtype); + +static inline int is_imx1_dma(struct imxdma_engine *imxdma) +{ + return imxdma->devtype == IMX1_DMA; +} + +static inline int is_imx21_dma(struct imxdma_engine *imxdma) +{ + return imxdma->devtype == IMX21_DMA; +} + +static inline int is_imx27_dma(struct imxdma_engine *imxdma) +{ + return imxdma->devtype == IMX27_DMA; +} static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan) { @@ -212,7 +249,9 @@ static unsigned imx_dmav1_readl(struct imxdma_engine *imxdma, unsigned offset) static int imxdma_hw_chain(struct imxdma_channel *imxdmac) { - if (cpu_is_mx27()) + struct imxdma_engine *imxdma = imxdmac->imxdma; + + if (is_imx27_dma(imxdma)) return imxdmac->hw_chaining; else return 0; @@ -267,7 +306,7 @@ static void imxdma_enable_hw(struct imxdma_desc *d) imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) | CCR_CEN | CCR_ACRPT, DMA_CCR(channel)); - if ((cpu_is_mx21() || cpu_is_mx27()) && + if (!is_imx1_dma(imxdma) && d->sg && imxdma_hw_chain(imxdmac)) { d->sg = sg_next(d->sg); if (d->sg) { @@ -436,7 +475,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) struct imxdma_engine *imxdma = dev_id; int i, disr; - if (cpu_is_mx21() || cpu_is_mx27()) + if (!is_imx1_dma(imxdma)) imxdma_err_handler(irq, dev_id); disr = imx_dmav1_readl(imxdma, DMA_DISR); @@ -961,35 +1000,32 @@ static void imxdma_issue_pending(struct dma_chan *chan) static int __init imxdma_probe(struct platform_device *pdev) { struct imxdma_engine *imxdma; + struct resource *res; int ret, i; + int irq, irq_err; - - imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL); + imxdma = devm_kzalloc(&pdev->dev, sizeof(*imxdma), GFP_KERNEL); if (!imxdma) return -ENOMEM; - if (cpu_is_mx1()) { - imxdma->base = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR); - } else if (cpu_is_mx21()) { - imxdma->base = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR); - } else if (cpu_is_mx27()) { - imxdma->base = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR); - } else { - kfree(imxdma); - return 0; - } + imxdma->devtype = pdev->id_entry->driver_data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + imxdma->base = devm_request_and_ioremap(&pdev->dev, res); + if (!imxdma->base) + return -EADDRNOTAVAIL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imxdma->dma_ipg)) { - ret = PTR_ERR(imxdma->dma_ipg); - goto err_clk; - } + if (IS_ERR(imxdma->dma_ipg)) + return PTR_ERR(imxdma->dma_ipg); imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(imxdma->dma_ahb)) { - ret = PTR_ERR(imxdma->dma_ahb); - goto err_clk; - } + if (IS_ERR(imxdma->dma_ahb)) + return PTR_ERR(imxdma->dma_ahb); clk_prepare_enable(imxdma->dma_ipg); clk_prepare_enable(imxdma->dma_ahb); @@ -997,18 +1033,25 @@ static int __init imxdma_probe(struct platform_device *pdev) /* reset DMA module */ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); - if (cpu_is_mx1()) { - ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma); + if (is_imx1_dma(imxdma)) { + ret = devm_request_irq(&pdev->dev, irq, + dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); - goto err_enable; + goto err; + } + + irq_err = platform_get_irq(pdev, 1); + if (irq_err < 0) { + ret = irq_err; + goto err; } - ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma); + ret = devm_request_irq(&pdev->dev, irq_err, + imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); - free_irq(MX1_DMA_INT, NULL); - goto err_enable; + goto err; } } @@ -1038,14 +1081,14 @@ static int __init imxdma_probe(struct platform_device *pdev) for (i = 0; i < IMX_DMA_CHANNELS; i++) { struct imxdma_channel *imxdmac = &imxdma->channel[i]; - if (cpu_is_mx21() || cpu_is_mx27()) { - ret = request_irq(MX2x_INT_DMACH0 + i, + if (!is_imx1_dma(imxdma)) { + ret = devm_request_irq(&pdev->dev, irq + i, dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ %d " "for DMA channel %d\n", - MX2x_INT_DMACH0 + i, i); - goto err_init; + irq + i, i); + goto err; } init_timer(&imxdmac->watchdog); imxdmac->watchdog.function = &imxdma_watchdog; @@ -1091,46 +1134,25 @@ static int __init imxdma_probe(struct platform_device *pdev) ret = dma_async_device_register(&imxdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); - goto err_init; + goto err; } return 0; -err_init: - - if (cpu_is_mx21() || cpu_is_mx27()) { - while (--i >= 0) - free_irq(MX2x_INT_DMACH0 + i, NULL); - } else if cpu_is_mx1() { - free_irq(MX1_DMA_INT, NULL); - free_irq(MX1_DMA_ERR, NULL); - } -err_enable: +err: clk_disable_unprepare(imxdma->dma_ipg); clk_disable_unprepare(imxdma->dma_ahb); -err_clk: - kfree(imxdma); return ret; } static int __exit imxdma_remove(struct platform_device *pdev) { struct imxdma_engine *imxdma = platform_get_drvdata(pdev); - int i; dma_async_device_unregister(&imxdma->dma_device); - if (cpu_is_mx21() || cpu_is_mx27()) { - for (i = 0; i < IMX_DMA_CHANNELS; i++) - free_irq(MX2x_INT_DMACH0 + i, NULL); - } else if cpu_is_mx1() { - free_irq(MX1_DMA_INT, NULL); - free_irq(MX1_DMA_ERR, NULL); - } - clk_disable_unprepare(imxdma->dma_ipg); clk_disable_unprepare(imxdma->dma_ahb); - kfree(imxdma); return 0; } @@ -1139,6 +1161,7 @@ static struct platform_driver imxdma_driver = { .driver = { .name = "imx-dma", }, + .id_table = imx_dma_devtype, .remove = __exit_p(imxdma_remove), }; diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c099ca0846f..f082aa3a918 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -40,7 +40,6 @@ #include <asm/irq.h> #include <linux/platform_data/dma-imx-sdma.h> #include <linux/platform_data/dma-imx.h> -#include <mach/hardware.h> #include "dmaengine.h" diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index c7573e50aa1..65855373cee 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -22,8 +22,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> - -#include <mach/ipu.h> +#include <linux/dma/ipu-dma.h> #include "../dmaengine.h" #include "ipu_intern.h" diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index fa95bcc3de1..a5ee37d5320 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -15,8 +15,7 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/module.h> - -#include <mach/ipu.h> +#include <linux/dma/ipu-dma.h> #include "ipu_intern.h" diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index bb2d8e7029e..7d35c237fbf 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -19,8 +19,7 @@ #include "virt-dma.h" -#include <plat/cpu.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> struct omap_dmadev { struct dma_device ddev; @@ -438,7 +437,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic( omap_disable_dma_irq(c->dma_ch, OMAP_DMA_BLOCK_IRQ); } - if (!cpu_class_is_omap1()) { + if (dma_omap2plus()) { omap_set_dma_src_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16); omap_set_dma_dest_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16); } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d055cee3694..6dbc4031f82 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -47,7 +47,7 @@ if GPIOLIB config OF_GPIO def_bool y - depends on OF && !SPARC + depends on OF config DEBUG_GPIO bool "Debug GPIO calls" @@ -152,7 +152,7 @@ config GPIO_MSM_V2 config GPIO_MVEBU def_bool y - depends on ARCH_MVEBU + depends on PLAT_ORION select GPIO_GENERIC select GENERIC_IRQ_CHIP diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index ed3e55161bd..f05e54258ff 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -153,7 +153,7 @@ static int __devinit gen_74x164_probe(struct spi_device *spi) } chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; - chip->buffer = devm_kzalloc(&spi->dev, chip->gpio_chip.ngpio, GFP_KERNEL); + chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL); if (!chip->buffer) { ret = -ENOMEM; goto exit_destroy; diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7a874129e5d..cf7afb9eb61 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -244,6 +244,8 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, if (ret) return ret; + mvebu_gpio_set(chip, pin, value); + spin_lock_irqsave(&mvchip->lock, flags); u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); u &= ~(1 << pin); @@ -644,7 +646,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) ct->handler = handle_edge_irq; ct->chip.name = mvchip->chip.label; - irq_setup_generic_chip(gc, IRQ_MSK(ngpios), IRQ_GC_INIT_MASK_CACHE, + irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); /* Setup irq domain on top of the generic chip. */ diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 94cbc842fbc..d335af1d4d8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -251,6 +251,40 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, } } +/** + * _clear_gpio_debounce - clear debounce settings for a gpio + * @bank: the gpio bank we're acting upon + * @gpio: the gpio number on this @gpio + * + * If a gpio is using debounce, then clear the debounce enable bit and if + * this is the only gpio in this bank using debounce, then clear the debounce + * time too. The debounce clock will also be disabled when calling this function + * if this is the only gpio in the bank using debounce. + */ +static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) +{ + u32 gpio_bit = GPIO_BIT(bank, gpio); + + if (!bank->dbck_flag) + return; + + if (!(bank->dbck_enable_mask & gpio_bit)) + return; + + bank->dbck_enable_mask &= ~gpio_bit; + bank->context.debounce_en &= ~gpio_bit; + __raw_writel(bank->context.debounce_en, + bank->base + bank->regs->debounce_en); + + if (!bank->dbck_enable_mask) { + bank->context.debounce = 0; + __raw_writel(bank->context.debounce, bank->base + + bank->regs->debounce); + clk_disable(bank->dbck); + bank->dbck_enabled = false; + } +} + static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, unsigned trigger) { @@ -539,6 +573,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) _set_gpio_irqenable(bank, gpio, 0); _clear_gpio_irqstatus(bank, gpio); _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); + _clear_gpio_debounce(bank, gpio); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a006f0db15a..88f41e51565 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2797,27 +2797,6 @@ static __init void exynos4_gpiolib_init(void) int group = 0; void __iomem *gpx_base; -#ifdef CONFIG_PINCTRL_SAMSUNG - /* - * This gpio driver includes support for device tree support and - * there are platforms using it. In order to maintain - * compatibility with those platforms, and to allow non-dt - * Exynos4210 platforms to use this gpiolib support, a check - * is added to find out if there is a active pin-controller - * driver support available. If it is available, this gpiolib - * support is ignored and the gpiolib support available in - * pin-controller driver is used. This is a temporary check and - * will go away when all of the Exynos4210 platforms have - * switched to using device tree and the pin-ctrl driver. - */ - struct device_node *pctrl_np; - const char *pctrl_compat = "samsung,pinctrl-exynos4210"; - pctrl_np = of_find_compatible_node(NULL, NULL, pctrl_compat); - if (pctrl_np) - if (of_device_is_available(pctrl_np)) - return; -#endif - /* gpio part1 */ gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); if (gpio_base1 == NULL) { @@ -3032,6 +3011,28 @@ static __init int samsung_gpiolib_init(void) int i, nr_chips; int group = 0; +#ifdef CONFIG_PINCTRL_SAMSUNG + /* + * This gpio driver includes support for device tree support and there + * are platforms using it. In order to maintain compatibility with those + * platforms, and to allow non-dt Exynos4210 platforms to use this + * gpiolib support, a check is added to find out if there is a active + * pin-controller driver support available. If it is available, this + * gpiolib support is ignored and the gpiolib support available in + * pin-controller driver is used. This is a temporary check and will go + * away when all of the Exynos4210 platforms have switched to using + * device tree and the pin-ctrl driver. + */ + struct device_node *pctrl_np; + static const struct of_device_id exynos_pinctrl_ids[] = { + { .compatible = "samsung,pinctrl-exynos4210", }, + { .compatible = "samsung,pinctrl-exynos4x12", }, + }; + for_each_matching_node(pctrl_np, exynos_pinctrl_ids) + if (pctrl_np && of_device_is_available(pctrl_np)) + return -ENODEV; +#endif + samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); if (soc_is_s3c24xx()) { diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 031c6adf5b6..1a3e2b9b477 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -116,7 +116,7 @@ static void timbgpio_irq_disable(struct irq_data *d) unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); - tgpio->last_ier &= ~(1 << offset); + tgpio->last_ier &= ~(1UL << offset); iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); spin_unlock_irqrestore(&tgpio->lock, flags); } @@ -128,7 +128,7 @@ static void timbgpio_irq_enable(struct irq_data *d) unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); - tgpio->last_ier |= 1 << offset; + tgpio->last_ier |= 1UL << offset; iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); spin_unlock_irqrestore(&tgpio->lock, flags); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5d6c71edc73..1c8d9e3380e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -623,9 +623,11 @@ static ssize_t export_store(struct class *class, */ status = gpio_request(gpio, "sysfs"); - if (status < 0) + if (status < 0) { + if (status == -EPROBE_DEFER) + status = -ENODEV; goto done; - + } status = gpio_export(gpio, true); if (status < 0) gpio_free(gpio); @@ -1191,8 +1193,10 @@ int gpio_request(unsigned gpio, const char *label) spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!gpio_is_valid(gpio)) { + status = -EINVAL; goto done; + } desc = &gpio_desc[gpio]; chip = desc->chip; if (chip == NULL) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 7ef1b673e1b..133b4132983 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -121,6 +121,8 @@ int drm_open(struct inode *inode, struct file *filp) int minor_id = iminor(inode); struct drm_minor *minor; int retcode = 0; + int need_setup = 0; + struct address_space *old_mapping; minor = idr_find(&drm_minors_idr, minor_id); if (!minor) @@ -132,23 +134,37 @@ int drm_open(struct inode *inode, struct file *filp) if (drm_device_is_unplugged(dev)) return -ENODEV; + if (!dev->open_count++) + need_setup = 1; + mutex_lock(&dev->struct_mutex); + old_mapping = dev->dev_mapping; + if (old_mapping == NULL) + dev->dev_mapping = &inode->i_data; + /* ihold ensures nobody can remove inode with our i_data */ + ihold(container_of(dev->dev_mapping, struct inode, i_data)); + inode->i_mapping = dev->dev_mapping; + filp->f_mapping = dev->dev_mapping; + mutex_unlock(&dev->struct_mutex); + retcode = drm_open_helper(inode, filp, dev); - if (!retcode) { - atomic_inc(&dev->counts[_DRM_STAT_OPENS]); - if (!dev->open_count++) - retcode = drm_setup(dev); - } - if (!retcode) { - mutex_lock(&dev->struct_mutex); - if (dev->dev_mapping == NULL) - dev->dev_mapping = &inode->i_data; - /* ihold ensures nobody can remove inode with our i_data */ - ihold(container_of(dev->dev_mapping, struct inode, i_data)); - inode->i_mapping = dev->dev_mapping; - filp->f_mapping = dev->dev_mapping; - mutex_unlock(&dev->struct_mutex); + if (retcode) + goto err_undo; + atomic_inc(&dev->counts[_DRM_STAT_OPENS]); + if (need_setup) { + retcode = drm_setup(dev); + if (retcode) + goto err_undo; } + return 0; +err_undo: + mutex_lock(&dev->struct_mutex); + filp->f_mapping = old_mapping; + inode->i_mapping = old_mapping; + iput(container_of(dev->dev_mapping, struct inode, i_data)); + dev->dev_mapping = old_mapping; + mutex_unlock(&dev->struct_mutex); + dev->open_count--; return retcode; } EXPORT_SYMBOL(drm_open); diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 59a26e577b5..fc345d4ebb0 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -1,6 +1,6 @@ config DRM_EXYNOS tristate "DRM Support for Samsung SoC EXYNOS Series" - depends on DRM && PLAT_SAMSUNG + depends on DRM && (PLAT_SAMSUNG || ARCH_MULTIPLATFORM) select DRM_KMS_HELPER select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index 18c271862ca..0f68a287267 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -374,6 +374,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, exynos_connector->encoder_id = encoder->base.id; exynos_connector->manager = manager; exynos_connector->dpms = DRM_MODE_DPMS_OFF; + connector->dpms = DRM_MODE_DPMS_OFF; connector->encoder = encoder; err = drm_mode_connector_attach_encoder(connector, encoder); diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index e51503fbaf2..241ad1eeec6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -43,12 +43,14 @@ * @manager: specific encoder has its own manager to control a hardware * appropriately and we can access a hardware drawing on this manager. * @dpms: store the encoder dpms value. + * @updated: indicate whether overlay data updating is needed or not. */ struct exynos_drm_encoder { struct drm_crtc *old_crtc; struct drm_encoder drm_encoder; struct exynos_drm_manager *manager; - int dpms; + int dpms; + bool updated; }; static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode) @@ -85,7 +87,9 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) switch (mode) { case DRM_MODE_DPMS_ON: if (manager_ops && manager_ops->apply) - manager_ops->apply(manager->dev); + if (!exynos_encoder->updated) + manager_ops->apply(manager->dev); + exynos_drm_connector_power(encoder, mode); exynos_encoder->dpms = mode; break; @@ -94,6 +98,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_OFF: exynos_drm_connector_power(encoder, mode); exynos_encoder->dpms = mode; + exynos_encoder->updated = false; break; default: DRM_ERROR("unspecified mode %d\n", mode); @@ -205,13 +210,22 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder) static void exynos_drm_encoder_commit(struct drm_encoder *encoder) { - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); + struct exynos_drm_manager *manager = exynos_encoder->manager; struct exynos_drm_manager_ops *manager_ops = manager->ops; DRM_DEBUG_KMS("%s\n", __FILE__); if (manager_ops && manager_ops->commit) manager_ops->commit(manager->dev); + + /* + * this will avoid one issue that overlay data is updated to + * real hardware two times. + * And this variable will be used to check if the data was + * already updated or not by exynos_drm_encoder_dpms function. + */ + exynos_encoder->updated = true; } static void exynos_drm_encoder_disable(struct drm_encoder *encoder) @@ -401,19 +415,6 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data) manager_ops->dpms(manager->dev, mode); /* - * set current mode to new one so that data aren't updated into - * registers by drm_helper_connector_dpms two times. - * - * in case that drm_crtc_helper_set_mode() is called, - * overlay_ops->commit() and manager_ops->commit() callbacks - * can be called two times, first at drm_crtc_helper_set_mode() - * and second at drm_helper_connector_dpms(). - * so with this setting, when drm_helper_connector_dpms() is called - * encoder->funcs->dpms() will be ignored. - */ - exynos_encoder->dpms = mode; - - /* * if this condition is ok then it means that the crtc is already * detached from encoder and last function for detaching is properly * done, so clear pipe from manager to prevent repeated call. diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 614b2e9ac46..e7fbb823fd8 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1142,7 +1142,7 @@ static int __devinit mixer_probe(struct platform_device *pdev) const struct of_device_id *match; match = of_match_node(of_match_ptr(mixer_match_types), pdev->dev.of_node); - drv = match->data; + drv = (struct mixer_drv_data *)match->data; } else { drv = (struct mixer_drv_data *) platform_get_device_id(pdev)->driver_data; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c9bfd83dde6..61ae104dca8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1505,7 +1505,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto put_gmch; } - i915_kick_out_firmware_fb(dev_priv); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kick_out_firmware_fb(dev_priv); pci_set_master(dev->pdev); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index f78061af704..6345878ae1e 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -143,7 +143,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) int old_dpms; /* PCH platforms and VLV only support on/off. */ - if (INTEL_INFO(dev)->gen < 5 && mode != DRM_MODE_DPMS_ON) + if (INTEL_INFO(dev)->gen >= 5 && mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) @@ -729,7 +729,7 @@ void intel_crt_init(struct drm_device *dev) crt->base.type = INTEL_OUTPUT_ANALOG; crt->base.cloneable = true; - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev) || IS_I830(dev)) crt->base.crtc_mask = (1 << 0); else crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 461a637f1ef..4154bcd7a07 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3841,6 +3841,17 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, } } + if (intel_encoder->type == INTEL_OUTPUT_EDP) { + /* Use VBT settings if we have an eDP panel */ + unsigned int edp_bpc = dev_priv->edp.bpp / 3; + + if (edp_bpc < display_bpc) { + DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); + display_bpc = edp_bpc; + } + continue; + } + /* * HDMI is either 12 or 8, so if the display lets 10bpc sneak * through, clamp it down. (Note: >12bpc will be caught below.) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 495625914e4..d7bc817f51a 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -341,9 +341,17 @@ static int intel_overlay_off(struct intel_overlay *overlay) intel_ring_emit(ring, flip_addr); intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); /* turn overlay off */ - intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF); - intel_ring_emit(ring, flip_addr); - intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + if (IS_I830(dev)) { + /* Workaround: Don't disable the overlay fully, since otherwise + * it dies on the next OVERLAY_ON cmd. */ + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_NOOP); + } else { + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF); + intel_ring_emit(ring, flip_addr); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + } intel_ring_advance(ring); return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e019b236986..e2aacd32954 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -435,7 +435,7 @@ int intel_panel_setup_backlight(struct drm_device *dev) props.type = BACKLIGHT_RAW; props.max_brightness = _intel_panel_get_max_backlight(dev); if (props.max_brightness == 0) { - DRM_ERROR("Failed to get maximum backlight value\n"); + DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; } dev_priv->backlight = diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index c01d97db006..c600fb06e25 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -894,6 +894,45 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) } #endif +static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, + unsigned if_index, uint8_t tx_rate, + uint8_t *data, unsigned length) +{ + uint8_t set_buf_index[2] = { if_index, 0 }; + uint8_t hbuf_size, tmp[8]; + int i; + + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_INDEX, + set_buf_index, 2)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO, + &hbuf_size, 1)) + return false; + + /* Buffer size is 0 based, hooray! */ + hbuf_size++; + + DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n", + if_index, length, hbuf_size); + + for (i = 0; i < hbuf_size; i += 8) { + memset(tmp, 0, 8); + if (i < length) + memcpy(tmp, data + i, min_t(unsigned, 8, length - i)); + + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_DATA, + tmp, 8)) + return false; + } + + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_TXRATE, + &tx_rate, 1); +} + static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) { struct dip_infoframe avi_if = { @@ -901,11 +940,7 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) .ver = DIP_VERSION_AVI, .len = DIP_LEN_AVI, }; - uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; - uint8_t set_buf_index[2] = { 1, 0 }; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; - uint64_t *data = (uint64_t *)sdvo_data; - unsigned i; intel_dip_infoframe_csum(&avi_if); @@ -915,22 +950,9 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) sdvo_data[3] = avi_if.checksum; memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi)); - if (!intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_HBUF_INDEX, - set_buf_index, 2)) - return false; - - for (i = 0; i < sizeof(sdvo_data); i += 8) { - if (!intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_HBUF_DATA, - data, 8)) - return false; - data++; - } - - return intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_HBUF_TXRATE, - &tx_rate, 1); + return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF, + SDVO_HBUF_TX_VSYNC, + sdvo_data, sizeof(sdvo_data)); } static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) @@ -2360,6 +2382,18 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) return true; } +static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo) +{ + struct drm_device *dev = intel_sdvo->base.base.dev; + struct drm_connector *connector, *tmp; + + list_for_each_entry_safe(connector, tmp, + &dev->mode_config.connector_list, head) { + if (intel_attached_encoder(connector) == &intel_sdvo->base) + intel_sdvo_destroy(connector); + } +} + static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, struct intel_sdvo_connector *intel_sdvo_connector, int type) @@ -2683,7 +2717,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on %s\n", SDVO_NAME(intel_sdvo)); - goto err; + /* Output_setup can leave behind connectors! */ + goto err_output; } /* Only enable the hotplug irq if we need it, to work around noisy @@ -2696,12 +2731,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) /* Set the input timing to the screen. Assume always input 0. */ if (!intel_sdvo_set_target_input(intel_sdvo)) - goto err; + goto err_output; if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, &intel_sdvo->pixel_clock_min, &intel_sdvo->pixel_clock_max)) - goto err; + goto err_output; DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " @@ -2721,6 +2756,9 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; +err_output: + intel_sdvo_output_cleanup(intel_sdvo); + err: drm_encoder_cleanup(&intel_encoder->base); i2c_del_adapter(&intel_sdvo->ddc); diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 9d030142ee4..770bdd6ecd9 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -708,6 +708,8 @@ struct intel_sdvo_enhancements_arg { #define SDVO_CMD_SET_AUDIO_STAT 0x91 #define SDVO_CMD_GET_AUDIO_STAT 0x92 #define SDVO_CMD_SET_HBUF_INDEX 0x93 + #define SDVO_HBUF_INDEX_ELD 0 + #define SDVO_HBUF_INDEX_AVI_IF 1 #define SDVO_CMD_GET_HBUF_INDEX 0x94 #define SDVO_CMD_GET_HBUF_INFO 0x95 #define SDVO_CMD_SET_HBUF_AV_SPLIT 0x96 diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c index 4d620644867..a6d3cd6490f 100644 --- a/drivers/gpu/drm/nouveau/core/core/mm.c +++ b/drivers/gpu/drm/nouveau/core/core/mm.c @@ -218,13 +218,16 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return -ENOMEM; - node->offset = roundup(offset, mm->block_size); - node->length = rounddown(offset + length, mm->block_size) - node->offset; + + if (length) { + node->offset = roundup(offset, mm->block_size); + node->length = rounddown(offset + length, mm->block_size); + node->length -= node->offset; + } list_add_tail(&node->nl_entry, &mm->nodes); list_add_tail(&node->fl_entry, &mm->free); mm->heap_nodes++; - mm->heap_size += length; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 16a9afb1060..05a909a17ce 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -22,6 +22,8 @@ * Authors: Ben Skeggs */ +#include <subdev/bar.h> + #include <engine/software.h> #include <engine/disp.h> @@ -37,6 +39,7 @@ nv50_disp_sclass[] = { static void nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) { + struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_disp *disp = &priv->base; struct nouveau_software_chan *chan, *temp; unsigned long flags; @@ -46,18 +49,19 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) if (chan->vblank.crtc != crtc) continue; - nv_wr32(priv, 0x001704, chan->vblank.channel); - nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); - if (nv_device(priv)->chipset == 0x50) { + nv_wr32(priv, 0x001704, chan->vblank.channel); + nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); + bar->flush(bar); nv_wr32(priv, 0x001570, chan->vblank.offset); nv_wr32(priv, 0x001574, chan->vblank.value); } else { - if (nv_device(priv)->chipset >= 0xc0) { - nv_wr32(priv, 0x06000c, - upper_32_bits(chan->vblank.offset)); - } - nv_wr32(priv, 0x060010, chan->vblank.offset); + nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); + bar->flush(bar); + nv_wr32(priv, 0x06000c, + upper_32_bits(chan->vblank.offset)); + nv_wr32(priv, 0x060010, + lower_32_bits(chan->vblank.offset)); nv_wr32(priv, 0x060014, chan->vblank.value); } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 8d0021049ec..425001204a8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -156,8 +156,8 @@ nv40_graph_context_ctor(struct nouveau_object *parent, static int nv40_graph_context_fini(struct nouveau_object *object, bool suspend) { - struct nv04_graph_priv *priv = (void *)object->engine; - struct nv04_graph_chan *chan = (void *)object; + struct nv40_graph_priv *priv = (void *)object->engine; + struct nv40_graph_chan *chan = (void *)object; u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; int ret = 0; diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c index 12418574efe..f7c581ad199 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c @@ -38,7 +38,7 @@ struct nv40_mpeg_priv { }; struct nv40_mpeg_chan { - struct nouveau_mpeg base; + struct nouveau_mpeg_chan base; }; /******************************************************************************* diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h index 9ee9bf4028c..975137ba34a 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/mm.h +++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h @@ -19,7 +19,6 @@ struct nouveau_mm { u32 block_size; int heap_nodes; - u32 heap_size; }; int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index 27fb1af7a77..5f570806143 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -219,13 +219,11 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ((priv->base.ram.size & 0x000000ff) << 32); tags = nv_rd32(priv, 0x100320); - if (tags) { - ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1); - if (ret) - return ret; + ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1); + if (ret) + return ret; - nv_debug(priv, "%d compression tags\n", tags); - } + nv_debug(priv, "%d compression tags\n", tags); size = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail; switch (device->chipset) { diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index 3d2c88310f9..dbfc2abf0cf 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -292,7 +292,7 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, case DCB_I2C_NVIO_BIT: port->drive = info.drive & 0x0f; if (device->card_type < NV_D0) { - if (info.drive >= ARRAY_SIZE(nv50_i2c_port)) + if (port->drive >= ARRAY_SIZE(nv50_i2c_port)) break; port->drive = nv50_i2c_port[port->drive]; port->sense = port->drive; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c index 49050d991e7..9474cfca6e4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c @@ -67,7 +67,7 @@ nv41_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) static void nv41_vm_flush(struct nouveau_vm *vm) { - struct nv04_vm_priv *priv = (void *)vm->vmm; + struct nv04_vmmgr_priv *priv = (void *)vm->vmm; mutex_lock(&nv_subdev(priv)->mutex); nv_wr32(priv, 0x100810, 0x00000022); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9a6e2cb282d..d3595b23434 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -355,7 +355,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) * valid - it's not (rh#613284) */ if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) { - if (!(nv_connector->edid = nouveau_acpi_edid(dev, connector))) { + if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) { status = connector_status_connected; goto out; } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index d2f8ffeed74..86124b131f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -290,6 +290,7 @@ nouveau_display_create(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_disp *pdisp = nouveau_disp(drm->device); struct nouveau_display *disp; + u32 pclass = dev->pdev->class >> 8; int ret, gen; disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); @@ -360,23 +361,27 @@ nouveau_display_create(struct drm_device *dev) drm_kms_helper_poll_init(dev); drm_kms_helper_poll_disable(dev); - if (nv_device(drm->device)->card_type < NV_50) - ret = nv04_display_create(dev); - else - if (nv_device(drm->device)->card_type < NV_D0) - ret = nv50_display_create(dev); - else - ret = nvd0_display_create(dev); - if (ret) - goto disp_create_err; - - if (dev->mode_config.num_crtc) { - ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (nouveau_modeset == 1 || + (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) { + if (nv_device(drm->device)->card_type < NV_50) + ret = nv04_display_create(dev); + else + if (nv_device(drm->device)->card_type < NV_D0) + ret = nv50_display_create(dev); + else + ret = nvd0_display_create(dev); if (ret) - goto vblank_err; + goto disp_create_err; + + if (dev->mode_config.num_crtc) { + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret) + goto vblank_err; + } + + nouveau_backlight_init(dev); } - nouveau_backlight_init(dev); return 0; vblank_err: @@ -395,7 +400,8 @@ nouveau_display_destroy(struct drm_device *dev) nouveau_backlight_exit(dev); drm_vblank_cleanup(dev); - disp->dtor(dev); + if (disp->dtor) + disp->dtor(dev); drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index ccae8c26ae2..0910125cbbc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -63,8 +63,9 @@ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration"); static int nouveau_noaccel = 0; module_param_named(noaccel, nouveau_noaccel, int, 0400); -MODULE_PARM_DESC(modeset, "enable driver"); -static int nouveau_modeset = -1; +MODULE_PARM_DESC(modeset, "enable driver (default: auto, " + "0 = disabled, 1 = enabled, 2 = headless)"); +int nouveau_modeset = -1; module_param_named(modeset, nouveau_modeset, int, 0400); static struct drm_driver driver; @@ -363,7 +364,8 @@ nouveau_drm_unload(struct drm_device *dev) nouveau_pm_fini(dev); - nouveau_display_fini(dev); + if (dev->mode_config.num_crtc) + nouveau_display_fini(dev); nouveau_display_destroy(dev); nouveau_irq_fini(dev); @@ -403,13 +405,15 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) pm_state.event == PM_EVENT_PRETHAW) return 0; - NV_INFO(drm, "suspending fbcon...\n"); - nouveau_fbcon_set_suspend(dev, 1); + if (dev->mode_config.num_crtc) { + NV_INFO(drm, "suspending fbcon...\n"); + nouveau_fbcon_set_suspend(dev, 1); - NV_INFO(drm, "suspending display...\n"); - ret = nouveau_display_suspend(dev); - if (ret) - return ret; + NV_INFO(drm, "suspending display...\n"); + ret = nouveau_display_suspend(dev); + if (ret) + return ret; + } NV_INFO(drm, "evicting buffers...\n"); ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); @@ -445,8 +449,10 @@ fail_client: nouveau_client_init(&cli->base); } - NV_INFO(drm, "resuming display...\n"); - nouveau_display_resume(dev); + if (dev->mode_config.num_crtc) { + NV_INFO(drm, "resuming display...\n"); + nouveau_display_resume(dev); + } return ret; } @@ -486,8 +492,10 @@ nouveau_drm_resume(struct pci_dev *pdev) nouveau_irq_postinstall(dev); nouveau_pm_resume(dev); - NV_INFO(drm, "resuming display...\n"); - nouveau_display_resume(dev); + if (dev->mode_config.num_crtc) { + NV_INFO(drm, "resuming display...\n"); + nouveau_display_resume(dev); + } return 0; } @@ -662,9 +670,7 @@ nouveau_drm_init(void) #ifdef CONFIG_VGA_CONSOLE if (vgacon_text_force()) nouveau_modeset = 0; - else #endif - nouveau_modeset = 1; } if (!nouveau_modeset) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 81947121754..a1016992708 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -141,4 +141,6 @@ int nouveau_drm_resume(struct pci_dev *); nv_info((cli), fmt, ##args); \ } while (0) +extern int nouveau_modeset; + #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 9ca8afdb554..1d8cb506a28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -61,13 +61,15 @@ nouveau_irq_handler(DRM_IRQ_ARGS) nv_subdev(pmc)->intr(nv_subdev(pmc)); - if (device->card_type >= NV_D0) { - if (nv_rd32(device, 0x000100) & 0x04000000) - nvd0_display_intr(dev); - } else - if (device->card_type >= NV_50) { - if (nv_rd32(device, 0x000100) & 0x04000000) - nv50_display_intr(dev); + if (dev->mode_config.num_crtc) { + if (device->card_type >= NV_D0) { + if (nv_rd32(device, 0x000100) & 0x04000000) + nvd0_display_intr(dev); + } else + if (device->card_type >= NV_50) { + if (nv_rd32(device, 0x000100) & 0x04000000) + nv50_display_intr(dev); + } } return IRQ_HANDLED; diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index 347a3bd78d0..64f7020fb60 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -220,7 +220,7 @@ out: NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode); if (blue == 0x18) { - NV_INFO(drm, "Load detected on head A\n"); + NV_DEBUG(drm, "Load detected on head A\n"); return connector_status_connected; } @@ -338,8 +338,8 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) if (nv17_dac_sample_load(encoder) & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { - NV_INFO(drm, "Load detected on output %c\n", - '@' + ffs(dcb->or)); + NV_DEBUG(drm, "Load detected on output %c\n", + '@' + ffs(dcb->or)); return connector_status_connected; } else { return connector_status_disconnected; @@ -413,9 +413,9 @@ static void nv04_dac_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); - NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), - nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); + NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", + drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), + nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) @@ -461,8 +461,8 @@ static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) return; nv_encoder->last_dpms = mode; - NV_INFO(drm, "Setting dpms mode %d on vga encoder (output %d)\n", - mode, nv_encoder->dcb->index); + NV_DEBUG(drm, "Setting dpms mode %d on vga encoder (output %d)\n", + mode, nv_encoder->dcb->index); nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); } diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index da55d7642c8..184cdf80676 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -476,9 +476,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); - NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), - nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); + NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", + drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), + nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) @@ -520,8 +520,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) return; nv_encoder->last_dpms = mode; - NV_INFO(drm, "Setting dpms mode %d on lvds encoder (output %d)\n", - mode, nv_encoder->dcb->index); + NV_DEBUG(drm, "Setting dpms mode %d on lvds encoder (output %d)\n", + mode, nv_encoder->dcb->index); if (was_powersaving && is_powersaving_dpms(mode)) return; @@ -565,8 +565,8 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode) return; nv_encoder->last_dpms = mode; - NV_INFO(drm, "Setting dpms mode %d on tmds encoder (output %d)\n", - mode, nv_encoder->dcb->index); + NV_DEBUG(drm, "Setting dpms mode %d on tmds encoder (output %d)\n", + mode, nv_encoder->dcb->index); nv04_dfp_update_backlight(encoder, mode); nv04_dfp_update_fp_control(encoder, mode); diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 099fbeda6e2..62e826a139b 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -75,8 +75,8 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) struct nv04_mode_state *state = &nv04_display(dev)->mode_reg; uint8_t crtc1A; - NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n", - mode, nv_encoder->dcb->index); + NV_DEBUG(drm, "Setting dpms mode %d on TV encoder (output %d)\n", + mode, nv_encoder->dcb->index); state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK); @@ -167,9 +167,8 @@ static void nv04_tv_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); - NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, - '@' + ffs(nv_encoder->dcb->or)); + NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", + drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } static void nv04_tv_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 2e566e123e9..3bce0299f64 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1696,35 +1696,43 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return ATOM_PPLL2; DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; - } else { - if (ASIC_IS_AVIVO(rdev)) { - /* in DP mode, the DP ref clock can come from either PPLL - * depending on the asic: - * DCE3: PPLL1 or PPLL2 - */ - if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { - /* use the same PPLL for all DP monitors */ - pll = radeon_get_shared_dp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } else { - /* use the same PPLL for all monitors with the same clock */ - pll = radeon_get_shared_nondp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - /* all other cases */ - pll_in_use = radeon_get_pll_use_mask(crtc); + } else if (ASIC_IS_AVIVO(rdev)) { + /* in DP mode, the DP ref clock can come from either PPLL + * depending on the asic: + * DCE3: PPLL1 or PPLL2 + */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } + /* all other cases */ + pll_in_use = radeon_get_pll_use_mask(crtc); + /* the order shouldn't matter here, but we probably + * need this until we have atomic modeset + */ + if (rdev->flags & RADEON_IS_IGP) { if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1; if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; - DRM_ERROR("unable to allocate a PPLL\n"); - return ATOM_PPLL_INVALID; } else { - /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ - return radeon_crtc->crtc_id; + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; } + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; + } else { + /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ + return radeon_crtc->crtc_id; } } diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index ba498f8e47a..010bae19554 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1625,7 +1625,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); /* some early dce3.2 boards have a bug in their transmitter control table */ - if ((rdev->family != CHIP_RV710) || (rdev->family != CHIP_RV730)) + if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730)) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 14313ad43b7..af31f829f4a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1372,7 +1372,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN); for (i = 0; i < rdev->num_crtc; i++) { - if (save->crtc_enabled) { + if (save->crtc_enabled[i]) { if (ASIC_IS_DCE6(rdev)) { tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 30271b64191..c042e497e45 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -264,7 +264,7 @@ static int evergreen_surface_check_2d(struct radeon_cs_parser *p, /* macro tile width & height */ palign = (8 * surf->bankw * track->npipes) * surf->mtilea; halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea; - mtileb = (palign / 8) * (halign / 8) * tileb;; + mtileb = (palign / 8) * (halign / 8) * tileb; mtile_pr = surf->nbx / palign; mtile_ps = (mtile_pr * surf->nby) / halign; surf->layer_size = mtile_ps * mtileb * slice_pt; @@ -2725,6 +2725,9 @@ static bool evergreen_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { case GRBM_GFX_INDEX: + case CP_STRMOUT_CNTL: + case CP_COHER_CNTL: + case CP_COHER_SIZE: case VGT_VTX_VECT_EJECT_REG: case VGT_CACHE_INVALIDATION: case VGT_GS_VERTEX_REUSE: diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index df542f1a5df..2bc0f6a1b42 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -91,6 +91,10 @@ #define FB_READ_EN (1 << 0) #define FB_WRITE_EN (1 << 1) +#define CP_STRMOUT_CNTL 0x84FC + +#define CP_COHER_CNTL 0x85F0 +#define CP_COHER_SIZE 0x85F4 #define CP_COHER_BASE 0x85F8 #define CP_STALLED_STAT1 0x8674 #define CP_STALLED_STAT2 0x8678 diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 37f6a907aea..15f5ded65e0 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -352,9 +352,9 @@ static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) } /** - * radeon_atpx_switchto - switch to the requested GPU + * radeon_atpx_power_state - power down/up the requested GPU * - * @id: GPU to switch to + * @id: GPU to power down/up * @state: requested power state (0 = off, 1 = on) * * Execute the necessary ATPX function to power down/up the discrete GPU diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 67cfc1795ec..b884c362a8c 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -941,7 +941,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) struct drm_mode_object *obj; int i; enum drm_connector_status ret = connector_status_disconnected; - bool dret = false; + bool dret = false, broken_edid = false; if (!force && radeon_check_hpd_status_unchanged(connector)) return connector->status; @@ -965,6 +965,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector)); radeon_connector->ddc_bus = NULL; + } else { + ret = connector_status_connected; + broken_edid = true; /* defer use_digital to later */ } } else { radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); @@ -1047,13 +1050,24 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) encoder_funcs = encoder->helper_private; if (encoder_funcs->detect) { - if (ret != connector_status_connected) { - ret = encoder_funcs->detect(encoder, connector); - if (ret == connector_status_connected) { - radeon_connector->use_digital = false; + if (!broken_edid) { + if (ret != connector_status_connected) { + /* deal with analog monitors without DDC */ + ret = encoder_funcs->detect(encoder, connector); + if (ret == connector_status_connected) { + radeon_connector->use_digital = false; + } + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } - if (ret != connector_status_disconnected) - radeon_connector->detected_by_load = true; + } else { + enum drm_connector_status lret; + /* assume digital unless load detected otherwise */ + radeon_connector->use_digital = true; + lret = encoder_funcs->detect(encoder, connector); + DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret); + if (lret == connector_status_connected) + radeon_connector->use_digital = false; } break; } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 5677a424b58..6857cb4efb7 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -295,6 +295,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; + uint32_t crtc_ext_cntl = 0; uint32_t mask; if (radeon_crtc->crtc_id) @@ -307,6 +308,16 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); + /* + * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC. + * Therefore it is set in the DAC DMPS function. + * This is different for GPU's with a single CRTC but a primary and a + * TV DAC: here it controls the single CRTC no matter where it is + * routed. Therefore we set it here. + */ + if (rdev->flags & RADEON_SINGLE_CRTC) + crtc_ext_cntl = RADEON_CRTC_CRT_ON; + switch (mode) { case DRM_MODE_DPMS_ON: radeon_crtc->enabled = true; @@ -317,7 +328,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) else { WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | RADEON_CRTC_DISP_REQ_EN_B)); - WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask); + WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl)); } drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); @@ -331,7 +342,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) else { WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | RADEON_CRTC_DISP_REQ_EN_B)); - WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); + WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl)); } radeon_crtc->enabled = false; /* adjust pm to dpms changes AFTER disabling crtcs */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 0063df9d166..f5ba2241dac 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -537,7 +537,9 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode break; } - WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + /* handled in radeon_crtc_dpms() */ + if (!(rdev->flags & RADEON_SINGLE_CRTC)) + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); WREG32(RADEON_DAC_CNTL, dac_cntl); WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); @@ -662,6 +664,8 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc if (ASIC_IS_R300(rdev)) tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else if (ASIC_IS_RV100(rdev)) + tmp |= (0x1ac << RADEON_DAC_FORCE_DATA_SHIFT); else tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); @@ -671,6 +675,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; WREG32(RADEON_DAC_CNTL, tmp); + tmp = dac_macro_cntl; tmp &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); @@ -1092,7 +1097,8 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) } else { if (is_tv) WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); - else + /* handled in radeon_crtc_dpms() */ + else if (!(rdev->flags & RADEON_SINGLE_CRTC)) WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); } @@ -1416,13 +1422,104 @@ static bool radeon_legacy_tv_detect(struct drm_encoder *encoder, return found; } +static bool radeon_legacy_ext_dac_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl; + uint32_t disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c; + uint32_t disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f; + uint32_t tmp, crtc2_h_total_disp, crtc2_v_total_disp; + uint32_t crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid; + bool found = false; + int i; + + /* save the regs we need */ + gpio_monid = RREG32(RADEON_GPIO_MONID); + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + disp_lin_trans_grph_a = RREG32(RADEON_DISP_LIN_TRANS_GRPH_A); + disp_lin_trans_grph_b = RREG32(RADEON_DISP_LIN_TRANS_GRPH_B); + disp_lin_trans_grph_c = RREG32(RADEON_DISP_LIN_TRANS_GRPH_C); + disp_lin_trans_grph_d = RREG32(RADEON_DISP_LIN_TRANS_GRPH_D); + disp_lin_trans_grph_e = RREG32(RADEON_DISP_LIN_TRANS_GRPH_E); + disp_lin_trans_grph_f = RREG32(RADEON_DISP_LIN_TRANS_GRPH_F); + crtc2_h_total_disp = RREG32(RADEON_CRTC2_H_TOTAL_DISP); + crtc2_v_total_disp = RREG32(RADEON_CRTC2_V_TOTAL_DISP); + crtc2_h_sync_strt_wid = RREG32(RADEON_CRTC2_H_SYNC_STRT_WID); + crtc2_v_sync_strt_wid = RREG32(RADEON_CRTC2_V_SYNC_STRT_WID); + + tmp = RREG32(RADEON_GPIO_MONID); + tmp &= ~RADEON_GPIO_A_0; + WREG32(RADEON_GPIO_MONID, tmp); + + WREG32(RADEON_FP2_GEN_CNTL, (RADEON_FP2_ON | + RADEON_FP2_PANEL_FORMAT | + R200_FP2_SOURCE_SEL_TRANS_UNIT | + RADEON_FP2_DVO_EN | + R200_FP2_DVO_RATE_SEL_SDR)); + + WREG32(RADEON_DISP_OUTPUT_CNTL, (RADEON_DISP_DAC_SOURCE_RMX | + RADEON_DISP_TRANS_MATRIX_GRAPHICS)); + + WREG32(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_EN | + RADEON_CRTC2_DISP_REQ_EN_B)); + + WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); + + WREG32(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); + WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); + WREG32(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); + WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); + + for (i = 0; i < 200; i++) { + tmp = RREG32(RADEON_GPIO_MONID); + if (tmp & RADEON_GPIO_Y_0) + found = true; + + if (found) + break; + + if (!drm_can_sleep()) + mdelay(1); + else + msleep(1); + } + + /* restore the regs we used */ + WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e); + WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f); + WREG32(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp); + WREG32(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp); + WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid); + WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + WREG32(RADEON_GPIO_MONID, gpio_monid); + + return found; +} + static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; - uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; + uint32_t crtc2_gen_cntl = 0, tv_dac_cntl, dac_cntl2, dac_ext_cntl; + uint32_t gpiopad_a = 0, pixclks_cntl, tmp; + uint32_t disp_output_cntl = 0, disp_hw_debug = 0, crtc_ext_cntl = 0; enum drm_connector_status found = connector_status_disconnected; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; @@ -1459,12 +1556,27 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder return connector_status_disconnected; } + /* R200 uses an external DAC for secondary DAC */ + if (rdev->family == CHIP_R200) { + if (radeon_legacy_ext_dac_detect(encoder, connector)) + found = connector_status_connected; + return found; + } + /* save the regs we need */ pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); - gpiopad_a = ASIC_IS_R300(rdev) ? RREG32(RADEON_GPIOPAD_A) : 0; - disp_output_cntl = ASIC_IS_R300(rdev) ? RREG32(RADEON_DISP_OUTPUT_CNTL) : 0; - disp_hw_debug = ASIC_IS_R300(rdev) ? 0 : RREG32(RADEON_DISP_HW_DEBUG); - crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + + if (rdev->flags & RADEON_SINGLE_CRTC) { + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + } else { + if (ASIC_IS_R300(rdev)) { + gpiopad_a = RREG32(RADEON_GPIOPAD_A); + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + } else { + disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + } + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + } tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); dac_cntl2 = RREG32(RADEON_DAC_CNTL2); @@ -1473,22 +1585,24 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder | RADEON_PIX2CLK_DAC_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - if (ASIC_IS_R300(rdev)) - WREG32_P(RADEON_GPIOPAD_A, 1, ~1); - - tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; - tmp |= RADEON_CRTC2_CRT2_ON | - (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); - - WREG32(RADEON_CRTC2_GEN_CNTL, tmp); - - if (ASIC_IS_R300(rdev)) { - tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; - tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; - WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + if (rdev->flags & RADEON_SINGLE_CRTC) { + tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; + WREG32(RADEON_CRTC_EXT_CNTL, tmp); } else { - tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; - WREG32(RADEON_DISP_HW_DEBUG, tmp); + tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; + tmp |= RADEON_CRTC2_CRT2_ON | + (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + + if (ASIC_IS_R300(rdev)) { + WREG32_P(RADEON_GPIOPAD_A, 1, ~1); + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + } else { + tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; + WREG32(RADEON_DISP_HW_DEBUG, tmp); + } } tmp = RADEON_TV_DAC_NBLANK | @@ -1530,14 +1644,19 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder WREG32(RADEON_DAC_CNTL2, dac_cntl2); WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); - WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); - if (ASIC_IS_R300(rdev)) { - WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); - WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + if (rdev->flags & RADEON_SINGLE_CRTC) { + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); } else { - WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + if (ASIC_IS_R300(rdev)) { + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + } else { + WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + } } + WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); return found; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index b0db712060f..4422d630b33 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2474,6 +2474,7 @@ static bool si_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { case GRBM_GFX_INDEX: + case CP_STRMOUT_CNTL: case VGT_VTX_VECT_EJECT_REG: case VGT_CACHE_INVALIDATION: case VGT_ESGS_RING_SIZE: diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 7d2a20e5657..a8871afc5b4 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -424,6 +424,7 @@ # define RDERR_INT_ENABLE (1 << 0) # define GUI_IDLE_INT_ENABLE (1 << 19) +#define CP_STRMOUT_CNTL 0x84FC #define SCRATCH_REG0 0x8500 #define SCRATCH_REG1 0x8504 #define SCRATCH_REG2 0x8508 diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 860dc4813e9..bd2a3b40cd1 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -749,7 +749,10 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags, /* clear the pages coming from the pool if requested */ if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) { list_for_each_entry(p, &plist, lru) { - clear_page(page_address(p)); + if (PageHighMem(p)) + clear_highpage(p); + else + clear_page(page_address(p)); } } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index bf8260133ea..7d759a43029 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -308,9 +308,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm) if (unlikely(to_page == NULL)) goto out_err; - preempt_disable(); copy_highpage(to_page, from_page); - preempt_enable(); page_cache_release(from_page); } @@ -358,9 +356,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) ret = PTR_ERR(to_page); goto out_err; } - preempt_disable(); copy_highpage(to_page, from_page); - preempt_enable(); set_page_dirty(to_page); mark_page_accessed(to_page); page_cache_release(to_page); diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index fccd361f7b5..87aa5f5d3c8 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -104,7 +104,7 @@ udl_fb_user_fb_create(struct drm_device *dev, int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, - u32 byte_offset, u32 byte_width, + u32 byte_offset, u32 device_byte_offset, u32 byte_width, int *ident_ptr, int *sent_ptr); int udl_dumb_create(struct drm_file *file_priv, diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 69a2b16f42a..d4ab3beaada 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -114,9 +114,10 @@ static void udlfb_dpy_deferred_io(struct fb_info *info, list_for_each_entry(cur, &fbdefio->pagelist, lru) { if (udl_render_hline(dev, (ufbdev->ufb.base.bits_per_pixel / 8), - &urb, (char *) info->fix.smem_start, - &cmd, cur->index << PAGE_SHIFT, - PAGE_SIZE, &bytes_identical, &bytes_sent)) + &urb, (char *) info->fix.smem_start, + &cmd, cur->index << PAGE_SHIFT, + cur->index << PAGE_SHIFT, + PAGE_SIZE, &bytes_identical, &bytes_sent)) goto error; bytes_rendered += PAGE_SIZE; } @@ -187,10 +188,11 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, for (i = y; i < y + height ; i++) { const int line_offset = fb->base.pitches[0] * i; const int byte_offset = line_offset + (x * bpp); - + const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); if (udl_render_hline(dev, bpp, &urb, (char *) fb->obj->vmapping, - &cmd, byte_offset, width * bpp, + &cmd, byte_offset, dev_byte_offset, + width * bpp, &bytes_identical, &bytes_sent)) goto error; } diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index dc095526ffb..142fee5f983 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -213,11 +213,12 @@ static void udl_compress_hline16( */ int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, - u32 byte_offset, u32 byte_width, + u32 byte_offset, u32 device_byte_offset, + u32 byte_width, int *ident_ptr, int *sent_ptr) { const u8 *line_start, *line_end, *next_pixel; - u32 base16 = 0 + (byte_offset / bpp) * 2; + u32 base16 = 0 + (device_byte_offset / bpp) * 2; struct urb *urb = *urb_ptr; u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index 3ce68a2e312..d1498bfd787 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -306,7 +306,7 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin) BUG_ON(!atomic_read(&bo->reserved)); BUG_ON(old_mem_type != TTM_PL_VRAM && - old_mem_type != VMW_PL_FLAG_GMR); + old_mem_type != VMW_PL_GMR); pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED; if (pin) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index ed3c1e7ddde..2dd185e42f2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1098,6 +1098,11 @@ static void vmw_pm_complete(struct device *kdev) struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); + mutex_lock(&dev_priv->hw_mutex); + vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); + (void) vmw_read(dev_priv, SVGA_REG_ID); + mutex_unlock(&dev_priv->hw_mutex); + /** * Reclaim 3d reference held by fbdev and potentially * start fifo. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index b07ca2e4d04..7290811f89b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -110,6 +110,8 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); ret = copy_to_user(buffer, bounce, size); + if (ret) + ret = -EFAULT; vfree(bounce); if (unlikely(ret != 0)) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 06ebdbb6ea0..fd7722aecf7 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -522,6 +522,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bd3971bf31b..f4109fd657f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1532,6 +1532,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, @@ -2139,6 +2142,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 269b50912a4..9d7a42857ea 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -118,6 +118,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254 +#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259 +#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a +#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249 #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a #define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 3acdcfcc17d..6fcd466d082 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -28,22 +28,30 @@ #define MS_RDESC 0x08 #define MS_NOGET 0x10 #define MS_DUPLICATE_USAGES 0x20 +#define MS_RDESC_3K 0x40 -/* - * Microsoft Wireless Desktop Receiver (Model 1028) has - * 'Usage Min/Max' where it ought to have 'Physical Min/Max' - */ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + /* + * Microsoft Wireless Desktop Receiver (Model 1028) has + * 'Usage Min/Max' where it ought to have 'Physical Min/Max' + */ if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); rdesc[557] = 0x35; rdesc[559] = 0x45; } + /* the same as above (s/usage/physical/) */ + if ((quirks & MS_RDESC_3K) && *rsize == 106 && rdesc[94] == 0x19 && + rdesc[95] == 0x00 && rdesc[96] == 0x29 && + rdesc[97] == 0xff) { + rdesc[94] = 0x35; + rdesc[96] = 0x45; + } return rdesc; } @@ -192,7 +200,7 @@ static const struct hid_device_id ms_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB), .driver_data = MS_PRESENTER }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K), - .driver_data = MS_ERGONOMY }, + .driver_data = MS_ERGONOMY | MS_RDESC_3K }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0), .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3eb02b94fc8..7867d69f0ef 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -210,8 +210,7 @@ static struct mt_class mt_classes[] = { }, { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | - MT_QUIRK_SLOT_IS_CONTACTNUMBER, - .maxcontacts = 10 + MT_QUIRK_SLOT_IS_CONTACTNUMBER }, { .name = MT_CLS_FLATFROG, @@ -421,11 +420,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, * contact max are global to the report */ td->last_field_index = field->index; return -1; - } case HID_DG_TOUCH: /* Legacy devices use TIPSWITCH and not TOUCH. * Let's just ignore this field. */ return -1; + } /* let hid-input decide for the others */ return 0; diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 17d15bb610d..7c47fc3f7b2 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -42,7 +42,6 @@ static struct cdev hidraw_cdev; static struct class *hidraw_class; static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; static DEFINE_MUTEX(minors_lock); -static void drop_ref(struct hidraw *hid, int exists_bit); static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { @@ -114,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, __u8 *buf; int ret = 0; - if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { + if (!hidraw_table[minor]) { ret = -ENODEV; goto out; } @@ -262,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file) } mutex_lock(&minors_lock); - if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { + if (!hidraw_table[minor]) { err = -ENODEV; goto out_unlock; } @@ -299,12 +298,36 @@ out: static int hidraw_release(struct inode * inode, struct file * file) { unsigned int minor = iminor(inode); + struct hidraw *dev; struct hidraw_list *list = file->private_data; + int ret; + int i; + + mutex_lock(&minors_lock); + if (!hidraw_table[minor]) { + ret = -ENODEV; + goto unlock; + } - drop_ref(hidraw_table[minor], 0); list_del(&list->node); + dev = hidraw_table[minor]; + if (!--dev->open) { + if (list->hidraw->exist) { + hid_hw_power(dev->hid, PM_HINT_NORMAL); + hid_hw_close(dev->hid); + } else { + kfree(list->hidraw); + } + } + + for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i) + kfree(list->buffer[i].value); kfree(list); - return 0; + ret = 0; +unlock: + mutex_unlock(&minors_lock); + + return ret; } static long hidraw_ioctl(struct file *file, unsigned int cmd, @@ -506,7 +529,21 @@ EXPORT_SYMBOL_GPL(hidraw_connect); void hidraw_disconnect(struct hid_device *hid) { struct hidraw *hidraw = hid->hidraw; - drop_ref(hidraw, 1); + + mutex_lock(&minors_lock); + hidraw->exist = 0; + + device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); + + hidraw_table[hidraw->minor] = NULL; + + if (hidraw->open) { + hid_hw_close(hid); + wake_up_interruptible(&hidraw->wait); + } else { + kfree(hidraw); + } + mutex_unlock(&minors_lock); } EXPORT_SYMBOL_GPL(hidraw_disconnect); @@ -555,23 +592,3 @@ void hidraw_exit(void) unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); } - -static void drop_ref(struct hidraw *hidraw, int exists_bit) -{ - mutex_lock(&minors_lock); - if (exists_bit) { - hid_hw_close(hidraw->hid); - hidraw->exist = 0; - if (hidraw->open) - wake_up_interruptible(&hidraw->wait); - } else { - --hidraw->open; - } - - if (!hidraw->open && !hidraw->exist) { - device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); - hidraw_table[hidraw->minor] = NULL; - kfree(hidraw); - } - mutex_unlock(&minors_lock); -} diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index a227be47149..520e5bf4f76 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -32,7 +32,7 @@ * ASB100-A supports pwm1, while plain ASB100 does not. There is no known * way for the driver to tell which one is there. * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * asb100 7 3 1 4 0x31 0x0694 yes no */ diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 68ad7d25551..4f411040738 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -2,7 +2,7 @@ * fam15h_power.c - AMD Family 15h processor power monitoring * * Copyright (c) 2011 Advanced Micro Devices, Inc. - * Author: Andreas Herrmann <andreas.herrmann3@amd.com> + * Author: Andreas Herrmann <herrmann.der.user@googlemail.com> * * * This driver is free software; you can redistribute it and/or @@ -28,7 +28,7 @@ #include <asm/processor.h> MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); -MODULE_AUTHOR("Andreas Herrmann <andreas.herrmann3@amd.com>"); +MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>"); MODULE_LICENSE("GPL"); /* D18F3 */ diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 36509ae3208..1381a2e3bbd 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -630,7 +630,9 @@ static struct platform_driver gpio_fan_driver = { .driver = { .name = "gpio-fan", .pm = GPIO_FAN_PM, +#ifdef CONFIG_OF_GPIO .of_match_table = of_match_ptr(of_gpio_fan_match), +#endif }, }; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 1821b7423d5..de3c7e04c3b 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -2083,6 +2083,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) mutex_init(&data->lock); mutex_init(&data->update_lock); data->name = w83627ehf_device_names[sio_data->kind]; + data->bank = 0xff; /* Force initial bank selection */ platform_set_drvdata(pdev, data); /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 5b1a6a66644..af158990870 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -25,7 +25,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) * w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) * w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 5a5046d94c3..20f11d31da4 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -24,7 +24,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * as99127f 7 3 0 3 0x31 0x12c3 yes no * as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no * w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 39ab7bcc616..ed397c64519 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -22,7 +22,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83791d 10 5 5 3 0x71 0x5ca3 yes no * * The w83791d chip appears to be part way between the 83781d and the diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 053645279f3..301942d0845 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -31,7 +31,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83792d 9 7 7 3 0x7a 0x5ca3 yes no */ diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index f0e8286c3c7..79710bcac2f 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -20,7 +20,7 @@ /* * Supports following chips: * - * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no */ diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index beee6b2d361..1722f50f247 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o obj-y += algos/ busses/ muxes/ +obj-$(CONFIG_I2C_STUB) += i2c-stub.o ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG CFLAGS_i2c-core.o := -Wno-deprecated-declarations diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 65dd599a026..e9df4612b7e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -81,7 +81,6 @@ config I2C_I801 tristate "Intel 82801 (ICH/PCH)" depends on PCI select CHECK_SIGNATURE if X86 && DMI - select GPIOLIB if I2C_MUX help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 2d33d62952c..395b516ffa0 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -85,7 +85,6 @@ obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o -obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 37793156bd9..6abc00d5988 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -82,7 +82,8 @@ #include <linux/wait.h> #include <linux/err.h> -#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE +#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ + defined CONFIG_DMI #include <linux/gpio.h> #include <linux/i2c-mux-gpio.h> #include <linux/platform_device.h> @@ -192,7 +193,8 @@ struct i801_priv { int len; u8 *data; -#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE +#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ + defined CONFIG_DMI const struct i801_mux_config *mux_drvdata; struct platform_device *mux_pdev; #endif @@ -921,7 +923,8 @@ static void __init input_apanel_init(void) {} static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {} #endif /* CONFIG_X86 && CONFIG_DMI */ -#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE +#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ + defined CONFIG_DMI static struct i801_mux_config i801_mux_config_asus_z8_d12 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03 }, @@ -1059,7 +1062,7 @@ static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv) id = dmi_first_match(mux_dmi_table); if (id) { - /* Remove from branch classes from trunk */ + /* Remove branch classes from trunk */ mux_config = id->driver_data; for (i = 0; i < mux_config->n_values; i++) class &= ~mux_config->classes[i]; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 2ef162d148c..b9734747d61 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -52,8 +52,6 @@ #include <linux/of_device.h> #include <linux/of_i2c.h> #include <linux/pinctrl/consumer.h> - -#include <mach/hardware.h> #include <linux/platform_data/i2c-imx.h> /** Defines ******************************************************************** @@ -115,6 +113,11 @@ static u16 __initdata i2c_clk_div[50][2] = { { 3072, 0x1E }, { 3840, 0x1F } }; +enum imx_i2c_type { + IMX1_I2C, + IMX21_I2C, +}; + struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; @@ -124,13 +127,33 @@ struct imx_i2c_struct { unsigned int disable_delay; int stopped; unsigned int ifdr; /* IMX_I2C_IFDR */ + enum imx_i2c_type devtype; +}; + +static struct platform_device_id imx_i2c_devtype[] = { + { + .name = "imx1-i2c", + .driver_data = IMX1_I2C, + }, { + .name = "imx21-i2c", + .driver_data = IMX21_I2C, + }, { + /* sentinel */ + } }; +MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); static const struct of_device_id i2c_imx_dt_ids[] = { - { .compatible = "fsl,imx1-i2c", }, + { .compatible = "fsl,imx1-i2c", .data = &imx_i2c_devtype[IMX1_I2C], }, + { .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], }, { /* sentinel */ } }; +static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) +{ + return i2c_imx->devtype == IMX1_I2C; +} + /** Functions for IMX I2C adapter driver *************************************** *******************************************************************************/ @@ -223,7 +246,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, i2c_imx->base + IMX_I2C_I2CR); } - if (cpu_is_mx1()) { + if (is_imx1_i2c(i2c_imx)) { /* * This delay caused by an i.MXL hardware bug. * If no (or too short) delay, no "STOP" bit will be generated. @@ -465,6 +488,8 @@ static struct i2c_algorithm i2c_imx_algo = { static int __init i2c_imx_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids, + &pdev->dev); struct imx_i2c_struct *i2c_imx; struct resource *res; struct imxi2c_platform_data *pdata = pdev->dev.platform_data; @@ -497,6 +522,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev) return -ENOMEM; } + if (of_id) + pdev->id_entry = of_id->data; + i2c_imx->devtype = pdev->id_entry->driver_data; + /* Setup i2c_imx driver structure */ strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name)); i2c_imx->adapter.owner = THIS_MODULE; @@ -593,7 +622,8 @@ static struct platform_driver i2c_imx_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = i2c_imx_dt_ids, - } + }, + .id_table = imx_i2c_devtype, }; static int __init i2c_adap_imx_init(void) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 1f58197062c..286ca191782 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -1,7 +1,7 @@ /* * Freescale MXS I2C bus driver * - * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K. + * Copyright (C) 2011-2012 Wolfram Sang, Pengutronix e.K. * * based on a (non-working) driver which was: * @@ -35,10 +35,6 @@ #define DRIVER_NAME "mxs-i2c" -static bool use_pioqueue; -module_param(use_pioqueue, bool, 0); -MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA"); - #define MXS_I2C_CTRL0 (0x00) #define MXS_I2C_CTRL0_SET (0x04) @@ -75,23 +71,6 @@ MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA"); MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \ MXS_I2C_CTRL1_SLAVE_IRQ) -#define MXS_I2C_QUEUECTRL (0x60) -#define MXS_I2C_QUEUECTRL_SET (0x64) -#define MXS_I2C_QUEUECTRL_CLR (0x68) - -#define MXS_I2C_QUEUECTRL_QUEUE_RUN 0x20 -#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE 0x04 - -#define MXS_I2C_QUEUESTAT (0x70) -#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000 -#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F - -#define MXS_I2C_QUEUECMD (0x80) - -#define MXS_I2C_QUEUEDATA (0x90) - -#define MXS_I2C_DATA (0xa0) - #define MXS_CMD_I2C_SELECT (MXS_I2C_CTRL0_RETAIN_CLOCK | \ MXS_I2C_CTRL0_PRE_SEND_START | \ @@ -153,7 +132,6 @@ struct mxs_i2c_dev { const struct mxs_i2c_speed_config *speed; /* DMA support components */ - bool dma_mode; int dma_channel; struct dma_chan *dmach; struct mxs_dma_data dma_data; @@ -172,99 +150,6 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); - if (i2c->dma_mode) - writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, - i2c->regs + MXS_I2C_QUEUECTRL_CLR); - else - writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, - i2c->regs + MXS_I2C_QUEUECTRL_SET); -} - -static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len, - int flags) -{ - u32 data; - - writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD); - - data = (addr << 1) | I2C_SMBUS_READ; - writel(data, i2c->regs + MXS_I2C_DATA); - - data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags; - writel(data, i2c->regs + MXS_I2C_QUEUECMD); -} - -static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c, - u8 addr, u8 *buf, int len, int flags) -{ - u32 data; - int i, shifts_left; - - data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags; - writel(data, i2c->regs + MXS_I2C_QUEUECMD); - - /* - * We have to copy the slave address (u8) and buffer (arbitrary number - * of u8) into the data register (u32). To achieve that, the u8 are put - * into the MSBs of 'data' which is then shifted for the next u8. When - * appropriate, 'data' is written to MXS_I2C_DATA. So, the first u32 - * looks like this: - * - * 3 2 1 0 - * 10987654|32109876|54321098|76543210 - * --------+--------+--------+-------- - * buffer+2|buffer+1|buffer+0|slave_addr - */ - - data = ((addr << 1) | I2C_SMBUS_WRITE) << 24; - - for (i = 0; i < len; i++) { - data >>= 8; - data |= buf[i] << 24; - if ((i & 3) == 2) - writel(data, i2c->regs + MXS_I2C_DATA); - } - - /* Write out the remaining bytes if any */ - shifts_left = 24 - (i & 3) * 8; - if (shifts_left) - writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA); -} - -/* - * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the - * rd_threshold to 1). Couldn't get this to work, though. - */ -static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - - while (readl(i2c->regs + MXS_I2C_QUEUESTAT) - & MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - cond_resched(); - } - - return 0; -} - -static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len) -{ - u32 uninitialized_var(data); - int i; - - for (i = 0; i < len; i++) { - if ((i & 3) == 0) { - if (mxs_i2c_wait_for_data(i2c)) - return -ETIMEDOUT; - data = readl(i2c->regs + MXS_I2C_QUEUEDATA); - } - buf[i] = data & 0xff; - data >>= 8; - } - - return 0; } static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c) @@ -432,39 +317,17 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, init_completion(&i2c->cmd_complete); i2c->cmd_err = 0; - if (i2c->dma_mode) { - ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); - if (ret) - return ret; - } else { - if (msg->flags & I2C_M_RD) { - mxs_i2c_pioq_setup_read(i2c, msg->addr, - msg->len, flags); - } else { - mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, - msg->len, flags); - } - - writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, - i2c->regs + MXS_I2C_QUEUECTRL_SET); - } + ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); + if (ret) + return ret; ret = wait_for_completion_timeout(&i2c->cmd_complete, msecs_to_jiffies(1000)); if (ret == 0) goto timeout; - if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) { - ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len); - if (ret) - goto timeout; - } - if (i2c->cmd_err == -ENXIO) mxs_i2c_reset(i2c); - else - writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, - i2c->regs + MXS_I2C_QUEUECTRL_CLR); dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err); @@ -472,8 +335,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, timeout: dev_dbg(i2c->dev, "Timeout!\n"); - if (i2c->dma_mode) - mxs_i2c_dma_finish(i2c); + mxs_i2c_dma_finish(i2c); mxs_i2c_reset(i2c); return -ETIMEDOUT; } @@ -502,7 +364,6 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) { struct mxs_i2c_dev *i2c = dev_id; u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK; - bool is_last_cmd; if (!stat) return IRQ_NONE; @@ -515,14 +376,6 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */ i2c->cmd_err = -EIO; - if (!i2c->dma_mode) { - is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & - MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; - - if (is_last_cmd || i2c->cmd_err) - complete(&i2c->cmd_complete); - } - writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); return IRQ_HANDLED; @@ -556,23 +409,14 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) int ret; /* - * The MXS I2C DMA mode is prefered and enabled by default. - * The PIO mode is still supported, but should be used only - * for debuging purposes etc. - */ - i2c->dma_mode = !use_pioqueue; - if (!i2c->dma_mode) - dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n"); - - /* * TODO: This is a temporary solution and should be changed * to use generic DMA binding later when the helpers get in. */ ret = of_property_read_u32(node, "fsl,i2c-dma-channel", &i2c->dma_channel); if (ret) { - dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n"); - i2c->dma_mode = 0; + dev_err(dev, "Failed to get DMA channel!\n"); + return -ENODEV; } ret = of_property_read_u32(node, "clock-frequency", &speed); @@ -634,15 +478,13 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) } /* Setup the DMA */ - if (i2c->dma_mode) { - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - i2c->dma_data.chan_irq = dmairq; - i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c); - if (!i2c->dmach) { - dev_err(dev, "Failed to request dma\n"); - return -ENODEV; - } + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + i2c->dma_data.chan_irq = dmairq; + i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c); + if (!i2c->dmach) { + dev_err(dev, "Failed to request dma\n"); + return -ENODEV; } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 698d7acb0f0..02c3115a2df 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -644,7 +644,11 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, pm_runtime_get_sync(&dev->adev->dev); - clk_enable(dev->clk); + status = clk_prepare_enable(dev->clk); + if (status) { + dev_err(&dev->adev->dev, "can't prepare_enable clock\n"); + goto out_clk; + } status = init_hw(dev); if (status) @@ -671,7 +675,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, } out: - clk_disable(dev->clk); + clk_disable_unprepare(dev->clk); +out_clk: pm_runtime_put_sync(&dev->adev->dev); dev->busy = false; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index f981ac4e678..dcea77bf6f5 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -742,7 +742,7 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, i2c_dev->irq, - tegra_i2c_isr, 0, pdev->name, i2c_dev); + tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); return ret; diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/i2c-stub.c index b1b3447942c..d0a9c590c3c 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/i2c-stub.c @@ -2,7 +2,7 @@ i2c-stub.c - I2C/SMBus chip emulator Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com> - Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2007, 2012 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -51,8 +51,8 @@ struct stub_chip { static struct stub_chip *stub_chips; /* Return negative errno on error. */ -static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, union i2c_smbus_data * data) +static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, union i2c_smbus_data *data) { s32 ret; int i, len; @@ -78,14 +78,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_WRITE) { chip->pointer = command; - dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " - "wrote 0x%02x.\n", - addr, command); + dev_dbg(&adap->dev, + "smbus byte - addr 0x%02x, wrote 0x%02x.\n", + addr, command); } else { data->byte = chip->words[chip->pointer++] & 0xff; - dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " - "read 0x%02x.\n", - addr, data->byte); + dev_dbg(&adap->dev, + "smbus byte - addr 0x%02x, read 0x%02x.\n", + addr, data->byte); } ret = 0; @@ -95,14 +95,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, if (read_write == I2C_SMBUS_WRITE) { chip->words[command] &= 0xff00; chip->words[command] |= data->byte; - dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " - "wrote 0x%02x at 0x%02x.\n", - addr, data->byte, command); + dev_dbg(&adap->dev, + "smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n", + addr, data->byte, command); } else { data->byte = chip->words[command] & 0xff; - dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " - "read 0x%02x at 0x%02x.\n", - addr, data->byte, command); + dev_dbg(&adap->dev, + "smbus byte data - addr 0x%02x, read 0x%02x at 0x%02x.\n", + addr, data->byte, command); } chip->pointer = command + 1; @@ -112,14 +112,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_WRITE) { chip->words[command] = data->word; - dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, " - "wrote 0x%04x at 0x%02x.\n", - addr, data->word, command); + dev_dbg(&adap->dev, + "smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n", + addr, data->word, command); } else { data->word = chip->words[command]; - dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, " - "read 0x%04x at 0x%02x.\n", - addr, data->word, command); + dev_dbg(&adap->dev, + "smbus word data - addr 0x%02x, read 0x%04x at 0x%02x.\n", + addr, data->word, command); } ret = 0; @@ -132,17 +132,17 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, chip->words[command + i] &= 0xff00; chip->words[command + i] |= data->block[1 + i]; } - dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, " - "wrote %d bytes at 0x%02x.\n", - addr, len, command); + dev_dbg(&adap->dev, + "i2c block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n", + addr, len, command); } else { for (i = 0; i < len; i++) { data->block[1 + i] = chip->words[command + i] & 0xff; } - dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, " - "read %d bytes at 0x%02x.\n", - addr, len, command); + dev_dbg(&adap->dev, + "i2c block data - addr 0x%02x, read %d bytes at 0x%02x.\n", + addr, len, command); } ret = 0; @@ -179,25 +179,24 @@ static int __init i2c_stub_init(void) int i, ret; if (!chip_addr[0]) { - printk(KERN_ERR "i2c-stub: Please specify a chip address\n"); + pr_err("i2c-stub: Please specify a chip address\n"); return -ENODEV; } for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) { if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) { - printk(KERN_ERR "i2c-stub: Invalid chip address " - "0x%02x\n", chip_addr[i]); + pr_err("i2c-stub: Invalid chip address 0x%02x\n", + chip_addr[i]); return -EINVAL; } - printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", - chip_addr[i]); + pr_info("i2c-stub: Virtual chip at 0x%02x\n", chip_addr[i]); } /* Allocate memory for all chips at once */ stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL); if (!stub_chips) { - printk(KERN_ERR "i2c-stub: Out of memory\n"); + pr_err("i2c-stub: Out of memory\n"); return -ENOMEM; } @@ -219,4 +218,3 @@ MODULE_LICENSE("GPL"); module_init(i2c_stub_init); module_exit(i2c_stub_exit); - diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 5f097f309b9..7fa5b24b16d 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -169,7 +169,7 @@ static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev) mux->busses = devm_kzalloc(&pdev->dev, sizeof(mux->busses) * mux->pdata->bus_count, GFP_KERNEL); - if (!mux->states) { + if (!mux->busses) { dev_err(&pdev->dev, "Cannot allocate busses\n"); ret = -ENOMEM; goto err; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b4b65af8612..de0874054e9 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -335,6 +335,7 @@ config KEYBOARD_LOCOMO config KEYBOARD_LPC32XX tristate "LPC32XX matrix key scanner support" depends on ARCH_LPC32XX && OF + select INPUT_MATRIXKMAP help Say Y here if you want to use NXP LPC32XX SoC key scanner interface, connected to a key matrix. diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 803ff6fe021..cad9d5dd597 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -368,6 +368,9 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) unsigned int mask = 0, direct_key_num = 0; unsigned long kpc = 0; + /* clear pending interrupt bit */ + keypad_readl(KPC); + /* enable matrix keys with automatic scan */ if (pdata->matrix_key_rows && pdata->matrix_key_cols) { kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL; diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 02ca8680ea5..6f7d9901303 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -311,7 +311,6 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateInitWait: @@ -350,6 +349,10 @@ InitWait: break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 3a78f235fa3..2baff1b79a5 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -84,6 +84,10 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262 #define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263 #define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264 +/* MacbookPro10,2 (unibody, October 2012) */ +#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259 +#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a +#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -137,6 +141,10 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS), + /* MacbookPro10,2 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS), /* Terminating entry */ {} }; @@ -379,6 +387,19 @@ static const struct bcm5974_config bcm5974_config_table[] = { { SN_COORD, -150, 6730 }, { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { SN_PRESSURE, 0, 300 }, + { SN_WIDTH, 0, 2048 }, + { SN_COORD, -4750, 5280 }, + { SN_COORD, -150, 6730 }, + { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } + }, {} }; diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 2c1e12bf2ab..858ad446de9 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -391,7 +391,7 @@ static int wacom_parse_hid(struct usb_interface *intf, features->pktlen = WACOM_PKGLEN_TPC2FG; } - if (features->type == MTSCREEN || WACOM_24HDT) + if (features->type == MTSCREEN || features->type == WACOM_24HDT) features->pktlen = WACOM_PKGLEN_MTOUCH; if (features->type == BAMBOO_PT) { diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index aa601013117..0a67031ffc1 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1518,6 +1518,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); + + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + wacom_setup_cintiq(wacom_wac); break; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1ba232cbc09..f7668b24c37 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -239,7 +239,7 @@ config TOUCHSCREEN_EETI config TOUCHSCREEN_EGALAX tristate "EETI eGalax multi-touch panel support" - depends on I2C + depends on I2C && OF help Say Y here to enable support for I2C connected EETI eGalax multi-touch panels. diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index c1e3460f119..13fa62fdfb0 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/bitops.h> #include <linux/input/mt.h> +#include <linux/of_gpio.h> /* * Mouse Mode: some panel may configure the controller to mouse mode, @@ -122,9 +123,17 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) /* wake up controller by an falling edge of interrupt gpio. */ static int egalax_wake_up_device(struct i2c_client *client) { - int gpio = irq_to_gpio(client->irq); + struct device_node *np = client->dev.of_node; + int gpio; int ret; + if (!np) + return -ENODEV; + + gpio = of_get_named_gpio(np, "wakeup-gpios", 0); + if (!gpio_is_valid(gpio)) + return -ENODEV; + ret = gpio_request(gpio, "egalax_irq"); if (ret < 0) { dev_err(&client->dev, @@ -181,7 +190,11 @@ static int __devinit egalax_ts_probe(struct i2c_client *client, ts->input_dev = input_dev; /* controller may be in sleep, wake it up. */ - egalax_wake_up_device(client); + error = egalax_wake_up_device(client); + if (error) { + dev_err(&client->dev, "Failed to wake up the controller\n"); + goto err_free_dev; + } ret = egalax_firmware_version(client); if (ret < 0) { @@ -274,11 +287,17 @@ static int egalax_ts_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); +static struct of_device_id egalax_ts_dt_ids[] = { + { .compatible = "eeti,egalax_ts" }, + { /* sentinel */ } +}; + static struct i2c_driver egalax_ts_driver = { .driver = { .name = "egalax_ts", .owner = THIS_MODULE, .pm = &egalax_ts_pm_ops, + .of_match_table = of_match_ptr(egalax_ts_dt_ids), }, .id_table = egalax_ts_id, .probe = egalax_ts_probe, diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c index 63209aaa55f..eb96f168fb9 100644 --- a/drivers/input/touchscreen/tsc40.c +++ b/drivers/input/touchscreen/tsc40.c @@ -107,7 +107,6 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv) __set_bit(BTN_TOUCH, input_dev->keybit); input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0); input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0); - input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0); serio_set_drvdata(serio, ptsc); diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index a649f146d17..41678639b7e 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -34,13 +34,11 @@ #include <linux/of_iommu.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/tegra-ahb.h> #include <asm/page.h> #include <asm/cacheflush.h> -#include <mach/iomap.h> -#include <mach/tegra-ahb.h> - enum smmu_hwgrp { HWGRP_AFI, HWGRP_AVPC, diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index dc670ccc697..16c78f1c5ef 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -168,7 +168,8 @@ static int __init armctrl_of_init(struct device_node *node, } static struct of_device_id irq_of_match[] __initconst = { - { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init } + { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init }, + { } }; void __init bcm2835_init_irq(void) diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index a233ed53913..86cd75a0e84 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -4,7 +4,7 @@ menuconfig ISDN bool "ISDN support" - depends on NET + depends on NET && NETDEVICES depends on !S390 && !UML ---help--- ISDN ("Integrated Services Digital Network", called RNIS in France) diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index 2302fbe70ac..9c6650ea848 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -6,7 +6,7 @@ if ISDN_I4L config ISDN_PPP bool "Support synchronous PPP" - depends on INET && NETDEVICES + depends on INET select SLHC help Over digital connections such as ISDN, there is no need to diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 8c610fa6782..e2a945ee9f0 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1312,7 +1312,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) } else return -EINVAL; break; -#ifdef CONFIG_NETDEVICES case IIOCNETGPN: /* Get peer phone number of a connected * isdn network interface */ @@ -1322,7 +1321,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) return isdn_net_getpeer(&phone, argp); } else return -EINVAL; -#endif default: return -EINVAL; } @@ -1352,7 +1350,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) case IIOCNETLCR: printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); return -ENODEV; -#ifdef CONFIG_NETDEVICES case IIOCNETAIF: /* Add a network-interface */ if (arg) { @@ -1491,7 +1488,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) return -EFAULT; return isdn_net_force_hangup(name); break; -#endif /* CONFIG_NETDEVICES */ case IIOCSETVER: dev->net_verbose = arg; printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index f508defc0d9..b58bc8a14b9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -379,7 +379,9 @@ config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" depends on LEDS_CLASS depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || \ - MACH_NETSPACE_MAX_V2 || MACH_D2NET_V2 + MACH_NETSPACE_MAX_V2 || MACH_D2NET_V2 || \ + MACH_NETSPACE_V2_DT || MACH_INETSPACE_V2_DT || \ + MACH_NETSPACE_MAX_V2_DT || MACH_NETSPACE_MINI_V2_DT default y help This option enable support for the dual-GPIO LED found on the diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index d176ec83f5d..d64cc2227fd 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -30,6 +30,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/platform_data/leds-kirkwood-ns2.h> +#include <linux/of_gpio.h> /* * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in @@ -263,6 +264,62 @@ static void delete_ns2_led(struct ns2_led_data *led_dat) gpio_free(led_dat->slow); } +#ifdef CONFIG_OF_GPIO +/* + * Translate OpenFirmware node properties into platform_data. + */ +static int __devinit +ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + struct device_node *child; + struct ns2_led *leds; + int num_leds = 0; + int i = 0; + + num_leds = of_get_child_count(np); + if (!num_leds) + return -ENODEV; + + leds = devm_kzalloc(dev, num_leds * sizeof(struct ns2_led), + GFP_KERNEL); + if (!leds) + return -ENOMEM; + + for_each_child_of_node(np, child) { + const char *string; + int ret; + + ret = of_get_named_gpio(child, "cmd-gpio", 0); + if (ret < 0) + return ret; + leds[i].cmd = ret; + ret = of_get_named_gpio(child, "slow-gpio", 0); + if (ret < 0) + return ret; + leds[i].slow = ret; + ret = of_property_read_string(child, "label", &string); + leds[i].name = (ret == 0) ? string : child->name; + ret = of_property_read_string(child, "linux,default-trigger", + &string); + if (ret == 0) + leds[i].default_trigger = string; + + i++; + } + + pdata->leds = leds; + pdata->num_leds = num_leds; + + return 0; +} + +static const struct of_device_id of_ns2_leds_match[] = { + { .compatible = "lacie,ns2-leds", }, + {}, +}; +#endif /* CONFIG_OF_GPIO */ + static int __devinit ns2_led_probe(struct platform_device *pdev) { struct ns2_led_platform_data *pdata = pdev->dev.platform_data; @@ -270,11 +327,25 @@ static int __devinit ns2_led_probe(struct platform_device *pdev) int i; int ret; +#ifdef CONFIG_OF_GPIO + if (!pdata) { + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct ns2_led_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = ns2_leds_get_of_pdata(&pdev->dev, pdata); + if (ret) + return ret; + } +#else if (!pdata) return -EINVAL; +#endif /* CONFIG_OF_GPIO */ leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) * - pdata->num_leds, GFP_KERNEL); + pdata->num_leds, GFP_KERNEL); if (!leds_data) return -ENOMEM; @@ -312,8 +383,9 @@ static struct platform_driver ns2_led_driver = { .probe = ns2_led_probe, .remove = __devexit_p(ns2_led_remove), .driver = { - .name = "leds-ns2", - .owner = THIS_MODULE, + .name = "leds-ns2", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_ns2_leds_match), }, }; diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c index b312056da14..4239b3955ff 100644 --- a/drivers/leds/ledtrig-cpu.c +++ b/drivers/leds/ledtrig-cpu.c @@ -33,8 +33,6 @@ struct led_trigger_cpu { char name[MAX_NAME_LEN]; struct led_trigger *_trig; - struct mutex lock; - int lock_is_inited; }; static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig); @@ -50,12 +48,6 @@ void ledtrig_cpu(enum cpu_led_event ledevt) { struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); - /* mutex lock should be initialized before calling mutex_call() */ - if (!trig->lock_is_inited) - return; - - mutex_lock(&trig->lock); - /* Locate the correct CPU LED */ switch (ledevt) { case CPU_LED_IDLE_END: @@ -75,8 +67,6 @@ void ledtrig_cpu(enum cpu_led_event ledevt) /* Will leave the LED as it is */ break; } - - mutex_unlock(&trig->lock); } EXPORT_SYMBOL(ledtrig_cpu); @@ -117,14 +107,9 @@ static int __init ledtrig_cpu_init(void) for_each_possible_cpu(cpu) { struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); - mutex_init(&trig->lock); - snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); - mutex_lock(&trig->lock); led_trigger_register_simple(trig->name, &trig->_trig); - trig->lock_is_inited = 1; - mutex_unlock(&trig->lock); } register_syscore_ops(&ledtrig_cpu_syscore_ops); @@ -142,15 +127,9 @@ static void __exit ledtrig_cpu_exit(void) for_each_possible_cpu(cpu) { struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); - mutex_lock(&trig->lock); - led_trigger_unregister_simple(trig->_trig); trig->_trig = NULL; memset(trig->name, 0, MAX_NAME_LEN); - trig->lock_is_inited = 0; - - mutex_unlock(&trig->lock); - mutex_destroy(&trig->lock); } unregister_syscore_ops(&ledtrig_cpu_syscore_ops); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 45135f69509..5e7dc772f5d 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -315,8 +315,11 @@ static int run(struct mddev *mddev) } conf->nfaults = 0; - rdev_for_each(rdev, mddev) + rdev_for_each(rdev, mddev) { conf->rdev = rdev; + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); + } md_set_array_sectors(mddev, faulty_size(mddev, 0, 0)); mddev->private = conf; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 8034fbd6190..636bae0405e 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2710,7 +2710,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) || disk_idx < 0) continue; if (test_bit(Replacement, &rdev->flags)) - disk = conf->mirrors + conf->raid_disks + disk_idx; + disk = conf->mirrors + mddev->raid_disks + disk_idx; else disk = conf->mirrors + disk_idx; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 906ccbd0f7d..d1295aff417 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1783,7 +1783,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) clear_bit(Unmerged, &rdev->flags); } md_integrity_add_rdev(rdev, mddev); - if (blk_queue_discard(bdev_get_queue(rdev->bdev))) + if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev))) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); print_conf(conf); @@ -3613,11 +3613,14 @@ static int run(struct mddev *mddev) discard_supported = true; } - if (discard_supported) - queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); - else - queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); - + if (mddev->queue) { + if (discard_supported) + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, + mddev->queue); + else + queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, + mddev->queue); + } /* need to check that every block has at least one working mirror */ if (!enough(conf, -1)) { printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n", diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index a3b1a34c896..4b1becc86e5 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -45,8 +45,8 @@ #include <media/v4l2-ioctl.h> #include <plat/cpu.h> -#include <plat/dma.h> -#include <plat/vrfb.h> +#include <plat-omap/dma-omap.h> +#include <video/omapvrfb.h> #include <video/omapdss.h> #include "omap_voutlib.h" diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 4be26abf6ce..8340445a0ee 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -16,12 +16,14 @@ #include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> -#include <plat/dma.h> -#include <plat/vrfb.h> +#include <plat-omap/dma-omap.h> +#include <video/omapvrfb.h> #include "omap_voutdef.h" #include "omap_voutlib.h" +#define OMAP_DMA_NO_DEVICE 0 + /* * Function for allocating video buffers */ diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h index 27a95d23b91..9ccfe1f475a 100644 --- a/drivers/media/platform/omap/omap_voutdef.h +++ b/drivers/media/platform/omap/omap_voutdef.h @@ -12,7 +12,7 @@ #define OMAP_VOUTDEF_H #include <video/omapdss.h> -#include <plat/vrfb.h> +#include <video/omapvrfb.h> #define YUYV_BPP 2 #define RGB565_BPP 2 diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index d1a8dee5e1c..e7f9c4292cc 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -34,6 +34,8 @@ #include "ispreg.h" #include "isphist.h" +#define OMAP24XX_DMA_NO_DEVICE 0 + #define HIST_CONFIG_DMA 1 #define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0) diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index a6fe653eb23..40f87cdd799 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -30,7 +30,7 @@ #include <linux/types.h> #include <linux/omap3isp.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include <media/v4l2-event.h> #include "isp.h" diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index a0b737fecf1..5bd40e6870c 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -36,7 +36,6 @@ #include <media/v4l2-ioctl.h> #include <plat/iommu.h> #include <plat/iovmm.h> -#include <plat/omap-pm.h> #include "ispvideo.h" #include "isp.h" diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 9fd9d1c5b21..e575ae82771 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -41,7 +41,6 @@ #include <linux/videodev2.h> #include <linux/platform_data/camera-mx2.h> -#include <mach/hardware.h> #include <asm/dma.h> @@ -121,11 +120,13 @@ #define CSICR1 0x00 #define CSICR2 0x04 -#define CSISR (cpu_is_mx27() ? 0x08 : 0x18) +#define CSISR_IMX25 0x18 +#define CSISR_IMX27 0x08 #define CSISTATFIFO 0x0c #define CSIRFIFO 0x10 #define CSIRXCNT 0x14 -#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08) +#define CSICR3_IMX25 0x08 +#define CSICR3_IMX27 0x1c #define CSIDMASA_STATFIFO 0x20 #define CSIDMATA_STATFIFO 0x24 #define CSIDMASA_FB1 0x28 @@ -268,6 +269,11 @@ struct mx2_buffer { struct mx2_buf_internal internal; }; +enum mx2_camera_type { + IMX25_CAMERA, + IMX27_CAMERA, +}; + struct mx2_camera_dev { struct device *dev; struct soc_camera_host soc_host; @@ -291,6 +297,9 @@ struct mx2_camera_dev { struct mx2_buffer *fb2_active; u32 csicr1; + u32 reg_csisr; + u32 reg_csicr3; + enum mx2_camera_type devtype; struct mx2_buf_internal buf_discard[2]; void *discard_buffer; @@ -303,6 +312,29 @@ struct mx2_camera_dev { struct vb2_alloc_ctx *alloc_ctx; }; +static struct platform_device_id mx2_camera_devtype[] = { + { + .name = "imx25-camera", + .driver_data = IMX25_CAMERA, + }, { + .name = "imx27-camera", + .driver_data = IMX27_CAMERA, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mx2_camera_devtype); + +static inline int is_imx25_camera(struct mx2_camera_dev *pcdev) +{ + return pcdev->devtype == IMX25_CAMERA; +} + +static inline int is_imx27_camera(struct mx2_camera_dev *pcdev) +{ + return pcdev->devtype == IMX27_CAMERA; +} + static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) { return container_of(int_buf, struct mx2_buffer, internal); @@ -434,9 +466,9 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) clk_disable_unprepare(pcdev->clk_csi); writel(0, pcdev->base_csi + CSICR1); - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { writel(0, pcdev->base_emma + PRP_CNTL); - } else if (cpu_is_mx25()) { + } else if (is_imx25_camera(pcdev)) { spin_lock_irqsave(&pcdev->lock, flags); pcdev->fb1_active = NULL; pcdev->fb2_active = NULL; @@ -466,7 +498,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) csicr1 = CSICR1_MCLKEN; - if (cpu_is_mx27()) + if (is_imx27_camera(pcdev)) csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | CSICR1_RXFF_LEVEL(0); @@ -542,7 +574,7 @@ out: static irqreturn_t mx25_camera_irq(int irq_csi, void *data) { struct mx2_camera_dev *pcdev = data; - u32 status = readl(pcdev->base_csi + CSISR); + u32 status = readl(pcdev->base_csi + pcdev->reg_csisr); if (status & CSISR_DMA_TSF_FB1_INT) mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE); @@ -551,7 +583,7 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data) /* FIXME: handle CSISR_RFF_OR_INT */ - writel(status, pcdev->base_csi + CSISR); + writel(status, pcdev->base_csi + pcdev->reg_csisr); return IRQ_HANDLED; } @@ -636,7 +668,7 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb) buf->state = MX2_STATE_QUEUED; list_add_tail(&buf->internal.queue, &pcdev->capture); - if (cpu_is_mx25()) { + if (is_imx25_camera(pcdev)) { u32 csicr3, dma_inten = 0; if (pcdev->fb1_active == NULL) { @@ -655,20 +687,20 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb) list_del(&buf->internal.queue); buf->state = MX2_STATE_ACTIVE; - csicr3 = readl(pcdev->base_csi + CSICR3); + csicr3 = readl(pcdev->base_csi + pcdev->reg_csicr3); /* Reflash DMA */ writel(csicr3 | CSICR3_DMA_REFLASH_RFF, - pcdev->base_csi + CSICR3); + pcdev->base_csi + pcdev->reg_csicr3); /* clear & enable interrupts */ - writel(dma_inten, pcdev->base_csi + CSISR); + writel(dma_inten, pcdev->base_csi + pcdev->reg_csisr); pcdev->csicr1 |= dma_inten; writel(pcdev->csicr1, pcdev->base_csi + CSICR1); /* enable DMA */ csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1); - writel(csicr3, pcdev->base_csi + CSICR3); + writel(csicr3, pcdev->base_csi + pcdev->reg_csicr3); } } @@ -712,7 +744,7 @@ static void mx2_videobuf_release(struct vb2_buffer *vb) */ spin_lock_irqsave(&pcdev->lock, flags); - if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { + if (is_imx25_camera(pcdev) && buf->state == MX2_STATE_ACTIVE) { if (pcdev->fb1_active == buf) { pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; writel(0, pcdev->base_csi + CSIDMASA_FB1); @@ -835,7 +867,7 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) unsigned long phys; int bytesperline; - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { unsigned long flags; if (count < 2) return -EINVAL; @@ -930,7 +962,7 @@ static int mx2_stop_streaming(struct vb2_queue *q) void *b; u32 cntl; - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { spin_lock_irqsave(&pcdev->lock, flags); cntl = readl(pcdev->base_emma + PRP_CNTL); @@ -1082,11 +1114,11 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) if (bytesperline < 0) return bytesperline; - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { ret = mx27_camera_emma_prp_reset(pcdev); if (ret) return ret; - } else if (cpu_is_mx25()) { + } else if (is_imx25_camera(pcdev)) { writel((bytesperline * icd->user_height) >> 2, pcdev->base_csi + CSIRXCNT); writel((bytesperline << 16) | icd->user_height, @@ -1392,7 +1424,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, /* FIXME: implement MX27 limits */ /* limit to MX25 hardware capabilities */ - if (cpu_is_mx25()) { + if (is_imx25_camera(pcdev)) { if (xlate->host_fmt->bits_per_sample <= 8) width_limit = 0xffff * 4; else @@ -1726,6 +1758,20 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) goto exit; } + pcdev->devtype = pdev->id_entry->driver_data; + switch (pcdev->devtype) { + case IMX25_CAMERA: + pcdev->reg_csisr = CSISR_IMX25; + pcdev->reg_csicr3 = CSICR3_IMX25; + break; + case IMX27_CAMERA: + pcdev->reg_csisr = CSISR_IMX27; + pcdev->reg_csicr3 = CSICR3_IMX27; + break; + default: + break; + } + pcdev->clk_csi = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(pcdev->clk_csi)) { dev_err(&pdev->dev, "Could not get csi clock\n"); @@ -1763,7 +1809,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) pcdev->dev = &pdev->dev; platform_set_drvdata(pdev, pcdev); - if (cpu_is_mx25()) { + if (is_imx25_camera(pcdev)) { err = devm_request_irq(&pdev->dev, irq_csi, mx25_camera_irq, 0, MX2_CAM_DRV_NAME, pcdev); if (err) { @@ -1772,7 +1818,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) } } - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { err = mx27_camera_emma_init(pdev); if (err) goto exit; @@ -1789,7 +1835,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) pcdev->soc_host.priv = pcdev; pcdev->soc_host.v4l2_dev.dev = &pdev->dev; pcdev->soc_host.nr = pdev->id; - if (cpu_is_mx25()) + if (is_imx25_camera(pcdev)) pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE; pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); @@ -1809,7 +1855,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) exit_free_emma: vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); eallocctx: - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { clk_disable_unprepare(pcdev->clk_emma_ipg); clk_disable_unprepare(pcdev->clk_emma_ahb); } @@ -1827,7 +1873,7 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev) vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); - if (cpu_is_mx27()) { + if (is_imx27_camera(pcdev)) { clk_disable_unprepare(pcdev->clk_emma_ipg); clk_disable_unprepare(pcdev->clk_emma_ahb); } @@ -1841,6 +1887,7 @@ static struct platform_driver mx2_camera_driver = { .driver = { .name = MX2_CAM_DRV_NAME, }, + .id_table = mx2_camera_devtype, .remove = __devexit_p(mx2_camera_remove), }; diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 3557ac97e43..64d39b1b558 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -17,6 +17,7 @@ #include <linux/vmalloc.h> #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/dma/ipu-dma.h> #include <media/v4l2-common.h> #include <media/v4l2-dev.h> @@ -24,7 +25,6 @@ #include <media/soc_camera.h> #include <media/soc_mediabus.h> -#include <mach/ipu.h> #include <linux/platform_data/camera-mx3.h> #include <linux/platform_data/dma-imx.h> diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index fa08c7695cc..cae9ce6275e 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -34,12 +34,13 @@ #include <media/videobuf-dma-contig.h> #include <media/videobuf-dma-sg.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #define DRIVER_NAME "omap1-camera" #define DRIVER_VERSION "0.0.2" +#define OMAP_DMA_CAMERA_IF_RX 20 /* * --------------------------------------------------------------------------- diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index 546199e9ccc..82e6c1e282d 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -28,7 +28,6 @@ #include <plat/dmtimer.h> #include <plat/clock.h> -#include <plat/omap-pm.h> #include <media/lirc.h> #include <media/lirc_dev.h> diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 55d58998141..998ce8cb306 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -41,11 +41,11 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/slab.h> +#include <linux/mfd/menelaus.h> #include <asm/mach/irq.h> #include <asm/gpio.h> -#include <plat/menelaus.h> #define DRIVER_NAME "menelaus" diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 23cec57c02b..cebfe0a68aa 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -26,9 +26,12 @@ #include <linux/spinlock.h> #include <linux/gpio.h> #include <plat/cpu.h> -#include <plat/usb.h> +#include <linux/platform_device.h> +#include <linux/platform_data/usb-omap.h> #include <linux/pm_runtime.h> +#include "omap-usb.h" + #define USBHS_DRIVER_NAME "usbhs_omap" #define OMAP_EHCI_DEVICE "ehci-omap" #define OMAP_OHCI_DEVICE "ohci-omap3" diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 4b7757b8430..0db0dfa3d08 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -25,8 +25,8 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/err.h> -#include <plat/usb.h> #include <linux/pm_runtime.h> +#include <linux/platform_data/usb-omap.h> #define USBTLL_DRIVER_NAME "usbhs_tll" diff --git a/drivers/mfd/omap-usb.h b/drivers/mfd/omap-usb.h new file mode 100644 index 00000000000..972aa961b06 --- /dev/null +++ b/drivers/mfd/omap-usb.h @@ -0,0 +1,2 @@ +extern int omap_tll_enable(void); +extern int omap_tll_disable(void); diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 660bbc52886..4d50da61816 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -208,7 +208,7 @@ static unsigned long exynos5250_dwmmc_caps[4] = { MMC_CAP_CMD23, }; -static struct dw_mci_drv_data exynos5250_drv_data = { +static const struct dw_mci_drv_data exynos5250_drv_data = { .caps = exynos5250_dwmmc_caps, .init = dw_mci_exynos_priv_init, .setup_clock = dw_mci_exynos_setup_clock, @@ -220,14 +220,14 @@ static struct dw_mci_drv_data exynos5250_drv_data = { static const struct of_device_id dw_mci_exynos_match[] = { { .compatible = "samsung,exynos5250-dw-mshc", - .data = (void *)&exynos5250_drv_data, }, + .data = &exynos5250_drv_data, }, {}, }; -MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); +MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); int dw_mci_exynos_probe(struct platform_device *pdev) { - struct dw_mci_drv_data *drv_data; + const struct dw_mci_drv_data *drv_data; const struct of_device_id *match; match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node); diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index c960ca7ffbe..917936bee5d 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -24,7 +24,7 @@ #include "dw_mmc.h" int dw_mci_pltfm_register(struct platform_device *pdev, - struct dw_mci_drv_data *drv_data) + const struct dw_mci_drv_data *drv_data) { struct dw_mci *host; struct resource *regs; @@ -50,8 +50,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev, if (!host->regs) return -ENOMEM; - if (host->drv_data->init) { - ret = host->drv_data->init(host); + if (drv_data && drv_data->init) { + ret = drv_data->init(host); if (ret) return ret; } diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h index 301f24541fc..2ac37b81de4 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.h +++ b/drivers/mmc/host/dw_mmc-pltfm.h @@ -13,7 +13,7 @@ #define _DW_MMC_PLTFM_H_ extern int dw_mci_pltfm_register(struct platform_device *pdev, - struct dw_mci_drv_data *drv_data); + const struct dw_mci_drv_data *drv_data); extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev); extern const struct dev_pm_ops dw_mci_pltfm_pmops; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c2828f35c3b..c0667c8af2b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -232,6 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) { struct mmc_data *data; struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 cmdr; cmd->error = -EINPROGRESS; @@ -261,8 +262,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) cmdr |= SDMMC_CMD_DAT_WR; } - if (slot->host->drv_data->prepare_command) - slot->host->drv_data->prepare_command(slot->host, &cmdr); + if (drv_data && drv_data->prepare_command) + drv_data->prepare_command(slot->host, &cmdr); return cmdr; } @@ -434,7 +435,7 @@ static int dw_mci_idmac_init(struct dw_mci *host) return 0; } -static struct dw_mci_dma_ops dw_mci_idmac_ops = { +static const struct dw_mci_dma_ops dw_mci_idmac_ops = { .init = dw_mci_idmac_init, .start = dw_mci_idmac_start_dma, .stop = dw_mci_idmac_stop_dma, @@ -772,6 +773,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 regs; /* set default 1 bit mode */ @@ -807,8 +809,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) slot->clock = ios->clock; } - if (slot->host->drv_data->set_ios) - slot->host->drv_data->set_ios(slot->host, ios); + if (drv_data && drv_data->set_ios) + drv_data->set_ios(slot->host, ios); switch (ios->power_mode) { case MMC_POWER_UP: @@ -1815,6 +1817,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) { struct mmc_host *mmc; struct dw_mci_slot *slot; + struct dw_mci_drv_data *drv_data = host->drv_data; int ctrl_id, ret; u8 bus_width; @@ -1854,8 +1857,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) } else { ctrl_id = to_platform_device(host->dev)->id; } - if (host->drv_data && host->drv_data->caps) - mmc->caps |= host->drv_data->caps[ctrl_id]; + if (drv_data && drv_data->caps) + mmc->caps |= drv_data->caps[ctrl_id]; if (host->pdata->caps2) mmc->caps2 = host->pdata->caps2; @@ -1867,10 +1870,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) else bus_width = 1; - if (host->drv_data->setup_bus) { + if (drv_data && drv_data->setup_bus) { struct device_node *slot_np; slot_np = dw_mci_of_find_slot_node(host->dev, slot->id); - ret = host->drv_data->setup_bus(host, slot_np, bus_width); + ret = drv_data->setup_bus(host, slot_np, bus_width); if (ret) goto err_setup_bus; } @@ -1968,7 +1971,7 @@ static void dw_mci_init_dma(struct dw_mci *host) /* Determine which DMA interface to use */ #ifdef CONFIG_MMC_DW_IDMAC host->dma_ops = &dw_mci_idmac_ops; - dev_info(&host->dev, "Using internal DMA controller.\n"); + dev_info(host->dev, "Using internal DMA controller.\n"); #endif if (!host->dma_ops) @@ -2035,6 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) struct dw_mci_board *pdata; struct device *dev = host->dev; struct device_node *np = dev->of_node; + struct dw_mci_drv_data *drv_data = host->drv_data; int idx, ret; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -2062,8 +2066,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); - if (host->drv_data->parse_dt) { - ret = host->drv_data->parse_dt(host); + if (drv_data && drv_data->parse_dt) { + ret = drv_data->parse_dt(host); if (ret) return ERR_PTR(ret); } @@ -2080,6 +2084,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) int dw_mci_probe(struct dw_mci *host) { + struct dw_mci_drv_data *drv_data = host->drv_data; int width, i, ret = 0; u32 fifo_size; int init_slots = 0; @@ -2127,8 +2132,8 @@ int dw_mci_probe(struct dw_mci *host) else host->bus_hz = clk_get_rate(host->ciu_clk); - if (host->drv_data->setup_clock) { - ret = host->drv_data->setup_clock(host); + if (drv_data && drv_data->setup_clock) { + ret = drv_data->setup_clock(host); if (ret) { dev_err(host->dev, "implementation specific clock setup failed\n"); @@ -2228,6 +2233,21 @@ int dw_mci_probe(struct dw_mci *host) else host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; + /* + * Enable interrupts for command done, data over, data empty, card det, + * receive ready and error such as transmit, receive timeout, crc error + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | + SDMMC_INT_TXDR | SDMMC_INT_RXDR | + DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); + mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ + + dev_info(host->dev, "DW MMC controller at irq %d, " + "%d bit host data width, " + "%u deep fifo\n", + host->irq, width, fifo_size); + /* We need at least one slot to succeed */ for (i = 0; i < host->num_slots; i++) { ret = dw_mci_init_slot(host, i); @@ -2257,20 +2277,6 @@ int dw_mci_probe(struct dw_mci *host) else host->data_offset = DATA_240A_OFFSET; - /* - * Enable interrupts for command done, data over, data empty, card det, - * receive ready and error such as transmit, receive timeout, crc error - */ - mci_writel(host, RINTSTS, 0xFFFFFFFF); - mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | - SDMMC_INT_TXDR | SDMMC_INT_RXDR | - DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); - mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ - - dev_info(host->dev, "DW MMC controller at irq %d, " - "%d bit host data width, " - "%u deep fifo\n", - host->irq, width, fifo_size); if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 565c2e4fac7..477f63bad52 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -41,7 +41,6 @@ #include <linux/platform_data/mmc-mxcmmc.h> #include <linux/platform_data/dma-imx.h> -#include <mach/hardware.h> #define DRIVER_NAME "mxc-mmc" #define MXCMCI_TIMEOUT_MS 10000 @@ -113,6 +112,11 @@ #define INT_WRITE_OP_DONE_EN (1 << 1) #define INT_READ_OP_EN (1 << 0) +enum mxcmci_type { + IMX21_MMC, + IMX31_MMC, +}; + struct mxcmci_host { struct mmc_host *mmc; struct resource *res; @@ -153,7 +157,26 @@ struct mxcmci_host { struct imx_dma_data dma_data; struct timer_list watchdog; + enum mxcmci_type devtype; +}; + +static struct platform_device_id mxcmci_devtype[] = { + { + .name = "imx21-mmc", + .driver_data = IMX21_MMC, + }, { + .name = "imx31-mmc", + .driver_data = IMX31_MMC, + }, { + /* sentinel */ + } }; +MODULE_DEVICE_TABLE(platform, mxcmci_devtype); + +static inline int is_imx31_mmc(struct mxcmci_host *host) +{ + return host->devtype == IMX31_MMC; +} static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); @@ -843,6 +866,8 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) { + struct mxcmci_host *mxcmci = mmc_priv(host); + /* * MX3 SoCs have a silicon bug which corrupts CRC calculation of * multi-block transfers when connected SDIO peripheral doesn't @@ -850,7 +875,7 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) * One way to prevent this is to only allow 1-bit transfers. */ - if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO) + if (is_imx31_mmc(mxcmci) && card->type == MMC_TYPE_SDIO) host->caps &= ~MMC_CAP_4_BIT_DATA; else host->caps |= MMC_CAP_4_BIT_DATA; @@ -948,6 +973,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->mmc = mmc; host->pdata = pdev->dev.platform_data; + host->devtype = pdev->id_entry->driver_data; spin_lock_init(&host->lock); mxcmci_init_ocr(host); @@ -1120,6 +1146,7 @@ static const struct dev_pm_ops mxcmci_pm_ops = { static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, .remove = mxcmci_remove, + .id_table = mxcmci_devtype, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, @@ -1134,4 +1161,4 @@ module_platform_driver(mxcmci_driver); MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-mmc"); +MODULE_ALIAS("platform:mxc-mmc"); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 48ad361613e..ae115c01283 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -28,9 +28,8 @@ #include <linux/clk.h> #include <linux/scatterlist.h> #include <linux/slab.h> +#include <linux/platform_data/mmc-omap.h> -#include <plat/mmc.h> -#include <plat/dma.h> #define OMAP_MMC_REG_CMD 0x00 #define OMAP_MMC_REG_ARGL 0x01 @@ -72,6 +71,13 @@ #define OMAP_MMC_STAT_CARD_BUSY (1 << 2) #define OMAP_MMC_STAT_END_OF_CMD (1 << 0) +#define mmc_omap7xx() (host->features & MMC_OMAP7XX) +#define mmc_omap15xx() (host->features & MMC_OMAP15XX) +#define mmc_omap16xx() (host->features & MMC_OMAP16XX) +#define MMC_OMAP1_MASK (MMC_OMAP7XX | MMC_OMAP15XX | MMC_OMAP16XX) +#define mmc_omap1() (host->features & MMC_OMAP1_MASK) +#define mmc_omap2() (!mmc_omap1()) + #define OMAP_MMC_REG(host, reg) (OMAP_MMC_REG_##reg << (host)->reg_shift) #define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg)) #define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg)) @@ -84,6 +90,16 @@ #define OMAP_MMC_CMDTYPE_AC 2 #define OMAP_MMC_CMDTYPE_ADTC 3 +#define OMAP_DMA_MMC_TX 21 +#define OMAP_DMA_MMC_RX 22 +#define OMAP_DMA_MMC2_TX 54 +#define OMAP_DMA_MMC2_RX 55 + +#define OMAP24XX_DMA_MMC2_TX 47 +#define OMAP24XX_DMA_MMC2_RX 48 +#define OMAP24XX_DMA_MMC1_TX 61 +#define OMAP24XX_DMA_MMC1_RX 62 + #define DRIVER_NAME "mmci-omap" @@ -147,6 +163,7 @@ struct mmc_omap_host { u32 buffer_bytes_left; u32 total_bytes_left; + unsigned features; unsigned use_dma:1; unsigned brs_received:1, dma_done:1; unsigned dma_in_use:1; @@ -988,7 +1005,7 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) * blocksize is at least that large. Blocksize is * usually 512 bytes; but not for some SD reads. */ - burst = cpu_is_omap15xx() ? 32 : 64; + burst = mmc_omap15xx() ? 32 : 64; if (burst > data->blksz) burst = data->blksz; @@ -1104,8 +1121,7 @@ static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_on, if (slot->pdata->set_power != NULL) slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_on, vdd); - - if (cpu_is_omap24xx()) { + if (mmc_omap2()) { u16 w; if (power_on) { @@ -1239,7 +1255,7 @@ static int __devinit mmc_omap_new_slot(struct mmc_omap_host *host, int id) mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; - if (cpu_class_is_omap2()) + if (mmc_omap2()) mmc->f_max = 48000000; else mmc->f_max = 24000000; @@ -1359,6 +1375,7 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) init_waitqueue_head(&host->slot_wq); host->pdata = pdata; + host->features = host->pdata->slots[0].features; host->dev = &pdev->dev; platform_set_drvdata(pdev, host); @@ -1391,7 +1408,7 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) host->dma_tx_burst = -1; host->dma_rx_burst = -1; - if (cpu_is_omap24xx()) + if (mmc_omap2()) sig = host->id == 0 ? OMAP24XX_DMA_MMC1_TX : OMAP24XX_DMA_MMC2_TX; else sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX; @@ -1407,7 +1424,7 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n", sig); #endif - if (cpu_is_omap24xx()) + if (mmc_omap2()) sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX; else sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX; @@ -1435,7 +1452,7 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) } host->nr_slots = pdata->nr_slots; - host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); + host->reg_shift = (mmc_omap7xx() ? 1 : 2); host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); if (!host->mmc_omap_wq) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 54bfd0cc106..e7c185233b1 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -38,9 +38,7 @@ #include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> -#include <mach/hardware.h> -#include <plat/mmc.h> -#include <plat/cpu.h> +#include <linux/platform_data/mmc-omap.h> /* OMAP HSMMC Host Controller Registers */ #define OMAP_HSMMC_SYSSTATUS 0x0014 @@ -178,7 +176,8 @@ struct omap_hsmmc_host { static int omap_hsmmc_card_detect(struct device *dev, int slot) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + struct omap_mmc_platform_data *mmc = host->pdata; /* NOTE: assumes card detect signal is active-low */ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -186,7 +185,8 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot) static int omap_hsmmc_get_wp(struct device *dev, int slot) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + struct omap_mmc_platform_data *mmc = host->pdata; /* NOTE: assumes write protect signal is active-high */ return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); @@ -194,7 +194,8 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot) static int omap_hsmmc_get_cover_state(struct device *dev, int slot) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + struct omap_mmc_platform_data *mmc = host->pdata; /* NOTE: assumes card detect signal is active-low */ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -204,7 +205,8 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot) static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + struct omap_mmc_platform_data *mmc = host->pdata; disable_irq(mmc->slots[0].card_detect_irq); return 0; @@ -212,7 +214,8 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + struct omap_mmc_platform_data *mmc = host->pdata; enable_irq(mmc->slots[0].card_detect_irq); return 0; @@ -2009,9 +2012,9 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) clk_put(host->dbclk); } - mmc_free_host(host->mmc); + omap_hsmmc_gpio_free(host->pdata); iounmap(host->base); - omap_hsmmc_gpio_free(pdev->dev.platform_data); + mmc_free_host(host->mmc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 90140eb03e3..8fd50a21103 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/err.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/err.h> @@ -84,30 +85,32 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev) struct sdhci_dove_priv *priv; int ret; - ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata); - if (ret) - goto sdhci_dove_register_fail; - priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "unable to allocate private data"); - ret = -ENOMEM; - goto sdhci_dove_allocate_fail; + return -ENOMEM; } + priv->clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); + + ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata); + if (ret) + goto sdhci_dove_register_fail; + host = platform_get_drvdata(pdev); pltfm_host = sdhci_priv(host); pltfm_host->priv = priv; - priv->clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); return 0; -sdhci_dove_allocate_fail: - sdhci_pltfm_unregister(pdev); sdhci_dove_register_fail: + if (!IS_ERR(priv->clk)) { + clk_disable_unprepare(priv->clk); + clk_put(priv->clk); + } return ret; } @@ -117,14 +120,13 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_dove_priv *priv = pltfm_host->priv; - if (priv->clk) { - if (!IS_ERR(priv->clk)) { - clk_disable_unprepare(priv->clk); - clk_put(priv->clk); - } - devm_kfree(&pdev->dev, priv->clk); + sdhci_pltfm_unregister(pdev); + + if (!IS_ERR(priv->clk)) { + clk_disable_unprepare(priv->clk); + clk_put(priv->clk); } - return sdhci_pltfm_unregister(pdev); + return 0; } static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = { diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index ae5fcbfa1ee..63d219f57ca 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -169,6 +169,16 @@ static void esdhc_of_resume(struct sdhci_host *host) } #endif +static void esdhc_of_platform_init(struct sdhci_host *host) +{ + u32 vvn; + + vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); + vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; + if (vvn == VENDOR_V_22) + host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; +} + static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl, .read_w = esdhc_readw, @@ -180,6 +190,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .enable_dma = esdhc_of_enable_dma, .get_max_clock = esdhc_of_get_max_clock, .get_min_clock = esdhc_of_get_min_clock, + .platform_init = esdhc_of_platform_init, #ifdef CONFIG_PM .platform_suspend = esdhc_of_suspend, .platform_resume = esdhc_of_resume, diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 4bb74b042a0..04936f353ce 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1196,7 +1196,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( return ERR_PTR(-ENODEV); } - if (pci_resource_len(pdev, bar) != 0x100) { + if (pci_resource_len(pdev, bar) < 0x100) { dev_err(&pdev->dev, "Invalid iomem size. You may " "experience problems.\n"); } diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 65551a9709c..27164457f86 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -150,6 +150,13 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err_remap; } + /* + * Some platforms need to probe the controller to be able to + * determine which caps should be used. + */ + if (host->ops && host->ops->platform_init) + host->ops->platform_init(host); + platform_set_drvdata(pdev, host); return host; diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 2903949594c..a54dd5d7a5f 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -211,8 +211,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) if (ourhost->cur_clk != best_src) { struct clk *clk = ourhost->clk_bus[best_src]; - clk_enable(clk); - clk_disable(ourhost->clk_bus[ourhost->cur_clk]); + clk_prepare_enable(clk); + clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); /* turn clock off to card before changing clock source */ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); @@ -607,7 +607,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) } /* enable the local io clock and keep it running for the moment. */ - clk_enable(sc->clk_io); + clk_prepare_enable(sc->clk_io); for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) { struct clk *clk; @@ -638,7 +638,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) } #ifndef CONFIG_PM_RUNTIME - clk_enable(sc->clk_bus[sc->cur_clk]); + clk_prepare_enable(sc->clk_bus[sc->cur_clk]); #endif res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -747,13 +747,14 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) sdhci_s3c_setup_card_detect_gpio(sc); #ifdef CONFIG_PM_RUNTIME - clk_disable(sc->clk_io); + if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) + clk_disable_unprepare(sc->clk_io); #endif return 0; err_req_regs: #ifndef CONFIG_PM_RUNTIME - clk_disable(sc->clk_bus[sc->cur_clk]); + clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); #endif for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { if (sc->clk_bus[ptr]) { @@ -762,7 +763,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) } err_no_busclks: - clk_disable(sc->clk_io); + clk_disable_unprepare(sc->clk_io); clk_put(sc->clk_io); err_io_clk: @@ -794,7 +795,8 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) gpio_free(sc->ext_cd_gpio); #ifdef CONFIG_PM_RUNTIME - clk_enable(sc->clk_io); + if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) + clk_prepare_enable(sc->clk_io); #endif sdhci_remove_host(host, 1); @@ -802,14 +804,14 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); #ifndef CONFIG_PM_RUNTIME - clk_disable(sc->clk_bus[sc->cur_clk]); + clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); #endif for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { if (sc->clk_bus[ptr]) { clk_put(sc->clk_bus[ptr]); } } - clk_disable(sc->clk_io); + clk_disable_unprepare(sc->clk_io); clk_put(sc->clk_io); if (pdev->dev.of_node) { @@ -849,8 +851,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev) ret = sdhci_runtime_suspend_host(host); - clk_disable(ourhost->clk_bus[ourhost->cur_clk]); - clk_disable(busclk); + clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); + clk_disable_unprepare(busclk); return ret; } @@ -861,8 +863,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev) struct clk *busclk = ourhost->clk_io; int ret; - clk_enable(busclk); - clk_enable(ourhost->clk_bus[ourhost->cur_clk]); + clk_prepare_enable(busclk); + clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); ret = sdhci_runtime_resume_host(host); return ret; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7922adb4238..c7851c0aabc 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1315,16 +1315,19 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) */ if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { - /* eMMC uses cmd21 while sd and sdio use cmd19 */ - tuning_opcode = mmc->card->type == MMC_TYPE_MMC ? - MMC_SEND_TUNING_BLOCK_HS200 : - MMC_SEND_TUNING_BLOCK; - spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc, tuning_opcode); - spin_lock_irqsave(&host->lock, flags); - - /* Restore original mmc_request structure */ - host->mrq = mrq; + if (mmc->card) { + /* eMMC uses cmd21 but sd and sdio use cmd19 */ + tuning_opcode = + mmc->card->type == MMC_TYPE_MMC ? + MMC_SEND_TUNING_BLOCK_HS200 : + MMC_SEND_TUNING_BLOCK; + spin_unlock_irqrestore(&host->lock, flags); + sdhci_execute_tuning(mmc, tuning_opcode); + spin_lock_irqsave(&host->lock, flags); + + /* Restore original mmc_request structure */ + host->mrq = mrq; + } } if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) @@ -2837,6 +2840,9 @@ int sdhci_add_host(struct sdhci_host *host) if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) mmc->caps |= MMC_CAP_4_BIT_DATA; + if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23) + mmc->caps &= ~MMC_CAP_CMD23; + if (caps[0] & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; @@ -2846,9 +2852,12 @@ int sdhci_add_host(struct sdhci_host *host) /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc"); - if (IS_ERR(host->vqmmc)) { - pr_info("%s: no vqmmc regulator found\n", mmc_hostname(mmc)); - host->vqmmc = NULL; + if (IS_ERR_OR_NULL(host->vqmmc)) { + if (PTR_ERR(host->vqmmc) < 0) { + pr_info("%s: no vqmmc regulator found\n", + mmc_hostname(mmc)); + host->vqmmc = NULL; + } } else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000)) regulator_enable(host->vqmmc); @@ -2904,9 +2913,12 @@ int sdhci_add_host(struct sdhci_host *host) ocr_avail = 0; host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); - if (IS_ERR(host->vmmc)) { - pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); - host->vmmc = NULL; + if (IS_ERR_OR_NULL(host->vmmc)) { + if (PTR_ERR(host->vmmc) < 0) { + pr_info("%s: no vmmc regulator found\n", + mmc_hostname(mmc)); + host->vmmc = NULL; + } } else regulator_enable(host->vmmc); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 97653ea8942..71a4a7ed46c 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -278,6 +278,7 @@ struct sdhci_ops { void (*hw_reset)(struct sdhci_host *host); void (*platform_suspend)(struct sdhci_host *host); void (*platform_resume)(struct sdhci_host *host); + void (*platform_init)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 11d2bc3b51d..d25bc97dc5c 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1466,9 +1466,9 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); + clk_disable(host->hclk); mmc_free_host(host->mmc); pm_runtime_put_sync(&pdev->dev); - clk_disable(host->hclk); pm_runtime_disable(&pdev->dev); return 0; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 72e31d86030..022dcdc256f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -37,15 +37,9 @@ #include <asm/mach/flash.h> #include <linux/platform_data/mtd-mxc_nand.h> -#include <mach/hardware.h> #define DRIVER_NAME "mxc_nand" -#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) -#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2a() cpu_is_mx51() -#define nfc_is_v3_2b() cpu_is_mx53() - /* Addresses for NFC registers */ #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) #define NFC_V1_V2_BUF_ADDR (host->regs + 0x04) @@ -1283,6 +1277,53 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { .ppb_shift = 8, }; +static inline int is_imx21_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx21_nand_devtype_data; +} + +static inline int is_imx27_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx27_nand_devtype_data; +} + +static inline int is_imx25_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx25_nand_devtype_data; +} + +static inline int is_imx51_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx51_nand_devtype_data; +} + +static inline int is_imx53_nfc(struct mxc_nand_host *host) +{ + return host->devtype_data == &imx53_nand_devtype_data; +} + +static struct platform_device_id mxcnd_devtype[] = { + { + .name = "imx21-nand", + .driver_data = (kernel_ulong_t) &imx21_nand_devtype_data, + }, { + .name = "imx27-nand", + .driver_data = (kernel_ulong_t) &imx27_nand_devtype_data, + }, { + .name = "imx25-nand", + .driver_data = (kernel_ulong_t) &imx25_nand_devtype_data, + }, { + .name = "imx51-nand", + .driver_data = (kernel_ulong_t) &imx51_nand_devtype_data, + }, { + .name = "imx53-nand", + .driver_data = (kernel_ulong_t) &imx53_nand_devtype_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mxcnd_devtype); + #ifdef CONFIG_OF_MTD static const struct of_device_id mxcnd_dt_ids[] = { { @@ -1337,32 +1378,6 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host) } #endif -static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) -{ - struct mxc_nand_platform_data *pdata = host->dev->platform_data; - - if (!pdata) - return -ENODEV; - - host->pdata = *pdata; - - if (nfc_is_v1()) { - if (cpu_is_mx21()) - host->devtype_data = &imx21_nand_devtype_data; - else - host->devtype_data = &imx27_nand_devtype_data; - } else if (nfc_is_v21()) { - host->devtype_data = &imx25_nand_devtype_data; - } else if (nfc_is_v3_2a()) { - host->devtype_data = &imx51_nand_devtype_data; - } else if (nfc_is_v3_2b()) { - host->devtype_data = &imx53_nand_devtype_data; - } else - BUG(); - - return 0; -} - static int __devinit mxcnd_probe(struct platform_device *pdev) { struct nand_chip *this; @@ -1404,8 +1419,16 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) return PTR_ERR(host->clk); err = mxcnd_probe_dt(host); - if (err > 0) - err = mxcnd_probe_pdata(host); + if (err > 0) { + struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; + if (pdata) { + host->pdata = *pdata; + host->devtype_data = (struct mxc_nand_devtype_data *) + pdev->id_entry->driver_data; + } else { + err = -ENODEV; + } + } if (err < 0) return err; @@ -1494,7 +1517,7 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) } /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { + if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) { err = -ENXIO; goto escan; } @@ -1508,7 +1531,7 @@ static int __devinit mxcnd_probe(struct platform_device *pdev) this->ecc.layout = host->devtype_data->ecclayout_4k; if (this->ecc.mode == NAND_ECC_HW) { - if (nfc_is_v1()) + if (is_imx21_nfc(host) || is_imx27_nfc(host)) this->ecc.strength = 1; else this->ecc.strength = (host->eccsize == 4) ? 4 : 8; @@ -1555,6 +1578,7 @@ static struct platform_driver mxcnd_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(mxcnd_dt_ids), }, + .id_table = mxcnd_devtype, .probe = mxcnd_probe, .remove = __devexit_p(mxcnd_remove), }; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5b313862064..5c8978e9024 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -27,8 +27,7 @@ #include <linux/bch.h> #endif -#include <plat/dma.h> -#include <plat/gpmc.h> +#include <plat-omap/dma-omap.h> #include <linux/platform_data/mtd-nand-omap2.h> #define DRIVER_NAME "omap2-nand" @@ -106,10 +105,18 @@ #define CS_MASK 0x7 #define ENABLE_PREFETCH (0x1 << 7) #define DMA_MPU_MODE_SHIFT 2 +#define ECCSIZE0_SHIFT 12 #define ECCSIZE1_SHIFT 22 #define ECC1RESULTSIZE 0x1 #define ECCCLEAR 0x100 #define ECC1 0x1 +#define PREFETCH_FIFOTHRESHOLD_MAX 0x40 +#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8) +#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff) +#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F) +#define STATUS_BUFF_EMPTY 0x00000001 + +#define OMAP24XX_DMA_GPMC 4 /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -269,7 +276,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) /* wait until buffer is available for write */ do { status = readl(info->reg.gpmc_status) & - GPMC_STATUS_BUFF_EMPTY; + STATUS_BUFF_EMPTY; } while (!status); } } @@ -307,7 +314,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) /* wait until buffer is available for write */ do { status = readl(info->reg.gpmc_status) & - GPMC_STATUS_BUFF_EMPTY; + STATUS_BUFF_EMPTY; } while (!status); } } @@ -348,7 +355,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) } else { do { r_count = readl(info->reg.gpmc_prefetch_status); - r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count); + r_count = PREFETCH_STATUS_FIFO_CNT(r_count); r_count = r_count >> 2; ioread32_rep(info->nand.IO_ADDR_R, p, r_count); p += r_count; @@ -395,7 +402,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, } else { while (len) { w_count = readl(info->reg.gpmc_prefetch_status); - w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count); + w_count = PREFETCH_STATUS_FIFO_CNT(w_count); w_count = w_count >> 1; for (i = 0; (i < w_count) && len; i++, len -= 2) iowrite16(*p++, info->nand.IO_ADDR_W); @@ -407,7 +414,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, do { cpu_relax(); val = readl(info->reg.gpmc_prefetch_status); - val = GPMC_PREFETCH_STATUS_COUNT(val); + val = PREFETCH_STATUS_COUNT(val); } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ @@ -493,7 +500,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, do { cpu_relax(); val = readl(info->reg.gpmc_prefetch_status); - val = GPMC_PREFETCH_STATUS_COUNT(val); + val = PREFETCH_STATUS_COUNT(val); } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ @@ -556,7 +563,7 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) u32 bytes; bytes = readl(info->reg.gpmc_prefetch_status); - bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); + bytes = PREFETCH_STATUS_FIFO_CNT(bytes); bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ if (this_irq == info->gpmc_irq_count) @@ -682,7 +689,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); do { val = readl(info->reg.gpmc_prefetch_status); - val = GPMC_PREFETCH_STATUS_COUNT(val); + val = PREFETCH_STATUS_COUNT(val); cpu_relax(); } while (val && (tim++ < limit)); @@ -996,7 +1003,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) cond_resched(); } - status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); + status = readb(info->reg.gpmc_nand_data); return status; } @@ -1029,19 +1036,45 @@ static int omap_dev_ready(struct mtd_info *mtd) static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) { int nerrors; - unsigned int dev_width; + unsigned int dev_width, nsectors; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); struct nand_chip *chip = mtd->priv; + u32 val; nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4; dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; + nsectors = 1; /* * Program GPMC to perform correction on one 512-byte sector at a time. * Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and * gives a slight (5%) performance gain (but requires additional code). */ - (void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors); + + writel(ECC1, info->reg.gpmc_ecc_control); + + /* + * When using BCH, sector size is hardcoded to 512 bytes. + * Here we are using wrapping mode 6 both for reading and writing, with: + * size0 = 0 (no additional protected byte in spare area) + * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) + */ + val = (32 << ECCSIZE1_SHIFT) | (0 << ECCSIZE0_SHIFT); + writel(val, info->reg.gpmc_ecc_size_config); + + /* BCH configuration */ + val = ((1 << 16) | /* enable BCH */ + (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ + (0x06 << 8) | /* wrap mode = 6 */ + (dev_width << 7) | /* bus width */ + (((nsectors-1) & 0x7) << 4) | /* number of sectors */ + (info->gpmc_cs << 1) | /* ECC CS */ + (0x1)); /* enable ECC */ + + writel(val, info->reg.gpmc_ecc_config); + + /* clear ecc and enable bits */ + writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); } /** @@ -1055,7 +1088,32 @@ static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code); + unsigned long nsectors, val1, val2; + int i; + + nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; + + for (i = 0; i < nsectors; i++) { + + /* Read hw-computed remainder */ + val1 = readl(info->reg.gpmc_bch_result0[i]); + val2 = readl(info->reg.gpmc_bch_result1[i]); + + /* + * Add constant polynomial to remainder, in order to get an ecc + * sequence of 0xFFs for a buffer filled with 0xFFs; and + * left-justify the resulting polynomial. + */ + *ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF); + *ecc_code++ = 0x13 ^ ((val2 >> 4) & 0xFF); + *ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF)); + *ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF); + *ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF); + *ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF); + *ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4); + } + + return 0; } /** @@ -1069,7 +1127,39 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code); + unsigned long nsectors, val1, val2, val3, val4; + int i; + + nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; + + for (i = 0; i < nsectors; i++) { + + /* Read hw-computed remainder */ + val1 = readl(info->reg.gpmc_bch_result0[i]); + val2 = readl(info->reg.gpmc_bch_result1[i]); + val3 = readl(info->reg.gpmc_bch_result2[i]); + val4 = readl(info->reg.gpmc_bch_result3[i]); + + /* + * Add constant polynomial to remainder, in order to get an ecc + * sequence of 0xFFs for a buffer filled with 0xFFs. + */ + *ecc_code++ = 0xef ^ (val4 & 0xFF); + *ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF); + *ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF); + *ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF); + *ecc_code++ = 0xed ^ (val3 & 0xFF); + *ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF); + *ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF); + *ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF); + *ecc_code++ = 0x97 ^ (val2 & 0xFF); + *ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF); + *ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF); + *ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF); + *ecc_code++ = 0xb5 ^ (val1 & 0xFF); + } + + return 0; } /** @@ -1125,7 +1215,7 @@ static void omap3_free_bch(struct mtd_info *mtd) */ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) { - int ret, max_errors; + int max_errors; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); #ifdef CONFIG_MTD_NAND_OMAP_BCH8 @@ -1142,11 +1232,6 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) goto fail; } - /* initialize GPMC BCH engine */ - ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors); - if (ret) - goto fail; - /* software bch library is only used to detect and locate errors */ info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */); if (!info->bch) @@ -1513,7 +1598,7 @@ static int omap_nand_remove(struct platform_device *pdev) /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); iounmap(info->nand.IO_ADDR_R); - release_mem_region(info->phys_base, NAND_IO_SIZE); + release_mem_region(info->phys_base, info->mem_size); kfree(info); return 0; } diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 1961be98517..99f96e19ebe 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -38,12 +38,10 @@ #include <linux/regulator/consumer.h> #include <asm/mach/flash.h> -#include <plat/gpmc.h> #include <linux/platform_data/mtd-onenand-omap2.h> #include <asm/gpio.h> -#include <plat/dma.h> -#include <plat/cpu.h> +#include <plat-omap/dma-omap.h> #define DRIVER_NAME "omap2-onenand" @@ -63,6 +61,7 @@ struct omap2_onenand { int freq; int (*setup)(void __iomem *base, int *freq_ptr); struct regulator *regulator; + u8 flags; }; static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) @@ -155,7 +154,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) { syscfg |= ONENAND_SYS_CFG1_IOBE; write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); - if (cpu_is_omap34xx()) + if (c->flags & ONENAND_IN_OMAP34XX) /* Add a delay to let GPIO settle */ syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); } @@ -446,13 +445,19 @@ out_copy: #else -int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count); +static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, + size_t count) +{ + return -ENOSYS; +} -int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count); +static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, + const unsigned char *buffer, + int offset, size_t count) +{ + return -ENOSYS; +} #endif @@ -550,13 +555,19 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, #else -int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count); +static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, + size_t count) +{ + return -ENOSYS; +} -int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count); +static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, + const unsigned char *buffer, + int offset, size_t count) +{ + return -ENOSYS; +} #endif @@ -639,6 +650,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) init_completion(&c->irq_done); init_completion(&c->dma_done); + c->flags = pdata->flags; c->gpmc_cs = pdata->cs; c->gpio_irq = pdata->gpio_irq; c->dma_channel = pdata->dma_channel; @@ -729,7 +741,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) this = &c->onenand; if (c->dma_channel >= 0) { this->wait = omap2_onenand_wait; - if (cpu_is_omap34xx()) { + if (c->flags & ONENAND_IN_OMAP34XX) { this->read_bufferram = omap3_onenand_read_bufferram; this->write_bufferram = omap3_onenand_write_bufferram; } else { @@ -803,7 +815,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) } iounmap(c->onenand.base); release_mem_region(c->phys_base, c->mem_size); - gpmc_cs_free(c->gpmc_cs); kfree(c); return 0; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index dc15d248443..ef8d2a080d1 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1060,7 +1060,7 @@ static ssize_t bonding_store_primary(struct device *d, goto out; } - sscanf(buf, "%16s", ifname); /* IFNAMSIZ */ + sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ /* check to see if we are clearing primary */ if (!strlen(ifname) || buf[0] == '\n') { @@ -1237,7 +1237,7 @@ static ssize_t bonding_store_active_slave(struct device *d, goto out; } - sscanf(buf, "%16s", ifname); /* IFNAMSIZ */ + sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ /* check to see if we are clearing active */ if (!strlen(ifname) || buf[0] == '\n') { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index c65295dded3..6e5bdd1a31d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1702,7 +1702,7 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata) SHMEM_EEE_ADV_STATUS_SHIFT); if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) { DP(BNX2X_MSG_ETHTOOL, - "Direct manipulation of EEE advertisment is not supported\n"); + "Direct manipulation of EEE advertisement is not supported\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index e2e45ee5df3..f6cfdc6cf20 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -137,7 +137,16 @@ #define LINK_20GTFD LINK_STATUS_SPEED_AND_DUPLEX_20GTFD #define LINK_20GXFD LINK_STATUS_SPEED_AND_DUPLEX_20GXFD - +#define LINK_UPDATE_MASK \ + (LINK_STATUS_SPEED_AND_DUPLEX_MASK | \ + LINK_STATUS_LINK_UP | \ + LINK_STATUS_PHYSICAL_LINK_FLAG | \ + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | \ + LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | \ + LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | \ + LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK | \ + LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE | \ + LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE) #define SFP_EEPROM_CON_TYPE_ADDR 0x2 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7 @@ -3295,6 +3304,21 @@ static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port) DEFAULT_PHY_DEV_ADDR); } +static void bnx2x_xgxs_specific_func(struct bnx2x_phy *phy, + struct link_params *params, + u32 action) +{ + struct bnx2x *bp = params->bp; + switch (action) { + case PHY_INIT: + /* Set correct devad */ + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + params->port*0x18, 0); + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18, + phy->def_md_devad); + break; + } +} + static void bnx2x_xgxs_deassert(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -3309,10 +3333,8 @@ static void bnx2x_xgxs_deassert(struct link_params *params) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val); udelay(500); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val); - - REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0); - REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, - params->phy[INT_PHY].def_md_devad); + bnx2x_xgxs_specific_func(¶ms->phy[INT_PHY], params, + PHY_INIT); } static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, @@ -3545,14 +3567,11 @@ static void bnx2x_warpcore_set_lpi_passthrough(struct bnx2x_phy *phy, static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, struct link_params *params, struct link_vars *vars) { - u16 val16 = 0, lane, i; + u16 lane, i, cl72_ctrl, an_adv = 0; + u16 ucode_ver; struct bnx2x *bp = params->bp; static struct bnx2x_reg_set reg_set[] = { {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7}, - {MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 0}, - {MDIO_WC_DEVAD, MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0}, - {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff}, - {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555}, {MDIO_PMA_DEVAD, MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0}, {MDIO_WC_DEVAD, MDIO_WC_REG_RX66_CONTROL, 0x7415}, {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190}, @@ -3565,12 +3584,19 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg, reg_set[i].val); + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, &cl72_ctrl); + cl72_ctrl &= 0xf8ff; + cl72_ctrl |= 0x3800; + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, cl72_ctrl); + /* Check adding advertisement for 1G KX */ if (((vars->line_speed == SPEED_AUTO_NEG) && (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) || (vars->line_speed == SPEED_1000)) { u32 addr = MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2; - val16 |= (1<<5); + an_adv |= (1<<5); /* Enable CL37 1G Parallel Detect */ bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, addr, 0x1); @@ -3580,11 +3606,14 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) || (vars->line_speed == SPEED_10000)) { /* Check adding advertisement for 10G KR */ - val16 |= (1<<7); + an_adv |= (1<<7); /* Enable 10G Parallel Detect */ + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, 0); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 1); - + bnx2x_set_aer_mmd(params, phy); DP(NETIF_MSG_LINK, "Advertize 10G\n"); } @@ -3604,7 +3633,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, /* Advertised speeds */ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, - MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16); + MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, an_adv); /* Advertised and set FEC (Forward Error Correction) */ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, @@ -3628,9 +3657,10 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, /* Set KR Autoneg Work-Around flag for Warpcore version older than D108 */ bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, - MDIO_WC_REG_UC_INFO_B1_VERSION, &val16); - if (val16 < 0xd108) { - DP(NETIF_MSG_LINK, "Enable AN KR work-around\n"); + MDIO_WC_REG_UC_INFO_B1_VERSION, &ucode_ver); + if (ucode_ver < 0xd108) { + DP(NETIF_MSG_LINK, "Enable AN KR work-around. WC ver:0x%x\n", + ucode_ver); vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY; } bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, @@ -3651,21 +3681,16 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u16 i; + u16 val16, i, lane; static struct bnx2x_reg_set reg_set[] = { /* Disable Autoneg */ {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7}, - {MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 0}, {MDIO_WC_DEVAD, MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00}, {MDIO_AN_DEVAD, MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0}, {MDIO_AN_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0}, {MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL3_UP1, 0x1}, {MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL5_MISC7, 0xa}, - /* Disable CL36 PCS Tx */ - {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0}, - /* Double Wide Single Data Rate @ pll rate */ - {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF}, /* Leave cl72 training enable, needed for KR */ {MDIO_PMA_DEVAD, MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150, @@ -3676,11 +3701,24 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg, reg_set[i].val); - /* Leave CL72 enabled */ - bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, - MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, - 0x3800); + lane = bnx2x_get_warpcore_lane(phy, params); + /* Global registers */ + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, 0); + /* Disable CL36 PCS Tx */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL0, &val16); + val16 &= ~(0x0011 << lane); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL0, val16); + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL1, &val16); + val16 |= (0x0303 << (lane << 1)); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL1, val16); + /* Restore AER */ + bnx2x_set_aer_mmd(params, phy); /* Set speed via PMA/PMD register */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040); @@ -4303,7 +4341,7 @@ static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy, struct link_params *params) { struct bnx2x *bp = params->bp; - u16 val16; + u16 val16, lane; bnx2x_sfp_e3_set_transmitter(params, phy, 0); bnx2x_set_mdio_clk(bp, params->chip_id, params->port); bnx2x_set_aer_mmd(params, phy); @@ -4340,6 +4378,30 @@ static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy, MDIO_WC_REG_XGXSBLK1_LANECTRL2, val16 & 0xff00); + lane = bnx2x_get_warpcore_lane(phy, params); + /* Disable CL36 PCS Tx */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL0, &val16); + val16 |= (0x11 << lane); + if (phy->flags & FLAGS_WC_DUAL_MODE) + val16 |= (0x22 << lane); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL0, val16); + + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL1, &val16); + val16 &= ~(0x0303 << (lane << 1)); + val16 |= (0x0101 << (lane << 1)); + if (phy->flags & FLAGS_WC_DUAL_MODE) { + val16 &= ~(0x0c0c << (lane << 1)); + val16 |= (0x0404 << (lane << 1)); + } + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL1, val16); + /* Restore AER */ + bnx2x_set_aer_mmd(params, phy); + } static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy, @@ -6296,15 +6358,7 @@ static int bnx2x_update_link_down(struct link_params *params, vars->mac_type = MAC_TYPE_NONE; /* Update shared memory */ - vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK | - LINK_STATUS_LINK_UP | - LINK_STATUS_PHYSICAL_LINK_FLAG | - LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | - LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | - LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | - LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK | - LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE | - LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE); + vars->link_status &= ~LINK_UPDATE_MASK; vars->line_speed = 0; bnx2x_update_mng(params, vars->link_status); @@ -6452,6 +6506,7 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars) u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed; u8 active_external_phy = INT_PHY; vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG; + vars->link_status &= ~LINK_UPDATE_MASK; for (phy_index = INT_PHY; phy_index < params->num_phys; phy_index++) { phy_vars[phy_index].flow_ctrl = 0; @@ -7579,7 +7634,7 @@ static void bnx2x_warpcore_power_module(struct link_params *params, static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy, struct link_params *params, u16 addr, u8 byte_cnt, - u8 *o_buf) + u8 *o_buf, u8 is_init) { int rc = 0; u8 i, j = 0, cnt = 0; @@ -7596,10 +7651,10 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy, /* 4 byte aligned address */ addr32 = addr & (~0x3); do { - if (cnt == I2C_WA_PWR_ITER) { + if ((!is_init) && (cnt == I2C_WA_PWR_ITER)) { bnx2x_warpcore_power_module(params, phy, 0); /* Note that 100us are not enough here */ - usleep_range(1000,1000); + usleep_range(1000, 2000); bnx2x_warpcore_power_module(params, phy, 1); } rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt, @@ -7719,7 +7774,7 @@ int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr, - byte_cnt, o_buf); + byte_cnt, o_buf, 0); break; } return rc; @@ -7923,6 +7978,7 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, { u8 val; + int rc; struct bnx2x *bp = params->bp; u16 timeout; /* Initialization time after hot-plug may take up to 300ms for @@ -7930,8 +7986,14 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, */ for (timeout = 0; timeout < 60; timeout++) { - if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val) - == 0) { + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) + rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, + params, 1, + 1, &val, 1); + else + rc = bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, + &val); + if (rc == 0) { DP(NETIF_MSG_LINK, "SFP+ module initialization took %d ms\n", timeout * 5); @@ -7939,7 +8001,8 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, } usleep_range(5000, 10000); } - return -EINVAL; + rc = bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val); + return rc; } static void bnx2x_8727_power_module(struct bnx2x *bp, @@ -9878,7 +9941,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, else rc = bnx2x_8483x_disable_eee(phy, params, vars); if (rc) { - DP(NETIF_MSG_LINK, "Failed to set EEE advertisment\n"); + DP(NETIF_MSG_LINK, "Failed to set EEE advertisement\n"); return rc; } } else { @@ -10993,7 +11056,7 @@ static struct bnx2x_phy phy_xgxs = { .format_fw_ver = (format_fw_ver_t)NULL, .hw_reset = (hw_reset_t)NULL, .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .phy_specific_func = (phy_specific_func_t)bnx2x_xgxs_specific_func }; static struct bnx2x_phy phy_warpcore = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, @@ -11465,6 +11528,11 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, phy->media_type = ETH_PHY_BASE_T; break; case PORT_HW_CFG_NET_SERDES_IF_XFI: + phy->supported &= (SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); phy->media_type = ETH_PHY_XFP_FIBER; break; case PORT_HW_CFG_NET_SERDES_IF_SFI: @@ -12919,7 +12987,7 @@ static u8 bnx2x_analyze_link_error(struct link_params *params, DP(NETIF_MSG_LINK, "Analyze TX Fault\n"); break; default: - DP(NETIF_MSG_LINK, "Analyze UNKOWN\n"); + DP(NETIF_MSG_LINK, "Analyze UNKNOWN\n"); } DP(NETIF_MSG_LINK, "Link changed:[%x %x]->%x\n", vars->link_up, old_status, status); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index d5648fc666b..bd1fd3d87c2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -6794,8 +6794,9 @@ static int bnx2x_init_hw_port(struct bnx2x *bp) bnx2x_init_block(bp, BLOCK_DORQ, init_phase); + bnx2x_init_block(bp, BLOCK_BRB1, init_phase); + if (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp)) { - bnx2x_init_block(bp, BLOCK_BRB1, init_phase); if (IS_MF(bp)) low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246); @@ -11902,7 +11903,15 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, /* disable FCOE L2 queue for E1x */ if (CHIP_IS_E1x(bp)) bp->flags |= NO_FCOE_FLAG; - + /* disable FCOE for 57840 device, until FW supports it */ + switch (ent->driver_data) { + case BCM57840_O: + case BCM57840_4_10: + case BCM57840_2_20: + case BCM57840_MFO: + case BCM57840_MF: + bp->flags |= NO_FCOE_FLAG; + } #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index c1cde11b0c6..0df1284df49 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3416,16 +3416,6 @@ static int adap_init0_config(struct adapter *adapter, int reset) finicsum, cfcsum); /* - * If we're a pure NIC driver then disable all offloading facilities. - * This will allow the firmware to optimize aspects of the hardware - * configuration which will result in improved performance. - */ - caps_cmd.ofldcaps = 0; - caps_cmd.iscsicaps = 0; - caps_cmd.rdmacaps = 0; - caps_cmd.fcoecaps = 0; - - /* * And now tell the firmware to use the configuration we just loaded. */ caps_cmd.op_to_write = diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 32eec15fe4c..730ae2cfa49 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2519,6 +2519,7 @@ int t4_fw_bye(struct adapter *adap, unsigned int mbox) { struct fw_bye_cmd c; + memset(&c, 0, sizeof(c)); INIT_CMD(c, BYE, WRITE); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -2535,6 +2536,7 @@ int t4_early_init(struct adapter *adap, unsigned int mbox) { struct fw_initialize_cmd c; + memset(&c, 0, sizeof(c)); INIT_CMD(c, INITIALIZE, WRITE); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -2551,6 +2553,7 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) { struct fw_reset_cmd c; + memset(&c, 0, sizeof(c)); INIT_CMD(c, RESET, WRITE); c.val = htonl(reset); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); @@ -2828,7 +2831,7 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, HOSTPAGESIZEPF7(sge_hps)); t4_set_reg_field(adap, SGE_CONTROL, - INGPADBOUNDARY(INGPADBOUNDARY_MASK) | + INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE_MASK, INGPADBOUNDARY(fl_align_log - 5) | EGRSTATUSPAGESIZE(stat_len != 64)); @@ -3278,6 +3281,7 @@ int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, { struct fw_vi_enable_cmd c; + memset(&c, 0, sizeof(c)); c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 1d03dcdd5e5..19ac096cb07 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1353,8 +1353,11 @@ static int gfar_restore(struct device *dev) struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; - if (!netif_running(ndev)) + if (!netif_running(ndev)) { + netif_device_attach(ndev); + return 0; + } gfar_init_bds(ndev); init_registers(ndev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 56b20d17d0e..116f0e901be 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2673,6 +2673,9 @@ static int ixgbe_get_ts_info(struct net_device *dev, case ixgbe_mac_X540: case ixgbe_mac_82599EB: info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE; diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index f8064df10cc..60ac46f4ac0 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -1860,10 +1860,14 @@ jme_open(struct net_device *netdev) jme_clear_pm(jme); JME_NAPI_ENABLE(jme); - tasklet_enable(&jme->linkch_task); - tasklet_enable(&jme->txclean_task); - tasklet_hi_enable(&jme->rxclean_task); - tasklet_hi_enable(&jme->rxempty_task); + tasklet_init(&jme->linkch_task, jme_link_change_tasklet, + (unsigned long) jme); + tasklet_init(&jme->txclean_task, jme_tx_clean_tasklet, + (unsigned long) jme); + tasklet_init(&jme->rxclean_task, jme_rx_clean_tasklet, + (unsigned long) jme); + tasklet_init(&jme->rxempty_task, jme_rx_empty_tasklet, + (unsigned long) jme); rc = jme_request_irq(jme); if (rc) @@ -1948,10 +1952,10 @@ jme_close(struct net_device *netdev) JME_NAPI_DISABLE(jme); - tasklet_disable(&jme->linkch_task); - tasklet_disable(&jme->txclean_task); - tasklet_disable(&jme->rxclean_task); - tasklet_disable(&jme->rxempty_task); + tasklet_kill(&jme->linkch_task); + tasklet_kill(&jme->txclean_task); + tasklet_kill(&jme->rxclean_task); + tasklet_kill(&jme->rxempty_task); jme_disable_rx_engine(jme); jme_disable_tx_engine(jme); @@ -3079,22 +3083,6 @@ jme_init_one(struct pci_dev *pdev, tasklet_init(&jme->pcc_task, jme_pcc_tasklet, (unsigned long) jme); - tasklet_init(&jme->linkch_task, - jme_link_change_tasklet, - (unsigned long) jme); - tasklet_init(&jme->txclean_task, - jme_tx_clean_tasklet, - (unsigned long) jme); - tasklet_init(&jme->rxclean_task, - jme_rx_clean_tasklet, - (unsigned long) jme); - tasklet_init(&jme->rxempty_task, - jme_rx_empty_tasklet, - (unsigned long) jme); - tasklet_disable_nosync(&jme->linkch_task); - tasklet_disable_nosync(&jme->txclean_task); - tasklet_disable_nosync(&jme->rxclean_task); - tasklet_disable_nosync(&jme->rxempty_task); jme->dpi.cur = PCC_P1; jme->reg_ghc = 0; diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index 9b9c2ac5c4c..d19a143aa5a 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -4026,7 +4026,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) dev0 = hw->dev[0]; unregister_netdev(dev0); - tasklet_disable(&hw->phy_task); + tasklet_kill(&hw->phy_task); spin_lock_irq(&hw->hw_lock); hw->intr_mask = 0; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 318fee91c79..69e01977a1d 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -5407,8 +5407,8 @@ static int netdev_close(struct net_device *dev) /* Delay for receive task to stop scheduling itself. */ msleep(2000 / HZ); - tasklet_disable(&hw_priv->rx_tasklet); - tasklet_disable(&hw_priv->tx_tasklet); + tasklet_kill(&hw_priv->rx_tasklet); + tasklet_kill(&hw_priv->tx_tasklet); free_irq(dev->irq, hw_priv->dev); transmit_cleanup(hw_priv, 0); @@ -5459,8 +5459,10 @@ static int prepare_hardware(struct net_device *dev) rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev); if (rc) return rc; - tasklet_enable(&hw_priv->rx_tasklet); - tasklet_enable(&hw_priv->tx_tasklet); + tasklet_init(&hw_priv->rx_tasklet, rx_proc_task, + (unsigned long) hw_priv); + tasklet_init(&hw_priv->tx_tasklet, tx_proc_task, + (unsigned long) hw_priv); hw->promiscuous = 0; hw->all_multi = 0; @@ -7033,16 +7035,6 @@ static int __devinit pcidev_init(struct pci_dev *pdev, spin_lock_init(&hw_priv->hwlock); mutex_init(&hw_priv->lock); - /* tasklet is enabled. */ - tasklet_init(&hw_priv->rx_tasklet, rx_proc_task, - (unsigned long) hw_priv); - tasklet_init(&hw_priv->tx_tasklet, tx_proc_task, - (unsigned long) hw_priv); - - /* tasklet_enable will decrement the atomic counter. */ - tasklet_disable(&hw_priv->rx_tasklet); - tasklet_disable(&hw_priv->tx_tasklet); - for (i = 0; i < TOTAL_PORT_NUM; i++) init_waitqueue_head(&hw_priv->counter[i].counter); diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 53743f7a2ca..af8b4142088 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1524,6 +1524,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev) pldat->dma_buff_base_p); free_irq(ndev->irq, ndev); iounmap(pldat->net_base); + mdiobus_unregister(pldat->mii_bus); mdiobus_free(pldat->mii_bus); clk_disable(pldat->clk); clk_put(pldat->clk); diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index e7ff886e804..927aa33d434 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -3827,6 +3827,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_29: case RTL_GIGA_MAC_VER_30: case RTL_GIGA_MAC_VER_32: @@ -4519,6 +4521,9 @@ static void rtl_set_rx_mode(struct net_device *dev) mc_filter[1] = swab32(data); } + if (tp->mac_version == RTL_GIGA_MAC_VER_35) + mc_filter[1] = mc_filter[0] = 0xffffffff; + RTL_W32(MAR0 + 4, mc_filter[1]); RTL_W32(MAR0 + 0, mc_filter[0]); diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 62d1baf111e..c53c0f4e2ce 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2110,7 +2110,7 @@ static void __devinit smsc911x_read_mac_address(struct net_device *dev) static int __devinit smsc911x_init(struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int byte_test; + unsigned int byte_test, mask; unsigned int to = 100; SMSC_TRACE(pdata, probe, "Driver Parameters:"); @@ -2130,9 +2130,22 @@ static int __devinit smsc911x_init(struct net_device *dev) /* * poll the READY bit in PMT_CTRL. Any other access to the device is * forbidden while this bit isn't set. Try for 100ms + * + * Note that this test is done before the WORD_SWAP register is + * programmed. So in some configurations the READY bit is at 16 before + * WORD_SWAP is written to. This issue is worked around by waiting + * until either bit 0 or bit 16 gets set in PMT_CTRL. + * + * SMSC has confirmed that checking bit 16 (marked as reserved in + * the datasheet) is fine since these bits "will either never be set + * or can only go high after READY does (so also indicate the device + * is ready)". */ - while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) + + mask = PMT_CTRL_READY_ | swahw32(PMT_CTRL_READY_); + while (!(smsc911x_reg_read(pdata, PMT_CTRL) & mask) && --to) udelay(1000); + if (to == 0) { pr_err("Device not READY in 100ms aborting\n"); return -ENODEV; diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 4e981001385..66e025ad5df 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -917,7 +917,7 @@ static int tile_net_setup_interrupts(struct net_device *dev) ingress_irq = rc; tile_irq_activate(ingress_irq, TILE_IRQ_PERCPU); rc = request_irq(ingress_irq, tile_net_handle_ingress_irq, - 0, NULL, NULL); + 0, "tile_net", NULL); if (rc != 0) { netdev_err(dev, "request_irq failed: %d\n", rc); destroy_irq(ingress_irq); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 0793299bd39..77e6db9dcfe 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -942,6 +942,10 @@ static int axienet_open(struct net_device *ndev) phy_start(lp->phy_dev); } + /* Enable tasklets for Axi DMA error handling */ + tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler, + (unsigned long) lp); + /* Enable interrupts for Axi DMA Tx */ ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev); if (ret) @@ -950,8 +954,7 @@ static int axienet_open(struct net_device *ndev) ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev); if (ret) goto err_rx_irq; - /* Enable tasklets for Axi DMA error handling */ - tasklet_enable(&lp->dma_err_tasklet); + return 0; err_rx_irq: @@ -960,6 +963,7 @@ err_tx_irq: if (lp->phy_dev) phy_disconnect(lp->phy_dev); lp->phy_dev = NULL; + tasklet_kill(&lp->dma_err_tasklet); dev_err(lp->dev, "request_irq() failed\n"); return ret; } @@ -990,7 +994,7 @@ static int axienet_stop(struct net_device *ndev) axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - tasklet_disable(&lp->dma_err_tasklet); + tasklet_kill(&lp->dma_err_tasklet); free_irq(lp->tx_irq, ndev); free_irq(lp->rx_irq, ndev); @@ -1613,10 +1617,6 @@ static int __devinit axienet_of_probe(struct platform_device *op) goto err_iounmap_2; } - tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler, - (unsigned long) lp); - tasklet_disable(&lp->dma_err_tasklet); - return 0; err_iounmap_2: diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index c81e278629f..08d55b6bf27 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -31,6 +31,7 @@ #include <linux/usb/cdc.h> #include <linux/usb/usbnet.h> #include <linux/gfp.h> +#include <linux/if_vlan.h> /* @@ -92,7 +93,7 @@ static int eem_bind(struct usbnet *dev, struct usb_interface *intf) /* no jumbogram (16K) support for now */ - dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN; + dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN + VLAN_HLEN; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; return 0; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4cd582a4f62..74fab1a4015 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -540,10 +540,12 @@ advance: (ctx->ether_desc == NULL) || (ctx->control != intf)) goto error; - /* claim interfaces, if any */ - temp = usb_driver_claim_interface(driver, ctx->data, dev); - if (temp) - goto error; + /* claim data interface, if different from control */ + if (ctx->data != ctx->control) { + temp = usb_driver_claim_interface(driver, ctx->data, dev); + if (temp) + goto error; + } iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; @@ -623,6 +625,10 @@ static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) tasklet_kill(&ctx->bh); + /* handle devices with combined control and data interface */ + if (ctx->control == ctx->data) + ctx->data = NULL; + /* disconnect master --> disconnect slave */ if (intf == ctx->control && ctx->data) { usb_set_intfdata(ctx->data, NULL); @@ -1245,6 +1251,14 @@ static const struct usb_device_id cdc_devs[] = { .driver_info = (unsigned long) &wwan_info, }, + /* Huawei NCM devices disguised as vendor specific */ + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16), + .driver_info = (unsigned long)&wwan_info, + }, + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46), + .driver_info = (unsigned long)&wwan_info, + }, + /* Generic CDC-NCM devices */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 7479a5761d0..362cb8cfeb9 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -184,7 +184,7 @@ static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx) /* set the address, index & direction (read from PHY) */ phy_id &= dev->mii.phy_id_mask; idx &= dev->mii.reg_num_mask; - addr = (phy_id << 11) | (idx << 6) | MII_READ_; + addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_; ret = smsc95xx_write_reg(dev, MII_ADDR, addr); check_warn_goto_done(ret, "Error writing MII_ADDR"); @@ -221,7 +221,7 @@ static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx, /* set the address, index & direction (write to PHY) */ phy_id &= dev->mii.phy_id_mask; idx &= dev->mii.reg_num_mask; - addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; + addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_; ret = smsc95xx_write_reg(dev, MII_ADDR, addr); check_warn_goto_done(ret, "Error writing MII_ADDR"); @@ -1344,6 +1344,7 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, } else { u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); skb_push(skb, 4); + cpu_to_le32s(&csum_preamble); memcpy(skb->data, &csum_preamble, 4); } } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index cb04f900cc4..edb81ed0695 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -359,10 +359,12 @@ static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, void usbnet_defer_kevent (struct usbnet *dev, int work) { set_bit (work, &dev->flags); - if (!schedule_work (&dev->kevent)) - netdev_err(dev->net, "kevent %d may have been dropped\n", work); - else + if (!schedule_work (&dev->kevent)) { + if (net_ratelimit()) + netdev_err(dev->net, "kevent %d may have been dropped\n", work); + } else { netdev_dbg(dev->net, "kevent %d scheduled\n", work); + } } EXPORT_SYMBOL_GPL(usbnet_defer_kevent); diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index ce9d4f2c977..0ae1bcc6da7 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -744,28 +744,43 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + u32 buf_size; - tbi = tq->buf_info + tq->tx_ring.next2fill; - tbi->map_type = VMXNET3_MAP_PAGE; - tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag, - 0, skb_frag_size(frag), - DMA_TO_DEVICE); + buf_offset = 0; + len = skb_frag_size(frag); + while (len) { + tbi = tq->buf_info + tq->tx_ring.next2fill; + if (len < VMXNET3_MAX_TX_BUF_SIZE) { + buf_size = len; + dw2 |= len; + } else { + buf_size = VMXNET3_MAX_TX_BUF_SIZE; + /* spec says that for TxDesc.len, 0 == 2^14 */ + } + tbi->map_type = VMXNET3_MAP_PAGE; + tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag, + buf_offset, buf_size, + DMA_TO_DEVICE); - tbi->len = skb_frag_size(frag); + tbi->len = buf_size; - gdesc = tq->tx_ring.base + tq->tx_ring.next2fill; - BUG_ON(gdesc->txd.gen == tq->tx_ring.gen); + gdesc = tq->tx_ring.base + tq->tx_ring.next2fill; + BUG_ON(gdesc->txd.gen == tq->tx_ring.gen); - gdesc->txd.addr = cpu_to_le64(tbi->dma_addr); - gdesc->dword[2] = cpu_to_le32(dw2 | skb_frag_size(frag)); - gdesc->dword[3] = 0; + gdesc->txd.addr = cpu_to_le64(tbi->dma_addr); + gdesc->dword[2] = cpu_to_le32(dw2); + gdesc->dword[3] = 0; - dev_dbg(&adapter->netdev->dev, - "txd[%u]: 0x%llu %u %u\n", - tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr), - le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]); - vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring); - dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT; + dev_dbg(&adapter->netdev->dev, + "txd[%u]: 0x%llu %u %u\n", + tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr), + le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]); + vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring); + dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT; + + len -= buf_size; + buf_offset += buf_size; + } } ctx->eop_txd = gdesc; @@ -886,6 +901,18 @@ vmxnet3_prepare_tso(struct sk_buff *skb, } } +static int txd_estimate(const struct sk_buff *skb) +{ + int count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + 1; + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + + count += VMXNET3_TXD_NEEDED(skb_frag_size(frag)); + } + return count; +} /* * Transmits a pkt thru a given tq @@ -914,9 +941,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, union Vmxnet3_GenericDesc tempTxDesc; #endif - /* conservatively estimate # of descriptors to use */ - count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + - skb_shinfo(skb)->nr_frags + 1; + count = txd_estimate(skb); ctx.ipv4 = (vlan_get_protocol(skb) == cpu_to_be16(ETH_P_IP)); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 607976c0016..8b5c6191707 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1,5 +1,5 @@ /* - * VXLAN: Virtual eXtensiable Local Area Network + * VXLAN: Virtual eXtensible Local Area Network * * Copyright (c) 2012 Vyatta Inc. * @@ -50,8 +50,8 @@ #define VXLAN_N_VID (1u << 24) #define VXLAN_VID_MASK (VXLAN_N_VID - 1) -/* VLAN + IP header + UDP + VXLAN */ -#define VXLAN_HEADROOM (4 + 20 + 8 + 8) +/* IP header + UDP + VXLAN + Ethernet header */ +#define VXLAN_HEADROOM (20 + 8 + 8 + 14) #define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ @@ -816,7 +816,7 @@ static void vxlan_cleanup(unsigned long arg) = container_of(p, struct vxlan_fdb, hlist); unsigned long timeout; - if (f->state == NUD_PERMANENT) + if (f->state & NUD_PERMANENT) continue; timeout = f->used + vxlan->age_interval * HZ; @@ -1102,6 +1102,10 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (!tb[IFLA_MTU]) dev->mtu = lowerdev->mtu - VXLAN_HEADROOM; + + /* update header length based on lower device */ + dev->hard_header_len = lowerdev->hard_header_len + + VXLAN_HEADROOM; } if (data[IFLA_VXLAN_TOS]) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 378bd70256b..741918a2027 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,6 +312,7 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) } bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + bf->bf_next = NULL; list_del(&bf->list); spin_unlock_bh(&sc->tx.txbuflock); @@ -393,7 +394,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; - bool rc_update = true; + bool rc_update = true, isba; struct ieee80211_tx_rate rates[4]; struct ath_frame_info *fi; int nframes; @@ -437,13 +438,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(an, tidno); seq_first = tid->seq_start; + isba = ts->ts_flags & ATH9K_TX_BA; /* * The hardware occasionally sends a tx status for the wrong TID. * In this case, the BA status cannot be considered valid and all * subframes need to be retransmitted + * + * Only BlockAcks have a TID and therefore normal Acks cannot be + * checked */ - if (tidno != ts->tid) + if (isba && tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); @@ -1774,6 +1779,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, list_add_tail(&bf->list, &bf_head); bf->bf_state.bf_type = 0; + bf->bf_next = NULL; bf->bf_lastbf = bf; ath_tx_fill_desc(sc, bf, txq, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_head, false); diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 192251adf98..282eedec675 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -382,7 +382,7 @@ static void cancel_transfers(struct b43legacy_pioqueue *queue) { struct b43legacy_pio_txpacket *packet, *tmp_packet; - tasklet_disable(&queue->txtask); + tasklet_kill(&queue->txtask); list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) free_txpacket(packet, 0); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index a6f1e816600..481345c23de 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4401,7 +4401,7 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode) static void brcmf_wiphy_pno_params(struct wiphy *wiphy) { -#ifndef CONFIG_BRCMFISCAN +#ifndef CONFIG_BRCMISCAN /* scheduled scan settings */ wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index ff8162d4c45..fa4d1b8cd9f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -521,7 +521,7 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); if (iwlagn_tx_skb(priv, control->sta, skb)) - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 7ff3f143067..408132cf83c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2114,7 +2114,7 @@ static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); - dev_kfree_skb_any(skb); + ieee80211_free_txskb(priv->hw, skb); } static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 17c8e5d8268..bb69f8f90b3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -321,6 +321,14 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) dma_map_page(trans->dev, page, 0, PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); + if (dma_mapping_error(trans->dev, rxb->page_dma)) { + rxb->page = NULL; + spin_lock_irqsave(&rxq->lock, flags); + list_add(&rxb->list, &rxq->rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + __free_pages(page, trans_pcie->rx_page_order); + return; + } /* dma address must be no more than 36 bits */ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); /* and also 256 byte aligned! */ @@ -488,8 +496,19 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, dma_map_page(trans->dev, rxb->page, 0, PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; + if (dma_mapping_error(trans->dev, rxb->page_dma)) { + /* + * free the page(s) as well to not break + * the invariant that the items on the used + * list have no page(s) + */ + __free_pages(rxb->page, trans_pcie->rx_page_order); + rxb->page = NULL; + list_add_tail(&rxb->list, &rxq->rx_used); + } else { + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } } else list_add_tail(&rxb->list, &rxq->rx_used); spin_unlock_irqrestore(&rxq->lock, flags); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 01dc8891070..59474ae0aec 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2449,7 +2449,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * Check if temperature compensation is supported. */ - if (tssi_bounds[4] == 0xff) + if (tssi_bounds[4] == 0xff || step == 0xff) return 0; /* diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 6241fd05bd4..a543746fb35 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -320,10 +320,7 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), } else next = dev->bus_list.next; - /* Run device routines with the device locked */ - device_lock(&dev->dev); retval = cb(dev, userdata); - device_unlock(&dev->dev); if (retval) break; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 94c6e2aa03d..6c94fc9489e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -398,6 +398,8 @@ static void pci_device_shutdown(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *drv = pci_dev->driver; + pm_runtime_resume(dev); + if (drv && drv->shutdown) drv->shutdown(pci_dev); pci_msi_shutdown(pci_dev); @@ -408,16 +410,6 @@ static void pci_device_shutdown(struct device *dev) * continue to do DMA */ pci_disable_device(pci_dev); - - /* - * Devices may be enabled to wake up by runtime PM, but they need not - * be supposed to wake up the system from its "power off" state (e.g. - * ACPI S5). Therefore disable wakeup for all devices that aren't - * supposed to wake up the system at this point. The state argument - * will be ignored by pci_enable_wake(). - */ - if (!device_may_wakeup(dev)) - pci_enable_wake(pci_dev, PCI_UNKNOWN, false); } #ifdef CONFIG_PM diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 02d107b1528..f39378d9da1 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -458,40 +458,6 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) } struct device_attribute vga_attr = __ATTR_RO(boot_vga); -static void -pci_config_pm_runtime_get(struct pci_dev *pdev) -{ - struct device *dev = &pdev->dev; - struct device *parent = dev->parent; - - if (parent) - pm_runtime_get_sync(parent); - pm_runtime_get_noresume(dev); - /* - * pdev->current_state is set to PCI_D3cold during suspending, - * so wait until suspending completes - */ - pm_runtime_barrier(dev); - /* - * Only need to resume devices in D3cold, because config - * registers are still accessible for devices suspended but - * not in D3cold. - */ - if (pdev->current_state == PCI_D3cold) - pm_runtime_resume(dev); -} - -static void -pci_config_pm_runtime_put(struct pci_dev *pdev) -{ - struct device *dev = &pdev->dev; - struct device *parent = dev->parent; - - pm_runtime_put(dev); - if (parent) - pm_runtime_put_sync(parent); -} - static ssize_t pci_read_config(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 54858838f09..aabf64798bd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1858,6 +1858,38 @@ bool pci_dev_run_wake(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_dev_run_wake); +void pci_config_pm_runtime_get(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + + if (parent) + pm_runtime_get_sync(parent); + pm_runtime_get_noresume(dev); + /* + * pdev->current_state is set to PCI_D3cold during suspending, + * so wait until suspending completes + */ + pm_runtime_barrier(dev); + /* + * Only need to resume devices in D3cold, because config + * registers are still accessible for devices suspended but + * not in D3cold. + */ + if (pdev->current_state == PCI_D3cold) + pm_runtime_resume(dev); +} + +void pci_config_pm_runtime_put(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + + pm_runtime_put(dev); + if (parent) + pm_runtime_put_sync(parent); +} + /** * pci_pm_init - Initialize PM functions of given PCI device * @dev: PCI device to handle. diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index bacbcba69cf..fd92aab9904 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -72,6 +72,8 @@ extern void pci_disable_enabled_device(struct pci_dev *dev); extern int pci_finish_runtime_suspend(struct pci_dev *dev); extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); extern void pci_wakeup_bus(struct pci_bus *bus); +extern void pci_config_pm_runtime_get(struct pci_dev *dev); +extern void pci_config_pm_runtime_put(struct pci_dev *dev); extern void pci_pm_init(struct pci_dev *dev); extern void platform_pci_wakeup_init(struct pci_dev *dev); extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 06bad96af41..af4e31cd3a3 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -213,6 +213,7 @@ static int report_error_detected(struct pci_dev *dev, void *data) struct aer_broadcast_data *result_data; result_data = (struct aer_broadcast_data *) data; + device_lock(&dev->dev); dev->error_state = result_data->state; if (!dev->driver || @@ -231,12 +232,14 @@ static int report_error_detected(struct pci_dev *dev, void *data) dev->driver ? "no AER-aware driver" : "no driver"); } - return 0; + goto out; } err_handler = dev->driver->err_handler; vote = err_handler->error_detected(dev, result_data->state); result_data->result = merge_result(result_data->result, vote); +out: + device_unlock(&dev->dev); return 0; } @@ -247,14 +250,17 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data) struct aer_broadcast_data *result_data; result_data = (struct aer_broadcast_data *) data; + device_lock(&dev->dev); if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->mmio_enabled) - return 0; + goto out; err_handler = dev->driver->err_handler; vote = err_handler->mmio_enabled(dev); result_data->result = merge_result(result_data->result, vote); +out: + device_unlock(&dev->dev); return 0; } @@ -265,14 +271,17 @@ static int report_slot_reset(struct pci_dev *dev, void *data) struct aer_broadcast_data *result_data; result_data = (struct aer_broadcast_data *) data; + device_lock(&dev->dev); if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->slot_reset) - return 0; + goto out; err_handler = dev->driver->err_handler; vote = err_handler->slot_reset(dev); result_data->result = merge_result(result_data->result, vote); +out: + device_unlock(&dev->dev); return 0; } @@ -280,15 +289,18 @@ static int report_resume(struct pci_dev *dev, void *data) { const struct pci_error_handlers *err_handler; + device_lock(&dev->dev); dev->error_state = pci_channel_io_normal; if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->resume) - return 0; + goto out; err_handler = dev->driver->err_handler; err_handler->resume(dev); +out: + device_unlock(&dev->dev); return 0; } diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index d03a7a39b2d..ed129b41462 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -272,7 +272,8 @@ static int get_port_device_capability(struct pci_dev *dev) } /* Hot-Plug Capable */ - if (cap_mask & PCIE_PORT_SERVICE_HP) { + if ((cap_mask & PCIE_PORT_SERVICE_HP) && + dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT) { pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, ®32); if (reg32 & PCI_EXP_SLTCAP_HPC) { services |= PCIE_PORT_SERVICE_HP; diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index eb907a8faf2..9b8505ccc56 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -76,6 +76,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp if (!access_ok(VERIFY_WRITE, buf, cnt)) return -EINVAL; + pci_config_pm_runtime_get(dev); + if ((pos & 1) && cnt) { unsigned char val; pci_user_read_config_byte(dev, pos, &val); @@ -121,6 +123,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp cnt--; } + pci_config_pm_runtime_put(dev); + *ppos = pos; return nbytes; } @@ -146,6 +150,8 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof if (!access_ok(VERIFY_READ, buf, cnt)) return -EINVAL; + pci_config_pm_runtime_get(dev); + if ((pos & 1) && cnt) { unsigned char val; __get_user(val, buf); @@ -191,6 +197,8 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof cnt--; } + pci_config_pm_runtime_put(dev); + *ppos = pos; i_size_write(ino, dp->size); return nbytes; diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index fa74efe8220..25c4b1993b3 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -25,7 +25,7 @@ #include <asm/sizes.h> #include <mach/mux.h> -#include <plat/tc.h> +#include <mach/tc.h> /* NOTE: don't expect this to support many I/O cards. The 16xx chips have diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7bf914df6e9..011133772d2 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -179,34 +179,16 @@ config PINCTRL_COH901 config PINCTRL_SAMSUNG bool "Samsung pinctrl driver" + depends on OF && GPIOLIB select PINMUX select PINCONF config PINCTRL_EXYNOS4 bool "Pinctrl driver data for Exynos4 SoC" + depends on OF && GPIOLIB select PINCTRL_SAMSUNG -config PINCTRL_MVEBU - bool - depends on ARCH_MVEBU - select PINMUX - select PINCONF - -config PINCTRL_DOVE - bool - select PINCTRL_MVEBU - -config PINCTRL_KIRKWOOD - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_370 - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_XP - bool - select PINCTRL_MVEBU +source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f395ba5cec2..3cb6a0a668a 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -36,12 +36,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o -obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o -obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o -obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o -obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o -obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o +obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 2e39c04fc16..cec6072cd7c 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -563,6 +563,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) return -EPROBE_DEFER; } + setting->dev_name = map->dev_name; + switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_map_to_setting(map, setting); diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 1f40ff68a8c..12f5694f3d5 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -105,12 +105,14 @@ struct pinctrl_setting_configs { * @type: the type of setting * @pctldev: pin control device handling to be programmed. Not used for * PIN_MAP_TYPE_DUMMY_STATE. + * @dev_name: the name of the device using this state * @data: Data specific to the setting type */ struct pinctrl_setting { struct list_head node; enum pinctrl_map_type type; struct pinctrl_dev *pctldev; + const char *dev_name; union { struct pinctrl_setting_mux mux; struct pinctrl_setting_configs configs; diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig new file mode 100644 index 00000000000..366fa541ee9 --- /dev/null +++ b/drivers/pinctrl/mvebu/Kconfig @@ -0,0 +1,24 @@ +if PLAT_ORION + +config PINCTRL_MVEBU + bool + select PINMUX + select PINCONF + +config PINCTRL_DOVE + bool + select PINCTRL_MVEBU + +config PINCTRL_KIRKWOOD + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_370 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_XP + bool + select PINCTRL_MVEBU + +endif diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile new file mode 100644 index 00000000000..37c253297af --- /dev/null +++ b/drivers/pinctrl/mvebu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o +obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o +obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o +obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o +obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o diff --git a/drivers/pinctrl/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c index c907647de6a..c907647de6a 100644 --- a/drivers/pinctrl/pinctrl-armada-370.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c diff --git a/drivers/pinctrl/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c index 40bd52a46b4..40bd52a46b4 100644 --- a/drivers/pinctrl/pinctrl-armada-xp.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c diff --git a/drivers/pinctrl/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index ffe74b27d66..40c9c3eecd9 100644 --- a/drivers/pinctrl/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c @@ -22,22 +22,22 @@ #include "pinctrl-mvebu.h" -#define DOVE_SB_REGS_VIRT_BASE 0xfde00000 -#define DOVE_MPP_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xd0200) +#define DOVE_SB_REGS_VIRT_BASE IOMEM(0xfde00000) +#define DOVE_MPP_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0200) #define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10) #define DOVE_AU0_AC97_SEL BIT(16) -#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE | 0xe802C) +#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C) #define DOVE_TWSI_ENABLE_OPTION1 BIT(7) -#define DOVE_GLOBAL_CONFIG_2 (DOVE_SB_REGS_VIRT_BASE | 0xe8030) +#define DOVE_GLOBAL_CONFIG_2 (DOVE_SB_REGS_VIRT_BASE + 0xe8030) #define DOVE_TWSI_ENABLE_OPTION2 BIT(20) #define DOVE_TWSI_ENABLE_OPTION3 BIT(21) #define DOVE_TWSI_OPTION3_GPIO BIT(22) -#define DOVE_SSP_CTRL_STATUS_1 (DOVE_SB_REGS_VIRT_BASE | 0xe8034) +#define DOVE_SSP_CTRL_STATUS_1 (DOVE_SB_REGS_VIRT_BASE + 0xe8034) #define DOVE_SSP_ON_AU1 BIT(0) -#define DOVE_MPP_GENERAL_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xe803c) +#define DOVE_MPP_GENERAL_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xe803c) #define DOVE_AU1_SPDIFO_GPIO_EN BIT(1) #define DOVE_NAND_GPIO_EN BIT(0) -#define DOVE_GPIO_LO_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xd0400) +#define DOVE_GPIO_LO_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0400) #define DOVE_MPP_CTRL4_VIRT_BASE (DOVE_GPIO_LO_VIRT_BASE + 0x40) #define DOVE_SPI_GPIO_SEL BIT(5) #define DOVE_UART1_GPIO_SEL BIT(4) @@ -234,6 +234,14 @@ static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl, unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE); unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2); + /* + * clear all audio1 related bits before configure + */ + gcfg2 &= ~DOVE_TWSI_OPTION3_GPIO; + gmpp &= ~DOVE_AU1_SPDIFO_GPIO_EN; + sspc1 &= ~DOVE_SSP_ON_AU1; + mpp4 &= ~DOVE_AU1_GPIO_SEL; + if (config & BIT(0)) gcfg2 |= DOVE_TWSI_OPTION3_GPIO; if (config & BIT(1)) diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c new file mode 100644 index 00000000000..fa6ce31c94d --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c @@ -0,0 +1,484 @@ +/* + * Marvell Kirkwood pinctrl driver based on mvebu pinctrl core + * + * Author: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-mvebu.h" + +#define V(f6180, f6190, f6192, f6281, f6282, dx4122) \ + ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \ + (f6281 << 3) | (f6282 << 4) | (dx4122 << 5)) + +enum kirkwood_variant { + VARIANT_MV88F6180 = V(1, 0, 0, 0, 0, 0), + VARIANT_MV88F6190 = V(0, 1, 0, 0, 0, 0), + VARIANT_MV88F6192 = V(0, 0, 1, 0, 0, 0), + VARIANT_MV88F6281 = V(0, 0, 0, 1, 0, 0), + VARIANT_MV88F6282 = V(0, 0, 0, 0, 1, 0), + VARIANT_MV98DX4122 = V(0, 0, 0, 0, 0, 1), +}; + +static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1))), + MPP_MODE(1, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1))), + MPP_MODE(2, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1))), + MPP_MODE(3, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1))), + MPP_MODE(4, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0))), + MPP_MODE(5, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(6, + MPP_VAR_FUNCTION(0x0, "sysrst", "out", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "spi", "mosi", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "ptp", "trig", V(1, 1, 1, 1, 0, 0))), + MPP_MODE(7, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(8, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0))), + MPP_MODE(9, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0))), + MPP_MODE(10, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0, 0))), + MPP_MODE(11, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0))), + MPP_MODE(12, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1, 0)), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(13, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(14, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0))), + MPP_MODE(15, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(16, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0))), + MPP_MODE(17, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(18, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(19, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1, 1))), + MPP_MODE(20, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 0, 0, 0, 0, 0))), + MPP_MODE(21, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(22, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(23, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(24, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(25, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(26, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(27, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(28, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(29, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(30, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(31, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(32, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(33, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(34, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(35, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 1, 1, 1, 1, 0))), + MPP_MODE(36, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(37, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(38, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(39, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(40, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(41, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(42, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(43, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(44, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(45, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(46, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(47, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(48, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1, 0))), + MPP_MODE(49, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 1)), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1, 0)), + MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1, 0))), +}; + +static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = { + MPP_REG_CTRL(0, 29), +}; + +static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 30), +}; + +static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = { + MPP_REG_CTRL(0, 35), +}; + +static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 4), +}; + +static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = { + MPP_REG_CTRL(0, 49), +}; + +static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 18), +}; + +static struct mvebu_pinctrl_soc_info mv88f6180_info = { + .variant = VARIANT_MV88F6180, + .controls = mv88f6180_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f6180_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f6180_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f6180_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6190_info = { + .variant = VARIANT_MV88F6190, + .controls = mv88f619x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f619x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6192_info = { + .variant = VARIANT_MV88F6192, + .controls = mv88f619x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f619x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6281_info = { + .variant = VARIANT_MV88F6281, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6282_info = { + .variant = VARIANT_MV88F6282, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv98dx4122_info = { + .variant = VARIANT_MV98DX4122, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + +static struct of_device_id kirkwood_pinctrl_of_match[] __devinitdata = { + { .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info }, + { .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info }, + { .compatible = "marvell,88f6192-pinctrl", .data = &mv88f6192_info }, + { .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info }, + { .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info }, + { .compatible = "marvell,98dx4122-pinctrl", .data = &mv98dx4122_info }, + { } +}; + +static int __devinit kirkwood_pinctrl_probe(struct platform_device *pdev) +{ + const struct of_device_id *match = + of_match_device(kirkwood_pinctrl_of_match, &pdev->dev); + pdev->dev.platform_data = match->data; + return mvebu_pinctrl_probe(pdev); +} + +static int __devexit kirkwood_pinctrl_remove(struct platform_device *pdev) +{ + return mvebu_pinctrl_remove(pdev); +} + +static struct platform_driver kirkwood_pinctrl_driver = { + .driver = { + .name = "kirkwood-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(kirkwood_pinctrl_of_match), + }, + .probe = kirkwood_pinctrl_probe, + .remove = __devexit_p(kirkwood_pinctrl_remove), +}; + +module_platform_driver(kirkwood_pinctrl_driver); + +MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>"); +MODULE_DESCRIPTION("Marvell Kirkwood pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index 8e6266c6249..6c44b7e8964 100644 --- a/drivers/pinctrl/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -24,7 +24,6 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> -#include "core.h" #include "pinctrl-mvebu.h" #define MPPS_PER_REG 8 diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h index 90bd3beee86..90bd3beee86 100644 --- a/drivers/pinctrl/pinctrl-mvebu.h +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 21362f48d37..19fab68a9fb 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -40,46 +40,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { static void exynos_gpio_irq_unmask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << edata->pin); + mask &= ~(1 << irqd->hwirq); writel(mask, d->virt_base + reg_mask); } static void exynos_gpio_irq_mask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask |= 1 << edata->pin; + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); } static void exynos_gpio_irq_ack(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset; - writel(1 << edata->pin, d->virt_base + reg_pend); + writel(1 << irqd->hwirq, d->virt_base + reg_pend); } static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) { - struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; struct samsung_pin_ctrl *ctrl = d->ctrl; - struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); - struct samsung_pin_bank *bank = edata->bank; - unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; + unsigned int pin = irqd->hwirq; + unsigned int shift = EXYNOS_EINT_CON_LEN * pin; unsigned int con, trig_type; - unsigned long reg_con = ctrl->geint_con + edata->eint_offset; + unsigned long reg_con = ctrl->geint_con + bank->eint_offset; unsigned int mask; switch (type) { @@ -114,7 +114,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) writel(con, d->virt_base + reg_con); reg_con = bank->pctl_offset; - shift = edata->pin * bank->func_width; + shift = pin * bank->func_width; mask = (1 << bank->func_width) - 1; con = readl(d->virt_base + reg_con); @@ -136,82 +136,23 @@ static struct irq_chip exynos_gpio_irq_chip = { .irq_set_type = exynos_gpio_irq_set_type, }; -/* - * given a controller-local external gpio interrupt number, prepare the handler - * data for it. - */ -static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, - struct samsung_pinctrl_drv_data *d) -{ - struct samsung_pin_bank *bank = d->ctrl->pin_banks; - struct exynos_geint_data *eint_data; - unsigned int nr_banks = d->ctrl->nr_banks, idx; - unsigned int irq_base = 0, eint_offset = 0; - - if (hw >= d->ctrl->nr_gint) { - dev_err(d->dev, "unsupported ext-gpio interrupt\n"); - return NULL; - } - - for (idx = 0; idx < nr_banks; idx++, bank++) { - if (bank->eint_type != EINT_TYPE_GPIO) - continue; - if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) - break; - irq_base += bank->nr_pins; - eint_offset += 4; - } - - if (idx == nr_banks) { - dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); - return NULL; - } - - eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); - if (!eint_data) { - dev_err(d->dev, "no memory for eint-gpio data\n"); - return NULL; - } - - eint_data->bank = bank; - eint_data->pin = hw - irq_base; - eint_data->eint_offset = eint_offset; - return eint_data; -} - static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { - struct samsung_pinctrl_drv_data *d = h->host_data; - struct exynos_geint_data *eint_data; - - eint_data = exynos_get_eint_data(hw, d); - if (!eint_data) - return -EINVAL; + struct samsung_pin_bank *b = h->host_data; - irq_set_handler_data(virq, eint_data); - irq_set_chip_data(virq, h->host_data); + irq_set_chip_data(virq, b); irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, handle_level_irq); set_irq_flags(virq, IRQF_VALID); return 0; } -static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) -{ - struct samsung_pinctrl_drv_data *d = h->host_data; - struct exynos_geint_data *eint_data; - - eint_data = irq_get_handler_data(virq); - devm_kfree(d->dev, eint_data); -} - /* * irq domain callbacks for external gpio interrupt controller. */ static const struct irq_domain_ops exynos_gpio_irqd_ops = { .map = exynos_gpio_irq_map, - .unmap = exynos_gpio_irq_unmap, .xlate = irq_domain_xlate_twocell, }; @@ -230,7 +171,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) return IRQ_HANDLED; bank += (group - 1); - virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); + virq = irq_linear_revmap(bank->irq_domain, pin); if (!virq) return IRQ_NONE; generic_handle_irq(virq); @@ -243,8 +184,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) */ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) { + struct samsung_pin_bank *bank; struct device *dev = d->dev; unsigned int ret; + unsigned int i; if (!d->irq) { dev_err(dev, "irq number not available\n"); @@ -258,11 +201,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) return -ENXIO; } - d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, - &exynos_gpio_irqd_ops, d); - if (!d->gpio_irqd) { - dev_err(dev, "gpio irq domain allocation failed\n"); - return -ENXIO; + bank = d->ctrl->pin_banks; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_GPIO) + continue; + bank->irq_domain = irq_domain_add_linear(bank->of_node, + bank->nr_pins, &exynos_gpio_irqd_ops, bank); + if (!bank->irq_domain) { + dev_err(dev, "gpio irq domain add failed\n"); + return -ENXIO; + } } return 0; @@ -270,48 +218,46 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) static void exynos_wkup_irq_unmask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); + struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = b->drvdata; + unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask &= ~(1 << pin); + mask &= ~(1 << irqd->hwirq); writel(mask, d->virt_base + reg_mask); } static void exynos_wkup_irq_mask(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); + struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = b->drvdata; + unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; unsigned long mask; mask = readl(d->virt_base + reg_mask); - mask |= 1 << pin; + mask |= 1 << irqd->hwirq; writel(mask, d->virt_base + reg_mask); } static void exynos_wkup_irq_ack(struct irq_data *irqd) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long pend = d->ctrl->weint_pend + (bank << 2); + struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = b->drvdata; + unsigned long pend = d->ctrl->weint_pend + b->eint_offset; - writel(1 << pin, d->virt_base + pend); + writel(1 << irqd->hwirq, d->virt_base + pend); } static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) { - struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); - unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; - unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); - unsigned long reg_con = d->ctrl->weint_con + (bank << 2); + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + struct samsung_pinctrl_drv_data *d = bank->drvdata; + unsigned int pin = irqd->hwirq; + unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; unsigned long shift = EXYNOS_EINT_CON_LEN * pin; unsigned long con, trig_type; + unsigned int mask; switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -343,6 +289,16 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) con &= ~(EXYNOS_EINT_CON_MASK << shift); con |= trig_type << shift; writel(con, d->virt_base + reg_con); + + reg_con = bank->pctl_offset; + shift = pin * bank->func_width; + mask = (1 << bank->func_width) - 1; + + con = readl(d->virt_base + reg_con); + con &= ~(mask << shift); + con |= EXYNOS_EINT_FUNC << shift; + writel(con, d->virt_base + reg_con); + return 0; } @@ -361,6 +317,7 @@ static struct irq_chip exynos_wkup_irq_chip = { static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) { struct exynos_weint_data *eintd = irq_get_handler_data(irq); + struct samsung_pin_bank *bank = eintd->bank; struct irq_chip *chip = irq_get_chip(irq); int eint_irq; @@ -370,20 +327,20 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) if (chip->irq_ack) chip->irq_ack(&desc->irq_data); - eint_irq = irq_linear_revmap(eintd->domain, eintd->irq); + eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq); generic_handle_irq(eint_irq); chip->irq_unmask(&desc->irq_data); chained_irq_exit(chip, desc); } -static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, - struct irq_domain *domain) +static inline void exynos_irq_demux_eint(unsigned long pend, + struct irq_domain *domain) { unsigned int irq; while (pend) { irq = fls(pend) - 1; - generic_handle_irq(irq_find_mapping(domain, irq_base + irq)); + generic_handle_irq(irq_find_mapping(domain, irq)); pend &= ~(1 << irq); } } @@ -392,18 +349,22 @@ static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_get_chip(irq); - struct exynos_weint_data *eintd = irq_get_handler_data(irq); - struct samsung_pinctrl_drv_data *d = eintd->domain->host_data; + struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq); + struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; + struct samsung_pin_ctrl *ctrl = d->ctrl; unsigned long pend; unsigned long mask; + int i; chained_irq_enter(chip, desc); - pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8); - mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8); - exynos_irq_demux_eint(16, pend & ~mask, eintd->domain); - pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC); - mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC); - exynos_irq_demux_eint(24, pend & ~mask, eintd->domain); + + for (i = 0; i < eintd->nr_banks; ++i) { + struct samsung_pin_bank *b = eintd->banks[i]; + pend = readl(d->virt_base + ctrl->weint_pend + b->eint_offset); + mask = readl(d->virt_base + ctrl->weint_mask + b->eint_offset); + exynos_irq_demux_eint(pend & ~mask, b->irq_domain); + } + chained_irq_exit(chip, desc); } @@ -433,7 +394,11 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) struct device *dev = d->dev; struct device_node *wkup_np = NULL; struct device_node *np; + struct samsung_pin_bank *bank; struct exynos_weint_data *weint_data; + struct exynos_muxed_weint_data *muxed_data; + unsigned int muxed_banks = 0; + unsigned int i; int idx, irq; for_each_child_of_node(dev->of_node, np) { @@ -445,90 +410,124 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) if (!wkup_np) return -ENODEV; - d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint, - &exynos_wkup_irqd_ops, d); - if (!d->wkup_irqd) { - dev_err(dev, "wakeup irq domain allocation failed\n"); - return -ENXIO; - } + bank = d->ctrl->pin_banks; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_WKUP) + continue; - weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL); - if (!weint_data) { - dev_err(dev, "could not allocate memory for weint_data\n"); - return -ENOMEM; - } + bank->irq_domain = irq_domain_add_linear(bank->of_node, + bank->nr_pins, &exynos_wkup_irqd_ops, bank); + if (!bank->irq_domain) { + dev_err(dev, "wkup irq domain add failed\n"); + return -ENXIO; + } - irq = irq_of_parse_and_map(wkup_np, 16); - if (irq) { - weint_data[16].domain = d->wkup_irqd; - irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); - irq_set_handler_data(irq, &weint_data[16]); - } else { - dev_err(dev, "irq number for EINT16-32 not found\n"); - } + if (!of_find_property(bank->of_node, "interrupts", NULL)) { + bank->eint_type = EINT_TYPE_WKUP_MUX; + ++muxed_banks; + continue; + } - for (idx = 0; idx < 16; idx++) { - weint_data[idx].domain = d->wkup_irqd; - weint_data[idx].irq = idx; + weint_data = devm_kzalloc(dev, bank->nr_pins + * sizeof(*weint_data), GFP_KERNEL); + if (!weint_data) { + dev_err(dev, "could not allocate memory for weint_data\n"); + return -ENOMEM; + } - irq = irq_of_parse_and_map(wkup_np, idx); - if (irq) { + for (idx = 0; idx < bank->nr_pins; ++idx) { + irq = irq_of_parse_and_map(bank->of_node, idx); + if (!irq) { + dev_err(dev, "irq number for eint-%s-%d not found\n", + bank->name, idx); + continue; + } + weint_data[idx].irq = idx; + weint_data[idx].bank = bank; irq_set_handler_data(irq, &weint_data[idx]); irq_set_chained_handler(irq, exynos_irq_eint0_15); - } else { - dev_err(dev, "irq number for eint-%x not found\n", idx); } } + + if (!muxed_banks) + return 0; + + irq = irq_of_parse_and_map(wkup_np, 0); + if (!irq) { + dev_err(dev, "irq number for muxed EINTs not found\n"); + return 0; + } + + muxed_data = devm_kzalloc(dev, sizeof(*muxed_data) + + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL); + if (!muxed_data) { + dev_err(dev, "could not allocate memory for muxed_data\n"); + return -ENOMEM; + } + + irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); + irq_set_handler_data(irq, muxed_data); + + bank = d->ctrl->pin_banks; + idx = 0; + for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { + if (bank->eint_type != EINT_TYPE_WKUP_MUX) + continue; + + muxed_data->banks[idx++] = bank; + } + muxed_data->nr_banks = muxed_banks; + return 0; } /* pin banks of exynos4210 pin-controller 0 */ static struct samsung_pin_bank exynos4210_pin_banks0[] = { - EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"), - EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"), - EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"), - EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"), - EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"), - EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"), - EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"), - EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"), - EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"), - EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"), - EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"), - EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"), - EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"), - EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"), - EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"), - EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"), + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), + EXYNOS_PIN_BANK_EINTG(5, 0x0E0, "gpe0", 0x1c), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20), + EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2", 0x24), + EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3", 0x28), + EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4", 0x2c), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), + EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38), + EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c), }; /* pin banks of exynos4210 pin-controller 1 */ static struct samsung_pin_bank exynos4210_pin_banks1[] = { - EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"), - EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"), - EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"), - EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"), - EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"), - EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"), - EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"), - EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"), - EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"), - EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"), - EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"), - EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"), - EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"), - EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"), - EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"), - EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"), - EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"), - EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"), - EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"), - EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"), + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00), + EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04), + EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), + EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), + EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), + EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), + EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpl0", 0x18), + EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1", 0x1c), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20), + EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"), + EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"), + EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"), + EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"), + EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"), + EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"), + EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"), + EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), }; /* pin banks of exynos4210 pin-controller 2 */ static struct samsung_pin_bank exynos4210_pin_banks2[] = { - EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"), + EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"), }; /* @@ -540,9 +539,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 0 data */ .pin_banks = exynos4210_pin_banks0, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), - .base = EXYNOS4210_GPIO_A0_START, - .nr_pins = EXYNOS4210_GPIOA_NR_PINS, - .nr_gint = EXYNOS4210_GPIOA_NR_GINT, .geint_con = EXYNOS_GPIO_ECON_OFFSET, .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, @@ -553,10 +549,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 1 data */ .pin_banks = exynos4210_pin_banks1, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), - .base = EXYNOS4210_GPIOA_NR_PINS, - .nr_pins = EXYNOS4210_GPIOB_NR_PINS, - .nr_gint = EXYNOS4210_GPIOB_NR_GINT, - .nr_wint = 32, .geint_con = EXYNOS_GPIO_ECON_OFFSET, .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, @@ -571,9 +563,116 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { /* pin-controller instance 2 data */ .pin_banks = exynos4210_pin_banks2, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), - .base = EXYNOS4210_GPIOA_NR_PINS + - EXYNOS4210_GPIOB_NR_PINS, - .nr_pins = EXYNOS4210_GPIOC_NR_PINS, .label = "exynos4210-gpio-ctrl2", }, }; + +/* pin banks of exynos4x12 pin-controller 0 */ +static struct samsung_pin_bank exynos4x12_pin_banks0[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), + EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38), + EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c), + EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x40), + EXYNOS_PIN_BANK_EINTG(5, 0x260, "gpj1", 0x44), +}; + +/* pin banks of exynos4x12 pin-controller 1 */ +static struct samsung_pin_bank exynos4x12_pin_banks1[] = { + EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), + EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), + EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), + EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), + EXYNOS_PIN_BANK_EINTG(7, 0x0C0, "gpl0", 0x18), + EXYNOS_PIN_BANK_EINTG(2, 0x0E0, "gpl1", 0x1c), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20), + EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24), + EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28), + EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c), + EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30), + EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34), + EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"), + EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"), + EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"), + EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"), + EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"), + EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"), + EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"), + EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), +}; + +/* pin banks of exynos4x12 pin-controller 2 */ +static struct samsung_pin_bank exynos4x12_pin_banks2[] = { + EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), +}; + +/* pin banks of exynos4x12 pin-controller 3 */ +static struct samsung_pin_bank exynos4x12_pin_banks3[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08), + EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv3", 0x0c), + EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpv4", 0x10), +}; + +/* + * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes + * four gpio/pin-mux/pinconfig controllers. + */ +struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { + { + /* pin-controller instance 0 data */ + .pin_banks = exynos4x12_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks0), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos4x12-gpio-ctrl0", + }, { + /* pin-controller instance 1 data */ + .pin_banks = exynos4x12_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks1), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .weint_con = EXYNOS_WKUP_ECON_OFFSET, + .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, + .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .label = "exynos4x12-gpio-ctrl1", + }, { + /* pin-controller instance 2 data */ + .pin_banks = exynos4x12_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks2), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos4x12-gpio-ctrl2", + }, { + /* pin-controller instance 3 data */ + .pin_banks = exynos4x12_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks3), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos4x12-gpio-ctrl3", + }, +}; diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 31d0a06174e..0a708890d8b 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -17,125 +17,6 @@ * (at your option) any later version. */ -#define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR)) - -#define EXYNOS4210_GPIO_A0_NR (8) -#define EXYNOS4210_GPIO_A1_NR (6) -#define EXYNOS4210_GPIO_B_NR (8) -#define EXYNOS4210_GPIO_C0_NR (5) -#define EXYNOS4210_GPIO_C1_NR (5) -#define EXYNOS4210_GPIO_D0_NR (4) -#define EXYNOS4210_GPIO_D1_NR (4) -#define EXYNOS4210_GPIO_E0_NR (5) -#define EXYNOS4210_GPIO_E1_NR (8) -#define EXYNOS4210_GPIO_E2_NR (6) -#define EXYNOS4210_GPIO_E3_NR (8) -#define EXYNOS4210_GPIO_E4_NR (8) -#define EXYNOS4210_GPIO_F0_NR (8) -#define EXYNOS4210_GPIO_F1_NR (8) -#define EXYNOS4210_GPIO_F2_NR (8) -#define EXYNOS4210_GPIO_F3_NR (6) -#define EXYNOS4210_GPIO_J0_NR (8) -#define EXYNOS4210_GPIO_J1_NR (5) -#define EXYNOS4210_GPIO_K0_NR (7) -#define EXYNOS4210_GPIO_K1_NR (7) -#define EXYNOS4210_GPIO_K2_NR (7) -#define EXYNOS4210_GPIO_K3_NR (7) -#define EXYNOS4210_GPIO_L0_NR (8) -#define EXYNOS4210_GPIO_L1_NR (3) -#define EXYNOS4210_GPIO_L2_NR (8) -#define EXYNOS4210_GPIO_Y0_NR (6) -#define EXYNOS4210_GPIO_Y1_NR (4) -#define EXYNOS4210_GPIO_Y2_NR (6) -#define EXYNOS4210_GPIO_Y3_NR (8) -#define EXYNOS4210_GPIO_Y4_NR (8) -#define EXYNOS4210_GPIO_Y5_NR (8) -#define EXYNOS4210_GPIO_Y6_NR (8) -#define EXYNOS4210_GPIO_X0_NR (8) -#define EXYNOS4210_GPIO_X1_NR (8) -#define EXYNOS4210_GPIO_X2_NR (8) -#define EXYNOS4210_GPIO_X3_NR (8) -#define EXYNOS4210_GPIO_Z_NR (7) - -enum exynos4210_gpio_xa_start { - EXYNOS4210_GPIO_A0_START = 0, - EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0), - EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1), - EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B), - EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0), - EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1), - EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0), - EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1), - EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0), - EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1), - EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2), - EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3), - EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4), - EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0), - EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1), - EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2), -}; - -enum exynos4210_gpio_xb_start { - EXYNOS4210_GPIO_J0_START = 0, - EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0), - EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1), - EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0), - EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1), - EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2), - EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3), - EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0), - EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1), - EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2), - EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0), - EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1), - EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2), - EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3), - EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4), - EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5), - EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6), - EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0), - EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1), - EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2), -}; - -enum exynos4210_gpio_xc_start { - EXYNOS4210_GPIO_Z_START = 0, -}; - -#define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START -#define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START -#define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START -#define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START -#define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START -#define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START -#define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START -#define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START -#define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START -#define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START -#define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START -#define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START -#define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START -#define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START -#define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START -#define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START -#define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START -#define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START -#define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START -#define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START -#define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START -#define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START -#define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START -#define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START -#define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START -#define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START - -#define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) -#define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) -#define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3) -#define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2) -#define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z) - /* External GPIO and wakeup interrupt related definitions */ #define EXYNOS_GPIO_ECON_OFFSET 0x700 #define EXYNOS_GPIO_EMASK_OFFSET 0x900 @@ -165,11 +46,10 @@ enum exynos4210_gpio_xc_start { #define EXYNOS_EINT_MAX_PER_BANK 8 #define EXYNOS_EINT_NR_WKUP_EINT -#define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \ +#define EXYNOS_PIN_BANK_EINTN(pins, reg, id) \ { \ .pctl_offset = reg, \ - .pin_base = (__gpio##_START), \ - .nr_pins = (__gpio##_NR), \ + .nr_pins = pins, \ .func_width = 4, \ .pud_width = 2, \ .drv_width = 2, \ @@ -179,40 +59,50 @@ enum exynos4210_gpio_xc_start { .name = id \ } -#define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \ +#define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs) \ { \ .pctl_offset = reg, \ - .pin_base = (__gpio##_START), \ - .nr_pins = (__gpio##_NR), \ + .nr_pins = pins, \ .func_width = 4, \ .pud_width = 2, \ .drv_width = 2, \ .conpdn_width = 2, \ .pudpdn_width = 2, \ .eint_type = EINT_TYPE_GPIO, \ - .irq_base = (__gpio##_IRQ), \ + .eint_offset = offs, \ .name = id \ } -/** - * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. - * @bank: pin bank from which this gpio interrupt originates. - * @pin: pin number within the bank. - * @eint_offset: offset to be added to the con/pend/mask register bank base. - */ -struct exynos_geint_data { - struct samsung_pin_bank *bank; - u32 pin; - u32 eint_offset; -}; +#define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs) \ + { \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .func_width = 4, \ + .pud_width = 2, \ + .drv_width = 2, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id \ + } /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. - * @domain: irq domain representing the external wakeup interrupts * @irq: interrupt number within the domain. + * @bank: bank responsible for this interrupt */ struct exynos_weint_data { - struct irq_domain *domain; - u32 irq; + unsigned int irq; + struct samsung_pin_bank *bank; +}; + +/** + * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts + * generated by the external wakeup interrupt controller. + * @nr_banks: count of banks being part of the mux + * @banks: array of banks being part of the mux + */ +struct exynos_muxed_weint_data { + unsigned int nr_banks; + struct samsung_pin_bank *banks[]; }; diff --git a/drivers/pinctrl/pinctrl-kirkwood.c b/drivers/pinctrl/pinctrl-kirkwood.c deleted file mode 100644 index 9a74ef674a0..00000000000 --- a/drivers/pinctrl/pinctrl-kirkwood.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Marvell Kirkwood pinctrl driver based on mvebu pinctrl core - * - * Author: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/err.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/pinctrl/pinctrl.h> - -#include "pinctrl-mvebu.h" - -#define V(f6180, f6190, f6192, f6281, f6282) \ - ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \ - (f6281 << 3) | (f6282 << 4)) - -enum kirkwood_variant { - VARIANT_MV88F6180 = V(1, 0, 0, 0, 0), - VARIANT_MV88F6190 = V(0, 1, 0, 0, 0), - VARIANT_MV88F6192 = V(0, 0, 1, 0, 0), - VARIANT_MV88F6281 = V(0, 0, 0, 1, 0), - VARIANT_MV88F6282 = V(0, 0, 0, 0, 1), -}; - -static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = { - MPP_MODE(0, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1))), - MPP_MODE(1, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1))), - MPP_MODE(2, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1))), - MPP_MODE(3, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1))), - MPP_MODE(4, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0))), - MPP_MODE(5, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1))), - MPP_MODE(6, - MPP_VAR_FUNCTION(0x0, "sysrst", "out", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "spi", "mosi", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "ptp", "trig", V(1, 1, 1, 1, 0))), - MPP_MODE(7, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1))), - MPP_MODE(8, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1))), - MPP_MODE(9, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1))), - MPP_MODE(10, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0))), - MPP_MODE(11, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1))), - MPP_MODE(12, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1)), - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1))), - MPP_MODE(13, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1))), - MPP_MODE(14, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1))), - MPP_MODE(15, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1))), - MPP_MODE(16, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1))), - MPP_MODE(17, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1))), - MPP_MODE(18, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1))), - MPP_MODE(19, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1))), - MPP_MODE(20, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 0, 0, 0, 0))), - MPP_MODE(21, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1))), - MPP_MODE(22, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1))), - MPP_MODE(23, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1))), - MPP_MODE(24, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1))), - MPP_MODE(25, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1))), - MPP_MODE(26, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1))), - MPP_MODE(27, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1))), - MPP_MODE(28, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1))), - MPP_MODE(29, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1))), - MPP_MODE(30, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1))), - MPP_MODE(31, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1))), - MPP_MODE(32, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1))), - MPP_MODE(33, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1))), - MPP_MODE(34, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1))), - MPP_MODE(35, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 1, 1, 1, 1))), - MPP_MODE(36, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1))), - MPP_MODE(37, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1))), - MPP_MODE(38, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1))), - MPP_MODE(39, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1))), - MPP_MODE(40, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1))), - MPP_MODE(41, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1))), - MPP_MODE(42, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1))), - MPP_MODE(43, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1))), - MPP_MODE(44, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1))), - MPP_MODE(45, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1))), - MPP_MODE(46, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1))), - MPP_MODE(47, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1))), - MPP_MODE(48, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1))), - MPP_MODE(49, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1)), - MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1)), - MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1))), -}; - -static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = { - MPP_REG_CTRL(0, 29), -}; - -static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = { - MPP_GPIO_RANGE(0, 0, 0, 30), -}; - -static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = { - MPP_REG_CTRL(0, 35), -}; - -static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = { - MPP_GPIO_RANGE(0, 0, 0, 32), - MPP_GPIO_RANGE(1, 32, 32, 4), -}; - -static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = { - MPP_REG_CTRL(0, 49), -}; - -static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = { - MPP_GPIO_RANGE(0, 0, 0, 32), - MPP_GPIO_RANGE(1, 32, 32, 18), -}; - -static struct mvebu_pinctrl_soc_info mv88f6180_info = { - .variant = VARIANT_MV88F6180, - .controls = mv88f6180_mpp_controls, - .ncontrols = ARRAY_SIZE(mv88f6180_mpp_controls), - .modes = mv88f6xxx_mpp_modes, - .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), - .gpioranges = mv88f6180_gpio_ranges, - .ngpioranges = ARRAY_SIZE(mv88f6180_gpio_ranges), -}; - -static struct mvebu_pinctrl_soc_info mv88f6190_info = { - .variant = VARIANT_MV88F6190, - .controls = mv88f619x_mpp_controls, - .ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls), - .modes = mv88f6xxx_mpp_modes, - .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), - .gpioranges = mv88f619x_gpio_ranges, - .ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges), -}; - -static struct mvebu_pinctrl_soc_info mv88f6192_info = { - .variant = VARIANT_MV88F6192, - .controls = mv88f619x_mpp_controls, - .ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls), - .modes = mv88f6xxx_mpp_modes, - .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), - .gpioranges = mv88f619x_gpio_ranges, - .ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges), -}; - -static struct mvebu_pinctrl_soc_info mv88f6281_info = { - .variant = VARIANT_MV88F6281, - .controls = mv88f628x_mpp_controls, - .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), - .modes = mv88f6xxx_mpp_modes, - .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), - .gpioranges = mv88f628x_gpio_ranges, - .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), -}; - -static struct mvebu_pinctrl_soc_info mv88f6282_info = { - .variant = VARIANT_MV88F6282, - .controls = mv88f628x_mpp_controls, - .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), - .modes = mv88f6xxx_mpp_modes, - .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), - .gpioranges = mv88f628x_gpio_ranges, - .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), -}; - -static struct of_device_id kirkwood_pinctrl_of_match[] __devinitdata = { - { .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info }, - { .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info }, - { .compatible = "marvell,88f6192-pinctrl", .data = &mv88f6192_info }, - { .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info }, - { .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info }, - { } -}; - -static int __devinit kirkwood_pinctrl_probe(struct platform_device *pdev) -{ - const struct of_device_id *match = - of_match_device(kirkwood_pinctrl_of_match, &pdev->dev); - pdev->dev.platform_data = match->data; - return mvebu_pinctrl_probe(pdev); -} - -static int __devexit kirkwood_pinctrl_remove(struct platform_device *pdev) -{ - return mvebu_pinctrl_remove(pdev); -} - -static struct platform_driver kirkwood_pinctrl_driver = { - .driver = { - .name = "kirkwood-pinctrl", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(kirkwood_pinctrl_of_match), - }, - .probe = kirkwood_pinctrl_probe, - .remove = __devexit_p(kirkwood_pinctrl_remove), -}; - -module_platform_driver(kirkwood_pinctrl_driver); - -MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>"); -MODULE_DESCRIPTION("Marvell Kirkwood pinctrl driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 861cd5f04d5..81c9896d4f6 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/err.h> #include <linux/gpio.h> +#include <linux/irqdomain.h> #include "core.h" #include "pinctrl-samsung.h" @@ -46,6 +47,13 @@ struct pin_config { { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, }; +static unsigned int pin_base = 0; + +static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) +{ + return container_of(gc, struct samsung_pin_bank, gpio_chip); +} + /* check if the selector is a valid pin group selector */ static int samsung_get_group_count(struct pinctrl_dev *pctldev) { @@ -250,14 +258,12 @@ static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, * given a pin number that is local to a pin controller, find out the pin bank * and the register base of the pin bank. */ -static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, - void __iomem **reg, u32 *offset, +static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, + unsigned pin, void __iomem **reg, u32 *offset, struct samsung_pin_bank **bank) { - struct samsung_pinctrl_drv_data *drvdata; struct samsung_pin_bank *b; - drvdata = dev_get_drvdata(gc->dev); b = drvdata->ctrl->pin_banks; while ((pin >= b->pin_base) && @@ -292,7 +298,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, * pin function number in the config register. */ for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { - pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, + pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base, ®, &pin_offset, &bank); mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; @@ -329,10 +335,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input) { struct samsung_pin_bank *bank; + struct samsung_pinctrl_drv_data *drvdata; void __iomem *reg; u32 data, pin_offset, mask, shift; - pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); + bank = gc_to_pin_bank(range->gc); + drvdata = pinctrl_dev_get_drvdata(pctldev); + + pin_offset = offset - bank->pin_base; + reg = drvdata->virt_base + bank->pctl_offset; + mask = (1 << bank->func_width) - 1; shift = pin_offset * bank->func_width; @@ -366,7 +378,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, u32 cfg_value, cfg_reg; drvdata = pinctrl_dev_get_drvdata(pctldev); - pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, + pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, &pin_offset, &bank); switch (cfg_type) { @@ -391,6 +403,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, return -EINVAL; } + if (!width) + return -EINVAL; + mask = (1 << width) - 1; shift = pin_offset * width; data = readl(reg_base + cfg_reg); @@ -463,14 +478,16 @@ static struct pinconf_ops samsung_pinconf_ops = { /* gpiolib gpio_set callback function */ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { + struct samsung_pin_bank *bank = gc_to_pin_bank(gc); void __iomem *reg; - u32 pin_offset, data; + u32 data; + + reg = bank->drvdata->virt_base + bank->pctl_offset; - pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); data = readl(reg + DAT_REG); - data &= ~(1 << pin_offset); + data &= ~(1 << offset); if (value) - data |= 1 << pin_offset; + data |= 1 << offset; writel(data, reg + DAT_REG); } @@ -478,11 +495,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) { void __iomem *reg; - u32 pin_offset, data; + u32 data; + struct samsung_pin_bank *bank = gc_to_pin_bank(gc); + + reg = bank->drvdata->virt_base + bank->pctl_offset; - pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); data = readl(reg + DAT_REG); - data >>= pin_offset; + data >>= offset; data &= 1; return data; } @@ -510,6 +529,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, } /* + * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin + * and a virtual IRQ, if not already present. + */ +static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct samsung_pin_bank *bank = gc_to_pin_bank(gc); + unsigned int virq; + + if (!bank->irq_domain) + return -ENXIO; + + virq = irq_create_mapping(bank->irq_domain, offset); + + return (virq) ? : -ENXIO; +} + +/* * Parse the pin names listed in the 'samsung,pins' property and convert it * into a list of gpio numbers are create a pin group from it. */ @@ -597,7 +633,7 @@ static int __devinit samsung_pinctrl_parse_dt(struct platform_device *pdev, */ for_each_child_of_node(dev_np, cfg_np) { u32 function; - if (of_find_property(cfg_np, "interrupt-controller", NULL)) + if (!of_find_property(cfg_np, "samsung,pins", NULL)) continue; ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, @@ -712,12 +748,16 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev, return -EINVAL; } - drvdata->grange.name = "samsung-pctrl-gpio-range"; - drvdata->grange.id = 0; - drvdata->grange.base = drvdata->ctrl->base; - drvdata->grange.npins = drvdata->ctrl->nr_pins; - drvdata->grange.gc = drvdata->gc; - pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); + for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { + pin_bank = &drvdata->ctrl->pin_banks[bank]; + pin_bank->grange.name = pin_bank->name; + pin_bank->grange.id = bank; + pin_bank->grange.pin_base = pin_bank->pin_base; + pin_bank->grange.base = pin_bank->gpio_chip.base; + pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; + pin_bank->grange.gc = &pin_bank->gpio_chip; + pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); + } ret = samsung_pinctrl_parse_dt(pdev, drvdata); if (ret) { @@ -728,68 +768,117 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev, return 0; } +static const struct gpio_chip samsung_gpiolib_chip = { + .set = samsung_gpio_set, + .get = samsung_gpio_get, + .direction_input = samsung_gpio_direction_input, + .direction_output = samsung_gpio_direction_output, + .to_irq = samsung_gpio_to_irq, + .owner = THIS_MODULE, +}; + /* register the gpiolib interface with the gpiolib subsystem */ static int __devinit samsung_gpiolib_register(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; struct gpio_chip *gc; int ret; - - gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); - if (!gc) { - dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); - return -ENOMEM; - } - - drvdata->gc = gc; - gc->base = drvdata->ctrl->base; - gc->ngpio = drvdata->ctrl->nr_pins; - gc->dev = &pdev->dev; - gc->set = samsung_gpio_set; - gc->get = samsung_gpio_get; - gc->direction_input = samsung_gpio_direction_input; - gc->direction_output = samsung_gpio_direction_output; - gc->label = drvdata->ctrl->label; - gc->owner = THIS_MODULE; - ret = gpiochip_add(gc); - if (ret) { - dev_err(&pdev->dev, "failed to register gpio_chip %s, error " - "code: %d\n", gc->label, ret); - return ret; + int i; + + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + bank->gpio_chip = samsung_gpiolib_chip; + + gc = &bank->gpio_chip; + gc->base = ctrl->base + bank->pin_base; + gc->ngpio = bank->nr_pins; + gc->dev = &pdev->dev; + gc->of_node = bank->of_node; + gc->label = bank->name; + + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", + gc->label, ret); + goto fail; + } } return 0; + +fail: + for (--i, --bank; i >= 0; --i, --bank) + if (gpiochip_remove(&bank->gpio_chip)) + dev_err(&pdev->dev, "gpio chip %s remove failed\n", + bank->gpio_chip.label); + return ret; } /* unregister the gpiolib interface with the gpiolib subsystem */ static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev, struct samsung_pinctrl_drv_data *drvdata) { - int ret = gpiochip_remove(drvdata->gc); - if (ret) { + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; + int ret = 0; + int i; + + for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) + ret = gpiochip_remove(&bank->gpio_chip); + + if (ret) dev_err(&pdev->dev, "gpio chip remove failed\n"); - return ret; - } - return 0; + + return ret; } static const struct of_device_id samsung_pinctrl_dt_match[]; /* retrieve the soc specific data */ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( + struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { int id; const struct of_device_id *match; - const struct device_node *node = pdev->dev.of_node; + struct device_node *node = pdev->dev.of_node; + struct device_node *np; + struct samsung_pin_ctrl *ctrl; + struct samsung_pin_bank *bank; + int i; - id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); + id = of_alias_get_id(node, "pinctrl"); if (id < 0) { dev_err(&pdev->dev, "failed to get alias id\n"); return NULL; } match = of_match_node(samsung_pinctrl_dt_match, node); - return (struct samsung_pin_ctrl *)match->data + id; + ctrl = (struct samsung_pin_ctrl *)match->data + id; + + bank = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + bank->drvdata = d; + bank->pin_base = ctrl->nr_pins; + ctrl->nr_pins += bank->nr_pins; + } + + for_each_child_of_node(node, np) { + if (!of_find_property(np, "gpio-controller", NULL)) + continue; + bank = ctrl->pin_banks; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { + if (!strcmp(bank->name, np->name)) { + bank->of_node = np; + break; + } + } + } + + ctrl->base = pin_base; + pin_base += ctrl->nr_pins; + + return ctrl; } static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) @@ -805,18 +894,18 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) return -ENODEV; } - ctrl = samsung_pinctrl_get_soc_data(pdev); - if (!ctrl) { - dev_err(&pdev->dev, "driver data not available\n"); - return -EINVAL; - } - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { dev_err(dev, "failed to allocate memory for driver's " "private data\n"); return -ENOMEM; } + + ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); + if (!ctrl) { + dev_err(&pdev->dev, "driver data not available\n"); + return -EINVAL; + } drvdata->ctrl = ctrl; drvdata->dev = dev; @@ -858,6 +947,8 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) static const struct of_device_id samsung_pinctrl_dt_match[] = { { .compatible = "samsung,pinctrl-exynos4210", .data = (void *)exynos4210_pin_ctrl }, + { .compatible = "samsung,pinctrl-exynos4x12", + .data = (void *)exynos4x12_pin_ctrl }, {}, }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index b8956934cda..5addfd16e3c 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -23,6 +23,8 @@ #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/machine.h> +#include <linux/gpio.h> + /* register offsets within a pin bank */ #define DAT_REG 0x4 #define PUD_REG 0x8 @@ -64,6 +66,7 @@ enum pincfg_type { * @EINT_TYPE_NONE: bank does not support external interrupts * @EINT_TYPE_GPIO: bank supportes external gpio interrupts * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts + * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts * * Samsung GPIO controller groups all the available pins into banks. The pins * in a pin bank can support external gpio interrupts or external wakeup @@ -76,6 +79,7 @@ enum eint_type { EINT_TYPE_NONE, EINT_TYPE_GPIO, EINT_TYPE_WKUP, + EINT_TYPE_WKUP_MUX, }; /* maximum length of a pin in pin descriptor (example: "gpa0-0") */ @@ -109,8 +113,12 @@ struct samsung_pinctrl_drv_data; * @conpdn_width: width of the sleep mode function selector bin field. * @pudpdn_width: width of the sleep mode pull up/down selector bit field. * @eint_type: type of the external interrupt supported by the bank. - * @irq_base: starting controller local irq number of the bank. * @name: name to be prefixed for each pin in this pin bank. + * @of_node: OF node of the bank. + * @drvdata: link to controller driver data + * @irq_domain: IRQ domain of the bank. + * @gpio_chip: GPIO chip of the bank. + * @grange: linux gpio pin range supported by this bank. */ struct samsung_pin_bank { u32 pctl_offset; @@ -122,8 +130,13 @@ struct samsung_pin_bank { u8 conpdn_width; u8 pudpdn_width; enum eint_type eint_type; - u32 irq_base; + u32 eint_offset; char *name; + struct device_node *of_node; + struct samsung_pinctrl_drv_data *drvdata; + struct irq_domain *irq_domain; + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range grange; }; /** @@ -132,8 +145,6 @@ struct samsung_pin_bank { * @nr_banks: number of pin banks. * @base: starting system wide pin number. * @nr_pins: number of pins supported by the controller. - * @nr_gint: number of external gpio interrupts supported. - * @nr_wint: number of external wakeup interrupts supported. * @geint_con: offset of the ext-gpio controller registers. * @geint_mask: offset of the ext-gpio interrupt mask registers. * @geint_pend: offset of the ext-gpio interrupt pending registers. @@ -153,8 +164,6 @@ struct samsung_pin_ctrl { u32 base; u32 nr_pins; - u32 nr_gint; - u32 nr_wint; u32 geint_con; u32 geint_mask; @@ -183,8 +192,6 @@ struct samsung_pin_ctrl { * @nr_groups: number of such pin groups. * @pmx_functions: list of pin functions available to the driver. * @nr_function: number of such pin functions. - * @gc: gpio_chip instance registered with gpiolib. - * @grange: linux gpio pin range supported by this controller. */ struct samsung_pinctrl_drv_data { void __iomem *virt_base; @@ -199,12 +206,6 @@ struct samsung_pinctrl_drv_data { unsigned int nr_groups; const struct samsung_pmx_func *pmx_functions; unsigned int nr_functions; - - struct irq_domain *gpio_irqd; - struct irq_domain *wkup_irqd; - - struct gpio_chip *gc; - struct pinctrl_gpio_range grange; }; /** @@ -235,5 +236,6 @@ struct samsung_pmx_func { /* list of all exported SoC specific data */ extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; +extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; #endif /* __PINCTRL_SAMSUNG_H */ diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9301a7a95ef..0ef01ee2835 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; char const * const *groups; unsigned num_groups; int ret; const char *group; int i; - const unsigned *pins; - unsigned num_pins; if (!pmxops) { dev_err(pctldev->dev, "does not support mux function\n"); @@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, } setting->data.mux.group = ret; - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins, - &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return -ENODEV; - } - - /* Try to allocate all pins in this group, one by one */ - for (i = 0; i < num_pins; i++) { - ret = pin_request(pctldev, pins[i], map->dev_name, NULL); - if (ret) { - dev_err(pctldev->dev, - "could not request pin %d on device %s\n", - pins[i], pinctrl_dev_get_name(pctldev)); - /* On error release all taken pins */ - i--; /* this pin just failed */ - for (; i >= 0; i--) - pin_free(pctldev, pins[i], NULL); - return -ENODEV; - } - } - return 0; } void pinmux_free_setting(struct pinctrl_setting const *setting) { - struct pinctrl_dev *pctldev = setting->pctldev; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const unsigned *pins; - unsigned num_pins; - int ret; - int i; - - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, - &pins, &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return; - } - - for (i = 0; i < num_pins; i++) - pin_free(pctldev, pins[i], NULL); + /* This function is currently unused */ } int pinmux_enable_setting(struct pinctrl_setting const *setting) @@ -446,6 +402,22 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Try to allocate all pins in this group, one by one */ + for (i = 0; i < num_pins; i++) { + ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); + if (ret) { + dev_err(pctldev->dev, + "could not request pin %d on device %s\n", + pins[i], pinctrl_dev_get_name(pctldev)); + /* On error release all taken pins */ + i--; /* this pin just failed */ + for (; i >= 0; i--) + pin_free(pctldev, pins[i], NULL); + return -ENODEV; + } + } + + /* Now that we have acquired the pins, encode the mux setting */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -482,6 +454,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Flag the descs that no setting is active */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -493,6 +466,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) desc->mux_setting = NULL; } + /* And release the pins */ + for (i = 0; i < num_pins; i++) + pin_free(pctldev, pins[i], NULL); + if (ops->disable) ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group); } diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index 5d4f44f462f..b1fd6ee33c6 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -244,7 +244,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, else temp = ~muxreg->val; - val |= temp; + val |= muxreg->mask & temp; pmx_writel(pmx, val, muxreg->reg); } } diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index d6cca8c81b9..0436fc7895d 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -25,8 +25,8 @@ static const struct pinctrl_pin_desc spear1310_pins[] = { }; /* registers */ -#define PERIP_CFG 0x32C - #define MCIF_SEL_SHIFT 3 +#define PERIP_CFG 0x3B0 + #define MCIF_SEL_SHIFT 5 #define MCIF_SEL_SD (0x1 << MCIF_SEL_SHIFT) #define MCIF_SEL_CF (0x2 << MCIF_SEL_SHIFT) #define MCIF_SEL_XD (0x3 << MCIF_SEL_SHIFT) @@ -164,6 +164,10 @@ static const struct pinctrl_pin_desc spear1310_pins[] = { #define PMX_SSP0_CS0_MASK (1 << 29) #define PMX_SSP0_CS1_2_MASK (1 << 30) +#define PAD_DIRECTION_SEL_0 0x65C +#define PAD_DIRECTION_SEL_1 0x660 +#define PAD_DIRECTION_SEL_2 0x664 + /* combined macros */ #define PMX_GMII_MASK (PMX_GMIICLK_MASK | \ PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK | \ @@ -237,6 +241,10 @@ static struct spear_muxreg i2c0_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_I2C0_MASK, .val = PMX_I2C0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_I2C0_MASK, + .val = PMX_I2C0_MASK, }, }; @@ -269,6 +277,10 @@ static struct spear_muxreg ssp0_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_SSP0_MASK, .val = PMX_SSP0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_SSP0_MASK, + .val = PMX_SSP0_MASK, }, }; @@ -294,6 +306,10 @@ static struct spear_muxreg ssp0_cs0_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_SSP0_CS0_MASK, .val = PMX_SSP0_CS0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_SSP0_CS0_MASK, + .val = PMX_SSP0_CS0_MASK, }, }; @@ -319,6 +335,10 @@ static struct spear_muxreg ssp0_cs1_2_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_SSP0_CS1_2_MASK, .val = PMX_SSP0_CS1_2_MASK, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_SSP0_CS1_2_MASK, + .val = PMX_SSP0_CS1_2_MASK, }, }; @@ -352,6 +372,10 @@ static struct spear_muxreg i2s0_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_I2S0_MASK, .val = PMX_I2S0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_I2S0_MASK, + .val = PMX_I2S0_MASK, }, }; @@ -384,6 +408,10 @@ static struct spear_muxreg i2s1_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_I2S1_MASK, .val = PMX_I2S1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_I2S1_MASK, + .val = PMX_I2S1_MASK, }, }; @@ -418,6 +446,10 @@ static struct spear_muxreg clcd_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_CLCD1_MASK, .val = PMX_CLCD1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_CLCD1_MASK, + .val = PMX_CLCD1_MASK, }, }; @@ -443,6 +475,10 @@ static struct spear_muxreg clcd_high_res_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_CLCD2_MASK, .val = PMX_CLCD2_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_CLCD2_MASK, + .val = PMX_CLCD2_MASK, }, }; @@ -461,7 +497,7 @@ static struct spear_pingroup clcd_high_res_pingroup = { .nmodemuxs = ARRAY_SIZE(clcd_high_res_modemux), }; -static const char *const clcd_grps[] = { "clcd_grp", "clcd_high_res" }; +static const char *const clcd_grps[] = { "clcd_grp", "clcd_high_res_grp" }; static struct spear_function clcd_function = { .name = "clcd", .groups = clcd_grps, @@ -479,6 +515,14 @@ static struct spear_muxreg arm_gpio_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_EGPIO_1_GRP_MASK, .val = PMX_EGPIO_1_GRP_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_EGPIO_0_GRP_MASK, + .val = PMX_EGPIO_0_GRP_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_EGPIO_1_GRP_MASK, + .val = PMX_EGPIO_1_GRP_MASK, }, }; @@ -511,6 +555,10 @@ static struct spear_muxreg smi_2_chips_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_SMI_MASK, .val = PMX_SMI_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_SMI_MASK, + .val = PMX_SMI_MASK, }, }; @@ -539,6 +587,14 @@ static struct spear_muxreg smi_4_chips_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK, .val = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_SMI_MASK, + .val = PMX_SMI_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK, + .val = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK, }, }; @@ -573,6 +629,10 @@ static struct spear_muxreg gmii_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_GMII_MASK, .val = PMX_GMII_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_GMII_MASK, + .val = PMX_GMII_MASK, }, }; @@ -615,6 +675,18 @@ static struct spear_muxreg rgmii_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_RGMII_REG2_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_RGMII_REG0_MASK, + .val = PMX_RGMII_REG0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_RGMII_REG1_MASK, + .val = PMX_RGMII_REG1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_RGMII_REG2_MASK, + .val = PMX_RGMII_REG2_MASK, }, }; @@ -649,6 +721,10 @@ static struct spear_muxreg smii_0_1_2_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_SMII_0_1_2_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_SMII_0_1_2_MASK, + .val = PMX_SMII_0_1_2_MASK, }, }; @@ -681,6 +757,10 @@ static struct spear_muxreg ras_mii_txclk_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_NFCE2_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_NFCE2_MASK, + .val = PMX_NFCE2_MASK, }, }; @@ -721,6 +801,14 @@ static struct spear_muxreg nand_8bit_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_NAND8BIT_1_MASK, .val = PMX_NAND8BIT_1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_NAND8BIT_0_MASK, + .val = PMX_NAND8BIT_0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_NAND8BIT_1_MASK, + .val = PMX_NAND8BIT_1_MASK, }, }; @@ -747,6 +835,10 @@ static struct spear_muxreg nand_16bit_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_NAND16BIT_1_MASK, .val = PMX_NAND16BIT_1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_NAND16BIT_1_MASK, + .val = PMX_NAND16BIT_1_MASK, }, }; @@ -772,6 +864,10 @@ static struct spear_muxreg nand_4_chips_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_NAND_4CHIPS_MASK, .val = PMX_NAND_4CHIPS_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_NAND_4CHIPS_MASK, + .val = PMX_NAND_4CHIPS_MASK, }, }; @@ -833,6 +929,10 @@ static struct spear_muxreg keyboard_rowcol6_8_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_KBD_ROWCOL68_MASK, .val = PMX_KBD_ROWCOL68_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_KBD_ROWCOL68_MASK, + .val = PMX_KBD_ROWCOL68_MASK, }, }; @@ -866,6 +966,10 @@ static struct spear_muxreg uart0_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_UART0_MASK, .val = PMX_UART0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_UART0_MASK, + .val = PMX_UART0_MASK, }, }; @@ -891,6 +995,10 @@ static struct spear_muxreg uart0_modem_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_UART0_MODEM_MASK, .val = PMX_UART0_MODEM_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_UART0_MODEM_MASK, + .val = PMX_UART0_MODEM_MASK, }, }; @@ -923,6 +1031,10 @@ static struct spear_muxreg gpt0_tmr0_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_GPT0_TMR0_MASK, .val = PMX_GPT0_TMR0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_GPT0_TMR0_MASK, + .val = PMX_GPT0_TMR0_MASK, }, }; @@ -948,6 +1060,10 @@ static struct spear_muxreg gpt0_tmr1_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_GPT0_TMR1_MASK, .val = PMX_GPT0_TMR1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_GPT0_TMR1_MASK, + .val = PMX_GPT0_TMR1_MASK, }, }; @@ -980,6 +1096,10 @@ static struct spear_muxreg gpt1_tmr0_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_GPT1_TMR0_MASK, .val = PMX_GPT1_TMR0_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_GPT1_TMR0_MASK, + .val = PMX_GPT1_TMR0_MASK, }, }; @@ -1005,6 +1125,10 @@ static struct spear_muxreg gpt1_tmr1_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_GPT1_TMR1_MASK, .val = PMX_GPT1_TMR1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_GPT1_TMR1_MASK, + .val = PMX_GPT1_TMR1_MASK, }, }; @@ -1049,6 +1173,20 @@ static const unsigned mcif_pins[] = { 86, 87, 88, 89, 90, 91, 92, 93, 213, 214, .reg = PAD_FUNCTION_EN_2, \ .mask = PMX_MCIFALL_2_MASK, \ .val = PMX_MCIFALL_2_MASK, \ + }, { \ + .reg = PAD_DIRECTION_SEL_0, \ + .mask = PMX_MCI_DATA8_15_MASK, \ + .val = PMX_MCI_DATA8_15_MASK, \ + }, { \ + .reg = PAD_DIRECTION_SEL_1, \ + .mask = PMX_MCIFALL_1_MASK | PMX_NFWPRT1_MASK | \ + PMX_NFWPRT2_MASK, \ + .val = PMX_MCIFALL_1_MASK | PMX_NFWPRT1_MASK | \ + PMX_NFWPRT2_MASK, \ + }, { \ + .reg = PAD_DIRECTION_SEL_2, \ + .mask = PMX_MCIFALL_2_MASK, \ + .val = PMX_MCIFALL_2_MASK, \ } /* sdhci device */ @@ -1154,6 +1292,10 @@ static struct spear_muxreg touch_xy_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_TOUCH_XY_MASK, .val = PMX_TOUCH_XY_MASK, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_TOUCH_XY_MASK, + .val = PMX_TOUCH_XY_MASK, }, }; @@ -1187,6 +1329,10 @@ static struct spear_muxreg uart1_dis_i2c_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_I2C0_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_I2C0_MASK, + .val = PMX_I2C0_MASK, }, }; @@ -1213,6 +1359,12 @@ static struct spear_muxreg uart1_dis_sd_muxreg[] = { .mask = PMX_MCIDATA1_MASK | PMX_MCIDATA2_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_MCIDATA1_MASK | + PMX_MCIDATA2_MASK, + .val = PMX_MCIDATA1_MASK | + PMX_MCIDATA2_MASK, }, }; @@ -1246,6 +1398,10 @@ static struct spear_muxreg uart2_3_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_I2S0_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_I2S0_MASK, + .val = PMX_I2S0_MASK, }, }; @@ -1278,6 +1434,10 @@ static struct spear_muxreg uart4_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_I2S0_MASK | PMX_CLCD1_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_I2S0_MASK | PMX_CLCD1_MASK, + .val = PMX_I2S0_MASK | PMX_CLCD1_MASK, }, }; @@ -1310,6 +1470,10 @@ static struct spear_muxreg uart5_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_CLCD1_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_CLCD1_MASK, + .val = PMX_CLCD1_MASK, }, }; @@ -1344,6 +1508,10 @@ static struct spear_muxreg rs485_0_1_tdm_0_1_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_CLCD1_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_CLCD1_MASK, + .val = PMX_CLCD1_MASK, }, }; @@ -1376,6 +1544,10 @@ static struct spear_muxreg i2c_1_2_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_CLCD1_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_CLCD1_MASK, + .val = PMX_CLCD1_MASK, }, }; @@ -1409,6 +1581,10 @@ static struct spear_muxreg i2c3_dis_smi_clcd_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_CLCD1_MASK | PMX_SMI_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_CLCD1_MASK | PMX_SMI_MASK, + .val = PMX_CLCD1_MASK | PMX_SMI_MASK, }, }; @@ -1435,6 +1611,10 @@ static struct spear_muxreg i2c3_dis_sd_i2s0_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_I2S1_MASK | PMX_MCIDATA3_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_I2S1_MASK | PMX_MCIDATA3_MASK, + .val = PMX_I2S1_MASK | PMX_MCIDATA3_MASK, }, }; @@ -1469,6 +1649,10 @@ static struct spear_muxreg i2c_4_5_dis_smi_muxreg[] = { .reg = PAD_FUNCTION_EN_0, .mask = PMX_SMI_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_SMI_MASK, + .val = PMX_SMI_MASK, }, }; @@ -1499,6 +1683,14 @@ static struct spear_muxreg i2c4_dis_sd_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_MCIDATA5_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_MCIDATA4_MASK, + .val = PMX_MCIDATA4_MASK, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCIDATA5_MASK, + .val = PMX_MCIDATA5_MASK, }, }; @@ -1526,6 +1718,12 @@ static struct spear_muxreg i2c5_dis_sd_muxreg[] = { .mask = PMX_MCIDATA6_MASK | PMX_MCIDATA7_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCIDATA6_MASK | + PMX_MCIDATA7_MASK, + .val = PMX_MCIDATA6_MASK | + PMX_MCIDATA7_MASK, }, }; @@ -1560,6 +1758,10 @@ static struct spear_muxreg i2c_6_7_dis_kbd_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_KBD_ROWCOL25_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_KBD_ROWCOL25_MASK, + .val = PMX_KBD_ROWCOL25_MASK, }, }; @@ -1587,6 +1789,12 @@ static struct spear_muxreg i2c6_dis_sd_muxreg[] = { .mask = PMX_MCIIORDRE_MASK | PMX_MCIIOWRWE_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCIIORDRE_MASK | + PMX_MCIIOWRWE_MASK, + .val = PMX_MCIIORDRE_MASK | + PMX_MCIIOWRWE_MASK, }, }; @@ -1613,6 +1821,12 @@ static struct spear_muxreg i2c7_dis_sd_muxreg[] = { .mask = PMX_MCIRESETCF_MASK | PMX_MCICS0CE_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCIRESETCF_MASK | + PMX_MCICS0CE_MASK, + .val = PMX_MCIRESETCF_MASK | + PMX_MCICS0CE_MASK, }, }; @@ -1651,6 +1865,14 @@ static struct spear_muxreg can0_dis_nor_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_NFRSTPWDWN3_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_NFRSTPWDWN2_MASK, + .val = PMX_NFRSTPWDWN2_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_NFRSTPWDWN3_MASK, + .val = PMX_NFRSTPWDWN3_MASK, }, }; @@ -1677,6 +1899,10 @@ static struct spear_muxreg can0_dis_sd_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_MCICFINTR_MASK | PMX_MCIIORDY_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCICFINTR_MASK | PMX_MCIIORDY_MASK, + .val = PMX_MCICFINTR_MASK | PMX_MCIIORDY_MASK, }, }; @@ -1711,6 +1937,10 @@ static struct spear_muxreg can1_dis_sd_muxreg[] = { .reg = PAD_FUNCTION_EN_2, .mask = PMX_MCICS1_MASK | PMX_MCIDMAACK_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCICS1_MASK | PMX_MCIDMAACK_MASK, + .val = PMX_MCICS1_MASK | PMX_MCIDMAACK_MASK, }, }; @@ -1737,6 +1967,10 @@ static struct spear_muxreg can1_dis_kbd_muxreg[] = { .reg = PAD_FUNCTION_EN_1, .mask = PMX_KBD_ROWCOL25_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_KBD_ROWCOL25_MASK, + .val = PMX_KBD_ROWCOL25_MASK, }, }; @@ -1763,29 +1997,64 @@ static struct spear_function can1_function = { .ngroups = ARRAY_SIZE(can1_grps), }; -/* Pad multiplexing for pci device */ -static const unsigned pci_sata_pins[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 18, +/* Pad multiplexing for (ras-ip) pci device */ +static const unsigned pci_pins[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 }; -#define PCI_SATA_MUXREG \ - { \ - .reg = PAD_FUNCTION_EN_0, \ - .mask = PMX_MCI_DATA8_15_MASK, \ - .val = 0, \ - }, { \ - .reg = PAD_FUNCTION_EN_1, \ - .mask = PMX_PCI_REG1_MASK, \ - .val = 0, \ - }, { \ - .reg = PAD_FUNCTION_EN_2, \ - .mask = PMX_PCI_REG2_MASK, \ - .val = 0, \ - } -/* pad multiplexing for pcie0 device */ +static struct spear_muxreg pci_muxreg[] = { + { + .reg = PAD_FUNCTION_EN_0, + .mask = PMX_MCI_DATA8_15_MASK, + .val = 0, + }, { + .reg = PAD_FUNCTION_EN_1, + .mask = PMX_PCI_REG1_MASK, + .val = 0, + }, { + .reg = PAD_FUNCTION_EN_2, + .mask = PMX_PCI_REG2_MASK, + .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_0, + .mask = PMX_MCI_DATA8_15_MASK, + .val = PMX_MCI_DATA8_15_MASK, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_PCI_REG1_MASK, + .val = PMX_PCI_REG1_MASK, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_PCI_REG2_MASK, + .val = PMX_PCI_REG2_MASK, + }, +}; + +static struct spear_modemux pci_modemux[] = { + { + .muxregs = pci_muxreg, + .nmuxregs = ARRAY_SIZE(pci_muxreg), + }, +}; + +static struct spear_pingroup pci_pingroup = { + .name = "pci_grp", + .pins = pci_pins, + .npins = ARRAY_SIZE(pci_pins), + .modemuxs = pci_modemux, + .nmodemuxs = ARRAY_SIZE(pci_modemux), +}; + +static const char *const pci_grps[] = { "pci_grp" }; +static struct spear_function pci_function = { + .name = "pci", + .groups = pci_grps, + .ngroups = ARRAY_SIZE(pci_grps), +}; + +/* pad multiplexing for (fix-part) pcie0 device */ static struct spear_muxreg pcie0_muxreg[] = { - PCI_SATA_MUXREG, { .reg = PCIE_SATA_CFG, .mask = PCIE_CFG_VAL(0), @@ -1802,15 +2071,12 @@ static struct spear_modemux pcie0_modemux[] = { static struct spear_pingroup pcie0_pingroup = { .name = "pcie0_grp", - .pins = pci_sata_pins, - .npins = ARRAY_SIZE(pci_sata_pins), .modemuxs = pcie0_modemux, .nmodemuxs = ARRAY_SIZE(pcie0_modemux), }; -/* pad multiplexing for pcie1 device */ +/* pad multiplexing for (fix-part) pcie1 device */ static struct spear_muxreg pcie1_muxreg[] = { - PCI_SATA_MUXREG, { .reg = PCIE_SATA_CFG, .mask = PCIE_CFG_VAL(1), @@ -1827,15 +2093,12 @@ static struct spear_modemux pcie1_modemux[] = { static struct spear_pingroup pcie1_pingroup = { .name = "pcie1_grp", - .pins = pci_sata_pins, - .npins = ARRAY_SIZE(pci_sata_pins), .modemuxs = pcie1_modemux, .nmodemuxs = ARRAY_SIZE(pcie1_modemux), }; -/* pad multiplexing for pcie2 device */ +/* pad multiplexing for (fix-part) pcie2 device */ static struct spear_muxreg pcie2_muxreg[] = { - PCI_SATA_MUXREG, { .reg = PCIE_SATA_CFG, .mask = PCIE_CFG_VAL(2), @@ -1852,22 +2115,20 @@ static struct spear_modemux pcie2_modemux[] = { static struct spear_pingroup pcie2_pingroup = { .name = "pcie2_grp", - .pins = pci_sata_pins, - .npins = ARRAY_SIZE(pci_sata_pins), .modemuxs = pcie2_modemux, .nmodemuxs = ARRAY_SIZE(pcie2_modemux), }; -static const char *const pci_grps[] = { "pcie0_grp", "pcie1_grp", "pcie2_grp" }; -static struct spear_function pci_function = { - .name = "pci", - .groups = pci_grps, - .ngroups = ARRAY_SIZE(pci_grps), +static const char *const pcie_grps[] = { "pcie0_grp", "pcie1_grp", "pcie2_grp" +}; +static struct spear_function pcie_function = { + .name = "pci_express", + .groups = pcie_grps, + .ngroups = ARRAY_SIZE(pcie_grps), }; /* pad multiplexing for sata0 device */ static struct spear_muxreg sata0_muxreg[] = { - PCI_SATA_MUXREG, { .reg = PCIE_SATA_CFG, .mask = SATA_CFG_VAL(0), @@ -1884,15 +2145,12 @@ static struct spear_modemux sata0_modemux[] = { static struct spear_pingroup sata0_pingroup = { .name = "sata0_grp", - .pins = pci_sata_pins, - .npins = ARRAY_SIZE(pci_sata_pins), .modemuxs = sata0_modemux, .nmodemuxs = ARRAY_SIZE(sata0_modemux), }; /* pad multiplexing for sata1 device */ static struct spear_muxreg sata1_muxreg[] = { - PCI_SATA_MUXREG, { .reg = PCIE_SATA_CFG, .mask = SATA_CFG_VAL(1), @@ -1909,15 +2167,12 @@ static struct spear_modemux sata1_modemux[] = { static struct spear_pingroup sata1_pingroup = { .name = "sata1_grp", - .pins = pci_sata_pins, - .npins = ARRAY_SIZE(pci_sata_pins), .modemuxs = sata1_modemux, .nmodemuxs = ARRAY_SIZE(sata1_modemux), }; /* pad multiplexing for sata2 device */ static struct spear_muxreg sata2_muxreg[] = { - PCI_SATA_MUXREG, { .reg = PCIE_SATA_CFG, .mask = SATA_CFG_VAL(2), @@ -1934,8 +2189,6 @@ static struct spear_modemux sata2_modemux[] = { static struct spear_pingroup sata2_pingroup = { .name = "sata2_grp", - .pins = pci_sata_pins, - .npins = ARRAY_SIZE(pci_sata_pins), .modemuxs = sata2_modemux, .nmodemuxs = ARRAY_SIZE(sata2_modemux), }; @@ -1957,6 +2210,14 @@ static struct spear_muxreg ssp1_dis_kbd_muxreg[] = { PMX_KBD_COL0_MASK | PMX_NFIO8_15_MASK | PMX_NFCE1_MASK | PMX_NFCE2_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_1, + .mask = PMX_KBD_ROWCOL25_MASK | PMX_KBD_COL1_MASK | + PMX_KBD_COL0_MASK | PMX_NFIO8_15_MASK | PMX_NFCE1_MASK | + PMX_NFCE2_MASK, + .val = PMX_KBD_ROWCOL25_MASK | PMX_KBD_COL1_MASK | + PMX_KBD_COL0_MASK | PMX_NFIO8_15_MASK | PMX_NFCE1_MASK | + PMX_NFCE2_MASK, }, }; @@ -1983,6 +2244,12 @@ static struct spear_muxreg ssp1_dis_sd_muxreg[] = { .mask = PMX_MCIADDR0ALE_MASK | PMX_MCIADDR2_MASK | PMX_MCICECF_MASK | PMX_MCICEXD_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCIADDR0ALE_MASK | PMX_MCIADDR2_MASK | + PMX_MCICECF_MASK | PMX_MCICEXD_MASK, + .val = PMX_MCIADDR0ALE_MASK | PMX_MCIADDR2_MASK | + PMX_MCICECF_MASK | PMX_MCICEXD_MASK, }, }; @@ -2017,6 +2284,12 @@ static struct spear_muxreg gpt64_muxreg[] = { .mask = PMX_MCICDCF1_MASK | PMX_MCICDCF2_MASK | PMX_MCICDXD_MASK | PMX_MCILEDS_MASK, .val = 0, + }, { + .reg = PAD_DIRECTION_SEL_2, + .mask = PMX_MCICDCF1_MASK | PMX_MCICDCF2_MASK | PMX_MCICDXD_MASK + | PMX_MCILEDS_MASK, + .val = PMX_MCICDCF1_MASK | PMX_MCICDCF2_MASK | PMX_MCICDXD_MASK + | PMX_MCILEDS_MASK, }, }; @@ -2093,6 +2366,7 @@ static struct spear_pingroup *spear1310_pingroups[] = { &can0_dis_sd_pingroup, &can1_dis_sd_pingroup, &can1_dis_kbd_pingroup, + &pci_pingroup, &pcie0_pingroup, &pcie1_pingroup, &pcie2_pingroup, @@ -2138,6 +2412,7 @@ static struct spear_function *spear1310_functions[] = { &can0_function, &can1_function, &pci_function, + &pcie_function, &sata_function, &ssp1_function, &gpt64_function, diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c index a0eb057e55b..0606b8cf3f2 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1340.c +++ b/drivers/pinctrl/spear/pinctrl-spear1340.c @@ -213,7 +213,7 @@ static const struct pinctrl_pin_desc spear1340_pins[] = { * Pad multiplexing for making all pads as gpio's. This is done to override the * values passed from bootloader and start from scratch. */ -static const unsigned pads_as_gpio_pins[] = { 251 }; +static const unsigned pads_as_gpio_pins[] = { 12, 88, 89, 251 }; static struct spear_muxreg pads_as_gpio_muxreg[] = { { .reg = PAD_FUNCTION_EN_1, @@ -1692,7 +1692,43 @@ static struct spear_pingroup clcd_pingroup = { .nmodemuxs = ARRAY_SIZE(clcd_modemux), }; -static const char *const clcd_grps[] = { "clcd_grp" }; +/* Disable cld runtime to save panel damage */ +static struct spear_muxreg clcd_sleep_muxreg[] = { + { + .reg = PAD_SHARED_IP_EN_1, + .mask = ARM_TRACE_MASK | MIPHY_DBG_MASK, + .val = 0, + }, { + .reg = PAD_FUNCTION_EN_5, + .mask = CLCD_REG4_MASK | CLCD_AND_ARM_TRACE_REG4_MASK, + .val = 0x0, + }, { + .reg = PAD_FUNCTION_EN_6, + .mask = CLCD_AND_ARM_TRACE_REG5_MASK, + .val = 0x0, + }, { + .reg = PAD_FUNCTION_EN_7, + .mask = CLCD_AND_ARM_TRACE_REG6_MASK, + .val = 0x0, + }, +}; + +static struct spear_modemux clcd_sleep_modemux[] = { + { + .muxregs = clcd_sleep_muxreg, + .nmuxregs = ARRAY_SIZE(clcd_sleep_muxreg), + }, +}; + +static struct spear_pingroup clcd_sleep_pingroup = { + .name = "clcd_sleep_grp", + .pins = clcd_pins, + .npins = ARRAY_SIZE(clcd_pins), + .modemuxs = clcd_sleep_modemux, + .nmodemuxs = ARRAY_SIZE(clcd_sleep_modemux), +}; + +static const char *const clcd_grps[] = { "clcd_grp", "clcd_sleep_grp" }; static struct spear_function clcd_function = { .name = "clcd", .groups = clcd_grps, @@ -1893,6 +1929,7 @@ static struct spear_pingroup *spear1340_pingroups[] = { &sdhci_pingroup, &cf_pingroup, &xd_pingroup, + &clcd_sleep_pingroup, &clcd_pingroup, &arm_trace_pingroup, &miphy_dbg_pingroup, diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index 020b1e0bdb3..ca47b0e5078 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -2240,6 +2240,10 @@ static struct spear_muxreg pwm2_pin_34_muxreg[] = { .mask = PMX_SSP_CS_MASK, .val = 0, }, { + .reg = MODE_CONFIG_REG, + .mask = PMX_PWM_MASK, + .val = PMX_PWM_MASK, + }, { .reg = IP_SEL_PAD_30_39_REG, .mask = PMX_PL_34_MASK, .val = PMX_PWM2_PL_34_VAL, @@ -2956,9 +2960,9 @@ static struct spear_function mii2_function = { }; /* Pad multiplexing for cadence mii 1_2 as smii or rmii device */ -static const unsigned smii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, +static const unsigned rmii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }; -static const unsigned rmii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 }; +static const unsigned smii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 }; static struct spear_muxreg mii0_1_muxreg[] = { { .reg = PMX_CONFIG_REG, diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.h b/drivers/pinctrl/spear/pinctrl-spear3xx.h index 31f44347f17..7860b36053c 100644 --- a/drivers/pinctrl/spear/pinctrl-spear3xx.h +++ b/drivers/pinctrl/spear/pinctrl-spear3xx.h @@ -15,6 +15,7 @@ #include "pinctrl-spear.h" /* pad mux declarations */ +#define PMX_PWM_MASK (1 << 16) #define PMX_FIRDA_MASK (1 << 14) #define PMX_I2C_MASK (1 << 13) #define PMX_SSP_CS_MASK (1 << 12) diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 49a89397231..b1d956d81f0 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -335,6 +335,9 @@ config AB8500_BATTERY_THERM_ON_BATCTRL help Say Y to enable battery temperature measurements using thermistor connected on BATCTRL ADC. + +source "drivers/power/reset/Kconfig" + endif # POWER_SUPPLY source "drivers/power/avs/Kconfig" diff --git a/drivers/power/Makefile b/drivers/power/Makefile index b949cf85590..f1d99f4a0bc 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o +obj-$(CONFIG_POWER_RESET) += reset/ diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig new file mode 100644 index 00000000000..6461b489fb0 --- /dev/null +++ b/drivers/power/reset/Kconfig @@ -0,0 +1,15 @@ +menuconfig POWER_RESET + bool "Board level reset or power off" + help + Provides a number of drivers which either reset a complete board + or shut it down, by manipulating the main power supply on the board. + + Say Y here to enable board reset and power off + +config POWER_RESET_GPIO + bool "GPIO power-off driver" + depends on OF_GPIO && POWER_RESET + help + This driver supports turning off your board via a GPIO line. + If your board needs a GPIO high/low to power down, say Y and + create a binding in your devicetree. diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile new file mode 100644 index 00000000000..751488a4a0c --- /dev/null +++ b/drivers/power/reset/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c new file mode 100644 index 00000000000..0491e5335d0 --- /dev/null +++ b/drivers/power/reset/gpio-poweroff.c @@ -0,0 +1,129 @@ +/* + * Toggles a GPIO pin to power down a device + * + * Jamie Lentin <jm@lentin.co.uk> + * Andrew Lunn <andrew@lunn.ch> + * + * Copyright (C) 2012 Jamie Lentin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/module.h> + +/* + * Hold configuration here, cannot be more than one instance of the driver + * since pm_power_off itself is global. + */ +static int gpio_num = -1; +static int gpio_active_low; + +static void gpio_poweroff_do_poweroff(void) +{ + BUG_ON(gpio_num == -1); + + /* drive it active */ + gpio_direction_output(gpio_num, !gpio_active_low); + mdelay(100); + /* rising edge or drive inactive */ + gpio_set_value(gpio_num, gpio_active_low); + mdelay(100); + /* falling edge */ + gpio_set_value(gpio_num, !gpio_active_low); + + /* give it some time */ + mdelay(3000); + + WARN_ON(1); +} + +static int __devinit gpio_poweroff_probe(struct platform_device *pdev) +{ + enum of_gpio_flags flags; + bool input = false; + int ret; + + /* If a pm_power_off function has already been added, leave it alone */ + if (pm_power_off != NULL) { + pr_err("%s: pm_power_off function already registered", + __func__); + return -EBUSY; + } + + gpio_num = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); + if (gpio_num < 0) { + pr_err("%s: Could not get GPIO configuration: %d", + __func__, gpio_num); + return -ENODEV; + } + gpio_active_low = flags & OF_GPIO_ACTIVE_LOW; + + if (of_get_property(pdev->dev.of_node, "input", NULL)) + input = true; + + ret = gpio_request(gpio_num, "poweroff-gpio"); + if (ret) { + pr_err("%s: Could not get GPIO %d", __func__, gpio_num); + return ret; + } + if (input) { + if (gpio_direction_input(gpio_num)) { + pr_err("Could not set direction of GPIO %d to input", + gpio_num); + goto err; + } + } else { + if (gpio_direction_output(gpio_num, gpio_active_low)) { + pr_err("Could not set direction of GPIO %d", gpio_num); + goto err; + } + } + + pm_power_off = &gpio_poweroff_do_poweroff; + return 0; + +err: + gpio_free(gpio_num); + return -ENODEV; +} + +static int __devexit gpio_poweroff_remove(struct platform_device *pdev) +{ + if (gpio_num != -1) + gpio_free(gpio_num); + if (pm_power_off == &gpio_poweroff_do_poweroff) + pm_power_off = NULL; + + return 0; +} + +static const struct of_device_id of_gpio_poweroff_match[] = { + { .compatible = "gpio-poweroff", }, + {}, +}; + +static struct platform_driver gpio_poweroff_driver = { + .probe = gpio_poweroff_probe, + .remove = __devexit_p(gpio_poweroff_remove), + .driver = { + .name = "poweroff-gpio", + .owner = THIS_MODULE, + .of_match_table = of_gpio_poweroff_match, + }, +}; + +module_platform_driver(gpio_poweroff_driver); + +MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>"); +MODULE_DESCRIPTION("GPIO poweroff driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:poweroff-gpio"); diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index c17ae22567e..0c6fcb461fa 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -401,7 +401,7 @@ EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); /** * rio_map_inb_region -- Map inbound memory region. * @mport: Master port. - * @lstart: physical address of memory region to be mapped + * @local: physical address of memory region to be mapped * @rbase: RIO base address assigned to this window * @size: Size of the memory region * @rflags: Flags for mapping. diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5c4829cba6a..e872c8be080 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1381,22 +1381,14 @@ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(regulator_get_exclusive); -/** - * regulator_put - "free" the regulator source - * @regulator: regulator source - * - * Note: drivers must ensure that all regulator_enable calls made on this - * regulator source are balanced by regulator_disable calls prior to calling - * this function. - */ -void regulator_put(struct regulator *regulator) +/* Locks held by regulator_put() */ +static void _regulator_put(struct regulator *regulator) { struct regulator_dev *rdev; if (regulator == NULL || IS_ERR(regulator)) return; - mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; debugfs_remove_recursive(regulator->debugfs); @@ -1412,6 +1404,20 @@ void regulator_put(struct regulator *regulator) rdev->exclusive = 0; module_put(rdev->owner); +} + +/** + * regulator_put - "free" the regulator source + * @regulator: regulator source + * + * Note: drivers must ensure that all regulator_enable calls made on this + * regulator source are balanced by regulator_disable calls prior to calling + * this function. + */ +void regulator_put(struct regulator *regulator) +{ + mutex_lock(®ulator_list_mutex); + _regulator_put(regulator); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_put); @@ -1974,7 +1980,7 @@ int regulator_is_supported_voltage(struct regulator *regulator, if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { ret = regulator_get_voltage(regulator); if (ret >= 0) - return (min_uV >= ret && ret <= max_uV); + return (min_uV <= ret && ret <= max_uV); else return ret; } @@ -3365,7 +3371,7 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret != 0) { rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", config->ena_gpio, ret); - goto clean; + goto wash; } rdev->ena_gpio = config->ena_gpio; @@ -3445,10 +3451,11 @@ unset_supplies: scrub: if (rdev->supply) - regulator_put(rdev->supply); + _regulator_put(rdev->supply); if (rdev->ena_gpio) gpio_free(rdev->ena_gpio); kfree(rdev->constraints); +wash: device_unregister(&rdev->dev); /* device core frees rdev */ rdev = ERR_PTR(ret); diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index cd0106293a4..7304139934a 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -17,8 +17,6 @@ #include <linux/platform_device.h> #include <linux/clk.h> -#include <mach/hardware.h> - #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) #define RTC_INPUT_CLK_38400HZ (0x02 << 5) @@ -72,14 +70,38 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { #define RTC_TEST2 0x2C /* 32bit rtc test reg 2 */ #define RTC_TEST3 0x30 /* 32bit rtc test reg 3 */ +enum imx_rtc_type { + IMX1_RTC, + IMX21_RTC, +}; + struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; int irq; struct clk *clk; struct rtc_time g_rtc_alarm; + enum imx_rtc_type devtype; }; +static struct platform_device_id imx_rtc_devtype[] = { + { + .name = "imx1-rtc", + .driver_data = IMX1_RTC, + }, { + .name = "imx21-rtc", + .driver_data = IMX21_RTC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_rtc_devtype); + +static inline int is_imx1_rtc(struct rtc_plat_data *data) +{ + return data->devtype == IMX1_RTC; +} + /* * This function is used to obtain the RTC time or the alarm value in * second. @@ -278,10 +300,13 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) */ static int mxc_rtc_set_mmss(struct device *dev, unsigned long time) { + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + /* * TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only */ - if (cpu_is_mx1()) { + if (is_imx1_rtc(pdata)) { struct rtc_time tm; rtc_time_to_tm(time, &tm); @@ -360,6 +385,8 @@ static int __devinit mxc_rtc_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; + pdata->devtype = pdev->id_entry->driver_data; + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) return -EBUSY; @@ -480,6 +507,7 @@ static struct platform_driver mxc_rtc_driver = { #endif .owner = THIS_MODULE, }, + .id_table = imx_rtc_devtype, .probe = mxc_rtc_probe, .remove = __devexit_p(mxc_rtc_remove), }; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 9ffb6d5f17a..4ed343e4eb4 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -44,7 +44,6 @@ #define RAW3215_NR_CCWS 3 #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ -#define RAW3215_FIXED 1 /* 3215 console device is not be freed */ #define RAW3215_WORKING 4 /* set if a request is being worked on */ #define RAW3215_THROTTLED 8 /* set if reading is disabled */ #define RAW3215_STOPPED 16 /* set if writing is disabled */ @@ -339,8 +338,10 @@ static void raw3215_wakeup(unsigned long data) struct tty_struct *tty; tty = tty_port_tty_get(&raw->port); - tty_wakeup(tty); - tty_kref_put(tty); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } /* @@ -629,8 +630,7 @@ static void raw3215_shutdown(struct raw3215_info *raw) DECLARE_WAITQUEUE(wait, current); unsigned long flags; - if (!(raw->port.flags & ASYNC_INITIALIZED) || - (raw->flags & RAW3215_FIXED)) + if (!(raw->port.flags & ASYNC_INITIALIZED)) return; /* Wait for outstanding requests, then free irq */ spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); @@ -926,8 +926,6 @@ static int __init con3215_init(void) dev_set_drvdata(&cdev->dev, raw); cdev->handler = raw3215_irq; - raw->flags |= RAW3215_FIXED; - /* Request the console irq */ if (raw3215_startup(raw) != 0) { raw3215_free_info(raw); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 33bb4d891e1..4af3dfe70ef 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -112,9 +112,6 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); extern void css_reiterate_subchannels(void); void css_update_ssd_info(struct subchannel *sch); -#define __MAX_SUBCHANNEL 65535 -#define __MAX_SSID 3 - struct channel_subsystem { u8 cssid; int valid; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index fc916f5d731..fd3143c291c 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1424,7 +1424,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) } if (device_is_disconnected(cdev)) return IO_SCH_REPROBE; - if (cdev->online) + if (cdev->online && !cdev->private->flags.resuming) return IO_SCH_VERIFY; if (cdev->private->state == DEV_STATE_NOT_OPER) return IO_SCH_UNREG_ATTACH; @@ -1469,12 +1469,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) rc = 0; goto out_unlock; case IO_SCH_VERIFY: - if (cdev->private->flags.resuming == 1) { - if (cio_enable_subchannel(sch, (u32)(addr_t)sch)) { - ccw_device_set_notoper(cdev); - break; - } - } /* Trigger path verification. */ io_subchannel_verify(sch); rc = 0; diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 199bc679117..65d13e38803 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -125,8 +125,7 @@ int idset_is_empty(struct idset *set) void idset_add_set(struct idset *to, struct idset *from) { - int len = min(__BITOPS_WORDS(to->num_ssid * to->num_id), - __BITOPS_WORDS(from->num_ssid * from->num_id)); + int len = min(to->num_ssid * to->num_id, from->num_ssid * from->num_id); bitmap_or(to->bitmap, to->bitmap, from->bitmap, len); } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3e25d315045..4d6ba00d004 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2942,13 +2942,33 @@ static int qeth_query_ipassists_cb(struct qeth_card *card, QETH_DBF_TEXT(SETUP, 2, "qipasscb"); cmd = (struct qeth_ipa_cmd *) data; + + switch (cmd->hdr.return_code) { + case IPA_RC_NOTSUPP: + case IPA_RC_L2_UNSUPPORTED_CMD: + QETH_DBF_TEXT(SETUP, 2, "ipaunsup"); + card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS; + card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS; + return -0; + default: + if (cmd->hdr.return_code) { + QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Unhandled " + "rc=%d\n", + dev_name(&card->gdev->dev), + cmd->hdr.return_code); + return 0; + } + } + if (cmd->hdr.prot_version == QETH_PROT_IPV4) { card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported; card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; - } else { + } else if (cmd->hdr.prot_version == QETH_PROT_IPV6) { card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported; card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; - } + } else + QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Flawed LIC detected" + "\n", dev_name(&card->gdev->dev)); QETH_DBF_TEXT(SETUP, 2, "suppenbl"); QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_supported); QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_enabled); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index e67e0258aec..fddb62654b6 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -626,10 +626,13 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "doL2init"); QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card)); - rc = qeth_query_setadapterparms(card); - if (rc) { - QETH_DBF_MESSAGE(2, "could not query adapter parameters on " - "device %s: x%x\n", CARD_BUS_ID(card), rc); + if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) { + rc = qeth_query_setadapterparms(card); + if (rc) { + QETH_DBF_MESSAGE(2, "could not query adapter " + "parameters on device %s: x%x\n", + CARD_BUS_ID(card), rc); + } } if (card->info.type == QETH_CARD_TYPE_IQD || @@ -676,7 +679,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) return -ERESTARTSYS; } rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]); - if (!rc) + if (!rc || (rc == IPA_RC_L2_MAC_NOT_FOUND)) rc = qeth_l2_send_setmac(card, addr->sa_data); return rc ? -EINVAL : 0; } diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index bd4708a422c..20fd974f903 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -149,6 +149,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) int qla24xx_disable_vp(scsi_qla_host_t *vha) { + unsigned long flags; int ret; ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); @@ -156,7 +157,9 @@ qla24xx_disable_vp(scsi_qla_host_t *vha) atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); /* Remove port id from vp target map */ + spin_lock_irqsave(&vha->hw->vport_slock, flags); qlt_update_vp_map(vha, RESET_AL_PA); + spin_unlock_irqrestore(&vha->hw->vport_slock, flags); qla2x00_mark_vp_devices_dead(vha); atomic_set(&vha->vp_state, VP_FAILED); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 0e09d8f433d..62aa5584f64 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -557,6 +557,7 @@ static bool qlt_check_fcport_exist(struct scsi_qla_host *vha, int pmap_len; fc_port_t *fcport; int global_resets; + unsigned long flags; retry: global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count); @@ -625,10 +626,10 @@ retry: sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain, fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id); - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id, + (fcport->flags & FCF_CONF_COMP_SUPPORTED)); + spin_unlock_irqrestore(&ha->hardware_lock, flags); res = true; @@ -740,10 +741,9 @@ static struct qla_tgt_sess *qlt_create_sess( qlt_undelete_sess(sess); kref_get(&sess->se_sess->sess_kref); - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); + ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id, + (fcport->flags & FCF_CONF_COMP_SUPPORTED)); + if (sess->local && !local) sess->local = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -796,8 +796,7 @@ static struct qla_tgt_sess *qlt_create_sess( */ kref_get(&sess->se_sess->sess_kref); - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); + sess->conf_compl_supported = (fcport->flags & FCF_CONF_COMP_SUPPORTED); BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name)); memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name)); @@ -869,10 +868,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007, "Reappeared sess %p\n", sess); } - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); + ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id, + (fcport->flags & FCF_CONF_COMP_SUPPORTED)); } if (sess && sess->local) { diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 170af157121..bad749561ec 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -648,6 +648,7 @@ struct qla_tgt_func_tmpl { int (*check_initiator_node_acl)(struct scsi_qla_host *, unsigned char *, void *, uint8_t *, uint16_t); + void (*update_sess)(struct qla_tgt_sess *, port_id_t, uint16_t, bool); struct qla_tgt_sess *(*find_sess_by_loop_id)(struct scsi_qla_host *, const uint16_t); struct qla_tgt_sess *(*find_sess_by_s_id)(struct scsi_qla_host *, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 2358c16c4c8..3d74f2f39ae 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -237,7 +237,7 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg) struct tcm_qla2xxx_tpg, se_tpg); struct tcm_qla2xxx_lport *lport = tpg->lport; - return &lport->lport_name[0]; + return lport->lport_naa_name; } static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg) @@ -1457,6 +1457,78 @@ static int tcm_qla2xxx_check_initiator_node_acl( return 0; } +static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id, + uint16_t loop_id, bool conf_compl_supported) +{ + struct qla_tgt *tgt = sess->tgt; + struct qla_hw_data *ha = tgt->ha; + struct tcm_qla2xxx_lport *lport = ha->tgt.target_lport_ptr; + struct se_node_acl *se_nacl = sess->se_sess->se_node_acl; + struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl, + struct tcm_qla2xxx_nacl, se_node_acl); + u32 key; + + + if (sess->loop_id != loop_id || sess->s_id.b24 != s_id.b24) + pr_info("Updating session %p from port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n", + sess, + sess->port_name[0], sess->port_name[1], + sess->port_name[2], sess->port_name[3], + sess->port_name[4], sess->port_name[5], + sess->port_name[6], sess->port_name[7], + sess->loop_id, loop_id, + sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa, + s_id.b.domain, s_id.b.area, s_id.b.al_pa); + + if (sess->loop_id != loop_id) { + /* + * Because we can shuffle loop IDs around and we + * update different sessions non-atomically, we might + * have overwritten this session's old loop ID + * already, and we might end up overwriting some other + * session that will be updated later. So we have to + * be extra careful and we can't warn about those things... + */ + if (lport->lport_loopid_map[sess->loop_id].se_nacl == se_nacl) + lport->lport_loopid_map[sess->loop_id].se_nacl = NULL; + + lport->lport_loopid_map[loop_id].se_nacl = se_nacl; + + sess->loop_id = loop_id; + } + + if (sess->s_id.b24 != s_id.b24) { + key = (((u32) sess->s_id.b.domain << 16) | + ((u32) sess->s_id.b.area << 8) | + ((u32) sess->s_id.b.al_pa)); + + if (btree_lookup32(&lport->lport_fcport_map, key)) + WARN(btree_remove32(&lport->lport_fcport_map, key) != se_nacl, + "Found wrong se_nacl when updating s_id %x:%x:%x\n", + sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa); + else + WARN(1, "No lport_fcport_map entry for s_id %x:%x:%x\n", + sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa); + + key = (((u32) s_id.b.domain << 16) | + ((u32) s_id.b.area << 8) | + ((u32) s_id.b.al_pa)); + + if (btree_lookup32(&lport->lport_fcport_map, key)) { + WARN(1, "Already have lport_fcport_map entry for s_id %x:%x:%x\n", + s_id.b.domain, s_id.b.area, s_id.b.al_pa); + btree_update32(&lport->lport_fcport_map, key, se_nacl); + } else { + btree_insert32(&lport->lport_fcport_map, key, se_nacl, GFP_ATOMIC); + } + + sess->s_id = s_id; + nacl->nport_id = key; + } + + sess->conf_compl_supported = conf_compl_supported; +} + /* * Calls into tcm_qla2xxx used by qla2xxx LLD I/O path. */ @@ -1467,6 +1539,7 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = { .free_cmd = tcm_qla2xxx_free_cmd, .free_mcmd = tcm_qla2xxx_free_mcmd, .free_session = tcm_qla2xxx_free_session, + .update_sess = tcm_qla2xxx_update_sess, .check_initiator_node_acl = tcm_qla2xxx_check_initiator_node_acl, .find_sess_by_s_id = tcm_qla2xxx_find_sess_by_s_id, .find_sess_by_loop_id = tcm_qla2xxx_find_sess_by_loop_id, @@ -1534,6 +1607,7 @@ static struct se_wwn *tcm_qla2xxx_make_lport( lport->lport_wwpn = wwpn; tcm_qla2xxx_format_wwn(&lport->lport_name[0], TCM_QLA2XXX_NAMELEN, wwpn); + sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) wwpn); ret = tcm_qla2xxx_init_lport(lport); if (ret != 0) @@ -1601,6 +1675,7 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport( lport->lport_npiv_wwnn = npiv_wwnn; tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0], TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn); + sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn); /* FIXME: tcm_qla2xxx_npiv_make_lport */ ret = -ENOSYS; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 82549810335..9ba075fe978 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -61,6 +61,8 @@ struct tcm_qla2xxx_lport { u64 lport_npiv_wwnn; /* ASCII formatted WWPN for FC Target Lport */ char lport_name[TCM_QLA2XXX_NAMELEN]; + /* ASCII formatted naa WWPN for VPD page 83 etc */ + char lport_naa_name[TCM_QLA2XXX_NAMELEN]; /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */ char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN]; /* map for fc_port pointers in 24-bit FC Port ID space */ diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index b191dd54920..71fddbc60f1 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1294,26 +1294,19 @@ static struct scsi_host_template qpti_template = { static const struct of_device_id qpti_match[]; static int __devinit qpti_sbus_probe(struct platform_device *op) { - const struct of_device_id *match; - struct scsi_host_template *tpnt; struct device_node *dp = op->dev.of_node; struct Scsi_Host *host; struct qlogicpti *qpti; static int nqptis; const char *fcode; - match = of_match_device(qpti_match, &op->dev); - if (!match) - return -EINVAL; - tpnt = match->data; - /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. */ if (op->archdata.irqs[0] == 0) return -ENODEV; - host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti)); + host = scsi_host_alloc(&qpti_template, sizeof(struct qlogicpti)); if (!host) return -ENOMEM; @@ -1445,19 +1438,15 @@ static int __devexit qpti_sbus_remove(struct platform_device *op) static const struct of_device_id qpti_match[] = { { .name = "ptisp", - .data = &qpti_template, }, { .name = "PTI,ptisp", - .data = &qpti_template, }, { .name = "QLGC,isp", - .data = &qpti_template, }, { .name = "SUNW,isp", - .data = &qpti_template, }, {}, }; diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h index f2ffd963f1c..d0cafd63719 100644 --- a/drivers/staging/android/android_alarm.h +++ b/drivers/staging/android/android_alarm.h @@ -51,12 +51,10 @@ enum android_alarm_return_flags { #define ANDROID_ALARM_WAIT _IO('a', 1) #define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) -#define ALARM_IOR(c, type, size) _IOR('a', (c) | ((type) << 4), size) - /* Set alarm */ #define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) #define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) -#define ANDROID_ALARM_GET_TIME(type) ALARM_IOR(4, type, struct timespec) +#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec) #define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) #define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) #define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 094fdc366f3..97cdf0856ae 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -39,7 +39,6 @@ #include <linux/workqueue.h> #include <mach/clk.h> -#include <mach/iomap.h> #include "nvec.h" diff --git a/drivers/staging/tidspbridge/include/dspbridge/host_os.h b/drivers/staging/tidspbridge/include/dspbridge/host_os.h index 5e2f4d82d92..7f3a1db3161 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/host_os.h +++ b/drivers/staging/tidspbridge/include/dspbridge/host_os.h @@ -40,7 +40,6 @@ #include <linux/vmalloc.h> #include <linux/ioport.h> #include <linux/platform_device.h> -#include <plat/clock.h> #include <linux/clk.h> #include <plat/mailbox.h> #include <linux/pagemap.h> diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d6ce2182e67..035c2c76253 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3719,7 +3719,9 @@ restart: */ iscsit_thread_check_cpumask(conn, current, 1); - schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); + wait_event_interruptible(conn->queues_wq, + !iscsit_conn_all_queues_empty(conn) || + ts->status == ISCSI_THREAD_SET_RESET); if ((ts->status == ISCSI_THREAD_SET_RESET) || signal_pending(current)) diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 2ba9f9b9435..21048dbf7d1 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -486,6 +486,7 @@ struct iscsi_tmr_req { }; struct iscsi_conn { + wait_queue_head_t queues_wq; /* Authentication Successful for this connection */ u8 auth_complete; /* State connection is currently in */ diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index cdc8a10939c..f8dbec05d5e 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -41,6 +41,7 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn) { + init_waitqueue_head(&conn->queues_wq); INIT_LIST_HEAD(&conn->conn_list); INIT_LIST_HEAD(&conn->conn_cmd_list); INIT_LIST_HEAD(&conn->immed_queue_list); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index afd98ccd40a..1a91195ab61 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -488,7 +488,7 @@ void iscsit_add_cmd_to_immediate_queue( atomic_set(&conn->check_immediate_queue, 1); spin_unlock_bh(&conn->immed_queue_lock); - wake_up_process(conn->thread_set->tx_thread); + wake_up(&conn->queues_wq); } struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) @@ -562,7 +562,7 @@ void iscsit_add_cmd_to_response_queue( atomic_inc(&cmd->response_queue_count); spin_unlock_bh(&conn->response_queue_lock); - wake_up_process(conn->thread_set->tx_thread); + wake_up(&conn->queues_wq); } struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) @@ -616,6 +616,24 @@ static void iscsit_remove_cmd_from_response_queue( } } +bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn) +{ + bool empty; + + spin_lock_bh(&conn->immed_queue_lock); + empty = list_empty(&conn->immed_queue_list); + spin_unlock_bh(&conn->immed_queue_lock); + + if (!empty) + return empty; + + spin_lock_bh(&conn->response_queue_lock); + empty = list_empty(&conn->response_queue_list); + spin_unlock_bh(&conn->response_queue_lock); + + return empty; +} + void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) { struct iscsi_queue_req *qr, *qr_tmp; diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 44054bd3543..894d0f83792 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -25,6 +25,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_ extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8); extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *); extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *); +extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_release_cmd(struct iscsi_cmd *); extern void iscsit_free_cmd(struct iscsi_cmd *); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 015f5be27bf..c123327499a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3206,7 +3206,8 @@ static int __init target_core_init_configfs(void) if (ret < 0) goto out; - if (core_dev_setup_virtual_lun0() < 0) + ret = core_dev_setup_virtual_lun0(); + if (ret < 0) goto out; return 0; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8d774da1632..9abef9f8eb7 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -850,20 +850,20 @@ int se_dev_check_shutdown(struct se_device *dev) static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) { - u32 tmp, aligned_max_sectors; + u32 aligned_max_sectors; + u32 alignment; /* * Limit max_sectors to a PAGE_SIZE aligned value for modern * transport_allocate_data_tasks() operation. */ - tmp = rounddown((max_sectors * block_size), PAGE_SIZE); - aligned_max_sectors = (tmp / block_size); - if (max_sectors != aligned_max_sectors) { - printk(KERN_INFO "Rounding down aligned max_sectors from %u" - " to %u\n", max_sectors, aligned_max_sectors); - return aligned_max_sectors; - } + alignment = max(1ul, PAGE_SIZE / block_size); + aligned_max_sectors = rounddown(max_sectors, alignment); + + if (max_sectors != aligned_max_sectors) + pr_info("Rounding down aligned max_sectors from %u to %u\n", + max_sectors, aligned_max_sectors); - return max_sectors; + return aligned_max_sectors; } void se_dev_set_default_attribs( diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 868f8aa04f1..a6e27d967c7 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -135,6 +135,12 @@ static int sbc_emulate_verify(struct se_cmd *cmd) return 0; } +static int sbc_emulate_noop(struct se_cmd *cmd) +{ + target_complete_cmd(cmd, GOOD); + return 0; +} + static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) { return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors; @@ -531,6 +537,18 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) size = 0; cmd->execute_cmd = sbc_emulate_verify; break; + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + /* + * There are still clients out there which use these old SCSI-2 + * commands. This mainly happens when running VMs with legacy + * guest systems, connected via SCSI command pass-through to + * iSCSI targets. Make them happy and return status GOOD. + */ + size = 0; + cmd->execute_cmd = sbc_emulate_noop; + break; default: ret = spc_parse_cdb(cmd, &size); if (ret) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 9229bd9ad61..6fd434d3d7e 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -605,6 +605,8 @@ static int spc_emulate_inquiry(struct se_cmd *cmd) unsigned char buf[SE_INQUIRY_BUF]; int p, ret; + memset(buf, 0, SE_INQUIRY_BUF); + if (dev == tpg->tpg_virt_lun0.lun_se_dev) buf[0] = 0x3f; /* Not connected */ else diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 1c59a3c23b2..be75c4331a9 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -140,15 +140,15 @@ void core_tmr_abort_task( printk("ABORT_TASK: Found referenced %s task_tag: %u\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); - spin_lock_irq(&se_cmd->t_state_lock); + spin_lock(&se_cmd->t_state_lock); if (se_cmd->transport_state & CMD_T_COMPLETE) { printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag); - spin_unlock_irq(&se_cmd->t_state_lock); + spin_unlock(&se_cmd->t_state_lock); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); goto out; } se_cmd->transport_state |= CMD_T_ABORTED; - spin_unlock_irq(&se_cmd->t_state_lock); + spin_unlock(&se_cmd->t_state_lock); list_del_init(&se_cmd->se_cmd_list); kref_get(&se_cmd->cmd_kref); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c33baff86aa..9097155e9eb 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1616,7 +1616,6 @@ static void target_complete_tmr_failure(struct work_struct *work) se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; se_cmd->se_tfo->queue_tm_rsp(se_cmd); - transport_generic_free_cmd(se_cmd, 0); } /** diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c index fd03e8581af..6dd29e4ce36 100644 --- a/drivers/thermal/exynos_thermal.c +++ b/drivers/thermal/exynos_thermal.c @@ -815,7 +815,7 @@ static struct platform_device_id exynos_tmu_driver_ids[] = { }, { }, }; -MODULE_DEVICE_TABLE(platform, exynos4_tmu_driver_ids); +MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids); static inline struct exynos_tmu_platform_data *exynos_get_driver_data( struct platform_device *pdev) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index d4452716aaa..f7a1b574a30 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -210,7 +210,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) goto error_free_priv; } - zone = thermal_zone_device_register("rcar_thermal", 0, priv, + zone = thermal_zone_device_register("rcar_thermal", 0, 0, priv, &rcar_thermal_zone_ops, 0, 0); if (IS_ERR(zone)) { dev_err(&pdev->dev, "thermal zone device is NULL\n"); diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index a5dec1ca1b8..13ee53bd0bf 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -424,7 +424,6 @@ static void hvc_hangup(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; unsigned long flags; - int temp_open_count; if (!hp) return; @@ -444,7 +443,6 @@ static void hvc_hangup(struct tty_struct *tty) return; } - temp_open_count = hp->port.count; hp->port.count = 0; spin_unlock_irqrestore(&hp->port.lock, flags); tty_port_tty_set(&hp->port, NULL); @@ -453,11 +451,6 @@ static void hvc_hangup(struct tty_struct *tty) if (hp->ops->notifier_hangup) hp->ops->notifier_hangup(hp, hp->data); - - while(temp_open_count) { - --temp_open_count; - tty_port_put(&hp->port); - } } /* diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 8c0b7b42319..60b076cc4e2 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -73,10 +73,42 @@ #define ECHO_OP_SET_CANON_COL 0x81 #define ECHO_OP_ERASE_TAB 0x82 +struct n_tty_data { + unsigned int column; + unsigned long overrun_time; + int num_overrun; + + unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; + unsigned char echo_overrun:1; + + DECLARE_BITMAP(process_char_map, 256); + DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE); + + char *read_buf; + int read_head; + int read_tail; + int read_cnt; + + unsigned char *echo_buf; + unsigned int echo_pos; + unsigned int echo_cnt; + + int canon_data; + unsigned long canon_head; + unsigned int canon_column; + + struct mutex atomic_read_lock; + struct mutex output_lock; + struct mutex echo_lock; + spinlock_t read_lock; +}; + static inline int tty_put_user(struct tty_struct *tty, unsigned char x, unsigned char __user *ptr) { - tty_audit_add_data(tty, &x, 1); + struct n_tty_data *ldata = tty->disc_data; + + tty_audit_add_data(tty, &x, 1, ldata->icanon); return put_user(x, ptr); } @@ -92,17 +124,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static void n_tty_set_room(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int left; int old_left; - /* tty->read_cnt is not read locked ? */ + /* ldata->read_cnt is not read locked ? */ if (I_PARMRK(tty)) { /* Multiply read_cnt by 3, since each byte might take up to * three times as many spaces when PARMRK is set (depending on * its flags, e.g. parity error). */ - left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1; + left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1; } else - left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + left = N_TTY_BUF_SIZE - ldata->read_cnt - 1; /* * If we are doing input canonicalization, and there are no @@ -111,44 +144,47 @@ static void n_tty_set_room(struct tty_struct *tty) * characters will be beeped. */ if (left <= 0) - left = tty->icanon && !tty->canon_data; + left = ldata->icanon && !ldata->canon_data; old_left = tty->receive_room; tty->receive_room = left; /* Did this open up the receive buffer? We may need to flip */ - if (left && !old_left) - schedule_work(&tty->buf.work); + if (left && !old_left) { + WARN_RATELIMIT(tty->port->itty == NULL, + "scheduling with invalid itty"); + schedule_work(&tty->port->buf.work); + } } -static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) +static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata) { - if (tty->read_cnt < N_TTY_BUF_SIZE) { - tty->read_buf[tty->read_head] = c; - tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1); - tty->read_cnt++; + if (ldata->read_cnt < N_TTY_BUF_SIZE) { + ldata->read_buf[ldata->read_head] = c; + ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1); + ldata->read_cnt++; } } /** * put_tty_queue - add character to tty * @c: character - * @tty: tty device + * @ldata: n_tty data * * Add a character to the tty read_buf queue. This is done under the * read_lock to serialize character addition and also to protect us * against parallel reads or flushes */ -static void put_tty_queue(unsigned char c, struct tty_struct *tty) +static void put_tty_queue(unsigned char c, struct n_tty_data *ldata) { unsigned long flags; /* * The problem of stomping on the buffers ends here. * Why didn't anyone see this one coming? --AJK */ - spin_lock_irqsave(&tty->read_lock, flags); - put_tty_queue_nolock(c, tty); - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); + put_tty_queue_nolock(c, ldata); + spin_unlock_irqrestore(&ldata->read_lock, flags); } /** @@ -179,18 +215,19 @@ static void check_unthrottle(struct tty_struct *tty) static void reset_buffer_flags(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; - spin_lock_irqsave(&tty->read_lock, flags); - tty->read_head = tty->read_tail = tty->read_cnt = 0; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); + ldata->read_head = ldata->read_tail = ldata->read_cnt = 0; + spin_unlock_irqrestore(&ldata->read_lock, flags); - mutex_lock(&tty->echo_lock); - tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0; - mutex_unlock(&tty->echo_lock); + mutex_lock(&ldata->echo_lock); + ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0; + mutex_unlock(&ldata->echo_lock); - tty->canon_head = tty->canon_data = tty->erasing = 0; - memset(&tty->read_flags, 0, sizeof tty->read_flags); + ldata->canon_head = ldata->canon_data = ldata->erasing = 0; + bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); n_tty_set_room(tty); } @@ -235,18 +272,19 @@ static void n_tty_flush_buffer(struct tty_struct *tty) static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; ssize_t n = 0; - spin_lock_irqsave(&tty->read_lock, flags); - if (!tty->icanon) { - n = tty->read_cnt; - } else if (tty->canon_data) { - n = (tty->canon_head > tty->read_tail) ? - tty->canon_head - tty->read_tail : - tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail); + spin_lock_irqsave(&ldata->read_lock, flags); + if (!ldata->icanon) { + n = ldata->read_cnt; + } else if (ldata->canon_data) { + n = (ldata->canon_head > ldata->read_tail) ? + ldata->canon_head - ldata->read_tail : + ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail); } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); return n; } @@ -301,6 +339,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) static int do_output_char(unsigned char c, struct tty_struct *tty, int space) { + struct n_tty_data *ldata = tty->disc_data; int spaces; if (!space) @@ -309,48 +348,48 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) switch (c) { case '\n': if (O_ONLRET(tty)) - tty->column = 0; + ldata->column = 0; if (O_ONLCR(tty)) { if (space < 2) return -1; - tty->canon_column = tty->column = 0; + ldata->canon_column = ldata->column = 0; tty->ops->write(tty, "\r\n", 2); return 2; } - tty->canon_column = tty->column; + ldata->canon_column = ldata->column; break; case '\r': - if (O_ONOCR(tty) && tty->column == 0) + if (O_ONOCR(tty) && ldata->column == 0) return 0; if (O_OCRNL(tty)) { c = '\n'; if (O_ONLRET(tty)) - tty->canon_column = tty->column = 0; + ldata->canon_column = ldata->column = 0; break; } - tty->canon_column = tty->column = 0; + ldata->canon_column = ldata->column = 0; break; case '\t': - spaces = 8 - (tty->column & 7); + spaces = 8 - (ldata->column & 7); if (O_TABDLY(tty) == XTABS) { if (space < spaces) return -1; - tty->column += spaces; + ldata->column += spaces; tty->ops->write(tty, " ", spaces); return spaces; } - tty->column += spaces; + ldata->column += spaces; break; case '\b': - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; break; default: if (!iscntrl(c)) { if (O_OLCUC(tty)) c = toupper(c); if (!is_continuation(c, tty)) - tty->column++; + ldata->column++; } break; } @@ -375,14 +414,15 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) static int process_output(unsigned char c, struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int space, retval; - mutex_lock(&tty->output_lock); + mutex_lock(&ldata->output_lock); space = tty_write_room(tty); retval = do_output_char(c, tty, space); - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->output_lock); if (retval < 0) return -1; else @@ -411,15 +451,16 @@ static int process_output(unsigned char c, struct tty_struct *tty) static ssize_t process_output_block(struct tty_struct *tty, const unsigned char *buf, unsigned int nr) { + struct n_tty_data *ldata = tty->disc_data; int space; int i; const unsigned char *cp; - mutex_lock(&tty->output_lock); + mutex_lock(&ldata->output_lock); space = tty_write_room(tty); if (!space) { - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->output_lock); return 0; } if (nr > space) @@ -431,30 +472,30 @@ static ssize_t process_output_block(struct tty_struct *tty, switch (c) { case '\n': if (O_ONLRET(tty)) - tty->column = 0; + ldata->column = 0; if (O_ONLCR(tty)) goto break_out; - tty->canon_column = tty->column; + ldata->canon_column = ldata->column; break; case '\r': - if (O_ONOCR(tty) && tty->column == 0) + if (O_ONOCR(tty) && ldata->column == 0) goto break_out; if (O_OCRNL(tty)) goto break_out; - tty->canon_column = tty->column = 0; + ldata->canon_column = ldata->column = 0; break; case '\t': goto break_out; case '\b': - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; break; default: if (!iscntrl(c)) { if (O_OLCUC(tty)) goto break_out; if (!is_continuation(c, tty)) - tty->column++; + ldata->column++; } break; } @@ -462,7 +503,7 @@ static ssize_t process_output_block(struct tty_struct *tty, break_out: i = tty->ops->write(tty, buf, i); - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->output_lock); return i; } @@ -494,21 +535,22 @@ break_out: static void process_echoes(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int space, nr; unsigned char c; unsigned char *cp, *buf_end; - if (!tty->echo_cnt) + if (!ldata->echo_cnt) return; - mutex_lock(&tty->output_lock); - mutex_lock(&tty->echo_lock); + mutex_lock(&ldata->output_lock); + mutex_lock(&ldata->echo_lock); space = tty_write_room(tty); - buf_end = tty->echo_buf + N_TTY_BUF_SIZE; - cp = tty->echo_buf + tty->echo_pos; - nr = tty->echo_cnt; + buf_end = ldata->echo_buf + N_TTY_BUF_SIZE; + cp = ldata->echo_buf + ldata->echo_pos; + nr = ldata->echo_cnt; while (nr > 0) { c = *cp; if (c == ECHO_OP_START) { @@ -545,7 +587,7 @@ static void process_echoes(struct tty_struct *tty) * Otherwise, tab spacing is normal. */ if (!(num_chars & 0x80)) - num_chars += tty->canon_column; + num_chars += ldata->canon_column; num_bs = 8 - (num_chars & 7); if (num_bs > space) { @@ -555,22 +597,22 @@ static void process_echoes(struct tty_struct *tty) space -= num_bs; while (num_bs--) { tty_put_char(tty, '\b'); - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; } cp += 3; nr -= 3; break; case ECHO_OP_SET_CANON_COL: - tty->canon_column = tty->column; + ldata->canon_column = ldata->column; cp += 2; nr -= 2; break; case ECHO_OP_MOVE_BACK_COL: - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; cp += 2; nr -= 2; break; @@ -582,7 +624,7 @@ static void process_echoes(struct tty_struct *tty) break; } tty_put_char(tty, ECHO_OP_START); - tty->column++; + ldata->column++; space--; cp += 2; nr -= 2; @@ -604,7 +646,7 @@ static void process_echoes(struct tty_struct *tty) } tty_put_char(tty, '^'); tty_put_char(tty, op ^ 0100); - tty->column += 2; + ldata->column += 2; space -= 2; cp += 2; nr -= 2; @@ -635,20 +677,20 @@ static void process_echoes(struct tty_struct *tty) } if (nr == 0) { - tty->echo_pos = 0; - tty->echo_cnt = 0; - tty->echo_overrun = 0; + ldata->echo_pos = 0; + ldata->echo_cnt = 0; + ldata->echo_overrun = 0; } else { - int num_processed = tty->echo_cnt - nr; - tty->echo_pos += num_processed; - tty->echo_pos &= N_TTY_BUF_SIZE - 1; - tty->echo_cnt = nr; + int num_processed = ldata->echo_cnt - nr; + ldata->echo_pos += num_processed; + ldata->echo_pos &= N_TTY_BUF_SIZE - 1; + ldata->echo_cnt = nr; if (num_processed > 0) - tty->echo_overrun = 0; + ldata->echo_overrun = 0; } - mutex_unlock(&tty->echo_lock); - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->echo_lock); + mutex_unlock(&ldata->output_lock); if (tty->ops->flush_chars) tty->ops->flush_chars(tty); @@ -657,72 +699,70 @@ static void process_echoes(struct tty_struct *tty) /** * add_echo_byte - add a byte to the echo buffer * @c: unicode byte to echo - * @tty: terminal device + * @ldata: n_tty data * * Add a character or operation byte to the echo buffer. * * Should be called under the echo lock to protect the echo buffer. */ -static void add_echo_byte(unsigned char c, struct tty_struct *tty) +static void add_echo_byte(unsigned char c, struct n_tty_data *ldata) { int new_byte_pos; - if (tty->echo_cnt == N_TTY_BUF_SIZE) { + if (ldata->echo_cnt == N_TTY_BUF_SIZE) { /* Circular buffer is already at capacity */ - new_byte_pos = tty->echo_pos; + new_byte_pos = ldata->echo_pos; /* * Since the buffer start position needs to be advanced, * be sure to step by a whole operation byte group. */ - if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) { - if (tty->echo_buf[(tty->echo_pos + 1) & + if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) { + if (ldata->echo_buf[(ldata->echo_pos + 1) & (N_TTY_BUF_SIZE - 1)] == ECHO_OP_ERASE_TAB) { - tty->echo_pos += 3; - tty->echo_cnt -= 2; + ldata->echo_pos += 3; + ldata->echo_cnt -= 2; } else { - tty->echo_pos += 2; - tty->echo_cnt -= 1; + ldata->echo_pos += 2; + ldata->echo_cnt -= 1; } } else { - tty->echo_pos++; + ldata->echo_pos++; } - tty->echo_pos &= N_TTY_BUF_SIZE - 1; + ldata->echo_pos &= N_TTY_BUF_SIZE - 1; - tty->echo_overrun = 1; + ldata->echo_overrun = 1; } else { - new_byte_pos = tty->echo_pos + tty->echo_cnt; + new_byte_pos = ldata->echo_pos + ldata->echo_cnt; new_byte_pos &= N_TTY_BUF_SIZE - 1; - tty->echo_cnt++; + ldata->echo_cnt++; } - tty->echo_buf[new_byte_pos] = c; + ldata->echo_buf[new_byte_pos] = c; } /** * echo_move_back_col - add operation to move back a column - * @tty: terminal device + * @ldata: n_tty data * * Add an operation to the echo buffer to move back one column. * * Locking: echo_lock to protect the echo buffer */ -static void echo_move_back_col(struct tty_struct *tty) +static void echo_move_back_col(struct n_tty_data *ldata) { - mutex_lock(&tty->echo_lock); - - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty); - - mutex_unlock(&tty->echo_lock); + mutex_lock(&ldata->echo_lock); + add_echo_byte(ECHO_OP_START, ldata); + add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata); + mutex_unlock(&ldata->echo_lock); } /** * echo_set_canon_col - add operation to set the canon column - * @tty: terminal device + * @ldata: n_tty data * * Add an operation to the echo buffer to set the canon column * to the current column. @@ -730,21 +770,19 @@ static void echo_move_back_col(struct tty_struct *tty) * Locking: echo_lock to protect the echo buffer */ -static void echo_set_canon_col(struct tty_struct *tty) +static void echo_set_canon_col(struct n_tty_data *ldata) { - mutex_lock(&tty->echo_lock); - - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_SET_CANON_COL, tty); - - mutex_unlock(&tty->echo_lock); + mutex_lock(&ldata->echo_lock); + add_echo_byte(ECHO_OP_START, ldata); + add_echo_byte(ECHO_OP_SET_CANON_COL, ldata); + mutex_unlock(&ldata->echo_lock); } /** * echo_erase_tab - add operation to erase a tab * @num_chars: number of character columns already used * @after_tab: true if num_chars starts after a previous tab - * @tty: terminal device + * @ldata: n_tty data * * Add an operation to the echo buffer to erase a tab. * @@ -758,12 +796,12 @@ static void echo_set_canon_col(struct tty_struct *tty) */ static void echo_erase_tab(unsigned int num_chars, int after_tab, - struct tty_struct *tty) + struct n_tty_data *ldata) { - mutex_lock(&tty->echo_lock); + mutex_lock(&ldata->echo_lock); - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_ERASE_TAB, tty); + add_echo_byte(ECHO_OP_START, ldata); + add_echo_byte(ECHO_OP_ERASE_TAB, ldata); /* We only need to know this modulo 8 (tab spacing) */ num_chars &= 7; @@ -772,9 +810,9 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, if (after_tab) num_chars |= 0x80; - add_echo_byte(num_chars, tty); + add_echo_byte(num_chars, ldata); - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -790,18 +828,16 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, * Locking: echo_lock to protect the echo buffer */ -static void echo_char_raw(unsigned char c, struct tty_struct *tty) +static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) { - mutex_lock(&tty->echo_lock); - + mutex_lock(&ldata->echo_lock); if (c == ECHO_OP_START) { - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_START, tty); + add_echo_byte(ECHO_OP_START, ldata); + add_echo_byte(ECHO_OP_START, ldata); } else { - add_echo_byte(c, tty); + add_echo_byte(c, ldata); } - - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -820,30 +856,32 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty) static void echo_char(unsigned char c, struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); + struct n_tty_data *ldata = tty->disc_data; + + mutex_lock(&ldata->echo_lock); if (c == ECHO_OP_START) { - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(ECHO_OP_START, tty); + add_echo_byte(ECHO_OP_START, ldata); + add_echo_byte(ECHO_OP_START, ldata); } else { if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') - add_echo_byte(ECHO_OP_START, tty); - add_echo_byte(c, tty); + add_echo_byte(ECHO_OP_START, ldata); + add_echo_byte(c, ldata); } - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** * finish_erasing - complete erase - * @tty: tty doing the erase + * @ldata: n_tty data */ -static inline void finish_erasing(struct tty_struct *tty) +static inline void finish_erasing(struct n_tty_data *ldata) { - if (tty->erasing) { - echo_char_raw('/', tty); - tty->erasing = 0; + if (ldata->erasing) { + echo_char_raw('/', ldata); + ldata->erasing = 0; } } @@ -861,12 +899,13 @@ static inline void finish_erasing(struct tty_struct *tty) static void eraser(unsigned char c, struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; enum { ERASE, WERASE, KILL } kill_type; int head, seen_alnums, cnt; unsigned long flags; /* FIXME: locking needed ? */ - if (tty->read_head == tty->canon_head) { + if (ldata->read_head == ldata->canon_head) { /* process_output('\a', tty); */ /* what do you think? */ return; } @@ -876,24 +915,24 @@ static void eraser(unsigned char c, struct tty_struct *tty) kill_type = WERASE; else { if (!L_ECHO(tty)) { - spin_lock_irqsave(&tty->read_lock, flags); - tty->read_cnt -= ((tty->read_head - tty->canon_head) & + spin_lock_irqsave(&ldata->read_lock, flags); + ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & (N_TTY_BUF_SIZE - 1)); - tty->read_head = tty->canon_head; - spin_unlock_irqrestore(&tty->read_lock, flags); + ldata->read_head = ldata->canon_head; + spin_unlock_irqrestore(&ldata->read_lock, flags); return; } if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { - spin_lock_irqsave(&tty->read_lock, flags); - tty->read_cnt -= ((tty->read_head - tty->canon_head) & + spin_lock_irqsave(&ldata->read_lock, flags); + ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & (N_TTY_BUF_SIZE - 1)); - tty->read_head = tty->canon_head; - spin_unlock_irqrestore(&tty->read_lock, flags); - finish_erasing(tty); + ldata->read_head = ldata->canon_head; + spin_unlock_irqrestore(&ldata->read_lock, flags); + finish_erasing(ldata); echo_char(KILL_CHAR(tty), tty); /* Add a newline if ECHOK is on and ECHOKE is off. */ if (L_ECHOK(tty)) - echo_char_raw('\n', tty); + echo_char_raw('\n', ldata); return; } kill_type = KILL; @@ -901,14 +940,14 @@ static void eraser(unsigned char c, struct tty_struct *tty) seen_alnums = 0; /* FIXME: Locking ?? */ - while (tty->read_head != tty->canon_head) { - head = tty->read_head; + while (ldata->read_head != ldata->canon_head) { + head = ldata->read_head; /* erase a single possibly multibyte character */ do { head = (head - 1) & (N_TTY_BUF_SIZE-1); - c = tty->read_buf[head]; - } while (is_continuation(c, tty) && head != tty->canon_head); + c = ldata->read_buf[head]; + } while (is_continuation(c, tty) && head != ldata->canon_head); /* do not partially erase */ if (is_continuation(c, tty)) @@ -921,30 +960,31 @@ static void eraser(unsigned char c, struct tty_struct *tty) else if (seen_alnums) break; } - cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1); - spin_lock_irqsave(&tty->read_lock, flags); - tty->read_head = head; - tty->read_cnt -= cnt; - spin_unlock_irqrestore(&tty->read_lock, flags); + cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1); + spin_lock_irqsave(&ldata->read_lock, flags); + ldata->read_head = head; + ldata->read_cnt -= cnt; + spin_unlock_irqrestore(&ldata->read_lock, flags); if (L_ECHO(tty)) { if (L_ECHOPRT(tty)) { - if (!tty->erasing) { - echo_char_raw('\\', tty); - tty->erasing = 1; + if (!ldata->erasing) { + echo_char_raw('\\', ldata); + ldata->erasing = 1; } /* if cnt > 1, output a multi-byte character */ echo_char(c, tty); while (--cnt > 0) { head = (head+1) & (N_TTY_BUF_SIZE-1); - echo_char_raw(tty->read_buf[head], tty); - echo_move_back_col(tty); + echo_char_raw(ldata->read_buf[head], + ldata); + echo_move_back_col(ldata); } } else if (kill_type == ERASE && !L_ECHOE(tty)) { echo_char(ERASE_CHAR(tty), tty); } else if (c == '\t') { unsigned int num_chars = 0; int after_tab = 0; - unsigned long tail = tty->read_head; + unsigned long tail = ldata->read_head; /* * Count the columns used for characters @@ -953,9 +993,9 @@ static void eraser(unsigned char c, struct tty_struct *tty) * This info is used to go back the correct * number of columns. */ - while (tail != tty->canon_head) { + while (tail != ldata->canon_head) { tail = (tail-1) & (N_TTY_BUF_SIZE-1); - c = tty->read_buf[tail]; + c = ldata->read_buf[tail]; if (c == '\t') { after_tab = 1; break; @@ -966,25 +1006,25 @@ static void eraser(unsigned char c, struct tty_struct *tty) num_chars++; } } - echo_erase_tab(num_chars, after_tab, tty); + echo_erase_tab(num_chars, after_tab, ldata); } else { if (iscntrl(c) && L_ECHOCTL(tty)) { - echo_char_raw('\b', tty); - echo_char_raw(' ', tty); - echo_char_raw('\b', tty); + echo_char_raw('\b', ldata); + echo_char_raw(' ', ldata); + echo_char_raw('\b', ldata); } if (!iscntrl(c) || L_ECHOCTL(tty)) { - echo_char_raw('\b', tty); - echo_char_raw(' ', tty); - echo_char_raw('\b', tty); + echo_char_raw('\b', ldata); + echo_char_raw(' ', ldata); + echo_char_raw('\b', ldata); } } } if (kill_type == ERASE) break; } - if (tty->read_head == tty->canon_head && L_ECHO(tty)) - finish_erasing(tty); + if (ldata->read_head == ldata->canon_head && L_ECHO(tty)) + finish_erasing(ldata); } /** @@ -1023,6 +1063,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) static inline void n_tty_receive_break(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; + if (I_IGNBRK(tty)) return; if (I_BRKINT(tty)) { @@ -1030,10 +1072,10 @@ static inline void n_tty_receive_break(struct tty_struct *tty) return; } if (I_PARMRK(tty)) { - put_tty_queue('\377', tty); - put_tty_queue('\0', tty); + put_tty_queue('\377', ldata); + put_tty_queue('\0', ldata); } - put_tty_queue('\0', tty); + put_tty_queue('\0', ldata); wake_up_interruptible(&tty->read_wait); } @@ -1052,16 +1094,17 @@ static inline void n_tty_receive_break(struct tty_struct *tty) static inline void n_tty_receive_overrun(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; char buf[64]; - tty->num_overrun++; - if (time_before(tty->overrun_time, jiffies - HZ) || - time_after(tty->overrun_time, jiffies)) { + ldata->num_overrun++; + if (time_after(jiffies, ldata->overrun_time + HZ) || + time_after(ldata->overrun_time, jiffies)) { printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), - tty->num_overrun); - tty->overrun_time = jiffies; - tty->num_overrun = 0; + ldata->num_overrun); + ldata->overrun_time = jiffies; + ldata->num_overrun = 0; } } @@ -1076,16 +1119,18 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty) static inline void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { + struct n_tty_data *ldata = tty->disc_data; + if (I_IGNPAR(tty)) return; if (I_PARMRK(tty)) { - put_tty_queue('\377', tty); - put_tty_queue('\0', tty); - put_tty_queue(c, tty); + put_tty_queue('\377', ldata); + put_tty_queue('\0', ldata); + put_tty_queue(c, ldata); } else if (I_INPCK(tty)) - put_tty_queue('\0', tty); + put_tty_queue('\0', ldata); else - put_tty_queue(c, tty); + put_tty_queue(c, ldata); wake_up_interruptible(&tty->read_wait); } @@ -1101,11 +1146,12 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; int parmrk; - if (tty->raw) { - put_tty_queue(c, tty); + if (ldata->raw) { + put_tty_queue(c, ldata); return; } @@ -1115,7 +1161,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) c = tolower(c); if (L_EXTPROC(tty)) { - put_tty_queue(c, tty); + put_tty_queue(c, ldata); return; } @@ -1143,26 +1189,26 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) * handle specially, do shortcut processing to speed things * up. */ - if (!test_bit(c, tty->process_char_map) || tty->lnext) { - tty->lnext = 0; + if (!test_bit(c, ldata->process_char_map) || ldata->lnext) { + ldata->lnext = 0; parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; - if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { + if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { /* beep if no space */ if (L_ECHO(tty)) process_output('\a', tty); return; } if (L_ECHO(tty)) { - finish_erasing(tty); + finish_erasing(ldata); /* Record the column of first canon char. */ - if (tty->canon_head == tty->read_head) - echo_set_canon_col(tty); + if (ldata->canon_head == ldata->read_head) + echo_set_canon_col(ldata); echo_char(c, tty); process_echoes(tty); } if (parmrk) - put_tty_queue(c, tty); - put_tty_queue(c, tty); + put_tty_queue(c, ldata); + put_tty_queue(c, ldata); return; } @@ -1218,7 +1264,7 @@ send_signal: } else if (c == '\n' && I_INLCR(tty)) c = '\r'; - if (tty->icanon) { + if (ldata->icanon) { if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { eraser(c, tty); @@ -1226,12 +1272,12 @@ send_signal: return; } if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { - tty->lnext = 1; + ldata->lnext = 1; if (L_ECHO(tty)) { - finish_erasing(tty); + finish_erasing(ldata); if (L_ECHOCTL(tty)) { - echo_char_raw('^', tty); - echo_char_raw('\b', tty); + echo_char_raw('^', ldata); + echo_char_raw('\b', ldata); process_echoes(tty); } } @@ -1239,34 +1285,34 @@ send_signal: } if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) { - unsigned long tail = tty->canon_head; + unsigned long tail = ldata->canon_head; - finish_erasing(tty); + finish_erasing(ldata); echo_char(c, tty); - echo_char_raw('\n', tty); - while (tail != tty->read_head) { - echo_char(tty->read_buf[tail], tty); + echo_char_raw('\n', ldata); + while (tail != ldata->read_head) { + echo_char(ldata->read_buf[tail], tty); tail = (tail+1) & (N_TTY_BUF_SIZE-1); } process_echoes(tty); return; } if (c == '\n') { - if (tty->read_cnt >= N_TTY_BUF_SIZE) { + if (ldata->read_cnt >= N_TTY_BUF_SIZE) { if (L_ECHO(tty)) process_output('\a', tty); return; } if (L_ECHO(tty) || L_ECHONL(tty)) { - echo_char_raw('\n', tty); + echo_char_raw('\n', ldata); process_echoes(tty); } goto handle_newline; } if (c == EOF_CHAR(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE) + if (ldata->read_cnt >= N_TTY_BUF_SIZE) return; - if (tty->canon_head != tty->read_head) + if (ldata->canon_head != ldata->read_head) set_bit(TTY_PUSH, &tty->flags); c = __DISABLED_CHAR; goto handle_newline; @@ -1275,7 +1321,7 @@ send_signal: (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; - if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) { + if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) { if (L_ECHO(tty)) process_output('\a', tty); return; @@ -1285,8 +1331,8 @@ send_signal: */ if (L_ECHO(tty)) { /* Record the column of first canon char. */ - if (tty->canon_head == tty->read_head) - echo_set_canon_col(tty); + if (ldata->canon_head == ldata->read_head) + echo_set_canon_col(ldata); echo_char(c, tty); process_echoes(tty); } @@ -1295,15 +1341,15 @@ send_signal: * EOL_CHAR and EOL2_CHAR? */ if (parmrk) - put_tty_queue(c, tty); + put_tty_queue(c, ldata); handle_newline: - spin_lock_irqsave(&tty->read_lock, flags); - set_bit(tty->read_head, tty->read_flags); - put_tty_queue_nolock(c, tty); - tty->canon_head = tty->read_head; - tty->canon_data++; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); + set_bit(ldata->read_head, ldata->read_flags); + put_tty_queue_nolock(c, ldata); + ldata->canon_head = ldata->read_head; + ldata->canon_data++; + spin_unlock_irqrestore(&ldata->read_lock, flags); kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); @@ -1312,29 +1358,29 @@ handle_newline: } parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; - if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { + if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { /* beep if no space */ if (L_ECHO(tty)) process_output('\a', tty); return; } if (L_ECHO(tty)) { - finish_erasing(tty); + finish_erasing(ldata); if (c == '\n') - echo_char_raw('\n', tty); + echo_char_raw('\n', ldata); else { /* Record the column of first canon char. */ - if (tty->canon_head == tty->read_head) - echo_set_canon_col(tty); + if (ldata->canon_head == ldata->read_head) + echo_set_canon_col(ldata); echo_char(c, tty); } process_echoes(tty); } if (parmrk) - put_tty_queue(c, tty); + put_tty_queue(c, ldata); - put_tty_queue(c, tty); + put_tty_queue(c, ldata); } @@ -1369,33 +1415,31 @@ static void n_tty_write_wakeup(struct tty_struct *tty) static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { + struct n_tty_data *ldata = tty->disc_data; const unsigned char *p; char *f, flags = TTY_NORMAL; int i; char buf[64]; unsigned long cpuflags; - if (!tty->read_buf) - return; - - if (tty->real_raw) { - spin_lock_irqsave(&tty->read_lock, cpuflags); - i = min(N_TTY_BUF_SIZE - tty->read_cnt, - N_TTY_BUF_SIZE - tty->read_head); + if (ldata->real_raw) { + spin_lock_irqsave(&ldata->read_lock, cpuflags); + i = min(N_TTY_BUF_SIZE - ldata->read_cnt, + N_TTY_BUF_SIZE - ldata->read_head); i = min(count, i); - memcpy(tty->read_buf + tty->read_head, cp, i); - tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); - tty->read_cnt += i; + memcpy(ldata->read_buf + ldata->read_head, cp, i); + ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1); + ldata->read_cnt += i; cp += i; count -= i; - i = min(N_TTY_BUF_SIZE - tty->read_cnt, - N_TTY_BUF_SIZE - tty->read_head); + i = min(N_TTY_BUF_SIZE - ldata->read_cnt, + N_TTY_BUF_SIZE - ldata->read_head); i = min(count, i); - memcpy(tty->read_buf + tty->read_head, cp, i); - tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); - tty->read_cnt += i; - spin_unlock_irqrestore(&tty->read_lock, cpuflags); + memcpy(ldata->read_buf + ldata->read_head, cp, i); + ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1); + ldata->read_cnt += i; + spin_unlock_irqrestore(&ldata->read_lock, cpuflags); } else { for (i = count, p = cp, f = fp; i; i--, p++) { if (f) @@ -1426,7 +1470,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, n_tty_set_room(tty); - if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) || + if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) || L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) @@ -1470,25 +1514,25 @@ int is_ignored(int sig) static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { + struct n_tty_data *ldata = tty->disc_data; int canon_change = 1; - BUG_ON(!tty); if (old) canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON; if (canon_change) { - memset(&tty->read_flags, 0, sizeof tty->read_flags); - tty->canon_head = tty->read_tail; - tty->canon_data = 0; - tty->erasing = 0; + bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); + ldata->canon_head = ldata->read_tail; + ldata->canon_data = 0; + ldata->erasing = 0; } - if (canon_change && !L_ICANON(tty) && tty->read_cnt) + if (canon_change && !L_ICANON(tty) && ldata->read_cnt) wake_up_interruptible(&tty->read_wait); - tty->icanon = (L_ICANON(tty) != 0); + ldata->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { - tty->raw = 1; - tty->real_raw = 1; + ldata->raw = 1; + ldata->real_raw = 1; n_tty_set_room(tty); return; } @@ -1496,51 +1540,51 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - memset(tty->process_char_map, 0, 256/8); + bitmap_zero(ldata->process_char_map, 256); if (I_IGNCR(tty) || I_ICRNL(tty)) - set_bit('\r', tty->process_char_map); + set_bit('\r', ldata->process_char_map); if (I_INLCR(tty)) - set_bit('\n', tty->process_char_map); + set_bit('\n', ldata->process_char_map); if (L_ICANON(tty)) { - set_bit(ERASE_CHAR(tty), tty->process_char_map); - set_bit(KILL_CHAR(tty), tty->process_char_map); - set_bit(EOF_CHAR(tty), tty->process_char_map); - set_bit('\n', tty->process_char_map); - set_bit(EOL_CHAR(tty), tty->process_char_map); + set_bit(ERASE_CHAR(tty), ldata->process_char_map); + set_bit(KILL_CHAR(tty), ldata->process_char_map); + set_bit(EOF_CHAR(tty), ldata->process_char_map); + set_bit('\n', ldata->process_char_map); + set_bit(EOL_CHAR(tty), ldata->process_char_map); if (L_IEXTEN(tty)) { set_bit(WERASE_CHAR(tty), - tty->process_char_map); + ldata->process_char_map); set_bit(LNEXT_CHAR(tty), - tty->process_char_map); + ldata->process_char_map); set_bit(EOL2_CHAR(tty), - tty->process_char_map); + ldata->process_char_map); if (L_ECHO(tty)) set_bit(REPRINT_CHAR(tty), - tty->process_char_map); + ldata->process_char_map); } } if (I_IXON(tty)) { - set_bit(START_CHAR(tty), tty->process_char_map); - set_bit(STOP_CHAR(tty), tty->process_char_map); + set_bit(START_CHAR(tty), ldata->process_char_map); + set_bit(STOP_CHAR(tty), ldata->process_char_map); } if (L_ISIG(tty)) { - set_bit(INTR_CHAR(tty), tty->process_char_map); - set_bit(QUIT_CHAR(tty), tty->process_char_map); - set_bit(SUSP_CHAR(tty), tty->process_char_map); + set_bit(INTR_CHAR(tty), ldata->process_char_map); + set_bit(QUIT_CHAR(tty), ldata->process_char_map); + set_bit(SUSP_CHAR(tty), ldata->process_char_map); } - clear_bit(__DISABLED_CHAR, tty->process_char_map); - tty->raw = 0; - tty->real_raw = 0; + clear_bit(__DISABLED_CHAR, ldata->process_char_map); + ldata->raw = 0; + ldata->real_raw = 0; } else { - tty->raw = 1; + ldata->raw = 1; if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && (I_IGNPAR(tty) || !I_INPCK(tty)) && (tty->driver->flags & TTY_DRIVER_REAL_RAW)) - tty->real_raw = 1; + ldata->real_raw = 1; else - tty->real_raw = 0; + ldata->real_raw = 0; } n_tty_set_room(tty); /* The termios change make the tty ready for I/O */ @@ -1560,15 +1604,13 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) static void n_tty_close(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; + n_tty_flush_buffer(tty); - if (tty->read_buf) { - kfree(tty->read_buf); - tty->read_buf = NULL; - } - if (tty->echo_buf) { - kfree(tty->echo_buf); - tty->echo_buf = NULL; - } + kfree(ldata->read_buf); + kfree(ldata->echo_buf); + kfree(ldata); + tty->disc_data = NULL; } /** @@ -1583,37 +1625,50 @@ static void n_tty_close(struct tty_struct *tty) static int n_tty_open(struct tty_struct *tty) { - if (!tty) - return -EINVAL; + struct n_tty_data *ldata; + + ldata = kzalloc(sizeof(*ldata), GFP_KERNEL); + if (!ldata) + goto err; + + ldata->overrun_time = jiffies; + mutex_init(&ldata->atomic_read_lock); + mutex_init(&ldata->output_lock); + mutex_init(&ldata->echo_lock); + spin_lock_init(&ldata->read_lock); /* These are ugly. Currently a malloc failure here can panic */ - if (!tty->read_buf) { - tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); - if (!tty->read_buf) - return -ENOMEM; - } - if (!tty->echo_buf) { - tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); + ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); + ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); + if (!ldata->read_buf || !ldata->echo_buf) + goto err_free_bufs; - if (!tty->echo_buf) - return -ENOMEM; - } + tty->disc_data = ldata; reset_buffer_flags(tty); tty_unthrottle(tty); - tty->column = 0; + ldata->column = 0; n_tty_set_termios(tty, NULL); tty->minimum_to_wake = 1; tty->closing = 0; + return 0; +err_free_bufs: + kfree(ldata->read_buf); + kfree(ldata->echo_buf); + kfree(ldata); +err: + return -ENOMEM; } static inline int input_available_p(struct tty_struct *tty, int amt) { + struct n_tty_data *ldata = tty->disc_data; + tty_flush_to_ldisc(tty); - if (tty->icanon && !L_EXTPROC(tty)) { - if (tty->canon_data) + if (ldata->icanon && !L_EXTPROC(tty)) { + if (ldata->canon_data) return 1; - } else if (tty->read_cnt >= (amt ? amt : 1)) + } else if (ldata->read_cnt >= (amt ? amt : 1)) return 1; return 0; @@ -1632,7 +1687,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * buffer, and once to drain the space from the (physical) beginning of * the buffer to head pointer. * - * Called under the tty->atomic_read_lock sem + * Called under the ldata->atomic_read_lock sem * */ @@ -1641,29 +1696,31 @@ static int copy_from_read_buf(struct tty_struct *tty, size_t *nr) { + struct n_tty_data *ldata = tty->disc_data; int retval; size_t n; unsigned long flags; bool is_eof; retval = 0; - spin_lock_irqsave(&tty->read_lock, flags); - n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); + spin_lock_irqsave(&ldata->read_lock, flags); + n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail); n = min(*nr, n); - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (n) { - retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); + retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n); n -= retval; is_eof = n == 1 && - tty->read_buf[tty->read_tail] == EOF_CHAR(tty); - tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n); - spin_lock_irqsave(&tty->read_lock, flags); - tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); - tty->read_cnt -= n; + ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty); + tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n, + ldata->icanon); + spin_lock_irqsave(&ldata->read_lock, flags); + ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1); + ldata->read_cnt -= n; /* Turn single EOF into zero-length read */ - if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt) + if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt) n = 0; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); *b += n; *nr -= n; } @@ -1730,6 +1787,7 @@ static int job_control(struct tty_struct *tty, struct file *file) static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { + struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; DECLARE_WAITQUEUE(wait, current); int c; @@ -1741,17 +1799,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, int packet; do_it_again: - - if (WARN_ON(!tty->read_buf)) - return -EAGAIN; - c = job_control(tty, file); if (c < 0) return c; minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; - if (!tty->icanon) { + if (!ldata->icanon) { time = (HZ / 10) * TIME_CHAR(tty); minimum = MIN_CHAR(tty); if (minimum) { @@ -1774,10 +1828,10 @@ do_it_again: * Internal serialization of reads. */ if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&tty->atomic_read_lock)) + if (!mutex_trylock(&ldata->atomic_read_lock)) return -EAGAIN; } else { - if (mutex_lock_interruptible(&tty->atomic_read_lock)) + if (mutex_lock_interruptible(&ldata->atomic_read_lock)) return -ERESTARTSYS; } packet = tty->packet; @@ -1830,7 +1884,6 @@ do_it_again: /* FIXME: does n_tty_set_room need locking ? */ n_tty_set_room(tty); timeout = schedule_timeout(timeout); - BUG_ON(!tty->read_buf); continue; } __set_current_state(TASK_RUNNING); @@ -1845,45 +1898,45 @@ do_it_again: nr--; } - if (tty->icanon && !L_EXTPROC(tty)) { + if (ldata->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ - spin_lock_irqsave(&tty->read_lock, flags); - while (nr && tty->read_cnt) { + spin_lock_irqsave(&ldata->read_lock, flags); + while (nr && ldata->read_cnt) { int eol; - eol = test_and_clear_bit(tty->read_tail, - tty->read_flags); - c = tty->read_buf[tty->read_tail]; - tty->read_tail = ((tty->read_tail+1) & + eol = test_and_clear_bit(ldata->read_tail, + ldata->read_flags); + c = ldata->read_buf[ldata->read_tail]; + ldata->read_tail = ((ldata->read_tail+1) & (N_TTY_BUF_SIZE-1)); - tty->read_cnt--; + ldata->read_cnt--; if (eol) { /* this test should be redundant: * we shouldn't be reading data if * canon_data is 0 */ - if (--tty->canon_data < 0) - tty->canon_data = 0; + if (--ldata->canon_data < 0) + ldata->canon_data = 0; } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (!eol || (c != __DISABLED_CHAR)) { if (tty_put_user(tty, c, b++)) { retval = -EFAULT; b--; - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); break; } nr--; } if (eol) { tty_audit_push(tty); - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); break; } - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (retval) break; } else { @@ -1915,7 +1968,7 @@ do_it_again: if (time) timeout = time; } - mutex_unlock(&tty->atomic_read_lock); + mutex_unlock(&ldata->atomic_read_lock); remove_wait_queue(&tty->read_wait, &wait); if (!waitqueue_active(&tty->read_wait)) @@ -2076,19 +2129,19 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, return mask; } -static unsigned long inq_canon(struct tty_struct *tty) +static unsigned long inq_canon(struct n_tty_data *ldata) { int nr, head, tail; - if (!tty->canon_data) + if (!ldata->canon_data) return 0; - head = tty->canon_head; - tail = tty->read_tail; + head = ldata->canon_head; + tail = ldata->read_tail; nr = (head - tail) & (N_TTY_BUF_SIZE-1); /* Skip EOF-chars.. */ while (head != tail) { - if (test_bit(tail, tty->read_flags) && - tty->read_buf[tail] == __DISABLED_CHAR) + if (test_bit(tail, ldata->read_flags) && + ldata->read_buf[tail] == __DISABLED_CHAR) nr--; tail = (tail+1) & (N_TTY_BUF_SIZE-1); } @@ -2098,6 +2151,7 @@ static unsigned long inq_canon(struct tty_struct *tty) static int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { + struct n_tty_data *ldata = tty->disc_data; int retval; switch (cmd) { @@ -2105,9 +2159,9 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, return put_user(tty_chars_in_buffer(tty), (int __user *) arg); case TIOCINQ: /* FIXME: Locking */ - retval = tty->read_cnt; + retval = ldata->read_cnt; if (L_ICANON(tty)) - retval = inq_canon(tty); + retval = inq_canon(ldata); return put_user(retval, (unsigned int __user *) arg); default: return n_tty_ioctl_helper(tty, file, cmd, arg); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index a82b39939a9..4219f040adb 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -4,9 +4,6 @@ * Added support for a Unix98-style ptmx device. * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998 * - * When reading this code see also fs/devpts. In particular note that the - * driver_data field is used by the devpts side as a binding to the devpts - * inode. */ #include <linux/module.h> @@ -59,7 +56,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) #ifdef CONFIG_UNIX98_PTYS if (tty->driver == ptm_driver) { mutex_lock(&devpts_mutex); - devpts_pty_kill(tty->link); + devpts_pty_kill(tty->link->driver_data); mutex_unlock(&devpts_mutex); } #endif @@ -96,7 +93,7 @@ static void pty_unthrottle(struct tty_struct *tty) static int pty_space(struct tty_struct *to) { - int n = 8192 - to->buf.memory_used; + int n = 8192 - to->port->buf.memory_used; if (n < 0) return 0; return n; @@ -348,6 +345,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, tty_port_init(ports[1]); o_tty->port = ports[0]; tty->port = ports[1]; + o_tty->port->itty = o_tty; tty_driver_kref_get(driver); tty->count++; @@ -366,8 +364,15 @@ err: return retval; } +/* this is called once with whichever end is closed last */ +static void pty_unix98_shutdown(struct tty_struct *tty) +{ + devpts_kill_index(tty->driver_data, tty->index); +} + static void pty_cleanup(struct tty_struct *tty) { + tty->port->itty = NULL; kfree(tty->port); } @@ -547,7 +552,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, struct tty_struct *tty; mutex_lock(&devpts_mutex); - tty = devpts_get_tty(pts_inode, idx); + tty = devpts_get_priv(pts_inode); mutex_unlock(&devpts_mutex); /* Master must be open before slave */ if (!tty) @@ -581,6 +586,7 @@ static const struct tty_operations ptm_unix98_ops = { .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, .resize = pty_resize, + .shutdown = pty_unix98_shutdown, .cleanup = pty_cleanup }; @@ -596,6 +602,7 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, + .shutdown = pty_unix98_shutdown, .cleanup = pty_cleanup, }; @@ -614,6 +621,7 @@ static const struct tty_operations pty_unix98_ops = { static int ptmx_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; + struct inode *slave_inode; int retval; int index; @@ -650,15 +658,21 @@ static int ptmx_open(struct inode *inode, struct file *filp) tty_add_file(tty, filp); - retval = devpts_pty_new(inode, tty->link); - if (retval) + slave_inode = devpts_pty_new(inode, + MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index, + tty->link); + if (IS_ERR(slave_inode)) { + retval = PTR_ERR(slave_inode); goto err_release; + } retval = ptm_driver->ops->open(tty, filp); if (retval) goto err_release; tty_unlock(tty); + tty->driver_data = inode; + tty->link->driver_data = slave_inode; return 0; err_release: tty_unlock(tty); diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 3ba4234592b..5ccbd90540c 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -2349,16 +2349,14 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, serial_port_out(port, UART_EFR, efr); } -#ifdef CONFIG_ARCH_OMAP1 /* Workaround to enable 115200 baud on OMAP1510 internal ports */ - if (cpu_is_omap1510() && is_omap_port(up)) { + if (is_omap1510_8250(up)) { if (baud == 115200) { quot = 1; serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); } else serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); } -#endif /* * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, @@ -2439,10 +2437,9 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt) { if (pt->port.iotype == UPIO_AU) return 0x1000; -#ifdef CONFIG_ARCH_OMAP1 - if (is_omap_port(pt)) + if (is_omap1_8250(pt)) return 0x16 << pt->port.regshift; -#endif + return 8 << pt->port.regshift; } diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 5a76f9c8d36..3b4ea84898c 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -106,3 +106,39 @@ static inline int serial8250_pnp_init(void) { return 0; } static inline void serial8250_pnp_exit(void) { } #endif +#ifdef CONFIG_ARCH_OMAP1 +static inline int is_omap1_8250(struct uart_8250_port *pt) +{ + int res; + + switch (pt->port.mapbase) { + case OMAP1_UART1_BASE: + case OMAP1_UART2_BASE: + case OMAP1_UART3_BASE: + res = 1; + break; + default: + res = 0; + break; + } + + return res; +} + +static inline int is_omap1510_8250(struct uart_8250_port *pt) +{ + if (!cpu_is_omap1510()) + return 0; + + return is_omap1_8250(pt); +} +#else +static inline int is_omap1_8250(struct uart_8250_port *pt) +{ + return 0; +} +static inline int is_omap1510_8250(struct uart_8250_port *pt) +{ + return 0; +} +#endif diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index eaafb98debe..843a150ba10 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -140,7 +140,7 @@ static void __init init_port(struct early_serial8250_device *device) serial_out(port, UART_FCR, 0); /* no fifo */ serial_out(port, UART_MCR, 0x3); /* DTR + RTS */ - divisor = port->uartclk / (16 * device->baud); + divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); c = serial_in(port, UART_LCR); serial_out(port, UART_LCR, c | UART_LCR_DLAB); serial_out(port, UART_DLL, divisor & 0xff); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 2bc28a59d38..1ab1d2c66de 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1239,6 +1239,7 @@ static int __devexit max310x_remove(struct spi_device *spi) static const struct spi_device_id max310x_id_table[] = { { "max3107", MAX310X_TYPE_MAX3107 }, { "max3108", MAX310X_TYPE_MAX3108 }, + { } }; MODULE_DEVICE_TABLE(spi, max310x_id_table); diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 7f04717176a..740458ca62c 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -530,16 +530,16 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, switch (level) { case 3: if (!IS_ERR(ourport->baudclk)) - clk_disable(ourport->baudclk); + clk_disable_unprepare(ourport->baudclk); - clk_disable(ourport->clk); + clk_disable_unprepare(ourport->clk); break; case 0: - clk_enable(ourport->clk); + clk_prepare_enable(ourport->clk); if (!IS_ERR(ourport->baudclk)) - clk_enable(ourport->baudclk); + clk_prepare_enable(ourport->baudclk); break; default: @@ -713,11 +713,11 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, s3c24xx_serial_setsource(port, clk_sel); if (!IS_ERR(ourport->baudclk)) { - clk_disable(ourport->baudclk); + clk_disable_unprepare(ourport->baudclk); ourport->baudclk = ERR_PTR(-EINVAL); } - clk_enable(clk); + clk_prepare_enable(clk); ourport->baudclk = clk; ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; @@ -1287,9 +1287,9 @@ static int s3c24xx_serial_resume(struct device *dev) struct s3c24xx_uart_port *ourport = to_ourport(port); if (port) { - clk_enable(ourport->clk); + clk_prepare_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); - clk_disable(ourport->clk); + clk_disable_unprepare(ourport->clk); uart_resume_port(&s3c24xx_uart_drv, port); } diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index b0b39b823cc..6953dc82850 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -23,7 +23,7 @@ struct tty_audit_buf { }; static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, - int icanon) + unsigned icanon) { struct tty_audit_buf *buf; @@ -239,7 +239,8 @@ int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid) * if TTY auditing is disabled or out of memory. Otherwise, return a new * reference to the buffer. */ -static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty) +static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, + unsigned icanon) { struct tty_audit_buf *buf, *buf2; @@ -257,7 +258,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty) buf2 = tty_audit_buf_alloc(tty->driver->major, tty->driver->minor_start + tty->index, - tty->icanon); + icanon); if (buf2 == NULL) { audit_log_lost("out of memory in TTY auditing"); return NULL; @@ -287,7 +288,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty) * Audit @data of @size from @tty, if necessary. */ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, - size_t size) + size_t size, unsigned icanon) { struct tty_audit_buf *buf; int major, minor; @@ -299,7 +300,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, && tty->driver->subtype == PTY_TYPE_MASTER) return; - buf = tty_audit_buf_get(tty); + buf = tty_audit_buf_get(tty, icanon); if (!buf) return; @@ -307,11 +308,11 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, major = tty->driver->major; minor = tty->driver->minor_start + tty->index; if (buf->major != major || buf->minor != minor - || buf->icanon != tty->icanon) { + || buf->icanon != icanon) { tty_audit_buf_push_current(buf); buf->major = major; buf->minor = minor; - buf->icanon = tty->icanon; + buf->icanon = icanon; } do { size_t run; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 91e326ffe7d..6cf87d7afb7 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -27,19 +27,21 @@ * Locking: none */ -void tty_buffer_free_all(struct tty_struct *tty) +void tty_buffer_free_all(struct tty_port *port) { + struct tty_bufhead *buf = &port->buf; struct tty_buffer *thead; - while ((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; + + while ((thead = buf->head) != NULL) { + buf->head = thead->next; kfree(thead); } - while ((thead = tty->buf.free) != NULL) { - tty->buf.free = thead->next; + while ((thead = buf->free) != NULL) { + buf->free = thead->next; kfree(thead); } - tty->buf.tail = NULL; - tty->buf.memory_used = 0; + buf->tail = NULL; + buf->memory_used = 0; } /** @@ -54,11 +56,11 @@ void tty_buffer_free_all(struct tty_struct *tty) * Locking: Caller must hold tty->buf.lock */ -static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) +static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) { struct tty_buffer *p; - if (tty->buf.memory_used + size > 65536) + if (port->buf.memory_used + size > 65536) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if (p == NULL) @@ -70,7 +72,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) p->read = 0; p->char_buf_ptr = (char *)(p->data); p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; - tty->buf.memory_used += size; + port->buf.memory_used += size; return p; } @@ -85,17 +87,19 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) * Locking: Caller must hold tty->buf.lock */ -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) +static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) { + struct tty_bufhead *buf = &port->buf; + /* Dumb strategy for now - should keep some stats */ - tty->buf.memory_used -= b->size; - WARN_ON(tty->buf.memory_used < 0); + buf->memory_used -= b->size; + WARN_ON(buf->memory_used < 0); if (b->size >= 512) kfree(b); else { - b->next = tty->buf.free; - tty->buf.free = b; + b->next = buf->free; + buf->free = b; } } @@ -110,15 +114,16 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) * Locking: Caller must hold tty->buf.lock */ -static void __tty_buffer_flush(struct tty_struct *tty) +static void __tty_buffer_flush(struct tty_port *port) { + struct tty_bufhead *buf = &port->buf; struct tty_buffer *thead; - while ((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; - tty_buffer_free(tty, thead); + while ((thead = buf->head) != NULL) { + buf->head = thead->next; + tty_buffer_free(port, thead); } - tty->buf.tail = NULL; + buf->tail = NULL; } /** @@ -134,21 +139,24 @@ static void __tty_buffer_flush(struct tty_struct *tty) void tty_buffer_flush(struct tty_struct *tty) { + struct tty_port *port = tty->port; + struct tty_bufhead *buf = &port->buf; unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); + + spin_lock_irqsave(&buf->lock, flags); /* If the data is being pushed to the tty layer then we can't process it here. Instead set a flag and the flush_to_ldisc path will process the flush request before it exits */ - if (test_bit(TTY_FLUSHING, &tty->flags)) { - set_bit(TTY_FLUSHPENDING, &tty->flags); - spin_unlock_irqrestore(&tty->buf.lock, flags); + if (test_bit(TTYP_FLUSHING, &port->iflags)) { + set_bit(TTYP_FLUSHPENDING, &port->iflags); + spin_unlock_irqrestore(&buf->lock, flags); wait_event(tty->read_wait, - test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); + test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0); return; } else - __tty_buffer_flush(tty); - spin_unlock_irqrestore(&tty->buf.lock, flags); + __tty_buffer_flush(port); + spin_unlock_irqrestore(&buf->lock, flags); } /** @@ -163,9 +171,9 @@ void tty_buffer_flush(struct tty_struct *tty) * Locking: Caller must hold tty->buf.lock */ -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) +static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size) { - struct tty_buffer **tbh = &tty->buf.free; + struct tty_buffer **tbh = &port->buf.free; while ((*tbh) != NULL) { struct tty_buffer *t = *tbh; if (t->size >= size) { @@ -174,14 +182,14 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) t->used = 0; t->commit = 0; t->read = 0; - tty->buf.memory_used += t->size; + port->buf.memory_used += t->size; return t; } tbh = &((*tbh)->next); } /* Round the buffer size out */ size = (size + 0xFF) & ~0xFF; - return tty_buffer_alloc(tty, size); + return tty_buffer_alloc(port, size); /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } @@ -192,29 +200,31 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. - * Locking: Caller must hold tty->buf.lock + * Locking: Caller must hold port->buf.lock */ -static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) +static int __tty_buffer_request_room(struct tty_port *port, size_t size) { + struct tty_bufhead *buf = &port->buf; struct tty_buffer *b, *n; int left; /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ - if ((b = tty->buf.tail) != NULL) + b = buf->tail; + if (b != NULL) left = b->size - b->used; else left = 0; if (left < size) { /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_find(tty, size)) != NULL) { + if ((n = tty_buffer_find(port, size)) != NULL) { if (b != NULL) { b->next = n; b->commit = b->used; } else - tty->buf.head = n; - tty->buf.tail = n; + buf->head = n; + buf->tail = n; } else size = left; } @@ -231,16 +241,17 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. * - * Locking: Takes tty->buf.lock + * Locking: Takes port->buf.lock */ int tty_buffer_request_room(struct tty_struct *tty, size_t size) { + struct tty_port *port = tty->port; unsigned long flags; int length; - spin_lock_irqsave(&tty->buf.lock, flags); - length = __tty_buffer_request_room(tty, size); - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_lock_irqsave(&port->buf.lock, flags); + length = __tty_buffer_request_room(port, size); + spin_unlock_irqrestore(&port->buf.lock, flags); return length; } EXPORT_SYMBOL_GPL(tty_buffer_request_room); @@ -255,12 +266,13 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room); * Queue a series of bytes to the tty buffering. All the characters * passed are marked with the supplied flag. Returns the number added. * - * Locking: Called functions may take tty->buf.lock + * Locking: Called functions may take port->buf.lock */ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, const unsigned char *chars, char flag, size_t size) { + struct tty_bufhead *buf = &tty->port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); @@ -268,18 +280,18 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, unsigned long flags; struct tty_buffer *tb; - spin_lock_irqsave(&tty->buf.lock, flags); - space = __tty_buffer_request_room(tty, goal); - tb = tty->buf.tail; + spin_lock_irqsave(&buf->lock, flags); + space = __tty_buffer_request_room(tty->port, goal); + tb = buf->tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_unlock_irqrestore(&buf->lock, flags); break; } memcpy(tb->char_buf_ptr + tb->used, chars, space); memset(tb->flag_buf_ptr + tb->used, flag, space); tb->used += space; - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_unlock_irqrestore(&buf->lock, flags); copied += space; chars += space; /* There is a small chance that we need to split the data over @@ -300,12 +312,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); * the flags array indicates the status of the character. Returns the * number added. * - * Locking: Called functions may take tty->buf.lock + * Locking: Called functions may take port->buf.lock */ int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size) { + struct tty_bufhead *buf = &tty->port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); @@ -313,18 +326,18 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned long __flags; struct tty_buffer *tb; - spin_lock_irqsave(&tty->buf.lock, __flags); - space = __tty_buffer_request_room(tty, goal); - tb = tty->buf.tail; + spin_lock_irqsave(&buf->lock, __flags); + space = __tty_buffer_request_room(tty->port, goal); + tb = buf->tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { - spin_unlock_irqrestore(&tty->buf.lock, __flags); + spin_unlock_irqrestore(&buf->lock, __flags); break; } memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space); tb->used += space; - spin_unlock_irqrestore(&tty->buf.lock, __flags); + spin_unlock_irqrestore(&buf->lock, __flags); copied += space; chars += space; flags += space; @@ -342,18 +355,23 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); * Takes any pending buffers and transfers their ownership to the * ldisc side of the queue. It then schedules those characters for * processing by the line discipline. + * Note that this function can only be used when the low_latency flag + * is unset. Otherwise the workqueue won't be flushed. * - * Locking: Takes tty->buf.lock + * Locking: Takes port->buf.lock */ void tty_schedule_flip(struct tty_struct *tty) { + struct tty_bufhead *buf = &tty->port->buf; unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) - tty->buf.tail->commit = tty->buf.tail->used; - spin_unlock_irqrestore(&tty->buf.lock, flags); - schedule_work(&tty->buf.work); + WARN_ON(tty->low_latency); + + spin_lock_irqsave(&buf->lock, flags); + if (buf->tail != NULL) + buf->tail->commit = buf->tail->used; + spin_unlock_irqrestore(&buf->lock, flags); + schedule_work(&buf->work); } EXPORT_SYMBOL(tty_schedule_flip); @@ -369,26 +387,27 @@ EXPORT_SYMBOL(tty_schedule_flip); * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! * - * Locking: May call functions taking tty->buf.lock + * Locking: May call functions taking port->buf.lock */ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, - size_t size) + size_t size) { + struct tty_bufhead *buf = &tty->port->buf; int space; unsigned long flags; struct tty_buffer *tb; - spin_lock_irqsave(&tty->buf.lock, flags); - space = __tty_buffer_request_room(tty, size); + spin_lock_irqsave(&buf->lock, flags); + space = __tty_buffer_request_room(tty->port, size); - tb = tty->buf.tail; + tb = buf->tail; if (likely(space)) { *chars = tb->char_buf_ptr + tb->used; memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); tb->used += space; } - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_unlock_irqrestore(&buf->lock, flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); @@ -406,26 +425,27 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! * - * Locking: May call functions taking tty->buf.lock + * Locking: May call functions taking port->buf.lock */ int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) { + struct tty_bufhead *buf = &tty->port->buf; int space; unsigned long __flags; struct tty_buffer *tb; - spin_lock_irqsave(&tty->buf.lock, __flags); - space = __tty_buffer_request_room(tty, size); + spin_lock_irqsave(&buf->lock, __flags); + space = __tty_buffer_request_room(tty->port, size); - tb = tty->buf.tail; + tb = buf->tail; if (likely(space)) { *chars = tb->char_buf_ptr + tb->used; *flags = tb->flag_buf_ptr + tb->used; tb->used += space; } - spin_unlock_irqrestore(&tty->buf.lock, __flags); + spin_unlock_irqrestore(&buf->lock, __flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); @@ -446,20 +466,25 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); static void flush_to_ldisc(struct work_struct *work) { - struct tty_struct *tty = - container_of(work, struct tty_struct, buf.work); + struct tty_port *port = container_of(work, struct tty_port, buf.work); + struct tty_bufhead *buf = &port->buf; + struct tty_struct *tty; unsigned long flags; struct tty_ldisc *disc; + tty = port->itty; + if (WARN_RATELIMIT(tty == NULL, "tty is NULL")) + return; + disc = tty_ldisc_ref(tty); if (disc == NULL) /* !TTY_LDISC */ return; - spin_lock_irqsave(&tty->buf.lock, flags); + spin_lock_irqsave(&buf->lock, flags); - if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) { + if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) { struct tty_buffer *head; - while ((head = tty->buf.head) != NULL) { + while ((head = buf->head) != NULL) { int count; char *char_buf; unsigned char *flag_buf; @@ -468,14 +493,14 @@ static void flush_to_ldisc(struct work_struct *work) if (!count) { if (head->next == NULL) break; - tty->buf.head = head->next; - tty_buffer_free(tty, head); + buf->head = head->next; + tty_buffer_free(port, head); continue; } /* Ldisc or user is trying to flush the buffers we are feeding to the ldisc, stop feeding the line discipline as we want to empty the queue */ - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) + if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) break; if (!tty->receive_room) break; @@ -484,22 +509,22 @@ static void flush_to_ldisc(struct work_struct *work) char_buf = head->char_buf_ptr + head->read; flag_buf = head->flag_buf_ptr + head->read; head->read += count; - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_unlock_irqrestore(&buf->lock, flags); disc->ops->receive_buf(tty, char_buf, flag_buf, count); - spin_lock_irqsave(&tty->buf.lock, flags); + spin_lock_irqsave(&buf->lock, flags); } - clear_bit(TTY_FLUSHING, &tty->flags); + clear_bit(TTYP_FLUSHING, &port->iflags); } /* We may have a deferred request to flush the input buffer, if so pull the chain under the lock and empty the queue */ - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { - __tty_buffer_flush(tty); - clear_bit(TTY_FLUSHPENDING, &tty->flags); + if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) { + __tty_buffer_flush(port); + clear_bit(TTYP_FLUSHPENDING, &port->iflags); wake_up(&tty->read_wait); } - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_unlock_irqrestore(&buf->lock, flags); tty_ldisc_deref(disc); } @@ -514,7 +539,8 @@ static void flush_to_ldisc(struct work_struct *work) */ void tty_flush_to_ldisc(struct tty_struct *tty) { - flush_work(&tty->buf.work); + if (!tty->low_latency) + flush_work(&tty->port->buf.work); } /** @@ -532,16 +558,18 @@ void tty_flush_to_ldisc(struct tty_struct *tty) void tty_flip_buffer_push(struct tty_struct *tty) { + struct tty_bufhead *buf = &tty->port->buf; unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) - tty->buf.tail->commit = tty->buf.tail->used; - spin_unlock_irqrestore(&tty->buf.lock, flags); + + spin_lock_irqsave(&buf->lock, flags); + if (buf->tail != NULL) + buf->tail->commit = buf->tail->used; + spin_unlock_irqrestore(&buf->lock, flags); if (tty->low_latency) - flush_to_ldisc(&tty->buf.work); + flush_to_ldisc(&buf->work); else - schedule_work(&tty->buf.work); + schedule_work(&buf->work); } EXPORT_SYMBOL(tty_flip_buffer_push); @@ -555,13 +583,15 @@ EXPORT_SYMBOL(tty_flip_buffer_push); * Locking: none */ -void tty_buffer_init(struct tty_struct *tty) +void tty_buffer_init(struct tty_port *port) { - spin_lock_init(&tty->buf.lock); - tty->buf.head = NULL; - tty->buf.tail = NULL; - tty->buf.free = NULL; - tty->buf.memory_used = 0; - INIT_WORK(&tty->buf.work, flush_to_ldisc); + struct tty_bufhead *buf = &port->buf; + + spin_lock_init(&buf->lock); + buf->head = NULL; + buf->tail = NULL; + buf->free = NULL; + buf->memory_used = 0; + INIT_WORK(&buf->work, flush_to_ldisc); } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 2ea176b2280..a3eba7f359e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -186,7 +186,6 @@ void free_tty_struct(struct tty_struct *tty) if (tty->dev) put_device(tty->dev); kfree(tty->write_buf); - tty_buffer_free_all(tty); tty->magic = 0xDEADDEAD; kfree(tty); } @@ -1417,6 +1416,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", __func__, tty->driver->name); + tty->port->itty = tty; + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need @@ -1552,6 +1553,7 @@ static void release_tty(struct tty_struct *tty, int idx) tty->ops->shutdown(tty); tty_free_termios(tty); tty_driver_remove_tty(tty->driver, tty); + tty->port->itty = NULL; if (tty->link) tty_kref_put(tty->link); @@ -1625,7 +1627,6 @@ int tty_release(struct inode *inode, struct file *filp) struct tty_struct *tty = file_tty(filp); struct tty_struct *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; - int devpts; int idx; char buf[64]; @@ -1640,7 +1641,6 @@ int tty_release(struct inode *inode, struct file *filp) idx = tty->index; pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); - devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; /* Review: parallel close */ o_tty = tty->link; @@ -1799,9 +1799,6 @@ int tty_release(struct inode *inode, struct file *filp) release_tty(tty, idx); mutex_unlock(&tty_mutex); - /* Make this pty number available for reallocation */ - if (devpts) - devpts_kill_index(inode, idx); return 0; } @@ -2937,19 +2934,13 @@ void initialize_tty_struct(struct tty_struct *tty, tty_ldisc_init(tty); tty->session = NULL; tty->pgrp = NULL; - tty->overrun_time = jiffies; - tty_buffer_init(tty); mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup); - mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); - mutex_init(&tty->output_lock); - mutex_init(&tty->echo_lock); - spin_lock_init(&tty->read_lock); spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 0f2a2c5e704..f4e6754525d 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -512,7 +512,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) static int tty_ldisc_halt(struct tty_struct *tty) { clear_bit(TTY_LDISC, &tty->flags); - return cancel_work_sync(&tty->buf.work); + return cancel_work_sync(&tty->port->buf.work); } /** @@ -525,7 +525,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) { flush_work(&tty->hangup_work); flush_work(&tty->SAK_work); - flush_work(&tty->buf.work); + flush_work(&tty->port->buf.work); } /** @@ -704,9 +704,9 @@ enable: /* Restart the work queue in case no characters kick it off. Safe if already running */ if (work) - schedule_work(&tty->buf.work); + schedule_work(&tty->port->buf.work); if (o_work) - schedule_work(&o_tty->buf.work); + schedule_work(&o_tty->port->buf.work); mutex_unlock(&tty->ldisc_mutex); tty_unlock(tty); return retval; @@ -817,7 +817,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) */ clear_bit(TTY_LDISC, &tty->flags); tty_unlock(tty); - cancel_work_sync(&tty->buf.work); + cancel_work_sync(&tty->port->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: tty_lock(tty); @@ -897,6 +897,11 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) static void tty_ldisc_kill(struct tty_struct *tty) { + /* There cannot be users from userspace now. But there still might be + * drivers holding a reference via tty_ldisc_ref. Do not steal them the + * ldisc until they are done. */ + tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT); + mutex_lock(&tty->ldisc_mutex); /* * Now kill off the ldisc diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index d7bdd8d0c23..416b42f7c34 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -21,6 +21,7 @@ void tty_port_init(struct tty_port *port) { memset(port, 0, sizeof(*port)); + tty_buffer_init(port); init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->delta_msr_wait); @@ -126,6 +127,7 @@ static void tty_port_destructor(struct kref *kref) struct tty_port *port = container_of(kref, struct tty_port, kref); if (port->xmit_buf) free_page((unsigned long)port->xmit_buf); + tty_buffer_free_all(port); if (port->ops->destruct) port->ops->destruct(port); else diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 8e9b4be97a2..60b7b692605 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -341,15 +341,11 @@ int paste_selection(struct tty_struct *tty) struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); - console_lock(); poke_blanked_console(); console_unlock(); - /* FIXME: wtf is this supposed to achieve ? */ - ld = tty_ldisc_ref(tty); - if (!ld) - ld = tty_ldisc_ref_wait(tty); + ld = tty_ldisc_ref_wait(tty); /* FIXME: this is completely unsafe */ add_wait_queue(&vc->paste_wait, &wait); @@ -361,8 +357,7 @@ int paste_selection(struct tty_struct *tty) } count = sel_buffer_lth - pasted; count = min(count, tty->receive_room); - tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, - NULL, count); + ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } remove_wait_queue(&vc->paste_wait, &wait); diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 6f3ea9bbc81..c48b93813fc 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -97,6 +97,7 @@ config UIO_NETX config UIO_PRUSS tristate "Texas Instruments PRUSS driver" depends on ARCH_DAVINCI_DA850 + select GENERIC_ALLOCATOR help PRUSS driver for OMAPL138/DA850/AM18XX devices PRUSS driver requires user space components, examples and user space diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 33a7a273b45..f8738de342b 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -25,7 +25,7 @@ #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <mach/sram.h> +#include <linux/genalloc.h> #define DRV_NAME "pruss_uio" #define DRV_VERSION "1.0" @@ -65,10 +65,11 @@ struct uio_pruss_dev { dma_addr_t sram_paddr; dma_addr_t ddr_paddr; void __iomem *prussio_vaddr; - void *sram_vaddr; + unsigned long sram_vaddr; void *ddr_vaddr; unsigned int hostirq_start; unsigned int pintc_base; + struct gen_pool *sram_pool; }; static irqreturn_t pruss_handler(int irq, struct uio_info *info) @@ -106,7 +107,9 @@ static void pruss_cleanup(struct platform_device *dev, gdev->ddr_paddr); } if (gdev->sram_vaddr) - sram_free(gdev->sram_vaddr, sram_pool_sz); + gen_pool_free(gdev->sram_pool, + gdev->sram_vaddr, + sram_pool_sz); kfree(gdev->info); clk_put(gdev->pruss_clk); kfree(gdev); @@ -152,10 +155,17 @@ static int __devinit pruss_probe(struct platform_device *dev) goto out_free; } - gdev->sram_vaddr = sram_alloc(sram_pool_sz, &(gdev->sram_paddr)); - if (!gdev->sram_vaddr) { - dev_err(&dev->dev, "Could not allocate SRAM pool\n"); - goto out_free; + if (pdata->sram_pool) { + gdev->sram_pool = pdata->sram_pool; + gdev->sram_vaddr = + gen_pool_alloc(gdev->sram_pool, sram_pool_sz); + if (!gdev->sram_vaddr) { + dev_err(&dev->dev, "Could not allocate SRAM pool\n"); + goto out_free; + } + gdev->sram_paddr = + gen_pool_virt_to_phys(gdev->sram_pool, + gdev->sram_vaddr); } gdev->ddr_vaddr = dma_alloc_coherent(&dev->dev, extram_pool_sz, diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1e741bca026..f034716190f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2151,8 +2151,15 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; + unsigned long flags; irqreturn_t rc; + /* IRQF_DISABLED doesn't work correctly with shared IRQs + * when the first handler doesn't use it. So let's just + * assume it's never used. + */ + local_irq_save(flags); + if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) rc = IRQ_NONE; else if (hcd->driver->irq(hcd) == IRQ_NONE) @@ -2160,6 +2167,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) else rc = IRQ_HANDLED; + local_irq_restore(flags); return rc; } EXPORT_SYMBOL_GPL(usb_hcd_irq); @@ -2347,6 +2355,14 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, int retval; if (hcd->driver->irq) { + + /* IRQF_DISABLED doesn't work as advertised when used together + * with IRQF_SHARED. As usb_hcd_irq() will always disable + * interrupts we can remove it here. + */ + if (irqflags & IRQF_SHARED) + irqflags &= ~IRQF_DISABLED; + snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); retval = request_irq(irqnum, &usb_hcd_irq, irqflags, diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index e426ad626d7..4bfa78af379 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -20,6 +20,7 @@ #include <linux/usb/ehci_def.h> #include <linux/delay.h> #include <linux/serial_core.h> +#include <linux/kconfig.h> #include <linux/kgdb.h> #include <linux/kthread.h> #include <asm/io.h> @@ -614,12 +615,6 @@ err: return -ENODEV; } -int dbgp_external_startup(struct usb_hcd *hcd) -{ - return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup(); -} -EXPORT_SYMBOL_GPL(dbgp_external_startup); - static int ehci_reset_port(int port) { u32 portsc; @@ -979,6 +974,7 @@ struct console early_dbgp_console = { .index = -1, }; +#if IS_ENABLED(CONFIG_USB_EHCI_HCD) int dbgp_reset_prep(struct usb_hcd *hcd) { int ret = xen_dbgp_reset_prep(hcd); @@ -1007,6 +1003,13 @@ int dbgp_reset_prep(struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(dbgp_reset_prep); +int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup(); +} +EXPORT_SYMBOL_GPL(dbgp_external_startup); +#endif /* USB_EHCI_HCD */ + #ifdef CONFIG_KGDB static char kgdbdbgp_buf[DBGP_MAX_PACKET]; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 2a4749c3eb3..23afa06b65a 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -44,7 +44,7 @@ #include <asm/unaligned.h> #include <asm/mach-types.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include <mach/usb.h> @@ -61,6 +61,8 @@ #define DRIVER_DESC "OMAP UDC driver" #define DRIVER_VERSION "4 October 2004" +#define OMAP_DMA_USB_W2FC_TX0 29 + /* * The OMAP UDC needs _very_ early endpoint setup: before enabling the * D+ pullup to allow enumeration. That's too early for the gadget diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 6458764994e..4ec3c0d7a18 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -20,6 +20,7 @@ #include <linux/ctype.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> +#include <linux/if_vlan.h> #include "u_ether.h" @@ -295,7 +296,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) while (skb2) { if (status < 0 || ETH_HLEN > skb2->len - || skb2->len > ETH_FRAME_LEN) { + || skb2->len > VLAN_ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; DBG(dev, "rx length %d\n", skb2->len); diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c index ca759652626..aa0f328922d 100644 --- a/drivers/usb/host/ehci-ls1x.c +++ b/drivers/usb/host/ehci-ls1x.c @@ -113,7 +113,7 @@ static int ehci_hcd_ls1x_probe(struct platform_device *pdev) goto err_put_hcd; } - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (ret) goto err_put_hcd; diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 4a08fc0b27c..8e58a5fa199 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -24,7 +24,6 @@ #include <linux/usb/ulpi.h> #include <linux/slab.h> -#include <mach/hardware.h> #include <linux/platform_data/usb-ehci-mxc.h> #include <asm/mach-types.h> diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index d7fe287d067..0d5ac36fdf4 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -39,12 +39,13 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/usb/ulpi.h> -#include <plat/usb.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> #include <linux/gpio.h> #include <linux/clk.h> +#include <linux/platform_data/usb-omap.h> + /* EHCI Register Set */ #define EHCI_INSNREG04 (0xA0) #define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5) diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 9c2717d6673..e7e8275028d 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -14,6 +14,9 @@ #include <linux/mbus.h> #include <linux/clk.h> #include <linux/platform_data/usb-ehci-orion.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> #define rdl(off) __raw_readl(hcd->regs + (off)) #define wrl(off, val) __raw_writel((val), hcd->regs + (off)) @@ -181,6 +184,8 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, } } +static u64 ehci_orion_dma_mask = DMA_BIT_MASK(32); + static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) { struct orion_ehci_data *pd = pdev->dev.platform_data; @@ -191,13 +196,17 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) struct clk *clk; void __iomem *regs; int irq, err; + enum orion_ehci_phy_ver phy_version; if (usb_disabled()) return -ENODEV; pr_debug("Initializing Orion-SoC USB Host Controller\n"); - irq = platform_get_irq(pdev, 0); + if (pdev->dev.of_node) + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + else + irq = platform_get_irq(pdev, 0); if (irq <= 0) { dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n", @@ -215,6 +224,14 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) goto err1; } + /* + * Right now device-tree probed devices don't get dma_mask + * set. Since shared usb code relies on it, set it here for + * now. Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &ehci_orion_dma_mask; + if (!request_mem_region(res->start, resource_size(res), ehci_orion_hc_driver.description)) { dev_dbg(&pdev->dev, "controller already in use\n"); @@ -262,7 +279,12 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) /* * setup Orion USB controller. */ - switch (pd->phy_version) { + if (pdev->dev.of_node) + phy_version = EHCI_PHY_NA; + else + phy_version = pd->phy_version; + + switch (phy_version) { case EHCI_PHY_NA: /* dont change USB phy settings */ break; case EHCI_PHY_ORION: @@ -317,9 +339,19 @@ static int __exit ehci_orion_drv_remove(struct platform_device *pdev) MODULE_ALIAS("platform:orion-ehci"); +static const struct of_device_id ehci_orion_dt_ids[] __devinitdata = { + { .compatible = "marvell,orion-ehci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids); + static struct platform_driver ehci_orion_driver = { .probe = ehci_orion_drv_probe, .remove = __exit_p(ehci_orion_drv_remove), .shutdown = usb_hcd_platform_shutdown, - .driver.name = "orion-ehci", + .driver = { + .name = "orion-ehci", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ehci_orion_dt_ids), + }, }; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 6223d175784..2de089001ae 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -28,7 +28,10 @@ #include <linux/pm_runtime.h> #include <linux/usb/tegra_usb_phy.h> -#include <mach/iomap.h> + +#define TEGRA_USB_BASE 0xC5000000 +#define TEGRA_USB2_BASE 0xC5004000 +#define TEGRA_USB3_BASE 0xC5008000 #define TEGRA_USB_DMA_ALIGN 32 diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 4531d03503c..439e6e4f2d6 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -25,7 +25,6 @@ #include <asm/mach-types.h> #include <mach/mux.h> -#include <plat/fpga.h> #include <mach/hardware.h> #include <mach/irqs.h> @@ -93,14 +92,14 @@ static int omap_ohci_transceiver_power(int on) { if (on) { if (machine_is_omap_innovator() && cpu_is_omap1510()) - fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) + __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); else if (machine_is_omap_osk()) tps65010_set_gpio_out_value(GPIO1, LOW); } else { if (machine_is_omap_innovator() && cpu_is_omap1510()) - fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) + __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); else if (machine_is_omap_osk()) diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index 1b8133b6e45..bd7803dce9b 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -30,7 +30,6 @@ */ #include <linux/platform_device.h> -#include <plat/usb.h> #include <linux/pm_runtime.h> /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c index 84201cd1a47..41e378f17c6 100644 --- a/drivers/usb/host/ohci-xls.c +++ b/drivers/usb/host/ohci-xls.c @@ -56,7 +56,7 @@ static int ohci_xls_probe_internal(const struct hc_driver *driver, goto err3; } - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err4; return retval; diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index c964d6af178..a87cdd2387c 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -34,8 +34,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/usb/nop-usb-xceiv.h> - -#include <plat/usb.h> +#include <linux/platform_data/usb-omap.h> #include "musb_core.h" diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index ff5f112053d..aa34f22181c 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -38,13 +38,12 @@ #include <linux/pm_runtime.h> #include <linux/module.h> #include <linux/usb/nop-usb-xceiv.h> +#include <linux/platform_data/usb-omap.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_address.h> -#include <plat/usb.h> - #include "musb_core.h" #ifdef CONFIG_OF diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d0b87e7b4ab..b6b84dacc79 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -707,11 +707,12 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = musb_readw(epio, MUSB_RXCOUNT); /* - * use mode 1 only if we expect data of at least ep packet_sz - * and have not yet received a short packet + * Enable Mode 1 on RX transfers only when short_not_ok flag + * is set. Currently short_not_ok flag is set only from + * file_storage and f_mass_storage drivers */ - if ((request->length - request->actual >= musb_ep->packet_sz) && - (fifo_count >= musb_ep->packet_sz)) + + if (request->short_not_ok && fifo_count == musb_ep->packet_sz) use_mode_1 = 1; else use_mode_1 = 0; @@ -727,6 +728,27 @@ static void rxstate(struct musb *musb, struct musb_request *req) c = musb->dma_controller; channel = musb_ep->dma; + /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in + * mode 0 only. So we do not get endpoint interrupts due to DMA + * completion. We only get interrupts from DMA controller. + * + * We could operate in DMA mode 1 if we knew the size of the tranfer + * in advance. For mass storage class, request->length = what the host + * sends, so that'd work. But for pretty much everything else, + * request->length is routinely more than what the host sends. For + * most these gadgets, end of is signified either by a short packet, + * or filling the last byte of the buffer. (Sending extra data in + * that last pckate should trigger an overflow fault.) But in mode 1, + * we don't get DMA completion interrupt for short packets. + * + * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1), + * to get endpoint interrupt on every DMA req, but that didn't seem + * to work reliably. + * + * REVISIT an updated g_file_storage can set req->short_not_ok, which + * then becomes usable as a runtime "use mode 1" hint... + */ + /* Experimental: Mode1 works with mass storage use cases */ if (use_mode_1) { csr |= MUSB_RXCSR_AUTOCLEAR; diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index b85f3973e78..8ef656659fc 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -10,7 +10,7 @@ #ifndef __MUSB_OMAP243X_H__ #define __MUSB_OMAP243X_H__ -#include <plat/usb.h> +#include <linux/platform_data/usb-omap.h> /* * OMAP2430-specific definitions diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index 7a62b95dac2..bfca114f7c5 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -16,7 +16,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include "musb_core.h" #include "tusb6010.h" @@ -25,6 +25,13 @@ #define MAX_DMAREQ 5 /* REVISIT: Really 6, but req5 not OK */ +#define OMAP24XX_DMA_EXT_DMAREQ0 2 +#define OMAP24XX_DMA_EXT_DMAREQ1 3 +#define OMAP242X_DMA_EXT_DMAREQ2 14 +#define OMAP242X_DMA_EXT_DMAREQ3 15 +#define OMAP242X_DMA_EXT_DMAREQ4 16 +#define OMAP242X_DMA_EXT_DMAREQ5 64 + struct tusb_omap_dma_ch { struct musb *musb; void __iomem *tbase; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index d62a91fedc2..0e62f504410 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -65,7 +65,7 @@ static int __devinit ux500_probe(struct platform_device *pdev) struct platform_device *musb; struct ux500_glue *glue; struct clk *clk; - + int musbid; int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index d8c8a42bff3..6223062d5d1 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -58,7 +58,7 @@ config USB_ULPI_VIEWPORT config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" - depends on TWL4030_CORE && REGULATOR_TWL4030 + depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS select USB_OTG_UTILS help Enable this to support the USB OTG transceiver on TWL4030 @@ -68,7 +68,7 @@ config TWL4030_USB config TWL6030_USB tristate "TWL6030 USB Transceiver Driver" - depends on TWL4030_CORE && OMAP_USB2 + depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS select USB_OTG_UTILS help Enable this to support the USB OTG transceiver on TWL6030 diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 987116f9efc..9d13c81754e 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -29,7 +29,9 @@ #include <linux/usb/ulpi.h> #include <asm/mach-types.h> #include <linux/usb/tegra_usb_phy.h> -#include <mach/iomap.h> + +#define TEGRA_USB_BASE 0xC5000000 +#define TEGRA_USB_SIZE SZ_16K #define ULPI_VIEWPORT 0x170 diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7179b0c5f81..cff8dd5b462 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -2430,7 +2430,7 @@ static void keyspan_release(struct usb_serial *serial) static int keyspan_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct keyspan_port_private *s_priv; + struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; const struct keyspan_device_details *d_details; struct callbacks *cback; @@ -2445,7 +2445,6 @@ static int keyspan_port_probe(struct usb_serial_port *port) if (!p_priv) return -ENOMEM; - s_priv = usb_get_serial_data(port->serial); p_priv->device_details = d_details; /* Setup values for the various callback routines */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5dee7d61241..edc64bb6f45 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -158,6 +158,7 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 +#define NOVATELWIRELESS_PRODUCT_E362 0x9010 #define NOVATELWIRELESS_PRODUCT_G1 0xA001 #define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 @@ -193,6 +194,9 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 #define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 +#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */ +#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */ + #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da #define KYOCERA_PRODUCT_KPC680 0x180a @@ -283,6 +287,7 @@ static void option_instat_callback(struct urb *urb); /* ALCATEL PRODUCTS */ #define ALCATEL_VENDOR_ID 0x1bbb #define ALCATEL_PRODUCT_X060S_X200 0x0000 +#define ALCATEL_PRODUCT_X220_X500D 0x0017 #define PIRELLI_VENDOR_ID 0x1266 #define PIRELLI_PRODUCT_C100_1 0x1002 @@ -706,6 +711,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, /* Novatel Ovation MC551 a.k.a. Verizon USB551L */ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -728,6 +734,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, @@ -1157,6 +1165,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 61a73ad1a18..a3e9c095f0d 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -455,9 +455,6 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, struct usb_serial *serial = port->serial; struct urb *urb; - if (endpoint == -1) - return NULL; /* endpoint not needed */ - urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ if (urb == NULL) { dev_dbg(&serial->interface->dev, @@ -489,6 +486,9 @@ int usb_wwan_port_probe(struct usb_serial_port *port) init_usb_anchor(&portdata->delayed); for (i = 0; i < N_IN_URB; i++) { + if (!port->bulk_in_size) + break; + buffer = (u8 *)__get_free_page(GFP_KERNEL); if (!buffer) goto bail_out_error; @@ -502,8 +502,8 @@ int usb_wwan_port_probe(struct usb_serial_port *port) } for (i = 0; i < N_OUT_URB; i++) { - if (port->bulk_out_endpointAddress == -1) - continue; + if (!port->bulk_out_size) + break; buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); if (!buffer) diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index cf2688de083..e501dbc966b 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -33,7 +33,6 @@ #include <linux/math64.h> #include <linux/platform_data/video-imxfb.h> -#include <mach/hardware.h> /* * Complain if VAR is out of range. @@ -53,8 +52,8 @@ #define LCDC_SIZE 0x04 #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20) -#define YMAX_MASK (cpu_is_mx1() ? 0x1ff : 0x3ff) -#define SIZE_YMAX(y) ((y) & YMAX_MASK) +#define YMAX_MASK_IMX1 0x1ff +#define YMAX_MASK_IMX21 0x3ff #define LCDC_VPW 0x08 #define VPW_VPW(x) ((x) & 0x3ff) @@ -128,12 +127,18 @@ struct imxfb_rgb { struct fb_bitfield transp; }; +enum imxfb_type { + IMX1_FB, + IMX21_FB, +}; + struct imxfb_info { struct platform_device *pdev; void __iomem *regs; struct clk *clk_ipg; struct clk *clk_ahb; struct clk *clk_per; + enum imxfb_type devtype; /* * These are the addresses we mapped @@ -168,6 +173,24 @@ struct imxfb_info { void (*backlight_power)(int); }; +static struct platform_device_id imxfb_devtype[] = { + { + .name = "imx1-fb", + .driver_data = IMX1_FB, + }, { + .name = "imx21-fb", + .driver_data = IMX21_FB, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imxfb_devtype); + +static inline int is_imx1_fb(struct imxfb_info *fbi) +{ + return fbi->devtype == IMX1_FB; +} + #define IMX_NAME "IMX" /* @@ -366,7 +389,7 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) break; case 16: default: - if (cpu_is_mx1()) + if (is_imx1_fb(fbi)) pcr |= PCR_BPIX_12; else pcr |= PCR_BPIX_16; @@ -596,6 +619,7 @@ static struct fb_ops imxfb_ops = { static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; + u32 ymax_mask = is_imx1_fb(fbi) ? YMAX_MASK_IMX1 : YMAX_MASK_IMX21; pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, @@ -617,7 +641,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf if (var->right_margin > 255) printk(KERN_ERR "%s: invalid right_margin %d\n", info->fix.id, var->right_margin); - if (var->yres < 1 || var->yres > YMAX_MASK) + if (var->yres < 1 || var->yres > ymax_mask) printk(KERN_ERR "%s: invalid yres %d\n", info->fix.id, var->yres); if (var->vsync_len > 100) @@ -645,7 +669,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf VCR_V_WAIT_2(var->upper_margin), fbi->regs + LCDC_VCR); - writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), + writel(SIZE_XMAX(var->xres) | (var->yres & ymax_mask), fbi->regs + LCDC_SIZE); writel(fbi->pcr, fbi->regs + LCDC_PCR); @@ -765,6 +789,7 @@ static int __init imxfb_probe(struct platform_device *pdev) return -ENOMEM; fbi = info->par; + fbi->devtype = pdev->id_entry->driver_data; if (!fb_mode) fb_mode = pdata->mode[0].mode.name; @@ -939,6 +964,7 @@ static struct platform_driver imxfb_driver = { .driver = { .name = DRIVER_NAME, }, + .id_table = imxfb_devtype, }; static int imxfb_setup(void) diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index ce1d452464e..73688720857 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -26,10 +26,9 @@ #include <linux/console.h> #include <linux/clk.h> #include <linux/mutex.h> +#include <linux/dma/ipu-dma.h> #include <linux/platform_data/dma-imx.h> -#include <mach/hardware.h> -#include <mach/ipu.h> #include <linux/platform_data/video-mx3fb.h> #include <asm/io.h> diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c index b38b1dd15ce..2ee423279e3 100644 --- a/drivers/video/omap/lcd_inn1510.c +++ b/drivers/video/omap/lcd_inn1510.c @@ -23,7 +23,8 @@ #include <linux/platform_device.h> #include <linux/io.h> -#include <plat/fpga.h> +#include <mach/hardware.h> + #include "omapfb.h" static int innovator1510_panel_init(struct lcd_panel *panel, @@ -38,13 +39,13 @@ static void innovator1510_panel_cleanup(struct lcd_panel *panel) static int innovator1510_panel_enable(struct lcd_panel *panel) { - fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL); + __raw_writeb(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL); return 0; } static void innovator1510_panel_disable(struct lcd_panel *panel) { - fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL); + __raw_writeb(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL); } static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel) diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c index 7767338f8b1..c39d6e46f8c 100644 --- a/drivers/video/omap/lcdc.c +++ b/drivers/video/omap/lcdc.c @@ -31,7 +31,7 @@ #include <linux/gfp.h> #include <mach/lcdc.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include <asm/mach-types.h> diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 4351c438b76..1b5ee8ec192 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -30,7 +30,7 @@ #include <linux/uaccess.h> #include <linux/module.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include "omapfb.h" #include "lcdc.h" diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c index f79c137753d..c510a445739 100644 --- a/drivers/video/omap/sossi.c +++ b/drivers/video/omap/sossi.c @@ -25,7 +25,7 @@ #include <linux/io.h> #include <linux/interrupt.h> -#include <plat/dma.h> +#include <plat-omap/dma-omap.h> #include "omapfb.h" #include "lcdc.h" diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index b2af72dc20b..d94ef9e31a3 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -237,7 +237,7 @@ static int __init omap_dss_probe(struct platform_device *pdev) core.pdev = pdev; - dss_features_init(); + dss_features_init(pdata->version); dss_apply_init(); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b43477a5fae..a5ab354f267 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -37,8 +37,6 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <plat/cpu.h> - #include <video/omapdss.h> #include "dss.h" @@ -4042,29 +4040,44 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { .gfx_fifo_workaround = true, }; -static int __init dispc_init_features(struct device *dev) +static int __init dispc_init_features(struct platform_device *pdev) { + struct omap_dss_board_info *pdata = pdev->dev.platform_data; const struct dispc_features *src; struct dispc_features *dst; - dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); if (!dst) { - dev_err(dev, "Failed to allocate DISPC Features\n"); + dev_err(&pdev->dev, "Failed to allocate DISPC Features\n"); return -ENOMEM; } - if (cpu_is_omap24xx()) { + switch (pdata->version) { + case OMAPDSS_VER_OMAP24xx: src = &omap24xx_dispc_feats; - } else if (cpu_is_omap34xx()) { - if (omap_rev() < OMAP3430_REV_ES3_0) - src = &omap34xx_rev1_0_dispc_feats; - else - src = &omap34xx_rev3_0_dispc_feats; - } else if (cpu_is_omap44xx()) { + break; + + case OMAPDSS_VER_OMAP34xx_ES1: + src = &omap34xx_rev1_0_dispc_feats; + break; + + case OMAPDSS_VER_OMAP34xx_ES3: + case OMAPDSS_VER_OMAP3630: + case OMAPDSS_VER_AM35xx: + src = &omap34xx_rev3_0_dispc_feats; + break; + + case OMAPDSS_VER_OMAP4430_ES1: + case OMAPDSS_VER_OMAP4430_ES2: + case OMAPDSS_VER_OMAP4: src = &omap44xx_dispc_feats; - } else if (soc_is_omap54xx()) { + break; + + case OMAPDSS_VER_OMAP5: src = &omap44xx_dispc_feats; - } else { + break; + + default: return -ENODEV; } @@ -4084,7 +4097,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dispc.pdev = pdev; - r = dispc_init_features(&dispc.pdev->dev); + r = dispc_init_features(dispc.pdev); if (r) return r; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 2ab1c3e9655..363852a0f76 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -35,8 +35,6 @@ #include <video/omapdss.h> -#include <plat/cpu.h> - #include "dss.h" #include "dss_features.h" @@ -792,29 +790,46 @@ static const struct dss_features omap54xx_dss_feats __initconst = { .dpi_select_source = &dss_dpi_select_source_omap5, }; -static int __init dss_init_features(struct device *dev) +static int __init dss_init_features(struct platform_device *pdev) { + struct omap_dss_board_info *pdata = pdev->dev.platform_data; const struct dss_features *src; struct dss_features *dst; - dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); if (!dst) { - dev_err(dev, "Failed to allocate local DSS Features\n"); + dev_err(&pdev->dev, "Failed to allocate local DSS Features\n"); return -ENOMEM; } - if (cpu_is_omap24xx()) + switch (pdata->version) { + case OMAPDSS_VER_OMAP24xx: src = &omap24xx_dss_feats; - else if (cpu_is_omap34xx()) + break; + + case OMAPDSS_VER_OMAP34xx_ES1: + case OMAPDSS_VER_OMAP34xx_ES3: + case OMAPDSS_VER_AM35xx: src = &omap34xx_dss_feats; - else if (cpu_is_omap3630()) + break; + + case OMAPDSS_VER_OMAP3630: src = &omap3630_dss_feats; - else if (cpu_is_omap44xx()) + break; + + case OMAPDSS_VER_OMAP4430_ES1: + case OMAPDSS_VER_OMAP4430_ES2: + case OMAPDSS_VER_OMAP4: src = &omap44xx_dss_feats; - else if (soc_is_omap54xx()) + break; + + case OMAPDSS_VER_OMAP5: src = &omap54xx_dss_feats; - else + break; + + default: return -ENODEV; + } memcpy(dst, src, sizeof(*dst)); dss.feat = dst; @@ -831,7 +846,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.pdev = pdev; - r = dss_init_features(&dss.pdev->dev); + r = dss_init_features(dss.pdev); if (r) return r; diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index acbc1e1efba..3e8287c8709 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -23,7 +23,6 @@ #include <linux/slab.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -825,10 +824,20 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { }; -void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data) +void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data, + enum omapdss_version version) { - if (cpu_is_omap44xx()) + switch (version) { + case OMAPDSS_VER_OMAP4430_ES1: + case OMAPDSS_VER_OMAP4430_ES2: + case OMAPDSS_VER_OMAP4: ip_data->ops = &omap4_hdmi_functions; + break; + default: + ip_data->ops = NULL; + } + + WARN_ON(ip_data->ops == NULL); } #endif @@ -929,29 +938,44 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type) return omap_current_dss_features->supported_rotation_types & rot_type; } -void dss_features_init(void) +void dss_features_init(enum omapdss_version version) { - if (cpu_is_omap24xx()) + switch (version) { + case OMAPDSS_VER_OMAP24xx: omap_current_dss_features = &omap2_dss_features; - else if (cpu_is_omap3630()) + break; + + case OMAPDSS_VER_OMAP34xx_ES1: + case OMAPDSS_VER_OMAP34xx_ES3: + omap_current_dss_features = &omap3430_dss_features; + break; + + case OMAPDSS_VER_OMAP3630: omap_current_dss_features = &omap3630_dss_features; - else if (cpu_is_omap34xx()) { - if (soc_is_am35xx()) { - omap_current_dss_features = &am35xx_dss_features; - } else { - omap_current_dss_features = &omap3430_dss_features; - } - } - else if (omap_rev() == OMAP4430_REV_ES1_0) + break; + + case OMAPDSS_VER_OMAP4430_ES1: omap_current_dss_features = &omap4430_es1_0_dss_features; - else if (omap_rev() == OMAP4430_REV_ES2_0 || - omap_rev() == OMAP4430_REV_ES2_1 || - omap_rev() == OMAP4430_REV_ES2_2) + break; + + case OMAPDSS_VER_OMAP4430_ES2: omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; - else if (cpu_is_omap44xx()) + break; + + case OMAPDSS_VER_OMAP4: omap_current_dss_features = &omap4_dss_features; - else if (soc_is_omap54xx()) + break; + + case OMAPDSS_VER_OMAP5: omap_current_dss_features = &omap5_dss_features; - else + break; + + case OMAPDSS_VER_AM35xx: + omap_current_dss_features = &am35xx_dss_features; + break; + + default: DSSWARN("Unsupported OMAP version"); + break; + } } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 9218113b5e8..fc492ef72a5 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -123,8 +123,9 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type); bool dss_has_feature(enum dss_feat_id id); void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); -void dss_features_init(void); +void dss_features_init(enum omapdss_version version); #if defined(CONFIG_OMAP4_DSS_HDMI) -void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data); +void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data, + enum omapdss_version version); #endif #endif diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a48a7dd75b3..adcc906d12f 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -323,6 +323,7 @@ static void hdmi_runtime_put(void) static int __init hdmi_init_display(struct omap_dss_device *dssdev) { + struct omap_dss_board_info *pdata = hdmi.pdev->dev.platform_data; int r; struct gpio gpios[] = { @@ -333,7 +334,7 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) DSSDBG("init_display\n"); - dss_init_hdmi_ip_ops(&hdmi.ip_data); + dss_init_hdmi_ip_ops(&hdmi.ip_data, pdata->version); if (hdmi.vdda_hdmi_dac_reg == NULL) { struct regulator *reg; diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 606b89f1235..55a39be694a 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -30,7 +30,7 @@ #include <linux/export.h> #include <video/omapdss.h> -#include <plat/vrfb.h> +#include <video/omapvrfb.h> #include <plat/vram.h> #include "omapfb.h" diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 16db1589bd9..bc225e46fdd 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -31,9 +31,8 @@ #include <linux/omapfb.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include <plat/vram.h> -#include <plat/vrfb.h> +#include <video/omapvrfb.h> #include "omapfb.h" @@ -2396,10 +2395,7 @@ static int __init omapfb_probe(struct platform_device *pdev) goto err0; } - /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE - * available for OMAP2 and OMAP3 - */ - if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) { + if (def_vrfb && !omap_vrfb_supported()) { def_vrfb = 0; dev_warn(&pdev->dev, "VRFB is not supported on this hardware, " "ignoring the module parameter vrfb=y\n"); diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index e8d8cc76a43..17aa174e187 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -30,7 +30,7 @@ #include <linux/omapfb.h> #include <video/omapdss.h> -#include <plat/vrfb.h> +#include <video/omapvrfb.h> #include "omapfb.h" diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c index 7e990220ad2..5d8fdac3b80 100644 --- a/drivers/video/omap2/vrfb.c +++ b/drivers/video/omap2/vrfb.c @@ -26,9 +26,9 @@ #include <linux/io.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <linux/platform_device.h> -#include <plat/vrfb.h> -#include <plat/sdrc.h> +#include <video/omapvrfb.h> #ifdef DEBUG #define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__) @@ -36,10 +36,10 @@ #define DBG(format, ...) #endif -#define SMS_ROT_VIRT_BASE(context, rot) \ - (((context >= 4) ? 0xD0000000 : 0x70000000) \ - + (0x4000000 * (context)) \ - + (0x1000000 * (rot))) +#define SMS_ROT_CONTROL(context) (0x0 + 0x10 * context) +#define SMS_ROT_SIZE(context) (0x4 + 0x10 * context) +#define SMS_ROT_PHYSICAL_BA(context) (0x8 + 0x10 * context) +#define SMS_ROT_VIRT_BASE(rot) (0x1000000 * (rot)) #define OMAP_VRFB_SIZE (2048 * 2048 * 4) @@ -53,10 +53,16 @@ #define SMS_PW_OFFSET 4 #define SMS_PS_OFFSET 0 -#define VRFB_NUM_CTXS 12 /* bitmap of reserved contexts */ static unsigned long ctx_map; +struct vrfb_ctx { + u32 base; + u32 physical_ba; + u32 control; + u32 size; +}; + static DEFINE_MUTEX(ctx_lock); /* @@ -65,17 +71,34 @@ static DEFINE_MUTEX(ctx_lock); * we don't need locking, since no drivers will run until after the wake-up * has finished. */ -static struct { - u32 physical_ba; - u32 control; - u32 size; -} vrfb_hw_context[VRFB_NUM_CTXS]; + +static void __iomem *vrfb_base; + +static int num_ctxs; +static struct vrfb_ctx *ctxs; + +static bool vrfb_loaded; + +static void omap2_sms_write_rot_control(u32 val, unsigned ctx) +{ + __raw_writel(val, vrfb_base + SMS_ROT_CONTROL(ctx)); +} + +static void omap2_sms_write_rot_size(u32 val, unsigned ctx) +{ + __raw_writel(val, vrfb_base + SMS_ROT_SIZE(ctx)); +} + +static void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx) +{ + __raw_writel(val, vrfb_base + SMS_ROT_PHYSICAL_BA(ctx)); +} static inline void restore_hw_context(int ctx) { - omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx); - omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx); - omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx); + omap2_sms_write_rot_control(ctxs[ctx].control, ctx); + omap2_sms_write_rot_size(ctxs[ctx].size, ctx); + omap2_sms_write_rot_physical_ba(ctxs[ctx].physical_ba, ctx); } static u32 get_image_width_roundup(u16 width, u8 bytespp) @@ -196,9 +219,9 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr, control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET; control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET; - vrfb_hw_context[ctx].physical_ba = paddr; - vrfb_hw_context[ctx].size = size; - vrfb_hw_context[ctx].control = control; + ctxs[ctx].physical_ba = paddr; + ctxs[ctx].size = size; + ctxs[ctx].control = control; omap2_sms_write_rot_physical_ba(paddr, ctx); omap2_sms_write_rot_size(size, ctx); @@ -274,11 +297,11 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) mutex_lock(&ctx_lock); - for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx) + for (ctx = 0; ctx < num_ctxs; ++ctx) if ((ctx_map & (1 << ctx)) == 0) break; - if (ctx == VRFB_NUM_CTXS) { + if (ctx == num_ctxs) { pr_err("vrfb: no free contexts\n"); r = -EBUSY; goto out; @@ -293,7 +316,7 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) vrfb->context = ctx; for (rot = 0; rot < 4; ++rot) { - paddr = SMS_ROT_VIRT_BASE(ctx, rot); + paddr = ctxs[ctx].base + SMS_ROT_VIRT_BASE(rot); if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) { pr_err("vrfb: failed to reserve VRFB " "area for ctx %d, rotation %d\n", @@ -314,3 +337,80 @@ out: return r; } EXPORT_SYMBOL(omap_vrfb_request_ctx); + +bool omap_vrfb_supported(void) +{ + return vrfb_loaded; +} +EXPORT_SYMBOL(omap_vrfb_supported); + +static int __init vrfb_probe(struct platform_device *pdev) +{ + struct resource *mem; + int i; + + /* first resource is the register res, the rest are vrfb contexts */ + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "can't get vrfb base address\n"); + return -EINVAL; + } + + vrfb_base = devm_request_and_ioremap(&pdev->dev, mem); + if (!vrfb_base) { + dev_err(&pdev->dev, "can't ioremap vrfb memory\n"); + return -ENOMEM; + } + + num_ctxs = pdev->num_resources - 1; + + ctxs = devm_kzalloc(&pdev->dev, + sizeof(struct vrfb_ctx) * num_ctxs, + GFP_KERNEL); + + if (!ctxs) + return -ENOMEM; + + for (i = 0; i < num_ctxs; ++i) { + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); + if (!mem) { + dev_err(&pdev->dev, "can't get vrfb ctx %d address\n", + i); + return -EINVAL; + } + + ctxs[i].base = mem->start; + } + + vrfb_loaded = true; + + return 0; +} + +static void __exit vrfb_remove(struct platform_device *pdev) +{ + vrfb_loaded = false; +} + +static struct platform_driver vrfb_driver = { + .driver.name = "omapvrfb", + .remove = __exit_p(vrfb_remove), +}; + +static int __init vrfb_init(void) +{ + return platform_driver_probe(&vrfb_driver, &vrfb_probe); +} + +static void __exit vrfb_exit(void) +{ + platform_driver_unregister(&vrfb_driver); +} + +module_init(vrfb_init); +module_exit(vrfb_exit); + +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); +MODULE_DESCRIPTION("OMAP VRFB"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index b7f5173ff9e..917bb568168 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -641,7 +641,6 @@ static void xenfb_backend_changed(struct xenbus_device *dev, case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateInitWait: @@ -670,6 +669,10 @@ InitWait: info->feature_resize = val; break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 1e8659ca27e..809b0de59c0 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -225,8 +225,10 @@ EXPORT_SYMBOL_GPL(register_virtio_device); void unregister_virtio_device(struct virtio_device *dev) { + int index = dev->index; /* save for after device release */ + device_unregister(&dev->dev); - ida_simple_remove(&virtio_index_ida, dev->index); + ida_simple_remove(&virtio_index_ida, index); } EXPORT_SYMBOL_GPL(unregister_virtio_device); diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index 05e1be85fde..dc42e44b6bc 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -32,6 +32,7 @@ #include <linux/timer.h> #include <linux/bitops.h> #include <linux/uaccess.h> +#include <linux/of.h> #include "at91sam9_wdt.h" @@ -302,11 +303,21 @@ static int __exit at91wdt_remove(struct platform_device *pdev) return res; } +#if defined(CONFIG_OF) +static const struct of_device_id at91_wdt_dt_ids[] __initconst = { + { .compatible = "atmel,at91sam9260-wdt" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids); +#endif + static struct platform_driver at91wdt_driver = { .remove = __exit_p(at91wdt_remove), .driver = { .name = "at91_wdt", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_wdt_dt_ids), }, }; diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index bcfab2b00ad..9a45d0294cf 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -33,7 +33,6 @@ #include <linux/uaccess.h> #include <linux/timer.h> #include <linux/jiffies.h> -#include <mach/hardware.h> #define DRIVER_NAME "imx2-wdt" diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index f5db18dbc0f..477a1d47a64 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -46,8 +46,8 @@ #include <linux/slab.h> #include <linux/pm_runtime.h> #include <mach/hardware.h> -#include <plat/cpu.h> -#include <plat/prcm.h> + +#include <linux/platform_data/omap-wd-timer.h> #include "omap_wdt.h" @@ -202,8 +202,10 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data, static long omap_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + struct omap_wd_timer_platform_data *pdata; struct omap_wdt_dev *wdev; - int new_margin; + u32 rs; + int new_margin, bs; static const struct watchdog_info ident = { .identity = "OMAP Watchdog", .options = WDIOF_SETTIMEOUT, @@ -211,6 +213,7 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd, }; wdev = file->private_data; + pdata = wdev->dev->platform_data; switch (cmd) { case WDIOC_GETSUPPORT: @@ -219,17 +222,12 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd, case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: -#ifdef CONFIG_ARCH_OMAP1 - if (cpu_is_omap16xx()) - return put_user(__raw_readw(ARM_SYSST), - (int __user *)arg); -#endif -#ifdef CONFIG_ARCH_OMAP2PLUS - if (cpu_is_omap24xx()) - return put_user(omap_prcm_get_reset_sources(), - (int __user *)arg); -#endif - return put_user(0, (int __user *)arg); + if (!pdata || !pdata->read_reset_sources) + return put_user(0, (int __user *)arg); + rs = pdata->read_reset_sources(); + bs = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ? + WDIOF_CARDRESET : 0; + return put_user(bs, (int __user *)arg); case WDIOC_KEEPALIVE: spin_lock(&wdt_lock); omap_wdt_ping(wdev); diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 0e863703545..74354708c6c 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -2,6 +2,7 @@ ifneq ($(CONFIG_ARM),y) obj-y += manage.o balloon.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o endif +obj-$(CONFIG_X86) += fallback.o obj-y += grant-table.o features.o events.o obj-y += xenbus/ diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 912ac81b6db..0be4df39e95 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1395,10 +1395,10 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); + irq_enter(); #ifdef CONFIG_X86 exit_idle(); #endif - irq_enter(); __xen_evtchn_do_upcall(); diff --git a/drivers/xen/fallback.c b/drivers/xen/fallback.c new file mode 100644 index 00000000000..0ef7c4d40f8 --- /dev/null +++ b/drivers/xen/fallback.c @@ -0,0 +1,80 @@ +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/bug.h> +#include <linux/export.h> +#include <asm/hypervisor.h> +#include <asm/xen/hypercall.h> + +int xen_event_channel_op_compat(int cmd, void *arg) +{ + struct evtchn_op op; + int rc; + + op.cmd = cmd; + memcpy(&op.u, arg, sizeof(op.u)); + rc = _hypercall1(int, event_channel_op_compat, &op); + + switch (cmd) { + case EVTCHNOP_close: + case EVTCHNOP_send: + case EVTCHNOP_bind_vcpu: + case EVTCHNOP_unmask: + /* no output */ + break; + +#define COPY_BACK(eop) \ + case EVTCHNOP_##eop: \ + memcpy(arg, &op.u.eop, sizeof(op.u.eop)); \ + break + + COPY_BACK(bind_interdomain); + COPY_BACK(bind_virq); + COPY_BACK(bind_pirq); + COPY_BACK(status); + COPY_BACK(alloc_unbound); + COPY_BACK(bind_ipi); +#undef COPY_BACK + + default: + WARN_ON(rc != -ENOSYS); + break; + } + + return rc; +} +EXPORT_SYMBOL_GPL(xen_event_channel_op_compat); + +int HYPERVISOR_physdev_op_compat(int cmd, void *arg) +{ + struct physdev_op op; + int rc; + + op.cmd = cmd; + memcpy(&op.u, arg, sizeof(op.u)); + rc = _hypercall1(int, physdev_op_compat, &op); + + switch (cmd) { + case PHYSDEVOP_IRQ_UNMASK_NOTIFY: + case PHYSDEVOP_set_iopl: + case PHYSDEVOP_set_iobitmap: + case PHYSDEVOP_apic_write: + /* no output */ + break; + +#define COPY_BACK(pop, fld) \ + case PHYSDEVOP_##pop: \ + memcpy(arg, &op.u.fld, sizeof(op.u.fld)); \ + break + + COPY_BACK(irq_status_query, irq_status_query); + COPY_BACK(apic_read, apic_op); + COPY_BACK(ASSIGN_VECTOR, irq_op); +#undef COPY_BACK + + default: + WARN_ON(rc != -ENOSYS); + break; + } + + return rc; +} diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 610bfc6be17..2e22df2f7a3 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -105,6 +105,21 @@ static void gntdev_print_maps(struct gntdev_priv *priv, #endif } +static void gntdev_free_map(struct grant_map *map) +{ + if (map == NULL) + return; + + if (map->pages) + free_xenballooned_pages(map->count, map->pages); + kfree(map->pages); + kfree(map->grants); + kfree(map->map_ops); + kfree(map->unmap_ops); + kfree(map->kmap_ops); + kfree(map); +} + static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) { struct grant_map *add; @@ -142,12 +157,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) return add; err: - kfree(add->pages); - kfree(add->grants); - kfree(add->map_ops); - kfree(add->unmap_ops); - kfree(add->kmap_ops); - kfree(add); + gntdev_free_map(add); return NULL; } @@ -198,17 +208,9 @@ static void gntdev_put_map(struct grant_map *map) evtchn_put(map->notify.event); } - if (map->pages) { - if (!use_ptemod) - unmap_grant_pages(map, 0, map->count); - - free_xenballooned_pages(map->count, map->pages); - } - kfree(map->pages); - kfree(map->grants); - kfree(map->map_ops); - kfree(map->unmap_ops); - kfree(map); + if (map->pages && !use_ptemod) + unmap_grant_pages(map, 0, map->count); + gntdev_free_map(map); } /* ------------------------------------------------------------------ */ diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index 89f76252a16..ac727028e65 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -458,7 +458,7 @@ static ssize_t xenbus_file_write(struct file *filp, goto out; /* Can't write a xenbus message larger we can buffer */ - if ((len + u->len) > sizeof(u->u.buffer)) { + if (len > sizeof(u->u.buffer) - u->len) { /* On error, dump existing buffer */ u->len = 0; rc = -EINVAL; |