diff options
author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-05-27 15:01:35 +0000 |
---|---|---|
committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-05-27 15:01:35 +0000 |
commit | 1ee6958324f44923ed309d2fa911fc432f514694 (patch) | |
tree | ec5ccc0121d0adc7430a0f6bd4a111dd5ab6e331 /target/linux/xburst/patches-3.2 | |
parent | 287550be2067ed412d4ce7148585c113fab125b8 (diff) |
xburst: remove support for old kernels
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@31904 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/xburst/patches-3.2')
21 files changed, 0 insertions, 5011 deletions
diff --git a/target/linux/xburst/patches-3.2/0001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch b/target/linux/xburst/patches-3.2/0001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch deleted file mode 100644 index c340c6c7e3..0000000000 --- a/target/linux/xburst/patches-3.2/0001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 73aab29ddc44a3e1a7156473ad5bc9cd80704274 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Tue, 15 Mar 2011 12:49:15 +0100 -Subject: [PATCH 01/21] ubi: Read only the vid header instead of the whole - page - ---- - drivers/mtd/ubi/io.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - ---- a/drivers/mtd/ubi/io.c -+++ b/drivers/mtd/ubi/io.c -@@ -1031,7 +1031,7 @@ int ubi_io_read_vid_hdr(struct ubi_devic - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, -- ubi->vid_hdr_alsize); -+ UBI_VID_HDR_SIZE + ubi->vid_hdr_shift); - if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) - return read_err; - diff --git a/target/linux/xburst/patches-3.2/0002-Add-jz4740-udc-driver.patch b/target/linux/xburst/patches-3.2/0002-Add-jz4740-udc-driver.patch deleted file mode 100644 index 507e99117a..0000000000 --- a/target/linux/xburst/patches-3.2/0002-Add-jz4740-udc-driver.patch +++ /dev/null @@ -1,2371 +0,0 @@ -From 537082e01849ca85227c5b462b8ac9aceb11b77a Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sat, 24 Apr 2010 12:18:46 +0200 -Subject: [PATCH 02/21] Add jz4740 udc driver - -History: -- driver by Ingenic -- patch by Lars-Peter Clausen. -- updated to 3.1 by Maarten ter Huurne ---- - drivers/usb/gadget/Kconfig | 8 + - drivers/usb/gadget/Makefile | 1 + - drivers/usb/gadget/gadget_chips.h | 3 + - drivers/usb/gadget/jz4740_udc.c | 2199 +++++++++++++++++++++++++++++++++++++ - drivers/usb/gadget/jz4740_udc.h | 101 ++ - 5 files changed, 2312 insertions(+), 0 deletions(-) - create mode 100644 drivers/usb/gadget/jz4740_udc.c - create mode 100644 drivers/usb/gadget/jz4740_udc.h - ---- a/drivers/usb/gadget/Kconfig -+++ b/drivers/usb/gadget/Kconfig -@@ -178,6 +178,14 @@ config USB_FUSB300 - help - Faraday usb device controller FUSB300 driver - -+config USB_JZ4740 -+ tristate "JZ4740 UDC" -+ depends on MACH_JZ4740 -+ select USB_GADGET_DUALSPEED -+ help -+ Select this to support the Ingenic JZ4740 processor -+ high speed USB device controller. -+ - config USB_OMAP - tristate "OMAP USB Device Controller" - depends on ARCH_OMAP ---- a/drivers/usb/gadget/Makefile -+++ b/drivers/usb/gadget/Makefile -@@ -31,6 +31,7 @@ obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o - mv_udc-y := mv_udc_core.o - obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o - obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o -+obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o - - # - # USB gadget drivers ---- a/drivers/usb/gadget/gadget_chips.h -+++ b/drivers/usb/gadget/gadget_chips.h -@@ -36,6 +36,7 @@ - #define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) - #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) - #define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) -+#define gadget_is_jz4740(g) (!strcmp("ingenic_hsusb", (g)->name)) - #define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) - #define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) - #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -@@ -118,6 +119,8 @@ static inline int usb_gadget_controller_ - return 0x31; - else if (gadget_is_dwc3(gadget)) - return 0x32; -+ else if (gadget_is_jz4740(gadget)) -+ return 0x33; - - return -ENOENT; - } ---- /dev/null -+++ b/drivers/usb/gadget/jz4740_udc.c -@@ -0,0 +1,2199 @@ -+/* -+ * linux/drivers/usb/gadget/jz4740_udc.c -+ * -+ * Ingenic JZ4740 on-chip high speed USB device controller -+ * -+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. -+ * Author: <jlwei@ingenic.cn> -+ * -+ * 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. -+ */ -+ -+/* -+ * This device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint. -+ * -+ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk. -+ * - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/delay.h> -+#include <linux/ioport.h> -+#include <linux/slab.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/proc_fs.h> -+#include <linux/usb.h> -+#include <linux/usb/gadget.h> -+#include <linux/clk.h> -+ -+#include <asm/byteorder.h> -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <asm/system.h> -+#include <asm/mach-jz4740/clock.h> -+ -+#include "jz4740_udc.h" -+ -+#define JZ_REG_UDC_FADDR 0x00 /* Function Address 8-bit */ -+#define JZ_REG_UDC_POWER 0x01 /* Power Management 8-bit */ -+#define JZ_REG_UDC_INTRIN 0x02 /* Interrupt IN 16-bit */ -+#define JZ_REG_UDC_INTROUT 0x04 /* Interrupt OUT 16-bit */ -+#define JZ_REG_UDC_INTRINE 0x06 /* Intr IN enable 16-bit */ -+#define JZ_REG_UDC_INTROUTE 0x08 /* Intr OUT enable 16-bit */ -+#define JZ_REG_UDC_INTRUSB 0x0a /* Interrupt USB 8-bit */ -+#define JZ_REG_UDC_INTRUSBE 0x0b /* Interrupt USB Enable 8-bit */ -+#define JZ_REG_UDC_FRAME 0x0c /* Frame number 16-bit */ -+#define JZ_REG_UDC_INDEX 0x0e /* Index register 8-bit */ -+#define JZ_REG_UDC_TESTMODE 0x0f /* USB test mode 8-bit */ -+ -+#define JZ_REG_UDC_CSR0 0x12 /* EP0 CSR 8-bit */ -+#define JZ_REG_UDC_INMAXP 0x10 /* EP1-2 IN Max Pkt Size 16-bit */ -+#define JZ_REG_UDC_INCSR 0x12 /* EP1-2 IN CSR LSB 8/16bit */ -+#define JZ_REG_UDC_INCSRH 0x13 /* EP1-2 IN CSR MSB 8-bit */ -+ -+#define JZ_REG_UDC_OUTMAXP 0x14 /* EP1 OUT Max Pkt Size 16-bit */ -+#define JZ_REG_UDC_OUTCSR 0x16 /* EP1 OUT CSR LSB 8/16bit */ -+#define JZ_REG_UDC_OUTCSRH 0x17 /* EP1 OUT CSR MSB 8-bit */ -+#define JZ_REG_UDC_OUTCOUNT 0x18 /* bytes in EP0/1 OUT FIFO 16-bit */ -+ -+#define JZ_REG_UDC_EP_FIFO(x) (4 * (x) + 0x20) -+ -+#define JZ_REG_UDC_EPINFO 0x78 /* Endpoint information */ -+#define JZ_REG_UDC_RAMINFO 0x79 /* RAM information */ -+ -+#define JZ_REG_UDC_INTR 0x200 /* DMA pending interrupts */ -+#define JZ_REG_UDC_CNTL1 0x204 /* DMA channel 1 control */ -+#define JZ_REG_UDC_ADDR1 0x208 /* DMA channel 1 AHB memory addr */ -+#define JZ_REG_UDC_COUNT1 0x20c /* DMA channel 1 byte count */ -+#define JZ_REG_UDC_CNTL2 0x214 /* DMA channel 2 control */ -+#define JZ_REG_UDC_ADDR2 0x218 /* DMA channel 2 AHB memory addr */ -+#define JZ_REG_UDC_COUNT2 0x21c /* DMA channel 2 byte count */ -+ -+/* Power register bit masks */ -+#define USB_POWER_SUSPENDM 0x01 -+#define USB_POWER_RESUME 0x04 -+#define USB_POWER_HSMODE 0x10 -+#define USB_POWER_HSENAB 0x20 -+#define USB_POWER_SOFTCONN 0x40 -+ -+/* Interrupt register bit masks */ -+#define USB_INTR_SUSPEND 0x01 -+#define USB_INTR_RESUME 0x02 -+#define USB_INTR_RESET 0x04 -+ -+#define USB_INTR_EP0 0x0001 -+#define USB_INTR_INEP1 0x0002 -+#define USB_INTR_INEP2 0x0004 -+#define USB_INTR_OUTEP1 0x0002 -+ -+/* CSR0 bit masks */ -+#define USB_CSR0_OUTPKTRDY 0x01 -+#define USB_CSR0_INPKTRDY 0x02 -+#define USB_CSR0_SENTSTALL 0x04 -+#define USB_CSR0_DATAEND 0x08 -+#define USB_CSR0_SETUPEND 0x10 -+#define USB_CSR0_SENDSTALL 0x20 -+#define USB_CSR0_SVDOUTPKTRDY 0x40 -+#define USB_CSR0_SVDSETUPEND 0x80 -+ -+/* Endpoint CSR register bits */ -+#define USB_INCSRH_AUTOSET 0x80 -+#define USB_INCSRH_ISO 0x40 -+#define USB_INCSRH_MODE 0x20 -+#define USB_INCSRH_DMAREQENAB 0x10 -+#define USB_INCSRH_DMAREQMODE 0x04 -+#define USB_INCSR_CDT 0x40 -+#define USB_INCSR_SENTSTALL 0x20 -+#define USB_INCSR_SENDSTALL 0x10 -+#define USB_INCSR_FF 0x08 -+#define USB_INCSR_UNDERRUN 0x04 -+#define USB_INCSR_FFNOTEMPT 0x02 -+#define USB_INCSR_INPKTRDY 0x01 -+ -+#define USB_OUTCSRH_AUTOCLR 0x80 -+#define USB_OUTCSRH_ISO 0x40 -+#define USB_OUTCSRH_DMAREQENAB 0x20 -+#define USB_OUTCSRH_DNYT 0x10 -+#define USB_OUTCSRH_DMAREQMODE 0x08 -+#define USB_OUTCSR_CDT 0x80 -+#define USB_OUTCSR_SENTSTALL 0x40 -+#define USB_OUTCSR_SENDSTALL 0x20 -+#define USB_OUTCSR_FF 0x10 -+#define USB_OUTCSR_DATAERR 0x08 -+#define USB_OUTCSR_OVERRUN 0x04 -+#define USB_OUTCSR_FFFULL 0x02 -+#define USB_OUTCSR_OUTPKTRDY 0x01 -+ -+/* DMA control bits */ -+#define USB_CNTL_ENA 0x01 -+#define USB_CNTL_DIR_IN 0x02 -+#define USB_CNTL_MODE_1 0x04 -+#define USB_CNTL_INTR_EN 0x08 -+#define USB_CNTL_EP(n) ((n) << 4) -+#define USB_CNTL_BURST_0 (0 << 9) -+#define USB_CNTL_BURST_4 (1 << 9) -+#define USB_CNTL_BURST_8 (2 << 9) -+#define USB_CNTL_BURST_16 (3 << 9) -+ -+ -+#ifndef DEBUG -+# define DEBUG(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_EP0 -+# define NO_STATES -+# define DEBUG_EP0(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_SETUP -+# define DEBUG_SETUP(fmt,args...) do {} while(0) -+#endif -+ -+static struct jz4740_udc jz4740_udc_controller; -+ -+/* -+ * Local declarations. -+ */ -+static int jz4740_udc_start(struct usb_gadget_driver *driver, -+ int (*bind)(struct usb_gadget *)); -+static int jz4740_udc_stop(struct usb_gadget_driver *driver); -+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep); -+static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr); -+ -+static void done(struct jz4740_ep *ep, struct jz4740_request *req, -+ int status); -+static void pio_irq_enable(struct jz4740_ep *ep); -+static void pio_irq_disable(struct jz4740_ep *ep); -+static void stop_activity(struct jz4740_udc *dev, -+ struct usb_gadget_driver *driver); -+static void nuke(struct jz4740_ep *ep, int status); -+static void flush(struct jz4740_ep *ep); -+static void udc_set_address(struct jz4740_udc *dev, unsigned char address); -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* inline functions of register read/write/set/clear */ -+ -+static inline uint8_t usb_readb(struct jz4740_udc *udc, size_t reg) -+{ -+ return readb(udc->base + reg); -+} -+ -+static inline uint16_t usb_readw(struct jz4740_udc *udc, size_t reg) -+{ -+ return readw(udc->base + reg); -+} -+ -+static inline uint32_t usb_readl(struct jz4740_udc *udc, size_t reg) -+{ -+ return readl(udc->base + reg); -+} -+ -+static inline void usb_writeb(struct jz4740_udc *udc, size_t reg, uint8_t val) -+{ -+ writeb(val, udc->base + reg); -+} -+ -+static inline void usb_writew(struct jz4740_udc *udc, size_t reg, uint16_t val) -+{ -+ writew(val, udc->base + reg); -+} -+ -+static inline void usb_writel(struct jz4740_udc *udc, size_t reg, uint32_t val) -+{ -+ writel(val, udc->base + reg); -+} -+ -+static inline void usb_setb(struct jz4740_udc *udc, size_t reg, uint8_t mask) -+{ -+ usb_writeb(udc, reg, usb_readb(udc, reg) | mask); -+} -+ -+static inline void usb_setw(struct jz4740_udc *udc, size_t reg, uint16_t mask) -+{ -+ usb_writew(udc, reg, usb_readw(udc, reg) | mask); -+} -+ -+static inline void usb_clearb(struct jz4740_udc *udc, size_t reg, uint8_t mask) -+{ -+ usb_writeb(udc, reg, usb_readb(udc, reg) & ~mask); -+} -+ -+static inline void usb_clearw(struct jz4740_udc *udc, size_t reg, uint16_t mask) -+{ -+ usb_writew(udc, reg, usb_readw(udc, reg) & ~mask); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static inline void jz_udc_set_index(struct jz4740_udc *udc, uint8_t index) -+{ -+ usb_writeb(udc, JZ_REG_UDC_INDEX, index); -+} -+ -+static inline void jz_udc_select_ep(struct jz4740_ep *ep) -+{ -+ jz_udc_set_index(ep->dev, ep_index(ep)); -+} -+ -+static inline int write_packet(struct jz4740_ep *ep, -+ struct jz4740_request *req, unsigned int count) -+{ -+ uint8_t *buf; -+ unsigned int length; -+ void __iomem *fifo = ep->dev->base + ep->fifo; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ buf = req->req.buf + req->req.actual; -+ -+ length = req->req.length - req->req.actual; -+ if (length > count) -+ length = count; -+ req->req.actual += length; -+ -+ DEBUG("Write %d (count %d), fifo %x\n", length, count, ep->fifo); -+ -+ writesl(fifo, buf, length >> 2); -+ writesb(fifo, &buf[length - (length & 3)], length & 3); -+ -+ return length; -+} -+ -+static int read_packet(struct jz4740_ep *ep, -+ struct jz4740_request *req, unsigned int count) -+{ -+ uint8_t *buf; -+ unsigned int length; -+ void __iomem *fifo = ep->dev->base + ep->fifo; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ buf = req->req.buf + req->req.actual; -+ -+ length = req->req.length - req->req.actual; -+ if (length > count) -+ length = count; -+ req->req.actual += length; -+ -+ DEBUG("Read %d, fifo %x\n", length, ep->fifo); -+ -+ readsl(fifo, buf, length >> 2); -+ readsb(fifo, &buf[length - (length & 3)], length & 3); -+ -+ return length; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * udc_disable - disable USB device controller -+ */ -+static void udc_disable(struct jz4740_udc *dev) -+{ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ udc_set_address(dev, 0); -+ -+ /* Disable interrupts */ -+ usb_writew(dev, JZ_REG_UDC_INTRINE, 0); -+ usb_writew(dev, JZ_REG_UDC_INTROUTE, 0); -+ usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0); -+ -+ /* Disable DMA */ -+ usb_writel(dev, JZ_REG_UDC_CNTL1, 0); -+ usb_writel(dev, JZ_REG_UDC_CNTL2, 0); -+ -+ /* Disconnect from usb */ -+ usb_clearb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN); -+ -+ /* Disable the USB PHY */ -+ clk_disable(dev->clk); -+ -+ dev->ep0state = WAIT_FOR_SETUP; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ return; -+} -+ -+/* -+ * udc_reinit - initialize software state -+ */ -+static void udc_reinit(struct jz4740_udc *dev) -+{ -+ int i; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ /* device/ep0 records init */ -+ INIT_LIST_HEAD(&dev->gadget.ep_list); -+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -+ dev->ep0state = WAIT_FOR_SETUP; -+ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ if (i != 0) -+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); -+ -+ INIT_LIST_HEAD(&ep->queue); -+ ep->desc = 0; -+ ep->stopped = 0; -+ } -+} -+ -+/* until it's enabled, this UDC should be completely invisible -+ * to any USB host. -+ */ -+static void udc_enable(struct jz4740_udc *dev) -+{ -+ int i; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ /* UDC state is incorrect - Added by River */ -+ if (dev->state != UDC_STATE_ENABLE) { -+ return; -+ } -+ -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* Flush FIFO for each */ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ jz_udc_select_ep(ep); -+ flush(ep); -+ } -+ -+ /* Set this bit to allow the UDC entering low-power mode when -+ * there are no actions on the USB bus. -+ * UDC still works during this bit was set. -+ */ -+ jz4740_clock_udc_enable_auto_suspend(); -+ -+ /* Enable the USB PHY */ -+ clk_enable(dev->clk); -+ -+ /* Disable interrupts */ -+/* usb_writew(dev, JZ_REG_UDC_INTRINE, 0); -+ usb_writew(dev, JZ_REG_UDC_INTROUTE, 0); -+ usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0);*/ -+ -+ /* Enable interrupts */ -+ usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_EP0); -+ usb_setb(dev, JZ_REG_UDC_INTRUSBE, USB_INTR_RESET); -+ /* Don't enable rest of the interrupts */ -+ /* usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2); -+ usb_setw(dev, JZ_REG_UDC_INTROUTE, USB_INTR_OUTEP1); */ -+ -+ /* Enable SUSPEND */ -+ /* usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SUSPENDM); */ -+ -+ /* Enable HS Mode */ -+ usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_HSENAB); -+ -+ /* Let host detect UDC: -+ * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this -+ * transistor on and pull the USBDP pin HIGH. -+ */ -+ usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN); -+ -+ return; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* keeping it simple: -+ * - one bus driver, initted first; -+ * - one function driver, initted second -+ */ -+ -+/* -+ * Register entry point for the peripheral controller driver. -+ */ -+ -+static int jz4740_udc_start(struct usb_gadget_driver *driver, -+ int (*bind)(struct usb_gadget *)) -+{ -+ struct jz4740_udc *dev = &jz4740_udc_controller; -+ int retval; -+ -+ if (!driver || !bind) -+ return -EINVAL; -+ -+ if (!dev) -+ return -ENODEV; -+ -+ if (dev->driver) -+ return -EBUSY; -+ -+ /* hook up the driver */ -+ dev->driver = driver; -+ dev->gadget.dev.driver = &driver->driver; -+ -+ retval = bind(&dev->gadget); -+ if (retval) { -+ DEBUG("%s: bind to driver %s --> error %d\n", dev->gadget.name, -+ driver->driver.name, retval); -+ dev->driver = 0; -+ return retval; -+ } -+ -+ /* then enable host detection and ep0; and we're ready -+ * for set_configuration as well as eventual disconnect. -+ */ -+ udc_enable(dev); -+ -+ DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name, -+ driver->driver.name); -+ -+ return 0; -+} -+ -+static void stop_activity(struct jz4740_udc *dev, -+ struct usb_gadget_driver *driver) -+{ -+ int i; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ /* don't disconnect drivers more than once */ -+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) -+ driver = 0; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* prevent new request submissions, kill any outstanding requests */ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ ep->stopped = 1; -+ -+ jz_udc_select_ep(ep); -+ nuke(ep, -ESHUTDOWN); -+ } -+ -+ /* report disconnect; the driver is already quiesced */ -+ if (driver) { -+ spin_unlock(&dev->lock); -+ driver->disconnect(&dev->gadget); -+ spin_lock(&dev->lock); -+ } -+ -+ /* re-init driver-visible data structures */ -+ udc_reinit(dev); -+} -+ -+ -+/* -+ * Unregister entry point for the peripheral controller driver. -+ */ -+static int jz4740_udc_stop(struct usb_gadget_driver *driver) -+{ -+ struct jz4740_udc *dev = &jz4740_udc_controller; -+ unsigned long flags; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ if (!dev) -+ return -ENODEV; -+ if (!driver || driver != dev->driver) -+ return -EINVAL; -+ if (!driver->unbind) -+ return -EBUSY; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ dev->driver = 0; -+ stop_activity(dev, driver); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ driver->unbind(&dev->gadget); -+ -+ udc_disable(dev); -+ -+ DEBUG("unregistered driver '%s'\n", driver->driver.name); -+ -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/** Write request to FIFO (max write == maxp size) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ * NOTE: INDEX register must be set for EP -+ */ -+static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ struct jz4740_udc *dev = ep->dev; -+ uint32_t max, csr; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ max = le16_to_cpu(ep->desc->wMaxPacketSize); -+ -+ csr = usb_readb(dev, ep->csr); -+ -+ if (!(csr & USB_INCSR_FFNOTEMPT)) { -+ unsigned count; -+ int is_last, is_short; -+ -+ count = write_packet(ep, req, max); -+ usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = is_short = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) -+ || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ /* interrupt/iso maxpacket may not fill the fifo */ -+ is_short = unlikely(max < ep_maxpacket(ep)); -+ } -+ -+ DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", is_short ? "/S" : "", -+ req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ if (list_empty(&ep->queue)) { -+ pio_irq_disable(ep); -+ } -+ return 1; -+ } -+ } else { -+ DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); -+ } -+ -+ return 0; -+} -+ -+/** Read to request from FIFO (max read == bytes in fifo) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ * NOTE: INDEX register must be set for EP -+ */ -+static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ struct jz4740_udc *dev = ep->dev; -+ uint32_t csr; -+ unsigned count, is_short; -+ -+ /* make sure there's a packet in the FIFO. */ -+ csr = usb_readb(dev, ep->csr); -+ if (!(csr & USB_OUTCSR_OUTPKTRDY)) { -+ DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ /* read all bytes from this packet */ -+ count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); -+ -+ is_short = (count < ep->ep.maxpacket); -+ -+ count = read_packet(ep, req, count); -+ -+ DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", -+ ep->ep.name, csr, count, -+ is_short ? "/S" : "", req, req->req.actual, req->req.length); -+ -+ /* Clear OutPktRdy */ -+ usb_clearb(dev, ep->csr, USB_OUTCSR_OUTPKTRDY); -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ -+ if (list_empty(&ep->queue)) -+ pio_irq_disable(ep); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+/* -+ * done - retire a request; caller blocked irqs -+ * INDEX register is preserved to keep same -+ */ -+static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status) -+{ -+ unsigned int stopped = ep->stopped; -+ uint32_t index; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ list_del_init(&req->queue); -+ -+ if (likely(req->req.status == -EINPROGRESS)) -+ req->req.status = status; -+ else -+ status = req->req.status; -+ -+ if (status && status != -ESHUTDOWN) -+ DEBUG("complete %s req %p stat %d len %u/%u\n", -+ ep->ep.name, &req->req, status, -+ req->req.actual, req->req.length); -+ -+ /* don't modify queue heads during completion callback */ -+ ep->stopped = 1; -+ /* Read current index (completion may modify it) */ -+ index = usb_readb(ep->dev, JZ_REG_UDC_INDEX); -+ spin_unlock_irqrestore(&ep->dev->lock, ep->dev->lock_flags); -+ -+ req->req.complete(&ep->ep, &req->req); -+ -+ spin_lock_irqsave(&ep->dev->lock, ep->dev->lock_flags); -+ /* Restore index */ -+ jz_udc_set_index(ep->dev, index); -+ ep->stopped = stopped; -+} -+ -+static inline unsigned int jz4740_udc_ep_irq_enable_reg(struct jz4740_ep *ep) -+{ -+ if (ep_is_in(ep)) -+ return JZ_REG_UDC_INTRINE; -+ else -+ return JZ_REG_UDC_INTROUTE; -+} -+ -+/** Enable EP interrupt */ -+static void pio_irq_enable(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); -+ -+ usb_setw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep))); -+} -+ -+/** Disable EP interrupt */ -+static void pio_irq_disable(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); -+ -+ usb_clearw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep))); -+} -+ -+/* -+ * nuke - dequeue ALL requests -+ */ -+static void nuke(struct jz4740_ep *ep, int status) -+{ -+ struct jz4740_request *req; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ -+ /* Flush FIFO */ -+ flush(ep); -+ -+ /* called with irqs blocked */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ done(ep, req, status); -+ } -+ -+ /* Disable IRQ if EP is enabled (has descriptor) */ -+ if (ep->desc) -+ pio_irq_disable(ep); -+} -+ -+/** Flush EP FIFO -+ * NOTE: INDEX register must be set before this call -+ */ -+static void flush(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: %s\n", __FUNCTION__, ep->ep.name); -+ -+ switch (ep->type) { -+ case ep_bulk_in: -+ case ep_interrupt: -+ usb_setb(ep->dev, ep->csr, USB_INCSR_FF); -+ break; -+ case ep_bulk_out: -+ usb_setb(ep->dev, ep->csr, USB_OUTCSR_FF); -+ break; -+ case ep_control: -+ break; -+ } -+} -+ -+/** -+ * jz4740_in_epn - handle IN interrupt -+ */ -+static void jz4740_in_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr) -+{ -+ uint32_t csr; -+ struct jz4740_ep *ep = &dev->ep[ep_idx + 1]; -+ struct jz4740_request *req; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ jz_udc_select_ep(ep); -+ -+ csr = usb_readb(dev, ep->csr); -+ DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); -+ -+ if (csr & USB_INCSR_SENTSTALL) { -+ DEBUG("USB_INCSR_SENTSTALL\n"); -+ usb_clearb(dev, ep->csr, USB_INCSR_SENTSTALL); -+ return; -+ } -+ -+ if (!ep->desc) { -+ DEBUG("%s: NO EP DESC\n", __FUNCTION__); -+ return; -+ } -+ -+ if (!list_empty(&ep->queue)) { -+ req = list_first_entry(&ep->queue, struct jz4740_request, queue); -+ write_fifo(ep, req); -+ } -+} -+ -+/* -+ * Bulk OUT (recv) -+ */ -+static void jz4740_out_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr) -+{ -+ struct jz4740_ep *ep = &dev->ep[ep_idx]; -+ struct jz4740_request *req; -+ -+ DEBUG("%s: %d\n", __FUNCTION__, ep_idx); -+ -+ jz_udc_select_ep(ep); -+ if (ep->desc) { -+ uint32_t csr; -+ -+ while ((csr = usb_readb(dev, ep->csr)) & -+ (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { -+ DEBUG("%s: %x\n", __FUNCTION__, csr); -+ -+ if (csr & USB_OUTCSR_SENTSTALL) { -+ DEBUG("%s: stall sent, flush fifo\n", -+ __FUNCTION__); -+ /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ -+ flush(ep); -+ } else if (csr & USB_OUTCSR_OUTPKTRDY) { -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = -+ list_entry(ep->queue.next, -+ struct jz4740_request, -+ queue); -+ -+ if (!req) { -+ DEBUG("%s: NULL REQ %d\n", -+ __FUNCTION__, ep_idx); -+ break; -+ } else { -+ read_fifo(ep, req); -+ } -+ } -+ } -+ } else { -+ /* Throw packet away.. */ -+ DEBUG("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx); -+ flush(ep); -+ } -+} -+ -+/** Halt specific EP -+ * Return 0 if success -+ * NOTE: Sets INDEX register to EP ! -+ */ -+static int jz4740_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct jz4740_udc *dev; -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ -+ jz_udc_select_ep(ep); -+ -+ DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); -+ -+ if (ep_index(ep) == 0) { -+ /* EP0 */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL); -+ } else if (ep_is_in(ep)) { -+ uint32_t csr = usb_readb(dev, ep->csr); -+ if (value && ((csr & USB_INCSR_FFNOTEMPT) -+ || !list_empty(&ep->queue))) { -+ /* -+ * Attempts to halt IN endpoints will fail (returning -EAGAIN) -+ * if any transfer requests are still queued, or if the controller -+ * FIFO still holds bytes that the host hasnÂ’t collected. -+ */ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ DEBUG -+ ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", -+ (csr & USB_INCSR_FFNOTEMPT), -+ !list_empty(&ep->queue)); -+ return -EAGAIN; -+ } -+ flush(ep); -+ if (value) { -+ usb_setb(dev, ep->csr, USB_INCSR_SENDSTALL); -+ } else { -+ usb_clearb(dev, ep->csr, USB_INCSR_SENDSTALL); -+ usb_setb(dev, ep->csr, USB_INCSR_CDT); -+ } -+ } else { -+ -+ flush(ep); -+ if (value) { -+ usb_setb(dev, ep->csr, USB_OUTCSR_SENDSTALL); -+ } else { -+ usb_clearb(dev, ep->csr, USB_OUTCSR_SENDSTALL); -+ usb_setb(dev, ep->csr, USB_OUTCSR_CDT); -+ } -+ } -+ -+ ep->stopped = value; -+ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); -+ -+ return 0; -+} -+ -+ -+static int jz4740_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct jz4740_ep *ep; -+ struct jz4740_udc *dev; -+ unsigned long flags; -+ uint32_t max, csrh = 0; -+ -+ DEBUG("%s: trying to enable %s\n", __FUNCTION__, _ep->name); -+ -+ if (!_ep || !desc) -+ return -EINVAL; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (ep->desc || ep->type == ep_control -+ || desc->bDescriptorType != USB_DT_ENDPOINT -+ || ep->bEndpointAddress != desc->bEndpointAddress) { -+ DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ /* xfer types must match, except that interrupt ~= bulk */ -+ if (ep->bmAttributes != desc->bmAttributes -+ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK -+ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { -+ DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { -+ DEBUG("%s, bogus device state\n", __FUNCTION__); -+ return -ESHUTDOWN; -+ } -+ -+ max = le16_to_cpu(desc->wMaxPacketSize); -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ /* Configure the endpoint */ -+ jz_udc_select_ep(ep); -+ if (ep_is_in(ep)) { -+ usb_writew(dev, JZ_REG_UDC_INMAXP, max); -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ case USB_ENDPOINT_XFER_INT: -+ csrh &= ~USB_INCSRH_ISO; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ csrh |= USB_INCSRH_ISO; -+ break; -+ } -+ usb_writeb(dev, JZ_REG_UDC_INCSRH, csrh); -+ } -+ else { -+ usb_writew(dev, JZ_REG_UDC_OUTMAXP, max); -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ csrh &= ~USB_OUTCSRH_ISO; -+ break; -+ case USB_ENDPOINT_XFER_INT: -+ csrh &= ~USB_OUTCSRH_ISO; -+ csrh |= USB_OUTCSRH_DNYT; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ csrh |= USB_OUTCSRH_ISO; -+ break; -+ } -+ usb_writeb(dev, JZ_REG_UDC_OUTCSRH, csrh); -+ } -+ -+ -+ ep->stopped = 0; -+ ep->desc = desc; -+ ep->ep.maxpacket = max; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ /* Reset halt state (does flush) */ -+ jz4740_set_halt(_ep, 0); -+ -+ DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); -+ -+ return 0; -+} -+ -+/** Disable EP -+ * NOTE: Sets INDEX register -+ */ -+static int jz4740_ep_disable(struct usb_ep *_ep) -+{ -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || !ep->desc) { -+ DEBUG("%s, %s not enabled\n", __FUNCTION__, -+ _ep ? ep->ep.name : NULL); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ jz_udc_select_ep(ep); -+ -+ /* Nuke all pending requests (does flush) */ -+ nuke(ep, -ESHUTDOWN); -+ -+ /* Disable ep IRQ */ -+ pio_irq_disable(ep); -+ -+ ep->desc = 0; -+ ep->stopped = 1; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); -+ return 0; -+} -+ -+static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -+{ -+ struct jz4740_request *req; -+ -+ req = kzalloc(sizeof(*req), gfp_flags); -+ if (!req) -+ return NULL; -+ -+ INIT_LIST_HEAD(&req->queue); -+ -+ return &req->req; -+} -+ -+static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req) -+{ -+ struct jz4740_request *req; -+ -+ req = container_of(_req, struct jz4740_request, req); -+ WARN_ON(!list_empty(&req->queue)); -+ -+ kfree(req); -+} -+ -+/*--------------------------------------------------------------------*/ -+ -+/** Queue one request -+ * Kickstart transfer if needed -+ * NOTE: Sets INDEX register -+ */ -+static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, -+ gfp_t gfp_flags) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep; -+ struct jz4740_udc *dev; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ req = container_of(_req, struct jz4740_request, req); -+ if (unlikely -+ (!_req || !_req->complete || !_req->buf -+ || !list_empty(&req->queue))) { -+ DEBUG("%s, bad params\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { -+ DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); -+ return -ESHUTDOWN; -+ } -+ -+ DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, -+ _req->buf); -+ -+ spin_lock_irqsave(&dev->lock, dev->lock_flags); -+ -+ _req->status = -EINPROGRESS; -+ _req->actual = 0; -+ -+ /* kickstart this i/o queue? */ -+ DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), -+ ep->stopped); -+ if (list_empty(&ep->queue) && likely(!ep->stopped)) { -+ uint32_t csr; -+ -+ if (unlikely(ep_index(ep) == 0)) { -+ /* EP0 */ -+ list_add_tail(&req->queue, &ep->queue); -+ jz4740_ep0_kick(dev, ep); -+ req = 0; -+ } -+ else if (ep_is_in(ep)) { -+ /* EP1 & EP2 */ -+ jz_udc_select_ep(ep); -+ csr = usb_readb(dev, ep->csr); -+ pio_irq_enable(ep); -+ if (!(csr & USB_INCSR_FFNOTEMPT)) { -+ if (write_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } else { -+ /* EP1 */ -+ jz_udc_select_ep(ep); -+ csr = usb_readb(dev, ep->csr); -+ pio_irq_enable(ep); -+ if (csr & USB_OUTCSR_OUTPKTRDY) { -+ if (read_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } -+ } -+ -+ /* pio or dma irq handler advances the queue. */ -+ if (likely(req != 0)) -+ list_add_tail(&req->queue, &ep->queue); -+ -+ spin_unlock_irqrestore(&dev->lock, dev->lock_flags); -+ -+ return 0; -+} -+ -+/* dequeue JUST ONE request */ -+static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct jz4740_ep *ep; -+ struct jz4740_request *req; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || ep->type == ep_control) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ /* make sure it's actually queued on this endpoint */ -+ list_for_each_entry(req, &ep->queue, queue) { -+ if (&req->req == _req) -+ break; -+ } -+ if (&req->req != _req) { -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return -EINVAL; -+ } -+ done(ep, req, -ECONNRESET); -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return 0; -+} -+ -+/** Return bytes in EP FIFO -+ * NOTE: Sets INDEX register to EP -+ */ -+static int jz4740_fifo_status(struct usb_ep *_ep) -+{ -+ uint32_t csr; -+ int count = 0; -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -ENODEV; -+ } -+ -+ DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); -+ -+ /* LPD can't report unclaimed bytes from IN fifos */ -+ if (ep_is_in(ep)) -+ return -EOPNOTSUPP; -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ jz_udc_select_ep(ep); -+ -+ csr = usb_readb(ep->dev, ep->csr); -+ if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || -+ csr & 0x1) { -+ count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT); -+ } -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ return count; -+} -+ -+/** Flush EP FIFO -+ * NOTE: Sets INDEX register to EP -+ */ -+static void jz4740_fifo_flush(struct usb_ep *_ep) -+{ -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->type == ep_control))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return; -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ jz_udc_select_ep(ep); -+ flush(ep); -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+} -+ -+/****************************************************************/ -+/* End Point 0 related functions */ -+/****************************************************************/ -+ -+/* return: 0 = still running, 1 = completed, negative = errno */ -+static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ uint32_t max; -+ unsigned count; -+ int is_last; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ max = ep_maxpacket(ep); -+ -+ count = write_packet(ep, req, max); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ } -+ -+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static inline int jz4740_fifo_read(struct jz4740_ep *ep, -+ unsigned char *cp, int max) -+{ -+ int bytes; -+ int count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT); -+ -+ if (count > max) -+ count = max; -+ bytes = count; -+ while (count--) -+ *cp++ = usb_readb(ep->dev, ep->fifo); -+ -+ return bytes; -+} -+ -+static inline void jz4740_fifo_write(struct jz4740_ep *ep, -+ unsigned char *cp, int count) -+{ -+ DEBUG("fifo_write: %d %d\n", ep_index(ep), count); -+ while (count--) -+ usb_writeb(ep->dev, ep->fifo, *cp++); -+} -+ -+static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ struct jz4740_udc *dev = ep->dev; -+ uint32_t csr; -+ uint8_t *buf; -+ unsigned bufferspace, count, is_short; -+ -+ DEBUG_EP0("%s\n", __FUNCTION__); -+ -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ if (!(csr & USB_CSR0_OUTPKTRDY)) -+ return 0; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetchw(buf); -+ bufferspace = req->req.length - req->req.actual; -+ -+ /* read all bytes from this packet */ -+ if (likely(csr & USB_CSR0_OUTPKTRDY)) { -+ count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); -+ req->req.actual += min(count, bufferspace); -+ } else /* zlp */ -+ count = 0; -+ -+ is_short = (count < ep->ep.maxpacket); -+ DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", -+ ep->ep.name, csr, count, -+ is_short ? "/S" : "", req, req->req.actual, req->req.length); -+ -+ while (likely(count-- != 0)) { -+ uint8_t byte = (uint8_t)usb_readl(dev, ep->fifo); -+ -+ if (unlikely(bufferspace == 0)) { -+ /* this happens when the driver's buffer -+ * is smaller than what the host sent. -+ * discard the extra data. -+ */ -+ if (req->req.status != -EOVERFLOW) -+ DEBUG_EP0("%s overflow %d\n", ep->ep.name, -+ count); -+ req->req.status = -EOVERFLOW; -+ } else { -+ *buf++ = byte; -+ bufferspace--; -+ } -+ } -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+/** -+ * udc_set_address - set the USB address for this device -+ * @address: -+ * -+ * Called from control endpoint function after it decodes a set address setup packet. -+ */ -+static void udc_set_address(struct jz4740_udc *dev, unsigned char address) -+{ -+ DEBUG_EP0("%s: %d\n", __FUNCTION__, address); -+ -+ usb_writeb(dev, JZ_REG_UDC_FADDR, address); -+} -+ -+/* -+ * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY) -+ * - if error -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits -+ * - else -+ * set USB_CSR0_SVDOUTPKTRDY bit -+ if last set USB_CSR0_DATAEND bit -+ */ -+static void jz4740_ep0_out(struct jz4740_udc *dev, uint32_t csr, int kickstart) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep = &dev->ep[0]; -+ int ret; -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (req) { -+ if (req->req.length == 0) { -+ DEBUG_EP0("ZERO LENGTH OUT!\n"); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return; -+ } else if (kickstart) { -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY)); -+ return; -+ } -+ ret = read_fifo_ep0(ep, req); -+ if (ret) { -+ /* Done! */ -+ DEBUG_EP0("%s: finished, waiting for status\n", -+ __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } else { -+ /* Not done yet.. */ -+ DEBUG_EP0("%s: not finished\n", __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ } -+ } else { -+ DEBUG_EP0("NO REQ??!\n"); -+ } -+} -+ -+/* -+ * DATA_STATE_XMIT -+ */ -+static int jz4740_ep0_in(struct jz4740_udc *dev, uint32_t csr) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep = &dev->ep[0]; -+ int ret, need_zlp = 0; -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (!req) { -+ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); -+ return 0; -+ } -+ -+ if (req->req.length == 0) { -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return 1; -+ } -+ -+ if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) { -+ /* Next write will end with the packet size, */ -+ /* so we need zero-length-packet */ -+ need_zlp = 1; -+ } -+ -+ ret = write_fifo_ep0(ep, req); -+ -+ if (ret == 1 && !need_zlp) { -+ /* Last packet */ -+ DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); -+ -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } else { -+ DEBUG_EP0("%s: not finished\n", __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY); -+ } -+ -+ if (need_zlp) { -+ DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY); -+ dev->ep0state = DATA_STATE_NEED_ZLP; -+ } -+ -+ return 1; -+} -+ -+static int jz4740_handle_get_status(struct jz4740_udc *dev, -+ struct usb_ctrlrequest *ctrl) -+{ -+ struct jz4740_ep *ep0 = &dev->ep[0]; -+ struct jz4740_ep *qep; -+ int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); -+ uint16_t val = 0; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ if (reqtype == USB_RECIP_INTERFACE) { -+ /* This is not supported. -+ * And according to the USB spec, this one does nothing.. -+ * Just return 0 -+ */ -+ DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); -+ } else if (reqtype == USB_RECIP_DEVICE) { -+ DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); -+ val |= (1 << 0); /* Self powered */ -+ /*val |= (1<<1); *//* Remote wakeup */ -+ } else if (reqtype == USB_RECIP_ENDPOINT) { -+ int ep_num = (ctrl->wIndex & ~USB_DIR_IN); -+ -+ DEBUG_SETUP -+ ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", -+ ep_num, ctrl->wLength); -+ -+ if (ctrl->wLength > 2 || ep_num > 3) -+ return -EOPNOTSUPP; -+ -+ qep = &dev->ep[ep_num]; -+ if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) -+ && ep_index(qep) != 0) { -+ return -EOPNOTSUPP; -+ } -+ -+ jz_udc_select_ep(qep); -+ -+ /* Return status on next IN token */ -+ switch (qep->type) { -+ case ep_control: -+ val = -+ (usb_readb(dev, qep->csr) & USB_CSR0_SENDSTALL) == -+ USB_CSR0_SENDSTALL; -+ break; -+ case ep_bulk_in: -+ case ep_interrupt: -+ val = -+ (usb_readb(dev, qep->csr) & USB_INCSR_SENDSTALL) == -+ USB_INCSR_SENDSTALL; -+ break; -+ case ep_bulk_out: -+ val = -+ (usb_readb(dev, qep->csr) & USB_OUTCSR_SENDSTALL) == -+ USB_OUTCSR_SENDSTALL; -+ break; -+ } -+ -+ /* Back to EP0 index */ -+ jz_udc_set_index(dev, 0); -+ -+ DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, -+ ctrl->wIndex, val); -+ } else { -+ DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); -+ return -EOPNOTSUPP; -+ } -+ -+ /* Clear "out packet ready" */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ /* Put status to FIFO */ -+ jz4740_fifo_write(ep0, (uint8_t *)&val, sizeof(val)); -+ /* Issue "In packet ready" */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ -+ return 0; -+} -+ -+/* -+ * WAIT_FOR_SETUP (OUTPKTRDY) -+ * - read data packet from EP0 FIFO -+ * - decode command -+ * - if error -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits -+ * - else -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits -+ */ -+static void jz4740_ep0_setup(struct jz4740_udc *dev, uint32_t csr) -+{ -+ struct jz4740_ep *ep = &dev->ep[0]; -+ struct usb_ctrlrequest ctrl; -+ int i; -+ -+ DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); -+ -+ /* Nuke all previous transfers */ -+ nuke(ep, -EPROTO); -+ -+ /* read control req from fifo (8 bytes) */ -+ jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8); -+ -+ DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n", -+ ctrl.bRequestType, ctrl.bRequest, -+ ctrl.wValue, ctrl.wIndex, ctrl.wLength); -+ -+ /* Set direction of EP0 */ -+ if (likely(ctrl.bRequestType & USB_DIR_IN)) { -+ ep->bEndpointAddress |= USB_DIR_IN; -+ } else { -+ ep->bEndpointAddress &= ~USB_DIR_IN; -+ } -+ -+ /* Handle some SETUP packets ourselves */ -+ switch (ctrl.bRequest) { -+ case USB_REQ_SET_ADDRESS: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); -+ udc_set_address(dev, ctrl.wValue); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ return; -+ -+ case USB_REQ_SET_CONFIGURATION: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue); -+/* usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/ -+ -+ /* Enable RESUME and SUSPEND interrupts */ -+ usb_setb(dev, JZ_REG_UDC_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND)); -+ break; -+ -+ case USB_REQ_SET_INTERFACE: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue); -+/* usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/ -+ break; -+ -+ case USB_REQ_GET_STATUS: -+ if (jz4740_handle_get_status(dev, &ctrl) == 0) -+ return; -+ -+ case USB_REQ_CLEAR_FEATURE: -+ case USB_REQ_SET_FEATURE: -+ if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { -+ struct jz4740_ep *qep; -+ int ep_num = (ctrl.wIndex & 0x0f); -+ -+ /* Support only HALT feature */ -+ if (ctrl.wValue != 0 || ctrl.wLength != 0 -+ || ep_num > 3 || ep_num < 1) -+ break; -+ -+ qep = &dev->ep[ep_num]; -+ spin_unlock(&dev->lock); -+ if (ctrl.bRequest == USB_REQ_SET_FEATURE) { -+ DEBUG_SETUP("SET_FEATURE (%d)\n", -+ ep_num); -+ jz4740_set_halt(&qep->ep, 1); -+ } else { -+ DEBUG_SETUP("CLR_FEATURE (%d)\n", -+ ep_num); -+ jz4740_set_halt(&qep->ep, 0); -+ } -+ spin_lock(&dev->lock); -+ -+ jz_udc_set_index(dev, 0); -+ -+ /* Reply with a ZLP on next IN token */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, -+ (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ return; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ /* gadget drivers see class/vendor specific requests, -+ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, -+ * and more. -+ */ -+ if (dev->driver) { -+ /* device-2-host (IN) or no data setup command, process immediately */ -+ spin_unlock(&dev->lock); -+ -+ i = dev->driver->setup(&dev->gadget, &ctrl); -+ spin_lock(&dev->lock); -+ -+ if (unlikely(i < 0)) { -+ /* setup processing failed, force stall */ -+ DEBUG_SETUP -+ (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", -+ i); -+ jz_udc_set_index(dev, 0); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL)); -+ -+ /* ep->stopped = 1; */ -+ dev->ep0state = WAIT_FOR_SETUP; -+ } -+ else { -+ DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength); -+/* if (!ctrl.wLength) { -+ usb_setb(JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ }*/ -+ } -+ } -+} -+ -+/* -+ * DATA_STATE_NEED_ZLP -+ */ -+static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, uint32_t csr) -+{ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+} -+ -+/* -+ * handle ep0 interrupt -+ */ -+static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr) -+{ -+ struct jz4740_ep *ep = &dev->ep[0]; -+ uint32_t csr; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ /* Set index 0 */ -+ jz_udc_set_index(dev, 0); -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ -+ DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]); -+ -+ /* -+ * if SENT_STALL is set -+ * - clear the SENT_STALL bit -+ */ -+ if (csr & USB_CSR0_SENTSTALL) { -+ DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr); -+ usb_clearb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL); -+ nuke(ep, -ECONNABORTED); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return; -+ } -+ -+ /* -+ * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear -+ * - fill EP0 FIFO -+ * - if last packet -+ * - set IN_PKT_RDY | DATA_END -+ * - else -+ * set IN_PKT_RDY -+ */ -+ if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) { -+ DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n", -+ __FUNCTION__); -+ -+ switch (dev->ep0state) { -+ case DATA_STATE_XMIT: -+ DEBUG_EP0("continue with DATA_STATE_XMIT\n"); -+ jz4740_ep0_in(dev, csr); -+ return; -+ case DATA_STATE_NEED_ZLP: -+ DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); -+ jz4740_ep0_in_zlp(dev, csr); -+ return; -+ default: -+ /* Stall? */ -+// DEBUG_EP0("Odd state!! state = %s\n", -+// state_names[dev->ep0state]); -+ dev->ep0state = WAIT_FOR_SETUP; -+ /* nuke(ep, 0); */ -+ /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */ -+// break; -+ return; -+ } -+ } -+ -+ /* -+ * if SETUPEND is set -+ * - abort the last transfer -+ * - set SERVICED_SETUP_END_BIT -+ */ -+ if (csr & USB_CSR0_SETUPEND) { -+ DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr); -+ -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDSETUPEND); -+ nuke(ep, 0); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } -+ -+ /* -+ * if USB_CSR0_OUTPKTRDY is set -+ * - read data packet from EP0 FIFO -+ * - decode command -+ * - if error -+ * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits -+ * - else -+ * set SVDOUTPKTRDY | DATAEND bits -+ */ -+ if (csr & USB_CSR0_OUTPKTRDY) { -+ -+ DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, -+ csr); -+ -+ switch (dev->ep0state) { -+ case WAIT_FOR_SETUP: -+ DEBUG_EP0("WAIT_FOR_SETUP\n"); -+ jz4740_ep0_setup(dev, csr); -+ break; -+ -+ case DATA_STATE_RECV: -+ DEBUG_EP0("DATA_STATE_RECV\n"); -+ jz4740_ep0_out(dev, csr, 0); -+ break; -+ -+ default: -+ /* send stall? */ -+ DEBUG_EP0("strange state!! 2. send stall? state = %d\n", -+ dev->ep0state); -+ break; -+ } -+ } -+} -+ -+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep) -+{ -+ uint32_t csr; -+ -+ jz_udc_set_index(dev, 0); -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ /* Clear "out packet ready" */ -+ -+ if (ep_is_in(ep)) { -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ dev->ep0state = DATA_STATE_XMIT; -+ jz4740_ep0_in(dev, csr); -+ } else { -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ dev->ep0state = DATA_STATE_RECV; -+ jz4740_ep0_out(dev, csr, 1); -+ } -+} -+ -+/** Handle USB RESET interrupt -+ */ -+static void jz4740_reset_irq(struct jz4740_udc *dev) -+{ -+ dev->gadget.speed = (usb_readb(dev, JZ_REG_UDC_POWER) & USB_POWER_HSMODE) ? -+ USB_SPEED_HIGH : USB_SPEED_FULL; -+ -+ DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, 0, -+ (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" ); -+} -+ -+/* -+ * jz4740 usb device interrupt handler. -+ */ -+static irqreturn_t jz4740_udc_irq(int irq, void *devid) -+{ -+ struct jz4740_udc *jz4740_udc = devid; -+ uint8_t index; -+ -+ uint32_t intr_usb = usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSB) & 0x7; /* mask SOF */ -+ uint32_t intr_in = usb_readw(jz4740_udc, JZ_REG_UDC_INTRIN); -+ uint32_t intr_out = usb_readw(jz4740_udc, JZ_REG_UDC_INTROUT); -+ uint32_t intr_dma = usb_readb(jz4740_udc, JZ_REG_UDC_INTR); -+ -+ if (!intr_usb && !intr_in && !intr_out && !intr_dma) -+ return IRQ_HANDLED; -+ -+ -+ DEBUG("intr_out=%x intr_in=%x intr_usb=%x\n", -+ intr_out, intr_in, intr_usb); -+ -+ spin_lock(&jz4740_udc->lock); -+ index = usb_readb(jz4740_udc, JZ_REG_UDC_INDEX); -+ -+ /* Check for resume from suspend mode */ -+ if ((intr_usb & USB_INTR_RESUME) && -+ (usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSBE) & USB_INTR_RESUME)) { -+ DEBUG("USB resume\n"); -+ jz4740_udc->driver->resume(&jz4740_udc->gadget); /* We have suspend(), so we must have resume() too. */ -+ } -+ -+ /* Check for system interrupts */ -+ if (intr_usb & USB_INTR_RESET) { -+ DEBUG("USB reset\n"); -+ jz4740_reset_irq(jz4740_udc); -+ } -+ -+ /* Check for endpoint 0 interrupt */ -+ if (intr_in & USB_INTR_EP0) { -+ DEBUG("USB_INTR_EP0 (control)\n"); -+ jz4740_handle_ep0(jz4740_udc, intr_in); -+ } -+ -+ /* Check for Bulk-IN DMA interrupt */ -+ if (intr_dma & 0x1) { -+ int ep_num; -+ struct jz4740_ep *ep; -+ ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL1) >> 4) & 0xf; -+ ep = &jz4740_udc->ep[ep_num + 1]; -+ jz_udc_select_ep(ep); -+ usb_setb(jz4740_udc, ep->csr, USB_INCSR_INPKTRDY); -+/* jz4740_in_epn(jz4740_udc, ep_num, intr_in);*/ -+ } -+ -+ /* Check for Bulk-OUT DMA interrupt */ -+ if (intr_dma & 0x2) { -+ int ep_num; -+ ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL2) >> 4) & 0xf; -+ jz4740_out_epn(jz4740_udc, ep_num, intr_out); -+ } -+ -+ /* Check for each configured endpoint interrupt */ -+ if (intr_in & USB_INTR_INEP1) { -+ DEBUG("USB_INTR_INEP1\n"); -+ jz4740_in_epn(jz4740_udc, 1, intr_in); -+ } -+ -+ if (intr_in & USB_INTR_INEP2) { -+ DEBUG("USB_INTR_INEP2\n"); -+ jz4740_in_epn(jz4740_udc, 2, intr_in); -+ } -+ -+ if (intr_out & USB_INTR_OUTEP1) { -+ DEBUG("USB_INTR_OUTEP1\n"); -+ jz4740_out_epn(jz4740_udc, 1, intr_out); -+ } -+ -+ /* Check for suspend mode */ -+ if ((intr_usb & USB_INTR_SUSPEND) && -+ (usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSBE) & USB_INTR_SUSPEND)) { -+ DEBUG("USB suspend\n"); -+ jz4740_udc->driver->suspend(&jz4740_udc->gadget); -+ /* Host unloaded from us, can do something, such as flushing -+ the NAND block cache etc. */ -+ } -+ -+ jz_udc_set_index(jz4740_udc, index); -+ -+ spin_unlock(&jz4740_udc->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+ -+static inline struct jz4740_udc *gadget_to_udc(struct usb_gadget *gadget) -+{ -+ return container_of(gadget, struct jz4740_udc, gadget); -+} -+ -+static int jz4740_udc_get_frame(struct usb_gadget *_gadget) -+{ -+ DEBUG("%s, %p\n", __FUNCTION__, _gadget); -+ return usb_readw(gadget_to_udc(_gadget), JZ_REG_UDC_FRAME); -+} -+ -+static int jz4740_udc_wakeup(struct usb_gadget *_gadget) -+{ -+ /* host may not have enabled remote wakeup */ -+ /*if ((UDCCS0 & UDCCS0_DRWF) == 0) -+ return -EHOSTUNREACH; -+ udc_set_mask_UDCCR(UDCCR_RSM); */ -+ return -ENOTSUPP; -+} -+ -+static int jz4740_udc_pullup(struct usb_gadget *_gadget, int on) -+{ -+ struct jz4740_udc *udc = gadget_to_udc(_gadget); -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (on) { -+ udc->state = UDC_STATE_ENABLE; -+ udc_enable(udc); -+ } else { -+ udc->state = UDC_STATE_DISABLE; -+ udc_disable(udc); -+ } -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+static const struct usb_gadget_ops jz4740_udc_ops = { -+ .get_frame = jz4740_udc_get_frame, -+ .wakeup = jz4740_udc_wakeup, -+ .pullup = jz4740_udc_pullup, -+ .start = jz4740_udc_start, -+ .stop = jz4740_udc_stop, -+}; -+ -+static struct usb_ep_ops jz4740_ep_ops = { -+ .enable = jz4740_ep_enable, -+ .disable = jz4740_ep_disable, -+ -+ .alloc_request = jz4740_alloc_request, -+ .free_request = jz4740_free_request, -+ -+ .queue = jz4740_queue, -+ .dequeue = jz4740_dequeue, -+ -+ .set_halt = jz4740_set_halt, -+ .fifo_status = jz4740_fifo_status, -+ .fifo_flush = jz4740_fifo_flush, -+}; -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct jz4740_udc jz4740_udc_controller = { -+ .gadget = { -+ .ops = &jz4740_udc_ops, -+ .ep0 = &jz4740_udc_controller.ep[0].ep, -+ .name = "jz4740-udc", -+ .dev = { -+ .init_name = "gadget", -+ }, -+ }, -+ -+ /* control endpoint */ -+ .ep[0] = { -+ .ep = { -+ .name = "ep0", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EP0_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 0, -+ .bmAttributes = 0, -+ -+ .type = ep_control, -+ .fifo = JZ_REG_UDC_EP_FIFO(0), -+ .csr = JZ_REG_UDC_CSR0, -+ }, -+ -+ /* bulk out endpoint */ -+ .ep[1] = { -+ .ep = { -+ .name = "ep1out-bulk", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPBULK_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 1, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ -+ .type = ep_bulk_out, -+ .fifo = JZ_REG_UDC_EP_FIFO(1), -+ .csr = JZ_REG_UDC_OUTCSR, -+ }, -+ -+ /* bulk in endpoint */ -+ .ep[2] = { -+ .ep = { -+ .name = "ep1in-bulk", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPBULK_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 1 | USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ -+ .type = ep_bulk_in, -+ .fifo = JZ_REG_UDC_EP_FIFO(1), -+ .csr = JZ_REG_UDC_INCSR, -+ }, -+ -+ /* interrupt in endpoint */ -+ .ep[3] = { -+ .ep = { -+ .name = "ep2in-int", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPINTR_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 2 | USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_INT, -+ -+ .type = ep_interrupt, -+ .fifo = JZ_REG_UDC_EP_FIFO(2), -+ .csr = JZ_REG_UDC_INCSR, -+ }, -+}; -+ -+static int __devinit jz4740_udc_probe(struct platform_device *pdev) -+{ -+ struct jz4740_udc *jz4740_udc = &jz4740_udc_controller; -+ int ret; -+ -+ spin_lock_init(&jz4740_udc->lock); -+ -+ jz4740_udc->dev = &pdev->dev; -+ jz4740_udc->gadget.dev.parent = &pdev->dev; -+ jz4740_udc->gadget.dev.dma_mask = pdev->dev.dma_mask; -+ -+ ret = device_register(&jz4740_udc->gadget.dev); -+ if (ret) -+ return ret; -+ -+ jz4740_udc->clk = clk_get(&pdev->dev, "udc"); -+ if (IS_ERR(jz4740_udc->clk)) { -+ ret = PTR_ERR(jz4740_udc->clk); -+ dev_err(&pdev->dev, "Failed to get udc clock: %d\n", ret); -+ goto err_device_unregister; -+ } -+ -+ platform_set_drvdata(pdev, jz4740_udc); -+ -+ jz4740_udc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ -+ if (!jz4740_udc->mem) { -+ ret = -ENOENT; -+ dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); -+ goto err_clk_put; -+ } -+ -+ jz4740_udc->mem = request_mem_region(jz4740_udc->mem->start, -+ resource_size(jz4740_udc->mem), pdev->name); -+ -+ if (!jz4740_udc->mem) { -+ ret = -EBUSY; -+ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); -+ goto err_device_unregister; -+ } -+ -+ jz4740_udc->base = ioremap(jz4740_udc->mem->start, resource_size(jz4740_udc->mem)); -+ -+ if (!jz4740_udc->base) { -+ ret = -EBUSY; -+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); -+ goto err_release_mem_region; -+ } -+ -+ jz4740_udc->irq = platform_get_irq(pdev, 0); -+ ret = request_irq(jz4740_udc->irq, jz4740_udc_irq, 0, pdev->name, -+ jz4740_udc); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); -+ goto err_iounmap; -+ } -+ -+ ret = usb_add_gadget_udc(&pdev->dev, &jz4740_udc->gadget); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to add gadget: %d\n", ret); -+ goto err_free_irq; -+ } -+ -+ udc_disable(jz4740_udc); -+ udc_reinit(jz4740_udc); -+ -+ return 0; -+ -+err_free_irq: -+ free_irq(jz4740_udc->irq, pdev); -+err_iounmap: -+ iounmap(jz4740_udc->base); -+err_release_mem_region: -+ release_mem_region(jz4740_udc->mem->start, resource_size(jz4740_udc->mem)); -+err_clk_put: -+ clk_put(jz4740_udc->clk); -+err_device_unregister: -+ device_unregister(&jz4740_udc->gadget.dev); -+ platform_set_drvdata(pdev, NULL); -+ -+ return ret; -+} -+ -+static int __devexit jz4740_udc_remove(struct platform_device *pdev) -+{ -+ struct jz4740_udc *dev = platform_get_drvdata(pdev); -+ -+ usb_del_gadget_udc(&dev->gadget); -+ if (dev->driver) -+ return -EBUSY; -+ -+ udc_disable(dev); -+ -+ free_irq(dev->irq, dev); -+ iounmap(dev->base); -+ release_mem_region(dev->mem->start, resource_size(dev->mem)); -+ clk_put(dev->clk); -+ -+ platform_set_drvdata(pdev, NULL); -+ device_unregister(&dev->gadget.dev); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+static int jz4740_udc_suspend(struct device *dev) -+{ -+ struct jz4740_udc *jz4740_udc = dev_get_drvdata(dev); -+ -+ if (jz4740_udc->state == UDC_STATE_ENABLE) -+ udc_disable(jz4740_udc); -+ -+ return 0; -+} -+ -+static int jz4740_udc_resume(struct device *dev) -+{ -+ struct jz4740_udc *jz4740_udc = dev_get_drvdata(dev); -+ -+ if (jz4740_udc->state == UDC_STATE_ENABLE) -+ udc_enable(jz4740_udc); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(jz4740_udc_pm_ops, jz4740_udc_suspend, jz4740_udc_resume); -+#define JZ4740_UDC_PM_OPS (&jz4740_udc_pm_ops) -+ -+#else -+#define JZ4740_UDC_PM_OPS NULL -+#endif -+ -+static struct platform_driver udc_driver = { -+ .probe = jz4740_udc_probe, -+ .remove = __devexit_p(jz4740_udc_remove), -+ .driver = { -+ .name = "jz-udc", -+ .owner = THIS_MODULE, -+ .pm = JZ4740_UDC_PM_OPS, -+ }, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __init udc_init (void) -+{ -+ return platform_driver_register(&udc_driver); -+} -+module_init(udc_init); -+ -+static void __exit udc_exit (void) -+{ -+ platform_driver_unregister(&udc_driver); -+} -+module_exit(udc_exit); -+ -+MODULE_DESCRIPTION("JZ4740 USB Device Controller"); -+MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/usb/gadget/jz4740_udc.h -@@ -0,0 +1,101 @@ -+/* -+ * linux/drivers/usb/gadget/jz4740_udc.h -+ * -+ * Ingenic JZ4740 on-chip high speed USB device controller -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: <jlwei@ingenic.cn> -+ * -+ * 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. -+ */ -+ -+#ifndef __USB_GADGET_JZ4740_H__ -+#define __USB_GADGET_JZ4740_H__ -+ -+/*-------------------------------------------------------------------------*/ -+ -+// Max packet size -+#define EP0_MAXPACKETSIZE 64 -+#define EPBULK_MAXPACKETSIZE 512 -+#define EPINTR_MAXPACKETSIZE 64 -+ -+#define UDC_MAX_ENDPOINTS 4 -+ -+/*-------------------------------------------------------------------------*/ -+ -+enum ep_type { -+ ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt -+}; -+ -+struct jz4740_ep { -+ struct usb_ep ep; -+ struct jz4740_udc *dev; -+ -+ const struct usb_endpoint_descriptor *desc; -+ -+ uint8_t stopped; -+ uint8_t bEndpointAddress; -+ uint8_t bmAttributes; -+ -+ enum ep_type type; -+ size_t fifo; -+ uint32_t csr; -+ -+ uint32_t reg_addr; -+ struct list_head queue; -+}; -+ -+struct jz4740_request { -+ struct usb_request req; -+ struct list_head queue; -+}; -+ -+enum ep0state { -+ WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */ -+ DATA_STATE_XMIT, /* data tx stage */ -+ DATA_STATE_NEED_ZLP, /* data tx zlp stage */ -+ WAIT_FOR_OUT_STATUS, /* status stages */ -+ DATA_STATE_RECV, /* data rx stage */ -+}; -+ -+/* For function binding with UDC Disable - Added by River */ -+typedef enum { -+ UDC_STATE_ENABLE = 0, -+ UDC_STATE_DISABLE, -+}udc_state_t; -+ -+struct jz4740_udc { -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ struct device *dev; -+ spinlock_t lock; -+ unsigned long lock_flags; -+ -+ enum ep0state ep0state; -+ struct jz4740_ep ep[UDC_MAX_ENDPOINTS]; -+ -+ udc_state_t state; -+ -+ struct resource *mem; -+ void __iomem *base; -+ int irq; -+ -+ struct clk *clk; -+}; -+ -+#define ep_maxpacket(EP) ((EP)->ep.maxpacket) -+ -+static inline bool ep_is_in(const struct jz4740_ep *ep) -+{ -+ return (ep->bEndpointAddress & USB_DIR_IN) == USB_DIR_IN; -+} -+ -+static inline uint8_t ep_index(const struct jz4740_ep *ep) -+{ -+ return ep->bEndpointAddress & 0xf; -+} -+ -+#endif /* __USB_GADGET_JZ4740_H__ */ diff --git a/target/linux/xburst/patches-3.2/0003-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch b/target/linux/xburst/patches-3.2/0003-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch deleted file mode 100644 index 9583ab76c5..0000000000 --- a/target/linux/xburst/patches-3.2/0003-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch +++ /dev/null @@ -1,40 +0,0 @@ -From b971c50dc50c07f981a1619f977e7509db9c4eac Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sat, 26 Feb 2011 15:30:07 +0100 -Subject: [PATCH 03/21] NAND: Optimize NAND_ECC_HW_OOB_FIRST read - -Avoid sending unnecessary READ commands to the chip. ---- - drivers/mtd/nand/nand_base.c | 14 ++++++++++---- - 1 files changed, 10 insertions(+), 4 deletions(-) - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -1294,9 +1294,15 @@ static int nand_read_page_hwecc_oob_firs - uint8_t *ecc_calc = chip->buffers->ecccalc; - - /* Read the OOB area first */ -- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ if (mtd->writesize > 512) { -+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ } else { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ } - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; -@@ -1465,7 +1471,7 @@ static int nand_do_read_ops(struct mtd_i - if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers->databuf; - -- if (likely(sndcmd)) { -+ if (likely(sndcmd) && chip->ecc.mode != NAND_ECC_HW_OOB_FIRST) { - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - sndcmd = 0; - } diff --git a/target/linux/xburst/patches-3.2/0004-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch b/target/linux/xburst/patches-3.2/0004-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch deleted file mode 100644 index 290a662206..0000000000 --- a/target/linux/xburst/patches-3.2/0004-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 297d8a7bdfb755778d4189ca2861dd2a6125e972 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Tue, 15 Mar 2011 12:33:41 +0100 -Subject: [PATCH 04/21] NAND: Add support for subpage reads for - NAND_ECC_HW_OOB_FIRST - ---- - drivers/mtd/nand/nand_base.c | 78 ++++++++++++++++++++++++++++++++++++++++-- - include/linux/mtd/nand.h | 8 ++-- - 2 files changed, 79 insertions(+), 7 deletions(-) - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -1143,7 +1143,7 @@ static int nand_read_page_swecc(struct m - * @bufpoi: buffer to store read data - */ - static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, -- uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) -+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page) - { - int start_step, end_step, num_steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; -@@ -1324,6 +1324,75 @@ static int nand_read_page_hwecc_oob_firs - } - - /** -+ * nand_read_subpage_hwecc_oob_first - [REPLACABLE] hw ecc based sub-page read function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @data_offs: offset of requested data within the page -+ * @readlen: data length -+ * @bufpoi: buffer to store read data -+ * @page: page number to read -+ * -+ * Hardware ECC for large page chips, require OOB to be read first. -+ * For this ECC mode, the write_page method is re-used from ECC_HW. -+ * These methods read/write ECC from the OOB area, unlike the -+ * ECC_HW_SYNDROME support with multiple ECC steps, follows the -+ * "infix ECC" scheme and reads/writes ECC from the data area, by -+ * overwriting the NAND manufacturer bad block markings. -+ */ -+static int nand_read_subpage_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip, -+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page) -+{ -+ int start_step, end_step, num_steps; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ uint8_t *p; -+ int data_col_addr; -+ int eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ int i; -+ -+ /* Column address wihin the page aligned to ECC size */ -+ start_step = data_offs / chip->ecc.size; -+ end_step = (data_offs + readlen - 1) / chip->ecc.size; -+ num_steps = end_step - start_step + 1; -+ -+ data_col_addr = start_step * chip->ecc.size; -+ -+ /* Read the OOB area first */ -+ if (mtd->writesize > 512) { -+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); -+ } else { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page); -+ } -+ -+ for (i = 0; i < chip->ecc.total; i++) -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ -+ p = bufpoi + data_col_addr; -+ -+ for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) { -+ int stat; -+ -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ chip->ecc.calculate(mtd, p, &ecc_calc[i]); -+ -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ -+ return 0; -+} -+ -+/** - * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read - * @mtd: mtd info structure - * @chip: nand chip info structure -@@ -1482,7 +1551,7 @@ static int nand_do_read_ops(struct mtd_i - bufpoi, page); - else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) - ret = chip->ecc.read_subpage(mtd, chip, -- col, bytes, bufpoi); -+ col, bytes, bufpoi, page); - else - ret = chip->ecc.read_page(mtd, chip, bufpoi, - page); -@@ -3292,8 +3361,11 @@ int nand_scan_tail(struct mtd_info *mtd) - "hardware ECC not possible\n"); - BUG(); - } -- if (!chip->ecc.read_page) -+ if (!chip->ecc.read_page) { - chip->ecc.read_page = nand_read_page_hwecc_oob_first; -+ if (!chip->ecc.read_subpage) -+ chip->ecc.read_subpage = nand_read_subpage_hwecc_oob_first; -+ } - - case NAND_ECC_HW: - /* Use standard hwecc read page function? */ ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -211,9 +211,9 @@ typedef enum { - #define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) - #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) - #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) --/* Large page NAND with SOFT_ECC should support subpage reads */ --#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ -- && (chip->page_shift > 9)) -+/* Large page NAND with read_subpage set should support subpage reads */ -+#define NAND_SUBPAGE_READ(chip) (((chip)->ecc.read_subpage) \ -+ && ((chip)->page_shift > 9)) - - /* Mask to zero out the chip options, which come from the id table */ - #define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) -@@ -367,7 +367,7 @@ struct nand_ecc_ctrl { - int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page); - int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, -- uint32_t offs, uint32_t len, uint8_t *buf); -+ uint32_t offs, uint32_t len, uint8_t *buf, int page); - void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf); - int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, diff --git a/target/linux/xburst/patches-3.2/0005-NAND-Optimize-reading-the-eec-data-for-the-JZ4740.patch b/target/linux/xburst/patches-3.2/0005-NAND-Optimize-reading-the-eec-data-for-the-JZ4740.patch deleted file mode 100644 index 38a1395075..0000000000 --- a/target/linux/xburst/patches-3.2/0005-NAND-Optimize-reading-the-eec-data-for-the-JZ4740.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 4f28237a750afd1112b6f1266d36f8b718efe89c Mon Sep 17 00:00:00 2001 -From: Xiangfu Liu <xiangfu@sharism.cc> -Date: Tue, 6 Mar 2012 11:19:26 +0800 -Subject: [PATCH 05/21] NAND-Optimize-reading-the-eec-data-for-the-JZ4740 - ---- - drivers/mtd/nand/nand_base.c | 14 ++++---------- - 1 files changed, 4 insertions(+), 10 deletions(-) - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -1295,8 +1295,8 @@ static int nand_read_page_hwecc_oob_firs - - /* Read the OOB area first */ - if (mtd->writesize > 512) { -- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); -- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize + eccpos[0], page); -+ chip->read_buf(mtd, ecc_code, chip->ecc.total); - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -@@ -1304,9 +1304,6 @@ static int nand_read_page_hwecc_oob_firs - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - } - -- for (i = 0; i < chip->ecc.total; i++) -- ecc_code[i] = chip->oob_poi[eccpos[i]]; -- - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - -@@ -1361,8 +1358,8 @@ static int nand_read_subpage_hwecc_oob_f - - /* Read the OOB area first */ - if (mtd->writesize > 512) { -- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); -- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize + eccpos[0], page); -+ chip->read_buf(mtd, ecc_code, chip->ecc.total); - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -@@ -1370,9 +1367,6 @@ static int nand_read_subpage_hwecc_oob_f - chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page); - } - -- for (i = 0; i < chip->ecc.total; i++) -- ecc_code[i] = chip->oob_poi[eccpos[i]]; -- - p = bufpoi + data_col_addr; - - for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) { diff --git a/target/linux/xburst/patches-3.2/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch b/target/linux/xburst/patches-3.2/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch deleted file mode 100644 index 4110147974..0000000000 --- a/target/linux/xburst/patches-3.2/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch +++ /dev/null @@ -1,417 +0,0 @@ -From d5814bdb661d3dac61422f8f69e459be884c9a9d Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Tue, 2 Aug 2011 10:49:28 +0200 -Subject: [PATCH 06/21] MTD: NAND: JZ4740: Multi-bank support with - autodetection - -The platform data can now specify which external memory banks to probe -for NAND chips, and in which order. Banks that contain a NAND are used -and the other banks are freed. - -Squashed version of development done in jz-2.6.38 branch. -Original patch by Lars-Peter Clausen with some bug fixes from me. -Thanks to Paul Cercueil for the initial autodetection patch. ---- - arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 4 + - arch/mips/jz4740/platform.c | 20 ++- - drivers/mtd/nand/jz4740_nand.c | 228 +++++++++++++++++++---- - 3 files changed, 215 insertions(+), 37 deletions(-) - ---- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h -+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h -@@ -19,6 +19,8 @@ - #include <linux/mtd/nand.h> - #include <linux/mtd/partitions.h> - -+#define JZ_NAND_NUM_BANKS 4 -+ - struct jz_nand_platform_data { - int num_partitions; - struct mtd_partition *partitions; -@@ -27,6 +29,8 @@ struct jz_nand_platform_data { - - unsigned int busy_gpio; - -+ unsigned char banks[JZ_NAND_NUM_BANKS]; -+ - void (*ident_callback)(struct platform_device *, struct nand_chip *, - struct mtd_partition **, int *num_partitions); - }; ---- a/arch/mips/jz4740/platform.c -+++ b/arch/mips/jz4740/platform.c -@@ -157,11 +157,29 @@ static struct resource jz4740_nand_resou - .flags = IORESOURCE_MEM, - }, - { -- .name = "bank", -+ .name = "bank1", - .start = 0x18000000, - .end = 0x180C0000 - 1, - .flags = IORESOURCE_MEM, - }, -+ { -+ .name = "bank2", -+ .start = 0x14000000, -+ .end = 0x140C0000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .name = "bank3", -+ .start = 0x0C000000, -+ .end = 0x0C0C0000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .name = "bank4", -+ .start = 0x08000000, -+ .end = 0x080C0000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, - }; - - struct platform_device jz4740_nand_device = { ---- a/drivers/mtd/nand/jz4740_nand.c -+++ b/drivers/mtd/nand/jz4740_nand.c -@@ -52,9 +52,10 @@ - - #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) - #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) -+#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa - --#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 - #define JZ_NAND_MEM_CMD_OFFSET 0x08000 -+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 - - struct jz_nand { - struct mtd_info mtd; -@@ -62,8 +63,11 @@ struct jz_nand { - void __iomem *base; - struct resource *mem; - -- void __iomem *bank_base; -- struct resource *bank_mem; -+ unsigned char banks[JZ_NAND_NUM_BANKS]; -+ void __iomem *bank_base[JZ_NAND_NUM_BANKS]; -+ struct resource *bank_mem[JZ_NAND_NUM_BANKS]; -+ -+ int selected_bank; - - struct jz_nand_platform_data *pdata; - bool is_reading; -@@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_ - return container_of(mtd, struct jz_nand, mtd); - } - -+static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) -+{ -+ struct jz_nand *nand = mtd_to_jz_nand(mtd); -+ struct nand_chip *chip = mtd->priv; -+ uint32_t ctrl; -+ int banknr; -+ -+ ctrl = readl(nand->base + JZ_REG_NAND_CTRL); -+ ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; -+ -+ if (chipnr == -1) { -+ banknr = -1; -+ } else { -+ banknr = nand->banks[chipnr] - 1; -+ chip->IO_ADDR_R = nand->bank_base[banknr]; -+ chip->IO_ADDR_W = nand->bank_base[banknr]; -+ } -+ writel(ctrl, nand->base + JZ_REG_NAND_CTRL); -+ -+ nand->selected_bank = banknr; -+} -+ - static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) - { - struct jz_nand *nand = mtd_to_jz_nand(mtd); - struct nand_chip *chip = mtd->priv; - uint32_t reg; -+ void __iomem *bank_base = nand->bank_base[nand->selected_bank]; -+ -+ BUG_ON(nand->selected_bank < 0); - - if (ctrl & NAND_CTRL_CHANGE) { - BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); - if (ctrl & NAND_ALE) -- chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET; -+ bank_base += JZ_NAND_MEM_ADDR_OFFSET; - else if (ctrl & NAND_CLE) -- chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET; -- else -- chip->IO_ADDR_W = nand->bank_base; -+ bank_base += JZ_NAND_MEM_CMD_OFFSET; -+ chip->IO_ADDR_W = bank_base; - - reg = readl(nand->base + JZ_REG_NAND_CTRL); - if (ctrl & NAND_NCE) -- reg |= JZ_NAND_CTRL_ASSERT_CHIP(0); -+ reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - else -- reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0); -+ reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - writel(reg, nand->base + JZ_REG_NAND_CTRL); - } - if (dat != NAND_CMD_NONE) -@@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct - } - - static int jz_nand_ioremap_resource(struct platform_device *pdev, -- const char *name, struct resource **res, void __iomem **base) -+ const char *name, struct resource **res, void *__iomem *base) - { - int ret; - -@@ -288,6 +316,90 @@ err: - return ret; - } - -+static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) -+{ -+ iounmap(base); -+ release_mem_region(res->start, resource_size(res)); -+} -+ -+static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { -+ int ret; -+ int gpio; -+ char gpio_name[9]; -+ char res_name[6]; -+ uint32_t ctrl; -+ struct mtd_info *mtd = &nand->mtd; -+ struct nand_chip *chip = &nand->chip; -+ -+ /* Request GPIO port. */ -+ gpio = JZ_GPIO_MEM_CS0 + bank - 1; -+ sprintf(gpio_name, "NAND CS%d", bank); -+ ret = gpio_request(gpio, gpio_name); -+ if (ret) { -+ dev_warn(&pdev->dev, -+ "Failed to request %s gpio %d: %d\n", -+ gpio_name, gpio, ret); -+ goto notfound_gpio; -+ } -+ -+ /* Request I/O resource. */ -+ sprintf(res_name, "bank%d", bank); -+ ret = jz_nand_ioremap_resource(pdev, res_name, -+ &nand->bank_mem[bank - 1], -+ &nand->bank_base[bank - 1]); -+ if (ret) -+ goto notfound_resource; -+ -+ /* Enable chip in bank. */ -+ jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0); -+ ctrl = readl(nand->base + JZ_REG_NAND_CTRL); -+ ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); -+ writel(ctrl, nand->base + JZ_REG_NAND_CTRL); -+ -+ if (chipnr == 0) { -+ /* Detect first chip. */ -+ ret = nand_scan_ident(mtd, 1, NULL); -+ if (ret) -+ goto notfound_id; -+ -+ /* Retrieve the IDs from the first chip. */ -+ chip->select_chip(mtd, 0); -+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); -+ *nand_maf_id = chip->read_byte(mtd); -+ *nand_dev_id = chip->read_byte(mtd); -+ } else { -+ /* Detect additional chip. */ -+ chip->select_chip(mtd, chipnr); -+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); -+ if (*nand_maf_id != chip->read_byte(mtd) -+ || *nand_dev_id != chip->read_byte(mtd)) { -+ ret = -ENODEV; -+ goto notfound_id; -+ } -+ -+ /* Update size of the MTD. */ -+ chip->numchips++; -+ mtd->size += chip->chipsize; -+ } -+ -+ dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank); -+ return 0; -+ -+notfound_id: -+ dev_info(&pdev->dev, "No chip found on bank %i\n", bank); -+ ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); -+ writel(ctrl, nand->base + JZ_REG_NAND_CTRL); -+ jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); -+ jz_nand_iounmap_resource(nand->bank_mem[bank - 1], -+ nand->bank_base[bank - 1]); -+notfound_resource: -+ gpio_free(gpio); -+notfound_gpio: -+ return ret; -+} -+ - static int __devinit jz_nand_probe(struct platform_device *pdev) - { - int ret; -@@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struc - struct nand_chip *chip; - struct mtd_info *mtd; - struct jz_nand_platform_data *pdata = pdev->dev.platform_data; -+ size_t chipnr, bank_idx; -+ uint8_t nand_maf_id = 0, nand_dev_id = 0; - - nand = kzalloc(sizeof(*nand), GFP_KERNEL); - if (!nand) { -@@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struc - ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); - if (ret) - goto err_free; -- ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem, -- &nand->bank_base); -- if (ret) -- goto err_iounmap_mmio; - - if (pdata && gpio_is_valid(pdata->busy_gpio)) { - ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); -@@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struc - dev_err(&pdev->dev, - "Failed to request busy gpio %d: %d\n", - pdata->busy_gpio, ret); -- goto err_iounmap_mem; -+ goto err_iounmap_mmio; - } - } - -@@ -338,22 +448,51 @@ static int __devinit jz_nand_probe(struc - - chip->chip_delay = 50; - chip->cmd_ctrl = jz_nand_cmd_ctrl; -+ chip->select_chip = jz_nand_select_chip; - - if (pdata && gpio_is_valid(pdata->busy_gpio)) - chip->dev_ready = jz_nand_dev_ready; - -- chip->IO_ADDR_R = nand->bank_base; -- chip->IO_ADDR_W = nand->bank_base; -- - nand->pdata = pdata; - platform_set_drvdata(pdev, nand); - -- writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL); -- -- ret = nand_scan_ident(mtd, 1, NULL); -- if (ret) { -- dev_err(&pdev->dev, "Failed to scan nand\n"); -- goto err_gpio_free; -+ /* We are going to autodetect NAND chips in the banks specified in the -+ * platform data. Although nand_scan_ident() can detect multiple chips, -+ * it requires those chips to be numbered consecuitively, which is not -+ * always the case for external memory banks. And a fixed chip-to-bank -+ * mapping is not practical either, since for example Dingoo units -+ * produced at different times have NAND chips in different banks. -+ */ -+ chipnr = 0; -+ for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { -+ unsigned char bank; -+ -+ /* If there is no platform data, look for NAND in bank 1, -+ * which is the most likely bank since it is the only one -+ * that can be booted from. -+ */ -+ bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; -+ if (bank == 0) -+ break; -+ if (bank > JZ_NAND_NUM_BANKS) { -+ dev_warn(&pdev->dev, -+ "Skipping non-existing bank: %d\n", bank); -+ continue; -+ } -+ /* The detection routine will directly or indirectly call -+ * jz_nand_select_chip(), so nand->banks has to contain the -+ * bank we're checking. -+ */ -+ nand->banks[chipnr] = bank; -+ if (jz_nand_detect_bank(pdev, nand, bank, chipnr, -+ &nand_maf_id, &nand_dev_id) == 0) -+ chipnr++; -+ else -+ nand->banks[chipnr] = 0; -+ } -+ if (chipnr == 0) { -+ dev_err(&pdev->dev, "No NAND chips found\n"); -+ goto err_gpio_busy; - } - - if (pdata && pdata->ident_callback) { -@@ -363,8 +502,8 @@ static int __devinit jz_nand_probe(struc - - ret = nand_scan_tail(mtd); - if (ret) { -- dev_err(&pdev->dev, "Failed to scan nand\n"); -- goto err_gpio_free; -+ dev_err(&pdev->dev, "Failed to scan NAND\n"); -+ goto err_unclaim_banks; - } - - ret = mtd_device_parse_register(mtd, NULL, 0, -@@ -381,14 +520,21 @@ static int __devinit jz_nand_probe(struc - return 0; - - err_nand_release: -- nand_release(&nand->mtd); --err_gpio_free: -+ nand_release(mtd); -+err_unclaim_banks: -+ while (chipnr--) { -+ unsigned char bank = nand->banks[chipnr]; -+ gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); -+ jz_nand_iounmap_resource(nand->bank_mem[bank - 1], -+ nand->bank_base[bank - 1]); -+ } -+ writel(0, nand->base + JZ_REG_NAND_CTRL); -+err_gpio_busy: -+ if (pdata && gpio_is_valid(pdata->busy_gpio)) -+ gpio_free(pdata->busy_gpio); - platform_set_drvdata(pdev, NULL); -- gpio_free(pdata->busy_gpio); --err_iounmap_mem: -- iounmap(nand->bank_base); - err_iounmap_mmio: -- iounmap(nand->base); -+ jz_nand_iounmap_resource(nand->mem, nand->base); - err_free: - kfree(nand); - return ret; -@@ -397,16 +543,26 @@ err_free: - static int __devexit jz_nand_remove(struct platform_device *pdev) - { - struct jz_nand *nand = platform_get_drvdata(pdev); -+ struct jz_nand_platform_data *pdata = pdev->dev.platform_data; -+ size_t i; - - nand_release(&nand->mtd); - - /* Deassert and disable all chips */ - writel(0, nand->base + JZ_REG_NAND_CTRL); - -- iounmap(nand->bank_base); -- release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem)); -- iounmap(nand->base); -- release_mem_region(nand->mem->start, resource_size(nand->mem)); -+ for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { -+ unsigned char bank = nand->banks[i]; -+ if (bank != 0) { -+ jz_nand_iounmap_resource(nand->bank_mem[bank - 1], -+ nand->bank_base[bank - 1]); -+ gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); -+ } -+ } -+ if (pdata && gpio_is_valid(pdata->busy_gpio)) -+ gpio_free(pdata->busy_gpio); -+ -+ jz_nand_iounmap_resource(nand->mem, nand->base); - - platform_set_drvdata(pdev, NULL); - kfree(nand); diff --git a/target/linux/xburst/patches-3.2/0007-Add-ili8960-lcd-driver.patch b/target/linux/xburst/patches-3.2/0007-Add-ili8960-lcd-driver.patch deleted file mode 100644 index d7eaa0793f..0000000000 --- a/target/linux/xburst/patches-3.2/0007-Add-ili8960-lcd-driver.patch +++ /dev/null @@ -1,304 +0,0 @@ -From 2248fb9c47fe7e72c735d6c16aba27bf92e1673a Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sun, 1 Aug 2010 21:19:40 +0200 -Subject: [PATCH 07/21] Add ili8960 lcd driver - ---- - drivers/video/backlight/Kconfig | 7 + - drivers/video/backlight/Makefile | 1 + - drivers/video/backlight/ili8960.c | 263 +++++++++++++++++++++++++++++++++++++ - 3 files changed, 271 insertions(+), 0 deletions(-) - create mode 100644 drivers/video/backlight/ili8960.c - ---- a/drivers/video/backlight/Kconfig -+++ b/drivers/video/backlight/Kconfig -@@ -59,6 +59,13 @@ config LCD_LTV350QV - - The LTV350QV panel is present on all ATSTK1000 boards. - -+config LCD_ILI8960 -+ tristate "Ilitek ili8960 LCD driver" -+ depends on LCD_CLASS_DEVICE && SPI -+ default n -+ help -+ Driver for the Ilitek ili8960 LCD controller chip. -+ - config LCD_ILI9320 - tristate - help ---- a/drivers/video/backlight/Makefile -+++ b/drivers/video/backlight/Makefile -@@ -6,6 +6,7 @@ obj-$(CONFIG_LCD_HP700) += jornada72 - obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o - obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o - obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o -+obj-$(CONFIG_LCD_ILI8960) += ili8960.o - obj-$(CONFIG_LCD_ILI9320) += ili9320.o - obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o - obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o ---- /dev/null -+++ b/drivers/video/backlight/ili8960.c -@@ -0,0 +1,263 @@ -+/* -+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> -+ * Driver for Ilitek ili8960 LCD -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/spi/spi.h> -+#include <linux/lcd.h> -+#include <linux/backlight.h> -+#include <linux/delay.h> -+ -+struct ili8960 { -+ struct spi_device *spi; -+ struct lcd_device *lcd; -+ struct backlight_device *bl; -+ bool enabled; -+ unsigned int brightness; -+}; -+ -+#define ILI8960_REG_BRIGHTNESS 0x03 -+#define ILI8960_REG_POWER 0x05 -+#define ILI8960_REG_CONTRAST 0x0d -+ -+static int ili8960_write_reg(struct spi_device *spi, uint8_t reg, -+ uint8_t data) -+{ -+ uint8_t buf[2]; -+ buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f); -+ buf[1] = data; -+ -+ return spi_write(spi, buf, sizeof(buf)); -+} -+ -+static int ili8960_programm_power(struct spi_device *spi, bool enabled) -+{ -+ int ret; -+ -+ if (enabled) -+ mdelay(20); -+ -+ ret = ili8960_write_reg(spi, ILI8960_REG_POWER, enabled ? 0xc7 : 0xc6); -+ -+ if (!enabled) -+ mdelay(20); -+ -+ return ret; -+} -+ -+static int ili8960_set_power(struct lcd_device *lcd, int power) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ -+ switch (power) { -+ case FB_BLANK_UNBLANK: -+ ili8960->enabled = true; -+ break; -+ default: -+ ili8960->enabled = false; -+ break; -+ } -+ -+ return ili8960_programm_power(ili8960->spi, ili8960->enabled); -+} -+ -+static int ili8960_get_power(struct lcd_device *lcd) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; -+} -+ -+static int ili8960_set_contrast(struct lcd_device *lcd, int contrast) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ -+ return ili8960_write_reg(ili8960->spi, ILI8960_REG_CONTRAST, contrast); -+} -+ -+static int ili8960_set_mode(struct lcd_device *lcd, struct fb_videomode *mode) -+{ -+ if (mode->xres != 320 && mode->yres != 240) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int ili8960_set_brightness(struct ili8960 *ili8960, int brightness) -+{ -+ int ret; -+ -+ ret = ili8960_write_reg(ili8960->spi, ILI8960_REG_BRIGHTNESS, brightness); -+ -+ if (ret == 0) -+ ili8960->brightness = brightness; -+ -+ return ret; -+} -+ -+static ssize_t ili8960_show_brightness(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct lcd_device *ld = to_lcd_device(dev); -+ struct ili8960 *ili8960 = lcd_get_data(ld); -+ -+ return sprintf(buf, "%u\n", ili8960->brightness); -+} -+ -+static ssize_t ili8960_store_brightness(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct lcd_device *ld = to_lcd_device(dev); -+ struct ili8960 *ili8960 = lcd_get_data(ld); -+ unsigned long brightness; -+ int ret; -+ -+ ret = strict_strtoul(buf, 0, &brightness); -+ if (ret) -+ return ret; -+ -+ if (brightness > 255) -+ return -EINVAL; -+ -+ ili8960_set_brightness(ili8960, brightness); -+ -+ return count; -+} -+ -+ -+static DEVICE_ATTR(brightness, 0644, ili8960_show_brightness, -+ ili8960_store_brightness); -+ -+static struct lcd_ops ili8960_lcd_ops = { -+ .set_power = ili8960_set_power, -+ .get_power = ili8960_get_power, -+ .set_contrast = ili8960_set_contrast, -+ .set_mode = ili8960_set_mode, -+}; -+ -+static int __devinit ili8960_probe(struct spi_device *spi) -+{ -+ int ret; -+ struct ili8960 *ili8960; -+ -+ ili8960 = kmalloc(sizeof(*ili8960), GFP_KERNEL); -+ if (!ili8960) -+ return -ENOMEM; -+ -+ spi->bits_per_word = 8; -+ spi->mode = SPI_MODE_3; -+ -+ ret = spi_setup(spi); -+ if (ret) { -+ dev_err(&spi->dev, "Failed to setup spi\n"); -+ goto err_free_ili8960; -+ } -+ -+ ili8960->spi = spi; -+ -+ ili8960->lcd = lcd_device_register("ili8960-lcd", &spi->dev, ili8960, -+ &ili8960_lcd_ops); -+ -+ if (IS_ERR(ili8960->lcd)) { -+ ret = PTR_ERR(ili8960->lcd); -+ dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret); -+ goto err_free_ili8960; -+ } -+ -+ ili8960->lcd->props.max_contrast = 255; -+ -+ ret = device_create_file(&ili8960->lcd->dev, &dev_attr_brightness); -+ if (ret) -+ goto err_unregister_lcd; -+ -+ ili8960_programm_power(ili8960->spi, true); -+ ili8960->enabled = true; -+ -+ spi_set_drvdata(spi, ili8960); -+ -+ ili8960_write_reg(spi, 0x13, 0x01); -+ -+ return 0; -+err_unregister_lcd: -+ lcd_device_unregister(ili8960->lcd); -+err_free_ili8960: -+ kfree(ili8960); -+ return ret; -+} -+ -+static int __devexit ili8960_remove(struct spi_device *spi) -+{ -+ struct ili8960 *ili8960 = spi_get_drvdata(spi); -+ -+ device_remove_file(&ili8960->lcd->dev, &dev_attr_brightness); -+ lcd_device_unregister(ili8960->lcd); -+ -+ spi_set_drvdata(spi, NULL); -+ kfree(ili8960); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+static int ili8960_suspend(struct spi_device *spi, pm_message_t state) -+{ -+ struct ili8960 *ili8960 = spi_get_drvdata(spi); -+ -+ if (ili8960->enabled) -+ ili8960_programm_power(ili8960->spi, false); -+ -+ return 0; -+} -+ -+static int ili8960_resume(struct spi_device *spi) -+{ -+ struct ili8960 *ili8960 = spi_get_drvdata(spi); -+ -+ if (ili8960->enabled) -+ ili8960_programm_power(ili8960->spi, true); -+ -+ return 0; -+} -+ -+#else -+#define ili8960_suspend NULL -+#define ili8960_resume NULL -+#endif -+ -+static struct spi_driver ili8960_driver = { -+ .driver = { -+ .name = "ili8960", -+ .owner = THIS_MODULE, -+ }, -+ .probe = ili8960_probe, -+ .remove = __devexit_p(ili8960_remove), -+ .suspend = ili8960_suspend, -+ .resume = ili8960_resume, -+}; -+ -+static int __init ili8960_init(void) -+{ -+ return spi_register_driver(&ili8960_driver); -+} -+module_init(ili8960_init); -+ -+static void __exit ili8960_exit(void) -+{ -+ spi_unregister_driver(&ili8960_driver); -+} -+module_exit(ili8960_exit) -+ -+MODULE_AUTHOR("Lars-Peter Clausen"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("LCD driver for Ilitek ili8960"); -+MODULE_ALIAS("spi:ili8960"); diff --git a/target/linux/xburst/patches-3.2/0008-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch b/target/linux/xburst/patches-3.2/0008-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch deleted file mode 100644 index 223459cab4..0000000000 --- a/target/linux/xburst/patches-3.2/0008-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch +++ /dev/null @@ -1,21 +0,0 @@ -From e5f25e25ed6c0478cbba7a32891b911e3183dad4 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Wed, 13 Oct 2010 01:17:24 +0200 -Subject: [PATCH 08/21] qi_lb60: Don't use 3-wire spi mode for the display for - now - -The spi_gpio driver does not support 3-wire mode. ---- - arch/mips/jz4740/board-qi_lb60.c | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) - ---- a/arch/mips/jz4740/board-qi_lb60.c -+++ b/arch/mips/jz4740/board-qi_lb60.c -@@ -310,7 +310,6 @@ static struct spi_board_info qi_lb60_spi - .chip_select = 0, - .bus_num = 1, - .max_speed_hz = 30 * 1000, -- .mode = SPI_3WIRE, - }, - }; - diff --git a/target/linux/xburst/patches-3.2/0009-dev-mem-Add-kernel-config-option-to-omit-this-device.patch b/target/linux/xburst/patches-3.2/0009-dev-mem-Add-kernel-config-option-to-omit-this-device.patch deleted file mode 100644 index 28388fba76..0000000000 --- a/target/linux/xburst/patches-3.2/0009-dev-mem-Add-kernel-config-option-to-omit-this-device.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 4003b9a2c05f4d0d37535c3dffbf4a7b47d5c36c Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Wed, 8 Sep 2010 02:31:19 +0200 -Subject: [PATCH 09/21] /dev/mem: Add kernel config option to omit this - device. - -Omitting this device prevents software from accessing the hardware directly, which can cause trouble if the kernel accesses the same hardware. -It also saves some space on embedded systems. ---- - arch/x86/Kconfig.debug | 1 + - drivers/char/Kconfig | 10 ++++++++++ - drivers/char/mem.c | 17 +++++++++++++++++ - 3 files changed, 28 insertions(+), 0 deletions(-) - ---- a/arch/x86/Kconfig.debug -+++ b/arch/x86/Kconfig.debug -@@ -7,6 +7,7 @@ source "lib/Kconfig.debug" - - config STRICT_DEVMEM - bool "Filter access to /dev/mem" -+ depends on DEVMEM - ---help--- - If this option is disabled, you allow userspace (root) access to all - of memory, including kernel and userspace memory. Accidental ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -6,6 +6,16 @@ menu "Character devices" - - source "drivers/tty/Kconfig" - -+config DEVMEM -+ bool "/dev/mem virtual device support" -+ default y -+ help -+ Say Y here if you want to support the /dev/mem device. -+ Some X server drivers access the video hardware using this device. -+ Accessing hardware directly from user space can be useful in some -+ cases, but it is not without risks. -+ When in doubt, say "N". -+ - config DEVKMEM - bool "/dev/kmem virtual device support" - default y ---- a/drivers/char/mem.c -+++ b/drivers/char/mem.c -@@ -87,6 +87,8 @@ void __weak unxlate_dev_mem_ptr(unsigned - { - } - -+#ifdef CONFIG_DEVMEM -+ - /* - * This funcion reads the *physical* memory. The f_pos points directly to the - * memory location. -@@ -210,6 +212,10 @@ static ssize_t write_mem(struct file *fi - return written; - } - -+#endif -+ -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) -+ - int __weak phys_mem_access_prot_allowed(struct file *file, - unsigned long pfn, unsigned long size, pgprot_t *vma_prot) - { -@@ -331,6 +337,8 @@ static int mmap_mem(struct file *file, s - return 0; - } - -+#endif -+ - #ifdef CONFIG_DEVKMEM - static int mmap_kmem(struct file *file, struct vm_area_struct *vma) - { -@@ -694,6 +702,7 @@ static loff_t null_lseek(struct file *fi - return file->f_pos = 0; - } - -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || defined(CONFIG_DEVPORT) - /* - * The memory devices use the full 32/64 bits of the offset, and so we cannot - * check against negative addresses: they are ok. The return value is weird, -@@ -726,11 +735,15 @@ static loff_t memory_lseek(struct file * - mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); - return ret; - } -+#endif - -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || \ -+ defined(CONFIG_DEVPORT) || defined(CONFIG_CRASH_DUMP) - static int open_port(struct inode * inode, struct file * filp) - { - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; - } -+#endif - - #define zero_lseek null_lseek - #define full_lseek null_lseek -@@ -740,6 +753,7 @@ static int open_port(struct inode * inod - #define open_kmem open_mem - #define open_oldmem open_mem - -+#ifdef CONFIG_DEVMEM - static const struct file_operations mem_fops = { - .llseek = memory_lseek, - .read = read_mem, -@@ -748,6 +762,7 @@ static const struct file_operations mem_ - .open = open_mem, - .get_unmapped_area = get_unmapped_area_mem, - }; -+#endif - - #ifdef CONFIG_DEVKMEM - static const struct file_operations kmem_fops = { -@@ -851,7 +866,9 @@ static const struct memdev { - const struct file_operations *fops; - struct backing_dev_info *dev_info; - } devlist[] = { -+#ifdef CONFIG_DEVMEM - [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi }, -+#endif - #ifdef CONFIG_DEVKMEM - [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi }, - #endif diff --git a/target/linux/xburst/patches-3.2/0010-cpufreq_stats-Support-runtime-changes-to-frequency-t.patch b/target/linux/xburst/patches-3.2/0010-cpufreq_stats-Support-runtime-changes-to-frequency-t.patch deleted file mode 100644 index 677e3c5e26..0000000000 --- a/target/linux/xburst/patches-3.2/0010-cpufreq_stats-Support-runtime-changes-to-frequency-t.patch +++ /dev/null @@ -1,301 +0,0 @@ -From ca40c7542f0cd0e0dfa074bd4ccefc04b8561427 Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Tue, 2 Aug 2011 10:26:09 +0200 -Subject: [PATCH 10/21] cpufreq_stats: Support runtime changes to frequency - table. - ---- - drivers/cpufreq/cpufreq_stats.c | 161 ++++++++++++++++++++------------------- - 1 files changed, 83 insertions(+), 78 deletions(-) - ---- a/drivers/cpufreq/cpufreq_stats.c -+++ b/drivers/cpufreq/cpufreq_stats.c -@@ -21,6 +21,7 @@ - #include <linux/kobject.h> - #include <linux/spinlock.h> - #include <linux/notifier.h> -+#include <linux/string.h> - #include <asm/cputime.h> - - static spinlock_t cpufreq_stats_lock; -@@ -37,7 +38,7 @@ struct cpufreq_stats { - unsigned long long last_time; - unsigned int max_state; - unsigned int state_num; -- unsigned int last_index; -+ int last_index; - cputime64_t *time_in_state; - unsigned int *freq_table; - #ifdef CONFIG_CPU_FREQ_STAT_DETAILS -@@ -60,7 +61,7 @@ static int cpufreq_stats_update(unsigned - cur_time = get_jiffies_64(); - spin_lock(&cpufreq_stats_lock); - stat = per_cpu(cpufreq_stats_table, cpu); -- if (stat->time_in_state) -+ if (stat->time_in_state && stat->last_index != -1) - stat->time_in_state[stat->last_index] = - cputime64_add(stat->time_in_state[stat->last_index], - cputime_sub(cur_time, stat->last_time)); -@@ -83,7 +84,7 @@ static ssize_t show_time_in_state(struct - ssize_t len = 0; - int i; - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); -- if (!stat) -+ if (!stat || !stat->time_in_state) - return 0; - cpufreq_stats_update(stat->cpu); - for (i = 0; i < stat->state_num; i++) { -@@ -101,7 +102,7 @@ static ssize_t show_trans_table(struct c - int i, j; - - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); -- if (!stat) -+ if (!stat || !stat->trans_table) - return 0; - cpufreq_stats_update(stat->cpu); - len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); -@@ -160,63 +161,35 @@ static struct attribute_group stats_attr - static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) - { - int index; -- for (index = 0; index < stat->max_state; index++) -- if (stat->freq_table[index] == freq) -- return index; -+ if (stat->freq_table) -+ for (index = 0; index < stat->max_state; index++) -+ if (stat->freq_table[index] == freq) -+ return index; - return -1; - } - --/* should be called late in the CPU removal sequence so that the stats -- * memory is still available in case someone tries to use it. -- */ - static void cpufreq_stats_free_table(unsigned int cpu) - { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); -+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); -+ if (policy && policy->cpu == cpu) -+ sysfs_remove_group(&policy->kobj, &stats_attr_group); - if (stat) { - kfree(stat->time_in_state); - kfree(stat); - } - per_cpu(cpufreq_stats_table, cpu) = NULL; --} -- --/* must be called early in the CPU removal sequence (before -- * cpufreq_remove_dev) so that policy is still valid. -- */ --static void cpufreq_stats_free_sysfs(unsigned int cpu) --{ -- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); -- if (policy && policy->cpu == cpu) -- sysfs_remove_group(&policy->kobj, &stats_attr_group); - if (policy) - cpufreq_cpu_put(policy); - } - --static int cpufreq_stats_create_table(struct cpufreq_policy *policy, -+static int cpufreq_stats_update_table(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table) - { -- unsigned int i, j, count = 0, ret = 0; -- struct cpufreq_stats *stat; -- struct cpufreq_policy *data; -+ unsigned int i, j, count = 0; - unsigned int alloc_size; - unsigned int cpu = policy->cpu; -- if (per_cpu(cpufreq_stats_table, cpu)) -- return -EBUSY; -- stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); -- if ((stat) == NULL) -- return -ENOMEM; -- -- data = cpufreq_cpu_get(cpu); -- if (data == NULL) { -- ret = -EINVAL; -- goto error_get_fail; -- } -- -- ret = sysfs_create_group(&data->kobj, &stats_attr_group); -- if (ret) -- goto error_out; -- -- stat->cpu = cpu; -- per_cpu(cpufreq_stats_table, cpu) = stat; -+ struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); - - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - unsigned int freq = table[i].frequency; -@@ -225,40 +198,73 @@ static int cpufreq_stats_create_table(st - count++; - } - -+ if (stat->max_state != count) { -+ stat->max_state = count; -+ kfree(stat->time_in_state); -+ stat->time_in_state = NULL; -+ } - alloc_size = count * sizeof(int) + count * sizeof(cputime64_t); -- - #ifdef CONFIG_CPU_FREQ_STAT_DETAILS - alloc_size += count * count * sizeof(int); - #endif -- stat->max_state = count; -- stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); -- if (!stat->time_in_state) { -- ret = -ENOMEM; -- goto error_out; -- } -- stat->freq_table = (unsigned int *)(stat->time_in_state + count); -- -+ if (stat->time_in_state) { -+ memset(stat->time_in_state, 0, alloc_size); -+ } else { -+ stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); -+ if (!stat->time_in_state) -+ return -ENOMEM; -+ stat->freq_table = (unsigned int *)( -+ stat->time_in_state + count); - #ifdef CONFIG_CPU_FREQ_STAT_DETAILS -- stat->trans_table = stat->freq_table + count; -+ stat->trans_table = stat->freq_table + count; - #endif -+ } -+ - j = 0; -- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { -- unsigned int freq = table[i].frequency; -- if (freq == CPUFREQ_ENTRY_INVALID) -- continue; -- if (freq_table_get_index(stat, freq) == -1) -- stat->freq_table[j++] = freq; -+ if (stat->freq_table) { -+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { -+ unsigned int freq = table[i].frequency; -+ if (freq == CPUFREQ_ENTRY_INVALID) -+ continue; -+ if (freq_table_get_index(stat, freq) == -1) -+ stat->freq_table[j++] = freq; -+ } - } - stat->state_num = j; - spin_lock(&cpufreq_stats_lock); - stat->last_time = get_jiffies_64(); - stat->last_index = freq_table_get_index(stat, policy->cur); - spin_unlock(&cpufreq_stats_lock); -+ return 0; -+} -+ -+static int cpufreq_stats_create_table(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table) -+{ -+ unsigned int ret = 0; -+ struct cpufreq_stats *stat; -+ struct cpufreq_policy *data; -+ unsigned int cpu = policy->cpu; -+ -+ stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); -+ if ((stat) == NULL) -+ return -ENOMEM; -+ -+ data = cpufreq_cpu_get(cpu); -+ if (data == NULL) { -+ ret = -EINVAL; -+ goto error_out; -+ } -+ ret = sysfs_create_group(&data->kobj, &stats_attr_group); - cpufreq_cpu_put(data); -+ if (ret) -+ goto error_out; -+ -+ stat->cpu = cpu; -+ per_cpu(cpufreq_stats_table, cpu) = stat; -+ - return 0; - error_out: -- cpufreq_cpu_put(data); --error_get_fail: - kfree(stat); - per_cpu(cpufreq_stats_table, cpu) = NULL; - return ret; -@@ -276,10 +282,12 @@ static int cpufreq_stat_notifier_policy( - table = cpufreq_frequency_get_table(cpu); - if (!table) - return 0; -- ret = cpufreq_stats_create_table(policy, table); -- if (ret) -- return ret; -- return 0; -+ if (!per_cpu(cpufreq_stats_table, cpu)) { -+ ret = cpufreq_stats_create_table(policy, table); -+ if (ret) -+ return ret; -+ } -+ return cpufreq_stats_update_table(policy, table); - } - - static int cpufreq_stat_notifier_trans(struct notifier_block *nb, -@@ -299,21 +307,23 @@ static int cpufreq_stat_notifier_trans(s - old_index = stat->last_index; - new_index = freq_table_get_index(stat, freq->new); - -- /* We can't do stat->time_in_state[-1]= .. */ -- if (old_index == -1 || new_index == -1) -- return 0; -- - cpufreq_stats_update(freq->cpu); -- - if (old_index == new_index) - return 0; - -+ if (new_index == -1) -+ return 0; -+ - spin_lock(&cpufreq_stats_lock); - stat->last_index = new_index; -+ if (old_index != -1) { - #ifdef CONFIG_CPU_FREQ_STAT_DETAILS -- stat->trans_table[old_index * stat->max_state + new_index]++; -+ if (stat->trans_table) -+ stat->trans_table[old_index * stat->max_state + -+ new_index]++; - #endif -- stat->total_trans++; -+ stat->total_trans++; -+ } - spin_unlock(&cpufreq_stats_lock); - return 0; - } -@@ -329,9 +339,6 @@ static int __cpuinit cpufreq_stat_cpu_ca - case CPU_ONLINE_FROZEN: - cpufreq_update_policy(cpu); - break; -- case CPU_DOWN_PREPARE: -- cpufreq_stats_free_sysfs(cpu); -- break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - cpufreq_stats_free_table(cpu); -@@ -340,10 +347,9 @@ static int __cpuinit cpufreq_stat_cpu_ca - return NOTIFY_OK; - } - --/* priority=1 so this will get called before cpufreq_remove_dev */ --static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { -+static struct notifier_block cpufreq_stat_cpu_notifier __refdata = -+{ - .notifier_call = cpufreq_stat_cpu_callback, -- .priority = 1, - }; - - static struct notifier_block notifier_policy_block = { -@@ -390,7 +396,6 @@ static void __exit cpufreq_stats_exit(vo - unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); - for_each_online_cpu(cpu) { - cpufreq_stats_free_table(cpu); -- cpufreq_stats_free_sysfs(cpu); - } - } - diff --git a/target/linux/xburst/patches-3.2/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch b/target/linux/xburst/patches-3.2/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch deleted file mode 100644 index 01c211ba77..0000000000 --- a/target/linux/xburst/patches-3.2/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch +++ /dev/null @@ -1,351 +0,0 @@ -From 27ff621cd9a5347efda4be502abbef13a99146ce Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Sun, 29 Aug 2010 08:11:00 +0200 -Subject: [PATCH 11/21] MIPS: JZ4740: Added setting of PLL rate and main - dividers. - -This functionality makes a cpufreq driver possible. -Squashed version of the development done in the jz-2.6.39 branch. ---- - arch/mips/jz4740/clock.c | 230 ++++++++++++++++++++++++++++++++++++++++++++-- - arch/mips/jz4740/clock.h | 4 + - 2 files changed, 224 insertions(+), 10 deletions(-) - ---- a/arch/mips/jz4740/clock.c -+++ b/arch/mips/jz4740/clock.c -@@ -1,5 +1,8 @@ - /* -+ * Copyright (c) 2006-2007, Ingenic Semiconductor Inc. - * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> -+ * Copyright (c) 2010, Ulrich Hecht <ulrich.hecht@gmail.com> -+ * Copyright (c) 2010, Maarten ter Huurne <maarten@treewalker.org> - * JZ4740 SoC clock support - * - * This program is free software; you can redistribute it and/or modify it -@@ -41,16 +44,20 @@ - #define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31) - #define JZ_CLOCK_CTRL_KO_ENABLE BIT(30) - #define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29) --#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000 - #define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22) - #define JZ_CLOCK_CTRL_PLL_HALF BIT(21) --#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000 - #define JZ_CLOCK_CTRL_UDIV_OFFSET 23 - #define JZ_CLOCK_CTRL_LDIV_OFFSET 16 - #define JZ_CLOCK_CTRL_MDIV_OFFSET 12 - #define JZ_CLOCK_CTRL_PDIV_OFFSET 8 - #define JZ_CLOCK_CTRL_HDIV_OFFSET 4 - #define JZ_CLOCK_CTRL_CDIV_OFFSET 0 -+#define JZ_CLOCK_CTRL_UDIV_MASK (0x3f << JZ_CLOCK_CTRL_UDIV_OFFSET) -+#define JZ_CLOCK_CTRL_LDIV_MASK (0x1f << JZ_CLOCK_CTRL_LDIV_OFFSET) -+#define JZ_CLOCK_CTRL_MDIV_MASK (0x0f << JZ_CLOCK_CTRL_MDIV_OFFSET) -+#define JZ_CLOCK_CTRL_PDIV_MASK (0x0f << JZ_CLOCK_CTRL_PDIV_OFFSET) -+#define JZ_CLOCK_CTRL_HDIV_MASK (0x0f << JZ_CLOCK_CTRL_HDIV_OFFSET) -+#define JZ_CLOCK_CTRL_CDIV_MASK (0x0f << JZ_CLOCK_CTRL_CDIV_OFFSET) - - #define JZ_CLOCK_GATE_UART0 BIT(0) - #define JZ_CLOCK_GATE_TCU BIT(1) -@@ -90,6 +97,7 @@ - #define JZ_CLOCK_PLL_M_OFFSET 23 - #define JZ_CLOCK_PLL_N_OFFSET 18 - #define JZ_CLOCK_PLL_OD_OFFSET 16 -+#define JZ_CLOCK_PLL_STABILIZE_OFFSET 0 - - #define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2) - #define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0) -@@ -97,10 +105,15 @@ - #define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7) - #define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6) - -+#define JZ_REG_EMC_RTCNT 0x88 -+#define JZ_REG_EMC_RTCOR 0x8C -+ - static void __iomem *jz_clock_base; - static spinlock_t jz_clock_lock; - static LIST_HEAD(jz_clocks); - -+static void __iomem *jz_emc_base; -+ - struct main_clk { - struct clk clk; - uint32_t div_offset; -@@ -204,25 +217,88 @@ static int jz_clk_ko_is_enabled(struct c - return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE); - } - -+static struct static_clk jz_clk_ext; -+ -+static unsigned long jz_clk_pll_calc_rate( -+ unsigned int in_div, unsigned int feedback, unsigned int out_div) -+{ -+ return ((jz_clk_ext.rate / in_div) * feedback) / out_div; -+} -+ -+static void jz_clk_pll_calc_dividers(unsigned long rate, -+ unsigned int *in_div, unsigned int *feedback, unsigned int *out_div) -+{ -+ unsigned int target; -+ -+ /* The frequency after the input divider must be between 1 and 15 MHz. -+ The highest divider yields the best resolution. */ -+ *in_div = jz_clk_ext.rate / 1000000; -+ if (*in_div >= 34) -+ *in_div = 33; -+ -+ /* The frequency before the output divider must be between 100 and -+ 500 MHz. The lowest target rate is more energy efficient. */ -+ if (rate < 25000000) { -+ *out_div = 4; -+ target = 25000000 * 4; -+ } else if (rate <= 50000000) { -+ *out_div = 4; -+ target = rate * 4; -+ } else if (rate <= 100000000) { -+ *out_div = 2; -+ target = rate * 2; -+ } else if (rate <= 500000000) { -+ *out_div = 1; -+ target = rate; -+ } else { -+ *out_div = 1; -+ target = 500000000; -+ } -+ -+ /* Compute the feedback divider. -+ Since the divided input is at least 1 MHz and the target frequency -+ at most 500 MHz, the feedback will be at most 500 and will therefore -+ always fit in the 9-bit register. -+ Similarly, the divided input is at most 15 MHz and the target -+ frequency at least 100 MHz, so the feedback will be at least 6 -+ where the minimum supported value is 2. */ -+ *feedback = ((target / 1000) * *in_div) / (jz_clk_ext.rate / 1000); -+} -+ -+static unsigned long jz_clk_pll_round_rate(struct clk *clk, unsigned long rate) -+{ -+ unsigned int in_div, feedback, out_div; -+ /* The PLL frequency must be a multiple of 24 MHz, since the LCD pixel -+ * clock must be exactly 12 MHz for the TV-out to work. -+ * TODO: A multiple of 12 MHz for the PLL would work if the PLL would -+ * not be divided by 2 before being passed to the set of derived -+ * clocks that includes the LCD pixel clock. -+ * TODO: Systemwide decisions like this should be made by the board -+ * support code, so add some kind of hook for that. -+ */ -+ unsigned long rate24 = (rate / 24000000) * 24000000; -+ -+ jz_clk_pll_calc_dividers(rate24, &in_div, &feedback, &out_div); -+ return jz_clk_pll_calc_rate(in_div, feedback, out_div); -+} -+ - static const int pllno[] = {1, 2, 2, 4}; - - static unsigned long jz_clk_pll_get_rate(struct clk *clk) - { - uint32_t val; -- int m; -- int n; -- int od; -+ unsigned int in_div, feedback, out_div; - - val = jz_clk_reg_read(JZ_REG_CLOCK_PLL); - - if (val & JZ_CLOCK_PLL_BYPASS) - return clk_get_rate(clk->parent); - -- m = ((val >> 23) & 0x1ff) + 2; -- n = ((val >> 18) & 0x1f) + 2; -- od = (val >> 16) & 0x3; -+ feedback = ((val >> 23) & 0x1ff) + 2; -+ in_div = ((val >> 18) & 0x1f) + 2; -+ out_div = pllno[(val >> 16) & 0x3]; - -- return ((clk_get_rate(clk->parent) / n) * m) / pllno[od]; -+ return jz_clk_pll_calc_rate(in_div, feedback, out_div); - } - - static unsigned long jz_clk_pll_half_get_rate(struct clk *clk) -@@ -235,7 +311,77 @@ static unsigned long jz_clk_pll_half_get - return jz_clk_pll_get_rate(clk->parent) >> 1; - } - --static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+#define SDRAM_TREF 15625 /* Refresh period: 4096 refresh cycles/64ms */ -+ -+static void sdram_set_pll(unsigned int pllin) -+{ -+ unsigned int ns, sdramclock; -+ -+ ns = 1000000000 / pllin; -+ sdramclock = (SDRAM_TREF / ns) / 64 + 1; -+ if (sdramclock > 0xff) sdramclock = 0xff; -+ /* Set refresh registers */ -+ writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCOR); -+ writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCNT); -+} -+ -+static int jz_clk_pll_set_rate(struct clk *clk, unsigned long rate) -+{ -+ unsigned int ctrl, plcr1; -+ unsigned int feedback, in_div, out_div, pllout, pllout2; -+ -+ jz_clk_pll_calc_dividers(rate, &in_div, &feedback, &out_div); -+ -+ ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); -+ pllout = jz_clk_pll_calc_rate(in_div, feedback, out_div); -+ pllout2 = (ctrl & JZ_CLOCK_CTRL_PLL_HALF) ? pllout : (pllout / 2); -+ -+ /* Init UHC clock */ -+ writel(pllout2 / 48000000 - 1, jz_clock_base + JZ_REG_CLOCK_UHC); -+ -+ plcr1 = ((feedback - 2) << JZ_CLOCK_PLL_M_OFFSET) | -+ ((in_div - 2) << JZ_CLOCK_PLL_N_OFFSET) | -+ ((out_div - 1) << JZ_CLOCK_PLL_OD_OFFSET) | -+ (0x20 << JZ_CLOCK_PLL_STABILIZE_OFFSET) | -+ JZ_CLOCK_PLL_ENABLED; -+ -+ sdram_set_pll(pllout); -+ -+ /* LCD pixclock */ -+ writel(pllout2 / 12000000 - 1, jz_clock_base + JZ_REG_CLOCK_LCD); -+ -+ /* configure PLL */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (jz_clock_base + JZ_REG_CLOCK_PLL), "r" (plcr1)); -+ -+ /* MtH: For some reason the MSC will have problems if this flag is not -+ restored, even though the MSC is supposedly the only divider -+ that is not affected by this flag. */ -+ jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_CHANGE_ENABLE); -+ -+ return 0; -+} -+ -+static const unsigned int jz_clk_main_divs[] = { -+ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 -+}; -+static const unsigned int jz_clk_main_divs_inv[] = { -+ -1, 0, 1, 2, 3, -1, 4, -1, 5, -1, -1, -1, 6, -1, -1, -1, -+ 7, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, -+ 9 -+}; - - static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate) - { -@@ -290,6 +436,64 @@ static int jz_clk_main_set_rate(struct c - return 0; - } - -+static struct main_clk jz_clk_cpu; -+ -+int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv, -+ unsigned int mdiv, unsigned int pdiv) -+{ -+ unsigned int cdiv_enc, hdiv_enc, mdiv_enc, pdiv_enc; -+ unsigned int ctrl; -+ unsigned int tmp, wait; -+ -+ if (cdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || -+ hdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || -+ mdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || -+ pdiv >= ARRAY_SIZE(jz_clk_main_divs_inv)) -+ return -EINVAL; -+ cdiv_enc = jz_clk_main_divs_inv[cdiv]; -+ hdiv_enc = jz_clk_main_divs_inv[hdiv]; -+ mdiv_enc = jz_clk_main_divs_inv[mdiv]; -+ pdiv_enc = jz_clk_main_divs_inv[pdiv]; -+ if (cdiv_enc == (unsigned int)-1 || -+ hdiv_enc == (unsigned int)-1 || -+ mdiv_enc == (unsigned int)-1 || -+ pdiv_enc == (unsigned int)-1) -+ return -EINVAL; -+ -+ ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); -+ ctrl &= ~(JZ_CLOCK_CTRL_CHANGE_ENABLE | -+ JZ_CLOCK_CTRL_CDIV_MASK | JZ_CLOCK_CTRL_HDIV_MASK | -+ JZ_CLOCK_CTRL_MDIV_MASK | JZ_CLOCK_CTRL_PDIV_MASK); -+ if (immediate) ctrl |= JZ_CLOCK_CTRL_CHANGE_ENABLE; -+ ctrl |= (cdiv_enc << JZ_CLOCK_CTRL_CDIV_OFFSET) | -+ (hdiv_enc << JZ_CLOCK_CTRL_HDIV_OFFSET) | -+ (mdiv_enc << JZ_CLOCK_CTRL_MDIV_OFFSET) | -+ (pdiv_enc << JZ_CLOCK_CTRL_PDIV_OFFSET); -+ -+ /* set dividers */ -+ /* delay loops lifted from the old Ingenic cpufreq driver */ -+ wait = ((clk_get_rate(&jz_clk_cpu.clk) / 1000000) * 500) / 1000; -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %2,0(%1)\n\t" -+ "li %0,0\n\t" -+ "1:\n\t" -+ "bne %0,%3,1b\n\t" -+ "addi %0, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : "=r" (tmp) -+ : "r" (jz_clock_base + JZ_REG_CLOCK_CTRL), "r" (ctrl), -+ "r" (wait)); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(clk_main_set_dividers); -+ - static struct clk_ops jz_clk_static_ops = { - .get_rate = jz_clk_static_get_rate, - .enable = jz_clk_enable_gating, -@@ -307,6 +511,8 @@ static struct static_clk jz_clk_ext = { - - static struct clk_ops jz_clk_pll_ops = { - .get_rate = jz_clk_pll_get_rate, -+ .set_rate = jz_clk_pll_set_rate, -+ .round_rate = jz_clk_pll_round_rate, - }; - - static struct clk jz_clk_pll = { -@@ -897,6 +1103,10 @@ static int jz4740_clock_init(void) - if (!jz_clock_base) - return -EBUSY; - -+ jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100); -+ if (!jz_emc_base) -+ return -EBUSY; -+ - spin_lock_init(&jz_clock_lock); - - jz_clk_ext.rate = jz4740_clock_bdata.ext_rate; ---- a/arch/mips/jz4740/clock.h -+++ b/arch/mips/jz4740/clock.h -@@ -17,6 +17,7 @@ - #define __MIPS_JZ4740_CLOCK_H__ - - #include <linux/list.h> -+#include <linux/types.h> - - struct jz4740_clock_board_data { - unsigned long ext_rate; -@@ -63,6 +64,9 @@ struct clk { - - int clk_is_enabled(struct clk *clk); - -+int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv, -+ unsigned int mdiv, unsigned int pdiv); -+ - #ifdef CONFIG_DEBUG_FS - void jz4740_clock_debugfs_init(void); - void jz4740_clock_debugfs_add_clk(struct clk *clk); diff --git a/target/linux/xburst/patches-3.2/0012-MIPS-JZ4740-Add-cpufreq-support.patch b/target/linux/xburst/patches-3.2/0012-MIPS-JZ4740-Add-cpufreq-support.patch deleted file mode 100644 index 48ec0ca741..0000000000 --- a/target/linux/xburst/patches-3.2/0012-MIPS-JZ4740-Add-cpufreq-support.patch +++ /dev/null @@ -1,298 +0,0 @@ -From d0f0d5739a31c12d349980ed05a670fa1e84696d Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Wed, 16 Mar 2011 03:16:04 +0100 -Subject: [PATCH 12/21] MIPS: JZ4740: Add cpufreq support. - -This is a squashed version of Uli's driver that was further developed in the opendingux-kernel repository. ---- - arch/mips/Kconfig | 1 + - arch/mips/jz4740/Makefile | 1 + - arch/mips/jz4740/cpufreq.c | 226 ++++++++++++++++++++++++++++++++++++++ - arch/mips/kernel/cpufreq/Kconfig | 13 ++- - 4 files changed, 240 insertions(+), 1 deletions(-) - create mode 100644 arch/mips/jz4740/cpufreq.c - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -209,6 +209,7 @@ config MACH_JZ4740 - select HAVE_PWM - select HAVE_CLK - select GENERIC_IRQ_CHIP -+ select CPU_SUPPORTS_CPUFREQ - - config LANTIQ - bool "Lantiq based platforms" ---- a/arch/mips/jz4740/Makefile -+++ b/arch/mips/jz4740/Makefile -@@ -16,5 +16,6 @@ obj-$(CONFIG_JZ4740_QI_LB60) += board-qi - # PM support - - obj-$(CONFIG_PM) += pm.o -+obj-$(CONFIG_CPU_FREQ_JZ) += cpufreq.o - - ccflags-y := -Werror -Wall ---- /dev/null -+++ b/arch/mips/jz4740/cpufreq.c -@@ -0,0 +1,226 @@ -+/* -+ * linux/arch/mips/jz4740/cpufreq.c -+ * -+ * cpufreq driver for JZ4740 -+ * -+ * Copyright (c) 2010 Ulrich Hecht <ulrich.hecht@gmail.com> -+ * Copyright (c) 2010 Maarten ter Huurne <maarten@treewalker.org> -+ * -+ * 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/module.h> -+#include <linux/init.h> -+#include <linux/err.h> -+ -+#include <linux/cpufreq.h> -+ -+#include <linux/clk.h> -+#include <asm/mach-jz4740/base.h> -+ -+#include "clock.h" -+ -+#define DEBUG_CPUFREQ -+ -+#ifdef DEBUG_CPUFREQ -+#define dprintk(X...) printk(KERN_INFO X) -+#else -+#define dprintk(X...) do { } while(0) -+#endif -+ -+#define HCLK_MIN 30000 -+/* TODO: The maximum MCLK most likely depends on the SDRAM chips used, -+ so it is board-specific. */ -+#define MCLK_MAX 140000 -+ -+/* Same as jz_clk_main_divs, but with 24 and 32 removed because the hardware -+ spec states those dividers must not be used for CCLK or HCLK. */ -+static const unsigned int jz4740_freq_cpu_divs[] = {1, 2, 3, 4, 6, 8, 12, 16}; -+ -+struct jz4740_freq_percpu_info { -+ unsigned int pll_rate; -+ struct cpufreq_frequency_table table[ -+ ARRAY_SIZE(jz4740_freq_cpu_divs) + 1]; -+}; -+ -+static struct clk *pll; -+static struct clk *cclk; -+ -+static struct jz4740_freq_percpu_info jz4740_freq_info; -+ -+static struct cpufreq_driver cpufreq_jz4740_driver; -+ -+static void jz4740_freq_fill_table(struct cpufreq_policy *policy, -+ unsigned int pll_rate) -+{ -+ struct cpufreq_frequency_table *table = &jz4740_freq_info.table[0]; -+ int i; -+ -+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS -+ /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ -+ static bool init = false; -+ if (init) -+ cpufreq_frequency_table_put_attr(policy->cpu); -+ else -+ init = true; -+#endif -+ -+ jz4740_freq_info.pll_rate = pll_rate; -+ -+ for (i = 0; i < ARRAY_SIZE(jz4740_freq_cpu_divs); i++) { -+ unsigned int freq = pll_rate / jz4740_freq_cpu_divs[i]; -+ if (freq < HCLK_MIN) break; -+ table[i].index = i; -+ table[i].frequency = freq; -+ } -+ table[i].index = i; -+ table[i].frequency = CPUFREQ_TABLE_END; -+ -+ policy->min = table[i - 1].frequency; -+ policy->max = table[0].frequency; -+ -+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS -+ cpufreq_frequency_table_get_attr(table, policy->cpu); -+#endif -+} -+ -+static unsigned int jz4740_freq_get(unsigned int cpu) -+{ -+ return clk_get_rate(cclk) / 1000; -+} -+ -+static int jz4740_freq_verify(struct cpufreq_policy *policy) -+{ -+ unsigned int new_pll; -+ -+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, -+ policy->cpuinfo.max_freq); -+ -+ new_pll = clk_round_rate(pll, policy->max * 1000) / 1000; -+ if (jz4740_freq_info.pll_rate != new_pll) -+ jz4740_freq_fill_table(policy, new_pll); -+ -+ return 0; -+} -+ -+static int jz4740_freq_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ struct cpufreq_frequency_table *table = &jz4740_freq_info.table[0]; -+ struct cpufreq_freqs freqs; -+ unsigned int new_index = 0; -+ unsigned int old_pll = clk_get_rate(pll) / 1000; -+ unsigned int new_pll = jz4740_freq_info.pll_rate; -+ int ret = 0; -+ -+ if (cpufreq_frequency_table_target(policy, table, -+ target_freq, relation, &new_index)) -+ return -EINVAL; -+ freqs = (struct cpufreq_freqs) { -+ .old = jz4740_freq_get(policy->cpu), -+ .new = table[new_index].frequency, -+ .cpu = policy->cpu, -+ .flags = cpufreq_jz4740_driver.flags, -+ }; -+ if (freqs.new != freqs.old || new_pll != old_pll) { -+ unsigned int cdiv, hdiv, mdiv, pdiv; -+ cdiv = jz4740_freq_cpu_divs[new_index]; -+ hdiv = (cdiv == 3 || cdiv == 6) ? cdiv * 2 : cdiv * 3; -+ while (new_pll < HCLK_MIN * hdiv) -+ hdiv -= cdiv; -+ mdiv = hdiv; -+ if (new_pll > MCLK_MAX * mdiv) { -+ /* 4,4 performs better than 3,6 */ -+ if (new_pll > MCLK_MAX * 4) -+ mdiv *= 2; -+ else -+ hdiv = mdiv = cdiv * 4; -+ } -+ pdiv = mdiv; -+ dprintk(KERN_INFO "%s: cclk %p, setting from %d to %d, " -+ "dividers %d, %d, %d, %d\n", -+ __FUNCTION__, cclk, freqs.old, freqs.new, -+ cdiv, hdiv, mdiv, pdiv); -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ ret = clk_main_set_dividers(new_pll == old_pll, -+ cdiv, hdiv, mdiv, pdiv); -+ if (ret) { -+ dprintk(KERN_INFO "failed to set dividers\n"); -+ } else if (new_pll != old_pll) { -+ dprintk(KERN_INFO "%s: pll %p, setting from %d to %d\n", -+ __FUNCTION__, pll, old_pll, new_pll); -+ ret = clk_set_rate(pll, new_pll * 1000); -+ } -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+ } -+ -+ return ret; -+} -+ -+static int jz4740_cpufreq_driver_init(struct cpufreq_policy *policy) -+{ -+ int ret; -+ -+ dprintk(KERN_INFO "Jz4740 cpufreq driver\n"); -+ -+ if (policy->cpu != 0) -+ return -EINVAL; -+ -+ pll = clk_get(NULL, "pll"); -+ if (IS_ERR(pll)) { -+ ret = PTR_ERR(pll); -+ goto err_exit; -+ } -+ -+ cclk = clk_get(NULL, "cclk"); -+ if (IS_ERR(cclk)) { -+ ret = PTR_ERR(cclk); -+ goto err_clk_put_pll; -+ } -+ -+ policy->cpuinfo.min_freq = HCLK_MIN; -+ policy->cpuinfo.max_freq = 500000; -+ policy->cpuinfo.transition_latency = 100000; /* in nanoseconds */ -+ policy->cur = jz4740_freq_get(policy->cpu); -+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; -+ /* min and max are set by jz4740_freq_fill_table() */ -+ -+ jz4740_freq_fill_table(policy, clk_get_rate(pll) / 1000 /* in kHz */); -+ -+ return 0; -+ -+err_clk_put_pll: -+ clk_put(pll); -+err_exit: -+ return ret; -+} -+ -+static struct cpufreq_driver cpufreq_jz4740_driver = { -+ .init = jz4740_cpufreq_driver_init, -+ .verify = jz4740_freq_verify, -+ .target = jz4740_freq_target, -+ .get = jz4740_freq_get, -+ .name = "jz4740", -+}; -+ -+static int __init jz4740_cpufreq_init(void) -+{ -+ return cpufreq_register_driver(&cpufreq_jz4740_driver); -+} -+ -+static void __exit jz4740_cpufreq_exit(void) -+{ -+ cpufreq_unregister_driver(&cpufreq_jz4740_driver); -+} -+ -+module_init(jz4740_cpufreq_init); -+module_exit(jz4740_cpufreq_exit); -+ -+MODULE_AUTHOR("Ulrich Hecht <ulrich.hecht@gmail.com>, " -+ "Maarten ter Huurne <maarten@treewalker.org>"); -+MODULE_DESCRIPTION("cpufreq driver for Jz4740"); -+MODULE_LICENSE("GPL"); ---- a/arch/mips/kernel/cpufreq/Kconfig -+++ b/arch/mips/kernel/cpufreq/Kconfig -@@ -8,7 +8,7 @@ config MIPS_EXTERNAL_TIMER - config MIPS_CPUFREQ - bool - default y -- depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER -+ depends on CPU_SUPPORTS_CPUFREQ - - if MIPS_CPUFREQ - -@@ -24,6 +24,7 @@ config LOONGSON2_CPUFREQ - tristate "Loongson2 CPUFreq Driver" - select CPU_FREQ_TABLE - depends on MIPS_CPUFREQ -+ depends on MIPS_EXTERNAL_TIMER - help - This option adds a CPUFreq driver for loongson processors which - support software configurable cpu frequency. -@@ -34,6 +35,16 @@ config LOONGSON2_CPUFREQ - - If in doubt, say N. - -+config CPU_FREQ_JZ -+ tristate "CPUfreq driver for JZ CPUs" -+ select CPU_FREQ_TABLE -+ depends on MACH_JZ4740 -+ default n -+ help -+ This enables the CPUfreq driver for JZ CPUs. -+ -+ If in doubt, say N. -+ - endif # CPU_FREQ - - endmenu diff --git a/target/linux/xburst/patches-3.2/0013-MMC-JZ4740-Added-support-for-CPU-frequency-changing.patch b/target/linux/xburst/patches-3.2/0013-MMC-JZ4740-Added-support-for-CPU-frequency-changing.patch deleted file mode 100644 index f42d67a6fa..0000000000 --- a/target/linux/xburst/patches-3.2/0013-MMC-JZ4740-Added-support-for-CPU-frequency-changing.patch +++ /dev/null @@ -1,129 +0,0 @@ -From b95144c1b702f98c7902c75beb83f323701eb7c5 Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Sun, 19 Jun 2011 10:57:18 +0200 -Subject: [PATCH 13/21] MMC: JZ4740: Added support for CPU frequency changing. - -The MSC device clock is stopped before the frequency change. -After the change a new divider is computed and the clock is restarted. -Also the frequency change is postponed if an I/O operation is in progress. ---- - drivers/mmc/host/jz4740_mmc.c | 69 +++++++++++++++++++++++++++++++++++++++- - 1 files changed, 67 insertions(+), 2 deletions(-) - ---- a/drivers/mmc/host/jz4740_mmc.c -+++ b/drivers/mmc/host/jz4740_mmc.c -@@ -23,6 +23,7 @@ - #include <linux/delay.h> - #include <linux/scatterlist.h> - #include <linux/clk.h> -+#include <linux/cpufreq.h> - - #include <linux/bitops.h> - #include <linux/gpio.h> -@@ -685,6 +686,60 @@ static void jz4740_mmc_enable_sdio_irq(s - jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); - } - -+#ifdef CONFIG_CPU_FREQ -+ -+static struct jz4740_mmc_host *cpufreq_host; -+ -+static int jz4740_mmc_cpufreq_transition(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ /* TODO: We only have to take action when the PLL freq changes: -+ the main dividers have no influence on the MSC device clock. */ -+ -+ if (val == CPUFREQ_PRECHANGE) { -+ mmc_claim_host(cpufreq_host->mmc); -+ clk_disable(cpufreq_host->clk); -+ } else if (val == CPUFREQ_POSTCHANGE) { -+ struct mmc_ios *ios = &cpufreq_host->mmc->ios; -+ if (ios->clock) -+ jz4740_mmc_set_clock_rate(cpufreq_host, ios->clock); -+ if (ios->power_mode != MMC_POWER_OFF) -+ clk_enable(cpufreq_host->clk); -+ mmc_release_host(cpufreq_host->mmc); -+ } -+ return 0; -+} -+ -+static struct notifier_block jz4740_mmc_cpufreq_nb = { -+ .notifier_call = jz4740_mmc_cpufreq_transition, -+}; -+ -+static inline int jz4740_mmc_cpufreq_register(struct jz4740_mmc_host *host) -+{ -+ cpufreq_host = host; -+ return cpufreq_register_notifier(&jz4740_mmc_cpufreq_nb, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+static inline void jz4740_mmc_cpufreq_unregister(void) -+{ -+ cpufreq_unregister_notifier(&jz4740_mmc_cpufreq_nb, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+#else -+ -+static inline int jz4740_mmc_cpufreq_register(struct jz4740_mmc_host *host) -+{ -+ return 0; -+} -+ -+static inline void jz4740_mmc_cpufreq_unregister(void) -+{ -+} -+ -+#endif -+ - static const struct mmc_host_ops jz4740_mmc_ops = { - .request = jz4740_mmc_request, - .set_ios = jz4740_mmc_set_ios, -@@ -834,11 +889,18 @@ static int __devinit jz4740_mmc_probe(st - goto err_free_host; - } - -+ ret = jz4740_mmc_cpufreq_register(host); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "Failed to register cpufreq transition notifier\n"); -+ goto err_clk_put; -+ } -+ - host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!host->mem) { - ret = -ENOENT; - dev_err(&pdev->dev, "Failed to get base platform memory\n"); -- goto err_clk_put; -+ goto err_cpufreq_unreg; - } - - host->mem = request_mem_region(host->mem->start, -@@ -846,7 +908,7 @@ static int __devinit jz4740_mmc_probe(st - if (!host->mem) { - ret = -EBUSY; - dev_err(&pdev->dev, "Failed to request base memory region\n"); -- goto err_clk_put; -+ goto err_cpufreq_unreg; - } - - host->base = ioremap_nocache(host->mem->start, resource_size(host->mem)); -@@ -929,6 +991,8 @@ err_iounmap: - iounmap(host->base); - err_release_mem_region: - release_mem_region(host->mem->start, resource_size(host->mem)); -+err_cpufreq_unreg: -+ jz4740_mmc_cpufreq_unregister(); - err_clk_put: - clk_put(host->clk); - err_free_host: -@@ -958,6 +1022,7 @@ static int __devexit jz4740_mmc_remove(s - iounmap(host->base); - release_mem_region(host->mem->start, resource_size(host->mem)); - -+ jz4740_mmc_cpufreq_unregister(); - clk_put(host->clk); - - platform_set_drvdata(pdev, NULL); diff --git a/target/linux/xburst/patches-3.2/0014-MIPS-JZ4740-reset-Initialize-hibernate-wakeup-counte.patch b/target/linux/xburst/patches-3.2/0014-MIPS-JZ4740-reset-Initialize-hibernate-wakeup-counte.patch deleted file mode 100644 index b4e484321f..0000000000 --- a/target/linux/xburst/patches-3.2/0014-MIPS-JZ4740-reset-Initialize-hibernate-wakeup-counte.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 2dcb0ca66d0bffc23d5f001fad81fb1a7a2c371b Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Tue, 28 Jun 2011 22:28:59 +0200 -Subject: [PATCH 14/21] MIPS: JZ4740: reset: Initialize hibernate wakeup - counters. - -In hibernation mode only the wakeup logic and the RTC are left running, -so this is what users perceive as power down. - -If the counters are not initialized, the corresponding pin (typically -connected to the power button) has to be asserted for two seconds -before the device wakes up. Most users expect a shorter wakeup time. - -I took the timing values of 100 ms and 60 ms from BouKiCHi's patch for -the Dingoo A320 kernel. ---- - arch/mips/jz4740/reset.c | 46 ++++++++++++++++++++++++++++++++++++++++------ - 1 files changed, 40 insertions(+), 6 deletions(-) - ---- a/arch/mips/jz4740/reset.c -+++ b/arch/mips/jz4740/reset.c -@@ -21,6 +21,9 @@ - #include <asm/mach-jz4740/base.h> - #include <asm/mach-jz4740/timer.h> - -+#include "reset.h" -+#include "clock.h" -+ - static void jz4740_halt(void) - { - while (1) { -@@ -53,21 +56,52 @@ static void jz4740_restart(char *command - jz4740_halt(); - } - --#define JZ_REG_RTC_CTRL 0x00 --#define JZ_REG_RTC_HIBERNATE 0x20 -- --#define JZ_RTC_CTRL_WRDY BIT(7) -+#define JZ_REG_RTC_CTRL 0x00 -+#define JZ_REG_RTC_HIBERNATE 0x20 -+#define JZ_REG_RTC_WAKEUP_FILTER 0x24 -+#define JZ_REG_RTC_RESET_COUNTER 0x28 -+ -+#define JZ_RTC_CTRL_WRDY BIT(7) -+#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 -+#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 - --static void jz4740_power_off(void) -+static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base) - { -- void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24); - uint32_t ctrl; -- - do { - ctrl = readl(rtc_base + JZ_REG_RTC_CTRL); - } while (!(ctrl & JZ_RTC_CTRL_WRDY)); -+} - -+static void jz4740_power_off(void) -+{ -+ void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38); -+ unsigned long long wakeup_filter_ticks; -+ unsigned long long reset_counter_ticks; -+ -+ /* Set minimum wakeup pin assertion time: 100 ms. -+ Range is 0 to 2 sec if RTC is clocked at 32 kHz. */ -+ wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000; -+ if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) -+ wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; -+ else -+ wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; -+ jz4740_rtc_wait_ready(rtc_base); -+ writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER); -+ -+ /* Set reset pin low-level assertion time after wakeup: 60 ms. -+ Range is 0 to 125 ms if RTC is clocked at 32 kHz. */ -+ reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000; -+ if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) -+ reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; -+ else -+ reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; -+ jz4740_rtc_wait_ready(rtc_base); -+ writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER); -+ -+ jz4740_rtc_wait_ready(rtc_base); - writel(1, rtc_base + JZ_REG_RTC_HIBERNATE); -+ - jz4740_halt(); - } - diff --git a/target/linux/xburst/patches-3.2/0015-ASoC-JZ4740-Replaced-comma-operators-with-semicolons.patch b/target/linux/xburst/patches-3.2/0015-ASoC-JZ4740-Replaced-comma-operators-with-semicolons.patch deleted file mode 100644 index 9e812e1ca6..0000000000 --- a/target/linux/xburst/patches-3.2/0015-ASoC-JZ4740-Replaced-comma-operators-with-semicolons.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 515f8006c03e1065bf98c9148a9ea787e2d120d3 Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Wed, 10 Aug 2011 00:20:16 +0200 -Subject: [PATCH 15/21] ASoC: JZ4740: Replaced comma operators with - semicolons. - -They were harmless but also unnecessary, probably a leftover from earlier code. ---- - sound/soc/jz4740/jz4740-i2s.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - ---- a/sound/soc/jz4740/jz4740-i2s.c -+++ b/sound/soc/jz4740/jz4740-i2s.c -@@ -346,7 +346,7 @@ static void jz4740_i2c_init_pcm_config(s - - /* Playback */ - dma_config = &i2s->pcm_config_playback.dma_config; -- dma_config->src_width = JZ4740_DMA_WIDTH_32BIT, -+ dma_config->src_width = JZ4740_DMA_WIDTH_32BIT; - dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; - dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT; - dma_config->flags = JZ4740_DMA_SRC_AUTOINC; -@@ -355,7 +355,7 @@ static void jz4740_i2c_init_pcm_config(s - - /* Capture */ - dma_config = &i2s->pcm_config_capture.dma_config; -- dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT, -+ dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT; - dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; - dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE; - dma_config->flags = JZ4740_DMA_DST_AUTOINC; diff --git a/target/linux/xburst/patches-3.2/0016-ASoC-JZ4740-Support-buffer-size-that-is-not-a-multip.patch b/target/linux/xburst/patches-3.2/0016-ASoC-JZ4740-Support-buffer-size-that-is-not-a-multip.patch deleted file mode 100644 index 552f811d6b..0000000000 --- a/target/linux/xburst/patches-3.2/0016-ASoC-JZ4740-Support-buffer-size-that-is-not-a-multip.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 8a5087fe59e31efb8641e704058328997c3c8ff1 Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Wed, 10 Aug 2011 00:25:11 +0200 -Subject: [PATCH 16/21] ASoC: JZ4740: Support buffer size that is not a - multiple of period size. - -This fixes glitches triggered by libao, which sets time-based intervals -instead of byte-based intervals like SDL does. - -Thanks to Paul Cercueil for figuring out that the buffer size was causing -the glitches and to Lars Clausen for helping me write the fix. ---- - sound/soc/jz4740/jz4740-pcm.c | 21 ++++++++++++++++++--- - 1 files changed, 18 insertions(+), 3 deletions(-) - ---- a/sound/soc/jz4740/jz4740-pcm.c -+++ b/sound/soc/jz4740/jz4740-pcm.c -@@ -31,6 +31,7 @@ - - struct jz4740_runtime_data { - unsigned long dma_period; -+ unsigned long dma_period_left; - dma_addr_t dma_start; - dma_addr_t dma_pos; - dma_addr_t dma_end; -@@ -67,10 +68,13 @@ static void jz4740_pcm_start_transfer(st - if (prtd->dma_pos == prtd->dma_end) - prtd->dma_pos = prtd->dma_start; - -- if (prtd->dma_pos + prtd->dma_period > prtd->dma_end) -+ if (prtd->dma_period_left == 0) -+ prtd->dma_period_left = prtd->dma_period; -+ -+ if (prtd->dma_pos + prtd->dma_period_left > prtd->dma_end) - count = prtd->dma_end - prtd->dma_pos; - else -- count = prtd->dma_period; -+ count = prtd->dma_period_left; - - jz4740_dma_disable(prtd->dma); - -@@ -85,6 +89,7 @@ static void jz4740_pcm_start_transfer(st - jz4740_dma_set_transfer_count(prtd->dma, count); - - prtd->dma_pos += count; -+ prtd->dma_period_left -= count; - - jz4740_dma_enable(prtd->dma); - } -@@ -96,7 +101,8 @@ static void jz4740_pcm_dma_transfer_done - struct snd_pcm_runtime *runtime = substream->runtime; - struct jz4740_runtime_data *prtd = runtime->private_data; - -- snd_pcm_period_elapsed(substream); -+ if (prtd->dma_period_left == 0) -+ snd_pcm_period_elapsed(substream); - - jz4740_pcm_start_transfer(prtd, substream); - } -@@ -133,6 +139,7 @@ static int jz4740_pcm_hw_params(struct s - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->dma_period = params_period_bytes(params); -+ prtd->dma_period_left = 0; - prtd->dma_start = runtime->dma_addr; - prtd->dma_pos = prtd->dma_start; - prtd->dma_end = prtd->dma_start + runtime->dma_bytes; -@@ -160,6 +167,7 @@ static int jz4740_pcm_prepare(struct snd - if (!prtd->dma) - return -EBUSY; - -+ prtd->dma_period_left = 0; - prtd->dma_pos = prtd->dma_start; - - return 0; -@@ -219,6 +227,13 @@ static int jz4740_pcm_open(struct snd_pc - if (prtd == NULL) - return -ENOMEM; - -+ /* Force period and buffer size to be a multiple of the DMA transfer -+ * size, which is 16 bytes. */ -+ snd_pcm_hw_constraint_step(runtime, 0, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); -+ snd_pcm_hw_constraint_step(runtime, 0, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); -+ - snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware); - - runtime->private_data = prtd; diff --git a/target/linux/xburst/patches-3.2/0017-MIPS-JZ4740-qi_lb60-Look-for-NAND-chip-in-bank-1.patch b/target/linux/xburst/patches-3.2/0017-MIPS-JZ4740-qi_lb60-Look-for-NAND-chip-in-bank-1.patch deleted file mode 100644 index f6b11540af..0000000000 --- a/target/linux/xburst/patches-3.2/0017-MIPS-JZ4740-qi_lb60-Look-for-NAND-chip-in-bank-1.patch +++ /dev/null @@ -1,21 +0,0 @@ -From cdb15b56aa9517a8cdbd14724088227514622a1b Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Wed, 11 Jan 2012 22:36:03 +0100 -Subject: [PATCH 17/21] MIPS: JZ4740: qi_lb60: Look for NAND chip in bank 1. - -All NanoNotes have their NAND in bank 1. -Specifying the bank is required since commit e7ca5a665877a030. ---- - arch/mips/jz4740/board-qi_lb60.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - ---- a/arch/mips/jz4740/board-qi_lb60.c -+++ b/arch/mips/jz4740/board-qi_lb60.c -@@ -140,6 +140,7 @@ static void qi_lb60_nand_ident(struct pl - static struct jz_nand_platform_data qi_lb60_nand_pdata = { - .ident_callback = qi_lb60_nand_ident, - .busy_gpio = 94, -+ .banks = { 1 }, - }; - - /* Keyboard*/ diff --git a/target/linux/xburst/patches-3.2/0018-ASoC-jz4740-Convert-qi_lb60-to-use-snd_soc_register_.patch b/target/linux/xburst/patches-3.2/0018-ASoC-jz4740-Convert-qi_lb60-to-use-snd_soc_register_.patch deleted file mode 100644 index 52962ad836..0000000000 --- a/target/linux/xburst/patches-3.2/0018-ASoC-jz4740-Convert-qi_lb60-to-use-snd_soc_register_.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 94f2b91d2a42854a8869d54a758bc88757d7f6d9 Mon Sep 17 00:00:00 2001 -From: Axel Lin <axel.lin@gmail.com> -Date: Fri, 6 Jan 2012 11:30:10 +0800 -Subject: [PATCH 18/21] ASoC: jz4740: Convert qi_lb60 to use - snd_soc_register_card() - -Use snd_soc_register_card() instead of creating a "soc-audio" platform device. - -Signed-off-by: Axel Lin <axel.lin@gmail.com> ---- - arch/mips/jz4740/board-qi_lb60.c | 6 ++++ - sound/soc/jz4740/qi_lb60.c | 56 +++++++++++++++++-------------------- - 2 files changed, 32 insertions(+), 30 deletions(-) - ---- a/arch/mips/jz4740/board-qi_lb60.c -+++ b/arch/mips/jz4740/board-qi_lb60.c -@@ -418,6 +418,11 @@ static struct platform_device qi_lb60_ch - }, - }; - -+/* audio */ -+static struct platform_device qi_lb60_audio_device = { -+ .name = "qi-lb60-audio", -+ .id = -1, -+}; - - static struct platform_device *jz_platform_devices[] __initdata = { - &jz4740_udc_device, -@@ -434,6 +439,7 @@ static struct platform_device *jz_platfo - &qi_lb60_gpio_keys, - &qi_lb60_pwm_beeper, - &qi_lb60_charger_device, -+ &qi_lb60_audio_device, - }; - - static void __init board_gpio_setup(void) ---- a/sound/soc/jz4740/qi_lb60.c -+++ b/sound/soc/jz4740/qi_lb60.c -@@ -90,56 +90,52 @@ static struct snd_soc_card qi_lb60 = { - .num_dapm_routes = ARRAY_SIZE(qi_lb60_routes), - }; - --static struct platform_device *qi_lb60_snd_device; -- - static const struct gpio qi_lb60_gpios[] = { - { QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" }, - { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" }, - }; - --static int __init qi_lb60_init(void) -+static int __devinit qi_lb60_probe(struct platform_device *pdev) - { -+ struct snd_soc_card *card = &qi_lb60; - int ret; - -- qi_lb60_snd_device = platform_device_alloc("soc-audio", -1); -- -- if (!qi_lb60_snd_device) -- return -ENOMEM; -- - ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); -- if (ret) { -- pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret); -- goto err_device_put; -- } -+ if (ret) -+ return ret; - -- platform_set_drvdata(qi_lb60_snd_device, &qi_lb60); -+ card->dev = &pdev->dev; - -- ret = platform_device_add(qi_lb60_snd_device); -+ ret = snd_soc_register_card(card); - if (ret) { -- pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret); -- goto err_unset_pdata; -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", -+ ret); -+ gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); - } -- -- return 0; -- --err_unset_pdata: -- platform_set_drvdata(qi_lb60_snd_device, NULL); --/*err_gpio_free_array:*/ -- gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); --err_device_put: -- platform_device_put(qi_lb60_snd_device); -- - return ret; - } --module_init(qi_lb60_init); - --static void __exit qi_lb60_exit(void) -+static int __devexit qi_lb60_remove(struct platform_device *pdev) - { -- platform_device_unregister(qi_lb60_snd_device); -+ struct snd_soc_card *card = platform_get_drvdata(pdev); -+ -+ snd_soc_unregister_card(card); - gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); -+ return 0; - } --module_exit(qi_lb60_exit); -+ -+static struct platform_driver qi_lb60_driver = { -+ .driver = { -+ .name = "qi-lb60-audio", -+ .owner = THIS_MODULE, -+ }, -+ .probe = qi_lb60_probe, -+ .remove = __devexit_p(qi_lb60_remove), -+}; -+ -+module_platform_driver(qi_lb60_driver); - - MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); - MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support"); - MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:qi-lb60-audio"); diff --git a/target/linux/xburst/patches-3.2/0019-Framebuffer-notifier-Call-notifier-callbacks-prior-t.patch b/target/linux/xburst/patches-3.2/0019-Framebuffer-notifier-Call-notifier-callbacks-prior-t.patch deleted file mode 100644 index 2709883ff1..0000000000 --- a/target/linux/xburst/patches-3.2/0019-Framebuffer-notifier-Call-notifier-callbacks-prior-t.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 159c4d81899db05a57bc4a0d55083e484c3d8a43 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sat, 24 Apr 2010 12:23:28 +0200 -Subject: [PATCH 19/21] Framebuffer notifier: Call notifier callbacks prior to - blanking the screen - ---- - drivers/video/fbmem.c | 8 ++++++-- - 1 files changed, 6 insertions(+), 2 deletions(-) - ---- a/drivers/video/fbmem.c -+++ b/drivers/video/fbmem.c -@@ -1032,12 +1032,12 @@ fb_set_var(struct fb_info *info, struct - int - fb_blank(struct fb_info *info, int blank) - { -- int ret = -EINVAL; -+ int ret = 0; - - if (blank > FB_BLANK_POWERDOWN) - blank = FB_BLANK_POWERDOWN; - -- if (info->fbops->fb_blank) -+ if (info->fbops->fb_blank && blank == FB_BLANK_UNBLANK) - ret = info->fbops->fb_blank(blank, info); - - if (!ret) { -@@ -1048,6 +1048,10 @@ fb_blank(struct fb_info *info, int blank - fb_notifier_call_chain(FB_EVENT_BLANK, &event); - } - -+ if (info->fbops->fb_blank && blank != FB_BLANK_UNBLANK) -+ ret = info->fbops->fb_blank(blank, info); -+ -+ - return ret; - } - diff --git a/target/linux/xburst/patches-3.2/0020-qi_lb60-NAND-add-data-partition.patch b/target/linux/xburst/patches-3.2/0020-qi_lb60-NAND-add-data-partition.patch deleted file mode 100644 index 9d45dd8698..0000000000 --- a/target/linux/xburst/patches-3.2/0020-qi_lb60-NAND-add-data-partition.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 1d7ef3445db5aebf48c90b20e18630633623c750 Mon Sep 17 00:00:00 2001 -From: Xiangfu Liu <xiangfu@macbook.(none)> -Date: Fri, 19 Aug 2011 15:46:52 +0800 -Subject: [PATCH 20/21] qi_lb60: NAND: add data partition - ---- - arch/mips/jz4740/board-qi_lb60.c | 7 ++++++- - 1 files changed, 6 insertions(+), 1 deletions(-) - ---- a/arch/mips/jz4740/board-qi_lb60.c -+++ b/arch/mips/jz4740/board-qi_lb60.c -@@ -118,8 +118,13 @@ static struct mtd_partition qi_lb60_part - { - .name = "NAND ROOTFS partition", - .offset = 8 * 0x100000, -- .size = (504 + 512 + 1024) * 0x100000, -+ .size = 512 * 0x100000, - }, -+ { -+ .name = "NAND DATA partition", -+ .offset = 520 * 0x100000, -+ .size = 1528 * 0x100000, -+ }, - }; - - static void qi_lb60_nand_ident(struct platform_device *pdev, diff --git a/target/linux/xburst/patches-3.2/0021-rtc-jz4740-fix-hwclock-give-time-out.patch b/target/linux/xburst/patches-3.2/0021-rtc-jz4740-fix-hwclock-give-time-out.patch deleted file mode 100644 index b68033d3bc..0000000000 --- a/target/linux/xburst/patches-3.2/0021-rtc-jz4740-fix-hwclock-give-time-out.patch +++ /dev/null @@ -1,20 +0,0 @@ -From a37ca6eb8cb52d620feff3323a3be4da24f5bee8 Mon Sep 17 00:00:00 2001 -From: Xiangfu <xiangfu@openmobilefree.net> -Date: Fri, 16 Mar 2012 17:48:45 +0800 -Subject: [PATCH 21/21] rtc: jz4740 fix hwclock give time out - ---- - drivers/rtc/rtc-jz4740.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - ---- a/drivers/rtc/rtc-jz4740.c -+++ b/drivers/rtc/rtc-jz4740.c -@@ -280,6 +280,8 @@ static int __devinit jz4740_rtc_probe(st - } - } - -+ jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ, 1); -+ - return 0; - - err_free_irq: |