diff options
Diffstat (limited to 'recipes')
15 files changed, 7691 insertions, 885 deletions
diff --git a/recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch b/recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch new file mode 100644 index 0000000000..56197a263f --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0001-DRM-for-platform-devices.patch @@ -0,0 +1,458 @@ +From 69d87612a1b545e6d4cf9fc93117be86f871f7d2 Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Sat, 22 May 2010 18:59:58 +0200 +Subject: [PATCH 01/13] DRM for platform devices + +This modifies the DRM core in a small number of places to allow platform +devices to be used for direct rendering, alongside PCI devices. + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/gpu/drm/Kconfig | 2 +- + drivers/gpu/drm/drm_bufs.c | 2 +- + drivers/gpu/drm/drm_drv.c | 27 ++++++++++ + drivers/gpu/drm/drm_info.c | 27 ++++++++-- + drivers/gpu/drm/drm_ioctl.c | 118 ++++++++++++++++++++++++++++++------------- + drivers/gpu/drm/drm_stub.c | 76 +++++++++++++++++++++++++++- + drivers/gpu/drm/drm_sysfs.c | 6 ++- + include/drm/drmP.h | 13 +++++ + 8 files changed, 224 insertions(+), 47 deletions(-) + +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index 305c590..7244cef 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -6,7 +6,7 @@ + # + menuconfig DRM + tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" +- depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU ++ depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU + select I2C + select I2C_ALGOBIT + help +diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c +index f7ba82e..30ce982 100644 +--- a/drivers/gpu/drm/drm_bufs.c ++++ b/drivers/gpu/drm/drm_bufs.c +@@ -189,7 +189,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) ++#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__) + if (map->offset + (map->size-1) < map->offset || + map->offset < virt_to_phys(high_memory)) { + kfree(map); +diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c +index 4a66201..769d12b 100644 +--- a/drivers/gpu/drm/drm_drv.c ++++ b/drivers/gpu/drm/drm_drv.c +@@ -250,6 +250,7 @@ int drm_lastclose(struct drm_device * dev) + */ + int drm_init(struct drm_driver *driver) + { ++#ifdef CONFIG_PCI + struct pci_dev *pdev = NULL; + const struct pci_device_id *pid; + int i; +@@ -283,11 +284,37 @@ int drm_init(struct drm_driver *driver) + drm_get_dev(pdev, pid, driver); + } + } ++#endif + return 0; + } + + EXPORT_SYMBOL(drm_init); + ++/** ++ * Call this to associate a drm_driver with a platform_device. ++ * ++ * \return zero on success or a negative number on failure. ++ * ++ * This is a replacement for drm_init(), but for platform drivers. ++ * In this case, the caller must provide the matching platform_device ++ * ++ * since there is no physical bus to scan through. ++ * ++ * \sa drm_init ++ * ++ */ ++int drm_platform_init(struct drm_driver *driver, struct platform_device *pdev, ++ void *priv) ++{ ++ DRM_DEBUG("\n"); ++ ++ INIT_LIST_HEAD(&driver->device_list); ++ ++ return drm_get_platform_dev(pdev, driver, priv); ++} ++ ++EXPORT_SYMBOL(drm_platform_init); ++ + void drm_exit(struct drm_driver *driver) + { + struct drm_device *dev, *tmp; +diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c +index f0f6c6b..838c2ee 100644 +--- a/drivers/gpu/drm/drm_info.c ++++ b/drivers/gpu/drm/drm_info.c +@@ -52,12 +52,28 @@ int drm_name_info(struct seq_file *m, void *data) + return 0; + + if (master->unique) { +- seq_printf(m, "%s %s %s\n", +- dev->driver->pci_driver.name, +- pci_name(dev->pdev), master->unique); ++ ++ if (drm_core_is_platform(dev)) { ++ seq_printf(m, "%s %s %s\n", ++ dev->driver->name, ++ dev_name(&dev->platform_dev->dev), ++ master->unique); ++ } else { ++ seq_printf(m, "%s %s %s\n", ++ dev->driver->pci_driver.name, ++ pci_name(dev->pdev), master->unique); ++ } ++ + } else { +- seq_printf(m, "%s %s\n", dev->driver->pci_driver.name, +- pci_name(dev->pdev)); ++ ++ if (drm_core_is_platform(dev)) { ++ seq_printf(m, "%s %s\n", dev->driver->name, ++ dev_name(&dev->platform_dev->dev)); ++ } else { ++ seq_printf(m, "%s %s\n", dev->driver->pci_driver.name, ++ pci_name(dev->pdev)); ++ } ++ + } + + return 0; +@@ -325,4 +341,3 @@ int drm_vma_info(struct seq_file *m, void *data) + } + + #endif +- +diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c +index 9b9ff46..133ef29 100644 +--- a/drivers/gpu/drm/drm_ioctl.c ++++ b/drivers/gpu/drm/drm_ioctl.c +@@ -83,7 +83,6 @@ int drm_setunique(struct drm_device *dev, void *data, + { + struct drm_unique *u = data; + struct drm_master *master = file_priv->master; +- int domain, bus, slot, func, ret; + + if (master->unique_len || master->unique) + return -EBUSY; +@@ -101,28 +100,46 @@ int drm_setunique(struct drm_device *dev, void *data, + + master->unique[master->unique_len] = '\0'; + +- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + +- strlen(master->unique) + 2, GFP_KERNEL); +- if (!dev->devname) +- return -ENOMEM; ++ if ( !drm_core_is_platform(dev) ) { + +- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, +- master->unique); ++ int domain, bus, slot, func, ret; + +- /* Return error if the busid submitted doesn't match the device's actual +- * busid. +- */ +- ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); +- if (ret != 3) +- return -EINVAL; +- domain = bus >> 8; +- bus &= 0xff; ++ /* PCI device */ ++ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + ++ strlen(master->unique) + 2, GFP_KERNEL); ++ if (!dev->devname) ++ return -ENOMEM; + +- if ((domain != drm_get_pci_domain(dev)) || +- (bus != dev->pdev->bus->number) || +- (slot != PCI_SLOT(dev->pdev->devfn)) || +- (func != PCI_FUNC(dev->pdev->devfn))) +- return -EINVAL; ++ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, ++ master->unique); ++ ++ /* Return error if the busid submitted doesn't match the ++ * device's actual busid. ++ */ ++ ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); ++ if (ret != 3) ++ return -EINVAL; ++ domain = bus >> 8; ++ bus &= 0xff; ++ ++ if ((domain != drm_get_pci_domain(dev)) || ++ (bus != dev->pdev->bus->number) || ++ (slot != PCI_SLOT(dev->pdev->devfn)) || ++ (func != PCI_FUNC(dev->pdev->devfn))) ++ return -EINVAL; ++ ++ } else { ++ ++ /* Platform device */ ++ dev->devname = kmalloc(strlen(dev->driver->name) + ++ strlen(master->unique) + 2, GFP_KERNEL); ++ if (!dev->devname) ++ return -ENOMEM; ++ ++ sprintf(dev->devname, "%s@%s", dev->driver->name, ++ master->unique); ++ ++ } + + return 0; + } +@@ -141,23 +158,52 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) + if (master->unique == NULL) + return -ENOMEM; + +- len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d", +- drm_get_pci_domain(dev), +- dev->pdev->bus->number, +- PCI_SLOT(dev->pdev->devfn), +- PCI_FUNC(dev->pdev->devfn)); +- if (len >= master->unique_len) +- DRM_ERROR("buffer overflow"); +- else +- master->unique_len = len; +- +- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + +- master->unique_len + 2, GFP_KERNEL); +- if (dev->devname == NULL) +- return -ENOMEM; ++ if ( !drm_core_is_platform(dev) ) { ++ ++ /* PCI device */ + +- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, +- master->unique); ++ len = snprintf(master->unique, master->unique_len, ++ "pci:%04x:%02x:%02x.%d", ++ drm_get_pci_domain(dev), ++ dev->pdev->bus->number, ++ PCI_SLOT(dev->pdev->devfn), ++ PCI_FUNC(dev->pdev->devfn)); ++ if (len >= master->unique_len) ++ DRM_ERROR("buffer overflow"); ++ else ++ master->unique_len = len; ++ ++ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + ++ master->unique_len + 2, GFP_KERNEL); ++ if (dev->devname == NULL) ++ return -ENOMEM; ++ ++ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, ++ master->unique); ++ ++ } else { ++ ++ /* Platform device */ ++ ++ int len; ++ ++ len = snprintf(master->unique, master->unique_len, ++ "platform:%s", dev->platform_dev->name); ++ ++ if (len >= master->unique_len) ++ DRM_ERROR("buffer overflow"); ++ else ++ master->unique_len = len; ++ ++ dev->devname = kmalloc(strlen(dev->driver->name) ++ + master->unique_len + 2, GFP_KERNEL); ++ if (dev->devname == NULL) ++ return -ENOMEM; ++ ++ sprintf(dev->devname, "%s@%s", dev->driver->name, ++ master->unique); ++ ++ } + + return 0; + } +diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c +index a0c365f..7e7eba6 100644 +--- a/drivers/gpu/drm/drm_stub.c ++++ b/drivers/gpu/drm/drm_stub.c +@@ -246,8 +246,10 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, + idr_init(&dev->drw_idr); + + dev->pdev = pdev; +- dev->pci_device = pdev->device; +- dev->pci_vendor = pdev->vendor; ++ if (pdev) { ++ dev->pci_device = pdev->device; ++ dev->pci_vendor = pdev->vendor; ++ } + + #ifdef __alpha__ + dev->hose = pdev->sysdata; +@@ -465,6 +467,76 @@ err_g1: + EXPORT_SYMBOL(drm_get_dev); + + /** ++ * ++ * Register a platform device as a DRM device ++ * ++ * \param pdev - platform device structure ++ * \param driver - the matching drm_driver structure ++ * \return zero on success or a negative number on failure. ++ * ++ * Attempt to gets inter module "drm" information. If we are first ++ * then register the character device and inter module information. ++ * Try and register, if we fail to register, backout previous work. ++ * ++ * \sa drm_get_dev ++ */ ++int drm_get_platform_dev(struct platform_device *pdev, ++ struct drm_driver *driver, void *priv) ++{ ++ struct drm_device *dev; ++ int ret; ++ DRM_DEBUG("\n"); ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ dev->dev_private = priv; ++ ++ if ((ret = drm_fill_in_dev(dev, NULL, NULL, driver))) { ++ printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); ++ goto err_g1; ++ } ++ dev->platform_dev = pdev; ++ ++ if (drm_core_check_feature(dev, DRIVER_MODESET)) { ++ ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); ++ if (ret) ++ goto err_g2; ++ } ++ ++ if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) ++ goto err_g3; ++ ++ if (dev->driver->load) { ++ ret = dev->driver->load(dev, 0); ++ if (ret) ++ goto err_g3; ++ } ++ ++ /* setup the grouping for the legacy output */ ++ if (drm_core_check_feature(dev, DRIVER_MODESET)) { ++ ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); ++ if (ret) ++ goto err_g3; ++ } ++ ++ list_add_tail(&dev->driver_item, &driver->device_list); ++ ++ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", ++ driver->name, driver->major, driver->minor, driver->patchlevel, ++ driver->date, dev->primary->index); ++ ++ return 0; ++ ++err_g3: ++ drm_put_minor(&dev->primary); ++err_g2: ++err_g1: ++ kfree(dev); ++ return ret; ++} ++ ++/** + * Put a secondary minor number. + * + * \param sec_minor - structure to be released +diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c +index 25bbd30..947e731 100644 +--- a/drivers/gpu/drm/drm_sysfs.c ++++ b/drivers/gpu/drm/drm_sysfs.c +@@ -488,7 +488,11 @@ int drm_sysfs_device_add(struct drm_minor *minor) + int err; + char *minor_str; + +- minor->kdev.parent = &minor->dev->pdev->dev; ++ if (minor->dev->pdev) { ++ minor->kdev.parent = &minor->dev->pdev->dev; ++ } else { ++ minor->kdev.parent = &minor->dev->platform_dev->dev; ++ } + minor->kdev.class = drm_class; + minor->kdev.release = drm_sysfs_device_release; + minor->kdev.devt = minor->device; +diff --git a/include/drm/drmP.h b/include/drm/drmP.h +index 2f3b3a0..43894ec 100644 +--- a/include/drm/drmP.h ++++ b/include/drm/drmP.h +@@ -56,6 +56,7 @@ + #include <linux/cdev.h> + #include <linux/mutex.h> + #include <linux/slab.h> ++#include <linux/platform_device.h> + #if defined(__alpha__) || defined(__powerpc__) + #include <asm/pgtable.h> /* For pte_wrprotect */ + #endif +@@ -144,6 +145,7 @@ extern void drm_ut_debug_printk(unsigned int request_level, + #define DRIVER_IRQ_VBL2 0x800 + #define DRIVER_GEM 0x1000 + #define DRIVER_MODESET 0x2000 ++#define DRIVER_IS_PLATFORM 0x4000 + + /***********************************************************************/ + /** \name Begin the DRM... */ +@@ -1014,6 +1016,7 @@ struct drm_device { + wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ + + struct drm_agp_head *agp; /**< AGP data */ ++ struct platform_device *platform_dev; /**< platform device structure */ + + struct pci_dev *pdev; /**< PCI device structure */ + int pci_vendor; /**< PCI vendor id */ +@@ -1124,12 +1127,20 @@ static inline int drm_mtrr_del(int handle, unsigned long offset, + } + #endif + ++static inline int drm_core_is_platform(struct drm_device *dev) ++{ ++ return drm_core_check_feature(dev, DRIVER_IS_PLATFORM); ++} ++ + /******************************************************************/ + /** \name Internal function definitions */ + /*@{*/ + + /* Driver support (drm_drv.h) */ + extern int drm_init(struct drm_driver *driver); ++extern int drm_platform_init(struct drm_driver *driver, ++ struct platform_device *pdev, ++ void *dev_private); + extern void drm_exit(struct drm_driver *driver); + extern long drm_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); +@@ -1350,6 +1361,8 @@ extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + struct drm_master *drm_master_create(struct drm_minor *minor); + extern struct drm_master *drm_master_get(struct drm_master *master); ++extern int drm_get_platform_dev(struct platform_device *pdev, ++ struct drm_driver *driver, void *priv); + extern void drm_master_put(struct drm_master **master); + extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, + struct drm_driver *driver); +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch b/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch new file mode 100644 index 0000000000..1b6964aee9 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch @@ -0,0 +1,1759 @@ +From b4c5d1702abcaef7d8af5d3dc8934b2184ba6be0 Mon Sep 17 00:00:00 2001 +From: Radek Polak <psonek2@seznam.cz> +Date: Fri, 9 Apr 2010 09:15:40 +0200 +Subject: [PATCH 1/4] accels.patch + +adds support for accelerometers. You will need include/linux/lis302dl.h and +drivers/input/misc/lis302dl.c from andy-tracking. The patch needs +spi_bitbang_transfer_sync() and bitbang_work() to be ported correctly (some +fixes from original 2.6.32 are missing). + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- + arch/arm/mach-s3c2410/include/mach/spi-gpio.h | 3 +- + arch/arm/mach-s3c2440/mach-gta02.c | 157 ++++ + drivers/input/misc/Kconfig | 9 + + drivers/input/misc/Makefile | 1 + + drivers/input/misc/lis302dl.c | 952 +++++++++++++++++++++++++ + drivers/spi/spi_bitbang.c | 231 ++++--- + drivers/spi/spi_s3c24xx_gpio.c | 7 +- + include/linux/lis302dl.h | 152 ++++ + include/linux/spi/spi.h | 30 + + include/linux/spi/spi_bitbang.h | 5 + + 10 files changed, 1433 insertions(+), 114 deletions(-) + create mode 100644 drivers/input/misc/lis302dl.c + create mode 100644 include/linux/lis302dl.h + +diff --git a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h +index dcef228..8eedc9c 100644 +--- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h ++++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h +@@ -21,7 +21,8 @@ struct s3c2410_spigpio_info { + int num_chipselect; + int bus_num; + +- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs); ++ int non_blocking_transfer; ++ void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs); + }; + + +diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c +index e8ac76b..795b9f4 100644 +--- a/arch/arm/mach-s3c2440/mach-gta02.c ++++ b/arch/arm/mach-s3c2440/mach-gta02.c +@@ -62,6 +62,7 @@ + + #include <linux/input.h> + #include <linux/gpio_keys.h> ++#include <linux/lis302dl.h> + + #include <linux/leds.h> + #include <linux/leds_pwm.h> +@@ -111,6 +112,22 @@ + #include <linux/glamofb.h> + #include <linux/mfd/glamo.h> + ++#define S3C2410_GPIONO(bank,offset) ((bank) + (offset)) ++ ++#define S3C2410_GPIO_BANKD (32*3) ++#define S3C2410_GPIO_BANKG (32*6) ++ ++#define S3C2410_GPG5 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5) ++#define S3C2410_GPG6 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6) ++#define S3C2410_GPG7 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 7) ++#define S3C2410_GPD12 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 12) ++#define S3C2410_GPD13 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 13) ++ ++#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ ++#define BITBANG_CS_INACTIVE 0 ++ ++#define S3C_SYSTEM_REV_ATAG GTA02v6_SYSTEM_REV ++ + static struct pcf50633 *gta02_pcf; + + /* +@@ -322,6 +339,60 @@ const static struct jbt6k74_platform_data jbt6k74_pdata = { + .gpio_reset = GTA02_GPIO_GLAMO(4), + }; + ++/*----------- SPI: Accelerometers attached to SPI of s3c244x ----------------- */ ++ ++void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume) ++{ ++ struct lis302dl_platform_data *pdata = lis->pdata; ++ ++ if (!resume) { ++ /* ++ * we don't want to power them with a high level ++ * because GSENSOR_3V3 is not up during suspend ++ */ ++ s3c2410_gpio_setpin(pdata->pin_chip_select, 0); ++ s3c2410_gpio_setpin(pdata->pin_clk, 0); ++ s3c2410_gpio_setpin(pdata->pin_mosi, 0); ++ /* misnomer: it is a pullDOWN in 2442 */ ++ s3c2410_gpio_pullup(pdata->pin_miso, 1); ++ return; ++ } ++ ++ /* back to normal */ ++ s3c2410_gpio_setpin(pdata->pin_chip_select, 1); ++ s3c2410_gpio_setpin(pdata->pin_clk, 1); ++ /* misnomer: it is a pullDOWN in 2442 */ ++ s3c2410_gpio_pullup(pdata->pin_miso, 0); ++ ++ s3c2410_gpio_cfgpin(pdata->pin_chip_select, S3C2410_GPIO_OUTPUT); ++ s3c2410_gpio_cfgpin(pdata->pin_clk, S3C2410_GPIO_OUTPUT); ++ s3c2410_gpio_cfgpin(pdata->pin_mosi, S3C2410_GPIO_OUTPUT); ++ s3c2410_gpio_cfgpin(pdata->pin_miso, S3C2410_GPIO_INPUT); ++ ++} ++ ++struct lis302dl_platform_data lis302_pdata_top = { ++ .name = "lis302-1 (top)", ++ .pin_chip_select= S3C2410_GPD12, ++ .pin_clk = S3C2410_GPG7, ++ .pin_mosi = S3C2410_GPG6, ++ .pin_miso = S3C2410_GPG5, ++ .interrupt = GTA02_IRQ_GSENSOR_1, ++ .open_drain = 1, /* altered at runtime by PCB rev */ ++ .lis302dl_suspend_io = gta02_lis302dl_suspend_io, ++}; ++ ++struct lis302dl_platform_data lis302_pdata_bottom = { ++ .name = "lis302-2 (bottom)", ++ .pin_chip_select= S3C2410_GPD13, ++ .pin_clk = S3C2410_GPG7, ++ .pin_mosi = S3C2410_GPG6, ++ .pin_miso = S3C2410_GPG5, ++ .interrupt = GTA02_IRQ_GSENSOR_2, ++ .open_drain = 1, /* altered at runtime by PCB rev */ ++ .lis302dl_suspend_io = gta02_lis302dl_suspend_io, ++}; ++ + static struct spi_board_info gta02_spi_board_info[] = { + { + .modalias = "jbt6k74", +@@ -332,6 +403,81 @@ static struct spi_board_info gta02_spi_board_info[] = { + .bus_num = 2, + .chip_select = 0 + }, ++ { ++ .modalias = "lis302dl", ++ /* platform_data */ ++ .platform_data = &lis302_pdata_top, ++ /* controller_data */ ++ /* irq */ ++ .max_speed_hz = 100 * 1000, ++ .bus_num = 3, ++ .chip_select = 0, ++ }, ++ { ++ .modalias = "lis302dl", ++ /* platform_data */ ++ .platform_data = &lis302_pdata_bottom, ++ /* controller_data */ ++ /* irq */ ++ .max_speed_hz = 100 * 1000, ++ .bus_num = 3, ++ .chip_select = 1, ++ }, ++}; ++ ++static void gta02_lis302_chip_select(struct s3c2410_spigpio_info *info, int csid, int cs) ++{ ++ ++ /* ++ * Huh... "quirk"... CS on this device is not really "CS" like you can ++ * expect. ++ * ++ * When it is 0 it selects SPI interface mode. ++ * When it is 1 it selects I2C interface mode. ++ * ++ * Because we have 2 devices on one interface we have to make sure ++ * that the "disabled" device (actually in I2C mode) don't think we're ++ * talking to it. ++ * ++ * When we talk to the "enabled" device, the "disabled" device sees ++ * the clocks as I2C clocks, creating havoc. ++ * ++ * I2C sees MOSI going LOW while CLK HIGH as a START action, thus we ++ * must ensure this is never issued. ++ */ ++ ++ int cs_gpio, other_cs_gpio; ++ ++ cs_gpio = csid ? S3C2410_GPD13 : S3C2410_GPD12; ++ other_cs_gpio = (1 - csid) ? S3C2410_GPD13 : S3C2410_GPD12; ++ ++ ++ if (cs == BITBANG_CS_ACTIVE) { ++ s3c2410_gpio_setpin(other_cs_gpio, 1); ++ s3c2410_gpio_setpin(cs_gpio, 1); ++ s3c2410_gpio_setpin(info->pin_clk, 1); ++ s3c2410_gpio_setpin(cs_gpio, 0); ++ } else { ++ s3c2410_gpio_setpin(cs_gpio, 1); ++ s3c2410_gpio_setpin(other_cs_gpio, 1); ++ } ++} ++ ++static struct s3c2410_spigpio_info gta02_spigpio_cfg = { ++ .pin_clk = S3C2410_GPG7, ++ .pin_mosi = S3C2410_GPG6, ++ .pin_miso = S3C2410_GPG5, ++ .bus_num = 3, ++ .num_chipselect = 2, ++ .chip_select = gta02_lis302_chip_select, ++ .non_blocking_transfer = 1, ++}; ++ ++static struct platform_device gta02_spi_gpio_dev = { ++ .name = "spi_s3c24xx_gpio", ++ .dev = { ++ .platform_data = >a02_spigpio_cfg, ++ }, + }; + + static struct resource gta02_glamo_resources[] = { +@@ -1091,6 +1237,7 @@ static struct platform_device *gta02_devices[] __initdata = { + >a02_pm_bt_dev, + >a02_pm_wlan_dev, + >a02_glamo_dev, ++ >a02_spi_gpio_dev, + &s3c_device_adc, + &s3c_device_ts, + }; +@@ -1302,6 +1449,16 @@ static void __init gta02_machine_init(void) + /* Set the panic callback to make AUX LED blink at ~5Hz. */ + panic_blink = gta02_panic_blink; + ++ switch (S3C_SYSTEM_REV_ATAG) { ++ case GTA02v6_SYSTEM_REV: ++ /* we need push-pull interrupt from motion sensors */ ++ lis302_pdata_top.open_drain = 0; ++ lis302_pdata_bottom.open_drain = 0; ++ break; ++ default: ++ break; ++ } ++ + bus_register_notifier(&platform_bus_type, >a02_device_register_notifier); + bus_register_notifier(&spi_bus_type, >a02_device_register_notifier); + +diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig +index 23140a3..d8d0932 100644 +--- a/drivers/input/misc/Kconfig ++++ b/drivers/input/misc/Kconfig +@@ -340,4 +340,13 @@ config INPUT_PCAP + To compile this driver as a module, choose M here: the + module will be called pcap_keys. + ++config INPUT_LIS302DL ++ tristate "STmicro LIS302DL 3-axis accelerometer" ++ depends on SPI_MASTER ++ help ++ SPI driver for the STmicro LIS302DL 3-axis accelerometer. ++ ++ The userspece interface is a 3-axis (X/Y/Z) relative movement ++ Linux input device, reporting REL_[XYZ] events. ++ + endif +diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile +index 7e95a5d..5b810db 100644 +--- a/drivers/input/misc/Makefile ++++ b/drivers/input/misc/Makefile +@@ -32,4 +32,5 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o + obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o + obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o + obj-$(CONFIG_INPUT_YEALINK) += yealink.o ++obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o + +diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c +new file mode 100644 +index 0000000..d345bfb +--- /dev/null ++++ b/drivers/input/misc/lis302dl.c +@@ -0,0 +1,952 @@ ++/* Linux kernel driver for the ST LIS302D 3-axis accelerometer ++ * ++ * Copyright (C) 2007-2008 by Openmoko, Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ * converted to private bitbang by: ++ * Andy Green <andy@openmoko.com> ++ * ability to set acceleration threshold added by: ++ * Simon Kagstrom <simon.kagstrom@gmail.com> ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ * TODO ++ * * statistics for overflow events ++ * * configuration interface (sysfs) for ++ * * enable/disable x/y/z axis data ready ++ * * enable/disable resume from freee fall / click ++ * * free fall / click parameters ++ * * high pass filter parameters ++ */ ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/delay.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/sysfs.h> ++#include <linux/spi/spi.h> ++ ++#include <linux/lis302dl.h> ++ ++/* Utility functions */ ++static u8 __reg_read(struct lis302dl_info *lis, u8 reg) ++{ ++ struct spi_message msg; ++ struct spi_transfer t; ++ u8 data[2] = {0xc0 | reg}; ++ int rc; ++ ++ spi_message_init(&msg); ++ memset(&t, 0, sizeof t); ++ t.len = 2; ++ spi_message_add_tail(&t, &msg); ++ t.tx_buf = &data[0]; ++ t.rx_buf = &data[0]; ++ ++ /* Should complete without blocking */ ++ rc = spi_non_blocking_transfer(lis->spi, &msg); ++ if (rc < 0) { ++ dev_err(lis->dev, "Error reading register\n"); ++ return rc; ++ } ++ ++ return data[1]; ++} ++ ++static void __reg_write(struct lis302dl_info *lis, u8 reg, u8 val) ++{ ++ struct spi_message msg; ++ struct spi_transfer t; ++ u8 data[2] = {reg, val}; ++ ++ spi_message_init(&msg); ++ memset(&t, 0, sizeof t); ++ t.len = 2; ++ spi_message_add_tail(&t, &msg); ++ t.tx_buf = &data[0]; ++ t.rx_buf = &data[0]; ++ ++ /* Completes without blocking */ ++ if (spi_non_blocking_transfer(lis->spi, &msg) < 0) ++ dev_err(lis->dev, "Error writing register\n"); ++} ++ ++static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask, ++ u8 val) ++{ ++ u_int8_t tmp; ++ ++ val &= mask; ++ ++ tmp = __reg_read(lis, reg); ++ tmp &= ~mask; ++ tmp |= val; ++ __reg_write(lis, reg, tmp); ++} ++ ++static int __ms_to_duration(struct lis302dl_info *lis, int ms) ++{ ++ /* If we have 400 ms sampling rate, the stepping is 2.5 ms, ++ * on 100 ms the stepping is 10ms */ ++ if (lis->flags & LIS302DL_F_DR) ++ return min((ms * 10) / 25, 637); ++ ++ return min(ms / 10, 2550); ++} ++ ++static int __duration_to_ms(struct lis302dl_info *lis, int duration) ++{ ++ if (lis->flags & LIS302DL_F_DR) ++ return (duration * 25) / 10; ++ ++ return duration * 10; ++} ++ ++static u8 __mg_to_threshold(struct lis302dl_info *lis, int mg) ++{ ++ /* If FS is set each bit is 71mg, otherwise 18mg. The THS register ++ * has 7 bits for the threshold value */ ++ if (lis->flags & LIS302DL_F_FS) ++ return min(mg / 71, 127); ++ ++ return min(mg / 18, 127); ++} ++ ++static int __threshold_to_mg(struct lis302dl_info *lis, u8 threshold) ++{ ++ if (lis->flags & LIS302DL_F_FS) ++ return threshold * 71; ++ ++ return threshold * 18; ++} ++ ++/* interrupt handling related */ ++ ++enum lis302dl_intmode { ++ LIS302DL_INTMODE_GND = 0x00, ++ LIS302DL_INTMODE_FF_WU_1 = 0x01, ++ LIS302DL_INTMODE_FF_WU_2 = 0x02, ++ LIS302DL_INTMODE_FF_WU_12 = 0x03, ++ LIS302DL_INTMODE_DATA_READY = 0x04, ++ LIS302DL_INTMODE_CLICK = 0x07, ++}; ++ ++static void __lis302dl_int_mode(struct device *dev, int int_pin, ++ enum lis302dl_intmode mode) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ switch (int_pin) { ++ case 1: ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode); ++ break; ++ case 2: ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void __enable_wakeup(struct lis302dl_info *lis) ++{ ++ __reg_write(lis, LIS302DL_REG_CTRL1, 0); ++ ++ /* First zero to get to a known state */ ++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE | ++ LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE | ++ LIS302DL_FFWUCFG_LIR); ++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, ++ __mg_to_threshold(lis, lis->wakeup.threshold)); ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, ++ __ms_to_duration(lis, lis->wakeup.duration)); ++ ++ /* Route the interrupt for wakeup */ ++ __lis302dl_int_mode(lis->dev, 1, ++ LIS302DL_INTMODE_FF_WU_1); ++ ++ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET); ++ __reg_read(lis, LIS302DL_REG_OUT_X); ++ __reg_read(lis, LIS302DL_REG_OUT_Y); ++ __reg_read(lis, LIS302DL_REG_OUT_Z); ++ __reg_read(lis, LIS302DL_REG_STATUS); ++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1); ++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_2); ++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7); ++} ++ ++static void __enable_data_collection(struct lis302dl_info *lis) ++{ ++ u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen; ++ ++ /* make sure we're powered up and generate data ready */ ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1); ++ ++ /* If the threshold is zero, let the device generated an interrupt ++ * on each datum */ ++ if (lis->threshold == 0) { ++ __reg_write(lis, LIS302DL_REG_CTRL2, 0); ++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY); ++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY); ++ } else { ++ __reg_write(lis, LIS302DL_REG_CTRL2, ++ LIS302DL_CTRL2_HPFF1); ++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, ++ __mg_to_threshold(lis, lis->threshold)); ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, ++ __ms_to_duration(lis, lis->duration)); ++ ++ /* Clear the HP filter "starting point" */ ++ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET); ++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, ++ LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE | ++ LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR); ++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12); ++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12); ++ } ++} ++ ++#if 0 ++static void _report_btn_single(struct input_dev *inp, int btn) ++{ ++ input_report_key(inp, btn, 1); ++ input_sync(inp); ++ input_report_key(inp, btn, 0); ++} ++ ++static void _report_btn_double(struct input_dev *inp, int btn) ++{ ++ input_report_key(inp, btn, 1); ++ input_sync(inp); ++ input_report_key(inp, btn, 0); ++ input_sync(inp); ++ input_report_key(inp, btn, 1); ++ input_sync(inp); ++ input_report_key(inp, btn, 0); ++} ++#endif ++ ++ ++static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis) ++{ ++ u8 data[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 2] = {0xC0 | LIS302DL_REG_STATUS}; ++ u8 *read = data + 1; ++ unsigned long flags; ++ int mg_per_sample = __threshold_to_mg(lis, 1); ++ struct spi_message msg; ++ struct spi_transfer t; ++ ++ spi_message_init(&msg); ++ memset(&t, 0, sizeof t); ++ t.len = sizeof(data); ++ spi_message_add_tail(&t, &msg); ++ t.tx_buf = &data[0]; ++ t.rx_buf = &data[0]; ++ ++ /* grab the set of register containing status and XYZ data */ ++ ++ local_irq_save(flags); ++ ++ /* Should complete without blocking */ ++ if (spi_non_blocking_transfer(lis->spi, &msg) < 0) ++ dev_err(lis->dev, "Error reading registers\n"); ++ ++ local_irq_restore(flags); ++ ++ /* ++ * at the minute the test below fails 50% of the time due to ++ * a problem with level interrupts causing ISRs to get called twice. ++ * This is a workaround for that, but actually this test is still ++ * valid and the information can be used for overrrun stats. ++ */ ++ ++ /* has any kind of overrun been observed by the lis302dl? */ ++ if (read[0] & (LIS302DL_STATUS_XOR | ++ LIS302DL_STATUS_YOR | ++ LIS302DL_STATUS_ZOR)) ++ lis->overruns++; ++ ++ /* we have a valid sample set? */ ++ if (read[0] & LIS302DL_STATUS_XYZDA) { ++ input_report_abs(lis->input_dev, ABS_X, mg_per_sample * ++ (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]); ++ input_report_abs(lis->input_dev, ABS_Y, mg_per_sample * ++ (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]); ++ input_report_abs(lis->input_dev, ABS_Z, mg_per_sample * ++ (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]); ++ ++ input_sync(lis->input_dev); ++ } ++ ++ if (lis->threshold) ++ /* acknowledge the wakeup source */ ++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1); ++} ++ ++static irqreturn_t lis302dl_interrupt(int irq, void *_lis) ++{ ++ struct lis302dl_info *lis = _lis; ++ ++ lis302dl_bitbang_read_sample(lis); ++ return IRQ_HANDLED; ++} ++ ++/* sysfs */ ++ ++static ssize_t show_overruns(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", lis->overruns); ++} ++ ++static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL); ++ ++static ssize_t show_rate(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ u8 ctrl1; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1); ++ local_irq_restore(flags); ++ ++ return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100); ++} ++ ++static ssize_t set_rate(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ if (!strcmp(buf, "400\n")) { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, ++ LIS302DL_CTRL1_DR); ++ lis->flags |= LIS302DL_F_DR; ++ } else { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, ++ 0); ++ lis->flags &= ~LIS302DL_F_DR; ++ } ++ local_irq_restore(flags); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate); ++ ++static ssize_t show_scale(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ u_int8_t ctrl1; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1); ++ local_irq_restore(flags); ++ ++ return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3"); ++} ++ ++static ssize_t set_scale(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ if (!strcmp(buf, "9.2\n")) { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, ++ LIS302DL_CTRL1_FS); ++ lis->flags |= LIS302DL_F_FS; ++ } else { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, ++ 0); ++ lis->flags &= ~LIS302DL_F_FS; ++ } ++ ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) ++ __enable_data_collection(lis); ++ ++ local_irq_restore(flags); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale); ++ ++static ssize_t show_threshold(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ /* Display the device view of the threshold setting */ ++ return sprintf(buf, "%d\n", __threshold_to_mg(lis, ++ __mg_to_threshold(lis, lis->threshold))); ++} ++ ++static ssize_t set_threshold(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ /* 8g is the maximum if FS is 1 */ ++ if (val > 8000) ++ return -ERANGE; ++ ++ /* Set the threshold and write it out if the device is used */ ++ lis->threshold = val; ++ ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ __enable_data_collection(lis); ++ local_irq_restore(flags); ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR, show_threshold, set_threshold); ++ ++static ssize_t show_duration(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", __duration_to_ms(lis, ++ __ms_to_duration(lis, lis->duration))); ++} ++ ++static ssize_t set_duration(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ if (val > 2550) ++ return -ERANGE; ++ ++ lis->duration = val; ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, ++ __ms_to_duration(lis, lis->duration)); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(duration, S_IRUGO | S_IWUSR, show_duration, set_duration); ++ ++static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ int n = 0; ++ u8 reg[0x40]; ++ char *end = buf; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ for (n = 0; n < sizeof(reg); n++) ++ reg[n] = __reg_read(lis, n); ++ ++ local_irq_restore(flags); ++ ++ for (n = 0; n < sizeof(reg); n += 16) { ++ hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0); ++ end += strlen(end); ++ *end++ = '\n'; ++ *end++ = '\0'; ++ } ++ ++ return end - buf; ++} ++static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL); ++ ++/* Configure freefall/wakeup interrupts */ ++static ssize_t set_wakeup_threshold(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int threshold; ++ ++ if (sscanf(buf, "%u\n", &threshold) != 1) ++ return -EINVAL; ++ ++ if (threshold > 8000) ++ return -ERANGE; ++ ++ /* Zero turns the feature off */ ++ if (threshold == 0) { ++ if (lis->flags & LIS302DL_F_IRQ_WAKE) { ++ disable_irq_wake(lis->pdata->interrupt); ++ lis->flags &= ~LIS302DL_F_IRQ_WAKE; ++ } ++ ++ return count; ++ } ++ ++ lis->wakeup.threshold = threshold; ++ ++ if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) { ++ enable_irq_wake(lis->pdata->interrupt); ++ lis->flags |= LIS302DL_F_IRQ_WAKE; ++ } ++ ++ return count; ++} ++ ++static ssize_t show_wakeup_threshold(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ /* All events off? */ ++ if (lis->wakeup.threshold == 0) ++ return sprintf(buf, "off\n"); ++ ++ return sprintf(buf, "%u\n", lis->wakeup.threshold); ++} ++ ++static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold, ++ set_wakeup_threshold); ++ ++static ssize_t set_wakeup_duration(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ unsigned int duration; ++ ++ if (sscanf(buf, "%u\n", &duration) != 1) ++ return -EINVAL; ++ ++ if (duration > 2550) ++ return -ERANGE; ++ ++ lis->wakeup.duration = duration; ++ ++ return count; ++} ++ ++static ssize_t show_wakeup_duration(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", lis->wakeup.duration); ++} ++ ++static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration, ++ set_wakeup_duration); ++ ++static struct attribute *lis302dl_sysfs_entries[] = { ++ &dev_attr_sample_rate.attr, ++ &dev_attr_full_scale.attr, ++ &dev_attr_threshold.attr, ++ &dev_attr_duration.attr, ++ &dev_attr_dump.attr, ++ &dev_attr_wakeup_threshold.attr, ++ &dev_attr_wakeup_duration.attr, ++ &dev_attr_overruns.attr, ++ NULL ++}; ++ ++static struct attribute_group lis302dl_attr_group = { ++ .name = NULL, ++ .attrs = lis302dl_sysfs_entries, ++}; ++ ++/* input device handling and driver core interaction */ ++ ++static int lis302dl_input_open(struct input_dev *inp) ++{ ++ struct lis302dl_info *lis = input_get_drvdata(inp); ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ __enable_data_collection(lis); ++ lis->flags |= LIS302DL_F_INPUT_OPEN; ++ ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static void lis302dl_input_close(struct input_dev *inp) ++{ ++ struct lis302dl_info *lis = input_get_drvdata(inp); ++ u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen | ++ LIS302DL_CTRL1_Zen; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ /* since the input core already serializes access and makes sure we ++ * only see close() for the close of the last user, we can safely ++ * disable the data ready events */ ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00); ++ lis->flags &= ~LIS302DL_F_INPUT_OPEN; ++ ++ /* however, don't power down the whole device if still needed */ ++ if (!(lis->flags & LIS302DL_F_WUP_FF || ++ lis->flags & LIS302DL_F_WUP_CLICK)) { ++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD, ++ 0x00); ++ } ++ local_irq_restore(flags); ++} ++ ++/* get the device to reload its coefficients from EEPROM and wait for it ++ * to complete ++ */ ++ ++static int __lis302dl_reset_device(struct lis302dl_info *lis) ++{ ++ int timeout = 10; ++ ++ __reg_write(lis, LIS302DL_REG_CTRL2, ++ LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS); ++ ++ while ((__reg_read(lis, LIS302DL_REG_CTRL2) ++ & LIS302DL_CTRL2_BOOT) && (timeout--)) ++ mdelay(1); ++ ++ return !!(timeout < 0); ++} ++ ++static int __devinit lis302dl_probe(struct spi_device *spi) ++{ ++ int rc; ++ struct lis302dl_info *lis; ++ u_int8_t wai; ++ unsigned long flags; ++ struct lis302dl_platform_data *pdata = spi->dev.platform_data; ++ ++ spi->mode = SPI_MODE_3; ++ rc = spi_setup(spi); ++ if (rc < 0) { ++ dev_err(&spi->dev, "spi_setup failed\n"); ++ return rc; ++ } ++ ++ lis = kzalloc(sizeof(*lis), GFP_KERNEL); ++ if (!lis) ++ return -ENOMEM; ++ ++ lis->dev = &spi->dev; ++ lis->spi = spi; ++ ++ dev_set_drvdata(lis->dev, lis); ++ ++ lis->pdata = pdata; ++ ++ rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group); ++ if (rc) { ++ dev_err(lis->dev, "error creating sysfs group\n"); ++ goto bail_free_lis; ++ } ++ ++ /* initialize input layer details */ ++ lis->input_dev = input_allocate_device(); ++ if (!lis->input_dev) { ++ dev_err(lis->dev, "Unable to allocate input device\n"); ++ goto bail_sysfs; ++ } ++ ++ input_set_drvdata(lis->input_dev, lis); ++ lis->input_dev->name = pdata->name; ++ /* SPI Bus not defined as a valid bus for input subsystem*/ ++ lis->input_dev->id.bustype = BUS_I2C; /* lie about it */ ++ lis->input_dev->open = lis302dl_input_open; ++ lis->input_dev->close = lis302dl_input_close; ++ ++ rc = input_register_device(lis->input_dev); ++ if (rc) { ++ dev_err(lis->dev, "error %d registering input device\n", rc); ++ goto bail_inp_dev; ++ } ++ ++ local_irq_save(flags); ++ /* Configure our IO */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 1); ++ ++ wai = __reg_read(lis, LIS302DL_REG_WHO_AM_I); ++ if (wai != LIS302DL_WHO_AM_I_MAGIC) { ++ dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai); ++ dev_set_drvdata(lis->dev, NULL); ++ rc = -ENODEV; ++ local_irq_restore(flags); ++ goto bail_inp_reg; ++ } ++ ++ set_bit(EV_ABS, lis->input_dev->evbit); ++ input_set_abs_params(lis->input_dev, ABS_X, 0, 0, 0, 0); ++ input_set_abs_params(lis->input_dev, ABS_Y, 0, 0, 0, 0); ++ input_set_abs_params(lis->input_dev, ABS_Z, 0, 0, 0, 0); ++ ++ ++ lis->threshold = 0; ++ lis->duration = 0; ++ memset(&lis->wakeup, 0, sizeof(lis->wakeup)); ++ ++ if (__lis302dl_reset_device(lis)) ++ dev_err(lis->dev, "device BOOT reload failed\n"); ++ ++ /* force us powered */ ++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | ++ LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | ++ LIS302DL_CTRL1_Zen); ++ mdelay(1); ++ ++ __reg_write(lis, LIS302DL_REG_CTRL2, 0); ++ __reg_write(lis, LIS302DL_REG_CTRL3, ++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL); ++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0); ++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00); ++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0); ++ ++ /* start off in powered down mode; we power up when someone opens us */ ++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen); ++ ++ if (pdata->open_drain) ++ /* switch interrupt to open collector, active-low */ ++ __reg_write(lis, LIS302DL_REG_CTRL3, ++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL); ++ else ++ /* push-pull, active-low */ ++ __reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL); ++ ++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_GND); ++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_GND); ++ ++ __reg_read(lis, LIS302DL_REG_STATUS); ++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1); ++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_2); ++ __reg_read(lis, LIS302DL_REG_CLICK_SRC); ++ local_irq_restore(flags); ++ ++ dev_info(lis->dev, "Found %s\n", pdata->name); ++ ++ lis->pdata = pdata; ++ ++ set_irq_handler(lis->pdata->interrupt, handle_level_irq); ++ ++ rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt, ++ IRQF_TRIGGER_LOW, "lis302dl", lis); ++ ++ if (rc < 0) { ++ dev_err(lis->dev, "error requesting IRQ %d\n", ++ lis->pdata->interrupt); ++ goto bail_inp_reg; ++ } ++ return 0; ++ ++bail_inp_reg: ++ input_unregister_device(lis->input_dev); ++bail_inp_dev: ++ input_free_device(lis->input_dev); ++bail_sysfs: ++ sysfs_remove_group(&lis->dev->kobj, &lis302dl_attr_group); ++bail_free_lis: ++ kfree(lis); ++ return rc; ++} ++ ++static int __devexit lis302dl_remove(struct spi_device *spi) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); ++ unsigned long flags; ++ ++ /* Disable interrupts */ ++ if (lis->flags & LIS302DL_F_IRQ_WAKE) ++ disable_irq_wake(lis->pdata->interrupt); ++ free_irq(lis->pdata->interrupt, lis); ++ ++ /* Reset and power down the device */ ++ local_irq_save(flags); ++ __reg_write(lis, LIS302DL_REG_CTRL3, 0x00); ++ __reg_write(lis, LIS302DL_REG_CTRL2, 0x00); ++ __reg_write(lis, LIS302DL_REG_CTRL1, 0x00); ++ local_irq_restore(flags); ++ ++ /* Cleanup resources */ ++ sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group); ++ input_unregister_device(lis->input_dev); ++ if (lis->input_dev) ++ input_free_device(lis->input_dev); ++ dev_set_drvdata(lis->dev, NULL); ++ kfree(lis); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++static u8 regs_to_save[] = { ++ LIS302DL_REG_CTRL2, ++ LIS302DL_REG_CTRL3, ++ LIS302DL_REG_FF_WU_CFG_1, ++ LIS302DL_REG_FF_WU_THS_1, ++ LIS302DL_REG_FF_WU_DURATION_1, ++ LIS302DL_REG_FF_WU_CFG_2, ++ LIS302DL_REG_FF_WU_THS_2, ++ LIS302DL_REG_FF_WU_DURATION_2, ++ LIS302DL_REG_CLICK_CFG, ++ LIS302DL_REG_CLICK_THSY_X, ++ LIS302DL_REG_CLICK_THSZ, ++ LIS302DL_REG_CLICK_TIME_LIMIT, ++ LIS302DL_REG_CLICK_LATENCY, ++ LIS302DL_REG_CLICK_WINDOW, ++ LIS302DL_REG_CTRL1, ++}; ++ ++static int lis302dl_suspend(struct spi_device *spi, pm_message_t state) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); ++ unsigned long flags; ++ u_int8_t tmp; ++ int n; ++ ++ /* determine if we want to wake up from the accel. */ ++ if (lis->flags & LIS302DL_F_WUP_CLICK) ++ return 0; ++ ++ disable_irq(lis->pdata->interrupt); ++ local_irq_save(flags); ++ ++ /* ++ * When we share SPI over multiple sensors, there is a race here ++ * that one or more sensors will lose. In that case, the shared ++ * SPI bus GPIO will be in sleep mode and partially pulled down. So ++ * we explicitly put our IO into "wake" mode here before the final ++ * traffic to the sensor. ++ */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 1); ++ ++ /* save registers */ ++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++) ++ lis->regs[regs_to_save[n]] = ++ __reg_read(lis, regs_to_save[n]); ++ ++ /* power down or enable wakeup */ ++ ++ if (lis->wakeup.threshold == 0) { ++ tmp = __reg_read(lis, LIS302DL_REG_CTRL1); ++ tmp &= ~LIS302DL_CTRL1_PD; ++ __reg_write(lis, LIS302DL_REG_CTRL1, tmp); ++ } else ++ __enable_wakeup(lis); ++ ++ /* place our IO to the device in sleep-compatible states */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 0); ++ ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static int lis302dl_resume(struct spi_device *spi) ++{ ++ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev); ++ unsigned long flags; ++ int n; ++ ++ if (lis->flags & LIS302DL_F_WUP_CLICK) ++ return 0; ++ ++ local_irq_save(flags); ++ ++ /* get our IO to the device back in operational states */ ++ (lis->pdata->lis302dl_suspend_io)(lis, 1); ++ ++ /* resume from powerdown first! */ ++ __reg_write(lis, LIS302DL_REG_CTRL1, ++ LIS302DL_CTRL1_PD | ++ LIS302DL_CTRL1_Xen | ++ LIS302DL_CTRL1_Yen | ++ LIS302DL_CTRL1_Zen); ++ mdelay(1); ++ ++ if (__lis302dl_reset_device(lis)) ++ dev_err(&spi->dev, "device BOOT reload failed\n"); ++ ++ /* restore registers after resume */ ++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++) ++ __reg_write(lis, regs_to_save[n], lis->regs[regs_to_save[n]]); ++ ++ /* if someone had us open, reset the non-wake threshold stuff */ ++ if (lis->flags & LIS302DL_F_INPUT_OPEN) ++ __enable_data_collection(lis); ++ ++ local_irq_restore(flags); ++ enable_irq(lis->pdata->interrupt); ++ ++ return 0; ++} ++#else ++#define lis302dl_suspend NULL ++#define lis302dl_resume NULL ++#endif ++ ++static struct spi_driver lis302dl_spi_driver = { ++ .driver = { ++ .name = "lis302dl", ++ .owner = THIS_MODULE, ++ }, ++ ++ .probe = lis302dl_probe, ++ .remove = __devexit_p(lis302dl_remove), ++ .suspend = lis302dl_suspend, ++ .resume = lis302dl_resume, ++}; ++ ++static int __devinit lis302dl_init(void) ++{ ++ return spi_register_driver(&lis302dl_spi_driver); ++} ++ ++static void __exit lis302dl_exit(void) ++{ ++ spi_unregister_driver(&lis302dl_spi_driver); ++} ++ ++MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>"); ++MODULE_LICENSE("GPL"); ++ ++module_init(lis302dl_init); ++module_exit(lis302dl_exit); +diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c +index 5265330..24c61a6 100644 +--- a/drivers/spi/spi_bitbang.c ++++ b/drivers/spi/spi_bitbang.c +@@ -254,134 +254,139 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) + * Drivers can provide word-at-a-time i/o primitives, or provide + * transfer-at-a-time ones to leverage dma or fifo hardware. + */ +-static void bitbang_work(struct work_struct *work) ++/* Synchronous non blocking transfer */ ++int ++spi_bitbang_transfer_sync(struct spi_device *spi, struct spi_message *m) + { +- struct spi_bitbang *bitbang = +- container_of(work, struct spi_bitbang, work); +- unsigned long flags; +- int do_setup = -1; +- int (*setup_transfer)(struct spi_device *, +- struct spi_transfer *); ++ struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); ++ struct spi_transfer *t; ++ unsigned long flags; ++ int cs_change = 1; ++ int status; ++ int nsecs; ++ int (*setup_transfer)(struct spi_device *, struct spi_transfer *); ++ ++ /* FIXME this is made-up ... the correct value is known to ++ * word-at-a-time bitbang code, and presumably chipselect() ++ * should enforce these requirements too? ++ */ ++ nsecs = 100; ++ cs_change = 1; ++ status = 0; ++ setup_transfer = NULL; ++ ++ local_irq_save(flags); ++ list_for_each_entry (t, &m->transfers, transfer_list) { ++ /* override or restore speed and wordsize */ ++ if (t->speed_hz || t->bits_per_word) { ++ setup_transfer = bitbang->setup_transfer; ++ if (!setup_transfer) { ++ status = -ENOPROTOOPT; ++ break; ++ } ++ } ++ if (setup_transfer) { ++ status = setup_transfer(spi, t); ++ if (status < 0) ++ break; ++ } + +- setup_transfer = bitbang->setup_transfer; ++ /* set up default clock polarity, and activate chip; ++ * this implicitly updates clock and spi modes as ++ * previously recorded for this device via setup(). ++ * (and also deselects any other chip that might be ++ * selected ...) ++ */ + +- spin_lock_irqsave(&bitbang->lock, flags); +- bitbang->busy = 1; +- while (!list_empty(&bitbang->queue)) { +- struct spi_message *m; +- struct spi_device *spi; +- unsigned nsecs; +- struct spi_transfer *t = NULL; +- unsigned tmp; +- unsigned cs_change; +- int status; ++ if (cs_change) { ++ bitbang->chipselect(spi, BITBANG_CS_ACTIVE); ++ ndelay(nsecs); ++ } + +- m = container_of(bitbang->queue.next, struct spi_message, +- queue); +- list_del_init(&m->queue); +- spin_unlock_irqrestore(&bitbang->lock, flags); ++ cs_change = t->cs_change; ++ if (!t->tx_buf && !t->rx_buf && t->len) { ++ status = -EINVAL; ++ break; ++ } + +- /* FIXME this is made-up ... the correct value is known to +- * word-at-a-time bitbang code, and presumably chipselect() +- * should enforce these requirements too? ++ /* transfer data. the lower level code handles any ++ * new dma mappings it needs. our caller always gave ++ * us dma-safe buffers. + */ +- nsecs = 100; ++ if (t->len) { ++ /* REVISIT dma API still needs a designated ++ * DMA_ADDR_INVALID; ~0 might be better. ++ */ ++ if (!m->is_dma_mapped) ++ t->rx_dma = t->tx_dma = 0; ++ status = bitbang->txrx_bufs(spi, t); ++ } + +- spi = m->spi; +- tmp = 0; +- cs_change = 1; ++ if (status > 0) ++ m->actual_length += status; ++ if (status != t->len) { ++ /* always report some kind of error */ ++ if (status >= 0) ++ status = -EREMOTEIO; ++ break; ++ } + status = 0; ++ /* protocol tweaks before next transfer */ ++ if (t->delay_usecs) ++ udelay(t->delay_usecs); ++ if (!cs_change) ++ continue; ++ if (t->transfer_list.next == &m->transfers) ++ break; ++ /* sometimes a short mid-message deselect of the chip ++ * may be needed to terminate a mode or command ++ */ ++ ndelay(nsecs); ++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ++ ndelay(nsecs); ++ } + +- list_for_each_entry (t, &m->transfers, transfer_list) { +- +- /* override speed or wordsize? */ +- if (t->speed_hz || t->bits_per_word) +- do_setup = 1; +- +- /* init (-1) or override (1) transfer params */ +- if (do_setup != 0) { +- if (!setup_transfer) { +- status = -ENOPROTOOPT; +- break; +- } +- status = setup_transfer(spi, t); +- if (status < 0) +- break; +- } ++ m->status = status; ++ if (m->complete) ++ m->complete(m->context); + +- /* set up default clock polarity, and activate chip; +- * this implicitly updates clock and spi modes as +- * previously recorded for this device via setup(). +- * (and also deselects any other chip that might be +- * selected ...) +- */ +- if (cs_change) { +- bitbang->chipselect(spi, BITBANG_CS_ACTIVE); +- ndelay(nsecs); +- } +- cs_change = t->cs_change; +- if (!t->tx_buf && !t->rx_buf && t->len) { +- status = -EINVAL; +- break; +- } ++ /* restore speed and wordsize */ ++ if (setup_transfer) ++ setup_transfer(spi, NULL); + +- /* transfer data. the lower level code handles any +- * new dma mappings it needs. our caller always gave +- * us dma-safe buffers. +- */ +- if (t->len) { +- /* REVISIT dma API still needs a designated +- * DMA_ADDR_INVALID; ~0 might be better. +- */ +- if (!m->is_dma_mapped) +- t->rx_dma = t->tx_dma = 0; +- status = bitbang->txrx_bufs(spi, t); +- } +- if (status > 0) +- m->actual_length += status; +- if (status != t->len) { +- /* always report some kind of error */ +- if (status >= 0) +- status = -EREMOTEIO; +- break; +- } +- status = 0; +- +- /* protocol tweaks before next transfer */ +- if (t->delay_usecs) +- udelay(t->delay_usecs); ++ /* normally deactivate chipselect ... unless no error and ++ * cs_change has hinted that the next message will probably ++ * be for this chip too. ++ */ ++ if (!(status == 0 && cs_change)) { ++ ndelay(nsecs); ++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ++ ndelay(nsecs); ++ } + +- if (!cs_change) +- continue; +- if (t->transfer_list.next == &m->transfers) +- break; ++ local_irq_restore(flags); + +- /* sometimes a short mid-message deselect of the chip +- * may be needed to terminate a mode or command +- */ +- ndelay(nsecs); +- bitbang->chipselect(spi, BITBANG_CS_INACTIVE); +- ndelay(nsecs); +- } ++ return status; ++} ++EXPORT_SYMBOL_GPL(spi_bitbang_transfer_sync); + +- m->status = status; +- m->complete(m->context); ++static void bitbang_work(struct work_struct *work) ++{ ++ struct spi_bitbang *bitbang = ++ container_of(work, struct spi_bitbang, work); ++ unsigned long flags; + +- /* restore speed and wordsize if it was overridden */ +- if (do_setup == 1) +- setup_transfer(spi, NULL); +- do_setup = 0; ++ spin_lock_irqsave(&bitbang->lock, flags); ++ bitbang->busy = 1; ++ while (!list_empty(&bitbang->queue)) { ++ struct spi_message *m; + +- /* normally deactivate chipselect ... unless no error and +- * cs_change has hinted that the next message will probably +- * be for this chip too. +- */ +- if (!(status == 0 && cs_change)) { +- ndelay(nsecs); +- bitbang->chipselect(spi, BITBANG_CS_INACTIVE); +- ndelay(nsecs); +- } ++ m = container_of(bitbang->queue.next, struct spi_message, ++ queue); ++ list_del_init(&m->queue); + ++ spin_unlock_irqrestore(&bitbang->lock, flags); ++ spi_bitbang_transfer_sync(m->spi, m); + spin_lock_irqsave(&bitbang->lock, flags); + } + bitbang->busy = 0; +@@ -456,6 +461,10 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) + + if (!bitbang->master->transfer) + bitbang->master->transfer = spi_bitbang_transfer; ++ ++ if (!bitbang->master->transfer_sync && bitbang->non_blocking_transfer) ++ bitbang->master->transfer_sync = spi_bitbang_transfer_sync; ++ + if (!bitbang->txrx_bufs) { + bitbang->use_dma = 0; + bitbang->txrx_bufs = spi_bitbang_bufs; +diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c +index bbf9371..5685b78 100644 +--- a/drivers/spi/spi_s3c24xx_gpio.c ++++ b/drivers/spi/spi_s3c24xx_gpio.c +@@ -92,7 +92,7 @@ static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value) + struct s3c2410_spigpio *sg = spidev_to_sg(dev); + + if (sg->info && sg->info->chip_select) +- (sg->info->chip_select)(sg->info, value); ++ (sg->info->chip_select)(sg->info, dev->chip_select, value); + } + + static int s3c2410_spigpio_probe(struct platform_device *dev) +@@ -113,14 +113,17 @@ static int s3c2410_spigpio_probe(struct platform_device *dev) + + platform_set_drvdata(dev, sp); + +- /* copy in the plkatform data */ ++ /* copy in the platform data */ + info = sp->info = dev->dev.platform_data; + ++ master->num_chipselect = info->num_chipselect; ++ + /* setup spi bitbang adaptor */ + sp->bitbang.master = spi_master_get(master); + sp->bitbang.master->bus_num = info->bus_num; + sp->bitbang.master->num_chipselect = info->num_chipselect; + sp->bitbang.chipselect = s3c2410_spigpio_chipselect; ++ sp->bitbang.non_blocking_transfer = info->non_blocking_transfer; + + sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0; + sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1; +diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h +new file mode 100644 +index 0000000..0c1fc30 +--- /dev/null ++++ b/include/linux/lis302dl.h +@@ -0,0 +1,152 @@ ++#ifndef _LINUX_LIS302DL_H ++#define _LINUX_LIS302DL_H ++ ++#include <linux/types.h> ++#include <linux/spi/spi.h> ++#include <linux/input.h> ++#include <linux/workqueue.h> ++ ++struct lis302dl_info; ++ ++struct lis302dl_platform_data { ++ char *name; ++ unsigned long pin_chip_select; ++ unsigned long pin_clk; ++ unsigned long pin_mosi; ++ unsigned long pin_miso; ++ int open_drain; ++ int interrupt; ++ void (*lis302dl_suspend_io)(struct lis302dl_info *, int resuming); ++}; ++ ++struct lis302dl_info { ++ struct lis302dl_platform_data *pdata; ++ struct device *dev; ++ struct input_dev *input_dev; ++ unsigned int flags; ++ unsigned int threshold; ++ unsigned int duration; ++ u32 overruns; ++ struct { ++ unsigned int threshold; /* mg */ ++ unsigned int duration; /* ms */ ++ } wakeup; ++ ++ struct spi_device *spi; ++ u_int8_t regs[0x40]; ++}; ++ ++enum lis302dl_reg { ++ LIS302DL_REG_WHO_AM_I = 0x0f, ++ LIS302DL_REG_CTRL1 = 0x20, ++ LIS302DL_REG_CTRL2 = 0x21, ++ LIS302DL_REG_CTRL3 = 0x22, ++ LIS302DL_REG_HP_FILTER_RESET = 0x23, ++ LIS302DL_REG_STATUS = 0x27, ++ LIS302DL_REG_OUT_X = 0x29, ++ LIS302DL_REG_OUT_Y = 0x2b, ++ LIS302DL_REG_OUT_Z = 0x2d, ++ LIS302DL_REG_FF_WU_CFG_1 = 0x30, ++ LIS302DL_REG_FF_WU_SRC_1 = 0x31, ++ LIS302DL_REG_FF_WU_THS_1 = 0x32, ++ LIS302DL_REG_FF_WU_DURATION_1 = 0x33, ++ LIS302DL_REG_FF_WU_CFG_2 = 0x34, ++ LIS302DL_REG_FF_WU_SRC_2 = 0x35, ++ LIS302DL_REG_FF_WU_THS_2 = 0x36, ++ LIS302DL_REG_FF_WU_DURATION_2 = 0x37, ++ LIS302DL_REG_CLICK_CFG = 0x38, ++ LIS302DL_REG_CLICK_SRC = 0x39, ++ LIS302DL_REG_CLICK_THSY_X = 0x3b, ++ LIS302DL_REG_CLICK_THSZ = 0x3c, ++ LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d, ++ LIS302DL_REG_CLICK_LATENCY = 0x3e, ++ LIS302DL_REG_CLICK_WINDOW = 0x3f, ++}; ++ ++enum lis302dl_reg_ctrl1 { ++ LIS302DL_CTRL1_Xen = 0x01, ++ LIS302DL_CTRL1_Yen = 0x02, ++ LIS302DL_CTRL1_Zen = 0x04, ++ LIS302DL_CTRL1_STM = 0x08, ++ LIS302DL_CTRL1_STP = 0x10, ++ LIS302DL_CTRL1_FS = 0x20, ++ LIS302DL_CTRL1_PD = 0x40, ++ LIS302DL_CTRL1_DR = 0x80, ++}; ++ ++enum lis302dl_reg_ctrl2 { ++ LIS302DL_CTRL2_HPC1 = 0x01, ++ LIS302DL_CTRL2_HPC2 = 0x02, ++ LIS302DL_CTRL2_HPFF1 = 0x04, ++ LIS302DL_CTRL2_HPFF2 = 0x08, ++ LIS302DL_CTRL2_FDS = 0x10, ++ LIS302DL_CTRL2_BOOT = 0x40, ++ LIS302DL_CTRL2_SIM = 0x80, ++}; ++enum lis302dl_reg_ctrl3 { ++ LIS302DL_CTRL3_PP_OD = 0x40, ++ LIS302DL_CTRL3_IHL = 0x80, ++}; ++ ++enum lis302dl_reg_status { ++ LIS302DL_STATUS_XDA = 0x01, ++ LIS302DL_STATUS_YDA = 0x02, ++ LIS302DL_STATUS_ZDA = 0x04, ++ LIS302DL_STATUS_XYZDA = 0x08, ++ LIS302DL_STATUS_XOR = 0x10, ++ LIS302DL_STATUS_YOR = 0x20, ++ LIS302DL_STATUS_ZOR = 0x40, ++ LIS302DL_STATUS_XYZOR = 0x80, ++}; ++ ++/* Wakeup/freefall interrupt defs */ ++enum lis302dl_reg_ffwucfg { ++ LIS302DL_FFWUCFG_XLIE = 0x01, ++ LIS302DL_FFWUCFG_XHIE = 0x02, ++ LIS302DL_FFWUCFG_YLIE = 0x04, ++ LIS302DL_FFWUCFG_YHIE = 0x08, ++ LIS302DL_FFWUCFG_ZLIE = 0x10, ++ LIS302DL_FFWUCFG_ZHIE = 0x20, ++ LIS302DL_FFWUCFG_LIR = 0x40, ++ LIS302DL_FFWUCFG_AOI = 0x80, ++}; ++ ++enum lis302dl_reg_ffwuths { ++ LIS302DL_FFWUTHS_DCRM = 0x80, ++}; ++ ++enum lis302dl_reg_ffwusrc { ++ LIS302DL_FFWUSRC_XL = 0x01, ++ LIS302DL_FFWUSRC_XH = 0x02, ++ LIS302DL_FFWUSRC_YL = 0x04, ++ LIS302DL_FFWUSRC_YH = 0x08, ++ LIS302DL_FFWUSRC_ZL = 0x10, ++ LIS302DL_FFWUSRC_ZH = 0x20, ++ LIS302DL_FFWUSRC_IA = 0x40, ++}; ++ ++enum lis302dl_reg_cloik_src { ++ LIS302DL_CLICKSRC_SINGLE_X = 0x01, ++ LIS302DL_CLICKSRC_DOUBLE_X = 0x02, ++ LIS302DL_CLICKSRC_SINGLE_Y = 0x04, ++ LIS302DL_CLICKSRC_DOUBLE_Y = 0x08, ++ LIS302DL_CLICKSRC_SINGLE_Z = 0x10, ++ LIS302DL_CLICKSRC_DOUBLE_Z = 0x20, ++ LIS302DL_CLICKSRC_IA = 0x40, ++}; ++ ++#define LIS302DL_WHO_AM_I_MAGIC 0x3b ++ ++#define LIS302DL_F_WUP_FF_1 0x0001 /* wake up from free fall */ ++#define LIS302DL_F_WUP_FF_2 0x0002 ++#define LIS302DL_F_WUP_FF 0x0003 ++#define LIS302DL_F_WUP_CLICK 0x0004 ++#define LIS302DL_F_POWER 0x0010 ++#define LIS302DL_F_FS 0x0020 /* ADC full scale */ ++#define LIS302DL_F_INPUT_OPEN 0x0040 /* Set if input device is opened */ ++#define LIS302DL_F_IRQ_WAKE 0x0080 /* IRQ is setup in wake mode */ ++#define LIS302DL_F_DR 0x0100 /* Data rate, 400Hz/100Hz */ ++ ++ ++#endif /* _LINUX_LIS302DL_H */ ++ +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index af56071..83ad05d 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -292,6 +292,13 @@ struct spi_master { + int (*transfer)(struct spi_device *spi, + struct spi_message *mesg); + ++ /* ++ * Synchronous non blocking transfer function. Should guarantee ++ * data availability when it returns ++ */ ++ int (*transfer_sync)(struct spi_device *spi, ++ struct spi_message *mesg); ++ + /* called on release() to free memory provided by spi_master */ + void (*cleanup)(struct spi_device *spi); + }; +@@ -543,6 +550,29 @@ static inline void spi_message_free(struct spi_message *m) + extern int spi_setup(struct spi_device *spi); + extern int spi_async(struct spi_device *spi, struct spi_message *message); + ++/** ++ * spi_non_blocking_transfer - Synchronous, non blocking transfer ++ * @spi: device with which data will be exchanged ++ * @message: describes the data transfers with optional completion handlers ++ * Context: any (irqs may be blocked, etc) ++ * ++ * Data is guaranteed to be written or read when this function returns. ++ * ++ * Note : This may not be supported by all spi masters. ++ */ ++ ++static inline int ++spi_non_blocking_transfer(struct spi_device *spi, struct spi_message *message) ++{ ++ if (unlikely(!spi->master->transfer_sync)) { ++ dev_err(&spi->master->dev, ++ "non-blocking transfers not supported\n"); ++ return -EIO; ++ } ++ ++ return spi->master->transfer_sync(spi, message); ++} ++ + /*---------------------------------------------------------------------------*/ + + /* All these synchronous SPI transfer routines are utilities layered +diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h +index 3274c50..6dc9b8b 100644 +--- a/include/linux/spi/spi_bitbang.h ++++ b/include/linux/spi/spi_bitbang.h +@@ -31,6 +31,9 @@ struct spi_bitbang { + u8 use_dma; + u8 flags; /* extra spi->mode support */ + ++ /* Support for synchronous non blocking transfers */ ++ int non_blocking_transfer; ++ + struct spi_master *master; + + /* setup_transfer() changes clock and/or wordsize to match settings +@@ -62,6 +65,8 @@ extern void spi_bitbang_cleanup(struct spi_device *spi); + extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); + extern int spi_bitbang_setup_transfer(struct spi_device *spi, + struct spi_transfer *t); ++extern int spi_bitbang_transfer_sync(struct spi_device *spi, ++ struct spi_message *m); + + /* start or stop queue processing */ + extern int spi_bitbang_start(struct spi_bitbang *spi); +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0002-Glamo-DRM-and-KMS-driver.patch b/recipes/linux/linux-openmoko-2.6.34/0002-Glamo-DRM-and-KMS-driver.patch new file mode 100644 index 0000000000..14dca73ab2 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0002-Glamo-DRM-and-KMS-driver.patch @@ -0,0 +1,3869 @@ +From 4fe52e62cc86fc303cbc0f9a3c5081e38f95b950 Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Sat, 22 May 2010 19:01:00 +0200 +Subject: [PATCH 02/13] Glamo DRM and KMS driver + +This adds the Glamo DRM and KMS driver, but note that modifications are needed +elsewhere to support it. + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- + drivers/mfd/glamo/Kconfig | 16 + + drivers/mfd/glamo/Makefile | 5 +- + drivers/mfd/glamo/glamo-buffer.c | 374 +++++++++++++ + drivers/mfd/glamo/glamo-buffer.h | 60 ++ + drivers/mfd/glamo/glamo-cmdq.c | 555 +++++++++++++++++++ + drivers/mfd/glamo/glamo-cmdq.h | 49 ++ + drivers/mfd/glamo/glamo-display.c | 975 +++++++++++++++++++++++++++++++++ + drivers/mfd/glamo/glamo-display.h | 41 ++ + drivers/mfd/glamo/glamo-drm-drv.c | 423 ++++++++++++++ + drivers/mfd/glamo/glamo-drm-private.h | 166 ++++++ + drivers/mfd/glamo/glamo-fence.c | 330 +++++++++++ + drivers/mfd/glamo/glamo-fence.h | 34 ++ + drivers/mfd/glamo/glamo-kms-fb.c | 493 +++++++++++++++++ + drivers/mfd/glamo/glamo-kms-fb.h | 41 ++ + include/drm/Kbuild | 1 + + include/drm/glamo_drm.h | 153 +++++ + 16 files changed, 3715 insertions(+), 1 deletions(-) + create mode 100644 drivers/mfd/glamo/glamo-buffer.c + create mode 100644 drivers/mfd/glamo/glamo-buffer.h + create mode 100644 drivers/mfd/glamo/glamo-cmdq.c + create mode 100644 drivers/mfd/glamo/glamo-cmdq.h + create mode 100644 drivers/mfd/glamo/glamo-display.c + create mode 100644 drivers/mfd/glamo/glamo-display.h + create mode 100644 drivers/mfd/glamo/glamo-drm-drv.c + create mode 100644 drivers/mfd/glamo/glamo-drm-private.h + create mode 100644 drivers/mfd/glamo/glamo-fence.c + create mode 100644 drivers/mfd/glamo/glamo-fence.h + create mode 100644 drivers/mfd/glamo/glamo-kms-fb.c + create mode 100644 drivers/mfd/glamo/glamo-kms-fb.h + create mode 100644 include/drm/glamo_drm.h + +diff --git a/drivers/mfd/glamo/Kconfig b/drivers/mfd/glamo/Kconfig +index 3aa4831..a12ebf6 100644 +--- a/drivers/mfd/glamo/Kconfig ++++ b/drivers/mfd/glamo/Kconfig +@@ -40,3 +40,19 @@ config MFD_GLAMO_MCI + neo1973 GTA-02. + + If unsure, say N. ++ ++config MFD_GLAMO_DRM ++ tristate "Glamo direct rendering and kernel modesetting support" ++ depends on MFD_GLAMO && DRM ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ select DRM_KMS_HELPER ++ help ++ Direct Rendering Manager interface for the S-Media Glamo chip, as ++ used in Openmoko FreeRunner (GTA02). ++ ++ This DRM driver includes kernel modesetting (KMS) support. As such, ++ do not select MFD_GLAMO_FB above if you choose to enable this option. ++ ++ If unsure, say N. +diff --git a/drivers/mfd/glamo/Makefile b/drivers/mfd/glamo/Makefile +index ebf26f7..d5ebf8f 100644 +--- a/drivers/mfd/glamo/Makefile ++++ b/drivers/mfd/glamo/Makefile +@@ -1,5 +1,5 @@ + # +-# Makefile for the Smedia Glamo framebuffer driver ++# Makefile for the Smedia Glamo driver(s) + # + + obj-$(CONFIG_MFD_GLAMO) += glamo-core.o +@@ -8,4 +8,7 @@ obj-$(CONFIG_MFD_GLAMO_SPI) += glamo-spi.o + + obj-$(CONFIG_MFD_GLAMO_FB) += glamo-fb.o + obj-$(CONFIG_MFD_GLAMO_MCI) += glamo-mci.o ++obj-$(CONFIG_MFD_GLAMO_DRM) += glamo-drm.o + ++glamo-drm-objs := glamo-drm-drv.o glamo-cmdq.o glamo-buffer.o \ ++ glamo-display.o glamo-kms-fb.o glamo-fence.o +diff --git a/drivers/mfd/glamo/glamo-buffer.c b/drivers/mfd/glamo/glamo-buffer.c +new file mode 100644 +index 0000000..82ea0c0 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-buffer.c +@@ -0,0 +1,374 @@ ++/* ++ * SMedia Glamo 336x/337x memory management ++ * ++ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * ++ * Memory mapping functions based on i915_gem.c, to which the following ++ * notice applies: ++ * ++ * Copyright © 2008 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ * ++ * Authors: ++ * Eric Anholt <eric@anholt.net> ++ */ ++ ++ ++#include <drm/drmP.h> ++#include <drm/glamo_drm.h> ++ ++#include "glamo-drm-private.h" ++#include "glamo-cmdq.h" /* For glamo_cmdq_blank() */ ++ ++ ++struct drm_gem_object *glamo_gem_object_alloc(struct drm_device *dev, int size, ++ int alignment) ++{ ++ struct drm_gem_object *obj; ++ struct glamodrm_handle *gdrm; ++ struct drm_glamo_gem_object *gobj; ++ ++ gdrm = dev->dev_private; ++ ++ size = roundup(size, PAGE_SIZE); ++ ++ obj = drm_gem_object_alloc(dev, size); ++ if (obj == NULL) return NULL; ++ ++ /* See glamodrm_gem_init_object() below */ ++ gobj = obj->driver_private; ++ ++ /* Allocate memory for this object in VRAM */ ++ gobj->block = drm_mm_search_free(gdrm->mmgr, size, alignment, 1); ++ if (!gobj->block) { ++ goto fail; ++ } ++ gobj->block = drm_mm_get_block(gobj->block, size, alignment); ++ if (!gobj->block) { ++ goto fail; ++ } ++ ++ /* Arrange for the contents to be set to zero */ ++ glamo_cmdq_blank(gdrm, obj); ++ ++ return obj; ++ ++fail: ++ mutex_lock(&dev->struct_mutex); ++ drm_gem_object_unreference(obj); ++ mutex_unlock(&dev->struct_mutex); ++ printk(KERN_INFO "[glamo-drm] Failed to allocate object\n"); ++ ++ return NULL; ++} ++ ++ ++int glamo_ioctl_gem_create(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_glamo_gem_create *args = data; ++ struct drm_gem_object *obj; ++ int handle, ret, alignment, size; ++ ++ /* Alignment must be a non-zero multiple of 2 */ ++ alignment = args->alignment; ++ if ( alignment < 2 ) alignment = 2; ++ if ( alignment % 2 ) alignment *= 2; ++ ++ /* Size must be similarly sanitised */ ++ size = args->size; ++ if ( size < 2 ) size = 2; ++ if ( size % 2 ) size += 1; ++ ++ /* Create an object */ ++ obj = glamo_gem_object_alloc(dev, size, alignment); ++ if ( obj == NULL ) return -ENOMEM; ++ ++ /* Create a handle for it */ ++ ret = drm_gem_handle_create(file_priv, obj, &handle); ++ mutex_lock(&dev->struct_mutex); ++ drm_gem_object_handle_unreference(obj); ++ mutex_unlock(&dev->struct_mutex); ++ if (ret) goto fail; ++ ++ /* Return */ ++ args->handle = handle; ++ return 0; ++ ++fail: ++ mutex_lock(&dev->struct_mutex); ++ drm_gem_object_unreference(obj); ++ mutex_unlock(&dev->struct_mutex); ++ printk(KERN_INFO "[glamo-drm] Failed to allocate object\n"); ++ return ret; ++} ++ ++ ++int glamodrm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct drm_device *dev = obj->dev; ++ struct drm_glamo_gem_object *gobj = obj->driver_private; ++ struct glamodrm_handle *gdrm = dev->dev_private; ++ pgoff_t page_offset; ++ unsigned long pfn; ++ int ret = 0; ++ ++ /* We don't use vmf->pgoff since that has the fake offset */ ++ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> ++ PAGE_SHIFT; ++ ++ mutex_lock(&dev->struct_mutex); ++ pfn = ((gdrm->vram->start + GLAMO_OFFSET_FB + gobj->block->start) ++ >> PAGE_SHIFT) + page_offset; ++ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); ++ mutex_unlock(&dev->struct_mutex); ++ ++ switch (ret) { ++ case -ENOMEM: ++ case -EAGAIN: ++ return VM_FAULT_OOM; ++ case -EFAULT: ++ case -EBUSY: ++ DRM_ERROR("can't insert pfn?? fault or busy...\n"); ++ return VM_FAULT_SIGBUS; ++ default: ++ return VM_FAULT_NOPAGE; ++ } ++} ++ ++ ++static int glamo_gem_create_mmap_offset(struct drm_gem_object *obj) ++{ ++ struct drm_device *dev = obj->dev; ++ struct drm_gem_mm *mm = dev->mm_private; ++ struct drm_glamo_gem_object *gobj = obj->driver_private; ++ struct drm_map_list *list; ++ struct drm_local_map *map; ++ int ret = 0; ++ ++ /* Set the object up for mmap'ing */ ++ list = &obj->map_list; ++ list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); ++ if (!list->map) ++ return -ENOMEM; ++ ++ map = list->map; ++ map->type = _DRM_GEM; ++ map->size = obj->size; ++ map->handle = obj; ++ ++ /* Get a DRM GEM mmap offset allocated... */ ++ list->file_offset_node = drm_mm_search_free(&mm->offset_manager, ++ obj->size / PAGE_SIZE, 0, 0); ++ if (!list->file_offset_node) { ++ DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); ++ ret = -ENOMEM; ++ goto out_free_list; ++ } ++ ++ list->file_offset_node = drm_mm_get_block(list->file_offset_node, ++ obj->size / PAGE_SIZE, 0); ++ if (!list->file_offset_node) { ++ ret = -ENOMEM; ++ goto out_free_list; ++ } ++ ++ list->hash.key = list->file_offset_node->start; ++ if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) { ++ DRM_ERROR("failed to add to map hash\n"); ++ goto out_free_mm; ++ } ++ ++ /* By now we should be all set, any drm_mmap request on the offset ++ * below will get to our mmap & fault handler */ ++ gobj->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT; ++ ++ return 0; ++ ++out_free_mm: ++ drm_mm_put_block(list->file_offset_node); ++out_free_list: ++ kfree(list->map); ++ ++ return ret; ++} ++ ++ ++int glamo_ioctl_gem_mmap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_glamo_gem_mmap *args = data; ++ struct drm_gem_object *obj; ++ struct drm_glamo_gem_object *gobj; ++ int ret; ++ ++ obj = drm_gem_object_lookup(dev, file_priv, args->handle); ++ if (obj == NULL) ++ return -EBADF; ++ ++ mutex_lock(&dev->struct_mutex); ++ ++ gobj = obj->driver_private; ++ if (!gobj->mmap_offset) { ++ ret = glamo_gem_create_mmap_offset(obj); ++ if (ret) { ++ printk(KERN_CRIT "Couldn't create mmap offset\n"); ++ drm_gem_object_unreference(obj); ++ mutex_unlock(&dev->struct_mutex); ++ return ret; ++ } ++ } ++ ++ args->offset = gobj->mmap_offset; ++ ++ drm_gem_object_unreference(obj); ++ mutex_unlock(&dev->struct_mutex); ++ ++ return 0; ++} ++ ++ ++int glamo_ioctl_gem_pin(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ printk(KERN_INFO "glamo_ioctl_gem_pin\n"); ++ return 0; ++} ++ ++ ++int glamo_ioctl_gem_unpin(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ printk(KERN_INFO "glamo_ioctl_gem_unpin\n"); ++ return 0; ++} ++ ++ ++int glamo_ioctl_gem_pread(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ printk(KERN_INFO "glamo_ioctl_gem_pread\n"); ++ return 0; ++} ++ ++ ++int glamo_ioctl_gem_pwrite(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ printk(KERN_INFO "glamo_ioctl_gem_pwrite\n"); ++ return 0; ++} ++ ++ ++int glamodrm_gem_init_object(struct drm_gem_object *obj) ++{ ++ struct drm_glamo_gem_object *gobj; ++ ++ /* Allocate a private structure */ ++ gobj = kzalloc(sizeof(*gobj), GFP_KERNEL); ++ if (!gobj) return -ENOMEM; ++ ++ obj->driver_private = gobj; ++ gobj->obj = obj; ++ ++ return 0; ++} ++ ++ ++void glamodrm_gem_free_object(struct drm_gem_object *obj) ++{ ++ struct drm_glamo_gem_object *gobj; ++ struct drm_map_list *list; ++ struct drm_device *dev; ++ struct drm_gem_mm *mm; ++ struct drm_local_map *map; ++ ++ dev = obj->dev; ++ mm = dev->mm_private; ++ gobj = obj->driver_private; ++ ++ /* Free the VRAM */ ++ if ( gobj->block != NULL ) { ++ drm_mm_put_block(gobj->block); ++ } ++ ++ /* Release mappings */ ++ list = &obj->map_list; ++ drm_ht_remove_item(&mm->offset_hash, &list->hash); ++ if (list->file_offset_node) { ++ drm_mm_put_block(list->file_offset_node); ++ list->file_offset_node = NULL; ++ } ++ map = list->map; ++ if (map) { ++ kfree(map); ++ list->map = NULL; ++ } ++ ++ /* Free the private structure */ ++ kfree(obj->driver_private); ++} ++ ++ ++/* Memory management initialisation */ ++int glamo_buffer_init(struct glamodrm_handle *gdrm) ++{ ++ gdrm->mmgr = kzalloc(sizeof(struct drm_mm), GFP_KERNEL); ++ drm_mm_init(gdrm->mmgr, 0, gdrm->vram_size); ++ ++ /* Reserve a scratch buffer. We do this outside the protections ++ * of the other GEM code. To do this safely, the allocation must ++ * be a multiple of PAGE_SIZE. */ ++ gdrm->scratch = drm_mm_search_free(gdrm->mmgr, PAGE_SIZE, 4, 1); ++ if ( gdrm->scratch ) { ++ gdrm->scratch = drm_mm_get_block(gdrm->scratch, PAGE_SIZE, 4); ++ } ++ if ( !gdrm->scratch ) { ++ printk(KERN_WARNING "[glamo-drm] Couldn't allocate" ++ " scratch buffer!\n"); ++ } ++ ++ return 0; ++} ++ ++ ++/* Memory management finalisation */ ++int glamo_buffer_final(struct glamodrm_handle *gdrm) ++{ ++ drm_mm_takedown(gdrm->mmgr); ++ kfree(gdrm->mmgr); ++ return 0; ++} +diff --git a/drivers/mfd/glamo/glamo-buffer.h b/drivers/mfd/glamo/glamo-buffer.h +new file mode 100644 +index 0000000..41f18fd +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-buffer.h +@@ -0,0 +1,60 @@ ++/* ++ * SMedia Glamo 336x/337x memory management ++ * ++ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ */ ++ ++#ifndef __GLAMO_BUFFER_H ++#define __GLAMO_BUFFER_H ++ ++#include <drm/drmP.h> ++ ++#include "glamo-drm-private.h" ++ ++extern int glamo_buffer_init(struct glamodrm_handle *gdrm); ++extern int glamo_buffer_final(struct glamodrm_handle *gdrm); ++ ++extern int glamodrm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); ++ ++extern int glamodrm_gem_init_object(struct drm_gem_object *obj); ++ ++extern void glamodrm_gem_free_object(struct drm_gem_object *obj); ++ ++extern struct drm_gem_object *glamo_gem_object_alloc(struct drm_device *dev, ++ int size, int alignment); ++ ++extern int glamo_ioctl_gem_create(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern int glamo_ioctl_gem_mmap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern int glamo_ioctl_gem_pin(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern int glamo_ioctl_gem_unpin(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern int glamo_ioctl_gem_pread(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern int glamo_ioctl_gem_pwrite(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++#endif /* __GLAMO_BUFFER_H */ +diff --git a/drivers/mfd/glamo/glamo-cmdq.c b/drivers/mfd/glamo/glamo-cmdq.c +new file mode 100644 +index 0000000..442963c +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-cmdq.c +@@ -0,0 +1,555 @@ ++/* ++ * SMedia Glamo 336x/337x command queue handling ++ * ++ * Copyright (C) 2008-2009 Thomas White <taw@bitwiz.org.uk> ++ * Copyright (C) 2009 Andreas Pokorny <andreas.pokorny@gmail.com> ++ * Based on xf86-video-glamo (see below for details) ++ * ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ * Command queue handling functions based on those from xf86-video-glamo, to ++ * which the following licence applies: ++ * ++ * Copyright 2007 OpenMoko, Inc. ++ * Copyright © 2009 Lars-Peter Clausen <lars@metafoo.de> ++ * ++ * This driver is based on Xati, ++ * Copyright 2004 Eric Anholt ++ * ++ * Permission to use, copy, modify, distribute, and sell this software and its ++ * documentation for any purpose is hereby granted without fee, provided that ++ * the above copyright notice appear in all copies and that both that copyright ++ * notice and this permission notice appear in supporting documentation, and ++ * that the name of the copyright holders not be used in advertising or ++ * publicity pertaining to distribution of the software without specific, ++ * written prior permission. The copyright holders make no representations ++ * about the suitability of this software for any purpose. It is provided "as ++ * is" without express or implied warranty. ++ * ++ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO ++ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR ++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE ++ * OF THIS SOFTWARE. ++ */ ++ ++ ++#include <drm/drmP.h> ++#include <drm/glamo_drm.h> ++ ++#include "glamo-core.h" ++#include "glamo-drm-private.h" ++#include "glamo-regs.h" ++ ++ ++#define GLAMO_CMDQ_SIZE (128 * 1024) /* 128k ring buffer */ ++ ++ ++static inline void reg_write(struct glamodrm_handle *gdrm, ++ u_int16_t reg, u_int16_t val) ++{ ++ iowrite16(val, gdrm->reg_base + reg); ++} ++ ++ ++static inline u16 reg_read(struct glamodrm_handle *gdrm, u_int16_t reg) ++{ ++ return ioread16(gdrm->reg_base + reg); ++} ++ ++ ++static u32 glamo_get_read(struct glamodrm_handle *gdrm) ++{ ++ /* we could turn off clock here */ ++ u32 ring_read = reg_read(gdrm, GLAMO_REG_CMDQ_READ_ADDRL); ++ ring_read |= (reg_read(gdrm, GLAMO_REG_CMDQ_READ_ADDRH) & 0x7) << 16; ++ ++ return ring_read; ++} ++ ++ ++static u32 glamo_get_write(struct glamodrm_handle *gdrm) ++{ ++ u32 ring_write = reg_read(gdrm, GLAMO_REG_CMDQ_WRITE_ADDRL); ++ ring_write |= (reg_read(gdrm, GLAMO_REG_CMDQ_WRITE_ADDRH) & 0x7) << 16; ++ ++ return ring_write; ++} ++ ++ ++/* Add commands to the ring buffer */ ++int glamo_add_to_ring(struct glamodrm_handle *gdrm, u16 *addr, ++ unsigned int count) ++{ ++ size_t ring_write, ring_read; ++ size_t new_ring_write; ++ ++ if ( count >= GLAMO_CMDQ_SIZE ) { ++ printk(KERN_WARNING "[glamo-drm] CmdQ submission too large\n"); ++ return -EINVAL; ++ } ++ ++ down(&gdrm->add_to_ring); ++ ++ ring_write = glamo_get_write(gdrm); ++ ++ /* Calculate where we'll end up */ ++ new_ring_write = (ring_write + count) % GLAMO_CMDQ_SIZE; ++ ++ /* Wait until there is enough space to queue the cmd buffer */ ++ if (new_ring_write > ring_write) { ++ /* Loop while the read pointer is between the old and new ++ * positions */ ++ do { ++ ring_read = glamo_get_read(gdrm); ++ } while (ring_read > ring_write && ring_read < new_ring_write); ++ } else { ++ /* Same, but kind of inside-out */ ++ do { ++ ring_read = glamo_get_read(gdrm); ++ } while (ring_read > ring_write || ring_read < new_ring_write); ++ } ++ ++ /* Are we about to wrap around? */ ++ if (ring_write >= new_ring_write) { ++ ++ u32 rest_size; ++ ++ /* Wrap around */ ++ rest_size = GLAMO_CMDQ_SIZE - ring_write; /* Space left */ ++ ++ /* Write from current position to end */ ++ memcpy_toio(gdrm->cmdq_base+ring_write, addr, rest_size); ++ ++ /* Write from start */ ++ memcpy_toio(gdrm->cmdq_base, addr+(rest_size>>1), ++ count - rest_size); ++ ++ /* ring_write being 0 will result in a deadlock because the ++ * cmdq read will never stop. To avoid such an behaviour insert ++ * an empty instruction. */ ++ if (new_ring_write == 0) { ++ iowrite16(0x0000, gdrm->cmdq_base); ++ iowrite16(0x0000, gdrm->cmdq_base + 2); ++ new_ring_write = 4; ++ } ++ ++ } else { ++ ++ memcpy_toio(gdrm->cmdq_base+ring_write, addr, count); ++ ++ } ++ ++ reg_write(gdrm, GLAMO_REG_CMDQ_WRITE_ADDRH, ++ (new_ring_write >> 16) & 0x7f); ++ reg_write(gdrm, GLAMO_REG_CMDQ_WRITE_ADDRL, ++ new_ring_write & 0xffff); ++ ++ if ( !(reg_read(gdrm, GLAMO_REG_CMDQ_STATUS) & 1<<3) ) { ++ printk(KERN_ERR "[glamo-drm] CmdQ decode failure.\n"); ++ } ++ ++ up(&gdrm->add_to_ring); ++ ++ return 0; ++} ++ ++ ++/* Return true for a legal sequence of commands, otherwise false */ ++static int glamo_sanitize_buffer(u16 *cmds, unsigned int count) ++{ ++ /* XXX FIXME TODO: Implementation... */ ++ return 1; ++} ++ ++ ++/* Substitute the real addresses in VRAM for any required buffer objects */ ++static int glamo_do_relocation(struct glamodrm_handle *gdrm, ++ drm_glamo_cmd_buffer_t *cbuf, u16 *cmds, ++ struct drm_device *dev, ++ struct drm_file *file_priv) ++{ ++ u32 *handles; ++ int *offsets; ++ int nobjs = cbuf->nobjs; ++ int i; ++ ++ if ( nobjs > 32 ) return -EINVAL; /* Get real... */ ++ ++ handles = kmalloc(nobjs*sizeof(u32), GFP_KERNEL); ++ if ( handles == NULL ) return -1; ++ if ( copy_from_user(handles, cbuf->objs, nobjs*sizeof(u32)) ) ++ return -1; ++ ++ offsets = kmalloc(nobjs*sizeof(int), GFP_KERNEL); ++ if ( offsets == NULL ) return -1; ++ if ( copy_from_user(offsets, cbuf->obj_pos, nobjs*sizeof(int)) ) ++ return -1; ++ ++ for ( i=0; i<nobjs; i++ ) { ++ ++ u32 handle = handles[i]; ++ int offset = offsets[i]; ++ struct drm_gem_object *obj; ++ struct drm_glamo_gem_object *gobj; ++ u32 addr; ++ u16 addr_low, addr_high; ++ ++ if ( offset > cbuf->bufsz ) { ++ printk(KERN_WARNING "[glamo-drm] Offset out of range" ++ " for this relocation!\n"); ++ goto fail; ++ } ++ ++ obj = drm_gem_object_lookup(dev, file_priv, handle); ++ if ( obj == NULL ) return -1; ++ ++ /* Unref the object now, or it'll never get freed. ++ * This should really happen after the GPU has finished ++ * the commands which are about to be submitted. */ ++ drm_gem_object_unreference(obj); ++ ++ gobj = obj->driver_private; ++ if ( gobj == NULL ) { ++ printk(KERN_WARNING "[glamo-drm] This object has no" ++ " private data!\n"); ++ goto fail; ++ } ++ ++ addr = GLAMO_OFFSET_FB + gobj->block->start; ++ addr_low = addr & 0xffff; ++ addr_high = (addr >> 16) & 0x7f; ++ ++ /* FIXME: Should really check that the register is a ++ * valid one for this relocation. */ ++ ++ *(cmds+(offset/2)+1) = addr_low; ++ *(cmds+(offset/2)+3) = addr_high; ++ ++ } ++ ++ kfree(handles); ++ kfree(offsets); ++ return 0; ++ ++fail: ++ kfree(handles); ++ kfree(offsets); ++ return -1; ++} ++ ++ ++/* This is DRM_IOCTL_GLAMO_CMDBUF */ ++int glamo_ioctl_cmdbuf(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ int ret = 0; ++ struct glamodrm_handle *gdrm; ++ unsigned int count; ++ drm_glamo_cmd_buffer_t *cbuf = data; ++ u16 *cmds; ++ ++ gdrm = dev->dev_private; ++ ++ count = cbuf->bufsz; ++ ++ if ( count > PAGE_SIZE ) return -EINVAL; ++ ++ cmds = kmalloc(count, GFP_KERNEL); ++ if ( cmds == NULL ) return -ENOMEM; ++ if ( copy_from_user(cmds, cbuf->buf, count) ) { ++ printk(KERN_WARNING "[glamo-drm] copy from user failed\n"); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ ++ /* Check the buffer isn't going to tell Glamo to enact naughtiness */ ++ if ( !glamo_sanitize_buffer(cmds, count) ) { ++ printk(KERN_WARNING "[glamo-drm] sanitize buffer failed\n"); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ ++ /* Perform relocation, if necessary */ ++ if ( cbuf->nobjs ) { ++ if ( glamo_do_relocation(gdrm, cbuf, cmds, dev, file_priv) ) ++ { ++ printk(KERN_WARNING "[glamo-drm] Relocation failed\n"); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ } ++ ++ glamo_add_to_ring(gdrm, cmds, count); ++ ++cleanup: ++ kfree(cmds); ++ ++ return ret; ++} ++ ++ ++/* Return true for a legal sequence of commands, otherwise false */ ++static int glamo_sanitize_burst(u16 base, u16 *cmds, unsigned int count) ++{ ++ /* XXX FIXME TODO: Implementation... */ ++ return 1; ++} ++ ++ ++static int glamo_relocate_burst(struct glamodrm_handle *gdrm, ++ drm_glamo_cmd_burst_t *cbuf, u16 *data, ++ struct drm_device *dev, ++ struct drm_file *file_priv) ++{ ++ u32 *handles; ++ int *offsets; ++ int nobjs = cbuf->nobjs; ++ int i; ++ ++ if ( nobjs > 32 ) return -EINVAL; /* Get real... */ ++ ++ handles = kmalloc(nobjs*sizeof(u32), GFP_KERNEL); ++ if ( handles == NULL ) return -1; ++ if ( copy_from_user(handles, cbuf->objs, nobjs*sizeof(u32)) ) ++ return -1; ++ ++ offsets = kmalloc(nobjs*sizeof(int), GFP_KERNEL); ++ if ( offsets == NULL ) return -1; ++ if ( copy_from_user(offsets, cbuf->obj_pos, nobjs*sizeof(int)) ) ++ return -1; ++ ++ for ( i=0; i<nobjs; i++ ) { ++ ++ u32 handle = handles[i]; ++ int offset = offsets[i]; ++ struct drm_gem_object *obj; ++ struct drm_glamo_gem_object *gobj; ++ u32 addr; ++ u16 addr_low, addr_high; ++ ++ if ( offset > cbuf->bufsz ) { ++ printk(KERN_WARNING "[glamo-drm] Offset out of range" ++ " for this relocation!\n"); ++ goto fail; ++ } ++ ++ obj = drm_gem_object_lookup(dev, file_priv, handle); ++ if ( obj == NULL ) return -1; ++ ++ /* Unref the object now, or it'll never get freed. ++ * FIXME: This should really happen after the GPU has ++ * finished executing these commands. */ ++ drm_gem_object_unreference(obj); ++ ++ gobj = obj->driver_private; ++ if ( gobj == NULL ) { ++ printk(KERN_WARNING "[glamo-drm] This object has no" ++ " private data!\n"); ++ goto fail; ++ } ++ ++ addr = GLAMO_OFFSET_FB + gobj->block->start; ++ addr_low = addr & 0xffff; ++ addr_high = (addr >> 16) & 0x7f; ++ ++ /* FIXME: Should really check that the register is a ++ * valid one for this relocation. */ ++ ++ *(data+(offset/2)+0) = addr_low; ++ *(data+(offset/2)+1) = addr_high; ++ ++ } ++ ++ kfree(handles); ++ kfree(offsets); ++ return 0; ++ ++fail: ++ kfree(handles); ++ kfree(offsets); ++ return -1; ++} ++ ++ ++/* This is DRM_IOCTL_GLAMO_CMDBURST */ ++int glamo_ioctl_cmdburst(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ int ret = 0; ++ struct glamodrm_handle *gdrm; ++ drm_glamo_cmd_burst_t *cbuf = data; ++ u16 *burst; ++ size_t burst_size; ++ size_t data_size; ++ ++ gdrm = dev->dev_private; ++ ++ data_size = cbuf->bufsz; ++ if ( data_size % 4 ) data_size += 2; ++ if ( data_size % 4 ) return -EINVAL; ++ burst_size = data_size + 4; /* Add space for header */ ++ if ( burst_size > PAGE_SIZE ) return -EINVAL; ++ ++ burst = kmalloc(burst_size, GFP_KERNEL); ++ if ( burst == NULL ) return -ENOMEM; ++ ++ /* Get data from userspace */ ++ if ( copy_from_user(burst+2, cbuf->data, cbuf->bufsz) ) { ++ printk(KERN_WARNING "[glamo-drm] copy from user failed\n"); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ ++ /* Sanitise */ ++ if ( !glamo_sanitize_burst(cbuf->base, burst+2, cbuf->bufsz) ) { ++ printk(KERN_WARNING "[glamo-drm] sanitize buffer failed\n"); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ ++ /* Relocate */ ++ if ( cbuf->nobjs ) { ++ if ( glamo_relocate_burst(gdrm, cbuf, burst+2, dev, file_priv) ) ++ { ++ printk(KERN_WARNING "[glamo-drm] Relocation failed\n"); ++ ret = -EINVAL; ++ goto cleanup; ++ } ++ } ++ ++ /* Add burst header */ ++ burst[0] = 1<<15 | cbuf->base; ++ burst[1] = data_size / 2; /* -> 2-byte words */ ++ if ( burst[1] & 0x01 ) { ++ printk(KERN_WARNING "[glamo-drm] Burst not aligned!\n"); ++ goto cleanup; ++ } ++ ++ /* Zero-pad if necessary */ ++ if ( data_size % 4 ) { ++ burst[burst_size-1] = 0x0000; ++ } ++ ++ /* Add to command queue */ ++ glamo_add_to_ring(gdrm, burst, burst_size); ++ ++cleanup: ++ kfree(burst); ++ ++ return ret; ++} ++ ++ ++int glamo_cmdq_setup(struct glamodrm_handle *gdrm) ++{ ++ unsigned int i; ++ ++ init_MUTEX(&gdrm->add_to_ring); ++ ++ /* Enable 2D and 3D */ ++ glamo_engine_enable(gdrm->glamo_core, GLAMO_ENGINE_2D); ++ glamo_engine_reset(gdrm->glamo_core, GLAMO_ENGINE_2D); ++ ++ /* Start by zeroing the command queue memory */ ++ for ( i=0; i<GLAMO_CMDQ_SIZE; i+=2 ) { ++ iowrite16(0x0000, gdrm->cmdq_base+i); ++ } ++ ++ glamo_engine_enable(gdrm->glamo_core, GLAMO_ENGINE_CMDQ); ++ glamo_engine_reset(gdrm->glamo_core, GLAMO_ENGINE_CMDQ); ++ ++ /* Set up command queue location */ ++ reg_write(gdrm, GLAMO_REG_CMDQ_BASE_ADDRL, ++ gdrm->cmdq_offs & 0xffff); ++ reg_write(gdrm, GLAMO_REG_CMDQ_BASE_ADDRH, ++ (gdrm->cmdq_offs >> 16) & 0x7f); ++ ++ /* Length of command queue in 1k blocks, minus one */ ++ reg_write(gdrm, GLAMO_REG_CMDQ_LEN, (GLAMO_CMDQ_SIZE >> 10)-1); ++ reg_write(gdrm, GLAMO_REG_CMDQ_WRITE_ADDRH, 0); ++ reg_write(gdrm, GLAMO_REG_CMDQ_WRITE_ADDRL, 0); ++ reg_write(gdrm, GLAMO_REG_CMDQ_CONTROL, ++ 1 << 12 | /* Turbo flip (?) */ ++ 5 << 8 | /* no interrupt */ ++ 8 << 4); /* HQ threshold */ ++ ++ return 0; ++} ++ ++ ++int glamo_cmdq_init(struct glamodrm_handle *gdrm) ++{ ++ struct drm_gem_object *obj; ++ struct drm_glamo_gem_object *gobj; ++ int ret = 0; ++ ++ obj = glamo_gem_object_alloc(dev, GLAMO_CMDQ_SIZE, 4); ++ if ( !obj ) { ++ printk(KERN_ERR "[glamo-drm] Failed to allocate CmdQ\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ gobj = fbo->driver_private; ++ gdrm->cmdq_offs = GLAMO_OFFSET_FB + gobj->block->start; ++ gdrm->cmdq_base = ioremap(gdrm->vram->start + offs, GLAMO_CMDQ_SIZE); ++ ++ /* Set up registers */ ++ glamo_cmdq_setup(gdrm); ++ ++out: ++ return ret; ++} ++ ++ ++int glamo_cmdq_shutdown(struct glamodrm_handle *gdrm) ++{ ++ return 0; ++} ++ ++ ++void glamo_cmdq_suspend(struct glamodrm_handle *gdrm) ++{ ++ /* Placeholder... */ ++} ++ ++ ++void glamo_cmdq_resume(struct glamodrm_handle *gdrm) ++{ ++ glamo_cmdq_setup(gdrm); ++} ++ ++ ++/* Initialise an object's contents to zero. ++ * This is in glamo-cmdq.c in the hope that we can accelerate it later. */ ++void glamo_cmdq_blank(struct glamodrm_handle *gdrm, struct drm_gem_object *obj) ++{ ++ char __iomem *cookie; ++ struct drm_glamo_gem_object *gobj; ++ int i; ++ ++ gobj = obj->driver_private; ++ ++ cookie = ioremap(gdrm->vram->start + gobj->block->start, obj->size); ++ for ( i=0; i<obj->size; i+=2 ) { ++ iowrite16(0, cookie+i); ++ } ++ iounmap(cookie); ++} +diff --git a/drivers/mfd/glamo/glamo-cmdq.h b/drivers/mfd/glamo/glamo-cmdq.h +new file mode 100644 +index 0000000..510d195 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-cmdq.h +@@ -0,0 +1,49 @@ ++/* Smedia Glamo 336x/337x command queue handling ++ * ++ * Copyright (c) 2008-2009 Thomas White <taw@bitwiz.org.uk> ++ * Copyright (c) 2009 Andreas Pokorny <andreas.pokorny@gmail.com> ++ * Based on xf86-video-glamo ++ * Copyright 2007 OpenMoko, Inc. ++ * Copyright © 2009 Lars-Peter Clausen <lars@metafoo.de> ++ * ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#ifndef __GLAMO_CMDQ_H ++#define __GLAMO_CMDQ_H ++ ++#include <drm/drmP.h> ++ ++#include "glamo-drm-private.h" ++ ++extern int glamo_ioctl_cmdbuf(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int glamo_ioctl_cmdburst(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern void glamo_cmdq_blank(struct glamodrm_handle *gdrm, ++ struct drm_gem_object *obj); ++ ++extern int glamo_cmdq_init(struct glamodrm_handle *gdrm); ++extern int glamo_cmdq_shutdown(struct glamodrm_handle *gdrm); ++extern void glamo_cmdq_suspend(struct glamodrm_handle *gdrm); ++extern void glamo_cmdq_resume(struct glamodrm_handle *gdrm); ++ ++extern int glamo_add_to_ring(struct glamodrm_handle *gdrm, u16 *addr, ++ unsigned int count); ++ ++#endif /* __GLAMO_CMDQ_H */ +diff --git a/drivers/mfd/glamo/glamo-display.c b/drivers/mfd/glamo/glamo-display.c +new file mode 100644 +index 0000000..75ad734 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-display.c +@@ -0,0 +1,975 @@ ++/* ++ * SMedia Glamo 336x/337x display ++ * ++ * Copyright (C) 2008-2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * Based on glamo-fb.c (C) 2007-2008 by Openmoko, Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ * ++ * Based on intel_display.c and intel_crt.c from drivers/gpu/drm/i915 ++ * to which the following licence applies: ++ * ++ * Copyright © 2006-2007 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Eric Anholt <eric@anholt.net> ++ * ++ */ ++ ++#include <drm/drmP.h> ++#include <drm/glamo_drm.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_crtc.h> ++#include <linux/glamofb.h> ++#include <linux/jbt6k74.h> ++ ++#include "glamo-core.h" ++#include "glamo-drm-private.h" ++#include "glamo-regs.h" ++#include "glamo-kms-fb.h" ++#include "glamo-display.h" ++ ++ ++#define GLAMO_LCD_WIDTH_MASK 0x03FF ++#define GLAMO_LCD_HEIGHT_MASK 0x03FF ++#define GLAMO_LCD_PITCH_MASK 0x07FE ++#define GLAMO_LCD_HV_TOTAL_MASK 0x03FF ++#define GLAMO_LCD_HV_RETR_START_MASK 0x03FF ++#define GLAMO_LCD_HV_RETR_END_MASK 0x03FF ++#define GLAMO_LCD_HV_RETR_DISP_START_MASK 0x03FF ++#define GLAMO_LCD_HV_RETR_DISP_END_MASK 0x03FF ++ ++ ++struct glamofb_par { ++ struct drm_device *dev; ++ struct drm_display_mode *our_mode; ++ struct glamo_framebuffer *glamo_fb; ++ int crtc_count; ++ /* crtc currently bound to this */ ++ uint32_t crtc_ids[2]; ++}; ++ ++ ++static int reg_read_lcd(struct glamodrm_handle *gdrm, u_int16_t reg) ++{ ++ int i = 0; ++ ++ for (i = 0; i != 2; i++) ++ nop(); ++ ++ return ioread16(gdrm->lcd_base + reg); ++} ++ ++ ++static void reg_write_lcd(struct glamodrm_handle *gdrm, ++ u_int16_t reg, u_int16_t val) ++{ ++ int i = 0; ++ ++ for (i = 0; i != 2; i++) ++ nop(); ++ ++ iowrite16(val, gdrm->lcd_base + reg); ++} ++ ++ ++static void reg_set_bit_mask_lcd(struct glamodrm_handle *gdrm, ++ u_int16_t reg, u_int16_t mask, ++ u_int16_t val) ++{ ++ u_int16_t tmp; ++ ++ val &= mask; ++ ++ tmp = reg_read_lcd(gdrm, reg); ++ tmp &= ~mask; ++ tmp |= val; ++ reg_write_lcd(gdrm, reg, tmp); ++} ++ ++ ++/* Note that this has nothing at all to do with the engine command queue ++ * in glamo-cmdq.c */ ++static inline int glamo_lcd_cmdq_empty(struct glamodrm_handle *gdrm) ++{ ++ /* DGCMdQempty -- 1 == command queue is empty */ ++ return reg_read_lcd(gdrm, GLAMO_REG_LCD_STATUS1) & (1 << 15); ++} ++ ++ ++/* call holding gfb->lock_cmd when locking, until you unlock */ ++int glamo_lcd_cmd_mode(struct glamodrm_handle *gdrm, int on) ++{ ++ int timeout = 2000000; ++ ++ dev_dbg(gdrm->dev, "glamofb_cmd_mode(on=%d)\n", on); ++ if (on) { ++ ++ while ((!glamo_lcd_cmdq_empty(gdrm)) && (timeout--)) ++ /* yield() */; ++ if (timeout < 0) { ++ printk(KERN_ERR "*************" ++ " LCD command queue never got empty " ++ "*************\n"); ++ return -EIO; ++ } ++ ++ /* display the entire frame then switch to command */ ++ reg_write_lcd(gdrm, GLAMO_REG_LCD_COMMAND1, ++ GLAMO_LCD_CMD_TYPE_DISP | ++ GLAMO_LCD_CMD_DATA_FIRE_VSYNC); ++ ++ /* wait until lcd idle */ ++ timeout = 2000000; ++ while ((!reg_read_lcd(gdrm, GLAMO_REG_LCD_STATUS2) & (1 << 12)) ++ && (timeout--)) ++ /* yield() */; ++ if (timeout < 0) { ++ printk(KERN_ERR"*************" ++ " LCD never idle " ++ "*************\n"); ++ return -EIO; ++ } ++ ++ mdelay(100); ++ ++ } else { ++ /* RGB interface needs vsync/hsync */ ++ int mode; ++ mode = reg_read_lcd(gdrm, GLAMO_REG_LCD_MODE3); ++ if ( mode & GLAMO_LCD_MODE3_RGB) ++ reg_write_lcd(gdrm, GLAMO_REG_LCD_COMMAND1, ++ GLAMO_LCD_CMD_TYPE_DISP | ++ GLAMO_LCD_CMD_DATA_DISP_SYNC); ++ ++ reg_write_lcd(gdrm, GLAMO_REG_LCD_COMMAND1, ++ GLAMO_LCD_CMD_TYPE_DISP | ++ GLAMO_LCD_CMD_DATA_DISP_FIRE); ++ } ++ ++ return 0; ++} ++ ++ ++static struct glamo_script lcd_init_script[] = { ++ { GLAMO_REG_LCD_MODE1, 0x0020 }, ++ /* no display rotation, no hardware cursor, no dither, no gamma, ++ * no retrace flip, vsync low-active, hsync low active, ++ * no TVCLK, no partial display, hw dest color from fb, ++ * no partial display mode, LCD1, software flip, */ ++ { GLAMO_REG_LCD_MODE2, 0x9020 }, ++ /* video flip, no ptr, no ptr, dhclk off, ++ * normal mode, no cpuif, ++ * res, serial msb first, single fb, no fr ctrl, ++ * cpu if bits all zero, no crc ++ * 0000 0000 0010 0000 */ ++ { GLAMO_REG_LCD_MODE3, 0x0b40 }, ++ /* src data rgb565, res, 18bit rgb666 ++ * 000 01 011 0100 0000 */ ++ { GLAMO_REG_LCD_POLARITY, 0x440c }, ++ /* DE high active, no cpu/lcd if, cs0 force low, a0 low active, ++ * np cpu if, 9bit serial data, sclk rising edge latch data ++ * 01 00 0 100 0 000 01 0 0 */ ++ /* The following values assume 640*480@16bpp */ ++ /* FIXME: fb0 has not yet been allocated! */ ++ { GLAMO_REG_LCD_A_BASE1, PAGE_SIZE }, /* display A base address 15:0 */ ++ { GLAMO_REG_LCD_A_BASE2, 0x0000 }, /* display A base address 22:16 */ ++ { GLAMO_REG_LCD_B_BASE1, 0x6000 }, /* display B base address 15:0 */ ++ { GLAMO_REG_LCD_B_BASE2, 0x0009 }, /* display B base address 22:16 */ ++ { GLAMO_REG_LCD_CURSOR_BASE1, 0xC000 }, /* cursor base address 15:0 */ ++ { GLAMO_REG_LCD_CURSOR_BASE2, 0x0012 }, /* cursor base address 22:16 */ ++ { GLAMO_REG_LCD_COMMAND2, 0x0000 }, /* display page A */ ++}; ++ ++ ++static int glamo_run_lcd_script(struct glamodrm_handle *gdrm, ++ struct glamo_script *script, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ struct glamo_script *line = &script[i]; ++ ++ if (line->reg == 0xffff) ++ return 0; ++ else if (line->reg == 0xfffe) ++ msleep(line->val); ++ else ++ reg_write_lcd(gdrm, script[i].reg, script[i].val); ++ } ++ ++ return 0; ++} ++ ++ ++static bool glamo_crtc_mode_fixup(struct drm_crtc *crtc, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ return true; ++} ++ ++ ++static int glamo_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ++ struct drm_framebuffer *old_fb) ++{ ++ struct glamodrm_handle *gdrm; ++ struct glamo_crtc *gcrtc; ++ struct glamo_framebuffer *gfb; ++ struct drm_gem_object *obj; ++ struct drm_glamo_gem_object *gobj; ++ u32 addr; ++ u16 addr_low, addr_high; ++ ++ if (!crtc->fb) { ++ DRM_DEBUG("No FB bound\n"); ++ return -EINVAL; ++ } ++ ++ /* Dig out our handle */ ++ gcrtc = to_glamo_crtc(crtc); ++ gdrm = gcrtc->gdrm; /* Here it is! */ ++ ++ if ( !gcrtc->pixel_clock_on ) { ++ printk(KERN_WARNING "[glamo-drm] Display is off - " ++ "enabling it before setting base.\n"); ++ glamo_lcd_power(gdrm, 1); ++ } ++ ++ gfb = to_glamo_framebuffer(crtc->fb); ++ obj = gfb->obj; ++ gobj = obj->driver_private; ++ ++ addr = GLAMO_OFFSET_FB + gobj->block->start; ++ addr_low = addr & 0xffff; ++ addr_high = ((addr >> 16) & 0x7f) | 0x4000; ++ ++ glamo_lcd_cmd_mode(gdrm, 1); ++ reg_write_lcd(gdrm, GLAMO_REG_LCD_A_BASE1, addr_low); ++ reg_write_lcd(gdrm, GLAMO_REG_LCD_A_BASE2, addr_high); ++ glamo_lcd_cmd_mode(gdrm, 0); ++ ++ return 0; ++} ++ ++ ++static int glamo_crtc_mode_set(struct drm_crtc *crtc, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode, ++ int x, int y, ++ struct drm_framebuffer *old_fb) ++{ ++ struct glamodrm_handle *gdrm; ++ struct glamo_crtc *gcrtc; ++ int retr_start, retr_end, disp_start, disp_end; ++ int rot; ++ ++ /* Dig out our handle */ ++ gcrtc = to_glamo_crtc(crtc); ++ gdrm = gcrtc->gdrm; /* Here it is! */ ++ ++ if ( !gcrtc->pixel_clock_on ) { ++ printk(KERN_WARNING "[glamo-drm] Display is off - " ++ "enabling it before setting mode.\n"); ++ glamo_lcd_power(gdrm, 1); ++ msleep(500); ++ } ++ ++ /* Rotate? */ ++ if ( (mode->hdisplay == 640) && (mode->vdisplay == 480) ) { ++ rot = GLAMO_LCD_ROT_MODE_90; ++ } else if ( (mode->hdisplay == 480) && (mode->vdisplay == 640) ) { ++ rot = GLAMO_LCD_ROT_MODE_0; ++ } else if ( (mode->hdisplay == 320) && (mode->vdisplay == 240) ) { ++ rot = GLAMO_LCD_ROT_MODE_90; ++ } else if ( (mode->hdisplay == 240) && (mode->vdisplay == 320) ) { ++ rot = GLAMO_LCD_ROT_MODE_0; ++ } else { ++ printk(KERN_WARNING "[glamo-drm] Couldn't choose rotation.\n"); ++ rot = GLAMO_LCD_ROT_MODE_0; ++ } ++ ++ glamo_lcd_cmd_mode(gdrm, 1); ++ ++ /* Set dimensions */ ++ if ( rot == GLAMO_LCD_ROT_MODE_0 ) { ++ ++ glamo_engine_reclock(gdrm->glamo_core, GLAMO_ENGINE_LCD, ++ mode->clock); ++ ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_WIDTH, ++ GLAMO_LCD_WIDTH_MASK, mode->hdisplay); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HEIGHT, ++ GLAMO_LCD_HEIGHT_MASK, mode->vdisplay); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_PITCH, ++ GLAMO_LCD_PITCH_MASK, mode->hdisplay*2); ++ ++ /* Set rotation */ ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_WIDTH, ++ GLAMO_LCD_ROT_MODE_MASK, rot); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_MODE1, ++ GLAMO_LCD_MODE1_ROTATE_EN, ++ (rot != GLAMO_LCD_ROT_MODE_0) ? ++ GLAMO_LCD_MODE1_ROTATE_EN : 0); ++ ++ /* Convert "X modeline timings" into "Glamo timings" */ ++ retr_start = 0; ++ retr_end = retr_start + mode->hsync_end - mode->hsync_start; ++ disp_start = mode->htotal - mode->hsync_start; ++ disp_end = disp_start + mode->hdisplay; ++ ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_TOTAL, ++ GLAMO_LCD_HV_TOTAL_MASK, mode->htotal); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_RETR_START, ++ GLAMO_LCD_HV_RETR_START_MASK, retr_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_RETR_END, ++ GLAMO_LCD_HV_RETR_END_MASK, retr_end); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_DISP_START, ++ GLAMO_LCD_HV_RETR_DISP_START_MASK, disp_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_DISP_END, ++ GLAMO_LCD_HV_RETR_DISP_END_MASK, disp_end); ++ ++ /* The same in the vertical direction */ ++ retr_start = 0; ++ retr_end = retr_start + mode->vsync_end - mode->vsync_start; ++ disp_start = mode->vtotal - mode->vsync_start; ++ disp_end = disp_start + mode->vdisplay; ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_TOTAL, ++ GLAMO_LCD_HV_TOTAL_MASK, mode->vtotal); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_RETR_START, ++ GLAMO_LCD_HV_RETR_START_MASK, retr_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_RETR_END, ++ GLAMO_LCD_HV_RETR_END_MASK, retr_end); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_DISP_START, ++ GLAMO_LCD_HV_RETR_DISP_START_MASK, ++ disp_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_DISP_END, ++ GLAMO_LCD_HV_RETR_DISP_END_MASK, disp_end); ++ ++ } else { ++ ++ glamo_engine_reclock(gdrm->glamo_core, GLAMO_ENGINE_LCD, ++ mode->clock/2); ++ ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_WIDTH, ++ GLAMO_LCD_WIDTH_MASK, mode->vdisplay); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HEIGHT, ++ GLAMO_LCD_HEIGHT_MASK, mode->hdisplay); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_PITCH, ++ GLAMO_LCD_PITCH_MASK, mode->hdisplay*2); ++ ++ /* Set rotation */ ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_WIDTH, ++ GLAMO_LCD_ROT_MODE_MASK, rot); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_MODE1, ++ GLAMO_LCD_MODE1_ROTATE_EN, ++ (rot != GLAMO_LCD_ROT_MODE_0) ? ++ GLAMO_LCD_MODE1_ROTATE_EN : 0); ++ ++ /* Apply "vertical" numbers to the horizontal registers */ ++ retr_start = 0; ++ retr_end = retr_start + mode->vsync_end - mode->vsync_start; ++ disp_start = mode->vtotal - mode->vsync_start; ++ disp_end = disp_start + mode->vdisplay; ++ ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_TOTAL, ++ GLAMO_LCD_HV_TOTAL_MASK, mode->vtotal); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_RETR_START, ++ GLAMO_LCD_HV_RETR_START_MASK, retr_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_RETR_END, ++ GLAMO_LCD_HV_RETR_END_MASK, retr_end); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_DISP_START, ++ GLAMO_LCD_HV_RETR_DISP_START_MASK, ++ disp_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_HORIZ_DISP_END, ++ GLAMO_LCD_HV_RETR_DISP_END_MASK, disp_end); ++ ++ /* Apply "horizontal" numbers to the vertical registers */ ++ retr_start = 0; ++ retr_end = retr_start + mode->hsync_end - mode->hsync_start; ++ disp_start = mode->htotal - mode->hsync_start; ++ disp_end = disp_start + mode->hdisplay; ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_TOTAL, ++ GLAMO_LCD_HV_TOTAL_MASK, mode->htotal); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_RETR_START, ++ GLAMO_LCD_HV_RETR_START_MASK, retr_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_RETR_END, ++ GLAMO_LCD_HV_RETR_END_MASK, retr_end); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_DISP_START, ++ GLAMO_LCD_HV_RETR_DISP_START_MASK, ++ disp_start); ++ reg_set_bit_mask_lcd(gdrm, GLAMO_REG_LCD_VERT_DISP_END, ++ GLAMO_LCD_HV_RETR_DISP_END_MASK, disp_end); ++ ++ } ++ ++ gdrm->saved_clock = mode->clock; ++ ++ glamo_lcd_cmd_mode(gdrm, 0); ++ ++ glamo_crtc_mode_set_base(crtc, 0, 0, old_fb); ++ ++ if ( mode->hdisplay == 240 ) { ++ jbt6k74_finish_resolutionchange(JBT_RESOLUTION_QVGA); ++ } else { ++ jbt6k74_finish_resolutionchange(JBT_RESOLUTION_VGA); ++ } ++ ++ gcrtc->current_mode = *mode; ++ gcrtc->current_mode_set = 1; ++ gcrtc->current_fb = old_fb; ++ ++ return 0; ++} ++ ++ ++/* This is not the right place to switch power on/off, because the helper ++ * stuff ends up calling this before/after setting the mode. We can't ++ * set modes with the display off (although backlight off would be OK) */ ++static void glamo_crtc_dpms(struct drm_crtc *crtc, int mode) ++{ ++ /* do nothing */ ++} ++ ++ ++static void glamo_crtc_prepare(struct drm_crtc *crtc) ++{ ++} ++ ++ ++static void glamo_crtc_commit(struct drm_crtc *crtc) ++{ ++} ++ ++ ++static int glamo_crtc_cursor_set(struct drm_crtc *crtc, ++ struct drm_file *file_priv, ++ uint32_t handle, ++ uint32_t width, uint32_t height) ++{ ++ return 0; ++} ++ ++ ++static int glamo_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) ++{ ++ return 0; ++} ++ ++ ++static void glamo_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, ++ u16 *blue, uint32_t size) ++{ ++} ++ ++ ++static void glamo_crtc_destroy(struct drm_crtc *crtc) ++{ ++ struct glamo_crtc *glamo_crtc = to_glamo_crtc(crtc); ++ drm_crtc_cleanup(crtc); ++ kfree(glamo_crtc); ++} ++ ++ ++static enum drm_connector_status ++glamo_connector_detect(struct drm_connector *connector) ++{ ++ /* One hopes it hasn't been de-soldered... */ ++ return connector_status_connected; ++} ++ ++ ++static void glamo_connector_destroy(struct drm_connector *connector) ++{ ++ drm_sysfs_connector_remove(connector); ++ drm_connector_cleanup(connector); ++ kfree(connector); ++} ++ ++ ++static int glamo_connector_get_modes(struct drm_connector *connector) ++{ ++ struct glamo_fb_platform_data *fb_info; ++ struct glamo_output *goutput = to_glamo_output(connector); ++ struct glamodrm_handle *gdrm = goutput->gdrm; ++ int i; ++ ++ /* Dig out the record which will tell us about the hardware */ ++ fb_info = gdrm->glamo_core->pdata->fb_data; ++ ++ for ( i=0; i<fb_info->num_modes; i++ ) { ++ ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_create(connector->dev); ++ if ( !mode ) continue; ++ ++ mode->type = DRM_MODE_TYPE_DEFAULT | DRM_MODE_TYPE_PREFERRED; ++ ++ /* Convert framebuffer timings into KMS timings. ++ * First: ps -> kHz */ ++ mode->clock = 1000000000UL / fb_info->modes[i].pixclock; ++ mode->clock *= 1000; /* then kHz -> Hz */ ++ mode->hdisplay = fb_info->modes[i].xres; ++ mode->hsync_start = fb_info->modes[i].right_margin ++ + mode->hdisplay; ++ mode->hsync_end = mode->hsync_start ++ + fb_info->modes[i].hsync_len; ++ mode->htotal = mode->hsync_end + fb_info->modes[i].left_margin; ++ mode->hskew = 0; ++ ++ mode->vdisplay = fb_info->modes[i].yres; ++ mode->vsync_start = fb_info->modes[i].lower_margin ++ + mode->vdisplay; ++ mode->vsync_end = mode->vsync_start ++ + fb_info->modes[i].vsync_len; ++ mode->vtotal = mode->vsync_end + fb_info->modes[i].upper_margin; ++ mode->vscan = 0; ++ ++ /* Physical size */ ++ mode->width_mm = fb_info->width; ++ mode->height_mm = fb_info->height; ++ ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); ++ ++ } ++ ++ return fb_info->num_modes; ++} ++ ++ ++static int glamo_connector_set_property(struct drm_connector *connector, ++ struct drm_property *property, ++ uint64_t value) ++{ ++ return 0; ++} ++ ++ ++static int glamo_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) ++ return MODE_NO_DBLESCAN; ++ ++ return MODE_OK; ++} ++ ++ ++struct drm_encoder * ++glamo_connector_best_encoder(struct drm_connector *connector) ++{ ++ struct glamo_output *glamo_output = to_glamo_output(connector); ++ return &glamo_output->enc; ++} ++ ++ ++static void glamo_encoder_dpms(struct drm_encoder *encoder, int mode) ++{ ++} ++ ++ ++static bool glamo_encoder_mode_fixup(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ if ( mode->clock == 0 ) return false; ++ return true; ++} ++ ++ ++void glamo_encoder_prepare(struct drm_encoder *encoder) ++{ ++} ++ ++ ++void glamo_encoder_commit(struct drm_encoder *encoder) ++{ ++} ++ ++ ++static void glamo_encoder_mode_set(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++} ++ ++ ++static void glamo_encoder_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++} ++ ++ ++static void glamo_framebuffer_destroy(struct drm_framebuffer *fb) ++{ ++ struct glamo_framebuffer *glamo_fb = to_glamo_framebuffer(fb); ++ struct drm_device *dev = fb->dev; ++ ++ drm_framebuffer_cleanup(fb); ++ mutex_lock(&dev->struct_mutex); ++ drm_gem_object_unreference(glamo_fb->obj); ++ mutex_unlock(&dev->struct_mutex); ++ ++ kfree(glamo_fb); ++} ++ ++static int glamo_framebuffer_create_handle(struct drm_framebuffer *fb, ++ struct drm_file *file_priv, ++ unsigned int *handle) ++{ ++ struct glamo_framebuffer *glamo_fb = to_glamo_framebuffer(fb); ++ struct drm_gem_object *object = glamo_fb->obj; ++ ++ return drm_gem_handle_create(file_priv, object, handle); ++} ++ ++ ++static const struct drm_framebuffer_funcs glamo_fb_funcs = { ++ .destroy = glamo_framebuffer_destroy, ++ .create_handle = glamo_framebuffer_create_handle, ++}; ++ ++ ++int glamo_framebuffer_create(struct drm_device *dev, ++ struct drm_mode_fb_cmd *mode_cmd, ++ struct drm_framebuffer **fb, ++ struct drm_gem_object *obj) ++{ ++ struct glamo_framebuffer *glamo_fb; ++ int ret; ++ ++ glamo_fb = kzalloc(sizeof(*glamo_fb), GFP_KERNEL); ++ if (!glamo_fb) ++ return -ENOMEM; ++ ++ ret = drm_framebuffer_init(dev, &glamo_fb->base, &glamo_fb_funcs); ++ if (ret) { ++ DRM_ERROR("framebuffer init failed %d\n", ret); ++ return ret; ++ } ++ ++ drm_helper_mode_fill_fb_struct(&glamo_fb->base, mode_cmd); ++ ++ glamo_fb->obj = obj; ++ ++ *fb = &glamo_fb->base; ++ ++ return 0; ++} ++ ++ ++static struct drm_framebuffer * ++glamo_user_framebuffer_create(struct drm_device *dev, ++ struct drm_file *filp, ++ struct drm_mode_fb_cmd *mode_cmd) ++{ ++ struct drm_gem_object *obj; ++ struct drm_framebuffer *fb; ++ int ret; ++ ++ obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); ++ if (!obj) ++ return NULL; ++ ++ ret = glamo_framebuffer_create(dev, mode_cmd, &fb, obj); ++ if (ret) { ++ drm_gem_object_unreference(obj); ++ return NULL; ++ } ++ ++ return fb; ++} ++ ++ ++int glamo_fbchanged(struct drm_device *dev) ++{ ++ return 0; ++} ++ ++ ++/* CRTC functions */ ++static const struct drm_crtc_funcs glamo_crtc_funcs = { ++ .cursor_set = glamo_crtc_cursor_set, ++ .cursor_move = glamo_crtc_cursor_move, ++ .gamma_set = glamo_crtc_gamma_set, ++ .set_config = drm_crtc_helper_set_config, ++ .destroy = glamo_crtc_destroy, ++}; ++ ++ ++/* CRTC helper functions */ ++static const struct drm_crtc_helper_funcs glamo_crtc_helper_funcs = { ++ .dpms = glamo_crtc_dpms, ++ .mode_fixup = glamo_crtc_mode_fixup, ++ .mode_set = glamo_crtc_mode_set, ++ .mode_set_base = glamo_crtc_mode_set_base, ++ .prepare = glamo_crtc_prepare, ++ .commit = glamo_crtc_commit, ++}; ++ ++ ++/* Connector functions */ ++static const struct drm_connector_funcs glamo_connector_funcs = { ++ .detect = glamo_connector_detect, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = glamo_connector_destroy, ++ .set_property = glamo_connector_set_property, ++}; ++ ++ ++/* Connector helper functions */ ++static const struct drm_connector_helper_funcs glamo_connector_helper_funcs = { ++ .mode_valid = glamo_connector_mode_valid, ++ .get_modes = glamo_connector_get_modes, ++ .best_encoder = glamo_connector_best_encoder, ++}; ++ ++ ++/* Encoder functions */ ++static const struct drm_encoder_funcs glamo_encoder_funcs = { ++ .destroy = glamo_encoder_destroy, ++}; ++ ++ ++/* Encoder helper functions */ ++static const struct drm_encoder_helper_funcs glamo_encoder_helper_funcs = { ++ .dpms = glamo_encoder_dpms, ++ .mode_fixup = glamo_encoder_mode_fixup, ++ .prepare = glamo_encoder_prepare, ++ .commit = glamo_encoder_commit, ++ .mode_set = glamo_encoder_mode_set, ++}; ++ ++ ++/* Mode functions */ ++static const struct drm_mode_config_funcs glamo_mode_funcs = { ++ .fb_create = glamo_user_framebuffer_create, ++ .fb_changed = glamo_fbchanged ++}; ++ ++ ++static struct drm_mode_set kernelfb_mode; ++ ++ ++/* Restore's the kernel's fbcon mode, used for panic path */ ++void glamo_display_restore(void) ++{ ++ drm_crtc_helper_set_config(&kernelfb_mode); ++} ++ ++ ++static int glamo_display_panic(struct notifier_block *n, unsigned long ununsed, ++ void *panic_str) ++{ ++ DRM_ERROR("panic occurred, switching back to text console\n"); ++ ++ glamo_display_restore(); ++ return 0; ++} ++ ++ ++static struct notifier_block paniced = { ++ .notifier_call = glamo_display_panic, ++}; ++ ++ ++int glamo_display_init(struct drm_device *dev) ++{ ++ struct glamodrm_handle *gdrm; ++ struct glamo_crtc *glamo_crtc; ++ struct glamo_output *glamo_output; ++ struct drm_connector *connector; ++ struct glamo_framebuffer *glamo_fb; ++ struct fb_info *info; ++ struct glamofb_par *par; ++ struct drm_mode_set *modeset; ++ ++ gdrm = dev->dev_private; ++ ++ /* Initial setup of the LCD controller */ ++ glamo_engine_enable(gdrm->glamo_core, GLAMO_ENGINE_LCD); ++ glamo_engine_reset(gdrm->glamo_core, GLAMO_ENGINE_LCD); ++ ++ glamo_run_lcd_script(gdrm, lcd_init_script, ++ ARRAY_SIZE(lcd_init_script)); ++ ++ drm_mode_config_init(dev); ++ ++ dev->mode_config.min_width = 240; ++ dev->mode_config.min_height = 240; ++ dev->mode_config.max_width = 640; ++ dev->mode_config.max_height = 640; ++ ++ dev->mode_config.funcs = (void *)&glamo_mode_funcs; ++ ++ /* Initialise our CRTC object. ++ * Only one connector per CRTC. We know this: it's kind of soldered. */ ++ glamo_crtc = kzalloc(sizeof(struct glamo_crtc) ++ + sizeof(struct drm_connector *), GFP_KERNEL); ++ if (glamo_crtc == NULL) return 1; ++ glamo_crtc->gdrm = gdrm; ++ gdrm->crtc = (struct drm_crtc *)glamo_crtc; ++ glamo_crtc->pixel_clock_on = 1; ++ glamo_crtc->blank_mode = DRM_MODE_DPMS_OFF; ++ drm_crtc_init(dev, &glamo_crtc->base, &glamo_crtc_funcs); ++ drm_crtc_helper_add(&glamo_crtc->base, &glamo_crtc_helper_funcs); ++ ++ glamo_crtc->mode_set.crtc = &glamo_crtc->base; ++ glamo_crtc->mode_set.connectors = ++ (struct drm_connector **)(glamo_crtc + 1); ++ glamo_crtc->mode_set.num_connectors = 0; ++ ++ /* Create our "output" object: consists of an output and an encoder */ ++ glamo_output = kzalloc(sizeof(struct glamo_output), GFP_KERNEL); ++ if (glamo_output == NULL) return 1; ++ connector = &glamo_output->base; ++ glamo_output->gdrm = gdrm; ++ ++ /* Initialise the connector */ ++ drm_connector_init(dev, connector, &glamo_connector_funcs, ++ DRM_MODE_CONNECTOR_LVDS); ++ drm_sysfs_connector_add(connector); ++ connector->interlace_allowed = 0; ++ connector->doublescan_allowed = 0; ++ ++ /* Initialise the encoder */ ++ drm_encoder_init(dev, &glamo_output->enc, &glamo_encoder_funcs, ++ DRM_MODE_ENCODER_DAC); ++ glamo_output->enc.possible_crtcs = 1 << 0; ++ drm_mode_connector_attach_encoder(&glamo_output->base, ++ &glamo_output->enc); ++ ++ drm_encoder_helper_add(&glamo_output->enc, &glamo_encoder_helper_funcs); ++ drm_connector_helper_add(connector, &glamo_connector_helper_funcs); ++ ++ drm_helper_initial_config(dev); ++ ++ if (list_empty(&dev->mode_config.fb_kernel_list)) { ++ int ret, cols, cols_g; ++ cols_g = reg_read_lcd(gdrm, GLAMO_REG_LCD_MODE3) & 0xc000; ++ switch ( cols_g ) { ++ case GLAMO_LCD_SRC_RGB565 : ++ cols = GLAMO_FB_RGB565; break; ++ case GLAMO_LCD_SRC_ARGB1555 : ++ cols = GLAMO_FB_ARGB1555; break; ++ case GLAMO_LCD_SRC_ARGB4444 : ++ cols = GLAMO_FB_ARGB4444; break; ++ default : ++ printk(KERN_WARNING "Unrecognised LCD colour mode\n"); ++ cols = GLAMO_FB_RGB565; break; /* Take a guess */ ++ } ++ ret = glamofb_create(dev, 480, 640, 480, 640, cols, &glamo_fb); ++ if (ret) return -EINVAL; ++ } ++ ++ info = glamo_fb->base.fbdev; ++ par = info->par; ++ ++ modeset = &glamo_crtc->mode_set; ++ modeset->fb = &glamo_fb->base; ++ modeset->connectors[0] = connector; ++ ++ par->crtc_ids[0] = glamo_crtc->base.base.id; ++ ++ modeset->num_connectors = 1; ++ modeset->mode = modeset->crtc->desired_mode; ++ ++ par->crtc_count = 1; ++ ++ if (register_framebuffer(info) < 0) ++ return -EINVAL; ++ ++ printk(KERN_INFO "[glamo-drm] fb%d: %s frame buffer device\n", ++ info->node, info->fix.id); ++ ++ /* Switch back to kernel console on panic */ ++ kernelfb_mode = *modeset; ++ atomic_notifier_chain_register(&panic_notifier_list, &paniced); ++ printk(KERN_INFO "[glamo-drm] Registered panic notifier\n"); ++ ++ return 0; ++} ++ ++ ++void glamo_lcd_power(struct glamodrm_handle *gdrm, int mode) ++{ ++ struct drm_crtc *crtc = gdrm->crtc; ++ struct glamo_crtc *gcrtc = to_glamo_crtc(crtc); ++ ++ if ( mode ) { ++ glamo_engine_enable(gdrm->glamo_core, GLAMO_ENGINE_LCD); ++ gcrtc->pixel_clock_on = 1; ++ jbt6k74_setpower(JBT_POWER_MODE_NORMAL); ++ if ( gcrtc->current_mode_set ) { ++ glamo_crtc_mode_set(crtc, &gcrtc->current_mode, ++ &gcrtc->current_mode, 0, 0, ++ gcrtc->current_fb); ++ } ++ } else { ++ jbt6k74_setpower(JBT_POWER_MODE_OFF); ++ glamo_engine_suspend(gdrm->glamo_core, GLAMO_ENGINE_LCD); ++ gcrtc->pixel_clock_on = 0; ++ } ++} ++ ++ ++void glamo_display_suspend(struct glamodrm_handle *gdrm) ++{ ++ /* do nothing */ ++} ++ ++ ++void glamo_display_resume(struct glamodrm_handle *gdrm) ++{ ++ struct drm_crtc *crtc = gdrm->crtc; ++ struct glamo_crtc *gcrtc = to_glamo_crtc(crtc); ++ ++ glamo_engine_enable(gdrm->glamo_core, GLAMO_ENGINE_LCD); ++ glamo_engine_reset(gdrm->glamo_core, GLAMO_ENGINE_LCD); ++ glamo_run_lcd_script(gdrm, lcd_init_script, ++ ARRAY_SIZE(lcd_init_script)); ++ ++ if ( gcrtc->current_mode_set ) { ++ glamo_crtc_mode_set(crtc, &gcrtc->current_mode, ++ &gcrtc->current_mode, 0, 0, ++ gcrtc->current_fb); ++ } ++} +diff --git a/drivers/mfd/glamo/glamo-display.h b/drivers/mfd/glamo/glamo-display.h +new file mode 100644 +index 0000000..728bba5 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-display.h +@@ -0,0 +1,41 @@ ++/* Smedia Glamo 336x/337x Display ++ * ++ * Copyright (c) 2008-2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#ifndef __GLAMO_DISPLAY_H ++#define __GLAMO_DISPLAY_H ++ ++#include <drm/drmP.h> ++#include "glamo-drm-private.h" ++ ++extern int glamo_display_init(struct drm_device *dev); ++ ++extern int glamo_framebuffer_create(struct drm_device *dev, ++ struct drm_mode_fb_cmd *mode_cmd, ++ struct drm_framebuffer **fb, ++ struct drm_gem_object *obj); ++ ++extern void glamo_display_suspend(struct glamodrm_handle *gdrm); ++extern void glamo_display_resume(struct glamodrm_handle *gdrm); ++ ++extern void glamo_lcd_power(struct glamodrm_handle *gdrm, int mode); ++ ++#endif /* __GLAMO_DISPLAY_H */ +diff --git a/drivers/mfd/glamo/glamo-drm-drv.c b/drivers/mfd/glamo/glamo-drm-drv.c +new file mode 100644 +index 0000000..774eaff +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-drm-drv.c +@@ -0,0 +1,423 @@ ++/* Smedia Glamo 336x/337x Graphics Driver ++ * ++ * Copyright (C) 2009 Openmoko, Inc. Jorge Luis Zapata <turran@openmoko.com> ++ * Copyright (C) 2008-2009 Thomas White <taw@bitwiz.org.uk> ++ * Copyright (C) 2009 Andreas Pokorny <andreas.pokorny@gmail.com> ++ * ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++ ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <drm/drmP.h> ++#include <drm/glamo_drm.h> ++#include <linux/glamofb.h> ++ ++#include "glamo-core.h" ++#include "glamo-cmdq.h" ++#include "glamo-buffer.h" ++#include "glamo-drm-private.h" ++#include "glamo-display.h" ++#include "glamo-kms-fb.h" ++#include "glamo-fence.h" ++ ++#define DRIVER_AUTHOR "Openmoko, Inc." ++#define DRIVER_NAME "glamo-drm" ++#define DRIVER_DESC "SMedia Glamo 3362" ++#define DRIVER_DATE "20090614" ++ ++ ++static int glamo_ioctl_swap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ printk(KERN_INFO "glamo_ioctl_swap\n"); ++ return 0; ++} ++ ++ ++static int glamo_ioctl_gem_info(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ printk(KERN_INFO "glamo_ioctl_gem_info\n"); ++ return 0; ++} ++ ++ ++struct drm_ioctl_desc glamo_ioctls[] = { ++ DRM_IOCTL_DEF(DRM_GLAMO_CMDBUF, glamo_ioctl_cmdbuf, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_SWAP, glamo_ioctl_swap, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_CMDBURST, glamo_ioctl_cmdburst, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_INFO, glamo_ioctl_gem_info, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_CREATE, glamo_ioctl_gem_create, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_MMAP, glamo_ioctl_gem_mmap, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_PIN, glamo_ioctl_gem_pin, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_UNPIN, glamo_ioctl_gem_unpin, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_PREAD, glamo_ioctl_gem_pread, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_PWRITE, glamo_ioctl_gem_pwrite, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_GLAMO_GEM_WAIT_RENDERING, ++ glamo_ioctl_wait_rendering, DRM_AUTH), ++}; ++ ++ ++static int glamodrm_firstopen(struct drm_device *dev) ++{ ++ DRM_DEBUG("\n"); ++ return 0; ++} ++ ++ ++static int glamodrm_open(struct drm_device *dev, struct drm_file *fh) ++{ ++ DRM_DEBUG("\n"); ++ return 0; ++} ++ ++ ++static void glamodrm_preclose(struct drm_device *dev, struct drm_file *fh) ++{ ++ DRM_DEBUG("\n"); ++} ++ ++static void glamodrm_postclose(struct drm_device *dev, struct drm_file *fh) ++{ ++ DRM_DEBUG("\n"); ++} ++ ++ ++static void glamodrm_lastclose(struct drm_device *dev) ++{ ++ DRM_DEBUG("\n"); ++} ++ ++ ++static int glamodrm_master_create(struct drm_device *dev, ++ struct drm_master *master) ++{ ++ DRM_DEBUG("\n"); ++ ++ return 0; ++} ++ ++ ++static void glamodrm_master_destroy(struct drm_device *dev, ++ struct drm_master *master) ++{ ++ DRM_DEBUG("\n"); ++} ++ ++ ++static int glamodrm_load(struct drm_device *dev, unsigned long flags) ++{ ++ struct glamodrm_handle *gdrm; ++ gdrm = dev->dev_private; ++ ++ glamo_buffer_init(gdrm); ++ glamo_cmdq_init(gdrm); ++ glamo_fence_init(gdrm); ++ glamo_display_init(dev); ++ ++ return 0; ++} ++ ++ ++static int glamodrm_unload(struct drm_device *dev) ++{ ++ struct glamodrm_handle *gdrm; ++ ++ gdrm = dev->dev_private; ++ ++ glamo_engine_disable(gdrm->glamo_core, GLAMO_ENGINE_2D); ++ glamo_engine_disable(gdrm->glamo_core, GLAMO_ENGINE_3D); ++ glamo_buffer_final(gdrm); ++ glamo_fence_shutdown(gdrm); ++ ++ return 0; ++} ++ ++ ++static struct vm_operations_struct glamodrm_gem_vm_ops = { ++ .fault = glamodrm_gem_fault, ++ .open = drm_gem_vm_open, ++ .close = drm_gem_vm_close, ++}; ++ ++static struct drm_driver glamodrm_drm_driver = { ++ .driver_features = DRIVER_IS_PLATFORM | DRIVER_GEM | DRIVER_MODESET, ++ .firstopen = glamodrm_firstopen, ++ .load = glamodrm_load, ++ .unload = glamodrm_unload, ++ .open = glamodrm_open, ++ .preclose = glamodrm_preclose, ++ .postclose = glamodrm_postclose, ++ .lastclose = glamodrm_lastclose, ++ .reclaim_buffers = drm_core_reclaim_buffers, ++ .get_map_ofs = drm_core_get_map_ofs, ++ .get_reg_ofs = drm_core_get_reg_ofs, ++ .master_create = glamodrm_master_create, ++ .master_destroy = glamodrm_master_destroy, ++ .gem_init_object = glamodrm_gem_init_object, ++ .gem_free_object = glamodrm_gem_free_object, ++ .gem_vm_ops = &glamodrm_gem_vm_ops, ++ .ioctls = glamo_ioctls, ++ .fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .ioctl = drm_ioctl, ++ .mmap = drm_gem_mmap, ++ .poll = drm_poll, ++ .fasync = drm_fasync, ++ }, ++ .major = 0, ++ .minor = 1, ++ .patchlevel = 0, ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++}; ++ ++ ++static int glamodrm_probe(struct platform_device *pdev) ++{ ++ int rc; ++ struct glamodrm_handle *gdrm; ++ struct glamo_core *core = dev_get_drvdata(pdev->dev.parent); ++ ++ printk(KERN_INFO "[glamo-drm] SMedia Glamo Direct Rendering Support\n"); ++ ++ gdrm = kzalloc(sizeof(*gdrm), GFP_KERNEL); ++ if ( !gdrm ) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, gdrm); ++ gdrm->glamo_core = core; ++ gdrm->dev = &pdev->dev; ++ ++ /* Find the command queue registers */ ++ gdrm->reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "glamo-cmdq-regs"); ++ if ( !gdrm->reg ) { ++ dev_err(&pdev->dev, "Unable to find cmdq registers.\n"); ++ rc = -ENOENT; ++ goto out_free; ++ } ++ gdrm->reg = request_mem_region(gdrm->reg->start, ++ resource_size(gdrm->reg), pdev->name); ++ if ( !gdrm->reg ) { ++ dev_err(&pdev->dev, "failed to request MMIO region\n"); ++ rc = -ENOENT; ++ goto out_free; ++ } ++ gdrm->reg_base = ioremap_nocache(gdrm->reg->start, ++ resource_size(gdrm->reg)); ++ if ( !gdrm->reg_base ) { ++ dev_err(&pdev->dev, "failed to ioremap() MMIO registers\n"); ++ rc = -ENOENT; ++ goto out_release_regs; ++ } ++ ++ /* Find the VRAM */ ++ gdrm->vram = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "glamo-fb-mem"); ++ if ( !gdrm->vram ) { ++ dev_err(&pdev->dev, "Unable to find VRAM.\n"); ++ rc = -ENOENT; ++ goto out_unmap_cmdq; ++ } ++ gdrm->vram = request_mem_region(gdrm->vram->start, ++ resource_size(gdrm->vram), pdev->name); ++ if ( !gdrm->vram ) { ++ dev_err(&pdev->dev, "failed to request VRAM region\n"); ++ rc = -ENOENT; ++ goto out_unmap_cmdq; ++ } ++ ++ /* Find the LCD controller */ ++ gdrm->lcd_regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "glamo-fb-regs"); ++ if ( !gdrm->lcd_regs ) { ++ dev_err(&pdev->dev, "Unable to find LCD registers.\n"); ++ rc = -ENOENT; ++ goto out_release_vram; ++ } ++ gdrm->lcd_regs = request_mem_region(gdrm->lcd_regs->start, ++ resource_size(gdrm->lcd_regs), ++ pdev->name); ++ if ( !gdrm->lcd_regs ) { ++ dev_err(&pdev->dev, "failed to request LCD registers\n"); ++ rc = -ENOENT; ++ goto out_release_vram; ++ } ++ gdrm->lcd_base = ioremap_nocache(gdrm->lcd_regs->start, ++ resource_size(gdrm->lcd_regs)); ++ if ( !gdrm->lcd_base ) { ++ dev_err(&pdev->dev, "failed to ioremap() LCD registers\n"); ++ rc = -ENOENT; ++ goto out_release_lcd; ++ } ++ ++ /* Find the 2D engine */ ++ gdrm->twod_regs = platform_get_resource(pdev, IORESOURCE_MEM, 4); ++ if ( !gdrm->twod_regs ) { ++ dev_err(&pdev->dev, "Unable to find 2D registers.\n"); ++ rc = -ENOENT; ++ goto out_unmap_lcd; ++ } ++ gdrm->twod_regs = request_mem_region(gdrm->twod_regs->start, ++ resource_size(gdrm->twod_regs), ++ pdev->name); ++ if ( !gdrm->twod_regs ) { ++ dev_err(&pdev->dev, "failed to request 2D registers\n"); ++ rc = -ENOENT; ++ goto out_unmap_lcd; ++ } ++ gdrm->twod_base = ioremap(gdrm->twod_regs->start, ++ resource_size(gdrm->twod_regs)); ++ if ( !gdrm->twod_base ) { ++ dev_err(&pdev->dev, "failed to ioremap() 2D registers\n"); ++ rc = -ENOENT; ++ goto out_release_2d; ++ } ++ ++ /* Hook up IRQ handle for fence processing */ ++ gdrm->twod_irq = platform_get_irq_byname(pdev, "glamo-2d-irq"); ++ ++ gdrm->vram_size = GLAMO_FB_SIZE; ++ printk(KERN_INFO "[glamo-drm] %lli bytes of VRAM\n", ++ (long long int)gdrm->vram_size); ++ ++ /* Initialise DRM */ ++ drm_platform_init(&glamodrm_drm_driver, pdev, (void *)gdrm); ++ ++ return 0; ++ ++out_release_2d: ++ release_mem_region(gdrm->twod_regs->start, ++ resource_size(gdrm->twod_regs)); ++out_unmap_lcd: ++ iounmap(gdrm->lcd_base); ++out_release_lcd: ++ release_mem_region(gdrm->lcd_regs->start, ++ resource_size(gdrm->lcd_regs)); ++out_release_vram: ++ release_mem_region(gdrm->vram->start, resource_size(gdrm->vram)); ++out_unmap_cmdq: ++ iounmap(gdrm->cmdq_base); ++out_release_cmdq: ++ release_mem_region(gdrm->cmdq->start, resource_size(gdrm->cmdq)); ++out_unmap_regs: ++ iounmap(gdrm->reg_base); ++out_release_regs: ++ release_mem_region(gdrm->reg->start, resource_size(gdrm->reg)); ++out_free: ++ kfree(gdrm); ++ dev_set_drvdata(&pdev->dev, NULL); ++ return rc; ++} ++ ++ ++static int glamodrm_remove(struct platform_device *pdev) ++{ ++ struct glamodrm_handle *gdrm = platform_get_drvdata(pdev); ++ ++ glamo_buffer_final(gdrm); ++ glamo_cmdq_shutdown(gdrm); ++ ++ drm_exit(&glamodrm_drm_driver); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ /* Release registers */ ++ iounmap(gdrm->reg_base); ++ release_mem_region(gdrm->reg->start, resource_size(gdrm->reg)); ++ ++ /* Release VRAM */ ++ release_mem_region(gdrm->vram->start, resource_size(gdrm->vram)); ++ ++ /* Release command queue */ ++ iounmap(gdrm->cmdq_base); ++ release_mem_region(gdrm->cmdq->start, resource_size(gdrm->cmdq)); ++ ++ /* Release 2D engine */ ++ iounmap(gdrm->twod_base); ++ release_mem_region(gdrm->twod_regs->start, ++ resource_size(gdrm->twod_regs)); ++ ++ kfree(gdrm); ++ ++ return 0; ++} ++ ++ ++static int glamodrm_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct glamodrm_handle *gdrm = platform_get_drvdata(pdev); ++ ++ glamo_kmsfb_suspend(gdrm); ++ glamo_display_suspend(gdrm); ++ glamo_cmdq_suspend(gdrm); ++ ++ /* glamo_core.c will suspend the engines for us */ ++ ++ return 0; ++} ++ ++ ++static int glamodrm_resume(struct platform_device *pdev) ++{ ++ struct glamodrm_handle *gdrm = platform_get_drvdata(pdev); ++ ++ glamo_cmdq_resume(gdrm); ++ glamo_display_resume(gdrm); ++ glamo_kmsfb_resume(gdrm); ++ ++ return 0; ++} ++ ++ ++static struct platform_driver glamodrm_driver = { ++ .probe = glamodrm_probe, ++ .remove = glamodrm_remove, ++ .suspend = glamodrm_suspend, ++ .resume = glamodrm_resume, ++ .driver = { ++ .name = "glamo-fb", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++ ++static int __devinit glamodrm_init(void) ++{ ++ glamodrm_drm_driver.num_ioctls = DRM_ARRAY_SIZE(glamo_ioctls); ++ return platform_driver_register(&glamodrm_driver); ++} ++ ++ ++static void __exit glamodrm_exit(void) ++{ ++ platform_driver_unregister(&glamodrm_driver); ++} ++ ++ ++module_init(glamodrm_init); ++module_exit(glamodrm_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/glamo/glamo-drm-private.h b/drivers/mfd/glamo/glamo-drm-private.h +new file mode 100644 +index 0000000..75f2757 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-drm-private.h +@@ -0,0 +1,166 @@ ++/* Smedia Glamo 336x/337x DRM private bits ++ * ++ * Copyright (C) 2008-2009 Thomas White <taw@bitwiz.org.uk> ++ * Copyright (C) 2009 Andreas Pokorny <andreas.pokorny@gmail.com> ++ * Based on xf86-video-glamo ++ * Copyright 2007 OpenMoko, Inc. ++ * Copyright © 2009 Lars-Peter Clausen <lars@metafoo.de> ++ * ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#ifndef __GLAMO_DRMPRIV_H ++#define __GLAMO_DRMPRIV_H ++ ++ ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/semaphore.h> ++#include <linux/spinlock.h> ++#include <linux/wait.h> ++ ++#include "glamo-core.h" ++ ++ ++/* Memory to allocate for the framebuffer. ++ * The rest is reserved for the DRM memory manager */ ++#define GLAMO_FRAMEBUFFER_ALLOCATION (2*480*640) ++ ++ ++struct glamodrm_handle { ++ ++ /* This device */ ++ struct device *dev; ++ ++ /* The parent device handle */ ++ struct glamo_core *glamo_core; ++ ++ /* Framebuffer handle for the console (i.e. /dev/fb0) */ ++ struct fb_info *fb; ++ ++ /* Command queue registers */ ++ struct resource *reg; ++ char __iomem *reg_base; ++ ++ /* VRAM region */ ++ struct resource *vram; ++ ++ /* Command queue region */ ++ char __iomem *cmdq_base; ++ unsigned long cmdq_offs; ++ ++ /* LCD controller registers */ ++ struct resource *lcd_regs; ++ char __iomem *lcd_base; ++ ++ /* 2D engine registers and IRQ */ ++ struct resource *twod_regs; ++ char __iomem *twod_base; ++ unsigned int twod_irq; ++ ++ ssize_t vram_size; ++ ++ /* Memory management */ ++ struct drm_mm *mmgr; ++ ++ /* semaphore against concurrent ioctl */ ++ struct semaphore add_to_ring; ++ ++ /* Saved state */ ++ u_int16_t saved_clock; ++ u_int16_t saved_width; ++ u_int16_t saved_height; ++ u_int16_t saved_pitch; ++ u_int16_t saved_htotal; ++ u_int16_t saved_hrtrst; ++ u_int16_t saved_hrtren; ++ u_int16_t saved_hdspst; ++ u_int16_t saved_hdspen; ++ u_int16_t saved_vtotal; ++ u_int16_t saved_vrtrst; ++ u_int16_t saved_vrtren; ++ u_int16_t saved_vdspst; ++ u_int16_t saved_vdspen; ++ ++ /* Fencing */ ++ atomic_t curr_seq; /* The last used stamp number */ ++ struct list_head fence_list; /* List of active fences */ ++ rwlock_t fence_list_lock; /* Lock to protect fence_list */ ++ wait_queue_head_t fence_queue; /* Waitqueue */ ++ struct tasklet_struct fence_tl; /* Tasklet for fence IRQ */ ++ ++ /* A scratch block */ ++ struct drm_mm_node *scratch; ++ ++ /* We only have one */ ++ struct drm_crtc *crtc; ++}; ++ ++ ++/* Private data. This is where we keep our memory management bits */ ++struct drm_glamo_gem_object { ++ struct drm_gem_object *obj; /* The GEM object this refers to */ ++ struct drm_mm_node *block; /* Block handle for drm_mm */ ++ uint64_t mmap_offset; ++}; ++ ++ ++struct glamo_crtc { ++ ++ struct drm_crtc base; ++ struct glamodrm_handle *gdrm; ++ /* a mode_set for fbdev users on this crtc */ ++ struct drm_mode_set mode_set; ++ int blank_mode; ++ ++ int pixel_clock_on; ++ ++ int current_mode_set; ++ struct drm_display_mode current_mode; ++ struct drm_framebuffer *current_fb; ++}; ++ ++ ++struct glamo_framebuffer { ++ struct drm_framebuffer base; ++ struct drm_gem_object *obj; ++}; ++ ++ ++struct glamo_output { ++ struct drm_connector base; ++ struct drm_encoder enc; ++ struct glamodrm_handle *gdrm; ++}; ++ ++ ++/* Colour mode for KMS framebuffer */ ++enum { ++ GLAMO_FB_RGB565, ++ GLAMO_FB_ARGB1555, ++ GLAMO_FB_ARGB4444 ++}; ++ ++ ++#define to_glamo_crtc(x) container_of(x, struct glamo_crtc, base) ++#define to_glamo_output(x) container_of(x, struct glamo_output, base) ++#define enc_to_glamo_output(x) container_of(x, struct glamo_output, enc) ++#define to_glamo_framebuffer(x) container_of(x, struct glamo_framebuffer, base) ++ ++ ++#endif /* __GLAMO_DRMPRIV_H */ +diff --git a/drivers/mfd/glamo/glamo-fence.c b/drivers/mfd/glamo/glamo-fence.c +new file mode 100644 +index 0000000..9119675 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-fence.c +@@ -0,0 +1,330 @@ ++/* ++ * SMedia Glamo 336x/337x fence objects ++ * ++ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * ++ * Loosely based on radeon_fence.c, to which the following notice applies: ++ * ++ * Copyright 2009 Jerome Glisse. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ */ ++/* ++ * Authors: ++ * Jerome Glisse <glisse@freedesktop.org> ++ * Dave Airlie ++ */ ++ ++ ++#include <drm/drmP.h> ++#include <drm/glamo_drm.h> ++#include <linux/kernel.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/spinlock.h> ++#include <linux/lockdep.h> ++ ++#include "glamo-drm-private.h" ++#include "glamo-regs.h" ++#include "glamo-core.h" ++#include "glamo-cmdq.h" ++ ++ ++static struct lock_class_key glamo_fence_lock_key; ++ ++ ++struct glamo_fence ++{ ++ struct list_head list; ++ uint16_t seq; /* Wait for at least this ID */ ++ int signalled; /* Non-zero when fence has passed */ ++ struct glamodrm_handle *gdrm; ++}; ++ ++ ++static void glamo_fence_emit(struct glamo_fence *fence) ++{ ++ u16 fring[6]; ++ ++ fring[0] = 0x8000 | GLAMO_REG_2D_ID1; ++ fring[1] = 3; ++ fence->seq = atomic_inc_return(&fence->gdrm->curr_seq); ++ if ( fence->seq > 1<<14 ) { ++ atomic_set(&fence->gdrm->curr_seq, 0); ++ fence->seq = atomic_inc_return(&fence->gdrm->curr_seq); ++ } ++ fring[2] = 1<<15 | fence->seq; ++ fring[3] = 0; /* Unused */ ++ fring[4] = 0; /* Unused */ ++ fring[5] = 0; /* Padding */ ++ ++ glamo_add_to_ring(fence->gdrm, fring, 12); ++} ++ ++ ++static void glamo_fence_enable(struct glamodrm_handle *gdrm) ++{ ++ enable_irq( GLAMO_IRQ_2D); ++} ++ ++ ++static inline u16 reg_read_2d(struct glamodrm_handle *gdrm, u_int16_t reg) ++{ ++ /* For command queue, the address is given relative to ++ * the overall base of Glamo. This isn't the case here. */ ++ return ioread16(gdrm->twod_base + reg-GLAMO_REGOFS_2D); ++} ++ ++ ++static inline u16 reg_read_cmdq(struct glamodrm_handle *gdrm, u_int16_t reg) ++{ ++ return ioread16(gdrm->reg_base + reg); ++} ++ ++ ++static void glamo_cmdq_wait(struct glamodrm_handle *gdrm, ++ enum glamo_engine engine) ++{ ++ u16 mask, val, status; ++ int i; ++ ++ switch (engine) ++ { ++ case GLAMO_ENGINE_ALL: ++ mask = 1 << 2; ++ val = mask; ++ break; ++ default: ++ return; ++ } ++ ++ for ( i=0; i<1000; i++ ) { ++ status = reg_read_cmdq(gdrm, GLAMO_REG_CMDQ_STATUS); ++ if ((status & mask) == val) break; ++ mdelay(1); ++ } ++ if ( i == 1000 ) { ++ size_t ring_read; ++ printk(KERN_WARNING "[glamo-drm] CmdQ timeout!\n"); ++ printk(KERN_WARNING "[glamo-drm] status = %x\n", status); ++ ring_read = reg_read_cmdq(gdrm, GLAMO_REG_CMDQ_READ_ADDRL); ++ ring_read |= ((reg_read_cmdq(gdrm, GLAMO_REG_CMDQ_READ_ADDRH) ++ & 0x7) << 16); ++ printk(KERN_INFO "[glamo-drm] ring_read now 0x%x\n", ++ ring_read); ++ } ++} ++ ++ ++static irqreturn_t glamo_fence_irq_handler(int irq, void *data) ++{ ++ struct glamodrm_handle *gdrm = data; ++ if (!gdrm) return IRQ_NONE; ++ tasklet_schedule(&gdrm->fence_tl); ++ return IRQ_HANDLED; ++} ++ ++ ++/* This is nasty. I'm sorry. */ ++static void glamo_fence_debodge(struct glamodrm_handle *gdrm) ++{ ++ struct list_head *tmp; ++ ++ printk(KERN_ERR "[glamo-drm] Attempting to recover...\n"); ++ ++ glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL); ++ glamo_engine_reset(gdrm->glamo_core, GLAMO_ENGINE_2D); ++ ++ read_lock(&gdrm->fence_list_lock); ++ list_for_each(tmp, &gdrm->fence_list) { ++ ++ struct glamo_fence *fence; ++ ++ fence = list_entry(tmp, struct glamo_fence, list); ++ ++ if ( fence->signalled != 1 ) { ++ printk(KERN_ERR "[glamo-drm] Fence seq#%i was not" ++ " signalled\n", fence->seq); ++ } ++ fence->signalled = 1; ++ ++ } ++ read_unlock(&gdrm->fence_list_lock); ++ ++ wake_up_all(&gdrm->fence_queue); ++} ++ ++ ++static void glamo_fence_tl(unsigned long data) ++{ ++ struct glamodrm_handle *gdrm = (struct glamodrm_handle *)data; ++ int wake = 0; ++ u16 seq; ++ struct list_head *tmp; ++ ++ seq = reg_read_2d(gdrm, GLAMO_REG_2D_ID1) & 0x7fff; ++ ++ read_lock(&gdrm->fence_list_lock); ++ list_for_each(tmp, &gdrm->fence_list) { ++ ++ struct glamo_fence *fence; ++ ++ fence = list_entry(tmp, struct glamo_fence, list); ++ if ( seq >= fence->seq ) { ++ fence->signalled = 1; ++ wake = 1; ++ } ++ ++ } ++ read_unlock(&gdrm->fence_list_lock); ++ ++ if ( wake ) wake_up_all(&gdrm->fence_queue); ++} ++ ++ ++static struct glamo_fence *glamo_fence_new(struct glamodrm_handle *gdrm) ++{ ++ struct glamo_fence *fence; ++ unsigned long irq_flags; ++ ++ fence = kmalloc(sizeof(*fence), GFP_KERNEL); ++ fence->signalled = 0; ++ fence->gdrm = gdrm; ++ ++ /* Add to list */ ++ write_lock_irqsave(&gdrm->fence_list_lock, irq_flags); ++ list_add(&fence->list, &gdrm->fence_list); ++ write_unlock_irqrestore(&gdrm->fence_list_lock, irq_flags); ++ ++ return fence; ++} ++ ++ ++static struct glamo_fence *glamo_fence_destroy(struct glamo_fence *fence) ++{ ++ unsigned long irq_flags; ++ struct glamodrm_handle *gdrm = fence->gdrm; ++ ++ /* Remove from list */ ++ write_lock_irqsave(&gdrm->fence_list_lock, irq_flags); ++ list_del(&fence->list); ++ write_unlock_irqrestore(&gdrm->fence_list_lock, irq_flags); ++ ++ kfree(fence); ++ ++ return fence; ++} ++ ++ ++int glamo_ioctl_wait_rendering(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct glamodrm_handle *gdrm; ++ struct drm_glamo_gem_wait_rendering *args = data; ++ struct glamo_fence *fence; ++ int r; ++ ++ gdrm = dev->dev_private; ++ ++ if ( !args->have_handle ) { ++ glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL); ++ return 0; ++ } ++ ++ fence = glamo_fence_new(gdrm); ++ if ( fence == NULL ) { ++ printk(KERN_WARNING "[glamo-drm] Couldn't allocate fence -" ++ " falling back to busy wait.\n"); ++ glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL); ++ return 0; ++ } ++ ++ glamo_fence_emit(fence); ++ ++ /* Wait... */ ++ r = wait_event_interruptible_timeout(gdrm->fence_queue, ++ fence->signalled, HZ); ++ if ( r == 0 ) { ++ printk(KERN_ERR "[glamo-drm] Timeout!\n"); ++ glamo_fence_debodge(gdrm); ++ } ++ ++ glamo_fence_destroy(fence); ++ ++ return 0; ++} ++ ++ ++void glamo_fence_init(struct glamodrm_handle *gdrm) ++{ ++ unsigned long irq_flags; ++ int r; ++ ++ if ( gdrm->twod_irq == 0 ) { ++ printk(KERN_ERR "[glamo-drm] Don't know which IRQ to use!\n"); ++ return; ++ } ++ ++ gdrm->fence_list_lock = __RW_LOCK_UNLOCKED(gdrm->fence_list_lock); ++ lockdep_set_class(&gdrm->fence_list_lock, &glamo_fence_lock_key); ++ init_waitqueue_head(&gdrm->fence_queue); ++ ++ atomic_set(&gdrm->curr_seq, 0); ++ ++ write_lock_irqsave(&gdrm->fence_list_lock, irq_flags); ++ INIT_LIST_HEAD(&gdrm->fence_list); ++ write_unlock_irqrestore(&gdrm->fence_list_lock, irq_flags); ++ ++ tasklet_init(&gdrm->fence_tl, glamo_fence_tl, (unsigned long)gdrm); ++ ++ r = request_irq(gdrm->twod_irq, glamo_fence_irq_handler, ++ IRQF_SHARED, "glamo-fence", gdrm); ++ if ( r ) { ++ printk(KERN_ERR "[glamo-drm] Failed to register irq.\n"); ++ return; ++ } ++ ++ glamo_fence_enable(gdrm); ++} ++ ++ ++void glamo_fence_shutdown(struct glamodrm_handle *gdrm) ++{ ++ free_irq(gdrm->twod_irq, gdrm); ++ wake_up_all(&gdrm->fence_queue); ++ tasklet_kill(&gdrm->fence_tl); ++} +diff --git a/drivers/mfd/glamo/glamo-fence.h b/drivers/mfd/glamo/glamo-fence.h +new file mode 100644 +index 0000000..deda995 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-fence.h +@@ -0,0 +1,34 @@ ++/* ++ * SMedia Glamo 336x/337x fence objects ++ * ++ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ */ ++ ++#ifndef __GLAMO_FENCE_H ++#define __GLAMO_FENCE_H ++ ++#include <drm/drmP.h> ++ ++#include "glamo-drm-private.h" ++ ++extern void glamo_fence_init(struct glamodrm_handle *gdrm); ++extern void glamo_fence_shutdown(struct glamodrm_handle *gdrm); ++ ++extern int glamo_ioctl_wait_rendering(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++#endif /* __GLAMO_FENCE_H */ +diff --git a/drivers/mfd/glamo/glamo-kms-fb.c b/drivers/mfd/glamo/glamo-kms-fb.c +new file mode 100644 +index 0000000..d76dd24 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-kms-fb.c +@@ -0,0 +1,493 @@ ++/* ++ * SMedia Glamo 336x/337x KMS Framebuffer ++ * ++ * Copyright (C) 2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * Based on glamo-fb.c (C) 2007-2008 by Openmoko, Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ * ++ * Based on intel_fb.c from drivers/gpu/drm/i915 ++ * to which the following licence applies: ++ * ++ * Copyright © 2006-2007 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Eric Anholt <eric@anholt.net> ++ * ++ */ ++ ++ ++#include <drm/drmP.h> ++#include <drm/glamo_drm.h> ++#include <drm/drm_crtc_helper.h> ++#include <drm/drm_crtc.h> ++ ++#include "glamo-core.h" ++#include "glamo-drm-private.h" ++#include "glamo-display.h" ++#include "glamo-buffer.h" ++ ++ ++struct glamofb_par { ++ struct drm_device *dev; ++ struct drm_display_mode *our_mode; ++ struct glamo_framebuffer *glamo_fb; ++ int crtc_count; ++ /* crtc currently bound to this */ ++ uint32_t crtc_ids[2]; ++}; ++ ++ ++static int glamofb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, ++ struct fb_info *info) ++{ ++ struct glamofb_par *par = info->par; ++ struct drm_device *dev = par->dev; ++ struct drm_crtc *crtc; ++ int i; ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ struct glamo_crtc *glamo_crtc = to_glamo_crtc(crtc); ++ struct drm_mode_set *modeset = &glamo_crtc->mode_set; ++ struct drm_framebuffer *fb = modeset->fb; ++ ++ for (i = 0; i < par->crtc_count; i++) ++ if (crtc->base.id == par->crtc_ids[i]) ++ break; ++ ++ if (i == par->crtc_count) ++ continue; ++ ++ ++ if (regno > 255) ++ return 1; ++ ++ if (regno < 16) { ++ switch (fb->depth) { ++ case 15: ++ fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | ++ ((green & 0xf800) >> 6) | ++ ((blue & 0xf800) >> 11); ++ break; ++ case 16: ++ fb->pseudo_palette[regno] = (red & 0xf800) | ++ ((green & 0xfc00) >> 5) | ++ ((blue & 0xf800) >> 11); ++ break; ++ case 24: ++ case 32: ++ fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | ++ (green & 0xff00) | ++ ((blue & 0xff00) >> 8); ++ break; ++ } ++ } ++ } ++ return 0; ++} ++ ++static int glamofb_check_var(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ struct glamofb_par *par = info->par; ++ struct glamo_framebuffer *glamo_fb = par->glamo_fb; ++ struct drm_framebuffer *fb = &glamo_fb->base; ++ int depth; ++ ++ /* Need to resize the fb object !!! */ ++ if (var->xres > fb->width || var->yres > fb->height) { ++ DRM_ERROR("Cannot resize framebuffer object (%dx%d > %dx%d)\n", ++ var->xres,var->yres,fb->width,fb->height); ++ DRM_ERROR("Need resizing code.\n"); ++ return -EINVAL; ++ } ++ ++ switch (var->bits_per_pixel) { ++ case 16: ++ depth = (var->green.length == 6) ? 16 : 15; ++ break; ++ case 32: ++ depth = (var->transp.length > 0) ? 32 : 24; ++ break; ++ default: ++ depth = var->bits_per_pixel; ++ break; ++ } ++ ++ switch (depth) { ++ case 16: ++ var->red.offset = 11; ++ var->green.offset = 5; ++ var->blue.offset = 0; ++ var->red.length = 5; ++ var->green.length = 6; ++ var->blue.length = 5; ++ var->transp.length = 0; ++ var->transp.offset = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* this will let fbcon do the mode init */ ++/* FIXME: take mode config lock? */ ++static int glamofb_set_par(struct fb_info *info) ++{ ++ struct glamofb_par *par = info->par; ++ struct drm_device *dev = par->dev; ++ struct fb_var_screeninfo *var = &info->var; ++ int i; ++ struct drm_crtc *crtc; ++ int ret; ++ ++ DRM_DEBUG("%d %d\n", var->xres, var->pixclock); ++ ++ if (var->pixclock != -1) { ++ DRM_ERROR("Warning: userspace gave me a pixel clock value (%i)" ++ "- I'm ignoring it.\n", var->pixclock); ++ } ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ struct glamo_crtc *glamo_crtc = to_glamo_crtc(crtc); ++ ++ for (i = 0; i < par->crtc_count; i++) ++ if (crtc->base.id == par->crtc_ids[i]) ++ break; ++ ++ if (i == par->crtc_count) ++ continue; ++ ++ if (crtc->fb == glamo_crtc->mode_set.fb) { ++ mutex_lock(&dev->mode_config.mutex); ++ ret = crtc->funcs->set_config(&glamo_crtc->mode_set); ++ mutex_unlock(&dev->mode_config.mutex); ++ if (ret) ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static int glamofb_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ struct glamofb_par *par = info->par; ++ struct drm_device *dev = par->dev; ++ struct drm_mode_set *modeset; ++ struct drm_crtc *crtc; ++ struct glamo_crtc *glamo_crtc; ++ int ret = 0; ++ int i; ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ for (i = 0; i < par->crtc_count; i++) ++ if (crtc->base.id == par->crtc_ids[i]) ++ break; ++ ++ if (i == par->crtc_count) ++ continue; ++ ++ glamo_crtc = to_glamo_crtc(crtc); ++ modeset = &glamo_crtc->mode_set; ++ ++ modeset->x = var->xoffset; ++ modeset->y = var->yoffset; ++ ++ if (modeset->num_connectors) { ++ mutex_lock(&dev->mode_config.mutex); ++ ret = crtc->funcs->set_config(modeset); ++ mutex_unlock(&dev->mode_config.mutex); ++ if (!ret) { ++ info->var.xoffset = var->xoffset; ++ info->var.yoffset = var->yoffset; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++static void glamofb_on(struct fb_info *info) ++{ ++ struct glamofb_par *par = info->par; ++ struct drm_device *dev = par->dev; ++ struct glamodrm_handle *gdrm = dev->dev_private; ++ ++ gdrm = dev->dev_private; ++ ++ glamo_lcd_power(gdrm, 1); ++} ++ ++static void glamofb_off(struct fb_info *info, int dpms_mode) ++{ ++ struct glamofb_par *par = info->par; ++ struct drm_device *dev = par->dev; ++ struct glamodrm_handle *gdrm = dev->dev_private; ++ ++ glamo_lcd_power(gdrm, 0); ++} ++ ++static int glamofb_blank(int blank, struct fb_info *info) ++{ ++ switch (blank) { ++ case FB_BLANK_UNBLANK: ++ glamofb_on(info); ++ break; ++ case FB_BLANK_NORMAL: ++ glamofb_off(info, DRM_MODE_DPMS_STANDBY); ++ break; ++ case FB_BLANK_HSYNC_SUSPEND: ++ glamofb_off(info, DRM_MODE_DPMS_STANDBY); ++ break; ++ case FB_BLANK_VSYNC_SUSPEND: ++ glamofb_off(info, DRM_MODE_DPMS_SUSPEND); ++ break; ++ case FB_BLANK_POWERDOWN: ++ glamofb_off(info, DRM_MODE_DPMS_OFF); ++ break; ++ } ++ return 0; ++} ++ ++static struct fb_ops glamofb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = glamofb_check_var, ++ .fb_set_par = glamofb_set_par, ++ .fb_setcolreg = glamofb_setcolreg, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_pan_display = glamofb_pan_display, ++ .fb_blank = glamofb_blank, ++}; ++ ++ ++#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1) ++ ++ ++/* Here, we create a GEM object of the correct size, and then turn it into ++ * /dev/fbX so that the kernel can put a console on it. */ ++int glamofb_create(struct drm_device *dev, uint32_t fb_width, ++ uint32_t fb_height, uint32_t surface_width, ++ uint32_t surface_height, int colour_mode, ++ struct glamo_framebuffer **glamo_fb_p) ++{ ++ struct fb_info *info; ++ struct glamofb_par *par; ++ struct drm_framebuffer *fb; ++ struct glamo_framebuffer *glamo_fb; ++ struct drm_mode_fb_cmd mode_cmd; ++ struct drm_gem_object *fbo = NULL; ++ struct drm_glamo_gem_object *gobj; ++ struct device *device = &dev->platform_dev->dev; ++ struct glamodrm_handle *gdrm; ++ int size, ret; ++ unsigned long offs; ++ ++ gdrm = dev->dev_private; ++ ++ mode_cmd.width = surface_width; ++ mode_cmd.height = surface_height; ++ ++ mode_cmd.bpp = 16; ++ mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); ++ mode_cmd.depth = 16; ++ ++ size = mode_cmd.pitch * mode_cmd.height; ++ size = ALIGN(size, PAGE_SIZE); ++ if ( size > GLAMO_FRAMEBUFFER_ALLOCATION ) { ++ printk(KERN_ERR "[glamo-drm] Not enough memory for fb\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ fbo = glamo_gem_object_alloc(dev, GLAMO_FRAMEBUFFER_ALLOCATION, 2); ++ if (!fbo) { ++ printk(KERN_ERR "[glamo-drm] Failed to allocate framebuffer\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ gobj = fbo->driver_private; ++ ++ mutex_lock(&dev->struct_mutex); ++ ++ ret = glamo_framebuffer_create(dev, &mode_cmd, &fb, fbo); ++ if (ret) { ++ DRM_ERROR("failed to allocate fb.\n"); ++ goto out_unref; ++ } ++ ++ list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); ++ ++ glamo_fb = to_glamo_framebuffer(fb); ++ *glamo_fb_p = glamo_fb; ++ ++ info = framebuffer_alloc(sizeof(struct glamofb_par), device); ++ if (!info) { ++ ret = -ENOMEM; ++ goto out_unref; ++ } ++ ++ par = info->par; ++ ++ strcpy(info->fix.id, "glamodrmfb"); ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ info->fix.type_aux = 0; ++ info->fix.xpanstep = 1; /* doing it in hw */ ++ info->fix.ypanstep = 1; /* doing it in hw */ ++ info->fix.ywrapstep = 0; ++ info->fix.accel = FB_ACCEL_GLAMO; ++ info->fix.type_aux = 0; ++ info->flags = FBINFO_DEFAULT; ++ ++ info->fbops = &glamofb_ops; ++ ++ info->fix.line_length = fb->pitch; ++ ++ info->flags = FBINFO_DEFAULT; ++ ++ offs = gobj->block->start; ++ info->screen_base = ioremap(gdrm->vram->start + offs + GLAMO_OFFSET_FB, ++ GLAMO_FRAMEBUFFER_ALLOCATION); ++ if (!info->screen_base) { ++ printk(KERN_ERR "[glamo-drm] Couldn't map framebuffer!\n"); ++ ret = -ENOSPC; ++ goto out_unref; ++ } ++ info->fix.smem_start = (unsigned long)gdrm->vram->start + offs; ++ info->fix.smem_len = size; ++ info->screen_size = size; ++ ++ info->pseudo_palette = fb->pseudo_palette; ++ info->var.xres_virtual = fb->width; ++ info->var.yres_virtual = fb->height; ++ info->var.bits_per_pixel = fb->bits_per_pixel; ++ info->var.xoffset = 0; ++ info->var.yoffset = 0; ++ info->var.activate = FB_ACTIVATE_NOW; ++ info->var.height = -1; ++ info->var.width = -1; ++ info->var.xres = fb_width; ++ info->var.yres = fb_height; ++ ++ info->fix.mmio_start = 0; ++ info->fix.mmio_len = 0; ++ ++ info->pixmap.size = 64*1024; ++ info->pixmap.buf_align = 8; ++ info->pixmap.access_align = 32; ++ info->pixmap.flags = FB_PIXMAP_SYSTEM; ++ info->pixmap.scan_align = 1; ++ ++ switch (fb->depth) { ++ case 16: ++ switch ( colour_mode ) { ++ case GLAMO_FB_RGB565: ++ info->var.red.offset = 11; ++ info->var.green.offset = 5; ++ info->var.blue.offset = 0; ++ info->var.red.length = 5; ++ info->var.green.length = 6; ++ info->var.blue.length = 5; ++ info->var.transp.length = 0; ++ break; ++ case GLAMO_FB_ARGB1555: ++ info->var.transp.offset = 15; ++ info->var.red.offset = 10; ++ info->var.green.offset = 5; ++ info->var.blue.offset = 0; ++ info->var.transp.length = 1; ++ info->var.red.length = 5; ++ info->var.green.length = 5; ++ info->var.blue.length = 5; ++ break; ++ case GLAMO_FB_ARGB4444: ++ info->var.transp.offset = 12; ++ info->var.red.offset = 8; ++ info->var.green.offset = 4; ++ info->var.blue.offset = 0; ++ info->var.transp.length = 4; ++ info->var.red.length = 4; ++ info->var.green.length = 4; ++ info->var.blue.length = 4; ++ break; ++ } ++ break; ++ case 24: ++ case 32: ++ default: ++ /* The Smedia Glamo doesn't support anything but 16bit color */ ++ printk(KERN_ERR "[glamo-drm] Only 16bpp is supported.\n"); ++ return -EINVAL; ++ } ++ ++ fb->fbdev = info; ++ par->glamo_fb = glamo_fb; ++ par->dev = dev; ++ gdrm->fb = info; ++ ++ info->var.pixclock = -1; ++ ++ printk(KERN_INFO "[glamo-drm] Allocated %dx%d fb: bo %p\n", ++ glamo_fb->base.width, glamo_fb->base.height, fbo); ++ mutex_unlock(&dev->struct_mutex); ++ return 0; ++ ++out_unref: ++ drm_gem_object_unreference(fbo); ++ mutex_unlock(&dev->struct_mutex); ++out: ++ return ret; ++} ++ ++ ++void glamo_kmsfb_suspend(struct glamodrm_handle *gdrm) ++{ ++ fb_set_suspend(gdrm->fb, 1); ++} ++ ++ ++void glamo_kmsfb_resume(struct glamodrm_handle *gdrm) ++{ ++ fb_set_suspend(gdrm->fb, 0); ++} +diff --git a/drivers/mfd/glamo/glamo-kms-fb.h b/drivers/mfd/glamo/glamo-kms-fb.h +new file mode 100644 +index 0000000..1960e76 +--- /dev/null ++++ b/drivers/mfd/glamo/glamo-kms-fb.h +@@ -0,0 +1,41 @@ ++/* ++ * SMedia Glamo 336x/337x KMS framebuffer ++ * ++ * Copyright (C) 2009 Thomas White <taw@bitwiz.org.uk> ++ * ++ * Based on glamo-fb.c (C) 2007-2008 by Openmoko, Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ * All rights reserved. ++ * ++ * 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 program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ */ ++ ++#ifndef __GLAMO_KMS_FB_H ++#define __GLAMO_KMS_FB_H ++ ++#include <drm/drmP.h> ++#include "glamo-drm-private.h" ++ ++extern int glamofb_create(struct drm_device *dev, uint32_t fb_width, ++ uint32_t fb_height, uint32_t surface_width, ++ uint32_t surface_height, int colour_mode, ++ struct glamo_framebuffer **glamo_fb_p); ++ ++extern void glamo_kmsfb_suspend(struct glamodrm_handle *gdrm); ++extern void glamo_kmsfb_resume(struct glamodrm_handle *gdrm); ++ ++#endif /* __GLAMO_KMS_FB_H */ +diff --git a/include/drm/Kbuild b/include/drm/Kbuild +index bd3a1c2..a8f06eb 100644 +--- a/include/drm/Kbuild ++++ b/include/drm/Kbuild +@@ -10,3 +10,4 @@ unifdef-y += savage_drm.h + unifdef-y += vmwgfx_drm.h + unifdef-y += via_drm.h + unifdef-y += nouveau_drm.h ++unifdef-y += glamo_drm.h +diff --git a/include/drm/glamo_drm.h b/include/drm/glamo_drm.h +new file mode 100644 +index 0000000..4c194dc +--- /dev/null ++++ b/include/drm/glamo_drm.h +@@ -0,0 +1,153 @@ ++/* glamo_drm.h -- Public header for the Glamo driver ++ * ++ * Copyright 2009 Thomas White ++ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. ++ * Copyright 2000 VA Linux Systems, Inc., Fremont, California. ++ * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Thomas White <taw@bitwiz.org.uk> ++ * Kevin E. Martin <martin@valinux.com> ++ * Gareth Hughes <gareth@valinux.com> ++ * Keith Whitwell <keith@tungstengraphics.com> ++ */ ++ ++#ifndef __GLAMO_DRM_H__ ++#define __GLAMO_DRM_H__ ++ ++#include "drm.h" ++ ++#define GLAMO_GEM_DOMAIN_VRAM (0x1) ++ ++/* Glamo specific ioctls */ ++#define DRM_GLAMO_CMDBUF 0x01 ++#define DRM_GLAMO_SWAP 0x02 ++#define DRM_GLAMO_CMDBURST 0x03 ++ ++#define DRM_GLAMO_GEM_INFO 0x1c ++#define DRM_GLAMO_GEM_CREATE 0x1d ++#define DRM_GLAMO_GEM_MMAP 0x1e ++#define DRM_GLAMO_GEM_PIN 0x1f ++#define DRM_GLAMO_GEM_UNPIN 0x20 ++#define DRM_GLAMO_GEM_PREAD 0x21 ++#define DRM_GLAMO_GEM_PWRITE 0x22 ++#define DRM_GLAMO_GEM_WAIT_RENDERING 0x24 ++ ++#define DRM_IOCTL_GLAMO_CMDBUF DRM_IOW(DRM_COMMAND_BASE + DRM_GLAMO_CMDBUF, drm_glamo_cmd_buffer_t) ++#define DRM_IOCTL_GLAMO_SWAP DRM_IO(DRM_COMMAND_BASE + DRM_GLAMO_SWAP) ++#define DRM_IOCTL_GLAMO_CMDBURST DRM_IOW(DRM_COMMAND_BASE + DRM_GLAMO_CMDBURST, drm_glamo_cmd_burst_t) ++ ++#define DRM_IOCTL_GLAMO_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_INFO, struct drm_glamo_gem_info) ++#define DRM_IOCTL_GLAMO_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_CREATE, struct drm_glamo_gem_create) ++#define DRM_IOCTL_GLAMO_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_MMAP, struct drm_glamo_gem_mmap) ++#define DRM_IOCTL_GLAMO_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_PIN, struct drm_glamo_gem_pin) ++#define DRM_IOCTL_GLAMO_GEM_UNPIN DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_UNPIN, struct drm_glamo_gem_unpin) ++#define DRM_IOCTL_GLAMO_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_PREAD, struct drm_glamo_gem_pread) ++#define DRM_IOCTL_GLAMO_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_GLAMO_GEM_PWRITE, struct drm_glamo_gem_pwrite) ++#define DRM_IOCTL_GLAMO_GEM_WAIT_RENDERING DRM_IOW(DRM_COMMAND_BASE + DRM_GLAMO_GEM_WAIT_RENDERING, struct drm_glamo_gem_wait_rendering) ++ ++ ++/* Simple command submission - a list of 16-bit address-data pairs */ ++typedef struct drm_glamo_cmd_buffer { ++ unsigned int bufsz; /* Size of buffer, in bytes */ ++ char __user *buf; /* Buffer of stuff to go onto the ring buffer */ ++ unsigned int *obj_pos; /* Offsets (in bytes) at which to put objs */ ++ uint32_t *objs; /* List of buffer object (handles) to use */ ++ unsigned int nobjs; /* Number of objects referenced */ ++ int nbox; ++ struct drm_clip_rect __user *boxes; ++} drm_glamo_cmd_buffer_t; ++ ++ ++/* Burst command submission - base address and data: ++ * - Data can be 32-bit (more easily) ++ * - Easier for the kernel to validate */ ++typedef struct drm_glamo_cmd_burst { ++ uint16_t base; /* Base address (command) */ ++ int bufsz; /* Size of data, in bytes */ ++ uint16_t *data; /* Pointer to data */ ++ unsigned int *obj_pos; /* Offsets (in bytes) at which to put objs */ ++ uint32_t *objs; /* List of buffer object (handles) to use */ ++ unsigned int nobjs; /* Number of objects referenced */ ++} drm_glamo_cmd_burst_t; ++ ++struct drm_glamo_gem_info { ++ uint64_t vram_start; ++ uint64_t vram_size; ++}; ++ ++struct drm_glamo_gem_create { ++ uint64_t size; ++ uint64_t alignment; ++ uint32_t handle; ++ uint32_t initial_domain; // to allow VRAM to be created ++ uint32_t no_backing_store; ++}; ++ ++struct drm_glamo_gem_mmap { ++ uint32_t handle; /* Handle goes in... */ ++ uint64_t offset; /* ...offset comes out */ ++}; ++ ++struct drm_glamo_gem_wait_rendering { ++ uint32_t handle; ++ int have_handle; ++}; ++ ++struct drm_glamo_gem_pin { ++ uint32_t handle; ++ uint32_t pin_domain; ++ uint64_t alignment; ++ uint64_t offset; ++}; ++ ++struct drm_glamo_gem_unpin { ++ uint32_t handle; ++ uint32_t pad; ++}; ++ ++struct drm_glamo_gem_pread { ++ /** Handle for the object being read. */ ++ uint32_t handle; ++ uint32_t pad; ++ /** Offset into the object to read from */ ++ uint64_t offset; ++ /** Length of data to read */ ++ uint64_t size; ++ /** Pointer to write the data into. */ ++ uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ ++}; ++ ++struct drm_glamo_gem_pwrite { ++ /** Handle for the object being written to. */ ++ uint32_t handle; ++ uint32_t pad; ++ /** Offset into the object to write to */ ++ uint64_t offset; ++ /** Length of data to write */ ++ uint64_t size; ++ /** Pointer to read the data from. */ ++ uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ ++}; ++ ++#endif +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0002-usbhost.patch.patch b/recipes/linux/linux-openmoko-2.6.34/0002-usbhost.patch.patch new file mode 100644 index 0000000000..ace16502c8 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0002-usbhost.patch.patch @@ -0,0 +1,414 @@ +From cbc005e5e709407bae373d006d06a4cf51fd3062 Mon Sep 17 00:00:00 2001 +From: Radek Polak <psonek2@seznam.cz> +Date: Fri, 9 Apr 2010 09:17:28 +0200 +Subject: [PATCH 2/4] usbhost.patch + +adds support for usb host mode and adds usb host pm sysfs node. I just copied +and modified how modem is powered up and backported changes in ohci-s3c2410.c. +No idea if this is the right approach, but it works - my usb keyboard is now +working after: + +echo 1 > /sys/devices/platform/s3c2440-i2c/i2c-0/0-0073/pcf50633-gpio/reg- +fixed-voltage.2/gta02-pm-usbhost.0/power_on +echo host > /sys/devices/platform/s3c2410-ohci/usb_mode + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- + arch/arm/mach-s3c2440/Makefile | 1 + + arch/arm/mach-s3c2440/gta02-pm-usbhost.c | 174 ++++++++++++++++++++++++++++++ + arch/arm/mach-s3c2440/mach-gta02.c | 48 ++++++++- + drivers/usb/host/ohci-s3c2410.c | 48 ++++++++ + 4 files changed, 270 insertions(+), 1 deletions(-) + create mode 100644 arch/arm/mach-s3c2440/gta02-pm-usbhost.c + +diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile +index 6ce800d..450cff9 100644 +--- a/arch/arm/mach-s3c2440/Makefile ++++ b/arch/arm/mach-s3c2440/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o \ + gta02-pm-bt.o \ + gta02-pm-gps.o \ + gta02-pm-gsm.o \ ++ gta02-pm-usbhost.o \ + gta02-pm-wlan.o \ + gta02-fiq.o \ + +diff --git a/arch/arm/mach-s3c2440/gta02-pm-usbhost.c b/arch/arm/mach-s3c2440/gta02-pm-usbhost.c +new file mode 100644 +index 0000000..233340a +--- /dev/null ++++ b/arch/arm/mach-s3c2440/gta02-pm-usbhost.c +@@ -0,0 +1,174 @@ ++/* ++ * USBHOST Management code for the Openmoko Freerunner GSM Phone ++ * ++ * (C) 2007 by Openmoko Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ * All rights reserved. ++ * ++ * 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/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/console.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/regulator/consumer.h> ++ ++#include <mach/gpio.h> ++#include <asm/mach-types.h> ++ ++#include <mach/hardware.h> ++ ++#include <mach/gta02.h> ++#include <mach/regs-gpio.h> ++#include <mach/regs-gpioj.h> ++ ++static struct regulator *gta02_usbhost_regulator; ++ ++static ssize_t usbhost_read(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ if (!strcmp(attr->attr.name, "power_on")) { ++ if (regulator_is_enabled(gta02_usbhost_regulator)) ++ goto out_1; ++ } ++ ++ return strlcpy(buf, "0\n", 3); ++out_1: ++ return strlcpy(buf, "1\n", 3); ++} ++ ++static void usbhost_on_off(struct device *dev, int on) ++{ ++ ++ on = !!on; ++ ++ if (on == regulator_is_enabled(gta02_usbhost_regulator)) ++ return; ++ ++ if (!on) { ++ regulator_disable(gta02_usbhost_regulator); ++ return; ++ } ++ ++ regulator_enable(gta02_usbhost_regulator); ++} ++ ++static ssize_t usbhost_write(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long on = simple_strtoul(buf, NULL, 10); ++ ++ if (!strcmp(attr->attr.name, "power_on")) { ++ usbhost_on_off(dev, on); ++ ++ return count; ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(power_on, 0644, usbhost_read, usbhost_write); ++ ++#ifdef CONFIG_PM ++ ++static int gta02_usbhost_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int gta02_usbhost_suspend_late(struct device *dev) ++{ ++ return 0; ++} ++ ++static int gta02_usbhost_resume(struct device *dev) ++{ ++ return 0; ++} ++ ++static struct dev_pm_ops gta02_usbhost_pm_ops = { ++ .suspend = gta02_usbhost_suspend, ++ .suspend_noirq = gta02_usbhost_suspend_late, ++ .resume = gta02_usbhost_resume, ++}; ++ ++#define GTA02_USBHOST_PM_OPS (>a02_usbhost_pm_ops) ++ ++#else ++#define GTA02_USBHOST_PM_OPS NULL ++#endif /* CONFIG_PM */ ++ ++static struct attribute *gta02_usbhost_sysfs_entries[] = { ++ &dev_attr_power_on.attr, ++ NULL ++}; ++ ++static struct attribute_group gta02_usbhost_attr_group = { ++ .name = NULL, ++ .attrs = gta02_usbhost_sysfs_entries, ++}; ++ ++static int __init gta02_usbhost_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ gta02_usbhost_regulator = regulator_get_exclusive(&pdev->dev, "USBHOST"); ++ ++ if (IS_ERR(gta02_usbhost_regulator)) { ++ ret = PTR_ERR(gta02_usbhost_regulator); ++ dev_err(&pdev->dev, "Failed to get regulator: %d\n", ret); ++ return ret; ++ } ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, >a02_usbhost_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to create sysfs entries: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int gta02_usbhost_remove(struct platform_device *pdev) ++{ ++ usbhost_on_off(&pdev->dev, 0); ++ ++ sysfs_remove_group(&pdev->dev.kobj, >a02_usbhost_attr_group); ++ regulator_put(gta02_usbhost_regulator); ++ ++ return 0; ++} ++ ++static struct platform_driver gta02_usbhost_driver = { ++ .probe = gta02_usbhost_probe, ++ .remove = gta02_usbhost_remove, ++ .driver = { ++ .name = "gta02-pm-usbhost", ++ .pm = GTA02_USBHOST_PM_OPS, ++ }, ++}; ++ ++static int __devinit gta02_usbhost_init(void) ++{ ++ return platform_driver_register(>a02_usbhost_driver); ++} ++module_init(gta02_usbhost_init); ++ ++static void gta02_usbhost_exit(void) ++{ ++ platform_driver_unregister(>a02_usbhost_driver); ++} ++module_exit(gta02_usbhost_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>"); ++MODULE_DESCRIPTION("Openmoko Freerunner USBHOST Power Management"); +diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c +index 795b9f4..e7d0b82 100644 +--- a/arch/arm/mach-s3c2440/mach-gta02.c ++++ b/arch/arm/mach-s3c2440/mach-gta02.c +@@ -202,6 +202,10 @@ static struct platform_device gta02_pm_gsm_dev = { + .name = "gta02-pm-gsm", + }; + ++static struct platform_device gta02_pm_usbhost_dev = { ++ .name = "gta02-pm-usbhost", ++}; ++ + static struct platform_device gta02_pm_wlan_dev = { + .name = "gta02-pm-wlan", + }; +@@ -211,6 +215,11 @@ static struct regulator_consumer_supply gsm_supply_consumer = { + .supply = "GSM", + }; + ++static struct regulator_consumer_supply usbhost_supply_consumer = { ++ .dev = >a02_pm_usbhost_dev.dev, ++ .supply = "USBHOST", ++}; ++ + static struct regulator_init_data gsm_supply_init_data = { + .constraints = { + .min_uV = 3700000, +@@ -222,6 +231,17 @@ static struct regulator_init_data gsm_supply_init_data = { + .consumer_supplies = &gsm_supply_consumer, + }; + ++static struct regulator_init_data usbhost_supply_init_data = { ++ .constraints = { ++ .min_uV = 3700000, ++ .max_uV = 3700000, ++ .valid_modes_mask = REGULATOR_MODE_NORMAL, ++ .valid_ops_mask = REGULATOR_CHANGE_STATUS, ++ }, ++ .num_consumer_supplies = 1, ++ .consumer_supplies = &usbhost_supply_consumer, ++}; ++ + static struct fixed_voltage_config gsm_supply_config = { + .supply_name = "GSM", + .microvolts = 3700000, +@@ -230,6 +250,14 @@ static struct fixed_voltage_config gsm_supply_config = { + .init_data = &gsm_supply_init_data, + }; + ++static struct fixed_voltage_config usbhost_supply_config = { ++ .supply_name = "USBHOST", ++ .microvolts = 3700000, ++ .gpio = GTA02_GPIO_PCF(PCF50633_GPO), ++ .enable_high = 1, ++ .init_data = &usbhost_supply_init_data, ++}; ++ + static struct platform_device gta02_gsm_supply_device = { + .name = "reg-fixed-voltage", + .id = 1, +@@ -238,6 +266,14 @@ static struct platform_device gta02_gsm_supply_device = { + }, + }; + ++static struct platform_device gta02_usbhost_supply_device = { ++ .name = "reg-fixed-voltage", ++ .id = 2, ++ .dev = { ++ .platform_data = &usbhost_supply_config, ++ }, ++}; ++ + /* + * we crank down SD Card clock dynamically when GPS is powered + */ +@@ -1287,12 +1323,17 @@ struct gta02_device_children { + + static struct platform_device* gta02_pcf50633_gpio_children[] = { + >a02_gsm_supply_device, ++ >a02_usbhost_supply_device, + }; + + static struct platform_device* gta02_gsm_supply_children[] = { + >a02_pm_gsm_dev, + }; + ++static struct platform_device* gta02_usbhost_supply_children[] = { ++ >a02_pm_usbhost_dev, ++}; ++ + static struct platform_device* gta02_hdq_children[] = { + &bq27000_battery_device, + }; +@@ -1301,7 +1342,7 @@ static struct platform_device* gta02_hdq_children[] = { + static struct gta02_device_children gta02_device_children[] = { + { + .dev_name = "pcf50633-gpio", +- .num_children = 1, ++ .num_children = 2, + .children = gta02_pcf50633_gpio_children, + }, + { +@@ -1310,6 +1351,11 @@ static struct gta02_device_children gta02_device_children[] = { + .children = gta02_gsm_supply_children, + }, + { ++ .dev_name = "reg-fixed-voltage.2", ++ .num_children = 1, ++ .children = gta02_usbhost_supply_children, ++ }, ++ { + .dev_name = "spi2.0", + .probed_callback = gta02_jbt6k74_probe_completed, + }, +diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c +index a68af2d..02bd7b0 100644 +--- a/drivers/usb/host/ohci-s3c2410.c ++++ b/drivers/usb/host/ohci-s3c2410.c +@@ -22,6 +22,10 @@ + #include <linux/platform_device.h> + #include <linux/clk.h> + #include <plat/usb-control.h> ++#include <mach/hardware.h> ++#include <mach/gpio-fns.h> ++#include <mach/regs-gpio.h> ++#include <mach/gta02.h> + + #define valid_port(idx) ((idx) == 1 || (idx) == 2) + +@@ -306,6 +310,42 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc) + local_irq_restore(flags); + } + ++/* switching of USB pads */ ++static ssize_t show_usb_mode(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ if (__raw_readl(S3C24XX_MISCCR) & S3C2410_MISCCR_USBHOST) ++ return sprintf(buf, "host\n"); ++ ++ return sprintf(buf, "device\n"); ++} ++ ++static ssize_t set_usb_mode(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ if (!strncmp(buf, "host", 4)) { ++ printk("s3c2410: changing usb to host\n"); ++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, ++ S3C2410_MISCCR_USBHOST); ++ /* FIXME: ++ * - call machine-specific disable-pullup function i ++ * - enable +Vbus (if hardware supports it) ++ */ ++ s3c2410_gpio_setpin(GTA02_GPIO_USB_PULLUP, 0); ++ } else if (!strncmp(buf, "device", 6)) { ++ printk("s3c2410: changing usb to device\n"); ++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, 0); ++ s3c2410_gpio_setpin(GTA02_GPIO_USB_PULLUP, 1); ++ } else { ++ printk("s3c2410: unknown mode\n"); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(usb_mode, S_IRUGO | S_IWUSR, show_usb_mode, set_usb_mode); ++ + /* may be called without controller electrically present */ + /* may be called with controller, bus, and devices active */ + +@@ -323,6 +363,7 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc) + static void + usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) + { ++ device_remove_file(&dev->dev, &dev_attr_usb_mode); + usb_remove_hcd(hcd); + s3c2410_stop_hc(dev); + iounmap(hcd->regs); +@@ -390,8 +431,15 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver, + if (retval != 0) + goto err_ioremap; + ++ retval = device_create_file(&dev->dev, &dev_attr_usb_mode); ++ if (retval != 0) ++ goto err_hcd; ++ + return 0; + ++ err_hcd: ++ usb_remove_hcd(hcd); ++ + err_ioremap: + s3c2410_stop_hc(dev); + iounmap(hcd->regs); +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0003-Work-on-Glamo-core-for-DRM.patch b/recipes/linux/linux-openmoko-2.6.34/0003-Work-on-Glamo-core-for-DRM.patch new file mode 100644 index 0000000000..c9afc89c96 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0003-Work-on-Glamo-core-for-DRM.patch @@ -0,0 +1,162 @@ +From 0c38c5d7bcce1b62534e76419ee04eea0fe50128 Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Tue, 17 Nov 2009 23:45:29 +0100 +Subject: [PATCH 03/13] Work on Glamo-core for DRM + +This adds modifications to the core of the Glamo driver to expose functionality +to support DRM and KMS. + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/mfd/glamo/glamo-core.c | 27 +++++++++++++++++++++------ + drivers/mfd/glamo/glamo-core.h | 32 ++++++++++++++++++++++---------- + drivers/mfd/glamo/glamo-regs.h | 24 ++++++++++++++++++++++++ + include/linux/mfd/glamo.h | 7 ++----- + 4 files changed, 69 insertions(+), 21 deletions(-) + +diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c +index 23073fe..f894c91 100644 +--- a/drivers/mfd/glamo/glamo-core.c ++++ b/drivers/mfd/glamo/glamo-core.c +@@ -222,10 +222,25 @@ static struct resource glamo_fb_resources[] = { + .flags = IORESOURCE_MEM, + }, { + .name = "glamo-fb-mem", +- .start = GLAMO_OFFSET_FB, +- .end = GLAMO_OFFSET_FB + GLAMO_FB_SIZE - 1, ++ .start = GLAMO_MEM_BASE + GLAMO_OFFSET_FB, ++ .end = GLAMO_MEM_BASE + GLAMO_OFFSET_FB + GLAMO_FB_SIZE - 1, + .flags = IORESOURCE_MEM, +- }, ++ }, { ++ .name = "glamo-cmdq-regs", ++ .start = GLAMO_REGOFS_CMDQUEUE, ++ .end = GLAMO_REGOFS_RISC - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = "glamo-2d-regs", ++ .start = GLAMO_REGOFS_2D, ++ .end = GLAMO_REGOFS_3D- 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = "glamo-2d-irq", ++ .start = GLAMO_IRQ_2D, ++ .end = GLAMO_IRQ_2D, ++ .flags = IORESOURCE_IRQ, ++ } + }; + + static struct resource glamo_mmc_resources[] = { +@@ -236,9 +251,9 @@ static struct resource glamo_mmc_resources[] = { + .flags = IORESOURCE_MEM + }, { + .name = "glamo-mmc-mem", +- .start = GLAMO_OFFSET_FB + GLAMO_FB_SIZE, +- .end = GLAMO_OFFSET_FB + GLAMO_FB_SIZE + +- GLAMO_MMC_BUFFER_SIZE - 1, ++ .start = GLAMO_MEM_BASE + GLAMO_OFFSET_MMC, ++ .end = GLAMO_MEM_BASE + GLAMO_OFFSET_MMC ++ + GLAMO_MMC_BUFFER_SIZE - 1, + .flags = IORESOURCE_MEM + }, { + .start = GLAMO_IRQ_MMC, +diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h +index 17017b0..0adba96 100644 +--- a/drivers/mfd/glamo/glamo-core.h ++++ b/drivers/mfd/glamo/glamo-core.h +@@ -3,18 +3,30 @@ + + #include <linux/mfd/glamo.h> + ++/* Amount of Glamo memory */ ++#define GLAMO_INTERNAL_RAM_SIZE 0x800000 ++ ++/* Arbitrarily determined amount for the hardware cursor */ ++#define GLAMO_CURSOR_SIZE (4096) ++#define GLAMO_MMC_BUFFER_SIZE (64 * 1024) /* 64k MMC buffer */ ++/* Remaining memory will be used for 2D and 3D graphics */ ++#define GLAMO_FB_SIZE (GLAMO_INTERNAL_RAM_SIZE \ ++ - GLAMO_CURSOR_SIZE \ ++ - GLAMO_MMC_BUFFER_SIZE) ++/* A 640x480, 16bpp, double-buffered framebuffer */ ++#if (GLAMO_FB_SIZE < (640 * 480 * 4)) /* == 0x12c000 */ ++#error Not enough Glamo VRAM for framebuffer! ++#endif ++ + /* for the time being, we put the on-screen framebuffer into the lowest + * VRAM space. This should make the code easily compatible with the various +- * 2MB/4MB/8MB variants of the Smedia chips */ +-#define GLAMO_OFFSET_VRAM 0x800000 +-#define GLAMO_OFFSET_FB (GLAMO_OFFSET_VRAM) +- +-/* we only allocate the minimum possible size for the framebuffer to make +- * sure we have sufficient memory for other functions of the chip */ +-/*#define GLAMO_FB_SIZE (640*480*4) *//* == 0x12c000 */ +-#define GLAMO_INTERNAL_RAM_SIZE 0x800000 +-#define GLAMO_MMC_BUFFER_SIZE (64 * 1024) +-#define GLAMO_FB_SIZE (GLAMO_INTERNAL_RAM_SIZE - GLAMO_MMC_BUFFER_SIZE) ++ * 2MB/4MB/8MB variants of the Smedia chips ++ * glamo-fb.c assumes FB comes first, followed by cursor, so DON'T MOVE THEM ++ * (see glamo_regs[] in glamo-fb.c for more information) */ ++#define GLAMO_MEM_BASE (0x800000) ++#define GLAMO_OFFSET_FB (0x000000) ++#define GLAMO_OFFSET_CURSOR (GLAMO_OFFSET_FB + GLAMO_FB_SIZE) ++#define GLAMO_OFFSET_MMC (GLAMO_OFFSET_CURSOR + GLAMO_CURSOR_SIZE) + + enum glamo_pll { + GLAMO_PLL1, +diff --git a/drivers/mfd/glamo/glamo-regs.h b/drivers/mfd/glamo/glamo-regs.h +index 59848e1..8b2fd47 100644 +--- a/drivers/mfd/glamo/glamo-regs.h ++++ b/drivers/mfd/glamo/glamo-regs.h +@@ -627,4 +627,28 @@ enum glamo_core_revisions { + GLAMO_CORE_REV_A3 = 0x0003, + }; + ++enum glamo_register_cq { ++ GLAMO_REG_CMDQ_BASE_ADDRL = 0x00, ++ GLAMO_REG_CMDQ_BASE_ADDRH = 0x02, ++ GLAMO_REG_CMDQ_LEN = 0x04, ++ GLAMO_REG_CMDQ_WRITE_ADDRL = 0x06, ++ GLAMO_REG_CMDQ_WRITE_ADDRH = 0x08, ++ GLAMO_REG_CMDQ_FLIP = 0x0a, ++ GLAMO_REG_CMDQ_CONTROL = 0x0c, ++ GLAMO_REG_CMDQ_READ_ADDRL = 0x0e, ++ GLAMO_REG_CMDQ_READ_ADDRH = 0x10, ++ GLAMO_REG_CMDQ_STATUS = 0x12, ++}; ++ ++#define REG_2D(x) (GLAMO_REGOFS_2D+(x)) ++ ++enum glamo_register_2d { ++ GLAMO_REG_2D_DST_X = REG_2D(0x0a), ++ GLAMO_REG_2D_COMMAND1 = REG_2D(0x3a), ++ GLAMO_REG_2D_STATUS = REG_2D(0x42), ++ GLAMO_REG_2D_ID1 = REG_2D(0x44), ++ GLAMO_REG_2D_ID2 = REG_2D(0x46), ++ GLAMO_REG_2D_ID3 = REG_2D(0x48), ++}; ++ + #endif /* _GLAMO_REGS_H */ +diff --git a/include/linux/mfd/glamo.h b/include/linux/mfd/glamo.h +index 529d4f0..ea91a06 100644 +--- a/include/linux/mfd/glamo.h ++++ b/include/linux/mfd/glamo.h +@@ -41,12 +41,9 @@ enum glamo_engine { + GLAMO_ENGINE_RISC = 11, + GLAMO_ENGINE_MICROP1_MPEG_ENC = 12, + GLAMO_ENGINE_MICROP1_MPEG_DEC = 13, +-#if 0 +- GLAMO_ENGINE_H264_DEC = 14, +- GLAMO_ENGINE_RISC1 = 15, +- GLAMO_ENGINE_SPI = 16, +-#endif + __NUM_GLAMO_ENGINES + }; + ++#define GLAMO_ENGINE_ALL (__NUM_GLAMO_ENGINES) ++ + #endif +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0003-ar6000_delay.patch.patch b/recipes/linux/linux-openmoko-2.6.34/0003-ar6000_delay.patch.patch new file mode 100644 index 0000000000..8241a1f7fa --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0003-ar6000_delay.patch.patch @@ -0,0 +1,29 @@ +From 3287722e641d6e21cb0e2a8fa13058467a5319e3 Mon Sep 17 00:00:00 2001 +From: Radek Polak <psonek2@seznam.cz> +Date: Fri, 9 Apr 2010 09:18:02 +0200 +Subject: [PATCH 3/4] ar6000_delay.patch + +patch from https://docs.openmoko.org/trac/ticket/2327 - wifi is working good +(100% until now) for me with this patch. + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- + drivers/ar6000/hif/hif2.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/ar6000/hif/hif2.c b/drivers/ar6000/hif/hif2.c +index 386d96e..90178d0 100644 +--- a/drivers/ar6000/hif/hif2.c ++++ b/drivers/ar6000/hif/hif2.c +@@ -517,6 +517,8 @@ static int ar6000_do_activate(struct hif_device *hif) + goto out_func_ready; + } + ++ mdelay (10); ++ + ret = htcCallbacks.deviceInsertedHandler(hif); + if (ret == A_OK) + return 0; +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch b/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch new file mode 100644 index 0000000000..692896f957 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0004-JBT6k74-work-for-KMS.patch @@ -0,0 +1,540 @@ +From 2042106d96a13c2a15f1425fe9133257b1e0fbed Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Sat, 21 Nov 2009 21:42:16 +0100 +Subject: [PATCH 04/13] JBT6k74 work for KMS + +This simplifies the JBT6k74 driver, and adds hooks for the Glamo driver to cooperate +more closely with it. + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/video/backlight/jbt6k74.c | 252 ++++++++++++++++++------------------ + include/linux/jbt6k74.h | 17 +++- + 2 files changed, 142 insertions(+), 127 deletions(-) + +diff --git a/drivers/video/backlight/jbt6k74.c b/drivers/video/backlight/jbt6k74.c +index 8450904..91651e7 100644 +--- a/drivers/video/backlight/jbt6k74.c ++++ b/drivers/video/backlight/jbt6k74.c +@@ -101,20 +101,10 @@ enum jbt_register { + JBT_REG_HCLOCK_QVGA = 0xed, + }; + +-enum jbt_resolution { +- JBT_RESOLUTION_VGA, +- JBT_RESOLUTION_QVGA, +-}; +- +-enum jbt_power_mode { +- JBT_POWER_MODE_DEEP_STANDBY, +- JBT_POWER_MODE_SLEEP, +- JBT_POWER_MODE_NORMAL, +-}; + + static const char *jbt_power_mode_names[] = { +- [JBT_POWER_MODE_DEEP_STANDBY] = "deep-standby", +- [JBT_POWER_MODE_SLEEP] = "sleep", ++ [JBT_POWER_MODE_OFF] = "off", ++ [JBT_POWER_MODE_STANDBY] = "standby", + [JBT_POWER_MODE_NORMAL] = "normal", + }; + +@@ -123,6 +113,7 @@ static const char *jbt_resolution_names[] = { + [JBT_RESOLUTION_QVGA] = "qvga", + }; + ++ + struct jbt_info { + struct mutex lock; /* protects this structure */ + enum jbt_resolution resolution; +@@ -141,6 +132,8 @@ struct jbt_info { + uint16_t reg_cache[0xEE]; + }; + ++struct jbt_info *jbt_global; ++ + #define JBT_COMMAND 0x000 + #define JBT_DATA 0x100 + +@@ -156,6 +149,8 @@ static int jbt_reg_write_nodata(struct jbt_info *jbt, uint8_t reg) + else + dev_err(&jbt->spi->dev, "Write failed: %d\n", ret); + ++ mdelay(1); ++ + return ret; + } + +@@ -173,6 +168,8 @@ static int jbt_reg_write(struct jbt_info *jbt, uint8_t reg, uint8_t data) + else + dev_err(&jbt->spi->dev, "Write failed: %d\n", ret); + ++ mdelay(1); ++ + return ret; + } + +@@ -191,6 +188,8 @@ static int jbt_reg_write16(struct jbt_info *jbt, uint8_t reg, uint16_t data) + else + dev_err(&jbt->spi->dev, "Write failed: %d\n", ret); + ++ mdelay(1); ++ + return ret; + } + +@@ -218,7 +217,7 @@ static int jbt_init_regs(struct jbt_info *jbt) + * to avoid red / blue flicker + */ + ret |= jbt_reg_write(jbt, JBT_REG_ASW_SLEW, 0x00 | (1 << 5)); +- ret |= jbt_reg_write(jbt, JBT_REG_DUMMY_DISPLAY, 0x00); ++ ret |= jbt_reg_write(jbt, JBT_REG_DUMMY_DISPLAY, 0xff); + + ret |= jbt_reg_write(jbt, JBT_REG_SLEEP_OUT_FR_A, 0x11); + ret |= jbt_reg_write(jbt, JBT_REG_SLEEP_OUT_FR_B, 0x11); +@@ -260,14 +259,18 @@ static int jbt_init_regs(struct jbt_info *jbt) + return ret ? -EIO : 0; + } + +-static int jbt_standby_to_sleep(struct jbt_info *jbt) ++ ++static int jbt_off_to_normal(struct jbt_info *jbt) + { + int ret; ++ + struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data; + + gpio_set_value_cansleep(pdata->gpio_reset, 1); + ret = regulator_bulk_enable(ARRAY_SIZE(jbt->supplies), jbt->supplies); + ++ mdelay(120); ++ + /* three times command zero */ + ret |= jbt_reg_write_nodata(jbt, 0x00); + mdelay(1); +@@ -279,18 +282,11 @@ static int jbt_standby_to_sleep(struct jbt_info *jbt) + /* deep standby out */ + ret |= jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x11); + mdelay(1); +- ret = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x28); ++ ret |= jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x28); + + /* (re)initialize register set */ + ret |= jbt_init_regs(jbt); + +- return ret ? -EIO : 0; +-} +- +-static int jbt_sleep_to_normal(struct jbt_info *jbt) +-{ +- int ret; +- + /* Make sure we are 120 ms after SLEEP_OUT */ + if (time_before(jiffies, jbt->next_sleep)) + mdelay(jiffies_to_msecs(jbt->next_sleep - jiffies)); +@@ -320,6 +316,7 @@ static int jbt_sleep_to_normal(struct jbt_info *jbt) + + /* Sleep mode off */ + ret |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT); ++ + jbt->next_sleep = jiffies + msecs_to_jiffies(120); + + /* Allow the booster and display controller to restart stably */ +@@ -328,45 +325,68 @@ static int jbt_sleep_to_normal(struct jbt_info *jbt) + return ret ? -EIO : 0; + } + +-static int jbt_normal_to_sleep(struct jbt_info *jbt) ++static int jbt_normal_to_off(struct jbt_info *jbt) + { + int ret; ++ struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data; + +- /* Make sure we are 120 ms after SLEEP_OUT */ +- while (time_before(jiffies, jbt->next_sleep)) +- cpu_relax(); ++ /* Pull the plug! */ ++ ret = regulator_bulk_disable(ARRAY_SIZE(jbt->supplies), ++ jbt->supplies); + ++ if (!ret) ++ gpio_set_value_cansleep(pdata->gpio_reset, 0); ++ ++ return ret ? -EIO : 0; ++} ++ ++ ++static int jbt_normal_to_standby(struct jbt_info *jbt) ++{ ++ int ret; ++ ++ if ( jbt->power_mode != JBT_POWER_MODE_NORMAL ) return 0; ++ ++ /* Make sure we are 120 ms after SLEEP_{IN,OUT} */ ++ while (time_before(jiffies, jbt->next_sleep)) cpu_relax(); ++ ++ /* Sleep mode on */ + ret = jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_OFF); + ret |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0x8000 | 1 << 3); ++ + ret |= jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_IN); +- jbt->next_sleep = jiffies + msecs_to_jiffies(120); ++ jbt->next_sleep = jiffies + msecs_to_jiffies(150); + +- /* Allow the internal circuits to stop automatically */ +- mdelay(5); ++ jbt->power_mode = JBT_POWER_MODE_STANDBY; + + return ret ? -EIO : 0; + } + +-static int jbt_sleep_to_standby(struct jbt_info *jbt) ++ ++static int jbt_standby_to_normal(struct jbt_info *jbt) + { + int ret; +- struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data; + +- ret = jbt_reg_write(jbt, JBT_REG_POWER_ON_OFF, 0x00); ++ if ( jbt->power_mode != JBT_POWER_MODE_STANDBY ) return 0; + +- if (!ret) +- ret = regulator_bulk_disable(ARRAY_SIZE(jbt->supplies), jbt->supplies); ++ /* Make sure we are 120 ms after SLEEP_{IN,OUT} */ ++ while (time_before(jiffies, jbt->next_sleep)) cpu_relax(); + +- if (!ret) +- gpio_set_value_cansleep(pdata->gpio_reset, 0); ++ ret = jbt_reg_write_nodata(jbt, JBT_REG_SLEEP_OUT); ++ jbt->next_sleep = jiffies + msecs_to_jiffies(150); + +- return ret; ++ ret |= jbt_reg_write_nodata(jbt, JBT_REG_DISPLAY_ON); ++ ret |= jbt_reg_write16(jbt, JBT_REG_OUTPUT_CONTROL, 0xdff9); ++ ++ jbt->power_mode = JBT_POWER_MODE_NORMAL; ++ ++ return ret ? -EIO : 0; + } + ++ + static int jbt6k74_enter_power_mode(struct jbt_info *jbt, + enum jbt_power_mode new_mode) + { +- struct jbt6k74_platform_data *pdata = jbt->spi->dev.platform_data; + int ret = -EINVAL; + + dev_dbg(&jbt->spi->dev, "entering (old_state=%s, new_state=%s)\n", +@@ -375,49 +395,17 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt, + + mutex_lock(&jbt->lock); + +- if (jbt->suspended) { +- switch (new_mode) { +- case JBT_POWER_MODE_DEEP_STANDBY: +- case JBT_POWER_MODE_SLEEP: +- case JBT_POWER_MODE_NORMAL: +- ret = 0; +- jbt->suspend_mode = new_mode; +- break; +- default: +- break; +- } +- } else if (new_mode == JBT_POWER_MODE_NORMAL && +- pdata->enable_pixel_clock) { +- pdata->enable_pixel_clock(&jbt->spi->dev, 1); +- } +- + switch (jbt->power_mode) { +- case JBT_POWER_MODE_DEEP_STANDBY: ++ case JBT_POWER_MODE_OFF: + switch (new_mode) { +- case JBT_POWER_MODE_DEEP_STANDBY: ++ case JBT_POWER_MODE_OFF: + ret = 0; + break; +- case JBT_POWER_MODE_SLEEP: +- ret = jbt_standby_to_sleep(jbt); +- break; + case JBT_POWER_MODE_NORMAL: +- /* first transition into sleep */ +- ret = jbt_standby_to_sleep(jbt); +- /* then transition into normal */ +- ret |= jbt_sleep_to_normal(jbt); ++ ret = jbt_off_to_normal(jbt); + break; +- } +- break; +- case JBT_POWER_MODE_SLEEP: +- switch (new_mode) { +- case JBT_POWER_MODE_SLEEP: +- ret = 0; +- break; +- case JBT_POWER_MODE_DEEP_STANDBY: +- ret = jbt_sleep_to_standby(jbt); +- break; +- case JBT_POWER_MODE_NORMAL: +- ret = jbt_sleep_to_normal(jbt); ++ case JBT_POWER_MODE_STANDBY: ++ ret = -EINVAL; + break; + } + break; +@@ -426,25 +414,23 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt, + case JBT_POWER_MODE_NORMAL: + ret = 0; + break; +- case JBT_POWER_MODE_DEEP_STANDBY: +- /* first transition into sleep */ +- ret = jbt_normal_to_sleep(jbt); +- /* then transition into deep standby */ +- ret |= jbt_sleep_to_standby(jbt); ++ case JBT_POWER_MODE_OFF: ++ ret = jbt_normal_to_off(jbt); + break; +- case JBT_POWER_MODE_SLEEP: +- ret = jbt_normal_to_sleep(jbt); ++ case JBT_POWER_MODE_STANDBY: ++ ret = -EINVAL; + break; + } ++ break; ++ case JBT_POWER_MODE_STANDBY: ++ ret = -EINVAL; ++ break; + } + + if (ret == 0) { + jbt->power_mode = new_mode; +- if (new_mode != JBT_POWER_MODE_NORMAL && +- pdata->enable_pixel_clock) +- pdata->enable_pixel_clock(&jbt->spi->dev, 0); + } else { +- dev_err(&jbt->spi->dev, "Failed enter state '%s': %d\n", ++ dev_err(&jbt->spi->dev, "Failed to enter state '%s': %d\n", + jbt_power_mode_names[new_mode], ret); + } + +@@ -456,28 +442,46 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt, + static int jbt6k74_set_resolution(struct jbt_info *jbt, + enum jbt_resolution new_resolution) + { ++ int old_resolution; + int ret = 0; +- enum jbt_resolution old_resolution; ++ ++ if ( !jbt ) return -1; + + mutex_lock(&jbt->lock); + +- if (jbt->resolution == new_resolution) +- goto out_unlock; ++ if ( jbt->resolution == new_resolution ) goto out_unlock; ++ if ( jbt->power_mode == JBT_POWER_MODE_OFF ) goto out_unlock; + + old_resolution = jbt->resolution; + jbt->resolution = new_resolution; + +- if (jbt->power_mode == JBT_POWER_MODE_NORMAL) { ++ if ( jbt->power_mode == JBT_POWER_MODE_NORMAL ) { ++ ++ ret = jbt_normal_to_standby(jbt); ++ ++ mdelay(25); + +- /* first transition into sleep */ +- ret = jbt_normal_to_sleep(jbt); +- ret |= jbt_sleep_to_normal(jbt); ++ if (jbt->resolution == JBT_RESOLUTION_VGA) { ++ /* Quad mode off */ ++ ret |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x00); ++ ret = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x80); ++ } else { ++ /* Quad mode on */ ++ ret |= jbt_reg_write(jbt, JBT_REG_QUAD_RATE, 0x22); ++ ret = jbt_reg_write(jbt, JBT_REG_DISPLAY_MODE, 0x81); ++ } ++ ++ mdelay(25); ++ ++ ret |= jbt_standby_to_normal(jbt); + + if (ret) { + jbt->resolution = old_resolution; +- dev_err(&jbt->spi->dev, "Failed to set resolution '%s')\n", ++ dev_err(&jbt->spi->dev, ++ "Failed to set resolution '%s')\n", + jbt_resolution_names[new_resolution]); + } ++ + } + + out_unlock: +@@ -589,7 +593,7 @@ static ssize_t reset_write(struct device *dev, struct device_attribute *attr, + + mutex_unlock(&jbt->lock); + +- jbt->power_mode = JBT_POWER_MODE_DEEP_STANDBY; ++ jbt->power_mode = JBT_POWER_MODE_OFF; + jbt6k74_enter_power_mode(jbt, old_power_mode); + + return count; +@@ -616,27 +620,6 @@ static struct attribute_group jbt_attr_group = { + .attrs = jbt_sysfs_entries, + }; + +-/* FIXME: This in an ugly hack to delay display blanking. +- When the jbt is in sleep mode it displays an all white screen and thus one +- will a see a short flash. +- By delaying the blanking we will give the backlight a chance to turn off and +- thus avoid getting the flash */ +-static void jbt_blank_worker(struct work_struct *work) +-{ +- struct jbt_info *jbt = container_of(work, struct jbt_info, +- blank_work.work); +- +- switch (jbt->blank_mode) { +- case FB_BLANK_NORMAL: +- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_SLEEP); +- break; +- case FB_BLANK_POWERDOWN: +- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_DEEP_STANDBY); +- break; +- default: +- break; +- } +-} + + static int jbt6k74_set_mode(struct lcd_device *ld, struct fb_videomode *m) + { +@@ -649,7 +632,7 @@ static int jbt6k74_set_mode(struct lcd_device *ld, struct fb_videomode *m) + ret = jbt6k74_set_resolution(jbt, JBT_RESOLUTION_VGA); + } else { + dev_err(&jbt->spi->dev, "Unknown resolution.\n"); +- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_SLEEP); ++ jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF); + } + + return ret; +@@ -671,11 +654,11 @@ static int jbt6k74_set_power(struct lcd_device *ld, int power) + break; + case FB_BLANK_NORMAL: + dev_dbg(&jbt->spi->dev, "blank\n"); +- ret = schedule_delayed_work(&jbt->blank_work, HZ); ++ ret = jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF); + break; + case FB_BLANK_POWERDOWN: + dev_dbg(&jbt->spi->dev, "powerdown\n"); +- ret = schedule_delayed_work(&jbt->blank_work, HZ); ++ ret = jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF); + break; + default: + break; +@@ -691,10 +674,10 @@ static int jbt6k74_get_power(struct lcd_device *ld) + switch (jbt->power_mode) { + case JBT_POWER_MODE_NORMAL: + return FB_BLANK_UNBLANK; +- case JBT_POWER_MODE_SLEEP: ++ case JBT_POWER_MODE_OFF: + return FB_BLANK_NORMAL; + default: +- return JBT_POWER_MODE_DEEP_STANDBY; ++ return JBT_POWER_MODE_OFF; + } + } + +@@ -728,6 +711,8 @@ static int __devinit jbt_probe(struct spi_device *spi) + if (!jbt) + return -ENOMEM; + ++ jbt_global = jbt; ++ + jbt->spi = spi; + + jbt->lcd_dev = lcd_device_register("jbt6k74-lcd", &spi->dev, jbt, +@@ -738,11 +723,9 @@ static int __devinit jbt_probe(struct spi_device *spi) + goto err_free_drvdata; + } + +- INIT_DELAYED_WORK(&jbt->blank_work, jbt_blank_worker); +- + jbt->resolution = JBT_RESOLUTION_VGA; +- jbt->power_mode = JBT_POWER_MODE_DEEP_STANDBY; + jbt->next_sleep = jiffies + msecs_to_jiffies(120); ++ jbt->power_mode = JBT_POWER_MODE_OFF; + mutex_init(&jbt->lock); + + dev_set_drvdata(&spi->dev, jbt); +@@ -831,6 +814,24 @@ static int __devexit jbt_remove(struct spi_device *spi) + return 0; + } + ++/* Begin horrible layering violations in the interest of making stuff work */ ++ ++int jbt6k74_finish_resolutionchange(enum jbt_resolution new_resolution) ++{ ++ if ( !jbt_global ) return 0; ++ return jbt6k74_set_resolution(jbt_global, new_resolution); ++} ++EXPORT_SYMBOL_GPL(jbt6k74_finish_resolutionchange); ++ ++void jbt6k74_setpower(enum jbt_power_mode new_power) ++{ ++ if ( !jbt_global ) return; ++ jbt6k74_enter_power_mode(jbt_global, new_power); ++} ++EXPORT_SYMBOL_GPL(jbt6k74_setpower); ++ ++/* End horrible layering violations */ ++ + #ifdef CONFIG_PM + static int jbt_suspend(struct spi_device *spi, pm_message_t state) + { +@@ -838,8 +839,7 @@ static int jbt_suspend(struct spi_device *spi, pm_message_t state) + + jbt->suspend_mode = jbt->power_mode; + +- jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_DEEP_STANDBY); +- jbt->suspended = 1; ++ jbt6k74_enter_power_mode(jbt, JBT_POWER_MODE_OFF); + + dev_info(&spi->dev, "suspended\n"); + +diff --git a/include/linux/jbt6k74.h b/include/linux/jbt6k74.h +index 75488c4..2010bdc 100644 +--- a/include/linux/jbt6k74.h ++++ b/include/linux/jbt6k74.h +@@ -3,6 +3,22 @@ + + #include <linux/spi/spi.h> + ++enum jbt_resolution { ++ JBT_RESOLUTION_VGA, ++ JBT_RESOLUTION_QVGA, ++}; ++ ++enum jbt_power_mode { ++ JBT_POWER_MODE_OFF, ++ JBT_POWER_MODE_STANDBY, ++ JBT_POWER_MODE_NORMAL, ++}; ++ ++extern void jbt6k74_setpower(enum jbt_power_mode new_power); ++extern int jbt6k74_prepare_resolutionchange(enum jbt_resolution new_resolution); ++extern int jbt6k74_finish_resolutionchange(enum jbt_resolution new_resolution); ++ ++ + /* + * struct jbt6k74_platform_data - Platform data for jbt6k74 driver + * @probe_completed: Callback to be called when the driver has been +@@ -13,7 +29,6 @@ + */ + struct jbt6k74_platform_data { + void (*probe_completed)(struct device *dev); +- void (*enable_pixel_clock)(struct device *dev, int enable); + + int gpio_reset; + }; +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0004-save_regs.patch.patch b/recipes/linux/linux-openmoko-2.6.34/0004-save_regs.patch.patch new file mode 100644 index 0000000000..185d9a1b99 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0004-save_regs.patch.patch @@ -0,0 +1,140 @@ +From b166d6d4fb0f5ed66b785e0c662db5fbd2f86e8c Mon Sep 17 00:00:00 2001 +From: Radek Polak <psonek2@seznam.cz> +Date: Fri, 9 Apr 2010 09:22:23 +0200 +Subject: [PATCH 4/4] save_regs.patch + +With this patch wifi can survive suspend. +--- + drivers/mmc/core/core.c | 3 +- + drivers/mmc/host/s3cmci.c | 46 +++++++++++++++++++++++++++++++++++++++++++- + drivers/mmc/host/s3cmci.h | 8 +++++++ + include/linux/mmc/core.h | 2 + + 4 files changed, 56 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index 3168ebd..8504458 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -75,10 +75,11 @@ static int mmc_schedule_delayed_work(struct delayed_work *work, + /* + * Internal function. Flush all scheduled work from the MMC work queue. + */ +-static void mmc_flush_scheduled_work(void) ++void mmc_flush_scheduled_work(void) + { + flush_workqueue(workqueue); + } ++EXPORT_SYMBOL_GPL(mmc_flush_scheduled_work); + + /** + * mmc_request_done - finish processing an MMC request +diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c +index 2fdf768..5f3effc 100644 +--- a/drivers/mmc/host/s3cmci.c ++++ b/drivers/mmc/host/s3cmci.c +@@ -1878,19 +1878,61 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); + + #ifdef CONFIG_PM + ++static int save_regs(struct mmc_host *mmc) ++{ ++ struct s3cmci_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ unsigned from; ++ u32 *to = host->saved; ++ ++ mmc_flush_scheduled_work(); ++ ++ local_irq_save(flags); ++ for (from = S3C2410_SDICON; from != S3C2410_SDIIMSK+4; from += 4) ++ if (from != host->sdidata) ++ *to++ = readl(host->base + from); ++ BUG_ON(to-host->saved != ARRAY_SIZE(host->saved)); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static int restore_regs(struct mmc_host *mmc) ++{ ++ struct s3cmci_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ unsigned to; ++ u32 *from = host->saved; ++ ++ /* ++ * Before we begin with the necromancy, make sure we don't ++ * inadvertently start something we'll regret microseconds later. ++ */ ++ from[S3C2410_SDICMDCON - S3C2410_SDICON] = 0; ++ ++ local_irq_save(flags); ++ for (to = S3C2410_SDICON; to != S3C2410_SDIIMSK+4; to += 4) ++ if (to != host->sdidata) ++ writel(*from++, host->base + to); ++ BUG_ON(from-host->saved != ARRAY_SIZE(host->saved)); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ + static int s3cmci_suspend(struct device *dev) + { + struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); + struct pm_message event = { PM_EVENT_SUSPEND }; + +- return mmc_suspend_host(mmc, event); ++ return save_regs(mmc); + } + + static int s3cmci_resume(struct device *dev) + { + struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); + +- return mmc_resume_host(mmc); ++ return restore_regs(mmc); + } + + static const struct dev_pm_ops s3cmci_pm = { +diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h +index c76b53d..551e715 100644 +--- a/drivers/mmc/host/s3cmci.h ++++ b/drivers/mmc/host/s3cmci.h +@@ -8,6 +8,8 @@ + * published by the Free Software Foundation. + */ + ++#include <mach/regs-sdi.h> ++ + enum s3cmci_waitfor { + COMPLETION_NONE, + COMPLETION_FINALIZE, +@@ -27,6 +29,12 @@ struct s3cmci_host { + int irq; + int irq_cd; + int dma; ++ /* ++ * Here's where we save the registers during suspend. Note that we skip ++ * SDIDATA, which is at different positions on 2410 and 2440, so ++ * there's no "+1" in the array size. ++ */ ++ u32 saved[(S3C2410_SDIIMSK-S3C2410_SDICON)/4]; + + unsigned long clk_rate; + unsigned long clk_div; +diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h +index e4898e9..b49d674 100644 +--- a/include/linux/mmc/core.h ++++ b/include/linux/mmc/core.h +@@ -129,6 +129,8 @@ struct mmc_request { + struct mmc_host; + struct mmc_card; + ++extern void mmc_flush_scheduled_work(void); ++ + extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); + extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); + extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0005-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch b/recipes/linux/linux-openmoko-2.6.34/0005-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch new file mode 100644 index 0000000000..cf73609478 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0005-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch @@ -0,0 +1,38 @@ +From 9cd5001fc2f4c817d5614b1ee5445d69af05d483 Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Thu, 4 Feb 2010 00:07:25 +0100 +Subject: [PATCH 05/13] Fix crash when reading Glamo registers via sysfs + +glamo-core didn't ioremap() some areas, so don't try to read them. + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/mfd/glamo/glamo-core.c | 8 ++++---- + 1 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c +index f894c91..a54106b 100644 +--- a/drivers/mfd/glamo/glamo-core.c ++++ b/drivers/mfd/glamo/glamo-core.c +@@ -91,14 +91,14 @@ static const struct reg_range reg_range[] = { + /* { 0x0500, 0x300, "ISP", 0 }, */ + /* { 0x0800, 0x400, "JPEG", 0 }, */ + /* { 0x0c00, 0xcc, "MPEG", 0 }, */ +- { 0x1100, 0xb2, "LCD 1", 1 }, +- { 0x1200, 0x64, "LCD 2", 1 }, +- { 0x1400, 0x42, "MMC", 1 }, ++ { 0x1100, 0xb2, "LCD 1", 0 }, ++ { 0x1200, 0x64, "LCD 2", 0 }, ++ { 0x1400, 0x42, "MMC", 0 }, + /* { 0x1500, 0x080, "MPU 0", 0 }, + { 0x1580, 0x080, "MPU 1", 0 }, + { 0x1600, 0x080, "Cmd Queue", 0 }, + { 0x1680, 0x080, "RISC CPU", 0 },*/ +- { 0x1700, 0x400, "2D Unit", 1 }, ++ { 0x1700, 0x400, "2D Unit", 0 }, + /* { 0x1b00, 0x900, "3D Unit", 0 }, */ + }; + +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0006-Fix-dynamic-command-queue-allocation.patch b/recipes/linux/linux-openmoko-2.6.34/0006-Fix-dynamic-command-queue-allocation.patch new file mode 100644 index 0000000000..ea570723d4 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0006-Fix-dynamic-command-queue-allocation.patch @@ -0,0 +1,131 @@ +From 752dfe99a5e2b361f740f2f986de93f5682b1a8d Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Thu, 6 May 2010 05:40:15 -0700 +Subject: [PATCH 06/13] Fix dynamic command queue allocation + +(Not tested...) + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/mfd/glamo/glamo-cmdq.c | 10 +++++++--- + drivers/mfd/glamo/glamo-cmdq.h | 2 +- + drivers/mfd/glamo/glamo-drm-drv.c | 17 +++++++---------- + 3 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/drivers/mfd/glamo/glamo-cmdq.c b/drivers/mfd/glamo/glamo-cmdq.c +index 442963c..28c5268 100644 +--- a/drivers/mfd/glamo/glamo-cmdq.c ++++ b/drivers/mfd/glamo/glamo-cmdq.c +@@ -57,6 +57,7 @@ + #include "glamo-core.h" + #include "glamo-drm-private.h" + #include "glamo-regs.h" ++#include "glamo-buffer.h" + + + #define GLAMO_CMDQ_SIZE (128 * 1024) /* 128k ring buffer */ +@@ -495,10 +496,11 @@ int glamo_cmdq_setup(struct glamodrm_handle *gdrm) + } + + +-int glamo_cmdq_init(struct glamodrm_handle *gdrm) ++int glamo_cmdq_init(struct drm_device *dev) + { + struct drm_gem_object *obj; + struct drm_glamo_gem_object *gobj; ++ struct glamodrm_handle *gdrm = dev->dev_private; + int ret = 0; + + obj = glamo_gem_object_alloc(dev, GLAMO_CMDQ_SIZE, 4); +@@ -507,9 +509,10 @@ int glamo_cmdq_init(struct glamodrm_handle *gdrm) + ret = -ENOMEM; + goto out; + } +- gobj = fbo->driver_private; ++ gobj = obj->driver_private; + gdrm->cmdq_offs = GLAMO_OFFSET_FB + gobj->block->start; +- gdrm->cmdq_base = ioremap(gdrm->vram->start + offs, GLAMO_CMDQ_SIZE); ++ gdrm->cmdq_base = ioremap(gdrm->vram->start + gdrm->cmdq_offs, ++ GLAMO_CMDQ_SIZE); + + /* Set up registers */ + glamo_cmdq_setup(gdrm); +@@ -521,6 +524,7 @@ out: + + int glamo_cmdq_shutdown(struct glamodrm_handle *gdrm) + { ++ iounmap(gdrm->cmdq_base); + return 0; + } + +diff --git a/drivers/mfd/glamo/glamo-cmdq.h b/drivers/mfd/glamo/glamo-cmdq.h +index 510d195..6d7f184 100644 +--- a/drivers/mfd/glamo/glamo-cmdq.h ++++ b/drivers/mfd/glamo/glamo-cmdq.h +@@ -38,7 +38,7 @@ extern int glamo_ioctl_cmdburst(struct drm_device *dev, void *data, + extern void glamo_cmdq_blank(struct glamodrm_handle *gdrm, + struct drm_gem_object *obj); + +-extern int glamo_cmdq_init(struct glamodrm_handle *gdrm); ++extern int glamo_cmdq_init(struct drm_device *de); + extern int glamo_cmdq_shutdown(struct glamodrm_handle *gdrm); + extern void glamo_cmdq_suspend(struct glamodrm_handle *gdrm); + extern void glamo_cmdq_resume(struct glamodrm_handle *gdrm); +diff --git a/drivers/mfd/glamo/glamo-drm-drv.c b/drivers/mfd/glamo/glamo-drm-drv.c +index 774eaff..ee648c1 100644 +--- a/drivers/mfd/glamo/glamo-drm-drv.c ++++ b/drivers/mfd/glamo/glamo-drm-drv.c +@@ -128,7 +128,7 @@ static int glamodrm_load(struct drm_device *dev, unsigned long flags) + gdrm = dev->dev_private; + + glamo_buffer_init(gdrm); +- glamo_cmdq_init(gdrm); ++ glamo_cmdq_init(dev); + glamo_fence_init(gdrm); + glamo_display_init(dev); + +@@ -237,14 +237,14 @@ static int glamodrm_probe(struct platform_device *pdev) + if ( !gdrm->vram ) { + dev_err(&pdev->dev, "Unable to find VRAM.\n"); + rc = -ENOENT; +- goto out_unmap_cmdq; ++ goto out_unmap_regs; + } + gdrm->vram = request_mem_region(gdrm->vram->start, + resource_size(gdrm->vram), pdev->name); + if ( !gdrm->vram ) { + dev_err(&pdev->dev, "failed to request VRAM region\n"); + rc = -ENOENT; +- goto out_unmap_cmdq; ++ goto out_unmap_regs; + } + + /* Find the LCD controller */ +@@ -316,10 +316,6 @@ out_release_lcd: + resource_size(gdrm->lcd_regs)); + out_release_vram: + release_mem_region(gdrm->vram->start, resource_size(gdrm->vram)); +-out_unmap_cmdq: +- iounmap(gdrm->cmdq_base); +-out_release_cmdq: +- release_mem_region(gdrm->cmdq->start, resource_size(gdrm->cmdq)); + out_unmap_regs: + iounmap(gdrm->reg_base); + out_release_regs: +@@ -349,9 +345,10 @@ static int glamodrm_remove(struct platform_device *pdev) + /* Release VRAM */ + release_mem_region(gdrm->vram->start, resource_size(gdrm->vram)); + +- /* Release command queue */ +- iounmap(gdrm->cmdq_base); +- release_mem_region(gdrm->cmdq->start, resource_size(gdrm->cmdq)); ++ /* Release LCD registers */ ++ iounmap(gdrm->lcd_base); ++ release_mem_region(gdrm->lcd_regs->start, ++ resource_size(gdrm->lcd_regs)); + + /* Release 2D engine */ + iounmap(gdrm->twod_base); +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0007-Debug-statements-for-testing.patch b/recipes/linux/linux-openmoko-2.6.34/0007-Debug-statements-for-testing.patch new file mode 100644 index 0000000000..1321d29491 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0007-Debug-statements-for-testing.patch @@ -0,0 +1,78 @@ +From 6d0e40938fa71d6a3a1f3c9892251053bda3be6d Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Thu, 6 May 2010 05:40:33 -0700 +Subject: [PATCH 07/13] Debug statements for testing + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/mfd/glamo/glamo-display.c | 7 +++++++ + drivers/video/backlight/jbt6k74.c | 4 +++- + 2 files changed, 10 insertions(+), 1 deletions(-) + +diff --git a/drivers/mfd/glamo/glamo-display.c b/drivers/mfd/glamo/glamo-display.c +index 75ad734..57292ff 100644 +--- a/drivers/mfd/glamo/glamo-display.c ++++ b/drivers/mfd/glamo/glamo-display.c +@@ -257,6 +257,8 @@ static int glamo_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + u32 addr; + u16 addr_low, addr_high; + ++ printk(KERN_CRIT "Setting base!\n"); ++ + if (!crtc->fb) { + DRM_DEBUG("No FB bound\n"); + return -EINVAL; +@@ -311,6 +313,8 @@ static int glamo_crtc_mode_set(struct drm_crtc *crtc, + msleep(500); + } + ++ printk(KERN_CRIT "Setting mode!\n"); ++ + /* Rotate? */ + if ( (mode->hdisplay == 640) && (mode->vdisplay == 480) ) { + rot = GLAMO_LCD_ROT_MODE_90; +@@ -935,15 +939,18 @@ void glamo_lcd_power(struct glamodrm_handle *gdrm, int mode) + struct glamo_crtc *gcrtc = to_glamo_crtc(crtc); + + if ( mode ) { ++ printk(KERN_CRIT "Power on sequence\n"); + glamo_engine_enable(gdrm->glamo_core, GLAMO_ENGINE_LCD); + gcrtc->pixel_clock_on = 1; + jbt6k74_setpower(JBT_POWER_MODE_NORMAL); + if ( gcrtc->current_mode_set ) { ++ printk(KERN_CRIT "Setting previous mode\n"); + glamo_crtc_mode_set(crtc, &gcrtc->current_mode, + &gcrtc->current_mode, 0, 0, + gcrtc->current_fb); + } + } else { ++ printk(KERN_CRIT "Power off sequence\n"); + jbt6k74_setpower(JBT_POWER_MODE_OFF); + glamo_engine_suspend(gdrm->glamo_core, GLAMO_ENGINE_LCD); + gcrtc->pixel_clock_on = 0; +diff --git a/drivers/video/backlight/jbt6k74.c b/drivers/video/backlight/jbt6k74.c +index 91651e7..56a3e3a 100644 +--- a/drivers/video/backlight/jbt6k74.c ++++ b/drivers/video/backlight/jbt6k74.c +@@ -389,7 +389,7 @@ static int jbt6k74_enter_power_mode(struct jbt_info *jbt, + { + int ret = -EINVAL; + +- dev_dbg(&jbt->spi->dev, "entering (old_state=%s, new_state=%s)\n", ++ printk(KERN_CRIT "entering (old_state=%s, new_state=%s)\n", + jbt_power_mode_names[jbt->power_mode], + jbt_power_mode_names[new_mode]); + +@@ -825,7 +825,9 @@ EXPORT_SYMBOL_GPL(jbt6k74_finish_resolutionchange); + + void jbt6k74_setpower(enum jbt_power_mode new_power) + { ++ printk(KERN_CRIT "About to set power..\n"); + if ( !jbt_global ) return; ++ printk(KERN_CRIT "Setting JBT power.. %i\n", new_power); + jbt6k74_enter_power_mode(jbt_global, new_power); + } + EXPORT_SYMBOL_GPL(jbt6k74_setpower); +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0008-Fix-claim-of-2D-register-resource.patch b/recipes/linux/linux-openmoko-2.6.34/0008-Fix-claim-of-2D-register-resource.patch new file mode 100644 index 0000000000..613f3a1d9a --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0008-Fix-claim-of-2D-register-resource.patch @@ -0,0 +1,27 @@ +From 92118a72fdf779a20693cb7d01d1a12fc8e12ace Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Thu, 6 May 2010 08:37:04 -0700 +Subject: [PATCH 08/13] Fix claim of 2D register resource + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/mfd/glamo/glamo-drm-drv.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/drivers/mfd/glamo/glamo-drm-drv.c b/drivers/mfd/glamo/glamo-drm-drv.c +index ee648c1..4f982ad 100644 +--- a/drivers/mfd/glamo/glamo-drm-drv.c ++++ b/drivers/mfd/glamo/glamo-drm-drv.c +@@ -272,7 +272,8 @@ static int glamodrm_probe(struct platform_device *pdev) + } + + /* Find the 2D engine */ +- gdrm->twod_regs = platform_get_resource(pdev, IORESOURCE_MEM, 4); ++ gdrm->twod_regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "glamo-2d-regs"); + if ( !gdrm->twod_regs ) { + dev_err(&pdev->dev, "Unable to find 2D registers.\n"); + rc = -ENOENT; +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/0009-Use-unlocked_ioctl-rather-than-ioctl.patch b/recipes/linux/linux-openmoko-2.6.34/0009-Use-unlocked_ioctl-rather-than-ioctl.patch new file mode 100644 index 0000000000..5937cb9820 --- /dev/null +++ b/recipes/linux/linux-openmoko-2.6.34/0009-Use-unlocked_ioctl-rather-than-ioctl.patch @@ -0,0 +1,28 @@ +From ea9d004f7b0d5c93610a2abdcbdf54af2a871c4b Mon Sep 17 00:00:00 2001 +From: Thomas White <taw@bitwiz.org.uk> +Date: Mon, 24 May 2010 21:49:14 +0200 +Subject: [PATCH 09/13] Use unlocked_ioctl rather than ioctl + +The arguments changed between 2.6.32 and 2.6.34. + +Signed-off-by: Thomas White <taw@bitwiz.org.uk> +--- + drivers/mfd/glamo/glamo-drm-drv.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/mfd/glamo/glamo-drm-drv.c b/drivers/mfd/glamo/glamo-drm-drv.c +index 4f982ad..75b5233 100644 +--- a/drivers/mfd/glamo/glamo-drm-drv.c ++++ b/drivers/mfd/glamo/glamo-drm-drv.c +@@ -179,7 +179,7 @@ static struct drm_driver glamodrm_drm_driver = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, +- .ioctl = drm_ioctl, ++ .unlocked_ioctl = drm_ioctl, + .mmap = drm_gem_mmap, + .poll = drm_poll, + .fasync = drm_fasync, +-- +1.7.1 + diff --git a/recipes/linux/linux-openmoko-2.6.34/gta02-defconfig-update-for-2.6.34.patch b/recipes/linux/linux-openmoko-2.6.34/gta02-defconfig-update-for-2.6.34.patch deleted file mode 100644 index bc6257aa46..0000000000 --- a/recipes/linux/linux-openmoko-2.6.34/gta02-defconfig-update-for-2.6.34.patch +++ /dev/null @@ -1,880 +0,0 @@ -From cabf6246eec8f2d546b8d0ec2335bb1b9c83b84f Mon Sep 17 00:00:00 2001 -From: Martin Jansa <Martin.Jansa@gmail.com> -Date: Tue, 18 May 2010 08:33:59 +0200 -Subject: [PATCH] gta02-defconfig update for 2.6.34 - ---- - arch/arm/configs/gta02_defconfig | 248 +++++++++++++++++++++++++------------- - 1 files changed, 163 insertions(+), 85 deletions(-) - -diff --git a/arch/arm/configs/gta02_defconfig b/arch/arm/configs/gta02_defconfig -index 73d26ba..f8142fd 100644 ---- a/arch/arm/configs/gta02_defconfig -+++ b/arch/arm/configs/gta02_defconfig -@@ -1,12 +1,13 @@ - # - # Automatically generated make config: don't edit --# Linux kernel version: 2.6.32 --# Wed Apr 7 23:27:29 2010 -+# Linux kernel version: 2.6.34 -+# Tue May 18 09:20:24 2010 - # - CONFIG_ARM=y - CONFIG_HAVE_PWM=y - CONFIG_SYS_SUPPORTS_APM_EMULATION=y - CONFIG_GENERIC_GPIO=y -+CONFIG_HAVE_PROC_CPU=y - CONFIG_NO_IOPORT=y - CONFIG_GENERIC_HARDIRQS=y - CONFIG_STACKTRACE_SUPPORT=y -@@ -19,6 +20,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y - CONFIG_ARCH_HAS_CPUFREQ=y - CONFIG_GENERIC_HWEIGHT=y - CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y - CONFIG_FIQ=y - CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y - CONFIG_VECTORS_BASE=0xffff0000 -@@ -31,8 +33,14 @@ CONFIG_CONSTRUCTORS=y - CONFIG_EXPERIMENTAL=y - CONFIG_BROKEN_ON_SMP=y - CONFIG_INIT_ENV_ARG_LIMIT=32 --CONFIG_LOCALVERSION="v20" -+CONFIG_LOCALVERSION="" - # CONFIG_LOCALVERSION_AUTO is not set -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZO=y -+CONFIG_KERNEL_GZIP=y -+# CONFIG_KERNEL_BZIP2 is not set -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_LZO is not set - CONFIG_SWAP=y - CONFIG_SYSVIPC=y - CONFIG_SYSVIPC_SYSCTL=y -@@ -46,13 +54,13 @@ CONFIG_SYSVIPC_SYSCTL=y - # - CONFIG_TREE_RCU=y - # CONFIG_TREE_PREEMPT_RCU is not set -+# CONFIG_TINY_RCU is not set - # CONFIG_RCU_TRACE is not set - CONFIG_RCU_FANOUT=32 - # CONFIG_RCU_FANOUT_EXACT is not set - # CONFIG_TREE_RCU_TRACE is not set - # CONFIG_IKCONFIG is not set - CONFIG_LOG_BUF_SHIFT=18 --# CONFIG_GROUP_SCHED is not set - # CONFIG_CGROUPS is not set - # CONFIG_SYSFS_DEPRECATED_V2 is not set - # CONFIG_RELAY is not set -@@ -67,6 +75,7 @@ CONFIG_INITRAMFS_SOURCE="" - CONFIG_RD_GZIP=y - CONFIG_RD_BZIP2=y - CONFIG_RD_LZMA=y -+CONFIG_RD_LZO=y - # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set - CONFIG_SYSCTL=y - CONFIG_ANON_INODES=y -@@ -87,10 +96,14 @@ CONFIG_TIMERFD=y - CONFIG_EVENTFD=y - CONFIG_SHMEM=y - CONFIG_AIO=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y - - # - # Kernel Performance Events And Counters - # -+# CONFIG_PERF_EVENTS is not set -+# CONFIG_PERF_COUNTERS is not set - CONFIG_VM_EVENT_COUNTERS=y - CONFIG_COMPAT_BRK=y - CONFIG_SLAB=y -@@ -119,21 +132,48 @@ CONFIG_MODULE_FORCE_UNLOAD=y - # CONFIG_MODULE_SRCVERSION_ALL is not set - CONFIG_BLOCK=y - # CONFIG_LBDAF is not set --# CONFIG_BLK_DEV_BSG is not set -+CONFIG_BLK_DEV_BSG=y - # CONFIG_BLK_DEV_INTEGRITY is not set - - # - # IO Schedulers - # - CONFIG_IOSCHED_NOOP=y --CONFIG_IOSCHED_AS=m - CONFIG_IOSCHED_DEADLINE=y - CONFIG_IOSCHED_CFQ=m --# CONFIG_DEFAULT_AS is not set - CONFIG_DEFAULT_DEADLINE=y - # CONFIG_DEFAULT_CFQ is not set - # CONFIG_DEFAULT_NOOP is not set - CONFIG_DEFAULT_IOSCHED="deadline" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+CONFIG_INLINE_SPIN_UNLOCK=y -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set - CONFIG_FREEZER=y - - # -@@ -145,6 +185,7 @@ CONFIG_MMU=y - # CONFIG_ARCH_REALVIEW is not set - # CONFIG_ARCH_VERSATILE is not set - # CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set - # CONFIG_ARCH_CLPS711X is not set - # CONFIG_ARCH_GEMINI is not set - # CONFIG_ARCH_EBSA110 is not set -@@ -154,7 +195,6 @@ CONFIG_MMU=y - # CONFIG_ARCH_STMP3XXX is not set - # CONFIG_ARCH_NETX is not set - # CONFIG_ARCH_H720X is not set --# CONFIG_ARCH_NOMADIK is not set - # CONFIG_ARCH_IOP13XX is not set - # CONFIG_ARCH_IOP32X is not set - # CONFIG_ARCH_IOP33X is not set -@@ -162,6 +202,7 @@ CONFIG_MMU=y - # CONFIG_ARCH_IXP2000 is not set - # CONFIG_ARCH_IXP4XX is not set - # CONFIG_ARCH_L7200 is not set -+# CONFIG_ARCH_DOVE is not set - # CONFIG_ARCH_KIRKWOOD is not set - # CONFIG_ARCH_LOKI is not set - # CONFIG_ARCH_MV78XX0 is not set -@@ -170,32 +211,27 @@ CONFIG_MMU=y - # CONFIG_ARCH_KS8695 is not set - # CONFIG_ARCH_NS9XXX is not set - # CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_NUC93X is not set - # CONFIG_ARCH_PNX4008 is not set - # CONFIG_ARCH_PXA is not set - # CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set - # CONFIG_ARCH_RPC is not set - # CONFIG_ARCH_SA1100 is not set - CONFIG_ARCH_S3C2410=y - # CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P6440 is not set -+# CONFIG_ARCH_S5P6442 is not set - # CONFIG_ARCH_S5PC1XX is not set -+# CONFIG_ARCH_S5PV210 is not set - # CONFIG_ARCH_SHARK is not set - # CONFIG_ARCH_LH7A40X is not set - # CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set - # CONFIG_ARCH_DAVINCI is not set - # CONFIG_ARCH_OMAP is not set --# CONFIG_ARCH_BCMRING is not set --CONFIG_PLAT_S3C24XX=y --CONFIG_S3C2410_CLOCK=y --CONFIG_CPU_S3C244X=y --CONFIG_S3C24XX_PWM=y --CONFIG_S3C24XX_GPIO_EXTRA=64 --CONFIG_S3C24XX_GPIO_EXTRA64=y --CONFIG_S3C2410_DMA=y --# CONFIG_S3C2410_DMA_DEBUG is not set --CONFIG_S3C24XX_ADC=y --CONFIG_PLAT_S3C=y --CONFIG_CPU_LLSERIAL_S3C2440_ONLY=y --CONFIG_CPU_LLSERIAL_S3C2440=y -+CONFIG_PLAT_SAMSUNG=y - - # - # Boot options -@@ -203,17 +239,27 @@ CONFIG_CPU_LLSERIAL_S3C2440=y - # CONFIG_S3C_BOOT_WATCHDOG is not set - # CONFIG_S3C_BOOT_ERROR_RESET is not set - CONFIG_S3C_BOOT_UART_FORCE_FIFO=y -- --# --# Power management --# --# CONFIG_S3C2410_PM_DEBUG is not set --# CONFIG_S3C2410_PM_CHECK is not set - CONFIG_S3C_LOWLEVEL_UART_PORT=2 -+CONFIG_SAMSUNG_GPIO_EXTRA=0 - CONFIG_S3C_GPIO_SPACE=0 --CONFIG_S3C_DMA=y -+CONFIG_S3C_ADC=y - CONFIG_S3C_DEV_USB_HOST=y - CONFIG_S3C_DEV_NAND=y -+CONFIG_S3C_DMA=y -+ -+# -+# Power management -+# -+# CONFIG_SAMSUNG_PM_DEBUG is not set -+# CONFIG_SAMSUNG_PM_CHECK is not set -+CONFIG_PLAT_S3C24XX=y -+CONFIG_CPU_LLSERIAL_S3C2440_ONLY=y -+CONFIG_CPU_LLSERIAL_S3C2440=y -+CONFIG_S3C2410_CLOCK=y -+CONFIG_S3C24XX_PWM=y -+CONFIG_S3C24XX_GPIO_EXTRA=0 -+CONFIG_S3C2410_DMA=y -+# CONFIG_S3C2410_DMA_DEBUG is not set - - # - # S3C2400 Machines -@@ -242,23 +288,22 @@ CONFIG_S3C2410_GPIO=y - # CONFIG_MACH_SMDK2413 is not set - # CONFIG_MACH_SMDK2412 is not set - # CONFIG_MACH_VSTMS is not set -+CONFIG_CPU_S3C2442=y -+CONFIG_CPU_S3C244X=y - - # --# S3C2440 Machines -+# S3C2440 and S3C2442 Machines - # - # CONFIG_MACH_ANUBIS is not set -+CONFIG_MACH_NEO1973_GTA02=y - # CONFIG_MACH_OSIRIS is not set - # CONFIG_MACH_RX3715 is not set - # CONFIG_ARCH_S3C2440 is not set - # CONFIG_MACH_NEXCODER_2440 is not set -+# CONFIG_SMDK2440_CPU2440 is not set -+# CONFIG_SMDK2440_CPU2442 is not set - # CONFIG_MACH_AT2440EVB is not set - # CONFIG_MACH_MINI2440 is not set --CONFIG_CPU_S3C2442=y -- --# --# S3C2442 Machines --# --CONFIG_MACH_NEO1973_GTA02=y - - # - # S3C2443 Machines -@@ -268,7 +313,6 @@ CONFIG_MACH_NEO1973_GTA02=y - # - # Processor Type - # --CONFIG_CPU_32=y - CONFIG_CPU_ARM920T=y - CONFIG_CPU_32v4T=y - CONFIG_CPU_ABRT_EV4T=y -@@ -319,12 +363,10 @@ CONFIG_FLATMEM_MANUAL=y - CONFIG_FLATMEM=y - CONFIG_FLAT_NODE_MEM_MAP=y - CONFIG_PAGEFLAGS_EXTENDED=y --CONFIG_SPLIT_PTLOCK_CPUS=4096 -+CONFIG_SPLIT_PTLOCK_CPUS=999999 - # CONFIG_PHYS_ADDR_T_64BIT is not set - CONFIG_ZONE_DMA_FLAG=0 - CONFIG_VIRT_TO_BUS=y --CONFIG_HAVE_MLOCK=y --CONFIG_HAVE_MLOCKED_PAGE_BIT=y - # CONFIG_KSM is not set - CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 - CONFIG_ALIGNMENT_TRAP=y -@@ -335,7 +377,7 @@ CONFIG_ALIGNMENT_TRAP=y - # - CONFIG_ZBOOT_ROM_TEXT=0x0 - CONFIG_ZBOOT_ROM_BSS=0x0 --CONFIG_CMDLINE="unused -- bootloader passes ATAG list" -+CONFIG_CMDLINE="unused -- bootloader passes ATAG list quiet " - # CONFIG_XIP_KERNEL is not set - # CONFIG_KEXEC is not set - -@@ -373,6 +415,7 @@ CONFIG_SUSPEND=y - CONFIG_SUSPEND_FREEZER=y - # CONFIG_APM_EMULATION is not set - # CONFIG_PM_RUNTIME is not set -+CONFIG_PM_OPS=y - CONFIG_ARCH_SUSPEND_POSSIBLE=y - CONFIG_NET=y - -@@ -380,7 +423,6 @@ CONFIG_NET=y - # Networking options - # - CONFIG_PACKET=y --CONFIG_PACKET_MMAP=y - CONFIG_UNIX=y - CONFIG_XFRM=y - CONFIG_XFRM_USER=m -@@ -458,6 +500,7 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=m - CONFIG_INET6_XFRM_MODE_BEET=m - # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set - CONFIG_IPV6_SIT=m -+# CONFIG_IPV6_SIT_6RD is not set - CONFIG_IPV6_NDISC_NODETYPE=y - CONFIG_IPV6_TUNNEL=m - # CONFIG_IPV6_MULTIPLE_TABLES is not set -@@ -496,6 +539,7 @@ CONFIG_NF_CT_NETLINK=m - CONFIG_NETFILTER_XTABLES=m - CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m - CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -+# CONFIG_NETFILTER_XT_TARGET_CT is not set - CONFIG_NETFILTER_XT_TARGET_DSCP=m - CONFIG_NETFILTER_XT_TARGET_HL=m - # CONFIG_NETFILTER_XT_TARGET_LED is not set -@@ -631,6 +675,7 @@ CONFIG_BRIDGE_EBT_ULOG=m - # CONFIG_ATM is not set - CONFIG_STP=y - CONFIG_BRIDGE=y -+CONFIG_BRIDGE_IGMP_SNOOPING=y - # CONFIG_NET_DSA is not set - # CONFIG_VLAN_8021Q is not set - # CONFIG_DECNET is not set -@@ -712,13 +757,15 @@ CONFIG_BT_HCIBTUSB=y - # CONFIG_BT_HCIBFUSB is not set - # CONFIG_BT_HCIVHCI is not set - # CONFIG_BT_MRVL is not set -+# CONFIG_BT_ATH3K is not set - # CONFIG_AF_RXRPC is not set - CONFIG_FIB_RULES=y - CONFIG_WIRELESS=y --# CONFIG_CFG80211 is not set --CONFIG_CFG80211_DEFAULT_PS_VALUE=0 --CONFIG_WIRELESS_OLD_REGULATORY=y - CONFIG_WIRELESS_EXT=y -+CONFIG_WEXT_CORE=y -+CONFIG_WEXT_PROC=y -+CONFIG_WEXT_PRIV=y -+# CONFIG_CFG80211 is not set - CONFIG_WIRELESS_EXT_SYSFS=y - # CONFIG_LIB80211 is not set - -@@ -736,7 +783,7 @@ CONFIG_WIRELESS_EXT_SYSFS=y - # - # Generic Driver Options - # --CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_UEVENT_HELPER_PATH="" - CONFIG_DEVTMPFS=y - CONFIG_DEVTMPFS_MOUNT=y - CONFIG_STANDALONE=y -@@ -850,6 +897,7 @@ CONFIG_BLK_DEV=y - # CONFIG_BLK_DEV_COW_COMMON is not set - CONFIG_BLK_DEV_LOOP=m - # CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_DRBD is not set - # CONFIG_BLK_DEV_NBD is not set - CONFIG_BLK_DEV_UB=m - CONFIG_BLK_DEV_RAM=y -@@ -866,6 +914,7 @@ CONFIG_HAVE_IDE=y - # - # SCSI device support - # -+CONFIG_SCSI_MOD=m - # CONFIG_RAID_ATTRS is not set - CONFIG_SCSI=m - CONFIG_SCSI_DMA=y -@@ -895,6 +944,7 @@ CONFIG_SCSI_WAIT_SCAN=m - # CONFIG_SCSI_SPI_ATTRS is not set - # CONFIG_SCSI_FC_ATTRS is not set - # CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_ATTRS is not set - # CONFIG_SCSI_SAS_LIBSAS is not set - # CONFIG_SCSI_SRP_ATTRS is not set - CONFIG_SCSI_LOWLEVEL=y -@@ -918,8 +968,8 @@ CONFIG_MII=m - # CONFIG_NETDEV_1000 is not set - # CONFIG_NETDEV_10000 is not set - CONFIG_WLAN=y --# CONFIG_WLAN_PRE80211 is not set --# CONFIG_WLAN_80211 is not set -+# CONFIG_USB_ZD1201 is not set -+# CONFIG_HOSTAP is not set - - # - # Enable WiMAX (Networking options) to see the WiMAX drivers -@@ -933,6 +983,7 @@ CONFIG_USB_KAWETH=m - CONFIG_USB_PEGASUS=m - CONFIG_USB_RTL8150=m - # CONFIG_USB_USBNET is not set -+# CONFIG_USB_IPHETH is not set - # CONFIG_WAN is not set - CONFIG_PPP=m - CONFIG_PPP_MULTILINK=y -@@ -958,6 +1009,7 @@ CONFIG_SLHC=m - CONFIG_INPUT=y - # CONFIG_INPUT_FF_MEMLESS is not set - # CONFIG_INPUT_POLLDEV is not set -+# CONFIG_INPUT_SPARSEKMAP is not set - - # - # Userland interfaces -@@ -991,20 +1043,15 @@ CONFIG_KEYBOARD_STOWAWAY=m - # CONFIG_INPUT_JOYSTICK is not set - # CONFIG_INPUT_TABLET is not set - CONFIG_INPUT_TOUCHSCREEN=y --CONFIG_TOUCHSCREEN_FILTER=y --CONFIG_TOUCHSCREEN_FILTER_GROUP=y --CONFIG_TOUCHSCREEN_FILTER_MEDIAN=y --CONFIG_TOUCHSCREEN_FILTER_MEAN=y --CONFIG_TOUCHSCREEN_FILTER_LINEAR=y --CONFIG_TOUCHSCREEN_S3C2410=y --# CONFIG_TOUCHSCREEN_S3C2410_DEBUG is not set - # CONFIG_TOUCHSCREEN_ADS7846 is not set - # CONFIG_TOUCHSCREEN_AD7877 is not set - # CONFIG_TOUCHSCREEN_AD7879_I2C is not set - # CONFIG_TOUCHSCREEN_AD7879_SPI is not set - # CONFIG_TOUCHSCREEN_AD7879 is not set -+# CONFIG_TOUCHSCREEN_DYNAPRO is not set - # CONFIG_TOUCHSCREEN_EETI is not set - # CONFIG_TOUCHSCREEN_FUJITSU is not set -+CONFIG_TOUCHSCREEN_S3C2410=y - # CONFIG_TOUCHSCREEN_GUNZE is not set - # CONFIG_TOUCHSCREEN_ELO is not set - # CONFIG_TOUCHSCREEN_WACOM_W8001 is not set -@@ -1029,7 +1076,6 @@ CONFIG_INPUT_MISC=y - CONFIG_INPUT_UINPUT=m - CONFIG_INPUT_PCF50633_PMU=y - # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set --CONFIG_INPUT_LIS302DL=y - - # - # Hardware I/O ports -@@ -1037,6 +1083,7 @@ CONFIG_INPUT_LIS302DL=y - CONFIG_SERIO=y - # CONFIG_SERIO_SERPORT is not set - # CONFIG_SERIO_RAW is not set -+# CONFIG_SERIO_ALTERA_PS2 is not set - # CONFIG_GAMEPORT is not set - - # -@@ -1065,6 +1112,7 @@ CONFIG_SERIAL_S3C2440=y - # CONFIG_SERIAL_MAX3100 is not set - CONFIG_SERIAL_CORE=y - CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set - CONFIG_UNIX98_PTYS=y - # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set - # CONFIG_LEGACY_PTYS is not set -@@ -1078,6 +1126,7 @@ CONFIG_I2C_BOARDINFO=y - # CONFIG_I2C_COMPAT is not set - CONFIG_I2C_CHARDEV=y - # CONFIG_I2C_HELPER_AUTO is not set -+# CONFIG_I2C_SMBUS is not set - - # - # I2C Algorithms -@@ -1098,6 +1147,7 @@ CONFIG_I2C_CHARDEV=y - # CONFIG_I2C_OCORES is not set - CONFIG_I2C_S3C2410=y - # CONFIG_I2C_SIMTEC is not set -+# CONFIG_I2C_XILINX is not set - - # - # External I2C/SMBus adapter drivers -@@ -1111,16 +1161,9 @@ CONFIG_I2C_S3C2410=y - # - # CONFIG_I2C_PCA_PLATFORM is not set - # CONFIG_I2C_STUB is not set -- --# --# Miscellaneous I2C Chip support --# --# CONFIG_DS1682 is not set --# CONFIG_SENSORS_TSL2550 is not set - # CONFIG_I2C_DEBUG_CORE is not set - # CONFIG_I2C_DEBUG_ALGO is not set - # CONFIG_I2C_DEBUG_BUS is not set --# CONFIG_I2C_DEBUG_CHIP is not set - CONFIG_SPI=y - CONFIG_SPI_MASTER=y - -@@ -1130,7 +1173,10 @@ CONFIG_SPI_MASTER=y - CONFIG_SPI_BITBANG=y - CONFIG_SPI_GPIO=y - CONFIG_SPI_S3C24XX=y -+# CONFIG_SPI_S3C24XX_FIQ is not set - CONFIG_SPI_S3C24XX_GPIO=y -+# CONFIG_SPI_XILINX is not set -+# CONFIG_SPI_DESIGNWARE is not set - - # - # SPI Protocol Masters -@@ -1149,13 +1195,16 @@ CONFIG_GPIO_SYSFS=y - # - # Memory mapped GPIO expanders: - # -+# CONFIG_GPIO_IT8761E is not set - - # - # I2C GPIO expanders: - # -+# CONFIG_GPIO_MAX7300 is not set - # CONFIG_GPIO_MAX732X is not set - # CONFIG_GPIO_PCA953X is not set - # CONFIG_GPIO_PCF857X is not set -+# CONFIG_GPIO_ADP5588 is not set - CONFIG_GPIO_PCF50633=y - - # -@@ -1194,6 +1243,7 @@ CONFIG_WATCHDOG=y - # - # CONFIG_SOFT_WATCHDOG is not set - CONFIG_S3C2410_WATCHDOG=y -+# CONFIG_MAX63XX_WATCHDOG is not set - - # - # USB-based Watchdog Cards -@@ -1210,10 +1260,12 @@ CONFIG_SSB_POSSIBLE=y - # Multifunction device drivers - # - CONFIG_MFD_CORE=y -+# CONFIG_MFD_88PM860X is not set - # CONFIG_MFD_SM501 is not set - # CONFIG_MFD_ASIC3 is not set - # CONFIG_HTC_EGPIO is not set - # CONFIG_HTC_PASIC3 is not set -+# CONFIG_HTC_I2CPLD is not set - # CONFIG_TPS65010 is not set - # CONFIG_TWL4030_CORE is not set - # CONFIG_MFD_TMIO is not set -@@ -1221,25 +1273,32 @@ CONFIG_MFD_CORE=y - # CONFIG_MFD_TC6387XB is not set - # CONFIG_MFD_TC6393XB is not set - # CONFIG_PMIC_DA903X is not set -+# CONFIG_PMIC_ADP5520 is not set -+# CONFIG_MFD_MAX8925 is not set - # CONFIG_MFD_WM8400 is not set - # CONFIG_MFD_WM831X is not set - # CONFIG_MFD_WM8350_I2C is not set -+# CONFIG_MFD_WM8994 is not set - CONFIG_MFD_PCF50633=y - # CONFIG_MFD_MC13783 is not set - CONFIG_PCF50633_ADC=y - # CONFIG_AB3100_CORE is not set - # CONFIG_EZX_PCAP is not set -+# CONFIG_AB4500_CORE is not set - CONFIG_MFD_GLAMO=y - CONFIG_MFD_GLAMO_FB=y - CONFIG_MFD_GLAMO_GPIO=y - CONFIG_MFD_GLAMO_MCI=y - CONFIG_REGULATOR=y - # CONFIG_REGULATOR_DEBUG is not set -+# CONFIG_REGULATOR_DUMMY is not set - CONFIG_REGULATOR_FIXED_VOLTAGE=y - # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set - CONFIG_REGULATOR_USERSPACE_CONSUMER=y - # CONFIG_REGULATOR_BQ24022 is not set - # CONFIG_REGULATOR_MAX1586 is not set -+# CONFIG_REGULATOR_MAX8649 is not set -+# CONFIG_REGULATOR_MAX8660 is not set - CONFIG_REGULATOR_PCF50633=y - # CONFIG_REGULATOR_LP3971 is not set - # CONFIG_REGULATOR_TPS65023 is not set -@@ -1283,6 +1342,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y - # CONFIG_FB_BROADSHEET is not set - CONFIG_BACKLIGHT_LCD_SUPPORT=y - CONFIG_LCD_CLASS_DEVICE=y -+# CONFIG_LCD_L4F00242T03 is not set - # CONFIG_LCD_LMS283GF05 is not set - # CONFIG_LCD_LTV350QV is not set - # CONFIG_LCD_ILI9320 is not set -@@ -1319,10 +1379,7 @@ CONFIG_FONT_6x11=y - # CONFIG_FONT_SUN8x16 is not set - # CONFIG_FONT_SUN12x22 is not set - # CONFIG_FONT_10x18 is not set --CONFIG_LOGO=y --# CONFIG_LOGO_LINUX_MONO is not set --# CONFIG_LOGO_LINUX_VGA16 is not set --# CONFIG_LOGO_LINUX_CLUT224 is not set -+# CONFIG_LOGO is not set - CONFIG_SOUND=y - CONFIG_SOUND_OSS_CORE=y - CONFIG_SOUND_OSS_CORE_PRECLAIM=y -@@ -1362,6 +1419,7 @@ CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753=y - CONFIG_SND_SOC_I2C_AND_SPI=y - # CONFIG_SND_SOC_ALL_CODECS is not set - CONFIG_SND_SOC_WM8753=y -+CONFIG_SND_SOC_LM4857=y - # CONFIG_SOUND_PRIME is not set - CONFIG_HID_SUPPORT=y - CONFIG_HID=y -@@ -1377,6 +1435,7 @@ CONFIG_USB_HID=y - # - # Special HID drivers - # -+# CONFIG_HID_3M_PCT is not set - CONFIG_HID_A4TECH=y - CONFIG_HID_APPLE=y - CONFIG_HID_BELKIN=y -@@ -1393,14 +1452,20 @@ CONFIG_HID_KENSINGTON=y - CONFIG_HID_LOGITECH=y - # CONFIG_LOGITECH_FF is not set - # CONFIG_LOGIRUMBLEPAD2_FF is not set -+# CONFIG_LOGIG940_FF is not set -+# CONFIG_HID_MAGICMOUSE is not set - CONFIG_HID_MICROSOFT=y -+# CONFIG_HID_MOSART is not set - CONFIG_HID_MONTEREY=y - CONFIG_HID_NTRIG=y -+CONFIG_HID_ORTEK=y - CONFIG_HID_PANTHERLORD=y - # CONFIG_PANTHERLORD_FF is not set - CONFIG_HID_PETALYNX=y -+# CONFIG_HID_QUANTA is not set - CONFIG_HID_SAMSUNG=y - CONFIG_HID_SONY=y -+# CONFIG_HID_STANTUM is not set - CONFIG_HID_SUNPLUS=y - CONFIG_HID_GREENASIA=y - # CONFIG_GREENASIA_FF is not set -@@ -1426,8 +1491,6 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y - # CONFIG_USB_DEVICEFS is not set - # CONFIG_USB_DEVICE_CLASS is not set - # CONFIG_USB_DYNAMIC_MINORS is not set --CONFIG_USB_SUSPEND=y --# CONFIG_USB_OTG is not set - # CONFIG_USB_MON is not set - # CONFIG_USB_WUSB is not set - # CONFIG_USB_WUSB_CBAF is not set -@@ -1522,6 +1585,7 @@ CONFIG_USB_SERIAL_MOS7840=m - CONFIG_USB_SERIAL_NAVMAN=m - CONFIG_USB_SERIAL_PL2303=m - # CONFIG_USB_SERIAL_OTI6858 is not set -+# CONFIG_USB_SERIAL_QCAUX is not set - # CONFIG_USB_SERIAL_QUALCOMM is not set - # CONFIG_USB_SERIAL_SPCP8X5 is not set - CONFIG_USB_SERIAL_HP4X=m -@@ -1536,6 +1600,7 @@ CONFIG_USB_SERIAL_XIRCOM=m - CONFIG_USB_SERIAL_OPTION=m - CONFIG_USB_SERIAL_OMNINET=m - # CONFIG_USB_SERIAL_OPTICON is not set -+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set - # CONFIG_USB_SERIAL_DEBUG is not set - - # -@@ -1548,7 +1613,6 @@ CONFIG_USB_SERIAL_OMNINET=m - # CONFIG_USB_RIO500 is not set - # CONFIG_USB_LEGOTOWER is not set - # CONFIG_USB_LCD is not set --CONFIG_USB_BERRY_CHARGE=m - # CONFIG_USB_LED is not set - # CONFIG_USB_CYPRESS_CY7C63 is not set - # CONFIG_USB_CYTHERM is not set -@@ -1560,7 +1624,6 @@ CONFIG_USB_TRANCEVIBRATOR=m - CONFIG_USB_IOWARRIOR=m - # CONFIG_USB_TEST is not set - # CONFIG_USB_ISIGHTFW is not set --# CONFIG_USB_VST is not set - CONFIG_USB_GADGET=y - # CONFIG_USB_GADGET_DEBUG_FILES is not set - CONFIG_USB_GADGET_VBUS_DRAW=500 -@@ -1589,20 +1652,24 @@ CONFIG_USB_S3C2410=y - # CONFIG_USB_GADGET_DUALSPEED is not set - # CONFIG_USB_ZERO is not set - # CONFIG_USB_AUDIO is not set --CONFIG_USB_ETH=y -+CONFIG_USB_ETH=m - CONFIG_USB_ETH_RNDIS=y - # CONFIG_USB_ETH_EEM is not set - # CONFIG_USB_GADGETFS is not set - # CONFIG_USB_FILE_STORAGE is not set -+# CONFIG_USB_MASS_STORAGE is not set - # CONFIG_USB_G_SERIAL is not set - # CONFIG_USB_MIDI_GADGET is not set - # CONFIG_USB_G_PRINTER is not set - # CONFIG_USB_CDC_COMPOSITE is not set -+# CONFIG_USB_G_NOKIA is not set -+# CONFIG_USB_G_MULTI is not set - - # - # OTG and related infrastructure - # - # CONFIG_USB_GPIO_VBUS is not set -+# CONFIG_USB_ULPI is not set - # CONFIG_NOP_USB_XCEIV is not set - CONFIG_MMC=y - # CONFIG_MMC_DEBUG is not set -@@ -1620,8 +1687,6 @@ CONFIG_MMC_BLOCK_BOUNCE=y - # MMC/SD/SDIO Host Controller Drivers - # - # CONFIG_MMC_SDHCI is not set --# CONFIG_MMC_AT91 is not set --# CONFIG_MMC_ATMELMCI is not set - # CONFIG_MMC_SPI is not set - CONFIG_MMC_S3C=y - # CONFIG_MMC_S3C_HW_SDIO_IRQ is not set -@@ -1635,7 +1700,7 @@ CONFIG_LEDS_CLASS=y - # - # LED drivers - # --# CONFIG_LEDS_S3C24XX is not set -+CONFIG_LEDS_S3C24XX=y - # CONFIG_LEDS_PCA9532 is not set - CONFIG_LEDS_GPIO=y - CONFIG_LEDS_GPIO_PLATFORM=y -@@ -1643,12 +1708,14 @@ CONFIG_LEDS_GPIO_PLATFORM=y - # CONFIG_LEDS_PCA955X is not set - # CONFIG_LEDS_DAC124S085 is not set - # CONFIG_LEDS_PWM is not set -+# CONFIG_LEDS_REGULATOR is not set - # CONFIG_LEDS_BD2802 is not set -+# CONFIG_LEDS_LT3593 is not set -+CONFIG_LEDS_TRIGGERS=y - - # - # LED Triggers - # --CONFIG_LEDS_TRIGGERS=y - CONFIG_LEDS_TRIGGER_TIMER=y - CONFIG_LEDS_TRIGGER_HEARTBEAT=y - # CONFIG_LEDS_TRIGGER_BACKLIGHT is not set -@@ -1687,6 +1754,7 @@ CONFIG_RTC_INTF_DEV=y - # CONFIG_RTC_DRV_PCF8563 is not set - # CONFIG_RTC_DRV_PCF8583 is not set - # CONFIG_RTC_DRV_M41T80 is not set -+# CONFIG_RTC_DRV_BQ32K is not set - # CONFIG_RTC_DRV_S35390A is not set - # CONFIG_RTC_DRV_FM3130 is not set - # CONFIG_RTC_DRV_RX8581 is not set -@@ -1716,7 +1784,9 @@ CONFIG_RTC_INTF_DEV=y - # CONFIG_RTC_DRV_M48T86 is not set - # CONFIG_RTC_DRV_M48T35 is not set - # CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_MSM6242 is not set - # CONFIG_RTC_DRV_BQ4802 is not set -+# CONFIG_RTC_DRV_RP5C01 is not set - # CONFIG_RTC_DRV_V3020 is not set - CONFIG_RTC_DRV_PCF50633=y - -@@ -1738,14 +1808,9 @@ CONFIG_STAGING=y - # CONFIG_ECHO is not set - # CONFIG_COMEDI is not set - # CONFIG_ASUS_OLED is not set --# CONFIG_INPUT_MIMIO is not set - # CONFIG_TRANZPORT is not set - - # --# Android --# -- --# - # Qualcomm MSM Camera And Video - # - -@@ -1753,9 +1818,7 @@ CONFIG_STAGING=y - # Camera Sensor Selection - # - # CONFIG_INPUT_GPIO is not set --# CONFIG_DST is not set - # CONFIG_POHMELFS is not set --# CONFIG_PLAN9AUTH is not set - # CONFIG_LINE6_USB is not set - # CONFIG_USB_SERIAL_QUATECH2 is not set - # CONFIG_USB_SERIAL_QUATECH_USB2 is not set -@@ -1767,6 +1830,10 @@ CONFIG_STAGING=y - # - # CONFIG_RAR_REGISTER is not set - # CONFIG_IIO is not set -+# CONFIG_RAMZSWAP is not set -+# CONFIG_BATMAN_ADV is not set -+# CONFIG_STRIP is not set -+# CONFIG_FB_SM7XX is not set - CONFIG_AR6000_WLAN=y - # CONFIG_AR6000_WLAN_DEBUG is not set - # CONFIG_AR6000_WLAN_RESET is not set -@@ -1787,7 +1854,7 @@ CONFIG_REISERFS_FS=m - # CONFIG_REISERFS_PROC_INFO is not set - # CONFIG_REISERFS_FS_XATTR is not set - # CONFIG_JFS_FS is not set --# CONFIG_FS_POSIX_ACL is not set -+CONFIG_FS_POSIX_ACL=y - # CONFIG_XFS_FS is not set - # CONFIG_OCFS2_FS is not set - # CONFIG_BTRFS_FS is not set -@@ -1802,6 +1869,7 @@ CONFIG_INOTIFY_USER=y - CONFIG_AUTOFS4_FS=m - CONFIG_FUSE_FS=m - CONFIG_CUSE=m -+CONFIG_GENERIC_ACL=y - - # - # Caches -@@ -1835,7 +1903,7 @@ CONFIG_PROC_SYSCTL=y - CONFIG_PROC_PAGE_MONITOR=y - CONFIG_SYSFS=y - CONFIG_TMPFS=y --# CONFIG_TMPFS_POSIX_ACL is not set -+CONFIG_TMPFS_POSIX_ACL=y - # CONFIG_HUGETLB_PAGE is not set - CONFIG_CONFIGFS_FS=m - CONFIG_MISC_FILESYSTEMS=y -@@ -1857,6 +1925,7 @@ CONFIG_JFFS2_ZLIB=y - # CONFIG_JFFS2_LZO is not set - CONFIG_JFFS2_RTIME=y - # CONFIG_JFFS2_RUBIN is not set -+# CONFIG_LOGFS is not set - # CONFIG_CRAMFS is not set - CONFIG_SQUASHFS=m - # CONFIG_SQUASHFS_EMBEDDED is not set -@@ -1886,6 +1955,7 @@ CONFIG_SUNRPC=m - # CONFIG_RPCSEC_GSS_KRB5 is not set - # CONFIG_RPCSEC_GSS_SPKM3 is not set - # CONFIG_SMB_FS is not set -+# CONFIG_CEPH_FS is not set - CONFIG_CIFS=m - # CONFIG_CIFS_STATS is not set - # CONFIG_CIFS_WEAK_PW_HASH is not set -@@ -1985,6 +2055,7 @@ CONFIG_TRACING_SUPPORT=y - CONFIG_HAVE_ARCH_KGDB=y - # CONFIG_ARM_UNWIND is not set - # CONFIG_DEBUG_USER is not set -+# CONFIG_OC_ETM is not set - CONFIG_DEBUG_S3C_UART=2 - - # -@@ -1993,7 +2064,11 @@ CONFIG_DEBUG_S3C_UART=2 - # CONFIG_KEYS is not set - # CONFIG_SECURITY is not set - # CONFIG_SECURITYFS is not set --# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+# CONFIG_DEFAULT_SECURITY_SELINUX is not set -+# CONFIG_DEFAULT_SECURITY_SMACK is not set -+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" - CONFIG_CRYPTO=y - - # -@@ -2109,9 +2184,11 @@ CONFIG_CRC7=y - CONFIG_LIBCRC32C=m - CONFIG_ZLIB_INFLATE=y - CONFIG_ZLIB_DEFLATE=y -+CONFIG_LZO_DECOMPRESS=y - CONFIG_DECOMPRESS_GZIP=y - CONFIG_DECOMPRESS_BZIP2=y - CONFIG_DECOMPRESS_LZMA=y -+CONFIG_DECOMPRESS_LZO=y - CONFIG_TEXTSEARCH=y - CONFIG_TEXTSEARCH_KMP=m - CONFIG_TEXTSEARCH_BM=m -@@ -2119,3 +2196,4 @@ CONFIG_TEXTSEARCH_FSM=m - CONFIG_HAS_IOMEM=y - CONFIG_HAS_DMA=y - CONFIG_NLATTR=y -+CONFIG_GENERIC_ATOMIC64=y --- -1.7.1 - diff --git a/recipes/linux/linux-openmoko-2.6.34_git.bb b/recipes/linux/linux-openmoko-2.6.34_git.bb index f600a02036..6d3b52b101 100644 --- a/recipes/linux/linux-openmoko-2.6.34_git.bb +++ b/recipes/linux/linux-openmoko-2.6.34_git.bb @@ -5,21 +5,34 @@ DESCRIPTION_${PN} = "Linux ${KERNEL_RELEASE} kernel for the Openmoko Neo GSM Sma KERNEL_RELEASE="2.6.34" -SRCREV = "e23313fc76e2724fe56354526275458a0bdc10c3" -OEV = "oe1" +SRCREV = "dd1225cc08c3375bf80289ac1965c724881b149a" +OEV = "oe2" PV = "${KERNEL_RELEASE}-${OEV}+gitr${SRCPV}" SRC_URI = "\ git://git.openmoko.org/git/kernel.git;protocol=git;branch=om-gta02-2.6.34 \ # build fix file://wm8753-fix-build-with-gcc-4.4.2-which-works-ok-with-.patch;patch=1 \ -# defconfig updates - file://gta02-defconfig-update-for-2.6.34.patch;patch=1 \ +# patches from Thomas White's gdrm-for-merging branch + file://0001-DRM-for-platform-devices.patch;patch=1 \ + file://0002-Glamo-DRM-and-KMS-driver.patch;patch=1 \ + file://0003-Work-on-Glamo-core-for-DRM.patch;patch=1 \ + file://0004-JBT6k74-work-for-KMS.patch;patch=1 \ + file://0005-Fix-crash-when-reading-Glamo-registers-via-sysfs.patch;patch=1 \ + file://0006-Fix-dynamic-command-queue-allocation.patch;patch=1 \ + file://0007-Debug-statements-for-testing.patch;patch=1 \ + file://0008-Fix-claim-of-2D-register-resource.patch;patch=1 \ + file://0009-Use-unlocked_ioctl-rather-than-ioctl.patch;patch=1 \ +# patches from Radek Polak used in qtmoko + file://0001-accels.patch.patch;patch=1 \ + file://0002-usbhost.patch.patch;patch=1 \ + file://0003-ar6000_delay.patch.patch;patch=1 \ + file://0004-save_regs.patch.patch;patch=1 \ " S = "${WORKDIR}/git" -CONFIG_NAME_om-gta02 = "gta02_defconfig" +CONFIG_NAME_om-gta02 = "gta02_drm_defconfig" do_configure_prepend() { install -m 644 ./arch/arm/configs/${CONFIG_NAME} ${WORKDIR}/defconfig-oe |