diff options
Diffstat (limited to 'drivers')
175 files changed, 9285 insertions, 4479 deletions
diff --git a/drivers/base/soc.c b/drivers/base/soc.c index ba29b2e73d48..72b5e7280d14 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c | |||
| @@ -42,7 +42,7 @@ struct device *soc_device_to_device(struct soc_device *soc_dev) | |||
| 42 | return &soc_dev->dev; | 42 | return &soc_dev->dev; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static mode_t soc_attribute_mode(struct kobject *kobj, | 45 | static umode_t soc_attribute_mode(struct kobject *kobj, |
| 46 | struct attribute *attr, | 46 | struct attribute *attr, |
| 47 | int index) | 47 | int index) |
| 48 | { | 48 | { |
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index d7038230b71e..7053140c6596 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c | |||
| @@ -35,9 +35,28 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | |||
| 35 | {0,} | 35 | {0,} |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | |||
| 39 | static void cirrus_kick_out_firmware_fb(struct pci_dev *pdev) | ||
| 40 | { | ||
| 41 | struct apertures_struct *ap; | ||
| 42 | bool primary = false; | ||
| 43 | |||
| 44 | ap = alloc_apertures(1); | ||
| 45 | ap->ranges[0].base = pci_resource_start(pdev, 0); | ||
| 46 | ap->ranges[0].size = pci_resource_len(pdev, 0); | ||
| 47 | |||
| 48 | #ifdef CONFIG_X86 | ||
| 49 | primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; | ||
| 50 | #endif | ||
| 51 | remove_conflicting_framebuffers(ap, "cirrusdrmfb", primary); | ||
| 52 | kfree(ap); | ||
| 53 | } | ||
| 54 | |||
| 38 | static int __devinit | 55 | static int __devinit |
| 39 | cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 56 | cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 40 | { | 57 | { |
| 58 | cirrus_kick_out_firmware_fb(pdev); | ||
| 59 | |||
| 41 | return drm_get_pci_dev(pdev, ent, &driver); | 60 | return drm_get_pci_dev(pdev, ent, &driver); |
| 42 | } | 61 | } |
| 43 | 62 | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 21bdfa8836f7..64ea597cb6d3 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h | |||
| @@ -145,7 +145,7 @@ struct cirrus_device { | |||
| 145 | struct ttm_bo_device bdev; | 145 | struct ttm_bo_device bdev; |
| 146 | atomic_t validate_sequence; | 146 | atomic_t validate_sequence; |
| 147 | } ttm; | 147 | } ttm; |
| 148 | 148 | bool mm_inited; | |
| 149 | }; | 149 | }; |
| 150 | 150 | ||
| 151 | 151 | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 2ebcd11a5023..50e170f879de 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c | |||
| @@ -275,12 +275,17 @@ int cirrus_mm_init(struct cirrus_device *cirrus) | |||
| 275 | pci_resource_len(dev->pdev, 0), | 275 | pci_resource_len(dev->pdev, 0), |
| 276 | DRM_MTRR_WC); | 276 | DRM_MTRR_WC); |
| 277 | 277 | ||
| 278 | cirrus->mm_inited = true; | ||
| 278 | return 0; | 279 | return 0; |
| 279 | } | 280 | } |
| 280 | 281 | ||
| 281 | void cirrus_mm_fini(struct cirrus_device *cirrus) | 282 | void cirrus_mm_fini(struct cirrus_device *cirrus) |
| 282 | { | 283 | { |
| 283 | struct drm_device *dev = cirrus->dev; | 284 | struct drm_device *dev = cirrus->dev; |
| 285 | |||
| 286 | if (!cirrus->mm_inited) | ||
| 287 | return; | ||
| 288 | |||
| 284 | ttm_bo_device_release(&cirrus->ttm.bdev); | 289 | ttm_bo_device_release(&cirrus->ttm.bdev); |
| 285 | 290 | ||
| 286 | cirrus_ttm_global_release(cirrus); | 291 | cirrus_ttm_global_release(cirrus); |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c3b5139eba7f..eb92fe257a39 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/i2c.h> | 32 | #include <linux/i2c.h> |
| 33 | #include <linux/export.h> | 33 | #include <linux/module.h> |
| 34 | #include "drmP.h" | 34 | #include "drmP.h" |
| 35 | #include "drm_edid.h" | 35 | #include "drm_edid.h" |
| 36 | #include "drm_edid_modes.h" | 36 | #include "drm_edid_modes.h" |
| @@ -149,6 +149,10 @@ int drm_edid_header_is_valid(const u8 *raw_edid) | |||
| 149 | } | 149 | } |
| 150 | EXPORT_SYMBOL(drm_edid_header_is_valid); | 150 | EXPORT_SYMBOL(drm_edid_header_is_valid); |
| 151 | 151 | ||
| 152 | static int edid_fixup __read_mostly = 6; | ||
| 153 | module_param_named(edid_fixup, edid_fixup, int, 0400); | ||
| 154 | MODULE_PARM_DESC(edid_fixup, | ||
| 155 | "Minimum number of valid EDID header bytes (0-8, default 6)"); | ||
| 152 | 156 | ||
| 153 | /* | 157 | /* |
| 154 | * Sanity check the EDID block (base or extension). Return 0 if the block | 158 | * Sanity check the EDID block (base or extension). Return 0 if the block |
| @@ -160,10 +164,13 @@ bool drm_edid_block_valid(u8 *raw_edid, int block) | |||
| 160 | u8 csum = 0; | 164 | u8 csum = 0; |
| 161 | struct edid *edid = (struct edid *)raw_edid; | 165 | struct edid *edid = (struct edid *)raw_edid; |
| 162 | 166 | ||
| 167 | if (edid_fixup > 8 || edid_fixup < 0) | ||
| 168 | edid_fixup = 6; | ||
| 169 | |||
| 163 | if (block == 0) { | 170 | if (block == 0) { |
| 164 | int score = drm_edid_header_is_valid(raw_edid); | 171 | int score = drm_edid_header_is_valid(raw_edid); |
| 165 | if (score == 8) ; | 172 | if (score == 8) ; |
| 166 | else if (score >= 6) { | 173 | else if (score >= edid_fixup) { |
| 167 | DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); | 174 | DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); |
| 168 | memcpy(raw_edid, edid_header, sizeof(edid_header)); | 175 | memcpy(raw_edid, edid_header, sizeof(edid_header)); |
| 169 | } else { | 176 | } else { |
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index f920fb5e42b6..fa9439159ebd 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c | |||
| @@ -130,11 +130,10 @@ static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) | |||
| 130 | return -EINVAL; | 130 | return -EINVAL; |
| 131 | 131 | ||
| 132 | /* This is all entirely broken */ | 132 | /* This is all entirely broken */ |
| 133 | down_write(¤t->mm->mmap_sem); | ||
| 134 | old_fops = file_priv->filp->f_op; | 133 | old_fops = file_priv->filp->f_op; |
| 135 | file_priv->filp->f_op = &i810_buffer_fops; | 134 | file_priv->filp->f_op = &i810_buffer_fops; |
| 136 | dev_priv->mmap_buffer = buf; | 135 | dev_priv->mmap_buffer = buf; |
| 137 | buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total, | 136 | buf_priv->virtual = (void *)vm_mmap(file_priv->filp, 0, buf->total, |
| 138 | PROT_READ | PROT_WRITE, | 137 | PROT_READ | PROT_WRITE, |
| 139 | MAP_SHARED, buf->bus_address); | 138 | MAP_SHARED, buf->bus_address); |
| 140 | dev_priv->mmap_buffer = NULL; | 139 | dev_priv->mmap_buffer = NULL; |
| @@ -145,7 +144,6 @@ static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) | |||
| 145 | retcode = PTR_ERR(buf_priv->virtual); | 144 | retcode = PTR_ERR(buf_priv->virtual); |
| 146 | buf_priv->virtual = NULL; | 145 | buf_priv->virtual = NULL; |
| 147 | } | 146 | } |
| 148 | up_write(¤t->mm->mmap_sem); | ||
| 149 | 147 | ||
| 150 | return retcode; | 148 | return retcode; |
| 151 | } | 149 | } |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 377c21f531e4..c9cfc67c2cf5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -942,6 +942,9 @@ struct drm_i915_gem_object { | |||
| 942 | 942 | ||
| 943 | /* prime dma-buf support */ | 943 | /* prime dma-buf support */ |
| 944 | struct sg_table *sg_table; | 944 | struct sg_table *sg_table; |
| 945 | void *dma_buf_vmapping; | ||
| 946 | int vmapping_count; | ||
| 947 | |||
| 945 | /** | 948 | /** |
| 946 | * Used for performing relocations during execbuffer insertion. | 949 | * Used for performing relocations during execbuffer insertion. |
| 947 | */ | 950 | */ |
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 8e269178d6a5..aa308e1337db 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c | |||
| @@ -74,6 +74,59 @@ static void i915_gem_dmabuf_release(struct dma_buf *dma_buf) | |||
| 74 | } | 74 | } |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) | ||
| 78 | { | ||
| 79 | struct drm_i915_gem_object *obj = dma_buf->priv; | ||
| 80 | struct drm_device *dev = obj->base.dev; | ||
| 81 | int ret; | ||
| 82 | |||
| 83 | ret = i915_mutex_lock_interruptible(dev); | ||
| 84 | if (ret) | ||
| 85 | return ERR_PTR(ret); | ||
| 86 | |||
| 87 | if (obj->dma_buf_vmapping) { | ||
| 88 | obj->vmapping_count++; | ||
| 89 | goto out_unlock; | ||
| 90 | } | ||
| 91 | |||
| 92 | if (!obj->pages) { | ||
| 93 | ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN); | ||
| 94 | if (ret) { | ||
| 95 | mutex_unlock(&dev->struct_mutex); | ||
| 96 | return ERR_PTR(ret); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | obj->dma_buf_vmapping = vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL); | ||
| 101 | if (!obj->dma_buf_vmapping) { | ||
| 102 | DRM_ERROR("failed to vmap object\n"); | ||
| 103 | goto out_unlock; | ||
| 104 | } | ||
| 105 | |||
| 106 | obj->vmapping_count = 1; | ||
| 107 | out_unlock: | ||
| 108 | mutex_unlock(&dev->struct_mutex); | ||
| 109 | return obj->dma_buf_vmapping; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) | ||
| 113 | { | ||
| 114 | struct drm_i915_gem_object *obj = dma_buf->priv; | ||
| 115 | struct drm_device *dev = obj->base.dev; | ||
| 116 | int ret; | ||
| 117 | |||
| 118 | ret = i915_mutex_lock_interruptible(dev); | ||
| 119 | if (ret) | ||
| 120 | return; | ||
| 121 | |||
| 122 | --obj->vmapping_count; | ||
| 123 | if (obj->vmapping_count == 0) { | ||
| 124 | vunmap(obj->dma_buf_vmapping); | ||
| 125 | obj->dma_buf_vmapping = NULL; | ||
| 126 | } | ||
| 127 | mutex_unlock(&dev->struct_mutex); | ||
| 128 | } | ||
| 129 | |||
| 77 | static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) | 130 | static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) |
| 78 | { | 131 | { |
| 79 | return NULL; | 132 | return NULL; |
| @@ -93,6 +146,11 @@ static void i915_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_n | |||
| 93 | 146 | ||
| 94 | } | 147 | } |
| 95 | 148 | ||
| 149 | static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) | ||
| 150 | { | ||
| 151 | return -EINVAL; | ||
| 152 | } | ||
| 153 | |||
| 96 | static const struct dma_buf_ops i915_dmabuf_ops = { | 154 | static const struct dma_buf_ops i915_dmabuf_ops = { |
| 97 | .map_dma_buf = i915_gem_map_dma_buf, | 155 | .map_dma_buf = i915_gem_map_dma_buf, |
| 98 | .unmap_dma_buf = i915_gem_unmap_dma_buf, | 156 | .unmap_dma_buf = i915_gem_unmap_dma_buf, |
| @@ -101,6 +159,9 @@ static const struct dma_buf_ops i915_dmabuf_ops = { | |||
| 101 | .kmap_atomic = i915_gem_dmabuf_kmap_atomic, | 159 | .kmap_atomic = i915_gem_dmabuf_kmap_atomic, |
| 102 | .kunmap = i915_gem_dmabuf_kunmap, | 160 | .kunmap = i915_gem_dmabuf_kunmap, |
| 103 | .kunmap_atomic = i915_gem_dmabuf_kunmap_atomic, | 161 | .kunmap_atomic = i915_gem_dmabuf_kunmap_atomic, |
| 162 | .mmap = i915_gem_dmabuf_mmap, | ||
| 163 | .vmap = i915_gem_dmabuf_vmap, | ||
| 164 | .vunmap = i915_gem_dmabuf_vunmap, | ||
| 104 | }; | 165 | }; |
| 105 | 166 | ||
| 106 | struct dma_buf *i915_gem_prime_export(struct drm_device *dev, | 167 | struct dma_buf *i915_gem_prime_export(struct drm_device *dev, |
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 3c8e04f54713..93e832d6c328 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c | |||
| @@ -41,9 +41,28 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | |||
| 41 | 41 | ||
| 42 | MODULE_DEVICE_TABLE(pci, pciidlist); | 42 | MODULE_DEVICE_TABLE(pci, pciidlist); |
| 43 | 43 | ||
| 44 | static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev) | ||
| 45 | { | ||
| 46 | struct apertures_struct *ap; | ||
| 47 | bool primary = false; | ||
| 48 | |||
| 49 | ap = alloc_apertures(1); | ||
| 50 | ap->ranges[0].base = pci_resource_start(pdev, 0); | ||
| 51 | ap->ranges[0].size = pci_resource_len(pdev, 0); | ||
| 52 | |||
| 53 | #ifdef CONFIG_X86 | ||
| 54 | primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; | ||
| 55 | #endif | ||
| 56 | remove_conflicting_framebuffers(ap, "mgag200drmfb", primary); | ||
| 57 | kfree(ap); | ||
| 58 | } | ||
| 59 | |||
| 60 | |||
| 44 | static int __devinit | 61 | static int __devinit |
| 45 | mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 62 | mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 46 | { | 63 | { |
| 64 | mgag200_kick_out_firmware_fb(pdev); | ||
| 65 | |||
| 47 | return drm_get_pci_dev(pdev, ent, &driver); | 66 | return drm_get_pci_dev(pdev, ent, &driver); |
| 48 | } | 67 | } |
| 49 | 68 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 634d222c93de..8613cb23808c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
| @@ -123,6 +123,9 @@ struct nouveau_bo { | |||
| 123 | 123 | ||
| 124 | struct drm_gem_object *gem; | 124 | struct drm_gem_object *gem; |
| 125 | int pin_refcnt; | 125 | int pin_refcnt; |
| 126 | |||
| 127 | struct ttm_bo_kmap_obj dma_buf_vmap; | ||
| 128 | int vmapping_count; | ||
| 126 | }; | 129 | }; |
| 127 | 130 | ||
| 128 | #define nouveau_bo_tile_layout(nvbo) \ | 131 | #define nouveau_bo_tile_layout(nvbo) \ |
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index c58aab7370c5..a89240e5fb29 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c | |||
| @@ -61,6 +61,48 @@ static void nouveau_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, | |||
| 61 | 61 | ||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static int nouveau_gem_prime_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) | ||
| 65 | { | ||
| 66 | return -EINVAL; | ||
| 67 | } | ||
| 68 | |||
| 69 | static void *nouveau_gem_prime_vmap(struct dma_buf *dma_buf) | ||
| 70 | { | ||
| 71 | struct nouveau_bo *nvbo = dma_buf->priv; | ||
| 72 | struct drm_device *dev = nvbo->gem->dev; | ||
| 73 | int ret; | ||
| 74 | |||
| 75 | mutex_lock(&dev->struct_mutex); | ||
| 76 | if (nvbo->vmapping_count) { | ||
| 77 | nvbo->vmapping_count++; | ||
| 78 | goto out_unlock; | ||
| 79 | } | ||
| 80 | |||
| 81 | ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.num_pages, | ||
| 82 | &nvbo->dma_buf_vmap); | ||
| 83 | if (ret) { | ||
| 84 | mutex_unlock(&dev->struct_mutex); | ||
| 85 | return ERR_PTR(ret); | ||
| 86 | } | ||
| 87 | nvbo->vmapping_count = 1; | ||
| 88 | out_unlock: | ||
| 89 | mutex_unlock(&dev->struct_mutex); | ||
| 90 | return nvbo->dma_buf_vmap.virtual; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void nouveau_gem_prime_vunmap(struct dma_buf *dma_buf, void *vaddr) | ||
| 94 | { | ||
| 95 | struct nouveau_bo *nvbo = dma_buf->priv; | ||
| 96 | struct drm_device *dev = nvbo->gem->dev; | ||
| 97 | |||
| 98 | mutex_lock(&dev->struct_mutex); | ||
| 99 | nvbo->vmapping_count--; | ||
| 100 | if (nvbo->vmapping_count == 0) { | ||
| 101 | ttm_bo_kunmap(&nvbo->dma_buf_vmap); | ||
| 102 | } | ||
| 103 | mutex_unlock(&dev->struct_mutex); | ||
| 104 | } | ||
| 105 | |||
| 64 | static const struct dma_buf_ops nouveau_dmabuf_ops = { | 106 | static const struct dma_buf_ops nouveau_dmabuf_ops = { |
| 65 | .map_dma_buf = nouveau_gem_map_dma_buf, | 107 | .map_dma_buf = nouveau_gem_map_dma_buf, |
| 66 | .unmap_dma_buf = nouveau_gem_unmap_dma_buf, | 108 | .unmap_dma_buf = nouveau_gem_unmap_dma_buf, |
| @@ -69,6 +111,9 @@ static const struct dma_buf_ops nouveau_dmabuf_ops = { | |||
| 69 | .kmap_atomic = nouveau_gem_kmap_atomic, | 111 | .kmap_atomic = nouveau_gem_kmap_atomic, |
| 70 | .kunmap = nouveau_gem_kunmap, | 112 | .kunmap = nouveau_gem_kunmap, |
| 71 | .kunmap_atomic = nouveau_gem_kunmap_atomic, | 113 | .kunmap_atomic = nouveau_gem_kunmap_atomic, |
| 114 | .mmap = nouveau_gem_prime_mmap, | ||
| 115 | .vmap = nouveau_gem_prime_vmap, | ||
| 116 | .vunmap = nouveau_gem_prime_vunmap, | ||
| 72 | }; | 117 | }; |
| 73 | 118 | ||
| 74 | static int | 119 | static int |
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 58991af90502..01550d05e273 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c | |||
| @@ -1029,6 +1029,11 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) | |||
| 1029 | WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); | 1029 | WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); |
| 1030 | WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); | 1030 | WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); |
| 1031 | WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); | 1031 | WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); |
| 1032 | if ((rdev->family == CHIP_JUNIPER) || | ||
| 1033 | (rdev->family == CHIP_CYPRESS) || | ||
| 1034 | (rdev->family == CHIP_HEMLOCK) || | ||
| 1035 | (rdev->family == CHIP_BARTS)) | ||
| 1036 | WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp); | ||
| 1032 | } | 1037 | } |
| 1033 | WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); | 1038 | WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); |
| 1034 | WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); | 1039 | WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); |
| @@ -1553,163 +1558,10 @@ int evergreen_cp_resume(struct radeon_device *rdev) | |||
| 1553 | /* | 1558 | /* |
| 1554 | * Core functions | 1559 | * Core functions |
| 1555 | */ | 1560 | */ |
| 1556 | static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, | ||
| 1557 | u32 num_tile_pipes, | ||
| 1558 | u32 num_backends, | ||
| 1559 | u32 backend_disable_mask) | ||
| 1560 | { | ||
| 1561 | u32 backend_map = 0; | ||
| 1562 | u32 enabled_backends_mask = 0; | ||
| 1563 | u32 enabled_backends_count = 0; | ||
| 1564 | u32 cur_pipe; | ||
| 1565 | u32 swizzle_pipe[EVERGREEN_MAX_PIPES]; | ||
| 1566 | u32 cur_backend = 0; | ||
| 1567 | u32 i; | ||
| 1568 | bool force_no_swizzle; | ||
| 1569 | |||
| 1570 | if (num_tile_pipes > EVERGREEN_MAX_PIPES) | ||
| 1571 | num_tile_pipes = EVERGREEN_MAX_PIPES; | ||
| 1572 | if (num_tile_pipes < 1) | ||
| 1573 | num_tile_pipes = 1; | ||
| 1574 | if (num_backends > EVERGREEN_MAX_BACKENDS) | ||
| 1575 | num_backends = EVERGREEN_MAX_BACKENDS; | ||
| 1576 | if (num_backends < 1) | ||
| 1577 | num_backends = 1; | ||
| 1578 | |||
| 1579 | for (i = 0; i < EVERGREEN_MAX_BACKENDS; ++i) { | ||
| 1580 | if (((backend_disable_mask >> i) & 1) == 0) { | ||
| 1581 | enabled_backends_mask |= (1 << i); | ||
| 1582 | ++enabled_backends_count; | ||
| 1583 | } | ||
| 1584 | if (enabled_backends_count == num_backends) | ||
| 1585 | break; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | if (enabled_backends_count == 0) { | ||
| 1589 | enabled_backends_mask = 1; | ||
| 1590 | enabled_backends_count = 1; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | if (enabled_backends_count != num_backends) | ||
| 1594 | num_backends = enabled_backends_count; | ||
| 1595 | |||
| 1596 | memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * EVERGREEN_MAX_PIPES); | ||
| 1597 | switch (rdev->family) { | ||
| 1598 | case CHIP_CEDAR: | ||
| 1599 | case CHIP_REDWOOD: | ||
| 1600 | case CHIP_PALM: | ||
| 1601 | case CHIP_SUMO: | ||
| 1602 | case CHIP_SUMO2: | ||
| 1603 | case CHIP_TURKS: | ||
| 1604 | case CHIP_CAICOS: | ||
| 1605 | force_no_swizzle = false; | ||
| 1606 | break; | ||
| 1607 | case CHIP_CYPRESS: | ||
| 1608 | case CHIP_HEMLOCK: | ||
| 1609 | case CHIP_JUNIPER: | ||
| 1610 | case CHIP_BARTS: | ||
| 1611 | default: | ||
| 1612 | force_no_swizzle = true; | ||
| 1613 | break; | ||
| 1614 | } | ||
| 1615 | if (force_no_swizzle) { | ||
| 1616 | bool last_backend_enabled = false; | ||
| 1617 | |||
| 1618 | force_no_swizzle = false; | ||
| 1619 | for (i = 0; i < EVERGREEN_MAX_BACKENDS; ++i) { | ||
| 1620 | if (((enabled_backends_mask >> i) & 1) == 1) { | ||
| 1621 | if (last_backend_enabled) | ||
| 1622 | force_no_swizzle = true; | ||
| 1623 | last_backend_enabled = true; | ||
| 1624 | } else | ||
| 1625 | last_backend_enabled = false; | ||
| 1626 | } | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | switch (num_tile_pipes) { | ||
| 1630 | case 1: | ||
| 1631 | case 3: | ||
| 1632 | case 5: | ||
| 1633 | case 7: | ||
| 1634 | DRM_ERROR("odd number of pipes!\n"); | ||
| 1635 | break; | ||
| 1636 | case 2: | ||
| 1637 | swizzle_pipe[0] = 0; | ||
| 1638 | swizzle_pipe[1] = 1; | ||
| 1639 | break; | ||
| 1640 | case 4: | ||
| 1641 | if (force_no_swizzle) { | ||
| 1642 | swizzle_pipe[0] = 0; | ||
| 1643 | swizzle_pipe[1] = 1; | ||
| 1644 | swizzle_pipe[2] = 2; | ||
| 1645 | swizzle_pipe[3] = 3; | ||
| 1646 | } else { | ||
| 1647 | swizzle_pipe[0] = 0; | ||
| 1648 | swizzle_pipe[1] = 2; | ||
| 1649 | swizzle_pipe[2] = 1; | ||
| 1650 | swizzle_pipe[3] = 3; | ||
| 1651 | } | ||
| 1652 | break; | ||
| 1653 | case 6: | ||
| 1654 | if (force_no_swizzle) { | ||
| 1655 | swizzle_pipe[0] = 0; | ||
| 1656 | swizzle_pipe[1] = 1; | ||
| 1657 | swizzle_pipe[2] = 2; | ||
| 1658 | swizzle_pipe[3] = 3; | ||
| 1659 | swizzle_pipe[4] = 4; | ||
| 1660 | swizzle_pipe[5] = 5; | ||
| 1661 | } else { | ||
| 1662 | swizzle_pipe[0] = 0; | ||
| 1663 | swizzle_pipe[1] = 2; | ||
| 1664 | swizzle_pipe[2] = 4; | ||
| 1665 | swizzle_pipe[3] = 1; | ||
| 1666 | swizzle_pipe[4] = 3; | ||
| 1667 | swizzle_pipe[5] = 5; | ||
| 1668 | } | ||
| 1669 | break; | ||
| 1670 | case 8: | ||
| 1671 | if (force_no_swizzle) { | ||
| 1672 | swizzle_pipe[0] = 0; | ||
| 1673 | swizzle_pipe[1] = 1; | ||
| 1674 | swizzle_pipe[2] = 2; | ||
| 1675 | swizzle_pipe[3] = 3; | ||
| 1676 | swizzle_pipe[4] = 4; | ||
| 1677 | swizzle_pipe[5] = 5; | ||
| 1678 | swizzle_pipe[6] = 6; | ||
| 1679 | swizzle_pipe[7] = 7; | ||
| 1680 | } else { | ||
| 1681 | swizzle_pipe[0] = 0; | ||
| 1682 | swizzle_pipe[1] = 2; | ||
| 1683 | swizzle_pipe[2] = 4; | ||
| 1684 | swizzle_pipe[3] = 6; | ||
| 1685 | swizzle_pipe[4] = 1; | ||
| 1686 | swizzle_pipe[5] = 3; | ||
| 1687 | swizzle_pipe[6] = 5; | ||
| 1688 | swizzle_pipe[7] = 7; | ||
| 1689 | } | ||
| 1690 | break; | ||
| 1691 | } | ||
| 1692 | |||
| 1693 | for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { | ||
| 1694 | while (((1 << cur_backend) & enabled_backends_mask) == 0) | ||
| 1695 | cur_backend = (cur_backend + 1) % EVERGREEN_MAX_BACKENDS; | ||
| 1696 | |||
| 1697 | backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4))); | ||
| 1698 | |||
| 1699 | cur_backend = (cur_backend + 1) % EVERGREEN_MAX_BACKENDS; | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | return backend_map; | ||
| 1703 | } | ||
| 1704 | |||
| 1705 | static void evergreen_gpu_init(struct radeon_device *rdev) | 1561 | static void evergreen_gpu_init(struct radeon_device *rdev) |
| 1706 | { | 1562 | { |
| 1707 | u32 cc_rb_backend_disable = 0; | 1563 | u32 gb_addr_config; |
| 1708 | u32 cc_gc_shader_pipe_config; | ||
| 1709 | u32 gb_addr_config = 0; | ||
| 1710 | u32 mc_shared_chmap, mc_arb_ramcfg; | 1564 | u32 mc_shared_chmap, mc_arb_ramcfg; |
| 1711 | u32 gb_backend_map; | ||
| 1712 | u32 grbm_gfx_index; | ||
| 1713 | u32 sx_debug_1; | 1565 | u32 sx_debug_1; |
| 1714 | u32 smx_dc_ctl0; | 1566 | u32 smx_dc_ctl0; |
| 1715 | u32 sq_config; | 1567 | u32 sq_config; |
| @@ -1724,6 +1576,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1724 | u32 sq_stack_resource_mgmt_3; | 1576 | u32 sq_stack_resource_mgmt_3; |
| 1725 | u32 vgt_cache_invalidation; | 1577 | u32 vgt_cache_invalidation; |
| 1726 | u32 hdp_host_path_cntl, tmp; | 1578 | u32 hdp_host_path_cntl, tmp; |
| 1579 | u32 disabled_rb_mask; | ||
| 1727 | int i, j, num_shader_engines, ps_thread_count; | 1580 | int i, j, num_shader_engines, ps_thread_count; |
| 1728 | 1581 | ||
| 1729 | switch (rdev->family) { | 1582 | switch (rdev->family) { |
| @@ -1748,6 +1601,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1748 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; | 1601 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; |
| 1749 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1602 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1750 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1603 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1604 | gb_addr_config = CYPRESS_GB_ADDR_CONFIG_GOLDEN; | ||
| 1751 | break; | 1605 | break; |
| 1752 | case CHIP_JUNIPER: | 1606 | case CHIP_JUNIPER: |
| 1753 | rdev->config.evergreen.num_ses = 1; | 1607 | rdev->config.evergreen.num_ses = 1; |
| @@ -1769,6 +1623,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1769 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; | 1623 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; |
| 1770 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1624 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1771 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1625 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1626 | gb_addr_config = JUNIPER_GB_ADDR_CONFIG_GOLDEN; | ||
| 1772 | break; | 1627 | break; |
| 1773 | case CHIP_REDWOOD: | 1628 | case CHIP_REDWOOD: |
| 1774 | rdev->config.evergreen.num_ses = 1; | 1629 | rdev->config.evergreen.num_ses = 1; |
| @@ -1790,6 +1645,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1790 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; | 1645 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; |
| 1791 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1646 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1792 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1647 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1648 | gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; | ||
| 1793 | break; | 1649 | break; |
| 1794 | case CHIP_CEDAR: | 1650 | case CHIP_CEDAR: |
| 1795 | default: | 1651 | default: |
| @@ -1812,6 +1668,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1812 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; | 1668 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; |
| 1813 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1669 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1814 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1670 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1671 | gb_addr_config = CEDAR_GB_ADDR_CONFIG_GOLDEN; | ||
| 1815 | break; | 1672 | break; |
| 1816 | case CHIP_PALM: | 1673 | case CHIP_PALM: |
| 1817 | rdev->config.evergreen.num_ses = 1; | 1674 | rdev->config.evergreen.num_ses = 1; |
| @@ -1833,6 +1690,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1833 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; | 1690 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; |
| 1834 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1691 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1835 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1692 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1693 | gb_addr_config = CEDAR_GB_ADDR_CONFIG_GOLDEN; | ||
| 1836 | break; | 1694 | break; |
| 1837 | case CHIP_SUMO: | 1695 | case CHIP_SUMO: |
| 1838 | rdev->config.evergreen.num_ses = 1; | 1696 | rdev->config.evergreen.num_ses = 1; |
| @@ -1860,6 +1718,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1860 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; | 1718 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; |
| 1861 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1719 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1862 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1720 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1721 | gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; | ||
| 1863 | break; | 1722 | break; |
| 1864 | case CHIP_SUMO2: | 1723 | case CHIP_SUMO2: |
| 1865 | rdev->config.evergreen.num_ses = 1; | 1724 | rdev->config.evergreen.num_ses = 1; |
| @@ -1881,6 +1740,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1881 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; | 1740 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; |
| 1882 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1741 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1883 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1742 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1743 | gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; | ||
| 1884 | break; | 1744 | break; |
| 1885 | case CHIP_BARTS: | 1745 | case CHIP_BARTS: |
| 1886 | rdev->config.evergreen.num_ses = 2; | 1746 | rdev->config.evergreen.num_ses = 2; |
| @@ -1902,6 +1762,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1902 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; | 1762 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; |
| 1903 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1763 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1904 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1764 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1765 | gb_addr_config = BARTS_GB_ADDR_CONFIG_GOLDEN; | ||
| 1905 | break; | 1766 | break; |
| 1906 | case CHIP_TURKS: | 1767 | case CHIP_TURKS: |
| 1907 | rdev->config.evergreen.num_ses = 1; | 1768 | rdev->config.evergreen.num_ses = 1; |
| @@ -1923,6 +1784,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1923 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; | 1784 | rdev->config.evergreen.sc_prim_fifo_size = 0x100; |
| 1924 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1785 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1925 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1786 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1787 | gb_addr_config = TURKS_GB_ADDR_CONFIG_GOLDEN; | ||
| 1926 | break; | 1788 | break; |
| 1927 | case CHIP_CAICOS: | 1789 | case CHIP_CAICOS: |
| 1928 | rdev->config.evergreen.num_ses = 1; | 1790 | rdev->config.evergreen.num_ses = 1; |
| @@ -1944,6 +1806,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1944 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; | 1806 | rdev->config.evergreen.sc_prim_fifo_size = 0x40; |
| 1945 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; | 1807 | rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; |
| 1946 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; | 1808 | rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; |
| 1809 | gb_addr_config = CAICOS_GB_ADDR_CONFIG_GOLDEN; | ||
| 1947 | break; | 1810 | break; |
| 1948 | } | 1811 | } |
| 1949 | 1812 | ||
| @@ -1960,20 +1823,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1960 | 1823 | ||
| 1961 | evergreen_fix_pci_max_read_req_size(rdev); | 1824 | evergreen_fix_pci_max_read_req_size(rdev); |
| 1962 | 1825 | ||
| 1963 | cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2; | ||
| 1964 | |||
| 1965 | cc_gc_shader_pipe_config |= | ||
| 1966 | INACTIVE_QD_PIPES((EVERGREEN_MAX_PIPES_MASK << rdev->config.evergreen.max_pipes) | ||
| 1967 | & EVERGREEN_MAX_PIPES_MASK); | ||
| 1968 | cc_gc_shader_pipe_config |= | ||
| 1969 | INACTIVE_SIMDS((EVERGREEN_MAX_SIMDS_MASK << rdev->config.evergreen.max_simds) | ||
| 1970 | & EVERGREEN_MAX_SIMDS_MASK); | ||
| 1971 | |||
| 1972 | cc_rb_backend_disable = | ||
| 1973 | BACKEND_DISABLE((EVERGREEN_MAX_BACKENDS_MASK << rdev->config.evergreen.max_backends) | ||
| 1974 | & EVERGREEN_MAX_BACKENDS_MASK); | ||
| 1975 | |||
| 1976 | |||
| 1977 | mc_shared_chmap = RREG32(MC_SHARED_CHMAP); | 1826 | mc_shared_chmap = RREG32(MC_SHARED_CHMAP); |
| 1978 | if ((rdev->family == CHIP_PALM) || | 1827 | if ((rdev->family == CHIP_PALM) || |
| 1979 | (rdev->family == CHIP_SUMO) || | 1828 | (rdev->family == CHIP_SUMO) || |
| @@ -1982,134 +1831,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 1982 | else | 1831 | else |
| 1983 | mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); | 1832 | mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); |
| 1984 | 1833 | ||
| 1985 | switch (rdev->config.evergreen.max_tile_pipes) { | ||
| 1986 | case 1: | ||
| 1987 | default: | ||
| 1988 | gb_addr_config |= NUM_PIPES(0); | ||
| 1989 | break; | ||
| 1990 | case 2: | ||
| 1991 | gb_addr_config |= NUM_PIPES(1); | ||
| 1992 | break; | ||
| 1993 | case 4: | ||
| 1994 | gb_addr_config |= NUM_PIPES(2); | ||
| 1995 | break; | ||
| 1996 | case 8: | ||
| 1997 | gb_addr_config |= NUM_PIPES(3); | ||
| 1998 | break; | ||
| 1999 | } | ||
| 2000 | |||
| 2001 | gb_addr_config |= PIPE_INTERLEAVE_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); | ||
| 2002 | gb_addr_config |= BANK_INTERLEAVE_SIZE(0); | ||
| 2003 | gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.evergreen.num_ses - 1); | ||
| 2004 | gb_addr_config |= SHADER_ENGINE_TILE_SIZE(1); | ||
| 2005 | gb_addr_config |= NUM_GPUS(0); /* Hemlock? */ | ||
| 2006 | gb_addr_config |= MULTI_GPU_TILE_SIZE(2); | ||
| 2007 | |||
| 2008 | if (((mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) > 2) | ||
| 2009 | gb_addr_config |= ROW_SIZE(2); | ||
| 2010 | else | ||
| 2011 | gb_addr_config |= ROW_SIZE((mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT); | ||
| 2012 | |||
| 2013 | if (rdev->ddev->pdev->device == 0x689e) { | ||
| 2014 | u32 efuse_straps_4; | ||
| 2015 | u32 efuse_straps_3; | ||
| 2016 | u8 efuse_box_bit_131_124; | ||
| 2017 | |||
| 2018 | WREG32(RCU_IND_INDEX, 0x204); | ||
| 2019 | efuse_straps_4 = RREG32(RCU_IND_DATA); | ||
| 2020 | WREG32(RCU_IND_INDEX, 0x203); | ||
| 2021 | efuse_straps_3 = RREG32(RCU_IND_DATA); | ||
| 2022 | efuse_box_bit_131_124 = (u8)(((efuse_straps_4 & 0xf) << 4) | ((efuse_straps_3 & 0xf0000000) >> 28)); | ||
| 2023 | |||
| 2024 | switch(efuse_box_bit_131_124) { | ||
| 2025 | case 0x00: | ||
| 2026 | gb_backend_map = 0x76543210; | ||
| 2027 | break; | ||
| 2028 | case 0x55: | ||
| 2029 | gb_backend_map = 0x77553311; | ||
| 2030 | break; | ||
| 2031 | case 0x56: | ||
| 2032 | gb_backend_map = 0x77553300; | ||
| 2033 | break; | ||
| 2034 | case 0x59: | ||
| 2035 | gb_backend_map = 0x77552211; | ||
| 2036 | break; | ||
| 2037 | case 0x66: | ||
| 2038 | gb_backend_map = 0x77443300; | ||
| 2039 | break; | ||
| 2040 | case 0x99: | ||
| 2041 | gb_backend_map = 0x66552211; | ||
| 2042 | break; | ||
| 2043 | case 0x5a: | ||
| 2044 | gb_backend_map = 0x77552200; | ||
| 2045 | break; | ||
| 2046 | case 0xaa: | ||
| 2047 | gb_backend_map = 0x66442200; | ||
| 2048 | break; | ||
| 2049 | case 0x95: | ||
| 2050 | gb_backend_map = 0x66553311; | ||
| 2051 | break; | ||
| 2052 | default: | ||
| 2053 | DRM_ERROR("bad backend map, using default\n"); | ||
| 2054 | gb_backend_map = | ||
| 2055 | evergreen_get_tile_pipe_to_backend_map(rdev, | ||
| 2056 | rdev->config.evergreen.max_tile_pipes, | ||
| 2057 | rdev->config.evergreen.max_backends, | ||
| 2058 | ((EVERGREEN_MAX_BACKENDS_MASK << | ||
| 2059 | rdev->config.evergreen.max_backends) & | ||
| 2060 | EVERGREEN_MAX_BACKENDS_MASK)); | ||
| 2061 | break; | ||
| 2062 | } | ||
| 2063 | } else if (rdev->ddev->pdev->device == 0x68b9) { | ||
| 2064 | u32 efuse_straps_3; | ||
| 2065 | u8 efuse_box_bit_127_124; | ||
| 2066 | |||
| 2067 | WREG32(RCU_IND_INDEX, 0x203); | ||
| 2068 | efuse_straps_3 = RREG32(RCU_IND_DATA); | ||
| 2069 | efuse_box_bit_127_124 = (u8)((efuse_straps_3 & 0xF0000000) >> 28); | ||
| 2070 | |||
| 2071 | switch(efuse_box_bit_127_124) { | ||
| 2072 | case 0x0: | ||
| 2073 | gb_backend_map = 0x00003210; | ||
| 2074 | break; | ||
| 2075 | case 0x5: | ||
| 2076 | case 0x6: | ||
| 2077 | case 0x9: | ||
| 2078 | case 0xa: | ||
| 2079 | gb_backend_map = 0x00003311; | ||
| 2080 | break; | ||
| 2081 | default: | ||
| 2082 | DRM_ERROR("bad backend map, using default\n"); | ||
| 2083 | gb_backend_map = | ||
| 2084 | evergreen_get_tile_pipe_to_backend_map(rdev, | ||
| 2085 | rdev->config.evergreen.max_tile_pipes, | ||
| 2086 | rdev->config.evergreen.max_backends, | ||
| 2087 | ((EVERGREEN_MAX_BACKENDS_MASK << | ||
| 2088 | rdev->config.evergreen.max_backends) & | ||
| 2089 | EVERGREEN_MAX_BACKENDS_MASK)); | ||
| 2090 | break; | ||
| 2091 | } | ||
| 2092 | } else { | ||
| 2093 | switch (rdev->family) { | ||
| 2094 | case CHIP_CYPRESS: | ||
| 2095 | case CHIP_HEMLOCK: | ||
| 2096 | case CHIP_BARTS: | ||
| 2097 | gb_backend_map = 0x66442200; | ||
| 2098 | break; | ||
| 2099 | case CHIP_JUNIPER: | ||
| 2100 | gb_backend_map = 0x00002200; | ||
| 2101 | break; | ||
| 2102 | default: | ||
| 2103 | gb_backend_map = | ||
| 2104 | evergreen_get_tile_pipe_to_backend_map(rdev, | ||
| 2105 | rdev->config.evergreen.max_tile_pipes, | ||
| 2106 | rdev->config.evergreen.max_backends, | ||
| 2107 | ((EVERGREEN_MAX_BACKENDS_MASK << | ||
| 2108 | rdev->config.evergreen.max_backends) & | ||
| 2109 | EVERGREEN_MAX_BACKENDS_MASK)); | ||
| 2110 | } | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | /* setup tiling info dword. gb_addr_config is not adequate since it does | 1834 | /* setup tiling info dword. gb_addr_config is not adequate since it does |
| 2114 | * not have bank info, so create a custom tiling dword. | 1835 | * not have bank info, so create a custom tiling dword. |
| 2115 | * bits 3:0 num_pipes | 1836 | * bits 3:0 num_pipes |
| @@ -2136,45 +1857,54 @@ static void evergreen_gpu_init(struct radeon_device *rdev) | |||
| 2136 | /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ | 1857 | /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ |
| 2137 | if (rdev->flags & RADEON_IS_IGP) | 1858 | if (rdev->flags & RADEON_IS_IGP) |
| 2138 | rdev->config.evergreen.tile_config |= 1 << 4; | 1859 | rdev->config.evergreen.tile_config |= 1 << 4; |
| 2139 | else | 1860 | else { |
| 2140 | rdev->config.evergreen.tile_config |= | 1861 | if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) |
| 2141 | ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; | 1862 | rdev->config.evergreen.tile_config |= 1 << 4; |
| 2142 | rdev->config.evergreen.tile_config |= | 1863 | else |
| 2143 | ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; | 1864 | rdev->config.evergreen.tile_config |= 0 << 4; |
| 1865 | } | ||
| 1866 | rdev->config.evergreen.tile_config |= 0 << 8; | ||
| 2144 | rdev->config.evergreen.tile_config |= | 1867 | rdev->config.evergreen.tile_config |= |
| 2145 | ((gb_addr_config & 0x30000000) >> 28) << 12; | 1868 | ((gb_addr_config & 0x30000000) >> 28) << 12; |
| 2146 | 1869 | ||
| 2147 | rdev->config.evergreen.backend_map = gb_backend_map; | 1870 | num_shader_engines = (gb_addr_config & NUM_SHADER_ENGINES(3) >> 12) + 1; |
| 2148 | WREG32(GB_BACKEND_MAP, gb_backend_map); | ||
| 2149 | WREG32(GB_ADDR_CONFIG, gb_addr_config); | ||
| 2150 | WREG32(DMIF_ADDR_CONFIG, gb_addr_config); | ||
| 2151 | WREG32(HDP_ADDR_CONFIG, gb_addr_config); | ||
| 2152 | |||
| 2153 | num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1; | ||
| 2154 | grbm_gfx_index = INSTANCE_BROADCAST_WRITES; | ||
| 2155 | 1871 | ||
| 2156 | for (i = 0; i < rdev->config.evergreen.num_ses; i++) { | 1872 | if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) { |
| 2157 | u32 rb = cc_rb_backend_disable | (0xf0 << 16); | 1873 | u32 efuse_straps_4; |
| 2158 | u32 sp = cc_gc_shader_pipe_config; | 1874 | u32 efuse_straps_3; |
| 2159 | u32 gfx = grbm_gfx_index | SE_INDEX(i); | ||
| 2160 | 1875 | ||
| 2161 | if (i == num_shader_engines) { | 1876 | WREG32(RCU_IND_INDEX, 0x204); |
| 2162 | rb |= BACKEND_DISABLE(EVERGREEN_MAX_BACKENDS_MASK); | 1877 | efuse_straps_4 = RREG32(RCU_IND_DATA); |
| 2163 | sp |= INACTIVE_SIMDS(EVERGREEN_MAX_SIMDS_MASK); | 1878 | WREG32(RCU_IND_INDEX, 0x203); |
| 1879 | efuse_straps_3 = RREG32(RCU_IND_DATA); | ||
| 1880 | tmp = (((efuse_straps_4 & 0xf) << 4) | | ||
| 1881 | ((efuse_straps_3 & 0xf0000000) >> 28)); | ||
| 1882 | } else { | ||
| 1883 | tmp = 0; | ||
| 1884 | for (i = (rdev->config.evergreen.num_ses - 1); i >= 0; i--) { | ||
| 1885 | u32 rb_disable_bitmap; | ||
| 1886 | |||
| 1887 | WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); | ||
| 1888 | WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); | ||
| 1889 | rb_disable_bitmap = (RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000) >> 16; | ||
| 1890 | tmp <<= 4; | ||
| 1891 | tmp |= rb_disable_bitmap; | ||
| 2164 | } | 1892 | } |
| 1893 | } | ||
| 1894 | /* enabled rb are just the one not disabled :) */ | ||
| 1895 | disabled_rb_mask = tmp; | ||
| 2165 | 1896 | ||
| 2166 | WREG32(GRBM_GFX_INDEX, gfx); | 1897 | WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); |
| 2167 | WREG32(RLC_GFX_INDEX, gfx); | 1898 | WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); |
| 2168 | 1899 | ||
| 2169 | WREG32(CC_RB_BACKEND_DISABLE, rb); | 1900 | WREG32(GB_ADDR_CONFIG, gb_addr_config); |
| 2170 | WREG32(CC_SYS_RB_BACKEND_DISABLE, rb); | 1901 | WREG32(DMIF_ADDR_CONFIG, gb_addr_config); |
| 2171 | WREG32(GC_USER_RB_BACKEND_DISABLE, rb); | 1902 | WREG32(HDP_ADDR_CONFIG, gb_addr_config); |
| 2172 | WREG32(CC_GC_SHADER_PIPE_CONFIG, sp); | ||
| 2173 | } | ||
| 2174 | 1903 | ||
| 2175 | grbm_gfx_index |= SE_BROADCAST_WRITES; | 1904 | tmp = gb_addr_config & NUM_PIPES_MASK; |
| 2176 | WREG32(GRBM_GFX_INDEX, grbm_gfx_index); | 1905 | tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends, |
| 2177 | WREG32(RLC_GFX_INDEX, grbm_gfx_index); | 1906 | EVERGREEN_MAX_BACKENDS, disabled_rb_mask); |
| 1907 | WREG32(GB_BACKEND_MAP, tmp); | ||
| 2178 | 1908 | ||
| 2179 | WREG32(CGTS_SYS_TCC_DISABLE, 0); | 1909 | WREG32(CGTS_SYS_TCC_DISABLE, 0); |
| 2180 | WREG32(CGTS_TCC_DISABLE, 0); | 1910 | WREG32(CGTS_TCC_DISABLE, 0); |
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 79130bfd1d6f..2773039b4902 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h | |||
| @@ -37,6 +37,15 @@ | |||
| 37 | #define EVERGREEN_MAX_PIPES_MASK 0xFF | 37 | #define EVERGREEN_MAX_PIPES_MASK 0xFF |
| 38 | #define EVERGREEN_MAX_LDS_NUM 0xFFFF | 38 | #define EVERGREEN_MAX_LDS_NUM 0xFFFF |
| 39 | 39 | ||
| 40 | #define CYPRESS_GB_ADDR_CONFIG_GOLDEN 0x02011003 | ||
| 41 | #define BARTS_GB_ADDR_CONFIG_GOLDEN 0x02011003 | ||
| 42 | #define CAYMAN_GB_ADDR_CONFIG_GOLDEN 0x02011003 | ||
| 43 | #define JUNIPER_GB_ADDR_CONFIG_GOLDEN 0x02010002 | ||
| 44 | #define REDWOOD_GB_ADDR_CONFIG_GOLDEN 0x02010002 | ||
| 45 | #define TURKS_GB_ADDR_CONFIG_GOLDEN 0x02010002 | ||
| 46 | #define CEDAR_GB_ADDR_CONFIG_GOLDEN 0x02010001 | ||
| 47 | #define CAICOS_GB_ADDR_CONFIG_GOLDEN 0x02010001 | ||
| 48 | |||
| 40 | /* Registers */ | 49 | /* Registers */ |
| 41 | 50 | ||
| 42 | #define RCU_IND_INDEX 0x100 | 51 | #define RCU_IND_INDEX 0x100 |
| @@ -54,6 +63,7 @@ | |||
| 54 | #define BACKEND_DISABLE(x) ((x) << 16) | 63 | #define BACKEND_DISABLE(x) ((x) << 16) |
| 55 | #define GB_ADDR_CONFIG 0x98F8 | 64 | #define GB_ADDR_CONFIG 0x98F8 |
| 56 | #define NUM_PIPES(x) ((x) << 0) | 65 | #define NUM_PIPES(x) ((x) << 0) |
| 66 | #define NUM_PIPES_MASK 0x0000000f | ||
| 57 | #define PIPE_INTERLEAVE_SIZE(x) ((x) << 4) | 67 | #define PIPE_INTERLEAVE_SIZE(x) ((x) << 4) |
| 58 | #define BANK_INTERLEAVE_SIZE(x) ((x) << 8) | 68 | #define BANK_INTERLEAVE_SIZE(x) ((x) << 8) |
| 59 | #define NUM_SHADER_ENGINES(x) ((x) << 12) | 69 | #define NUM_SHADER_ENGINES(x) ((x) << 12) |
| @@ -452,6 +462,7 @@ | |||
| 452 | #define MC_VM_MD_L1_TLB0_CNTL 0x2654 | 462 | #define MC_VM_MD_L1_TLB0_CNTL 0x2654 |
| 453 | #define MC_VM_MD_L1_TLB1_CNTL 0x2658 | 463 | #define MC_VM_MD_L1_TLB1_CNTL 0x2658 |
| 454 | #define MC_VM_MD_L1_TLB2_CNTL 0x265C | 464 | #define MC_VM_MD_L1_TLB2_CNTL 0x265C |
| 465 | #define MC_VM_MD_L1_TLB3_CNTL 0x2698 | ||
| 455 | 466 | ||
| 456 | #define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C | 467 | #define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C |
| 457 | #define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 | 468 | #define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 |
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index ce4e7cc6c905..3df4efa11942 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c | |||
| @@ -417,215 +417,17 @@ out: | |||
| 417 | /* | 417 | /* |
| 418 | * Core functions | 418 | * Core functions |
| 419 | */ | 419 | */ |
| 420 | static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev, | ||
| 421 | u32 num_tile_pipes, | ||
| 422 | u32 num_backends_per_asic, | ||
| 423 | u32 *backend_disable_mask_per_asic, | ||
| 424 | u32 num_shader_engines) | ||
| 425 | { | ||
| 426 | u32 backend_map = 0; | ||
| 427 | u32 enabled_backends_mask = 0; | ||
| 428 | u32 enabled_backends_count = 0; | ||
| 429 | u32 num_backends_per_se; | ||
| 430 | u32 cur_pipe; | ||
| 431 | u32 swizzle_pipe[CAYMAN_MAX_PIPES]; | ||
| 432 | u32 cur_backend = 0; | ||
| 433 | u32 i; | ||
| 434 | bool force_no_swizzle; | ||
| 435 | |||
| 436 | /* force legal values */ | ||
| 437 | if (num_tile_pipes < 1) | ||
| 438 | num_tile_pipes = 1; | ||
| 439 | if (num_tile_pipes > rdev->config.cayman.max_tile_pipes) | ||
| 440 | num_tile_pipes = rdev->config.cayman.max_tile_pipes; | ||
| 441 | if (num_shader_engines < 1) | ||
| 442 | num_shader_engines = 1; | ||
| 443 | if (num_shader_engines > rdev->config.cayman.max_shader_engines) | ||
| 444 | num_shader_engines = rdev->config.cayman.max_shader_engines; | ||
| 445 | if (num_backends_per_asic < num_shader_engines) | ||
| 446 | num_backends_per_asic = num_shader_engines; | ||
| 447 | if (num_backends_per_asic > (rdev->config.cayman.max_backends_per_se * num_shader_engines)) | ||
| 448 | num_backends_per_asic = rdev->config.cayman.max_backends_per_se * num_shader_engines; | ||
| 449 | |||
| 450 | /* make sure we have the same number of backends per se */ | ||
| 451 | num_backends_per_asic = ALIGN(num_backends_per_asic, num_shader_engines); | ||
| 452 | /* set up the number of backends per se */ | ||
| 453 | num_backends_per_se = num_backends_per_asic / num_shader_engines; | ||
| 454 | if (num_backends_per_se > rdev->config.cayman.max_backends_per_se) { | ||
| 455 | num_backends_per_se = rdev->config.cayman.max_backends_per_se; | ||
| 456 | num_backends_per_asic = num_backends_per_se * num_shader_engines; | ||
| 457 | } | ||
| 458 | |||
| 459 | /* create enable mask and count for enabled backends */ | ||
| 460 | for (i = 0; i < CAYMAN_MAX_BACKENDS; ++i) { | ||
| 461 | if (((*backend_disable_mask_per_asic >> i) & 1) == 0) { | ||
| 462 | enabled_backends_mask |= (1 << i); | ||
| 463 | ++enabled_backends_count; | ||
| 464 | } | ||
| 465 | if (enabled_backends_count == num_backends_per_asic) | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* force the backends mask to match the current number of backends */ | ||
| 470 | if (enabled_backends_count != num_backends_per_asic) { | ||
| 471 | u32 this_backend_enabled; | ||
| 472 | u32 shader_engine; | ||
| 473 | u32 backend_per_se; | ||
| 474 | |||
| 475 | enabled_backends_mask = 0; | ||
| 476 | enabled_backends_count = 0; | ||
| 477 | *backend_disable_mask_per_asic = CAYMAN_MAX_BACKENDS_MASK; | ||
| 478 | for (i = 0; i < CAYMAN_MAX_BACKENDS; ++i) { | ||
| 479 | /* calc the current se */ | ||
| 480 | shader_engine = i / rdev->config.cayman.max_backends_per_se; | ||
| 481 | /* calc the backend per se */ | ||
| 482 | backend_per_se = i % rdev->config.cayman.max_backends_per_se; | ||
| 483 | /* default to not enabled */ | ||
| 484 | this_backend_enabled = 0; | ||
| 485 | if ((shader_engine < num_shader_engines) && | ||
| 486 | (backend_per_se < num_backends_per_se)) | ||
| 487 | this_backend_enabled = 1; | ||
| 488 | if (this_backend_enabled) { | ||
| 489 | enabled_backends_mask |= (1 << i); | ||
| 490 | *backend_disable_mask_per_asic &= ~(1 << i); | ||
| 491 | ++enabled_backends_count; | ||
| 492 | } | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * CAYMAN_MAX_PIPES); | ||
| 498 | switch (rdev->family) { | ||
| 499 | case CHIP_CAYMAN: | ||
| 500 | case CHIP_ARUBA: | ||
| 501 | force_no_swizzle = true; | ||
| 502 | break; | ||
| 503 | default: | ||
| 504 | force_no_swizzle = false; | ||
| 505 | break; | ||
| 506 | } | ||
| 507 | if (force_no_swizzle) { | ||
| 508 | bool last_backend_enabled = false; | ||
| 509 | |||
| 510 | force_no_swizzle = false; | ||
| 511 | for (i = 0; i < CAYMAN_MAX_BACKENDS; ++i) { | ||
| 512 | if (((enabled_backends_mask >> i) & 1) == 1) { | ||
| 513 | if (last_backend_enabled) | ||
| 514 | force_no_swizzle = true; | ||
| 515 | last_backend_enabled = true; | ||
| 516 | } else | ||
| 517 | last_backend_enabled = false; | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | switch (num_tile_pipes) { | ||
| 522 | case 1: | ||
| 523 | case 3: | ||
| 524 | case 5: | ||
| 525 | case 7: | ||
| 526 | DRM_ERROR("odd number of pipes!\n"); | ||
| 527 | break; | ||
| 528 | case 2: | ||
| 529 | swizzle_pipe[0] = 0; | ||
| 530 | swizzle_pipe[1] = 1; | ||
| 531 | break; | ||
| 532 | case 4: | ||
| 533 | if (force_no_swizzle) { | ||
| 534 | swizzle_pipe[0] = 0; | ||
| 535 | swizzle_pipe[1] = 1; | ||
| 536 | swizzle_pipe[2] = 2; | ||
| 537 | swizzle_pipe[3] = 3; | ||
| 538 | } else { | ||
| 539 | swizzle_pipe[0] = 0; | ||
| 540 | swizzle_pipe[1] = 2; | ||
| 541 | swizzle_pipe[2] = 1; | ||
| 542 | swizzle_pipe[3] = 3; | ||
| 543 | } | ||
| 544 | break; | ||
| 545 | case 6: | ||
| 546 | if (force_no_swizzle) { | ||
| 547 | swizzle_pipe[0] = 0; | ||
| 548 | swizzle_pipe[1] = 1; | ||
| 549 | swizzle_pipe[2] = 2; | ||
| 550 | swizzle_pipe[3] = 3; | ||
| 551 | swizzle_pipe[4] = 4; | ||
| 552 | swizzle_pipe[5] = 5; | ||
| 553 | } else { | ||
| 554 | swizzle_pipe[0] = 0; | ||
| 555 | swizzle_pipe[1] = 2; | ||
| 556 | swizzle_pipe[2] = 4; | ||
| 557 | swizzle_pipe[3] = 1; | ||
| 558 | swizzle_pipe[4] = 3; | ||
| 559 | swizzle_pipe[5] = 5; | ||
| 560 | } | ||
| 561 | break; | ||
| 562 | case 8: | ||
| 563 | if (force_no_swizzle) { | ||
| 564 | swizzle_pipe[0] = 0; | ||
| 565 | swizzle_pipe[1] = 1; | ||
| 566 | swizzle_pipe[2] = 2; | ||
| 567 | swizzle_pipe[3] = 3; | ||
| 568 | swizzle_pipe[4] = 4; | ||
| 569 | swizzle_pipe[5] = 5; | ||
| 570 | swizzle_pipe[6] = 6; | ||
| 571 | swizzle_pipe[7] = 7; | ||
| 572 | } else { | ||
| 573 | swizzle_pipe[0] = 0; | ||
| 574 | swizzle_pipe[1] = 2; | ||
| 575 | swizzle_pipe[2] = 4; | ||
| 576 | swizzle_pipe[3] = 6; | ||
| 577 | swizzle_pipe[4] = 1; | ||
| 578 | swizzle_pipe[5] = 3; | ||
| 579 | swizzle_pipe[6] = 5; | ||
| 580 | swizzle_pipe[7] = 7; | ||
| 581 | } | ||
| 582 | break; | ||
| 583 | } | ||
| 584 | |||
| 585 | for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { | ||
| 586 | while (((1 << cur_backend) & enabled_backends_mask) == 0) | ||
| 587 | cur_backend = (cur_backend + 1) % CAYMAN_MAX_BACKENDS; | ||
| 588 | |||
| 589 | backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4))); | ||
| 590 | |||
| 591 | cur_backend = (cur_backend + 1) % CAYMAN_MAX_BACKENDS; | ||
| 592 | } | ||
| 593 | |||
| 594 | return backend_map; | ||
| 595 | } | ||
| 596 | |||
| 597 | static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev, | ||
| 598 | u32 disable_mask_per_se, | ||
| 599 | u32 max_disable_mask_per_se, | ||
| 600 | u32 num_shader_engines) | ||
| 601 | { | ||
| 602 | u32 disable_field_width_per_se = r600_count_pipe_bits(disable_mask_per_se); | ||
| 603 | u32 disable_mask_per_asic = disable_mask_per_se & max_disable_mask_per_se; | ||
| 604 | |||
| 605 | if (num_shader_engines == 1) | ||
| 606 | return disable_mask_per_asic; | ||
| 607 | else if (num_shader_engines == 2) | ||
| 608 | return disable_mask_per_asic | (disable_mask_per_asic << disable_field_width_per_se); | ||
| 609 | else | ||
| 610 | return 0xffffffff; | ||
| 611 | } | ||
| 612 | |||
| 613 | static void cayman_gpu_init(struct radeon_device *rdev) | 420 | static void cayman_gpu_init(struct radeon_device *rdev) |
| 614 | { | 421 | { |
| 615 | u32 cc_rb_backend_disable = 0; | ||
| 616 | u32 cc_gc_shader_pipe_config; | ||
| 617 | u32 gb_addr_config = 0; | 422 | u32 gb_addr_config = 0; |
| 618 | u32 mc_shared_chmap, mc_arb_ramcfg; | 423 | u32 mc_shared_chmap, mc_arb_ramcfg; |
| 619 | u32 gb_backend_map; | ||
| 620 | u32 cgts_tcc_disable; | 424 | u32 cgts_tcc_disable; |
| 621 | u32 sx_debug_1; | 425 | u32 sx_debug_1; |
| 622 | u32 smx_dc_ctl0; | 426 | u32 smx_dc_ctl0; |
| 623 | u32 gc_user_shader_pipe_config; | ||
| 624 | u32 gc_user_rb_backend_disable; | ||
| 625 | u32 cgts_user_tcc_disable; | ||
| 626 | u32 cgts_sm_ctrl_reg; | 427 | u32 cgts_sm_ctrl_reg; |
| 627 | u32 hdp_host_path_cntl; | 428 | u32 hdp_host_path_cntl; |
| 628 | u32 tmp; | 429 | u32 tmp; |
| 430 | u32 disabled_rb_mask; | ||
| 629 | int i, j; | 431 | int i, j; |
| 630 | 432 | ||
| 631 | switch (rdev->family) { | 433 | switch (rdev->family) { |
| @@ -650,6 +452,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 650 | rdev->config.cayman.sc_prim_fifo_size = 0x100; | 452 | rdev->config.cayman.sc_prim_fifo_size = 0x100; |
| 651 | rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30; | 453 | rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30; |
| 652 | rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130; | 454 | rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130; |
| 455 | gb_addr_config = CAYMAN_GB_ADDR_CONFIG_GOLDEN; | ||
| 653 | break; | 456 | break; |
| 654 | case CHIP_ARUBA: | 457 | case CHIP_ARUBA: |
| 655 | default: | 458 | default: |
| @@ -687,6 +490,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 687 | rdev->config.cayman.sc_prim_fifo_size = 0x40; | 490 | rdev->config.cayman.sc_prim_fifo_size = 0x40; |
| 688 | rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30; | 491 | rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30; |
| 689 | rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130; | 492 | rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130; |
| 493 | gb_addr_config = ARUBA_GB_ADDR_CONFIG_GOLDEN; | ||
| 690 | break; | 494 | break; |
| 691 | } | 495 | } |
| 692 | 496 | ||
| @@ -706,39 +510,6 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 706 | mc_shared_chmap = RREG32(MC_SHARED_CHMAP); | 510 | mc_shared_chmap = RREG32(MC_SHARED_CHMAP); |
| 707 | mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); | 511 | mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); |
| 708 | 512 | ||
| 709 | cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE); | ||
| 710 | cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); | ||
| 711 | cgts_tcc_disable = 0xffff0000; | ||
| 712 | for (i = 0; i < rdev->config.cayman.max_texture_channel_caches; i++) | ||
| 713 | cgts_tcc_disable &= ~(1 << (16 + i)); | ||
| 714 | gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE); | ||
| 715 | gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG); | ||
| 716 | cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE); | ||
| 717 | |||
| 718 | rdev->config.cayman.num_shader_engines = rdev->config.cayman.max_shader_engines; | ||
| 719 | tmp = ((~gc_user_shader_pipe_config) & INACTIVE_QD_PIPES_MASK) >> INACTIVE_QD_PIPES_SHIFT; | ||
| 720 | rdev->config.cayman.num_shader_pipes_per_simd = r600_count_pipe_bits(tmp); | ||
| 721 | rdev->config.cayman.num_tile_pipes = rdev->config.cayman.max_tile_pipes; | ||
| 722 | tmp = ((~gc_user_shader_pipe_config) & INACTIVE_SIMDS_MASK) >> INACTIVE_SIMDS_SHIFT; | ||
| 723 | rdev->config.cayman.num_simds_per_se = r600_count_pipe_bits(tmp); | ||
| 724 | tmp = ((~gc_user_rb_backend_disable) & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT; | ||
| 725 | rdev->config.cayman.num_backends_per_se = r600_count_pipe_bits(tmp); | ||
| 726 | tmp = (gc_user_rb_backend_disable & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT; | ||
| 727 | rdev->config.cayman.backend_disable_mask_per_asic = | ||
| 728 | cayman_get_disable_mask_per_asic(rdev, tmp, CAYMAN_MAX_BACKENDS_PER_SE_MASK, | ||
| 729 | rdev->config.cayman.num_shader_engines); | ||
| 730 | rdev->config.cayman.backend_map = | ||
| 731 | cayman_get_tile_pipe_to_backend_map(rdev, rdev->config.cayman.num_tile_pipes, | ||
| 732 | rdev->config.cayman.num_backends_per_se * | ||
| 733 | rdev->config.cayman.num_shader_engines, | ||
| 734 | &rdev->config.cayman.backend_disable_mask_per_asic, | ||
| 735 | rdev->config.cayman.num_shader_engines); | ||
| 736 | tmp = ((~cgts_user_tcc_disable) & TCC_DISABLE_MASK) >> TCC_DISABLE_SHIFT; | ||
| 737 | rdev->config.cayman.num_texture_channel_caches = r600_count_pipe_bits(tmp); | ||
| 738 | tmp = (mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT; | ||
| 739 | rdev->config.cayman.mem_max_burst_length_bytes = (tmp + 1) * 256; | ||
| 740 | if (rdev->config.cayman.mem_max_burst_length_bytes > 512) | ||
| 741 | rdev->config.cayman.mem_max_burst_length_bytes = 512; | ||
| 742 | tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT; | 513 | tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT; |
| 743 | rdev->config.cayman.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; | 514 | rdev->config.cayman.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; |
| 744 | if (rdev->config.cayman.mem_row_size_in_kb > 4) | 515 | if (rdev->config.cayman.mem_row_size_in_kb > 4) |
| @@ -748,73 +519,6 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 748 | rdev->config.cayman.num_gpus = 1; | 519 | rdev->config.cayman.num_gpus = 1; |
| 749 | rdev->config.cayman.multi_gpu_tile_size = 64; | 520 | rdev->config.cayman.multi_gpu_tile_size = 64; |
| 750 | 521 | ||
| 751 | //gb_addr_config = 0x02011003 | ||
| 752 | #if 0 | ||
| 753 | gb_addr_config = RREG32(GB_ADDR_CONFIG); | ||
| 754 | #else | ||
| 755 | gb_addr_config = 0; | ||
| 756 | switch (rdev->config.cayman.num_tile_pipes) { | ||
| 757 | case 1: | ||
| 758 | default: | ||
| 759 | gb_addr_config |= NUM_PIPES(0); | ||
| 760 | break; | ||
| 761 | case 2: | ||
| 762 | gb_addr_config |= NUM_PIPES(1); | ||
| 763 | break; | ||
| 764 | case 4: | ||
| 765 | gb_addr_config |= NUM_PIPES(2); | ||
| 766 | break; | ||
| 767 | case 8: | ||
| 768 | gb_addr_config |= NUM_PIPES(3); | ||
| 769 | break; | ||
| 770 | } | ||
| 771 | |||
| 772 | tmp = (rdev->config.cayman.mem_max_burst_length_bytes / 256) - 1; | ||
| 773 | gb_addr_config |= PIPE_INTERLEAVE_SIZE(tmp); | ||
| 774 | gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.cayman.num_shader_engines - 1); | ||
| 775 | tmp = (rdev->config.cayman.shader_engine_tile_size / 16) - 1; | ||
| 776 | gb_addr_config |= SHADER_ENGINE_TILE_SIZE(tmp); | ||
| 777 | switch (rdev->config.cayman.num_gpus) { | ||
| 778 | case 1: | ||
| 779 | default: | ||
| 780 | gb_addr_config |= NUM_GPUS(0); | ||
| 781 | break; | ||
| 782 | case 2: | ||
| 783 | gb_addr_config |= NUM_GPUS(1); | ||
| 784 | break; | ||
| 785 | case 4: | ||
| 786 | gb_addr_config |= NUM_GPUS(2); | ||
| 787 | break; | ||
| 788 | } | ||
| 789 | switch (rdev->config.cayman.multi_gpu_tile_size) { | ||
| 790 | case 16: | ||
| 791 | gb_addr_config |= MULTI_GPU_TILE_SIZE(0); | ||
| 792 | break; | ||
| 793 | case 32: | ||
| 794 | default: | ||
| 795 | gb_addr_config |= MULTI_GPU_TILE_SIZE(1); | ||
| 796 | break; | ||
| 797 | case 64: | ||
| 798 | gb_addr_config |= MULTI_GPU_TILE_SIZE(2); | ||
| 799 | break; | ||
| 800 | case 128: | ||
| 801 | gb_addr_config |= MULTI_GPU_TILE_SIZE(3); | ||
| 802 | break; | ||
| 803 | } | ||
| 804 | switch (rdev->config.cayman.mem_row_size_in_kb) { | ||
| 805 | case 1: | ||
| 806 | default: | ||
| 807 | gb_addr_config |= ROW_SIZE(0); | ||
| 808 | break; | ||
| 809 | case 2: | ||
| 810 | gb_addr_config |= ROW_SIZE(1); | ||
| 811 | break; | ||
| 812 | case 4: | ||
| 813 | gb_addr_config |= ROW_SIZE(2); | ||
| 814 | break; | ||
| 815 | } | ||
| 816 | #endif | ||
| 817 | |||
| 818 | tmp = (gb_addr_config & NUM_PIPES_MASK) >> NUM_PIPES_SHIFT; | 522 | tmp = (gb_addr_config & NUM_PIPES_MASK) >> NUM_PIPES_SHIFT; |
| 819 | rdev->config.cayman.num_tile_pipes = (1 << tmp); | 523 | rdev->config.cayman.num_tile_pipes = (1 << tmp); |
| 820 | tmp = (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT; | 524 | tmp = (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT; |
| @@ -828,17 +532,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 828 | tmp = (gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT; | 532 | tmp = (gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT; |
| 829 | rdev->config.cayman.mem_row_size_in_kb = 1 << tmp; | 533 | rdev->config.cayman.mem_row_size_in_kb = 1 << tmp; |
| 830 | 534 | ||
| 831 | //gb_backend_map = 0x76541032; | 535 | |
| 832 | #if 0 | ||
| 833 | gb_backend_map = RREG32(GB_BACKEND_MAP); | ||
| 834 | #else | ||
| 835 | gb_backend_map = | ||
| 836 | cayman_get_tile_pipe_to_backend_map(rdev, rdev->config.cayman.num_tile_pipes, | ||
| 837 | rdev->config.cayman.num_backends_per_se * | ||
| 838 | rdev->config.cayman.num_shader_engines, | ||
| 839 | &rdev->config.cayman.backend_disable_mask_per_asic, | ||
| 840 | rdev->config.cayman.num_shader_engines); | ||
| 841 | #endif | ||
| 842 | /* setup tiling info dword. gb_addr_config is not adequate since it does | 536 | /* setup tiling info dword. gb_addr_config is not adequate since it does |
| 843 | * not have bank info, so create a custom tiling dword. | 537 | * not have bank info, so create a custom tiling dword. |
| 844 | * bits 3:0 num_pipes | 538 | * bits 3:0 num_pipes |
| @@ -866,33 +560,49 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 866 | /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ | 560 | /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ |
| 867 | if (rdev->flags & RADEON_IS_IGP) | 561 | if (rdev->flags & RADEON_IS_IGP) |
| 868 | rdev->config.cayman.tile_config |= 1 << 4; | 562 | rdev->config.cayman.tile_config |= 1 << 4; |
| 869 | else | 563 | else { |
| 870 | rdev->config.cayman.tile_config |= | 564 | if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) |
| 871 | ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; | 565 | rdev->config.cayman.tile_config |= 1 << 4; |
| 566 | else | ||
| 567 | rdev->config.cayman.tile_config |= 0 << 4; | ||
| 568 | } | ||
| 872 | rdev->config.cayman.tile_config |= | 569 | rdev->config.cayman.tile_config |= |
| 873 | ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; | 570 | ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; |
| 874 | rdev->config.cayman.tile_config |= | 571 | rdev->config.cayman.tile_config |= |
| 875 | ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12; | 572 | ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12; |
| 876 | 573 | ||
| 877 | rdev->config.cayman.backend_map = gb_backend_map; | 574 | tmp = 0; |
| 878 | WREG32(GB_BACKEND_MAP, gb_backend_map); | 575 | for (i = (rdev->config.cayman.max_shader_engines - 1); i >= 0; i--) { |
| 576 | u32 rb_disable_bitmap; | ||
| 577 | |||
| 578 | WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); | ||
| 579 | WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); | ||
| 580 | rb_disable_bitmap = (RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000) >> 16; | ||
| 581 | tmp <<= 4; | ||
| 582 | tmp |= rb_disable_bitmap; | ||
| 583 | } | ||
| 584 | /* enabled rb are just the one not disabled :) */ | ||
| 585 | disabled_rb_mask = tmp; | ||
| 586 | |||
| 587 | WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); | ||
| 588 | WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); | ||
| 589 | |||
| 879 | WREG32(GB_ADDR_CONFIG, gb_addr_config); | 590 | WREG32(GB_ADDR_CONFIG, gb_addr_config); |
| 880 | WREG32(DMIF_ADDR_CONFIG, gb_addr_config); | 591 | WREG32(DMIF_ADDR_CONFIG, gb_addr_config); |
| 881 | WREG32(HDP_ADDR_CONFIG, gb_addr_config); | 592 | WREG32(HDP_ADDR_CONFIG, gb_addr_config); |
| 882 | 593 | ||
| 883 | /* primary versions */ | 594 | tmp = gb_addr_config & NUM_PIPES_MASK; |
| 884 | WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); | 595 | tmp = r6xx_remap_render_backend(rdev, tmp, |
| 885 | WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); | 596 | rdev->config.cayman.max_backends_per_se * |
| 886 | WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); | 597 | rdev->config.cayman.max_shader_engines, |
| 598 | CAYMAN_MAX_BACKENDS, disabled_rb_mask); | ||
| 599 | WREG32(GB_BACKEND_MAP, tmp); | ||
| 887 | 600 | ||
| 601 | cgts_tcc_disable = 0xffff0000; | ||
| 602 | for (i = 0; i < rdev->config.cayman.max_texture_channel_caches; i++) | ||
| 603 | cgts_tcc_disable &= ~(1 << (16 + i)); | ||
| 888 | WREG32(CGTS_TCC_DISABLE, cgts_tcc_disable); | 604 | WREG32(CGTS_TCC_DISABLE, cgts_tcc_disable); |
| 889 | WREG32(CGTS_SYS_TCC_DISABLE, cgts_tcc_disable); | 605 | WREG32(CGTS_SYS_TCC_DISABLE, cgts_tcc_disable); |
| 890 | |||
| 891 | /* user versions */ | ||
| 892 | WREG32(GC_USER_RB_BACKEND_DISABLE, cc_rb_backend_disable); | ||
| 893 | WREG32(GC_USER_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); | ||
| 894 | WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); | ||
| 895 | |||
| 896 | WREG32(CGTS_USER_SYS_TCC_DISABLE, cgts_tcc_disable); | 606 | WREG32(CGTS_USER_SYS_TCC_DISABLE, cgts_tcc_disable); |
| 897 | WREG32(CGTS_USER_TCC_DISABLE, cgts_tcc_disable); | 607 | WREG32(CGTS_USER_TCC_DISABLE, cgts_tcc_disable); |
| 898 | 608 | ||
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 2aa7046ada56..a0b98066e207 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h | |||
| @@ -41,6 +41,9 @@ | |||
| 41 | #define CAYMAN_MAX_TCC 16 | 41 | #define CAYMAN_MAX_TCC 16 |
| 42 | #define CAYMAN_MAX_TCC_MASK 0xFF | 42 | #define CAYMAN_MAX_TCC_MASK 0xFF |
| 43 | 43 | ||
| 44 | #define CAYMAN_GB_ADDR_CONFIG_GOLDEN 0x02011003 | ||
| 45 | #define ARUBA_GB_ADDR_CONFIG_GOLDEN 0x12010001 | ||
| 46 | |||
| 44 | #define DMIF_ADDR_CONFIG 0xBD4 | 47 | #define DMIF_ADDR_CONFIG 0xBD4 |
| 45 | #define SRBM_GFX_CNTL 0x0E44 | 48 | #define SRBM_GFX_CNTL 0x0E44 |
| 46 | #define RINGID(x) (((x) & 0x3) << 0) | 49 | #define RINGID(x) (((x) & 0x3) << 0) |
| @@ -148,6 +151,8 @@ | |||
| 148 | #define CGTS_SYS_TCC_DISABLE 0x3F90 | 151 | #define CGTS_SYS_TCC_DISABLE 0x3F90 |
| 149 | #define CGTS_USER_SYS_TCC_DISABLE 0x3F94 | 152 | #define CGTS_USER_SYS_TCC_DISABLE 0x3F94 |
| 150 | 153 | ||
| 154 | #define RLC_GFX_INDEX 0x3FC4 | ||
| 155 | |||
| 151 | #define CONFIG_MEMSIZE 0x5428 | 156 | #define CONFIG_MEMSIZE 0x5428 |
| 152 | 157 | ||
| 153 | #define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 | 158 | #define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 |
| @@ -212,6 +217,12 @@ | |||
| 212 | #define SOFT_RESET_VGT (1 << 14) | 217 | #define SOFT_RESET_VGT (1 << 14) |
| 213 | #define SOFT_RESET_IA (1 << 15) | 218 | #define SOFT_RESET_IA (1 << 15) |
| 214 | 219 | ||
| 220 | #define GRBM_GFX_INDEX 0x802C | ||
| 221 | #define INSTANCE_INDEX(x) ((x) << 0) | ||
| 222 | #define SE_INDEX(x) ((x) << 16) | ||
| 223 | #define INSTANCE_BROADCAST_WRITES (1 << 30) | ||
| 224 | #define SE_BROADCAST_WRITES (1 << 31) | ||
| 225 | |||
| 215 | #define SCRATCH_REG0 0x8500 | 226 | #define SCRATCH_REG0 0x8500 |
| 216 | #define SCRATCH_REG1 0x8504 | 227 | #define SCRATCH_REG1 0x8504 |
| 217 | #define SCRATCH_REG2 0x8508 | 228 | #define SCRATCH_REG2 0x8508 |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index f388a1d73b63..45cfcea63507 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
| @@ -1376,113 +1376,51 @@ int r600_asic_reset(struct radeon_device *rdev) | |||
| 1376 | return r600_gpu_soft_reset(rdev); | 1376 | return r600_gpu_soft_reset(rdev); |
| 1377 | } | 1377 | } |
| 1378 | 1378 | ||
| 1379 | static u32 r600_get_tile_pipe_to_backend_map(u32 num_tile_pipes, | 1379 | u32 r6xx_remap_render_backend(struct radeon_device *rdev, |
| 1380 | u32 num_backends, | 1380 | u32 tiling_pipe_num, |
| 1381 | u32 backend_disable_mask) | 1381 | u32 max_rb_num, |
| 1382 | { | 1382 | u32 total_max_rb_num, |
| 1383 | u32 backend_map = 0; | 1383 | u32 disabled_rb_mask) |
| 1384 | u32 enabled_backends_mask; | 1384 | { |
| 1385 | u32 enabled_backends_count; | 1385 | u32 rendering_pipe_num, rb_num_width, req_rb_num; |
| 1386 | u32 cur_pipe; | 1386 | u32 pipe_rb_ratio, pipe_rb_remain; |
| 1387 | u32 swizzle_pipe[R6XX_MAX_PIPES]; | 1387 | u32 data = 0, mask = 1 << (max_rb_num - 1); |
| 1388 | u32 cur_backend; | 1388 | unsigned i, j; |
| 1389 | u32 i; | 1389 | |
| 1390 | 1390 | /* mask out the RBs that don't exist on that asic */ | |
| 1391 | if (num_tile_pipes > R6XX_MAX_PIPES) | 1391 | disabled_rb_mask |= (0xff << max_rb_num) & 0xff; |
| 1392 | num_tile_pipes = R6XX_MAX_PIPES; | 1392 | |
| 1393 | if (num_tile_pipes < 1) | 1393 | rendering_pipe_num = 1 << tiling_pipe_num; |
| 1394 | num_tile_pipes = 1; | 1394 | req_rb_num = total_max_rb_num - r600_count_pipe_bits(disabled_rb_mask); |
| 1395 | if (num_backends > R6XX_MAX_BACKENDS) | 1395 | BUG_ON(rendering_pipe_num < req_rb_num); |
| 1396 | num_backends = R6XX_MAX_BACKENDS; | 1396 | |
| 1397 | if (num_backends < 1) | 1397 | pipe_rb_ratio = rendering_pipe_num / req_rb_num; |
| 1398 | num_backends = 1; | 1398 | pipe_rb_remain = rendering_pipe_num - pipe_rb_ratio * req_rb_num; |
| 1399 | 1399 | ||
| 1400 | enabled_backends_mask = 0; | 1400 | if (rdev->family <= CHIP_RV740) { |
| 1401 | enabled_backends_count = 0; | 1401 | /* r6xx/r7xx */ |
| 1402 | for (i = 0; i < R6XX_MAX_BACKENDS; ++i) { | 1402 | rb_num_width = 2; |
| 1403 | if (((backend_disable_mask >> i) & 1) == 0) { | 1403 | } else { |
| 1404 | enabled_backends_mask |= (1 << i); | 1404 | /* eg+ */ |
| 1405 | ++enabled_backends_count; | 1405 | rb_num_width = 4; |
| 1406 | } | ||
| 1407 | if (enabled_backends_count == num_backends) | ||
| 1408 | break; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | if (enabled_backends_count == 0) { | ||
| 1412 | enabled_backends_mask = 1; | ||
| 1413 | enabled_backends_count = 1; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | if (enabled_backends_count != num_backends) | ||
| 1417 | num_backends = enabled_backends_count; | ||
| 1418 | |||
| 1419 | memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R6XX_MAX_PIPES); | ||
| 1420 | switch (num_tile_pipes) { | ||
| 1421 | case 1: | ||
| 1422 | swizzle_pipe[0] = 0; | ||
| 1423 | break; | ||
| 1424 | case 2: | ||
| 1425 | swizzle_pipe[0] = 0; | ||
| 1426 | swizzle_pipe[1] = 1; | ||
| 1427 | break; | ||
| 1428 | case 3: | ||
| 1429 | swizzle_pipe[0] = 0; | ||
| 1430 | swizzle_pipe[1] = 1; | ||
| 1431 | swizzle_pipe[2] = 2; | ||
| 1432 | break; | ||
| 1433 | case 4: | ||
| 1434 | swizzle_pipe[0] = 0; | ||
| 1435 | swizzle_pipe[1] = 1; | ||
| 1436 | swizzle_pipe[2] = 2; | ||
| 1437 | swizzle_pipe[3] = 3; | ||
| 1438 | break; | ||
| 1439 | case 5: | ||
| 1440 | swizzle_pipe[0] = 0; | ||
| 1441 | swizzle_pipe[1] = 1; | ||
| 1442 | swizzle_pipe[2] = 2; | ||
| 1443 | swizzle_pipe[3] = 3; | ||
| 1444 | swizzle_pipe[4] = 4; | ||
| 1445 | break; | ||
| 1446 | case 6: | ||
| 1447 | swizzle_pipe[0] = 0; | ||
| 1448 | swizzle_pipe[1] = 2; | ||
| 1449 | swizzle_pipe[2] = 4; | ||
| 1450 | swizzle_pipe[3] = 5; | ||
| 1451 | swizzle_pipe[4] = 1; | ||
| 1452 | swizzle_pipe[5] = 3; | ||
| 1453 | break; | ||
| 1454 | case 7: | ||
| 1455 | swizzle_pipe[0] = 0; | ||
| 1456 | swizzle_pipe[1] = 2; | ||
| 1457 | swizzle_pipe[2] = 4; | ||
| 1458 | swizzle_pipe[3] = 6; | ||
| 1459 | swizzle_pipe[4] = 1; | ||
| 1460 | swizzle_pipe[5] = 3; | ||
| 1461 | swizzle_pipe[6] = 5; | ||
| 1462 | break; | ||
| 1463 | case 8: | ||
| 1464 | swizzle_pipe[0] = 0; | ||
| 1465 | swizzle_pipe[1] = 2; | ||
| 1466 | swizzle_pipe[2] = 4; | ||
| 1467 | swizzle_pipe[3] = 6; | ||
| 1468 | swizzle_pipe[4] = 1; | ||
| 1469 | swizzle_pipe[5] = 3; | ||
| 1470 | swizzle_pipe[6] = 5; | ||
| 1471 | swizzle_pipe[7] = 7; | ||
| 1472 | break; | ||
| 1473 | } | 1406 | } |
| 1474 | 1407 | ||
| 1475 | cur_backend = 0; | 1408 | for (i = 0; i < max_rb_num; i++) { |
| 1476 | for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { | 1409 | if (!(mask & disabled_rb_mask)) { |
| 1477 | while (((1 << cur_backend) & enabled_backends_mask) == 0) | 1410 | for (j = 0; j < pipe_rb_ratio; j++) { |
| 1478 | cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS; | 1411 | data <<= rb_num_width; |
| 1479 | 1412 | data |= max_rb_num - i - 1; | |
| 1480 | backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2))); | 1413 | } |
| 1481 | 1414 | if (pipe_rb_remain) { | |
| 1482 | cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS; | 1415 | data <<= rb_num_width; |
| 1416 | data |= max_rb_num - i - 1; | ||
| 1417 | pipe_rb_remain--; | ||
| 1418 | } | ||
| 1419 | } | ||
| 1420 | mask >>= 1; | ||
| 1483 | } | 1421 | } |
| 1484 | 1422 | ||
| 1485 | return backend_map; | 1423 | return data; |
| 1486 | } | 1424 | } |
| 1487 | 1425 | ||
| 1488 | int r600_count_pipe_bits(uint32_t val) | 1426 | int r600_count_pipe_bits(uint32_t val) |
| @@ -1500,7 +1438,6 @@ void r600_gpu_init(struct radeon_device *rdev) | |||
| 1500 | { | 1438 | { |
| 1501 | u32 tiling_config; | 1439 | u32 tiling_config; |
| 1502 | u32 ramcfg; | 1440 | u32 ramcfg; |
| 1503 | u32 backend_map; | ||
| 1504 | u32 cc_rb_backend_disable; | 1441 | u32 cc_rb_backend_disable; |
| 1505 | u32 cc_gc_shader_pipe_config; | 1442 | u32 cc_gc_shader_pipe_config; |
| 1506 | u32 tmp; | 1443 | u32 tmp; |
| @@ -1511,8 +1448,9 @@ void r600_gpu_init(struct radeon_device *rdev) | |||
| 1511 | u32 sq_thread_resource_mgmt = 0; | 1448 | u32 sq_thread_resource_mgmt = 0; |
| 1512 | u32 sq_stack_resource_mgmt_1 = 0; | 1449 | u32 sq_stack_resource_mgmt_1 = 0; |
| 1513 | u32 sq_stack_resource_mgmt_2 = 0; | 1450 | u32 sq_stack_resource_mgmt_2 = 0; |
| 1451 | u32 disabled_rb_mask; | ||
| 1514 | 1452 | ||
| 1515 | /* FIXME: implement */ | 1453 | rdev->config.r600.tiling_group_size = 256; |
| 1516 | switch (rdev->family) { | 1454 | switch (rdev->family) { |
| 1517 | case CHIP_R600: | 1455 | case CHIP_R600: |
| 1518 | rdev->config.r600.max_pipes = 4; | 1456 | rdev->config.r600.max_pipes = 4; |
| @@ -1616,10 +1554,7 @@ void r600_gpu_init(struct radeon_device *rdev) | |||
| 1616 | rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); | 1554 | rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); |
| 1617 | tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); | 1555 | tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); |
| 1618 | tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); | 1556 | tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); |
| 1619 | if ((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) | 1557 | |
| 1620 | rdev->config.r600.tiling_group_size = 512; | ||
| 1621 | else | ||
| 1622 | rdev->config.r600.tiling_group_size = 256; | ||
| 1623 | tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT; | 1558 | tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT; |
| 1624 | if (tmp > 3) { | 1559 | if (tmp > 3) { |
| 1625 | tiling_config |= ROW_TILING(3); | 1560 | tiling_config |= ROW_TILING(3); |
| @@ -1631,32 +1566,36 @@ void r600_gpu_init(struct radeon_device *rdev) | |||
| 1631 | tiling_config |= BANK_SWAPS(1); | 1566 | tiling_config |= BANK_SWAPS(1); |
| 1632 | 1567 | ||
| 1633 | cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; | 1568 | cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; |
| 1634 | cc_rb_backend_disable |= | 1569 | tmp = R6XX_MAX_BACKENDS - |
| 1635 | BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK); | 1570 | r600_count_pipe_bits((cc_rb_backend_disable >> 16) & R6XX_MAX_BACKENDS_MASK); |
| 1636 | 1571 | if (tmp < rdev->config.r600.max_backends) { | |
| 1637 | cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; | 1572 | rdev->config.r600.max_backends = tmp; |
| 1638 | cc_gc_shader_pipe_config |= | 1573 | } |
| 1639 | INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK); | 1574 | |
| 1640 | cc_gc_shader_pipe_config |= | 1575 | cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0x00ffff00; |
| 1641 | INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK); | 1576 | tmp = R6XX_MAX_PIPES - |
| 1642 | 1577 | r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R6XX_MAX_PIPES_MASK); | |
| 1643 | backend_map = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes, | 1578 | if (tmp < rdev->config.r600.max_pipes) { |
| 1644 | (R6XX_MAX_BACKENDS - | 1579 | rdev->config.r600.max_pipes = tmp; |
| 1645 | r600_count_pipe_bits((cc_rb_backend_disable & | 1580 | } |
| 1646 | R6XX_MAX_BACKENDS_MASK) >> 16)), | 1581 | tmp = R6XX_MAX_SIMDS - |
| 1647 | (cc_rb_backend_disable >> 16)); | 1582 | r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK); |
| 1583 | if (tmp < rdev->config.r600.max_simds) { | ||
| 1584 | rdev->config.r600.max_simds = tmp; | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R6XX_MAX_BACKENDS_MASK; | ||
| 1588 | tmp = (tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; | ||
| 1589 | tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.r600.max_backends, | ||
| 1590 | R6XX_MAX_BACKENDS, disabled_rb_mask); | ||
| 1591 | tiling_config |= tmp << 16; | ||
| 1592 | rdev->config.r600.backend_map = tmp; | ||
| 1593 | |||
| 1648 | rdev->config.r600.tile_config = tiling_config; | 1594 | rdev->config.r600.tile_config = tiling_config; |
| 1649 | rdev->config.r600.backend_map = backend_map; | ||
| 1650 | tiling_config |= BACKEND_MAP(backend_map); | ||
| 1651 | WREG32(GB_TILING_CONFIG, tiling_config); | 1595 | WREG32(GB_TILING_CONFIG, tiling_config); |
| 1652 | WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); | 1596 | WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); |
| 1653 | WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff); | 1597 | WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff); |
| 1654 | 1598 | ||
| 1655 | /* Setup pipes */ | ||
| 1656 | WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); | ||
| 1657 | WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); | ||
| 1658 | WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); | ||
| 1659 | |||
| 1660 | tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); | 1599 | tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); |
| 1661 | WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); | 1600 | WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); |
| 1662 | WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK); | 1601 | WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK); |
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 15bd3b216243..a0dbf1fe6a40 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h | |||
| @@ -219,6 +219,8 @@ | |||
| 219 | #define BACKEND_MAP(x) ((x) << 16) | 219 | #define BACKEND_MAP(x) ((x) << 16) |
| 220 | 220 | ||
| 221 | #define GB_TILING_CONFIG 0x98F0 | 221 | #define GB_TILING_CONFIG 0x98F0 |
| 222 | #define PIPE_TILING__SHIFT 1 | ||
| 223 | #define PIPE_TILING__MASK 0x0000000e | ||
| 222 | 224 | ||
| 223 | #define GC_USER_SHADER_PIPE_CONFIG 0x8954 | 225 | #define GC_USER_SHADER_PIPE_CONFIG 0x8954 |
| 224 | #define INACTIVE_QD_PIPES(x) ((x) << 8) | 226 | #define INACTIVE_QD_PIPES(x) ((x) << 8) |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 492654f8ee74..85dac33e3cce 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
| @@ -346,6 +346,9 @@ struct radeon_bo { | |||
| 346 | /* Constant after initialization */ | 346 | /* Constant after initialization */ |
| 347 | struct radeon_device *rdev; | 347 | struct radeon_device *rdev; |
| 348 | struct drm_gem_object gem_base; | 348 | struct drm_gem_object gem_base; |
| 349 | |||
| 350 | struct ttm_bo_kmap_obj dma_buf_vmap; | ||
| 351 | int vmapping_count; | ||
| 349 | }; | 352 | }; |
| 350 | #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) | 353 | #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) |
| 351 | 354 | ||
| @@ -1845,6 +1848,11 @@ extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock); | |||
| 1845 | extern void r600_hdmi_enable(struct drm_encoder *encoder); | 1848 | extern void r600_hdmi_enable(struct drm_encoder *encoder); |
| 1846 | extern void r600_hdmi_disable(struct drm_encoder *encoder); | 1849 | extern void r600_hdmi_disable(struct drm_encoder *encoder); |
| 1847 | extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); | 1850 | extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); |
| 1851 | extern u32 r6xx_remap_render_backend(struct radeon_device *rdev, | ||
| 1852 | u32 tiling_pipe_num, | ||
| 1853 | u32 max_rb_num, | ||
| 1854 | u32 total_max_rb_num, | ||
| 1855 | u32 enabled_rb_mask); | ||
| 1848 | 1856 | ||
| 1849 | /* | 1857 | /* |
| 1850 | * evergreen functions used by radeon_encoder.c | 1858 | * evergreen functions used by radeon_encoder.c |
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 0137689ed461..142f89462aa4 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
| @@ -147,6 +147,7 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p) | |||
| 147 | sync_to_ring, p->ring); | 147 | sync_to_ring, p->ring); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | /* XXX: note that this is called from the legacy UMS CS ioctl as well */ | ||
| 150 | int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) | 151 | int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) |
| 151 | { | 152 | { |
| 152 | struct drm_radeon_cs *cs = data; | 153 | struct drm_radeon_cs *cs = data; |
| @@ -245,22 +246,24 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) | |||
| 245 | } | 246 | } |
| 246 | } | 247 | } |
| 247 | 248 | ||
| 248 | if ((p->cs_flags & RADEON_CS_USE_VM) && | 249 | /* these are KMS only */ |
| 249 | !p->rdev->vm_manager.enabled) { | 250 | if (p->rdev) { |
| 250 | DRM_ERROR("VM not active on asic!\n"); | 251 | if ((p->cs_flags & RADEON_CS_USE_VM) && |
| 251 | return -EINVAL; | 252 | !p->rdev->vm_manager.enabled) { |
| 252 | } | 253 | DRM_ERROR("VM not active on asic!\n"); |
| 253 | 254 | return -EINVAL; | |
| 254 | /* we only support VM on SI+ */ | 255 | } |
| 255 | if ((p->rdev->family >= CHIP_TAHITI) && | ||
| 256 | ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { | ||
| 257 | DRM_ERROR("VM required on SI+!\n"); | ||
| 258 | return -EINVAL; | ||
| 259 | } | ||
| 260 | 256 | ||
| 261 | if (radeon_cs_get_ring(p, ring, priority)) | 257 | /* we only support VM on SI+ */ |
| 262 | return -EINVAL; | 258 | if ((p->rdev->family >= CHIP_TAHITI) && |
| 259 | ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { | ||
| 260 | DRM_ERROR("VM required on SI+!\n"); | ||
| 261 | return -EINVAL; | ||
| 262 | } | ||
| 263 | 263 | ||
| 264 | if (radeon_cs_get_ring(p, ring, priority)) | ||
| 265 | return -EINVAL; | ||
| 266 | } | ||
| 264 | 267 | ||
| 265 | /* deal with non-vm */ | 268 | /* deal with non-vm */ |
| 266 | if ((p->chunk_ib_idx != -1) && | 269 | if ((p->chunk_ib_idx != -1) && |
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c index b8f835d8ecb4..8ddab4c76710 100644 --- a/drivers/gpu/drm/radeon/radeon_prime.c +++ b/drivers/gpu/drm/radeon/radeon_prime.c | |||
| @@ -85,6 +85,47 @@ static void radeon_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, v | |||
| 85 | 85 | ||
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static int radeon_gem_prime_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) | ||
| 89 | { | ||
| 90 | return -EINVAL; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void *radeon_gem_prime_vmap(struct dma_buf *dma_buf) | ||
| 94 | { | ||
| 95 | struct radeon_bo *bo = dma_buf->priv; | ||
| 96 | struct drm_device *dev = bo->rdev->ddev; | ||
| 97 | int ret; | ||
| 98 | |||
| 99 | mutex_lock(&dev->struct_mutex); | ||
| 100 | if (bo->vmapping_count) { | ||
| 101 | bo->vmapping_count++; | ||
| 102 | goto out_unlock; | ||
| 103 | } | ||
| 104 | |||
| 105 | ret = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, | ||
| 106 | &bo->dma_buf_vmap); | ||
| 107 | if (ret) { | ||
| 108 | mutex_unlock(&dev->struct_mutex); | ||
| 109 | return ERR_PTR(ret); | ||
| 110 | } | ||
| 111 | bo->vmapping_count = 1; | ||
| 112 | out_unlock: | ||
| 113 | mutex_unlock(&dev->struct_mutex); | ||
| 114 | return bo->dma_buf_vmap.virtual; | ||
| 115 | } | ||
| 116 | |||
| 117 | static void radeon_gem_prime_vunmap(struct dma_buf *dma_buf, void *vaddr) | ||
| 118 | { | ||
| 119 | struct radeon_bo *bo = dma_buf->priv; | ||
| 120 | struct drm_device *dev = bo->rdev->ddev; | ||
| 121 | |||
| 122 | mutex_lock(&dev->struct_mutex); | ||
| 123 | bo->vmapping_count--; | ||
| 124 | if (bo->vmapping_count == 0) { | ||
| 125 | ttm_bo_kunmap(&bo->dma_buf_vmap); | ||
| 126 | } | ||
| 127 | mutex_unlock(&dev->struct_mutex); | ||
| 128 | } | ||
| 88 | const static struct dma_buf_ops radeon_dmabuf_ops = { | 129 | const static struct dma_buf_ops radeon_dmabuf_ops = { |
| 89 | .map_dma_buf = radeon_gem_map_dma_buf, | 130 | .map_dma_buf = radeon_gem_map_dma_buf, |
| 90 | .unmap_dma_buf = radeon_gem_unmap_dma_buf, | 131 | .unmap_dma_buf = radeon_gem_unmap_dma_buf, |
| @@ -93,6 +134,9 @@ const static struct dma_buf_ops radeon_dmabuf_ops = { | |||
| 93 | .kmap_atomic = radeon_gem_kmap_atomic, | 134 | .kmap_atomic = radeon_gem_kmap_atomic, |
| 94 | .kunmap = radeon_gem_kunmap, | 135 | .kunmap = radeon_gem_kunmap, |
| 95 | .kunmap_atomic = radeon_gem_kunmap_atomic, | 136 | .kunmap_atomic = radeon_gem_kunmap_atomic, |
| 137 | .mmap = radeon_gem_prime_mmap, | ||
| 138 | .vmap = radeon_gem_prime_vmap, | ||
| 139 | .vunmap = radeon_gem_prime_vunmap, | ||
| 96 | }; | 140 | }; |
| 97 | 141 | ||
| 98 | static int radeon_prime_create(struct drm_device *dev, | 142 | static int radeon_prime_create(struct drm_device *dev, |
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index c2f473bc13b8..04ddc365a908 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c | |||
| @@ -151,6 +151,8 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) | |||
| 151 | WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); | 151 | WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); |
| 152 | WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); | 152 | WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); |
| 153 | WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); | 153 | WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); |
| 154 | if (rdev->family == CHIP_RV740) | ||
| 155 | WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp); | ||
| 154 | WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); | 156 | WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); |
| 155 | WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); | 157 | WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); |
| 156 | WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); | 158 | WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); |
| @@ -363,180 +365,6 @@ void r700_cp_fini(struct radeon_device *rdev) | |||
| 363 | /* | 365 | /* |
| 364 | * Core functions | 366 | * Core functions |
| 365 | */ | 367 | */ |
| 366 | static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev, | ||
| 367 | u32 num_tile_pipes, | ||
| 368 | u32 num_backends, | ||
| 369 | u32 backend_disable_mask) | ||
| 370 | { | ||
| 371 | u32 backend_map = 0; | ||
| 372 | u32 enabled_backends_mask; | ||
| 373 | u32 enabled_backends_count; | ||
| 374 | u32 cur_pipe; | ||
| 375 | u32 swizzle_pipe[R7XX_MAX_PIPES]; | ||
| 376 | u32 cur_backend; | ||
| 377 | u32 i; | ||
| 378 | bool force_no_swizzle; | ||
| 379 | |||
| 380 | if (num_tile_pipes > R7XX_MAX_PIPES) | ||
| 381 | num_tile_pipes = R7XX_MAX_PIPES; | ||
| 382 | if (num_tile_pipes < 1) | ||
| 383 | num_tile_pipes = 1; | ||
| 384 | if (num_backends > R7XX_MAX_BACKENDS) | ||
| 385 | num_backends = R7XX_MAX_BACKENDS; | ||
| 386 | if (num_backends < 1) | ||
| 387 | num_backends = 1; | ||
| 388 | |||
| 389 | enabled_backends_mask = 0; | ||
| 390 | enabled_backends_count = 0; | ||
| 391 | for (i = 0; i < R7XX_MAX_BACKENDS; ++i) { | ||
| 392 | if (((backend_disable_mask >> i) & 1) == 0) { | ||
| 393 | enabled_backends_mask |= (1 << i); | ||
| 394 | ++enabled_backends_count; | ||
| 395 | } | ||
| 396 | if (enabled_backends_count == num_backends) | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | |||
| 400 | if (enabled_backends_count == 0) { | ||
| 401 | enabled_backends_mask = 1; | ||
| 402 | enabled_backends_count = 1; | ||
| 403 | } | ||
| 404 | |||
| 405 | if (enabled_backends_count != num_backends) | ||
| 406 | num_backends = enabled_backends_count; | ||
| 407 | |||
| 408 | switch (rdev->family) { | ||
| 409 | case CHIP_RV770: | ||
| 410 | case CHIP_RV730: | ||
| 411 | force_no_swizzle = false; | ||
| 412 | break; | ||
| 413 | case CHIP_RV710: | ||
| 414 | case CHIP_RV740: | ||
| 415 | default: | ||
| 416 | force_no_swizzle = true; | ||
| 417 | break; | ||
| 418 | } | ||
| 419 | |||
| 420 | memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES); | ||
| 421 | switch (num_tile_pipes) { | ||
| 422 | case 1: | ||
| 423 | swizzle_pipe[0] = 0; | ||
| 424 | break; | ||
| 425 | case 2: | ||
| 426 | swizzle_pipe[0] = 0; | ||
| 427 | swizzle_pipe[1] = 1; | ||
| 428 | break; | ||
| 429 | case 3: | ||
| 430 | if (force_no_swizzle) { | ||
| 431 | swizzle_pipe[0] = 0; | ||
| 432 | swizzle_pipe[1] = 1; | ||
| 433 | swizzle_pipe[2] = 2; | ||
| 434 | } else { | ||
| 435 | swizzle_pipe[0] = 0; | ||
| 436 | swizzle_pipe[1] = 2; | ||
| 437 | swizzle_pipe[2] = 1; | ||
| 438 | } | ||
| 439 | break; | ||
| 440 | case 4: | ||
| 441 | if (force_no_swizzle) { | ||
| 442 | swizzle_pipe[0] = 0; | ||
| 443 | swizzle_pipe[1] = 1; | ||
| 444 | swizzle_pipe[2] = 2; | ||
| 445 | swizzle_pipe[3] = 3; | ||
| 446 | } else { | ||
| 447 | swizzle_pipe[0] = 0; | ||
| 448 | swizzle_pipe[1] = 2; | ||
| 449 | swizzle_pipe[2] = 3; | ||
| 450 | swizzle_pipe[3] = 1; | ||
| 451 | } | ||
| 452 | break; | ||
| 453 | case 5: | ||
| 454 | if (force_no_swizzle) { | ||
| 455 | swizzle_pipe[0] = 0; | ||
| 456 | swizzle_pipe[1] = 1; | ||
| 457 | swizzle_pipe[2] = 2; | ||
| 458 | swizzle_pipe[3] = 3; | ||
| 459 | swizzle_pipe[4] = 4; | ||
| 460 | } else { | ||
| 461 | swizzle_pipe[0] = 0; | ||
| 462 | swizzle_pipe[1] = 2; | ||
| 463 | swizzle_pipe[2] = 4; | ||
| 464 | swizzle_pipe[3] = 1; | ||
| 465 | swizzle_pipe[4] = 3; | ||
| 466 | } | ||
| 467 | break; | ||
| 468 | case 6: | ||
| 469 | if (force_no_swizzle) { | ||
| 470 | swizzle_pipe[0] = 0; | ||
| 471 | swizzle_pipe[1] = 1; | ||
| 472 | swizzle_pipe[2] = 2; | ||
| 473 | swizzle_pipe[3] = 3; | ||
| 474 | swizzle_pipe[4] = 4; | ||
| 475 | swizzle_pipe[5] = 5; | ||
| 476 | } else { | ||
| 477 | swizzle_pipe[0] = 0; | ||
| 478 | swizzle_pipe[1] = 2; | ||
| 479 | swizzle_pipe[2] = 4; | ||
| 480 | swizzle_pipe[3] = 5; | ||
| 481 | swizzle_pipe[4] = 3; | ||
| 482 | swizzle_pipe[5] = 1; | ||
| 483 | } | ||
| 484 | break; | ||
| 485 | case 7: | ||
| 486 | if (force_no_swizzle) { | ||
| 487 | swizzle_pipe[0] = 0; | ||
| 488 | swizzle_pipe[1] = 1; | ||
| 489 | swizzle_pipe[2] = 2; | ||
| 490 | swizzle_pipe[3] = 3; | ||
| 491 | swizzle_pipe[4] = 4; | ||
| 492 | swizzle_pipe[5] = 5; | ||
| 493 | swizzle_pipe[6] = 6; | ||
| 494 | } else { | ||
| 495 | swizzle_pipe[0] = 0; | ||
| 496 | swizzle_pipe[1] = 2; | ||
| 497 | swizzle_pipe[2] = 4; | ||
| 498 | swizzle_pipe[3] = 6; | ||
| 499 | swizzle_pipe[4] = 3; | ||
| 500 | swizzle_pipe[5] = 1; | ||
| 501 | swizzle_pipe[6] = 5; | ||
| 502 | } | ||
| 503 | break; | ||
| 504 | case 8: | ||
| 505 | if (force_no_swizzle) { | ||
| 506 | swizzle_pipe[0] = 0; | ||
| 507 | swizzle_pipe[1] = 1; | ||
| 508 | swizzle_pipe[2] = 2; | ||
| 509 | swizzle_pipe[3] = 3; | ||
| 510 | swizzle_pipe[4] = 4; | ||
| 511 | swizzle_pipe[5] = 5; | ||
| 512 | swizzle_pipe[6] = 6; | ||
| 513 | swizzle_pipe[7] = 7; | ||
| 514 | } else { | ||
| 515 | swizzle_pipe[0] = 0; | ||
| 516 | swizzle_pipe[1] = 2; | ||
| 517 | swizzle_pipe[2] = 4; | ||
| 518 | swizzle_pipe[3] = 6; | ||
| 519 | swizzle_pipe[4] = 3; | ||
| 520 | swizzle_pipe[5] = 1; | ||
| 521 | swizzle_pipe[6] = 7; | ||
| 522 | swizzle_pipe[7] = 5; | ||
| 523 | } | ||
| 524 | break; | ||
| 525 | } | ||
| 526 | |||
| 527 | cur_backend = 0; | ||
| 528 | for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { | ||
| 529 | while (((1 << cur_backend) & enabled_backends_mask) == 0) | ||
| 530 | cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS; | ||
| 531 | |||
| 532 | backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2))); | ||
| 533 | |||
| 534 | cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS; | ||
| 535 | } | ||
| 536 | |||
| 537 | return backend_map; | ||
| 538 | } | ||
| 539 | |||
| 540 | static void rv770_gpu_init(struct radeon_device *rdev) | 368 | static void rv770_gpu_init(struct radeon_device *rdev) |
| 541 | { | 369 | { |
| 542 | int i, j, num_qd_pipes; | 370 | int i, j, num_qd_pipes; |
| @@ -552,14 +380,17 @@ static void rv770_gpu_init(struct radeon_device *rdev) | |||
| 552 | u32 sq_thread_resource_mgmt; | 380 | u32 sq_thread_resource_mgmt; |
| 553 | u32 hdp_host_path_cntl; | 381 | u32 hdp_host_path_cntl; |
| 554 | u32 sq_dyn_gpr_size_simd_ab_0; | 382 | u32 sq_dyn_gpr_size_simd_ab_0; |
| 555 | u32 backend_map; | ||
| 556 | u32 gb_tiling_config = 0; | 383 | u32 gb_tiling_config = 0; |
| 557 | u32 cc_rb_backend_disable = 0; | 384 | u32 cc_rb_backend_disable = 0; |
| 558 | u32 cc_gc_shader_pipe_config = 0; | 385 | u32 cc_gc_shader_pipe_config = 0; |
| 559 | u32 mc_arb_ramcfg; | 386 | u32 mc_arb_ramcfg; |
| 560 | u32 db_debug4; | 387 | u32 db_debug4, tmp; |
| 388 | u32 inactive_pipes, shader_pipe_config; | ||
| 389 | u32 disabled_rb_mask; | ||
| 390 | unsigned active_number; | ||
| 561 | 391 | ||
| 562 | /* setup chip specs */ | 392 | /* setup chip specs */ |
| 393 | rdev->config.rv770.tiling_group_size = 256; | ||
| 563 | switch (rdev->family) { | 394 | switch (rdev->family) { |
| 564 | case CHIP_RV770: | 395 | case CHIP_RV770: |
| 565 | rdev->config.rv770.max_pipes = 4; | 396 | rdev->config.rv770.max_pipes = 4; |
| @@ -670,33 +501,70 @@ static void rv770_gpu_init(struct radeon_device *rdev) | |||
| 670 | /* setup tiling, simd, pipe config */ | 501 | /* setup tiling, simd, pipe config */ |
| 671 | mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); | 502 | mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); |
| 672 | 503 | ||
| 504 | shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); | ||
| 505 | inactive_pipes = (shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> INACTIVE_QD_PIPES_SHIFT; | ||
| 506 | for (i = 0, tmp = 1, active_number = 0; i < R7XX_MAX_PIPES; i++) { | ||
| 507 | if (!(inactive_pipes & tmp)) { | ||
| 508 | active_number++; | ||
| 509 | } | ||
| 510 | tmp <<= 1; | ||
| 511 | } | ||
| 512 | if (active_number == 1) { | ||
| 513 | WREG32(SPI_CONFIG_CNTL, DISABLE_INTERP_1); | ||
| 514 | } else { | ||
| 515 | WREG32(SPI_CONFIG_CNTL, 0); | ||
| 516 | } | ||
| 517 | |||
| 518 | cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; | ||
| 519 | tmp = R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_rb_backend_disable >> 16); | ||
| 520 | if (tmp < rdev->config.rv770.max_backends) { | ||
| 521 | rdev->config.rv770.max_backends = tmp; | ||
| 522 | } | ||
| 523 | |||
| 524 | cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; | ||
| 525 | tmp = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R7XX_MAX_PIPES_MASK); | ||
| 526 | if (tmp < rdev->config.rv770.max_pipes) { | ||
| 527 | rdev->config.rv770.max_pipes = tmp; | ||
| 528 | } | ||
| 529 | tmp = R7XX_MAX_SIMDS - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK); | ||
| 530 | if (tmp < rdev->config.rv770.max_simds) { | ||
| 531 | rdev->config.rv770.max_simds = tmp; | ||
| 532 | } | ||
| 533 | |||
| 673 | switch (rdev->config.rv770.max_tile_pipes) { | 534 | switch (rdev->config.rv770.max_tile_pipes) { |
| 674 | case 1: | 535 | case 1: |
| 675 | default: | 536 | default: |
| 676 | gb_tiling_config |= PIPE_TILING(0); | 537 | gb_tiling_config = PIPE_TILING(0); |
| 677 | break; | 538 | break; |
| 678 | case 2: | 539 | case 2: |
| 679 | gb_tiling_config |= PIPE_TILING(1); | 540 | gb_tiling_config = PIPE_TILING(1); |
| 680 | break; | 541 | break; |
| 681 | case 4: | 542 | case 4: |
| 682 | gb_tiling_config |= PIPE_TILING(2); | 543 | gb_tiling_config = PIPE_TILING(2); |
| 683 | break; | 544 | break; |
| 684 | case 8: | 545 | case 8: |
| 685 | gb_tiling_config |= PIPE_TILING(3); | 546 | gb_tiling_config = PIPE_TILING(3); |
| 686 | break; | 547 | break; |
| 687 | } | 548 | } |
| 688 | rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes; | 549 | rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes; |
| 689 | 550 | ||
| 551 | disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R7XX_MAX_BACKENDS_MASK; | ||
| 552 | tmp = (gb_tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; | ||
| 553 | tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.rv770.max_backends, | ||
| 554 | R7XX_MAX_BACKENDS, disabled_rb_mask); | ||
| 555 | gb_tiling_config |= tmp << 16; | ||
| 556 | rdev->config.rv770.backend_map = tmp; | ||
| 557 | |||
| 690 | if (rdev->family == CHIP_RV770) | 558 | if (rdev->family == CHIP_RV770) |
| 691 | gb_tiling_config |= BANK_TILING(1); | 559 | gb_tiling_config |= BANK_TILING(1); |
| 692 | else | 560 | else { |
| 693 | gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); | 561 | if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) |
| 562 | gb_tiling_config |= BANK_TILING(1); | ||
| 563 | else | ||
| 564 | gb_tiling_config |= BANK_TILING(0); | ||
| 565 | } | ||
| 694 | rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3); | 566 | rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3); |
| 695 | gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); | 567 | gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); |
| 696 | if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) | ||
| 697 | rdev->config.rv770.tiling_group_size = 512; | ||
| 698 | else | ||
| 699 | rdev->config.rv770.tiling_group_size = 256; | ||
| 700 | if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) { | 568 | if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) { |
| 701 | gb_tiling_config |= ROW_TILING(3); | 569 | gb_tiling_config |= ROW_TILING(3); |
| 702 | gb_tiling_config |= SAMPLE_SPLIT(3); | 570 | gb_tiling_config |= SAMPLE_SPLIT(3); |
| @@ -708,47 +576,19 @@ static void rv770_gpu_init(struct radeon_device *rdev) | |||
| 708 | } | 576 | } |
| 709 | 577 | ||
| 710 | gb_tiling_config |= BANK_SWAPS(1); | 578 | gb_tiling_config |= BANK_SWAPS(1); |
| 711 | |||
| 712 | cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; | ||
| 713 | cc_rb_backend_disable |= | ||
| 714 | BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << rdev->config.rv770.max_backends) & R7XX_MAX_BACKENDS_MASK); | ||
| 715 | |||
| 716 | cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; | ||
| 717 | cc_gc_shader_pipe_config |= | ||
| 718 | INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << rdev->config.rv770.max_pipes) & R7XX_MAX_PIPES_MASK); | ||
| 719 | cc_gc_shader_pipe_config |= | ||
| 720 | INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << rdev->config.rv770.max_simds) & R7XX_MAX_SIMDS_MASK); | ||
| 721 | |||
| 722 | if (rdev->family == CHIP_RV740) | ||
| 723 | backend_map = 0x28; | ||
| 724 | else | ||
| 725 | backend_map = r700_get_tile_pipe_to_backend_map(rdev, | ||
| 726 | rdev->config.rv770.max_tile_pipes, | ||
| 727 | (R7XX_MAX_BACKENDS - | ||
| 728 | r600_count_pipe_bits((cc_rb_backend_disable & | ||
| 729 | R7XX_MAX_BACKENDS_MASK) >> 16)), | ||
| 730 | (cc_rb_backend_disable >> 16)); | ||
| 731 | |||
| 732 | rdev->config.rv770.tile_config = gb_tiling_config; | 579 | rdev->config.rv770.tile_config = gb_tiling_config; |
| 733 | rdev->config.rv770.backend_map = backend_map; | ||
| 734 | gb_tiling_config |= BACKEND_MAP(backend_map); | ||
| 735 | 580 | ||
| 736 | WREG32(GB_TILING_CONFIG, gb_tiling_config); | 581 | WREG32(GB_TILING_CONFIG, gb_tiling_config); |
| 737 | WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); | 582 | WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); |
| 738 | WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); | 583 | WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); |
| 739 | 584 | ||
| 740 | WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); | ||
| 741 | WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); | ||
| 742 | WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); | ||
| 743 | WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); | ||
| 744 | |||
| 745 | WREG32(CGTS_SYS_TCC_DISABLE, 0); | 585 | WREG32(CGTS_SYS_TCC_DISABLE, 0); |
| 746 | WREG32(CGTS_TCC_DISABLE, 0); | 586 | WREG32(CGTS_TCC_DISABLE, 0); |
| 747 | WREG32(CGTS_USER_SYS_TCC_DISABLE, 0); | 587 | WREG32(CGTS_USER_SYS_TCC_DISABLE, 0); |
| 748 | WREG32(CGTS_USER_TCC_DISABLE, 0); | 588 | WREG32(CGTS_USER_TCC_DISABLE, 0); |
| 749 | 589 | ||
| 750 | num_qd_pipes = | 590 | |
| 751 | R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); | 591 | num_qd_pipes = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); |
| 752 | WREG32(VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & DEALLOC_DIST_MASK); | 592 | WREG32(VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & DEALLOC_DIST_MASK); |
| 753 | WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & VTX_REUSE_DEPTH_MASK); | 593 | WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & VTX_REUSE_DEPTH_MASK); |
| 754 | 594 | ||
| @@ -809,8 +649,6 @@ static void rv770_gpu_init(struct radeon_device *rdev) | |||
| 809 | 649 | ||
| 810 | WREG32(VGT_NUM_INSTANCES, 1); | 650 | WREG32(VGT_NUM_INSTANCES, 1); |
| 811 | 651 | ||
| 812 | WREG32(SPI_CONFIG_CNTL, GPR_WRITE_PRIORITY(0)); | ||
| 813 | |||
| 814 | WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4)); | 652 | WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4)); |
| 815 | 653 | ||
| 816 | WREG32(CP_PERFMON_CNTL, 0); | 654 | WREG32(CP_PERFMON_CNTL, 0); |
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 9c549f702f2f..fdc089896011 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h | |||
| @@ -106,10 +106,13 @@ | |||
| 106 | #define BACKEND_MAP(x) ((x) << 16) | 106 | #define BACKEND_MAP(x) ((x) << 16) |
| 107 | 107 | ||
| 108 | #define GB_TILING_CONFIG 0x98F0 | 108 | #define GB_TILING_CONFIG 0x98F0 |
| 109 | #define PIPE_TILING__SHIFT 1 | ||
| 110 | #define PIPE_TILING__MASK 0x0000000e | ||
| 109 | 111 | ||
| 110 | #define GC_USER_SHADER_PIPE_CONFIG 0x8954 | 112 | #define GC_USER_SHADER_PIPE_CONFIG 0x8954 |
| 111 | #define INACTIVE_QD_PIPES(x) ((x) << 8) | 113 | #define INACTIVE_QD_PIPES(x) ((x) << 8) |
| 112 | #define INACTIVE_QD_PIPES_MASK 0x0000FF00 | 114 | #define INACTIVE_QD_PIPES_MASK 0x0000FF00 |
| 115 | #define INACTIVE_QD_PIPES_SHIFT 8 | ||
| 113 | #define INACTIVE_SIMDS(x) ((x) << 16) | 116 | #define INACTIVE_SIMDS(x) ((x) << 16) |
| 114 | #define INACTIVE_SIMDS_MASK 0x00FF0000 | 117 | #define INACTIVE_SIMDS_MASK 0x00FF0000 |
| 115 | 118 | ||
| @@ -174,6 +177,7 @@ | |||
| 174 | #define MC_VM_MD_L1_TLB0_CNTL 0x2654 | 177 | #define MC_VM_MD_L1_TLB0_CNTL 0x2654 |
| 175 | #define MC_VM_MD_L1_TLB1_CNTL 0x2658 | 178 | #define MC_VM_MD_L1_TLB1_CNTL 0x2658 |
| 176 | #define MC_VM_MD_L1_TLB2_CNTL 0x265C | 179 | #define MC_VM_MD_L1_TLB2_CNTL 0x265C |
| 180 | #define MC_VM_MD_L1_TLB3_CNTL 0x2698 | ||
| 177 | #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C | 181 | #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C |
| 178 | #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 | 182 | #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 |
| 179 | #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 | 183 | #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 |
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 36792bd4da77..b67cfcaa661f 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
| @@ -1834,6 +1834,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) | |||
| 1834 | spin_unlock(&glob->lru_lock); | 1834 | spin_unlock(&glob->lru_lock); |
| 1835 | (void) ttm_bo_cleanup_refs(bo, false, false, false); | 1835 | (void) ttm_bo_cleanup_refs(bo, false, false, false); |
| 1836 | kref_put(&bo->list_kref, ttm_bo_release_list); | 1836 | kref_put(&bo->list_kref, ttm_bo_release_list); |
| 1837 | spin_lock(&glob->lru_lock); | ||
| 1837 | continue; | 1838 | continue; |
| 1838 | } | 1839 | } |
| 1839 | 1840 | ||
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index a029ee39b0c5..ce9a61179925 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c | |||
| @@ -156,8 +156,17 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, | |||
| 156 | if (!fb->active_16) | 156 | if (!fb->active_16) |
| 157 | return 0; | 157 | return 0; |
| 158 | 158 | ||
| 159 | if (!fb->obj->vmapping) | 159 | if (!fb->obj->vmapping) { |
| 160 | udl_gem_vmap(fb->obj); | 160 | ret = udl_gem_vmap(fb->obj); |
| 161 | if (ret == -ENOMEM) { | ||
| 162 | DRM_ERROR("failed to vmap fb\n"); | ||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | if (!fb->obj->vmapping) { | ||
| 166 | DRM_ERROR("failed to vmapping\n"); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | } | ||
| 161 | 170 | ||
| 162 | start_cycles = get_cycles(); | 171 | start_cycles = get_cycles(); |
| 163 | 172 | ||
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 97acc9c6c95b..7bd65bdd15a8 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c | |||
| @@ -180,6 +180,18 @@ int udl_gem_vmap(struct udl_gem_object *obj) | |||
| 180 | int page_count = obj->base.size / PAGE_SIZE; | 180 | int page_count = obj->base.size / PAGE_SIZE; |
| 181 | int ret; | 181 | int ret; |
| 182 | 182 | ||
| 183 | if (obj->base.import_attach) { | ||
| 184 | ret = dma_buf_begin_cpu_access(obj->base.import_attach->dmabuf, | ||
| 185 | 0, obj->base.size, DMA_BIDIRECTIONAL); | ||
| 186 | if (ret) | ||
| 187 | return -EINVAL; | ||
| 188 | |||
| 189 | obj->vmapping = dma_buf_vmap(obj->base.import_attach->dmabuf); | ||
| 190 | if (!obj->vmapping) | ||
| 191 | return -ENOMEM; | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 183 | ret = udl_gem_get_pages(obj, GFP_KERNEL); | 195 | ret = udl_gem_get_pages(obj, GFP_KERNEL); |
| 184 | if (ret) | 196 | if (ret) |
| 185 | return ret; | 197 | return ret; |
| @@ -192,6 +204,13 @@ int udl_gem_vmap(struct udl_gem_object *obj) | |||
| 192 | 204 | ||
| 193 | void udl_gem_vunmap(struct udl_gem_object *obj) | 205 | void udl_gem_vunmap(struct udl_gem_object *obj) |
| 194 | { | 206 | { |
| 207 | if (obj->base.import_attach) { | ||
| 208 | dma_buf_vunmap(obj->base.import_attach->dmabuf, obj->vmapping); | ||
| 209 | dma_buf_end_cpu_access(obj->base.import_attach->dmabuf, 0, | ||
| 210 | obj->base.size, DMA_BIDIRECTIONAL); | ||
| 211 | return; | ||
| 212 | } | ||
| 213 | |||
| 195 | if (obj->vmapping) | 214 | if (obj->vmapping) |
| 196 | vunmap(obj->vmapping); | 215 | vunmap(obj->vmapping); |
| 197 | 216 | ||
| @@ -202,12 +221,12 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj) | |||
| 202 | { | 221 | { |
| 203 | struct udl_gem_object *obj = to_udl_bo(gem_obj); | 222 | struct udl_gem_object *obj = to_udl_bo(gem_obj); |
| 204 | 223 | ||
| 205 | if (gem_obj->import_attach) | ||
| 206 | drm_prime_gem_destroy(gem_obj, obj->sg); | ||
| 207 | |||
| 208 | if (obj->vmapping) | 224 | if (obj->vmapping) |
| 209 | udl_gem_vunmap(obj); | 225 | udl_gem_vunmap(obj); |
| 210 | 226 | ||
| 227 | if (gem_obj->import_attach) | ||
| 228 | drm_prime_gem_destroy(gem_obj, obj->sg); | ||
| 229 | |||
| 211 | if (obj->pages) | 230 | if (obj->pages) |
| 212 | udl_gem_put_pages(obj); | 231 | udl_gem_put_pages(obj); |
| 213 | 232 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 51c9ba5cd2fb..21ee78226560 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | |||
| @@ -66,7 +66,7 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv, | |||
| 66 | cmd += sizeof(remap_cmd) / sizeof(uint32); | 66 | cmd += sizeof(remap_cmd) / sizeof(uint32); |
| 67 | 67 | ||
| 68 | for (i = 0; i < num_pages; ++i) { | 68 | for (i = 0; i < num_pages; ++i) { |
| 69 | if (VMW_PPN_SIZE > 4) | 69 | if (VMW_PPN_SIZE <= 4) |
| 70 | *cmd = page_to_pfn(*pages++); | 70 | *cmd = page_to_pfn(*pages++); |
| 71 | else | 71 | else |
| 72 | *((uint64_t *)cmd) = page_to_pfn(*pages++); | 72 | *((uint64_t *)cmd) = page_to_pfn(*pages++); |
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 444143e5f28c..d99db5623acf 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c | |||
| @@ -1653,7 +1653,6 @@ mpt_mapresources(MPT_ADAPTER *ioc) | |||
| 1653 | unsigned long port; | 1653 | unsigned long port; |
| 1654 | u32 msize; | 1654 | u32 msize; |
| 1655 | u32 psize; | 1655 | u32 psize; |
| 1656 | u8 revision; | ||
| 1657 | int r = -ENODEV; | 1656 | int r = -ENODEV; |
| 1658 | struct pci_dev *pdev; | 1657 | struct pci_dev *pdev; |
| 1659 | 1658 | ||
| @@ -1670,8 +1669,6 @@ mpt_mapresources(MPT_ADAPTER *ioc) | |||
| 1670 | return r; | 1669 | return r; |
| 1671 | } | 1670 | } |
| 1672 | 1671 | ||
| 1673 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | ||
| 1674 | |||
| 1675 | if (sizeof(dma_addr_t) > 4) { | 1672 | if (sizeof(dma_addr_t) > 4) { |
| 1676 | const uint64_t required_mask = dma_get_required_mask | 1673 | const uint64_t required_mask = dma_get_required_mask |
| 1677 | (&pdev->dev); | 1674 | (&pdev->dev); |
| @@ -1779,7 +1776,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1779 | MPT_ADAPTER *ioc; | 1776 | MPT_ADAPTER *ioc; |
| 1780 | u8 cb_idx; | 1777 | u8 cb_idx; |
| 1781 | int r = -ENODEV; | 1778 | int r = -ENODEV; |
| 1782 | u8 revision; | ||
| 1783 | u8 pcixcmd; | 1779 | u8 pcixcmd; |
| 1784 | static int mpt_ids = 0; | 1780 | static int mpt_ids = 0; |
| 1785 | #ifdef CONFIG_PROC_FS | 1781 | #ifdef CONFIG_PROC_FS |
| @@ -1887,8 +1883,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1887 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", | 1883 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", |
| 1888 | ioc->name, &ioc->facts, &ioc->pfacts[0])); | 1884 | ioc->name, &ioc->facts, &ioc->pfacts[0])); |
| 1889 | 1885 | ||
| 1890 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | 1886 | mpt_get_product_name(pdev->vendor, pdev->device, pdev->revision, |
| 1891 | mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); | 1887 | ioc->prod_name); |
| 1892 | 1888 | ||
| 1893 | switch (pdev->device) | 1889 | switch (pdev->device) |
| 1894 | { | 1890 | { |
| @@ -1903,7 +1899,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1903 | break; | 1899 | break; |
| 1904 | 1900 | ||
| 1905 | case MPI_MANUFACTPAGE_DEVICEID_FC929X: | 1901 | case MPI_MANUFACTPAGE_DEVICEID_FC929X: |
| 1906 | if (revision < XL_929) { | 1902 | if (pdev->revision < XL_929) { |
| 1907 | /* 929X Chip Fix. Set Split transactions level | 1903 | /* 929X Chip Fix. Set Split transactions level |
| 1908 | * for PCIX. Set MOST bits to zero. | 1904 | * for PCIX. Set MOST bits to zero. |
| 1909 | */ | 1905 | */ |
| @@ -1934,7 +1930,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1934 | /* 1030 Chip Fix. Disable Split transactions | 1930 | /* 1030 Chip Fix. Disable Split transactions |
| 1935 | * for PCIX. Set MOST bits to zero if Rev < C0( = 8). | 1931 | * for PCIX. Set MOST bits to zero if Rev < C0( = 8). |
| 1936 | */ | 1932 | */ |
| 1937 | if (revision < C0_1030) { | 1933 | if (pdev->revision < C0_1030) { |
| 1938 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); | 1934 | pci_read_config_byte(pdev, 0x6a, &pcixcmd); |
| 1939 | pcixcmd &= 0x8F; | 1935 | pcixcmd &= 0x8F; |
| 1940 | pci_write_config_byte(pdev, 0x6a, pcixcmd); | 1936 | pci_write_config_byte(pdev, 0x6a, pcixcmd); |
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 6e6e16aab9da..b383b6961e59 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c | |||
| @@ -1250,7 +1250,6 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) | |||
| 1250 | int iocnum; | 1250 | int iocnum; |
| 1251 | unsigned int port; | 1251 | unsigned int port; |
| 1252 | int cim_rev; | 1252 | int cim_rev; |
| 1253 | u8 revision; | ||
| 1254 | struct scsi_device *sdev; | 1253 | struct scsi_device *sdev; |
| 1255 | VirtDevice *vdevice; | 1254 | VirtDevice *vdevice; |
| 1256 | 1255 | ||
| @@ -1324,8 +1323,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) | |||
| 1324 | pdev = (struct pci_dev *) ioc->pcidev; | 1323 | pdev = (struct pci_dev *) ioc->pcidev; |
| 1325 | 1324 | ||
| 1326 | karg->pciId = pdev->device; | 1325 | karg->pciId = pdev->device; |
| 1327 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | 1326 | karg->hwRev = pdev->revision; |
| 1328 | karg->hwRev = revision; | ||
| 1329 | karg->subSystemDevice = pdev->subsystem_device; | 1327 | karg->subSystemDevice = pdev->subsystem_device; |
| 1330 | karg->subSystemVendor = pdev->subsystem_vendor; | 1328 | karg->subSystemVendor = pdev->subsystem_vendor; |
| 1331 | 1329 | ||
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 671c8bc14bbc..50e83dc5dc49 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
| @@ -2735,6 +2735,7 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = { | |||
| 2735 | REGULATOR_SUPPLY("vcore", "uart2"), | 2735 | REGULATOR_SUPPLY("vcore", "uart2"), |
| 2736 | REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"), | 2736 | REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"), |
| 2737 | REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"), | 2737 | REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"), |
| 2738 | REGULATOR_SUPPLY("vddvario", "smsc911x.0"), | ||
| 2738 | }; | 2739 | }; |
| 2739 | 2740 | ||
| 2740 | static struct regulator_consumer_supply db8500_vsmps2_consumers[] = { | 2741 | static struct regulator_consumer_supply db8500_vsmps2_consumers[] = { |
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5760c1a4b3f6..27143e042af5 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
| @@ -128,7 +128,7 @@ config MTD_AFS_PARTS | |||
| 128 | 128 | ||
| 129 | config MTD_OF_PARTS | 129 | config MTD_OF_PARTS |
| 130 | tristate "OpenFirmware partitioning information support" | 130 | tristate "OpenFirmware partitioning information support" |
| 131 | default Y | 131 | default y |
| 132 | depends on OF | 132 | depends on OF |
| 133 | help | 133 | help |
| 134 | This provides a partition parsing function which derives | 134 | This provides a partition parsing function which derives |
diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 608321ee056e..63d2a64331f7 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> | 4 | * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> |
| 5 | * Mike Albon <malbon@openwrt.org> | 5 | * Mike Albon <malbon@openwrt.org> |
| 6 | * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> | 6 | * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> |
| 7 | * Copyright © 2011 Jonas Gorski <jonas.gorski@gmail.com> | 7 | * Copyright © 2011-2012 Jonas Gorski <jonas.gorski@gmail.com> |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
| @@ -82,6 +82,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, | |||
| 82 | int namelen = 0; | 82 | int namelen = 0; |
| 83 | int i; | 83 | int i; |
| 84 | u32 computed_crc; | 84 | u32 computed_crc; |
| 85 | bool rootfs_first = false; | ||
| 85 | 86 | ||
| 86 | if (bcm63xx_detect_cfe(master)) | 87 | if (bcm63xx_detect_cfe(master)) |
| 87 | return -EINVAL; | 88 | return -EINVAL; |
| @@ -109,6 +110,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, | |||
| 109 | char *boardid = &(buf->board_id[0]); | 110 | char *boardid = &(buf->board_id[0]); |
| 110 | char *tagversion = &(buf->tag_version[0]); | 111 | char *tagversion = &(buf->tag_version[0]); |
| 111 | 112 | ||
| 113 | sscanf(buf->flash_image_start, "%u", &rootfsaddr); | ||
| 112 | sscanf(buf->kernel_address, "%u", &kerneladdr); | 114 | sscanf(buf->kernel_address, "%u", &kerneladdr); |
| 113 | sscanf(buf->kernel_length, "%u", &kernellen); | 115 | sscanf(buf->kernel_length, "%u", &kernellen); |
| 114 | sscanf(buf->total_length, "%u", &totallen); | 116 | sscanf(buf->total_length, "%u", &totallen); |
| @@ -117,10 +119,19 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, | |||
| 117 | tagversion, boardid); | 119 | tagversion, boardid); |
| 118 | 120 | ||
| 119 | kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; | 121 | kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; |
| 120 | rootfsaddr = kerneladdr + kernellen; | 122 | rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE; |
| 121 | spareaddr = roundup(totallen, master->erasesize) + cfelen; | 123 | spareaddr = roundup(totallen, master->erasesize) + cfelen; |
| 122 | sparelen = master->size - spareaddr - nvramlen; | 124 | sparelen = master->size - spareaddr - nvramlen; |
| 123 | rootfslen = spareaddr - rootfsaddr; | 125 | |
| 126 | if (rootfsaddr < kerneladdr) { | ||
| 127 | /* default Broadcom layout */ | ||
| 128 | rootfslen = kerneladdr - rootfsaddr; | ||
| 129 | rootfs_first = true; | ||
| 130 | } else { | ||
| 131 | /* OpenWrt layout */ | ||
| 132 | rootfsaddr = kerneladdr + kernellen; | ||
| 133 | rootfslen = spareaddr - rootfsaddr; | ||
| 134 | } | ||
| 124 | } else { | 135 | } else { |
| 125 | pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n", | 136 | pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n", |
| 126 | buf->header_crc, computed_crc); | 137 | buf->header_crc, computed_crc); |
| @@ -156,18 +167,26 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, | |||
| 156 | curpart++; | 167 | curpart++; |
| 157 | 168 | ||
| 158 | if (kernellen > 0) { | 169 | if (kernellen > 0) { |
| 159 | parts[curpart].name = "kernel"; | 170 | int kernelpart = curpart; |
| 160 | parts[curpart].offset = kerneladdr; | 171 | |
| 161 | parts[curpart].size = kernellen; | 172 | if (rootfslen > 0 && rootfs_first) |
| 173 | kernelpart++; | ||
| 174 | parts[kernelpart].name = "kernel"; | ||
| 175 | parts[kernelpart].offset = kerneladdr; | ||
| 176 | parts[kernelpart].size = kernellen; | ||
| 162 | curpart++; | 177 | curpart++; |
| 163 | } | 178 | } |
| 164 | 179 | ||
| 165 | if (rootfslen > 0) { | 180 | if (rootfslen > 0) { |
| 166 | parts[curpart].name = "rootfs"; | 181 | int rootfspart = curpart; |
| 167 | parts[curpart].offset = rootfsaddr; | 182 | |
| 168 | parts[curpart].size = rootfslen; | 183 | if (kernellen > 0 && rootfs_first) |
| 169 | if (sparelen > 0) | 184 | rootfspart--; |
| 170 | parts[curpart].size += sparelen; | 185 | parts[rootfspart].name = "rootfs"; |
| 186 | parts[rootfspart].offset = rootfsaddr; | ||
| 187 | parts[rootfspart].size = rootfslen; | ||
| 188 | if (sparelen > 0 && !rootfs_first) | ||
| 189 | parts[rootfspart].size += sparelen; | ||
| 171 | curpart++; | 190 | curpart++; |
| 172 | } | 191 | } |
| 173 | 192 | ||
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index d02592e6a0f0..22d0493a026f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
| @@ -317,7 +317,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd) | |||
| 317 | 317 | ||
| 318 | if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) { | 318 | if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) { |
| 319 | cfi->cfiq->EraseRegionInfo[0] |= 0x0040; | 319 | cfi->cfiq->EraseRegionInfo[0] |= 0x0040; |
| 320 | pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name); | 320 | pr_warning("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n", mtd->name); |
| 321 | } | 321 | } |
| 322 | } | 322 | } |
| 323 | 323 | ||
| @@ -328,10 +328,23 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd) | |||
| 328 | 328 | ||
| 329 | if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) { | 329 | if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) { |
| 330 | cfi->cfiq->EraseRegionInfo[1] &= ~0x0040; | 330 | cfi->cfiq->EraseRegionInfo[1] &= ~0x0040; |
| 331 | pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name); | 331 | pr_warning("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n", mtd->name); |
| 332 | } | 332 | } |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | static void fixup_s29ns512p_sectors(struct mtd_info *mtd) | ||
| 336 | { | ||
| 337 | struct map_info *map = mtd->priv; | ||
| 338 | struct cfi_private *cfi = map->fldrv_priv; | ||
| 339 | |||
| 340 | /* | ||
| 341 | * S29NS512P flash uses more than 8bits to report number of sectors, | ||
| 342 | * which is not permitted by CFI. | ||
| 343 | */ | ||
| 344 | cfi->cfiq->EraseRegionInfo[0] = 0x020001ff; | ||
| 345 | pr_warning("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", mtd->name); | ||
| 346 | } | ||
| 347 | |||
| 335 | /* Used to fix CFI-Tables of chips without Extended Query Tables */ | 348 | /* Used to fix CFI-Tables of chips without Extended Query Tables */ |
| 336 | static struct cfi_fixup cfi_nopri_fixup_table[] = { | 349 | static struct cfi_fixup cfi_nopri_fixup_table[] = { |
| 337 | { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ | 350 | { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ |
| @@ -362,6 +375,7 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
| 362 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, | 375 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, |
| 363 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, | 376 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, |
| 364 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, | 377 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, |
| 378 | { CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors }, | ||
| 365 | { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ | 379 | { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ |
| 366 | { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ | 380 | { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ |
| 367 | { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ | 381 | { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ |
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index ddf9ec6d9168..4558e0f4d07f 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c | |||
| @@ -70,7 +70,7 @@ struct cmdline_mtd_partition { | |||
| 70 | /* mtdpart_setup() parses into here */ | 70 | /* mtdpart_setup() parses into here */ |
| 71 | static struct cmdline_mtd_partition *partitions; | 71 | static struct cmdline_mtd_partition *partitions; |
| 72 | 72 | ||
| 73 | /* the command line passed to mtdpart_setupd() */ | 73 | /* the command line passed to mtdpart_setup() */ |
| 74 | static char *cmdline; | 74 | static char *cmdline; |
| 75 | static int cmdline_parsed = 0; | 75 | static int cmdline_parsed = 0; |
| 76 | 76 | ||
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index a4a80b742e65..681e2ee0f2d6 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
| @@ -52,8 +52,6 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) | |||
| 52 | 52 | ||
| 53 | while (pages) { | 53 | while (pages) { |
| 54 | page = page_read(mapping, index); | 54 | page = page_read(mapping, index); |
| 55 | if (!page) | ||
| 56 | return -ENOMEM; | ||
| 57 | if (IS_ERR(page)) | 55 | if (IS_ERR(page)) |
| 58 | return PTR_ERR(page); | 56 | return PTR_ERR(page); |
| 59 | 57 | ||
| @@ -112,8 +110,6 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 112 | len = len - cpylen; | 110 | len = len - cpylen; |
| 113 | 111 | ||
| 114 | page = page_read(dev->blkdev->bd_inode->i_mapping, index); | 112 | page = page_read(dev->blkdev->bd_inode->i_mapping, index); |
| 115 | if (!page) | ||
| 116 | return -ENOMEM; | ||
| 117 | if (IS_ERR(page)) | 113 | if (IS_ERR(page)) |
| 118 | return PTR_ERR(page); | 114 | return PTR_ERR(page); |
| 119 | 115 | ||
| @@ -148,8 +144,6 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, | |||
| 148 | len = len - cpylen; | 144 | len = len - cpylen; |
| 149 | 145 | ||
| 150 | page = page_read(mapping, index); | 146 | page = page_read(mapping, index); |
| 151 | if (!page) | ||
| 152 | return -ENOMEM; | ||
| 153 | if (IS_ERR(page)) | 147 | if (IS_ERR(page)) |
| 154 | return PTR_ERR(page); | 148 | return PTR_ERR(page); |
| 155 | 149 | ||
| @@ -271,7 +265,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
| 271 | dev->mtd.flags = MTD_CAP_RAM; | 265 | dev->mtd.flags = MTD_CAP_RAM; |
| 272 | dev->mtd._erase = block2mtd_erase; | 266 | dev->mtd._erase = block2mtd_erase; |
| 273 | dev->mtd._write = block2mtd_write; | 267 | dev->mtd._write = block2mtd_write; |
| 274 | dev->mtd._writev = mtd_writev; | ||
| 275 | dev->mtd._sync = block2mtd_sync; | 268 | dev->mtd._sync = block2mtd_sync; |
| 276 | dev->mtd._read = block2mtd_read; | 269 | dev->mtd._read = block2mtd_read; |
| 277 | dev->mtd.priv = dev; | 270 | dev->mtd.priv = dev; |
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 50aa90aa7a7f..f70854d728fe 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c | |||
| @@ -227,7 +227,7 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, | |||
| 227 | u8 data8, *dst8; | 227 | u8 data8, *dst8; |
| 228 | 228 | ||
| 229 | doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); | 229 | doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); |
| 230 | cdr = len & 0x3; | 230 | cdr = len & 0x1; |
| 231 | len4 = len - cdr; | 231 | len4 = len - cdr; |
| 232 | 232 | ||
| 233 | if (first) | 233 | if (first) |
| @@ -732,12 +732,24 @@ err: | |||
| 732 | * @len: the number of bytes to be read (must be a multiple of 4) | 732 | * @len: the number of bytes to be read (must be a multiple of 4) |
| 733 | * @buf: the buffer to be filled in (or NULL is forget bytes) | 733 | * @buf: the buffer to be filled in (or NULL is forget bytes) |
| 734 | * @first: 1 if first time read, DOC_READADDRESS should be set | 734 | * @first: 1 if first time read, DOC_READADDRESS should be set |
| 735 | * @last_odd: 1 if last read ended up on an odd byte | ||
| 736 | * | ||
| 737 | * Reads bytes from a prepared page. There is a trickery here : if the last read | ||
| 738 | * ended up on an odd offset in the 1024 bytes double page, ie. between the 2 | ||
| 739 | * planes, the first byte must be read apart. If a word (16bit) read was used, | ||
| 740 | * the read would return the byte of plane 2 as low *and* high endian, which | ||
| 741 | * will mess the read. | ||
| 735 | * | 742 | * |
| 736 | */ | 743 | */ |
| 737 | static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, | 744 | static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, |
| 738 | int first) | 745 | int first, int last_odd) |
| 739 | { | 746 | { |
| 740 | doc_read_data_area(docg3, buf, len, first); | 747 | if (last_odd && len > 0) { |
| 748 | doc_read_data_area(docg3, buf, 1, first); | ||
| 749 | doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0); | ||
| 750 | } else { | ||
| 751 | doc_read_data_area(docg3, buf, len, first); | ||
| 752 | } | ||
| 741 | doc_delay(docg3, 2); | 753 | doc_delay(docg3, 2); |
| 742 | return len; | 754 | return len; |
| 743 | } | 755 | } |
| @@ -850,6 +862,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 850 | u8 *buf = ops->datbuf; | 862 | u8 *buf = ops->datbuf; |
| 851 | size_t len, ooblen, nbdata, nboob; | 863 | size_t len, ooblen, nbdata, nboob; |
| 852 | u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; | 864 | u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; |
| 865 | int max_bitflips = 0; | ||
| 853 | 866 | ||
| 854 | if (buf) | 867 | if (buf) |
| 855 | len = ops->len; | 868 | len = ops->len; |
| @@ -876,7 +889,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 876 | ret = 0; | 889 | ret = 0; |
| 877 | skip = from % DOC_LAYOUT_PAGE_SIZE; | 890 | skip = from % DOC_LAYOUT_PAGE_SIZE; |
| 878 | mutex_lock(&docg3->cascade->lock); | 891 | mutex_lock(&docg3->cascade->lock); |
| 879 | while (!ret && (len > 0 || ooblen > 0)) { | 892 | while (ret >= 0 && (len > 0 || ooblen > 0)) { |
| 880 | calc_block_sector(from - skip, &block0, &block1, &page, &ofs, | 893 | calc_block_sector(from - skip, &block0, &block1, &page, &ofs, |
| 881 | docg3->reliable); | 894 | docg3->reliable); |
| 882 | nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); | 895 | nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); |
| @@ -887,20 +900,20 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 887 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); | 900 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); |
| 888 | if (ret < 0) | 901 | if (ret < 0) |
| 889 | goto err_in_read; | 902 | goto err_in_read; |
| 890 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1); | 903 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0); |
| 891 | if (ret < skip) | 904 | if (ret < skip) |
| 892 | goto err_in_read; | 905 | goto err_in_read; |
| 893 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); | 906 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2); |
| 894 | if (ret < nbdata) | 907 | if (ret < nbdata) |
| 895 | goto err_in_read; | 908 | goto err_in_read; |
| 896 | doc_read_page_getbytes(docg3, | 909 | doc_read_page_getbytes(docg3, |
| 897 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, | 910 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, |
| 898 | NULL, 0); | 911 | NULL, 0, (skip + nbdata) % 2); |
| 899 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); | 912 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0); |
| 900 | if (ret < nboob) | 913 | if (ret < nboob) |
| 901 | goto err_in_read; | 914 | goto err_in_read; |
| 902 | doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, | 915 | doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, |
| 903 | NULL, 0); | 916 | NULL, 0, nboob % 2); |
| 904 | 917 | ||
| 905 | doc_get_bch_hw_ecc(docg3, hwecc); | 918 | doc_get_bch_hw_ecc(docg3, hwecc); |
| 906 | eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); | 919 | eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); |
| @@ -936,7 +949,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 936 | } | 949 | } |
| 937 | if (ret > 0) { | 950 | if (ret > 0) { |
| 938 | mtd->ecc_stats.corrected += ret; | 951 | mtd->ecc_stats.corrected += ret; |
| 939 | ret = -EUCLEAN; | 952 | max_bitflips = max(max_bitflips, ret); |
| 953 | ret = max_bitflips; | ||
| 940 | } | 954 | } |
| 941 | } | 955 | } |
| 942 | 956 | ||
| @@ -1004,7 +1018,7 @@ static int doc_reload_bbt(struct docg3 *docg3) | |||
| 1004 | DOC_LAYOUT_PAGE_SIZE); | 1018 | DOC_LAYOUT_PAGE_SIZE); |
| 1005 | if (!ret) | 1019 | if (!ret) |
| 1006 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, | 1020 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, |
| 1007 | buf, 1); | 1021 | buf, 1, 0); |
| 1008 | buf += DOC_LAYOUT_PAGE_SIZE; | 1022 | buf += DOC_LAYOUT_PAGE_SIZE; |
| 1009 | } | 1023 | } |
| 1010 | doc_read_page_finish(docg3); | 1024 | doc_read_page_finish(docg3); |
| @@ -1064,10 +1078,10 @@ static int doc_get_erase_count(struct docg3 *docg3, loff_t from) | |||
| 1064 | ret = doc_reset_seq(docg3); | 1078 | ret = doc_reset_seq(docg3); |
| 1065 | if (!ret) | 1079 | if (!ret) |
| 1066 | ret = doc_read_page_prepare(docg3, block0, block1, page, | 1080 | ret = doc_read_page_prepare(docg3, block0, block1, page, |
| 1067 | ofs + DOC_LAYOUT_WEAR_OFFSET); | 1081 | ofs + DOC_LAYOUT_WEAR_OFFSET, 0); |
| 1068 | if (!ret) | 1082 | if (!ret) |
| 1069 | ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, | 1083 | ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, |
| 1070 | buf, 1); | 1084 | buf, 1, 0); |
| 1071 | doc_read_page_finish(docg3); | 1085 | doc_read_page_finish(docg3); |
| 1072 | 1086 | ||
| 1073 | if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) | 1087 | if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 1924d247c1cb..5d0d68c3fe27 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
| @@ -639,12 +639,16 @@ static const struct spi_device_id m25p_ids[] = { | |||
| 639 | { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, | 639 | { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, |
| 640 | { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, | 640 | { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, |
| 641 | 641 | ||
| 642 | /* Everspin */ | ||
| 643 | { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, | ||
| 644 | |||
| 642 | /* Intel/Numonyx -- xxxs33b */ | 645 | /* Intel/Numonyx -- xxxs33b */ |
| 643 | { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, | 646 | { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, |
| 644 | { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, | 647 | { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, |
| 645 | { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, | 648 | { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, |
| 646 | 649 | ||
| 647 | /* Macronix */ | 650 | /* Macronix */ |
| 651 | { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, | ||
| 648 | { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, | 652 | { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, |
| 649 | { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, | 653 | { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, |
| 650 | { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, | 654 | { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, |
| @@ -728,6 +732,7 @@ static const struct spi_device_id m25p_ids[] = { | |||
| 728 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, | 732 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, |
| 729 | { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, | 733 | { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, |
| 730 | { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, | 734 | { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, |
| 735 | { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, | ||
| 731 | 736 | ||
| 732 | /* Catalyst / On Semiconductor -- non-JEDEC */ | 737 | /* Catalyst / On Semiconductor -- non-JEDEC */ |
| 733 | { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, | 738 | { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, |
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index 797d43cd3550..67960362681e 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c | |||
| @@ -990,9 +990,9 @@ static int __devinit spear_smi_probe(struct platform_device *pdev) | |||
| 990 | goto err_clk; | 990 | goto err_clk; |
| 991 | } | 991 | } |
| 992 | 992 | ||
| 993 | ret = clk_enable(dev->clk); | 993 | ret = clk_prepare_enable(dev->clk); |
| 994 | if (ret) | 994 | if (ret) |
| 995 | goto err_clk_enable; | 995 | goto err_clk_prepare_enable; |
| 996 | 996 | ||
| 997 | ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev); | 997 | ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev); |
| 998 | if (ret) { | 998 | if (ret) { |
| @@ -1020,8 +1020,8 @@ err_bank_setup: | |||
| 1020 | free_irq(irq, dev); | 1020 | free_irq(irq, dev); |
| 1021 | platform_set_drvdata(pdev, NULL); | 1021 | platform_set_drvdata(pdev, NULL); |
| 1022 | err_irq: | 1022 | err_irq: |
| 1023 | clk_disable(dev->clk); | 1023 | clk_disable_unprepare(dev->clk); |
| 1024 | err_clk_enable: | 1024 | err_clk_prepare_enable: |
| 1025 | clk_put(dev->clk); | 1025 | clk_put(dev->clk); |
| 1026 | err_clk: | 1026 | err_clk: |
| 1027 | iounmap(dev->io_base); | 1027 | iounmap(dev->io_base); |
| @@ -1074,7 +1074,7 @@ static int __devexit spear_smi_remove(struct platform_device *pdev) | |||
| 1074 | irq = platform_get_irq(pdev, 0); | 1074 | irq = platform_get_irq(pdev, 0); |
| 1075 | free_irq(irq, dev); | 1075 | free_irq(irq, dev); |
| 1076 | 1076 | ||
| 1077 | clk_disable(dev->clk); | 1077 | clk_disable_unprepare(dev->clk); |
| 1078 | clk_put(dev->clk); | 1078 | clk_put(dev->clk); |
| 1079 | iounmap(dev->io_base); | 1079 | iounmap(dev->io_base); |
| 1080 | kfree(dev); | 1080 | kfree(dev); |
| @@ -1091,7 +1091,7 @@ int spear_smi_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 1091 | struct spear_smi *dev = platform_get_drvdata(pdev); | 1091 | struct spear_smi *dev = platform_get_drvdata(pdev); |
| 1092 | 1092 | ||
| 1093 | if (dev && dev->clk) | 1093 | if (dev && dev->clk) |
| 1094 | clk_disable(dev->clk); | 1094 | clk_disable_unprepare(dev->clk); |
| 1095 | 1095 | ||
| 1096 | return 0; | 1096 | return 0; |
| 1097 | } | 1097 | } |
| @@ -1102,7 +1102,7 @@ int spear_smi_resume(struct platform_device *pdev) | |||
| 1102 | int ret = -EPERM; | 1102 | int ret = -EPERM; |
| 1103 | 1103 | ||
| 1104 | if (dev && dev->clk) | 1104 | if (dev && dev->clk) |
| 1105 | ret = clk_enable(dev->clk); | 1105 | ret = clk_prepare_enable(dev->clk); |
| 1106 | 1106 | ||
| 1107 | if (!ret) | 1107 | if (!ret) |
| 1108 | spear_smi_hw_init(dev); | 1108 | spear_smi_hw_init(dev); |
diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c index dbfe17baf046..45abed67f1ef 100644 --- a/drivers/mtd/lpddr/qinfo_probe.c +++ b/drivers/mtd/lpddr/qinfo_probe.c | |||
| @@ -57,7 +57,7 @@ static struct qinfo_query_info qinfo_array[] = { | |||
| 57 | 57 | ||
| 58 | static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str) | 58 | static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str) |
| 59 | { | 59 | { |
| 60 | int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info); | 60 | int qinfo_lines = ARRAY_SIZE(qinfo_array); |
| 61 | int i; | 61 | int i; |
| 62 | int bankwidth = map_bankwidth(map) * 8; | 62 | int bankwidth = map_bankwidth(map) * 8; |
| 63 | int major, minor; | 63 | int major, minor; |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 8af67cfd671a..5ba2458e799a 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
| @@ -224,7 +224,7 @@ config MTD_CK804XROM | |||
| 224 | 224 | ||
| 225 | config MTD_SCB2_FLASH | 225 | config MTD_SCB2_FLASH |
| 226 | tristate "BIOS flash chip on Intel SCB2 boards" | 226 | tristate "BIOS flash chip on Intel SCB2 boards" |
| 227 | depends on X86 && MTD_JEDECPROBE | 227 | depends on X86 && MTD_JEDECPROBE && PCI |
| 228 | help | 228 | help |
| 229 | Support for treating the BIOS flash chip on Intel SCB2 boards | 229 | Support for treating the BIOS flash chip on Intel SCB2 boards |
| 230 | as an MTD device - with this you can reprogram your BIOS. | 230 | as an MTD device - with this you can reprogram your BIOS. |
diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 92e1f41634c7..93f03175c82d 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c | |||
| @@ -260,18 +260,7 @@ static struct pci_driver vr_nor_pci_driver = { | |||
| 260 | .id_table = vr_nor_pci_ids, | 260 | .id_table = vr_nor_pci_ids, |
| 261 | }; | 261 | }; |
| 262 | 262 | ||
| 263 | static int __init vr_nor_mtd_init(void) | 263 | module_pci_driver(vr_nor_pci_driver); |
| 264 | { | ||
| 265 | return pci_register_driver(&vr_nor_pci_driver); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void __exit vr_nor_mtd_exit(void) | ||
| 269 | { | ||
| 270 | pci_unregister_driver(&vr_nor_pci_driver); | ||
| 271 | } | ||
| 272 | |||
| 273 | module_init(vr_nor_mtd_init); | ||
| 274 | module_exit(vr_nor_mtd_exit); | ||
| 275 | 264 | ||
| 276 | MODULE_AUTHOR("Andy Lowe"); | 265 | MODULE_AUTHOR("Andy Lowe"); |
| 277 | MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range"); | 266 | MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range"); |
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 1d005a3e9b41..f14ce0af763f 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c | |||
| @@ -352,18 +352,7 @@ static struct pci_driver mtd_pci_driver = { | |||
| 352 | .id_table = mtd_pci_ids, | 352 | .id_table = mtd_pci_ids, |
| 353 | }; | 353 | }; |
| 354 | 354 | ||
| 355 | static int __init mtd_pci_maps_init(void) | 355 | module_pci_driver(mtd_pci_driver); |
| 356 | { | ||
| 357 | return pci_register_driver(&mtd_pci_driver); | ||
| 358 | } | ||
| 359 | |||
| 360 | static void __exit mtd_pci_maps_exit(void) | ||
| 361 | { | ||
| 362 | pci_unregister_driver(&mtd_pci_driver); | ||
| 363 | } | ||
| 364 | |||
| 365 | module_init(mtd_pci_maps_init); | ||
| 366 | module_exit(mtd_pci_maps_exit); | ||
| 367 | 356 | ||
| 368 | MODULE_LICENSE("GPL"); | 357 | MODULE_LICENSE("GPL"); |
| 369 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | 358 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); |
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 934a72c80078..9dcbc684abdb 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c | |||
| @@ -234,20 +234,7 @@ static struct pci_driver scb2_flash_driver = { | |||
| 234 | .remove = __devexit_p(scb2_flash_remove), | 234 | .remove = __devexit_p(scb2_flash_remove), |
| 235 | }; | 235 | }; |
| 236 | 236 | ||
| 237 | static int __init | 237 | module_pci_driver(scb2_flash_driver); |
| 238 | scb2_flash_init(void) | ||
| 239 | { | ||
| 240 | return pci_register_driver(&scb2_flash_driver); | ||
| 241 | } | ||
| 242 | |||
| 243 | static void __exit | ||
| 244 | scb2_flash_exit(void) | ||
| 245 | { | ||
| 246 | pci_unregister_driver(&scb2_flash_driver); | ||
| 247 | } | ||
| 248 | |||
| 249 | module_init(scb2_flash_init); | ||
| 250 | module_exit(scb2_flash_exit); | ||
| 251 | 238 | ||
| 252 | MODULE_LICENSE("GPL"); | 239 | MODULE_LICENSE("GPL"); |
| 253 | MODULE_AUTHOR("Tim Hockin <thockin@sun.com>"); | 240 | MODULE_AUTHOR("Tim Hockin <thockin@sun.com>"); |
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 71b0ba797912..e7534c82f93a 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c | |||
| @@ -59,7 +59,7 @@ static struct mtd_partition bigflash_parts[] = { | |||
| 59 | } | 59 | } |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; | 62 | static const char *part_probes[] __initconst = {"cmdlinepart", "RedBoot", NULL}; |
| 63 | 63 | ||
| 64 | #define init_sbc82xx_one_flash(map, br, or) \ | 64 | #define init_sbc82xx_one_flash(map, br, or) \ |
| 65 | do { \ | 65 | do { \ |
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c837507dfb1c..575730744fdb 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
| @@ -250,6 +250,43 @@ static ssize_t mtd_name_show(struct device *dev, | |||
| 250 | } | 250 | } |
| 251 | static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL); | 251 | static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL); |
| 252 | 252 | ||
| 253 | static ssize_t mtd_ecc_strength_show(struct device *dev, | ||
| 254 | struct device_attribute *attr, char *buf) | ||
| 255 | { | ||
| 256 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
| 257 | |||
| 258 | return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength); | ||
| 259 | } | ||
| 260 | static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL); | ||
| 261 | |||
| 262 | static ssize_t mtd_bitflip_threshold_show(struct device *dev, | ||
| 263 | struct device_attribute *attr, | ||
| 264 | char *buf) | ||
| 265 | { | ||
| 266 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
| 267 | |||
| 268 | return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold); | ||
| 269 | } | ||
| 270 | |||
| 271 | static ssize_t mtd_bitflip_threshold_store(struct device *dev, | ||
| 272 | struct device_attribute *attr, | ||
| 273 | const char *buf, size_t count) | ||
| 274 | { | ||
| 275 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
| 276 | unsigned int bitflip_threshold; | ||
| 277 | int retval; | ||
| 278 | |||
| 279 | retval = kstrtouint(buf, 0, &bitflip_threshold); | ||
| 280 | if (retval) | ||
| 281 | return retval; | ||
| 282 | |||
| 283 | mtd->bitflip_threshold = bitflip_threshold; | ||
| 284 | return count; | ||
| 285 | } | ||
| 286 | static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR, | ||
| 287 | mtd_bitflip_threshold_show, | ||
| 288 | mtd_bitflip_threshold_store); | ||
| 289 | |||
| 253 | static struct attribute *mtd_attrs[] = { | 290 | static struct attribute *mtd_attrs[] = { |
| 254 | &dev_attr_type.attr, | 291 | &dev_attr_type.attr, |
| 255 | &dev_attr_flags.attr, | 292 | &dev_attr_flags.attr, |
| @@ -260,6 +297,8 @@ static struct attribute *mtd_attrs[] = { | |||
| 260 | &dev_attr_oobsize.attr, | 297 | &dev_attr_oobsize.attr, |
| 261 | &dev_attr_numeraseregions.attr, | 298 | &dev_attr_numeraseregions.attr, |
| 262 | &dev_attr_name.attr, | 299 | &dev_attr_name.attr, |
| 300 | &dev_attr_ecc_strength.attr, | ||
| 301 | &dev_attr_bitflip_threshold.attr, | ||
| 263 | NULL, | 302 | NULL, |
| 264 | }; | 303 | }; |
| 265 | 304 | ||
| @@ -322,6 +361,10 @@ int add_mtd_device(struct mtd_info *mtd) | |||
| 322 | mtd->index = i; | 361 | mtd->index = i; |
| 323 | mtd->usecount = 0; | 362 | mtd->usecount = 0; |
| 324 | 363 | ||
| 364 | /* default value if not set by driver */ | ||
| 365 | if (mtd->bitflip_threshold == 0) | ||
| 366 | mtd->bitflip_threshold = mtd->ecc_strength; | ||
| 367 | |||
| 325 | if (is_power_of_2(mtd->erasesize)) | 368 | if (is_power_of_2(mtd->erasesize)) |
| 326 | mtd->erasesize_shift = ffs(mtd->erasesize) - 1; | 369 | mtd->erasesize_shift = ffs(mtd->erasesize) - 1; |
| 327 | else | 370 | else |
| @@ -757,12 +800,24 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area); | |||
| 757 | int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, | 800 | int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, |
| 758 | u_char *buf) | 801 | u_char *buf) |
| 759 | { | 802 | { |
| 803 | int ret_code; | ||
| 760 | *retlen = 0; | 804 | *retlen = 0; |
| 761 | if (from < 0 || from > mtd->size || len > mtd->size - from) | 805 | if (from < 0 || from > mtd->size || len > mtd->size - from) |
| 762 | return -EINVAL; | 806 | return -EINVAL; |
| 763 | if (!len) | 807 | if (!len) |
| 764 | return 0; | 808 | return 0; |
| 765 | return mtd->_read(mtd, from, len, retlen, buf); | 809 | |
| 810 | /* | ||
| 811 | * In the absence of an error, drivers return a non-negative integer | ||
| 812 | * representing the maximum number of bitflips that were corrected on | ||
| 813 | * any one ecc region (if applicable; zero otherwise). | ||
| 814 | */ | ||
| 815 | ret_code = mtd->_read(mtd, from, len, retlen, buf); | ||
| 816 | if (unlikely(ret_code < 0)) | ||
| 817 | return ret_code; | ||
| 818 | if (mtd->ecc_strength == 0) | ||
| 819 | return 0; /* device lacks ecc */ | ||
| 820 | return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; | ||
| 766 | } | 821 | } |
| 767 | EXPORT_SYMBOL_GPL(mtd_read); | 822 | EXPORT_SYMBOL_GPL(mtd_read); |
| 768 | 823 | ||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9651c06de0a9..d518e4db8a0b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
| @@ -67,12 +67,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 67 | stats = part->master->ecc_stats; | 67 | stats = part->master->ecc_stats; |
| 68 | res = part->master->_read(part->master, from + part->offset, len, | 68 | res = part->master->_read(part->master, from + part->offset, len, |
| 69 | retlen, buf); | 69 | retlen, buf); |
| 70 | if (unlikely(res)) { | 70 | if (unlikely(mtd_is_eccerr(res))) |
| 71 | if (mtd_is_bitflip(res)) | 71 | mtd->ecc_stats.failed += |
| 72 | mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; | 72 | part->master->ecc_stats.failed - stats.failed; |
| 73 | if (mtd_is_eccerr(res)) | 73 | else |
| 74 | mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; | 74 | mtd->ecc_stats.corrected += |
| 75 | } | 75 | part->master->ecc_stats.corrected - stats.corrected; |
| 76 | return res; | 76 | return res; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| @@ -517,6 +517,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, | |||
| 517 | 517 | ||
| 518 | slave->mtd.ecclayout = master->ecclayout; | 518 | slave->mtd.ecclayout = master->ecclayout; |
| 519 | slave->mtd.ecc_strength = master->ecc_strength; | 519 | slave->mtd.ecc_strength = master->ecc_strength; |
| 520 | slave->mtd.bitflip_threshold = master->bitflip_threshold; | ||
| 521 | |||
| 520 | if (master->_block_isbad) { | 522 | if (master->_block_isbad) { |
| 521 | uint64_t offs = 0; | 523 | uint64_t offs = 0; |
| 522 | 524 | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 7d17cecad69d..31bb7e5b504a 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
| @@ -115,6 +115,46 @@ config MTD_NAND_OMAP2 | |||
| 115 | Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 | 115 | Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 |
| 116 | platforms. | 116 | platforms. |
| 117 | 117 | ||
| 118 | config MTD_NAND_OMAP_BCH | ||
| 119 | depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3 | ||
| 120 | bool "Enable support for hardware BCH error correction" | ||
| 121 | default n | ||
| 122 | select BCH | ||
| 123 | select BCH_CONST_PARAMS | ||
| 124 | help | ||
| 125 | Support for hardware BCH error correction. | ||
| 126 | |||
| 127 | choice | ||
| 128 | prompt "BCH error correction capability" | ||
| 129 | depends on MTD_NAND_OMAP_BCH | ||
| 130 | |||
| 131 | config MTD_NAND_OMAP_BCH8 | ||
| 132 | bool "8 bits / 512 bytes (recommended)" | ||
| 133 | help | ||
| 134 | Support correcting up to 8 bitflips per 512-byte block. | ||
| 135 | This will use 13 bytes of spare area per 512 bytes of page data. | ||
| 136 | This is the recommended mode, as 4-bit mode does not work | ||
| 137 | on some OMAP3 revisions, due to a hardware bug. | ||
| 138 | |||
| 139 | config MTD_NAND_OMAP_BCH4 | ||
| 140 | bool "4 bits / 512 bytes" | ||
| 141 | help | ||
| 142 | Support correcting up to 4 bitflips per 512-byte block. | ||
| 143 | This will use 7 bytes of spare area per 512 bytes of page data. | ||
| 144 | Note that this mode does not work on some OMAP3 revisions, due to a | ||
| 145 | hardware bug. Please check your OMAP datasheet before selecting this | ||
| 146 | mode. | ||
| 147 | |||
| 148 | endchoice | ||
| 149 | |||
| 150 | if MTD_NAND_OMAP_BCH | ||
| 151 | config BCH_CONST_M | ||
| 152 | default 13 | ||
| 153 | config BCH_CONST_T | ||
| 154 | default 4 if MTD_NAND_OMAP_BCH4 | ||
| 155 | default 8 if MTD_NAND_OMAP_BCH8 | ||
| 156 | endif | ||
| 157 | |||
| 118 | config MTD_NAND_IDS | 158 | config MTD_NAND_IDS |
| 119 | tristate | 159 | tristate |
| 120 | 160 | ||
| @@ -440,7 +480,7 @@ config MTD_NAND_NANDSIM | |||
| 440 | 480 | ||
| 441 | config MTD_NAND_GPMI_NAND | 481 | config MTD_NAND_GPMI_NAND |
| 442 | bool "GPMI NAND Flash Controller driver" | 482 | bool "GPMI NAND Flash Controller driver" |
| 443 | depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28) | 483 | depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q) |
| 444 | help | 484 | help |
| 445 | Enables NAND Flash support for IMX23 or IMX28. | 485 | Enables NAND Flash support for IMX23 or IMX28. |
| 446 | The GPMI controller is very powerful, with the help of BCH | 486 | The GPMI controller is very powerful, with the help of BCH |
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c index 4f20e1d8bef1..60a0dfdb0808 100644 --- a/drivers/mtd/nand/alauda.c +++ b/drivers/mtd/nand/alauda.c | |||
| @@ -414,7 +414,7 @@ static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 414 | } | 414 | } |
| 415 | err = 0; | 415 | err = 0; |
| 416 | if (corrected) | 416 | if (corrected) |
| 417 | err = -EUCLEAN; | 417 | err = 1; /* return max_bitflips per ecc step */ |
| 418 | if (uncorrected) | 418 | if (uncorrected) |
| 419 | err = -EBADMSG; | 419 | err = -EBADMSG; |
| 420 | out: | 420 | out: |
| @@ -446,7 +446,7 @@ static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 446 | } | 446 | } |
| 447 | err = 0; | 447 | err = 0; |
| 448 | if (corrected) | 448 | if (corrected) |
| 449 | err = -EUCLEAN; | 449 | err = 1; /* return max_bitflips per ecc step */ |
| 450 | if (uncorrected) | 450 | if (uncorrected) |
| 451 | err = -EBADMSG; | 451 | err = -EBADMSG; |
| 452 | return err; | 452 | return err; |
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 2165576a1c67..97ac6712bb19 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
| @@ -324,9 +324,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd, | |||
| 324 | * mtd: mtd info structure | 324 | * mtd: mtd info structure |
| 325 | * chip: nand chip info structure | 325 | * chip: nand chip info structure |
| 326 | * buf: buffer to store read data | 326 | * buf: buffer to store read data |
| 327 | * oob_required: caller expects OOB data read to chip->oob_poi | ||
| 327 | */ | 328 | */ |
| 328 | static int atmel_nand_read_page(struct mtd_info *mtd, | 329 | static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 329 | struct nand_chip *chip, uint8_t *buf, int page) | 330 | uint8_t *buf, int oob_required, int page) |
| 330 | { | 331 | { |
| 331 | int eccsize = chip->ecc.size; | 332 | int eccsize = chip->ecc.size; |
| 332 | int eccbytes = chip->ecc.bytes; | 333 | int eccbytes = chip->ecc.bytes; |
| @@ -335,6 +336,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, | |||
| 335 | uint8_t *oob = chip->oob_poi; | 336 | uint8_t *oob = chip->oob_poi; |
| 336 | uint8_t *ecc_pos; | 337 | uint8_t *ecc_pos; |
| 337 | int stat; | 338 | int stat; |
| 339 | unsigned int max_bitflips = 0; | ||
| 338 | 340 | ||
| 339 | /* | 341 | /* |
| 340 | * Errata: ALE is incorrectly wired up to the ECC controller | 342 | * Errata: ALE is incorrectly wired up to the ECC controller |
| @@ -371,10 +373,12 @@ static int atmel_nand_read_page(struct mtd_info *mtd, | |||
| 371 | /* check if there's an error */ | 373 | /* check if there's an error */ |
| 372 | stat = chip->ecc.correct(mtd, p, oob, NULL); | 374 | stat = chip->ecc.correct(mtd, p, oob, NULL); |
| 373 | 375 | ||
| 374 | if (stat < 0) | 376 | if (stat < 0) { |
| 375 | mtd->ecc_stats.failed++; | 377 | mtd->ecc_stats.failed++; |
| 376 | else | 378 | } else { |
| 377 | mtd->ecc_stats.corrected += stat; | 379 | mtd->ecc_stats.corrected += stat; |
| 380 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 381 | } | ||
| 378 | 382 | ||
| 379 | /* get back to oob start (end of page) */ | 383 | /* get back to oob start (end of page) */ |
| 380 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); | 384 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); |
| @@ -382,7 +386,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, | |||
| 382 | /* read the oob */ | 386 | /* read the oob */ |
| 383 | chip->read_buf(mtd, oob, mtd->oobsize); | 387 | chip->read_buf(mtd, oob, mtd->oobsize); |
| 384 | 388 | ||
| 385 | return 0; | 389 | return max_bitflips; |
| 386 | } | 390 | } |
| 387 | 391 | ||
| 388 | /* | 392 | /* |
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 73abbc3e093e..9f609d2dcf62 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
| @@ -508,8 +508,6 @@ static int __devinit au1550nd_probe(struct platform_device *pdev) | |||
| 508 | this->chip_delay = 30; | 508 | this->chip_delay = 30; |
| 509 | this->ecc.mode = NAND_ECC_SOFT; | 509 | this->ecc.mode = NAND_ECC_SOFT; |
| 510 | 510 | ||
| 511 | this->options = NAND_NO_AUTOINCR; | ||
| 512 | |||
| 513 | if (pd->devwidth) | 511 | if (pd->devwidth) |
| 514 | this->options |= NAND_BUSWIDTH_16; | 512 | this->options |= NAND_BUSWIDTH_16; |
| 515 | 513 | ||
diff --git a/drivers/mtd/nand/bcm_umi_bch.c b/drivers/mtd/nand/bcm_umi_bch.c index a930666d0687..5914bb32e001 100644 --- a/drivers/mtd/nand/bcm_umi_bch.c +++ b/drivers/mtd/nand/bcm_umi_bch.c | |||
| @@ -22,9 +22,9 @@ | |||
| 22 | 22 | ||
| 23 | /* ---- Private Function Prototypes -------------------------------------- */ | 23 | /* ---- Private Function Prototypes -------------------------------------- */ |
| 24 | static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, | 24 | static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, |
| 25 | struct nand_chip *chip, uint8_t *buf, int page); | 25 | struct nand_chip *chip, uint8_t *buf, int oob_required, int page); |
| 26 | static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, | 26 | static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, |
| 27 | struct nand_chip *chip, const uint8_t *buf); | 27 | struct nand_chip *chip, const uint8_t *buf, int oob_required); |
| 28 | 28 | ||
| 29 | /* ---- Private Variables ------------------------------------------------ */ | 29 | /* ---- Private Variables ------------------------------------------------ */ |
| 30 | 30 | ||
| @@ -103,11 +103,12 @@ static struct nand_ecclayout nand_hw_eccoob_4096 = { | |||
| 103 | * @mtd: mtd info structure | 103 | * @mtd: mtd info structure |
| 104 | * @chip: nand chip info structure | 104 | * @chip: nand chip info structure |
| 105 | * @buf: buffer to store read data | 105 | * @buf: buffer to store read data |
| 106 | * @oob_required: caller expects OOB data read to chip->oob_poi | ||
| 106 | * | 107 | * |
| 107 | ***************************************************************************/ | 108 | ***************************************************************************/ |
| 108 | static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, | 109 | static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, |
| 109 | struct nand_chip *chip, uint8_t * buf, | 110 | struct nand_chip *chip, uint8_t * buf, |
| 110 | int page) | 111 | int oob_required, int page) |
| 111 | { | 112 | { |
| 112 | int sectorIdx = 0; | 113 | int sectorIdx = 0; |
| 113 | int eccsize = chip->ecc.size; | 114 | int eccsize = chip->ecc.size; |
| @@ -116,6 +117,7 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, | |||
| 116 | uint8_t eccCalc[NAND_ECC_NUM_BYTES]; | 117 | uint8_t eccCalc[NAND_ECC_NUM_BYTES]; |
| 117 | int sectorOobSize = mtd->oobsize / eccsteps; | 118 | int sectorOobSize = mtd->oobsize / eccsteps; |
| 118 | int stat; | 119 | int stat; |
| 120 | unsigned int max_bitflips = 0; | ||
| 119 | 121 | ||
| 120 | for (sectorIdx = 0; sectorIdx < eccsteps; | 122 | for (sectorIdx = 0; sectorIdx < eccsteps; |
| 121 | sectorIdx++, datap += eccsize) { | 123 | sectorIdx++, datap += eccsize) { |
| @@ -177,9 +179,10 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, | |||
| 177 | } | 179 | } |
| 178 | #endif | 180 | #endif |
| 179 | mtd->ecc_stats.corrected += stat; | 181 | mtd->ecc_stats.corrected += stat; |
| 182 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 180 | } | 183 | } |
| 181 | } | 184 | } |
| 182 | return 0; | 185 | return max_bitflips; |
| 183 | } | 186 | } |
| 184 | 187 | ||
| 185 | /**************************************************************************** | 188 | /**************************************************************************** |
| @@ -188,10 +191,11 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, | |||
| 188 | * @mtd: mtd info structure | 191 | * @mtd: mtd info structure |
| 189 | * @chip: nand chip info structure | 192 | * @chip: nand chip info structure |
| 190 | * @buf: data buffer | 193 | * @buf: data buffer |
| 194 | * @oob_required: must write chip->oob_poi to OOB | ||
| 191 | * | 195 | * |
| 192 | ***************************************************************************/ | 196 | ***************************************************************************/ |
| 193 | static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, | 197 | static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, |
| 194 | struct nand_chip *chip, const uint8_t *buf) | 198 | struct nand_chip *chip, const uint8_t *buf, int oob_required) |
| 195 | { | 199 | { |
| 196 | int sectorIdx = 0; | 200 | int sectorIdx = 0; |
| 197 | int eccsize = chip->ecc.size; | 201 | int eccsize = chip->ecc.size; |
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 6908cdde3065..c855e7cd337b 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c | |||
| @@ -341,7 +341,7 @@ static int bcm_umi_nand_verify_buf(struct mtd_info *mtd, const u_char * buf, | |||
| 341 | * for MLC parts which may have permanently stuck bits. | 341 | * for MLC parts which may have permanently stuck bits. |
| 342 | */ | 342 | */ |
| 343 | struct nand_chip *chip = mtd->priv; | 343 | struct nand_chip *chip = mtd->priv; |
| 344 | int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0); | 344 | int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0, 0); |
| 345 | if (ret < 0) | 345 | if (ret < 0) |
| 346 | return -EFAULT; | 346 | return -EFAULT; |
| 347 | else { | 347 | else { |
| @@ -476,12 +476,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) | |||
| 476 | this->badblock_pattern = &largepage_bbt; | 476 | this->badblock_pattern = &largepage_bbt; |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | /* | 479 | this->ecc.strength = 8; |
| 480 | * FIXME: ecc strength value of 6 bits per 512 bytes of data is a | ||
| 481 | * conservative guess, given 13 ecc bytes and using bch alg. | ||
| 482 | * (Assume Galois field order m=15 to allow a margin of error.) | ||
| 483 | */ | ||
| 484 | this->ecc.strength = 6; | ||
| 485 | 480 | ||
| 486 | #endif | 481 | #endif |
| 487 | 482 | ||
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index d7b86b925de5..3f1c18599cbd 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
| @@ -558,7 +558,7 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, | |||
| 558 | } | 558 | } |
| 559 | 559 | ||
| 560 | static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 560 | static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
| 561 | uint8_t *buf, int page) | 561 | uint8_t *buf, int oob_required, int page) |
| 562 | { | 562 | { |
| 563 | bf5xx_nand_read_buf(mtd, buf, mtd->writesize); | 563 | bf5xx_nand_read_buf(mtd, buf, mtd->writesize); |
| 564 | bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); | 564 | bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); |
| @@ -567,7 +567,7 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip | |||
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 569 | static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
| 570 | const uint8_t *buf) | 570 | const uint8_t *buf, int oob_required) |
| 571 | { | 571 | { |
| 572 | bf5xx_nand_write_buf(mtd, buf, mtd->writesize); | 572 | bf5xx_nand_write_buf(mtd, buf, mtd->writesize); |
| 573 | bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); | 573 | bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 2a96e1a12062..41371ba1a811 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
| @@ -364,25 +364,27 @@ static int cafe_nand_write_oob(struct mtd_info *mtd, | |||
| 364 | 364 | ||
| 365 | /* Don't use -- use nand_read_oob_std for now */ | 365 | /* Don't use -- use nand_read_oob_std for now */ |
| 366 | static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | 366 | static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
| 367 | int page, int sndcmd) | 367 | int page) |
| 368 | { | 368 | { |
| 369 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | 369 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); |
| 370 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 370 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
| 371 | return 1; | 371 | return 0; |
| 372 | } | 372 | } |
| 373 | /** | 373 | /** |
| 374 | * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read | 374 | * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read |
| 375 | * @mtd: mtd info structure | 375 | * @mtd: mtd info structure |
| 376 | * @chip: nand chip info structure | 376 | * @chip: nand chip info structure |
| 377 | * @buf: buffer to store read data | 377 | * @buf: buffer to store read data |
| 378 | * @oob_required: caller expects OOB data read to chip->oob_poi | ||
| 378 | * | 379 | * |
| 379 | * The hw generator calculates the error syndrome automatically. Therefor | 380 | * The hw generator calculates the error syndrome automatically. Therefor |
| 380 | * we need a special oob layout and handling. | 381 | * we need a special oob layout and handling. |
| 381 | */ | 382 | */ |
| 382 | static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, | 383 | static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 383 | uint8_t *buf, int page) | 384 | uint8_t *buf, int oob_required, int page) |
| 384 | { | 385 | { |
| 385 | struct cafe_priv *cafe = mtd->priv; | 386 | struct cafe_priv *cafe = mtd->priv; |
| 387 | unsigned int max_bitflips = 0; | ||
| 386 | 388 | ||
| 387 | cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n", | 389 | cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n", |
| 388 | cafe_readl(cafe, NAND_ECC_RESULT), | 390 | cafe_readl(cafe, NAND_ECC_RESULT), |
| @@ -449,10 +451,11 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 449 | } else { | 451 | } else { |
| 450 | dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n); | 452 | dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n); |
| 451 | mtd->ecc_stats.corrected += n; | 453 | mtd->ecc_stats.corrected += n; |
| 454 | max_bitflips = max_t(unsigned int, max_bitflips, n); | ||
| 452 | } | 455 | } |
| 453 | } | 456 | } |
| 454 | 457 | ||
| 455 | return 0; | 458 | return max_bitflips; |
| 456 | } | 459 | } |
| 457 | 460 | ||
| 458 | static struct nand_ecclayout cafe_oobinfo_2048 = { | 461 | static struct nand_ecclayout cafe_oobinfo_2048 = { |
| @@ -518,7 +521,8 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = { | |||
| 518 | 521 | ||
| 519 | 522 | ||
| 520 | static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, | 523 | static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, |
| 521 | struct nand_chip *chip, const uint8_t *buf) | 524 | struct nand_chip *chip, |
| 525 | const uint8_t *buf, int oob_required) | ||
| 522 | { | 526 | { |
| 523 | struct cafe_priv *cafe = mtd->priv; | 527 | struct cafe_priv *cafe = mtd->priv; |
| 524 | 528 | ||
| @@ -530,16 +534,17 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, | |||
| 530 | } | 534 | } |
| 531 | 535 | ||
| 532 | static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | 536 | static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 533 | const uint8_t *buf, int page, int cached, int raw) | 537 | const uint8_t *buf, int oob_required, int page, |
| 538 | int cached, int raw) | ||
| 534 | { | 539 | { |
| 535 | int status; | 540 | int status; |
| 536 | 541 | ||
| 537 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); | 542 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); |
| 538 | 543 | ||
| 539 | if (unlikely(raw)) | 544 | if (unlikely(raw)) |
| 540 | chip->ecc.write_page_raw(mtd, chip, buf); | 545 | chip->ecc.write_page_raw(mtd, chip, buf, oob_required); |
| 541 | else | 546 | else |
| 542 | chip->ecc.write_page(mtd, chip, buf); | 547 | chip->ecc.write_page(mtd, chip, buf, oob_required); |
| 543 | 548 | ||
| 544 | /* | 549 | /* |
| 545 | * Cached progamming disabled for now, Not sure if its worth the | 550 | * Cached progamming disabled for now, Not sure if its worth the |
| @@ -685,7 +690,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
| 685 | 690 | ||
| 686 | /* Enable the following for a flash based bad block table */ | 691 | /* Enable the following for a flash based bad block table */ |
| 687 | cafe->nand.bbt_options = NAND_BBT_USE_FLASH; | 692 | cafe->nand.bbt_options = NAND_BBT_USE_FLASH; |
| 688 | cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; | 693 | cafe->nand.options = NAND_OWN_BUFFERS; |
| 689 | 694 | ||
| 690 | if (skipbbt) { | 695 | if (skipbbt) { |
| 691 | cafe->nand.options |= NAND_SKIP_BBTSCAN; | 696 | cafe->nand.options |= NAND_SKIP_BBTSCAN; |
| @@ -888,17 +893,7 @@ static struct pci_driver cafe_nand_pci_driver = { | |||
| 888 | .resume = cafe_nand_resume, | 893 | .resume = cafe_nand_resume, |
| 889 | }; | 894 | }; |
| 890 | 895 | ||
| 891 | static int __init cafe_nand_init(void) | 896 | module_pci_driver(cafe_nand_pci_driver); |
| 892 | { | ||
| 893 | return pci_register_driver(&cafe_nand_pci_driver); | ||
| 894 | } | ||
| 895 | |||
| 896 | static void __exit cafe_nand_exit(void) | ||
| 897 | { | ||
| 898 | pci_unregister_driver(&cafe_nand_pci_driver); | ||
| 899 | } | ||
| 900 | module_init(cafe_nand_init); | ||
| 901 | module_exit(cafe_nand_exit); | ||
| 902 | 897 | ||
| 903 | MODULE_LICENSE("GPL"); | 898 | MODULE_LICENSE("GPL"); |
| 904 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | 899 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); |
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 821c34c62500..adb6c3ef37fb 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c | |||
| @@ -240,7 +240,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) | |||
| 240 | 240 | ||
| 241 | /* Enable the following for a flash based bad block table */ | 241 | /* Enable the following for a flash based bad block table */ |
| 242 | this->bbt_options = NAND_BBT_USE_FLASH; | 242 | this->bbt_options = NAND_BBT_USE_FLASH; |
| 243 | this->options = NAND_NO_AUTOINCR; | ||
| 244 | 243 | ||
| 245 | /* Scan to find existence of the device */ | 244 | /* Scan to find existence of the device */ |
| 246 | if (nand_scan(new_mtd, 1)) { | 245 | if (nand_scan(new_mtd, 1)) { |
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index a9e57d686297..0650aafa0dd2 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c | |||
| @@ -924,9 +924,10 @@ bool is_erased(uint8_t *buf, int len) | |||
| 924 | #define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) | 924 | #define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) |
| 925 | 925 | ||
| 926 | static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, | 926 | static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, |
| 927 | uint32_t irq_status) | 927 | uint32_t irq_status, unsigned int *max_bitflips) |
| 928 | { | 928 | { |
| 929 | bool check_erased_page = false; | 929 | bool check_erased_page = false; |
| 930 | unsigned int bitflips = 0; | ||
| 930 | 931 | ||
| 931 | if (irq_status & INTR_STATUS__ECC_ERR) { | 932 | if (irq_status & INTR_STATUS__ECC_ERR) { |
| 932 | /* read the ECC errors. we'll ignore them for now */ | 933 | /* read the ECC errors. we'll ignore them for now */ |
| @@ -965,6 +966,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, | |||
| 965 | /* correct the ECC error */ | 966 | /* correct the ECC error */ |
| 966 | buf[offset] ^= err_correction_value; | 967 | buf[offset] ^= err_correction_value; |
| 967 | denali->mtd.ecc_stats.corrected++; | 968 | denali->mtd.ecc_stats.corrected++; |
| 969 | bitflips++; | ||
| 968 | } | 970 | } |
| 969 | } else { | 971 | } else { |
| 970 | /* if the error is not correctable, need to | 972 | /* if the error is not correctable, need to |
| @@ -984,6 +986,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, | |||
| 984 | clear_interrupts(denali); | 986 | clear_interrupts(denali); |
| 985 | denali_set_intr_modes(denali, true); | 987 | denali_set_intr_modes(denali, true); |
| 986 | } | 988 | } |
| 989 | *max_bitflips = bitflips; | ||
| 987 | return check_erased_page; | 990 | return check_erased_page; |
| 988 | } | 991 | } |
| 989 | 992 | ||
| @@ -1084,7 +1087,7 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1084 | * by write_page above. | 1087 | * by write_page above. |
| 1085 | * */ | 1088 | * */ |
| 1086 | static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, | 1089 | static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 1087 | const uint8_t *buf) | 1090 | const uint8_t *buf, int oob_required) |
| 1088 | { | 1091 | { |
| 1089 | /* for regular page writes, we let HW handle all the ECC | 1092 | /* for regular page writes, we let HW handle all the ECC |
| 1090 | * data written to the device. */ | 1093 | * data written to the device. */ |
| @@ -1096,7 +1099,7 @@ static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1096 | * write_page() function above. | 1099 | * write_page() function above. |
| 1097 | */ | 1100 | */ |
| 1098 | static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 1101 | static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
| 1099 | const uint8_t *buf) | 1102 | const uint8_t *buf, int oob_required) |
| 1100 | { | 1103 | { |
| 1101 | /* for raw page writes, we want to disable ECC and simply write | 1104 | /* for raw page writes, we want to disable ECC and simply write |
| 1102 | whatever data is in the buffer. */ | 1105 | whatever data is in the buffer. */ |
| @@ -1110,17 +1113,17 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1110 | } | 1113 | } |
| 1111 | 1114 | ||
| 1112 | static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | 1115 | static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
| 1113 | int page, int sndcmd) | 1116 | int page) |
| 1114 | { | 1117 | { |
| 1115 | read_oob_data(mtd, chip->oob_poi, page); | 1118 | read_oob_data(mtd, chip->oob_poi, page); |
| 1116 | 1119 | ||
| 1117 | return 0; /* notify NAND core to send command to | 1120 | return 0; |
| 1118 | NAND device. */ | ||
| 1119 | } | 1121 | } |
| 1120 | 1122 | ||
| 1121 | static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, | 1123 | static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 1122 | uint8_t *buf, int page) | 1124 | uint8_t *buf, int oob_required, int page) |
| 1123 | { | 1125 | { |
| 1126 | unsigned int max_bitflips; | ||
| 1124 | struct denali_nand_info *denali = mtd_to_denali(mtd); | 1127 | struct denali_nand_info *denali = mtd_to_denali(mtd); |
| 1125 | 1128 | ||
| 1126 | dma_addr_t addr = denali->buf.dma_buf; | 1129 | dma_addr_t addr = denali->buf.dma_buf; |
| @@ -1153,7 +1156,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1153 | 1156 | ||
| 1154 | memcpy(buf, denali->buf.buf, mtd->writesize); | 1157 | memcpy(buf, denali->buf.buf, mtd->writesize); |
| 1155 | 1158 | ||
| 1156 | check_erased_page = handle_ecc(denali, buf, irq_status); | 1159 | check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); |
| 1157 | denali_enable_dma(denali, false); | 1160 | denali_enable_dma(denali, false); |
| 1158 | 1161 | ||
| 1159 | if (check_erased_page) { | 1162 | if (check_erased_page) { |
| @@ -1167,11 +1170,11 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1167 | denali->mtd.ecc_stats.failed++; | 1170 | denali->mtd.ecc_stats.failed++; |
| 1168 | } | 1171 | } |
| 1169 | } | 1172 | } |
| 1170 | return 0; | 1173 | return max_bitflips; |
| 1171 | } | 1174 | } |
| 1172 | 1175 | ||
| 1173 | static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 1176 | static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
| 1174 | uint8_t *buf, int page) | 1177 | uint8_t *buf, int oob_required, int page) |
| 1175 | { | 1178 | { |
| 1176 | struct denali_nand_info *denali = mtd_to_denali(mtd); | 1179 | struct denali_nand_info *denali = mtd_to_denali(mtd); |
| 1177 | 1180 | ||
| @@ -1702,17 +1705,4 @@ static struct pci_driver denali_pci_driver = { | |||
| 1702 | .remove = denali_pci_remove, | 1705 | .remove = denali_pci_remove, |
| 1703 | }; | 1706 | }; |
| 1704 | 1707 | ||
| 1705 | static int __devinit denali_init(void) | 1708 | module_pci_driver(denali_pci_driver); |
| 1706 | { | ||
| 1707 | printk(KERN_INFO "Spectra MTD driver\n"); | ||
| 1708 | return pci_register_driver(&denali_pci_driver); | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | /* Free memory */ | ||
| 1712 | static void __devexit denali_exit(void) | ||
| 1713 | { | ||
| 1714 | pci_unregister_driver(&denali_pci_driver); | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | module_init(denali_init); | ||
| 1718 | module_exit(denali_exit); | ||
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index b08202664543..a225e49a5623 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c | |||
| @@ -720,6 +720,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, | |||
| 720 | struct docg4_priv *doc = nand->priv; | 720 | struct docg4_priv *doc = nand->priv; |
| 721 | void __iomem *docptr = doc->virtadr; | 721 | void __iomem *docptr = doc->virtadr; |
| 722 | uint16_t status, edc_err, *buf16; | 722 | uint16_t status, edc_err, *buf16; |
| 723 | int bits_corrected = 0; | ||
| 723 | 724 | ||
| 724 | dev_dbg(doc->dev, "%s: page %08x\n", __func__, page); | 725 | dev_dbg(doc->dev, "%s: page %08x\n", __func__, page); |
| 725 | 726 | ||
| @@ -772,7 +773,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, | |||
| 772 | 773 | ||
| 773 | /* If bitflips are reported, attempt to correct with ecc */ | 774 | /* If bitflips are reported, attempt to correct with ecc */ |
| 774 | if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) { | 775 | if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) { |
| 775 | int bits_corrected = correct_data(mtd, buf, page); | 776 | bits_corrected = correct_data(mtd, buf, page); |
| 776 | if (bits_corrected == -EBADMSG) | 777 | if (bits_corrected == -EBADMSG) |
| 777 | mtd->ecc_stats.failed++; | 778 | mtd->ecc_stats.failed++; |
| 778 | else | 779 | else |
| @@ -781,24 +782,24 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, | |||
| 781 | } | 782 | } |
| 782 | 783 | ||
| 783 | writew(0, docptr + DOC_DATAEND); | 784 | writew(0, docptr + DOC_DATAEND); |
| 784 | return 0; | 785 | return bits_corrected; |
| 785 | } | 786 | } |
| 786 | 787 | ||
| 787 | 788 | ||
| 788 | static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, | 789 | static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, |
| 789 | uint8_t *buf, int page) | 790 | uint8_t *buf, int oob_required, int page) |
| 790 | { | 791 | { |
| 791 | return read_page(mtd, nand, buf, page, false); | 792 | return read_page(mtd, nand, buf, page, false); |
| 792 | } | 793 | } |
| 793 | 794 | ||
| 794 | static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, | 795 | static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, |
| 795 | uint8_t *buf, int page) | 796 | uint8_t *buf, int oob_required, int page) |
| 796 | { | 797 | { |
| 797 | return read_page(mtd, nand, buf, page, true); | 798 | return read_page(mtd, nand, buf, page, true); |
| 798 | } | 799 | } |
| 799 | 800 | ||
| 800 | static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, | 801 | static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, |
| 801 | int page, int sndcmd) | 802 | int page) |
| 802 | { | 803 | { |
| 803 | struct docg4_priv *doc = nand->priv; | 804 | struct docg4_priv *doc = nand->priv; |
| 804 | void __iomem *docptr = doc->virtadr; | 805 | void __iomem *docptr = doc->virtadr; |
| @@ -952,13 +953,13 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand, | |||
| 952 | } | 953 | } |
| 953 | 954 | ||
| 954 | static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, | 955 | static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, |
| 955 | const uint8_t *buf) | 956 | const uint8_t *buf, int oob_required) |
| 956 | { | 957 | { |
| 957 | return write_page(mtd, nand, buf, false); | 958 | return write_page(mtd, nand, buf, false); |
| 958 | } | 959 | } |
| 959 | 960 | ||
| 960 | static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, | 961 | static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, |
| 961 | const uint8_t *buf) | 962 | const uint8_t *buf, int oob_required) |
| 962 | { | 963 | { |
| 963 | return write_page(mtd, nand, buf, true); | 964 | return write_page(mtd, nand, buf, true); |
| 964 | } | 965 | } |
| @@ -1002,7 +1003,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd) | |||
| 1002 | return -ENOMEM; | 1003 | return -ENOMEM; |
| 1003 | 1004 | ||
| 1004 | read_page_prologue(mtd, g4_addr); | 1005 | read_page_prologue(mtd, g4_addr); |
| 1005 | status = docg4_read_page(mtd, nand, buf, DOCG4_FACTORY_BBT_PAGE); | 1006 | status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); |
| 1006 | if (status) | 1007 | if (status) |
| 1007 | goto exit; | 1008 | goto exit; |
| 1008 | 1009 | ||
| @@ -1079,7 +1080,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
| 1079 | 1080 | ||
| 1080 | /* write first page of block */ | 1081 | /* write first page of block */ |
| 1081 | write_page_prologue(mtd, g4_addr); | 1082 | write_page_prologue(mtd, g4_addr); |
| 1082 | docg4_write_page(mtd, nand, buf); | 1083 | docg4_write_page(mtd, nand, buf, 1); |
| 1083 | ret = pageprog(mtd); | 1084 | ret = pageprog(mtd); |
| 1084 | if (!ret) | 1085 | if (!ret) |
| 1085 | mtd->ecc_stats.badblocks++; | 1086 | mtd->ecc_stats.badblocks++; |
| @@ -1192,8 +1193,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd) | |||
| 1192 | nand->ecc.prepad = 8; | 1193 | nand->ecc.prepad = 8; |
| 1193 | nand->ecc.bytes = 8; | 1194 | nand->ecc.bytes = 8; |
| 1194 | nand->ecc.strength = DOCG4_T; | 1195 | nand->ecc.strength = DOCG4_T; |
| 1195 | nand->options = | 1196 | nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE; |
| 1196 | NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR; | ||
| 1197 | nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; | 1197 | nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; |
| 1198 | nand->controller = &nand->hwcontrol; | 1198 | nand->controller = &nand->hwcontrol; |
| 1199 | spin_lock_init(&nand->controller->lock); | 1199 | spin_lock_init(&nand->controller->lock); |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 80b5264f0a32..784293806110 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
| @@ -75,6 +75,7 @@ struct fsl_elbc_fcm_ctrl { | |||
| 75 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ | 75 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ |
| 76 | unsigned int oob; /* Non zero if operating on OOB data */ | 76 | unsigned int oob; /* Non zero if operating on OOB data */ |
| 77 | unsigned int counter; /* counter for the initializations */ | 77 | unsigned int counter; /* counter for the initializations */ |
| 78 | unsigned int max_bitflips; /* Saved during READ0 cmd */ | ||
| 78 | }; | 79 | }; |
| 79 | 80 | ||
| 80 | /* These map to the positions used by the FCM hardware ECC generator */ | 81 | /* These map to the positions used by the FCM hardware ECC generator */ |
| @@ -253,6 +254,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
| 253 | if (chip->ecc.mode != NAND_ECC_HW) | 254 | if (chip->ecc.mode != NAND_ECC_HW) |
| 254 | return 0; | 255 | return 0; |
| 255 | 256 | ||
| 257 | elbc_fcm_ctrl->max_bitflips = 0; | ||
| 258 | |||
| 256 | if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { | 259 | if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { |
| 257 | uint32_t lteccr = in_be32(&lbc->lteccr); | 260 | uint32_t lteccr = in_be32(&lbc->lteccr); |
| 258 | /* | 261 | /* |
| @@ -262,11 +265,16 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
| 262 | * bits 28-31 are uncorrectable errors, marked elsewhere. | 265 | * bits 28-31 are uncorrectable errors, marked elsewhere. |
| 263 | * for small page nand only 1 bit is used. | 266 | * for small page nand only 1 bit is used. |
| 264 | * if the ELBC doesn't have the lteccr register it reads 0 | 267 | * if the ELBC doesn't have the lteccr register it reads 0 |
| 268 | * FIXME: 4 bits can be corrected on NANDs with 2k pages, so | ||
| 269 | * count the number of sub-pages with bitflips and update | ||
| 270 | * ecc_stats.corrected accordingly. | ||
| 265 | */ | 271 | */ |
| 266 | if (lteccr & 0x000F000F) | 272 | if (lteccr & 0x000F000F) |
| 267 | out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ | 273 | out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ |
| 268 | if (lteccr & 0x000F0000) | 274 | if (lteccr & 0x000F0000) { |
| 269 | mtd->ecc_stats.corrected++; | 275 | mtd->ecc_stats.corrected++; |
| 276 | elbc_fcm_ctrl->max_bitflips = 1; | ||
| 277 | } | ||
| 270 | } | 278 | } |
| 271 | 279 | ||
| 272 | return 0; | 280 | return 0; |
| @@ -738,26 +746,28 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
| 738 | return 0; | 746 | return 0; |
| 739 | } | 747 | } |
| 740 | 748 | ||
| 741 | static int fsl_elbc_read_page(struct mtd_info *mtd, | 749 | static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 742 | struct nand_chip *chip, | 750 | uint8_t *buf, int oob_required, int page) |
| 743 | uint8_t *buf, | ||
| 744 | int page) | ||
| 745 | { | 751 | { |
| 752 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 753 | struct fsl_lbc_ctrl *ctrl = priv->ctrl; | ||
| 754 | struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; | ||
| 755 | |||
| 746 | fsl_elbc_read_buf(mtd, buf, mtd->writesize); | 756 | fsl_elbc_read_buf(mtd, buf, mtd->writesize); |
| 747 | fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | 757 | if (oob_required) |
| 758 | fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 748 | 759 | ||
| 749 | if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) | 760 | if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) |
| 750 | mtd->ecc_stats.failed++; | 761 | mtd->ecc_stats.failed++; |
| 751 | 762 | ||
| 752 | return 0; | 763 | return elbc_fcm_ctrl->max_bitflips; |
| 753 | } | 764 | } |
| 754 | 765 | ||
| 755 | /* ECC will be calculated automatically, and errors will be detected in | 766 | /* ECC will be calculated automatically, and errors will be detected in |
| 756 | * waitfunc. | 767 | * waitfunc. |
| 757 | */ | 768 | */ |
| 758 | static void fsl_elbc_write_page(struct mtd_info *mtd, | 769 | static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 759 | struct nand_chip *chip, | 770 | const uint8_t *buf, int oob_required) |
| 760 | const uint8_t *buf) | ||
| 761 | { | 771 | { |
| 762 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); | 772 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); |
| 763 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); | 773 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); |
| @@ -795,7 +805,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
| 795 | chip->bbt_md = &bbt_mirror_descr; | 805 | chip->bbt_md = &bbt_mirror_descr; |
| 796 | 806 | ||
| 797 | /* set up nand options */ | 807 | /* set up nand options */ |
| 798 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; | 808 | chip->options = NAND_NO_READRDY; |
| 799 | chip->bbt_options = NAND_BBT_USE_FLASH; | 809 | chip->bbt_options = NAND_BBT_USE_FLASH; |
| 800 | 810 | ||
| 801 | chip->controller = &elbc_fcm_ctrl->controller; | 811 | chip->controller = &elbc_fcm_ctrl->controller; |
| @@ -814,11 +824,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
| 814 | chip->ecc.size = 512; | 824 | chip->ecc.size = 512; |
| 815 | chip->ecc.bytes = 3; | 825 | chip->ecc.bytes = 3; |
| 816 | chip->ecc.strength = 1; | 826 | chip->ecc.strength = 1; |
| 817 | /* | ||
| 818 | * FIXME: can hardware ecc correct 4 bitflips if page size is | ||
| 819 | * 2k? Then does hardware report number of corrections for this | ||
| 820 | * case? If so, ecc_stats reporting needs to be fixed as well. | ||
| 821 | */ | ||
| 822 | } else { | 827 | } else { |
| 823 | /* otherwise fall back to default software ECC */ | 828 | /* otherwise fall back to default software ECC */ |
| 824 | chip->ecc.mode = NAND_ECC_SOFT; | 829 | chip->ecc.mode = NAND_ECC_SOFT; |
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index c30ac7b83d28..9602c1b7e27e 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c | |||
| @@ -63,6 +63,7 @@ struct fsl_ifc_nand_ctrl { | |||
| 63 | unsigned int oob; /* Non zero if operating on OOB data */ | 63 | unsigned int oob; /* Non zero if operating on OOB data */ |
| 64 | unsigned int eccread; /* Non zero for a full-page ECC read */ | 64 | unsigned int eccread; /* Non zero for a full-page ECC read */ |
| 65 | unsigned int counter; /* counter for the initializations */ | 65 | unsigned int counter; /* counter for the initializations */ |
| 66 | unsigned int max_bitflips; /* Saved during READ0 cmd */ | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl; | 69 | static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl; |
| @@ -262,6 +263,8 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) | |||
| 262 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER) | 263 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER) |
| 263 | dev_err(priv->dev, "NAND Flash Write Protect Error\n"); | 264 | dev_err(priv->dev, "NAND Flash Write Protect Error\n"); |
| 264 | 265 | ||
| 266 | nctrl->max_bitflips = 0; | ||
| 267 | |||
| 265 | if (nctrl->eccread) { | 268 | if (nctrl->eccread) { |
| 266 | int errors; | 269 | int errors; |
| 267 | int bufnum = nctrl->page & priv->bufnum_mask; | 270 | int bufnum = nctrl->page & priv->bufnum_mask; |
| @@ -290,6 +293,9 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) | |||
| 290 | } | 293 | } |
| 291 | 294 | ||
| 292 | mtd->ecc_stats.corrected += errors; | 295 | mtd->ecc_stats.corrected += errors; |
| 296 | nctrl->max_bitflips = max_t(unsigned int, | ||
| 297 | nctrl->max_bitflips, | ||
| 298 | errors); | ||
| 293 | } | 299 | } |
| 294 | 300 | ||
| 295 | nctrl->eccread = 0; | 301 | nctrl->eccread = 0; |
| @@ -375,21 +381,31 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
| 375 | 381 | ||
| 376 | return; | 382 | return; |
| 377 | 383 | ||
| 378 | /* READID must read all 8 possible bytes */ | ||
| 379 | case NAND_CMD_READID: | 384 | case NAND_CMD_READID: |
| 385 | case NAND_CMD_PARAM: { | ||
| 386 | int timing = IFC_FIR_OP_RB; | ||
| 387 | if (command == NAND_CMD_PARAM) | ||
| 388 | timing = IFC_FIR_OP_RBCD; | ||
| 389 | |||
| 380 | out_be32(&ifc->ifc_nand.nand_fir0, | 390 | out_be32(&ifc->ifc_nand.nand_fir0, |
| 381 | (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | | 391 | (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | |
| 382 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | | 392 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | |
| 383 | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); | 393 | (timing << IFC_NAND_FIR0_OP2_SHIFT)); |
| 384 | out_be32(&ifc->ifc_nand.nand_fcr0, | 394 | out_be32(&ifc->ifc_nand.nand_fcr0, |
| 385 | NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); | 395 | command << IFC_NAND_FCR0_CMD0_SHIFT); |
| 386 | /* 8 bytes for manuf, device and exts */ | 396 | out_be32(&ifc->ifc_nand.row3, column); |
| 387 | out_be32(&ifc->ifc_nand.nand_fbcr, 8); | 397 | |
| 388 | ifc_nand_ctrl->read_bytes = 8; | 398 | /* |
| 399 | * although currently it's 8 bytes for READID, we always read | ||
| 400 | * the maximum 256 bytes(for PARAM) | ||
| 401 | */ | ||
| 402 | out_be32(&ifc->ifc_nand.nand_fbcr, 256); | ||
| 403 | ifc_nand_ctrl->read_bytes = 256; | ||
| 389 | 404 | ||
| 390 | set_addr(mtd, 0, 0, 0); | 405 | set_addr(mtd, 0, 0, 0); |
| 391 | fsl_ifc_run_command(mtd); | 406 | fsl_ifc_run_command(mtd); |
| 392 | return; | 407 | return; |
| 408 | } | ||
| 393 | 409 | ||
| 394 | /* ERASE1 stores the block and page address */ | 410 | /* ERASE1 stores the block and page address */ |
| 395 | case NAND_CMD_ERASE1: | 411 | case NAND_CMD_ERASE1: |
| @@ -682,15 +698,16 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
| 682 | return nand_fsr | NAND_STATUS_WP; | 698 | return nand_fsr | NAND_STATUS_WP; |
| 683 | } | 699 | } |
| 684 | 700 | ||
| 685 | static int fsl_ifc_read_page(struct mtd_info *mtd, | 701 | static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 686 | struct nand_chip *chip, | 702 | uint8_t *buf, int oob_required, int page) |
| 687 | uint8_t *buf, int page) | ||
| 688 | { | 703 | { |
| 689 | struct fsl_ifc_mtd *priv = chip->priv; | 704 | struct fsl_ifc_mtd *priv = chip->priv; |
| 690 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | 705 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; |
| 706 | struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; | ||
| 691 | 707 | ||
| 692 | fsl_ifc_read_buf(mtd, buf, mtd->writesize); | 708 | fsl_ifc_read_buf(mtd, buf, mtd->writesize); |
| 693 | fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | 709 | if (oob_required) |
| 710 | fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 694 | 711 | ||
| 695 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) | 712 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) |
| 696 | dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n"); | 713 | dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n"); |
| @@ -698,15 +715,14 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, | |||
| 698 | if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) | 715 | if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) |
| 699 | mtd->ecc_stats.failed++; | 716 | mtd->ecc_stats.failed++; |
| 700 | 717 | ||
| 701 | return 0; | 718 | return nctrl->max_bitflips; |
| 702 | } | 719 | } |
| 703 | 720 | ||
| 704 | /* ECC will be calculated automatically, and errors will be detected in | 721 | /* ECC will be calculated automatically, and errors will be detected in |
| 705 | * waitfunc. | 722 | * waitfunc. |
| 706 | */ | 723 | */ |
| 707 | static void fsl_ifc_write_page(struct mtd_info *mtd, | 724 | static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 708 | struct nand_chip *chip, | 725 | const uint8_t *buf, int oob_required) |
| 709 | const uint8_t *buf) | ||
| 710 | { | 726 | { |
| 711 | fsl_ifc_write_buf(mtd, buf, mtd->writesize); | 727 | fsl_ifc_write_buf(mtd, buf, mtd->writesize); |
| 712 | fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); | 728 | fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); |
| @@ -789,7 +805,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) | |||
| 789 | out_be32(&ifc->ifc_nand.ncfgr, 0x0); | 805 | out_be32(&ifc->ifc_nand.ncfgr, 0x0); |
| 790 | 806 | ||
| 791 | /* set up nand options */ | 807 | /* set up nand options */ |
| 792 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; | 808 | chip->options = NAND_NO_READRDY; |
| 793 | chip->bbt_options = NAND_BBT_USE_FLASH; | 809 | chip->bbt_options = NAND_BBT_USE_FLASH; |
| 794 | 810 | ||
| 795 | 811 | ||
| @@ -811,6 +827,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) | |||
| 811 | /* Hardware generates ECC per 512 Bytes */ | 827 | /* Hardware generates ECC per 512 Bytes */ |
| 812 | chip->ecc.size = 512; | 828 | chip->ecc.size = 512; |
| 813 | chip->ecc.bytes = 8; | 829 | chip->ecc.bytes = 8; |
| 830 | chip->ecc.strength = 4; | ||
| 814 | 831 | ||
| 815 | switch (csor & CSOR_NAND_PGS_MASK) { | 832 | switch (csor & CSOR_NAND_PGS_MASK) { |
| 816 | case CSOR_NAND_PGS_512: | 833 | case CSOR_NAND_PGS_512: |
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 1b8330e1155a..38d26240d8b1 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c | |||
| @@ -692,6 +692,7 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, | |||
| 692 | * @mtd: mtd info structure | 692 | * @mtd: mtd info structure |
| 693 | * @chip: nand chip info structure | 693 | * @chip: nand chip info structure |
| 694 | * @buf: buffer to store read data | 694 | * @buf: buffer to store read data |
| 695 | * @oob_required: caller expects OOB data read to chip->oob_poi | ||
| 695 | * @page: page number to read | 696 | * @page: page number to read |
| 696 | * | 697 | * |
| 697 | * This routine is needed for fsmc version 8 as reading from NAND chip has to be | 698 | * This routine is needed for fsmc version 8 as reading from NAND chip has to be |
| @@ -701,7 +702,7 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, | |||
| 701 | * max of 8 bits) | 702 | * max of 8 bits) |
| 702 | */ | 703 | */ |
| 703 | static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 704 | static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 704 | uint8_t *buf, int page) | 705 | uint8_t *buf, int oob_required, int page) |
| 705 | { | 706 | { |
| 706 | struct fsmc_nand_data *host = container_of(mtd, | 707 | struct fsmc_nand_data *host = container_of(mtd, |
| 707 | struct fsmc_nand_data, mtd); | 708 | struct fsmc_nand_data, mtd); |
| @@ -720,6 +721,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 720 | */ | 721 | */ |
| 721 | uint16_t ecc_oob[7]; | 722 | uint16_t ecc_oob[7]; |
| 722 | uint8_t *oob = (uint8_t *)&ecc_oob[0]; | 723 | uint8_t *oob = (uint8_t *)&ecc_oob[0]; |
| 724 | unsigned int max_bitflips = 0; | ||
| 723 | 725 | ||
| 724 | for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { | 726 | for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { |
| 725 | chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); | 727 | chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); |
| @@ -748,13 +750,15 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 748 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | 750 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
| 749 | 751 | ||
| 750 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); | 752 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); |
| 751 | if (stat < 0) | 753 | if (stat < 0) { |
| 752 | mtd->ecc_stats.failed++; | 754 | mtd->ecc_stats.failed++; |
| 753 | else | 755 | } else { |
| 754 | mtd->ecc_stats.corrected += stat; | 756 | mtd->ecc_stats.corrected += stat; |
| 757 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 758 | } | ||
| 755 | } | 759 | } |
| 756 | 760 | ||
| 757 | return 0; | 761 | return max_bitflips; |
| 758 | } | 762 | } |
| 759 | 763 | ||
| 760 | /* | 764 | /* |
| @@ -994,9 +998,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
| 994 | return PTR_ERR(host->clk); | 998 | return PTR_ERR(host->clk); |
| 995 | } | 999 | } |
| 996 | 1000 | ||
| 997 | ret = clk_enable(host->clk); | 1001 | ret = clk_prepare_enable(host->clk); |
| 998 | if (ret) | 1002 | if (ret) |
| 999 | goto err_clk_enable; | 1003 | goto err_clk_prepare_enable; |
| 1000 | 1004 | ||
| 1001 | /* | 1005 | /* |
| 1002 | * This device ID is actually a common AMBA ID as used on the | 1006 | * This device ID is actually a common AMBA ID as used on the |
| @@ -1176,8 +1180,8 @@ err_req_write_chnl: | |||
| 1176 | if (host->mode == USE_DMA_ACCESS) | 1180 | if (host->mode == USE_DMA_ACCESS) |
| 1177 | dma_release_channel(host->read_dma_chan); | 1181 | dma_release_channel(host->read_dma_chan); |
| 1178 | err_req_read_chnl: | 1182 | err_req_read_chnl: |
| 1179 | clk_disable(host->clk); | 1183 | clk_disable_unprepare(host->clk); |
| 1180 | err_clk_enable: | 1184 | err_clk_prepare_enable: |
| 1181 | clk_put(host->clk); | 1185 | clk_put(host->clk); |
| 1182 | return ret; | 1186 | return ret; |
| 1183 | } | 1187 | } |
| @@ -1198,7 +1202,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) | |||
| 1198 | dma_release_channel(host->write_dma_chan); | 1202 | dma_release_channel(host->write_dma_chan); |
| 1199 | dma_release_channel(host->read_dma_chan); | 1203 | dma_release_channel(host->read_dma_chan); |
| 1200 | } | 1204 | } |
| 1201 | clk_disable(host->clk); | 1205 | clk_disable_unprepare(host->clk); |
| 1202 | clk_put(host->clk); | 1206 | clk_put(host->clk); |
| 1203 | } | 1207 | } |
| 1204 | 1208 | ||
| @@ -1210,7 +1214,7 @@ static int fsmc_nand_suspend(struct device *dev) | |||
| 1210 | { | 1214 | { |
| 1211 | struct fsmc_nand_data *host = dev_get_drvdata(dev); | 1215 | struct fsmc_nand_data *host = dev_get_drvdata(dev); |
| 1212 | if (host) | 1216 | if (host) |
| 1213 | clk_disable(host->clk); | 1217 | clk_disable_unprepare(host->clk); |
| 1214 | return 0; | 1218 | return 0; |
| 1215 | } | 1219 | } |
| 1216 | 1220 | ||
| @@ -1218,7 +1222,7 @@ static int fsmc_nand_resume(struct device *dev) | |||
| 1218 | { | 1222 | { |
| 1219 | struct fsmc_nand_data *host = dev_get_drvdata(dev); | 1223 | struct fsmc_nand_data *host = dev_get_drvdata(dev); |
| 1220 | if (host) { | 1224 | if (host) { |
| 1221 | clk_enable(host->clk); | 1225 | clk_prepare_enable(host->clk); |
| 1222 | fsmc_nand_setup(host->regs_va, host->bank, | 1226 | fsmc_nand_setup(host->regs_va, host->bank, |
| 1223 | host->nand.options & NAND_BUSWIDTH_16, | 1227 | host->nand.options & NAND_BUSWIDTH_16, |
| 1224 | host->dev_timings); | 1228 | host->dev_timings); |
diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h index 4effb8c579db..a0924515c396 100644 --- a/drivers/mtd/nand/gpmi-nand/bch-regs.h +++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h | |||
| @@ -51,15 +51,26 @@ | |||
| 51 | 51 | ||
| 52 | #define BP_BCH_FLASH0LAYOUT0_ECC0 12 | 52 | #define BP_BCH_FLASH0LAYOUT0_ECC0 12 |
| 53 | #define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0) | 53 | #define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0) |
| 54 | #define BF_BCH_FLASH0LAYOUT0_ECC0(v) \ | 54 | #define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0 11 |
| 55 | (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0) | 55 | #define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0 (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0) |
| 56 | #define BF_BCH_FLASH0LAYOUT0_ECC0(v, x) \ | ||
| 57 | (GPMI_IS_MX6Q(x) \ | ||
| 58 | ? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0) \ | ||
| 59 | & MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0) \ | ||
| 60 | : (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) \ | ||
| 61 | & BM_BCH_FLASH0LAYOUT0_ECC0) \ | ||
| 62 | ) | ||
| 56 | 63 | ||
| 57 | #define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 | 64 | #define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 |
| 58 | #define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ | 65 | #define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ |
| 59 | (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) | 66 | (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) |
| 60 | #define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \ | 67 | #define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ |
| 61 | (((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\ | 68 | (0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) |
| 62 | & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) | 69 | #define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x) \ |
| 70 | (GPMI_IS_MX6Q(x) \ | ||
| 71 | ? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \ | ||
| 72 | : ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \ | ||
| 73 | ) | ||
| 63 | 74 | ||
| 64 | #define HW_BCH_FLASH0LAYOUT1 0x00000090 | 75 | #define HW_BCH_FLASH0LAYOUT1 0x00000090 |
| 65 | 76 | ||
| @@ -72,13 +83,24 @@ | |||
| 72 | 83 | ||
| 73 | #define BP_BCH_FLASH0LAYOUT1_ECCN 12 | 84 | #define BP_BCH_FLASH0LAYOUT1_ECCN 12 |
| 74 | #define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN) | 85 | #define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN) |
| 75 | #define BF_BCH_FLASH0LAYOUT1_ECCN(v) \ | 86 | #define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN 11 |
| 76 | (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN) | 87 | #define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN) |
| 88 | #define BF_BCH_FLASH0LAYOUT1_ECCN(v, x) \ | ||
| 89 | (GPMI_IS_MX6Q(x) \ | ||
| 90 | ? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN) \ | ||
| 91 | & MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN) \ | ||
| 92 | : (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) \ | ||
| 93 | & BM_BCH_FLASH0LAYOUT1_ECCN) \ | ||
| 94 | ) | ||
| 77 | 95 | ||
| 78 | #define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 | 96 | #define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 |
| 79 | #define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ | 97 | #define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ |
| 80 | (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) | 98 | (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) |
| 81 | #define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \ | 99 | #define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ |
| 82 | (((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ | 100 | (0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) |
| 83 | & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) | 101 | #define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x) \ |
| 102 | (GPMI_IS_MX6Q(x) \ | ||
| 103 | ? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ | ||
| 104 | : ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ | ||
| 105 | ) | ||
| 84 | #endif | 106 | #endif |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index e8ea7107932e..a1f43329ad43 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include <linux/mtd/gpmi-nand.h> | 21 | #include <linux/mtd/gpmi-nand.h> |
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
| 24 | #include <mach/mxs.h> | ||
| 25 | 24 | ||
| 26 | #include "gpmi-nand.h" | 25 | #include "gpmi-nand.h" |
| 27 | #include "gpmi-regs.h" | 26 | #include "gpmi-regs.h" |
| @@ -37,6 +36,8 @@ struct timing_threshod timing_default_threshold = { | |||
| 37 | .max_dll_delay_in_ns = 16, | 36 | .max_dll_delay_in_ns = 16, |
| 38 | }; | 37 | }; |
| 39 | 38 | ||
| 39 | #define MXS_SET_ADDR 0x4 | ||
| 40 | #define MXS_CLR_ADDR 0x8 | ||
| 40 | /* | 41 | /* |
| 41 | * Clear the bit and poll it cleared. This is usually called with | 42 | * Clear the bit and poll it cleared. This is usually called with |
| 42 | * a reset address and mask being either SFTRST(bit 31) or CLKGATE | 43 | * a reset address and mask being either SFTRST(bit 31) or CLKGATE |
| @@ -47,7 +48,7 @@ static int clear_poll_bit(void __iomem *addr, u32 mask) | |||
| 47 | int timeout = 0x400; | 48 | int timeout = 0x400; |
| 48 | 49 | ||
| 49 | /* clear the bit */ | 50 | /* clear the bit */ |
| 50 | __mxs_clrl(mask, addr); | 51 | writel(mask, addr + MXS_CLR_ADDR); |
| 51 | 52 | ||
| 52 | /* | 53 | /* |
| 53 | * SFTRST needs 3 GPMI clocks to settle, the reference manual | 54 | * SFTRST needs 3 GPMI clocks to settle, the reference manual |
| @@ -92,11 +93,11 @@ static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) | |||
| 92 | goto error; | 93 | goto error; |
| 93 | 94 | ||
| 94 | /* clear CLKGATE */ | 95 | /* clear CLKGATE */ |
| 95 | __mxs_clrl(MODULE_CLKGATE, reset_addr); | 96 | writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); |
| 96 | 97 | ||
| 97 | if (!just_enable) { | 98 | if (!just_enable) { |
| 98 | /* set SFTRST to reset the block */ | 99 | /* set SFTRST to reset the block */ |
| 99 | __mxs_setl(MODULE_SFTRST, reset_addr); | 100 | writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR); |
| 100 | udelay(1); | 101 | udelay(1); |
| 101 | 102 | ||
| 102 | /* poll CLKGATE becoming set */ | 103 | /* poll CLKGATE becoming set */ |
| @@ -223,13 +224,13 @@ int bch_set_geometry(struct gpmi_nand_data *this) | |||
| 223 | /* Configure layout 0. */ | 224 | /* Configure layout 0. */ |
| 224 | writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) | 225 | writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) |
| 225 | | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) | 226 | | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) |
| 226 | | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) | 227 | | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) |
| 227 | | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), | 228 | | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this), |
| 228 | r->bch_regs + HW_BCH_FLASH0LAYOUT0); | 229 | r->bch_regs + HW_BCH_FLASH0LAYOUT0); |
| 229 | 230 | ||
| 230 | writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) | 231 | writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
| 231 | | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) | 232 | | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) |
| 232 | | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size), | 233 | | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this), |
| 233 | r->bch_regs + HW_BCH_FLASH0LAYOUT1); | 234 | r->bch_regs + HW_BCH_FLASH0LAYOUT1); |
| 234 | 235 | ||
| 235 | /* Set *all* chip selects to use layout 0. */ | 236 | /* Set *all* chip selects to use layout 0. */ |
| @@ -255,11 +256,12 @@ static unsigned int ns_to_cycles(unsigned int time, | |||
| 255 | return max(k, min); | 256 | return max(k, min); |
| 256 | } | 257 | } |
| 257 | 258 | ||
| 259 | #define DEF_MIN_PROP_DELAY 5 | ||
| 260 | #define DEF_MAX_PROP_DELAY 9 | ||
| 258 | /* Apply timing to current hardware conditions. */ | 261 | /* Apply timing to current hardware conditions. */ |
| 259 | static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, | 262 | static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, |
| 260 | struct gpmi_nfc_hardware_timing *hw) | 263 | struct gpmi_nfc_hardware_timing *hw) |
| 261 | { | 264 | { |
| 262 | struct gpmi_nand_platform_data *pdata = this->pdata; | ||
| 263 | struct timing_threshod *nfc = &timing_default_threshold; | 265 | struct timing_threshod *nfc = &timing_default_threshold; |
| 264 | struct nand_chip *nand = &this->nand; | 266 | struct nand_chip *nand = &this->nand; |
| 265 | struct nand_timing target = this->timing; | 267 | struct nand_timing target = this->timing; |
| @@ -276,8 +278,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, | |||
| 276 | int ideal_sample_delay_in_ns; | 278 | int ideal_sample_delay_in_ns; |
| 277 | unsigned int sample_delay_factor; | 279 | unsigned int sample_delay_factor; |
| 278 | int tEYE; | 280 | int tEYE; |
| 279 | unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; | 281 | unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY; |
| 280 | unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; | 282 | unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY; |
| 281 | 283 | ||
| 282 | /* | 284 | /* |
| 283 | * If there are multiple chips, we need to relax the timings to allow | 285 | * If there are multiple chips, we need to relax the timings to allow |
| @@ -803,7 +805,8 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) | |||
| 803 | if (GPMI_IS_MX23(this)) { | 805 | if (GPMI_IS_MX23(this)) { |
| 804 | mask = MX23_BM_GPMI_DEBUG_READY0 << chip; | 806 | mask = MX23_BM_GPMI_DEBUG_READY0 << chip; |
| 805 | reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); | 807 | reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); |
| 806 | } else if (GPMI_IS_MX28(this)) { | 808 | } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6Q(this)) { |
| 809 | /* MX28 shares the same R/B register as MX6Q. */ | ||
| 807 | mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); | 810 | mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); |
| 808 | reg = readl(r->gpmi_regs + HW_GPMI_STAT); | 811 | reg = readl(r->gpmi_regs + HW_GPMI_STAT); |
| 809 | } else | 812 | } else |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index b68e04310bd8..a05b7b444d4f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
| @@ -25,6 +25,8 @@ | |||
| 25 | #include <linux/mtd/gpmi-nand.h> | 25 | #include <linux/mtd/gpmi-nand.h> |
| 26 | #include <linux/mtd/partitions.h> | 26 | #include <linux/mtd/partitions.h> |
| 27 | #include <linux/pinctrl/consumer.h> | 27 | #include <linux/pinctrl/consumer.h> |
| 28 | #include <linux/of.h> | ||
| 29 | #include <linux/of_device.h> | ||
| 28 | #include "gpmi-nand.h" | 30 | #include "gpmi-nand.h" |
| 29 | 31 | ||
| 30 | /* add our owner bbt descriptor */ | 32 | /* add our owner bbt descriptor */ |
| @@ -387,7 +389,7 @@ static void release_bch_irq(struct gpmi_nand_data *this) | |||
| 387 | static bool gpmi_dma_filter(struct dma_chan *chan, void *param) | 389 | static bool gpmi_dma_filter(struct dma_chan *chan, void *param) |
| 388 | { | 390 | { |
| 389 | struct gpmi_nand_data *this = param; | 391 | struct gpmi_nand_data *this = param; |
| 390 | struct resource *r = this->private; | 392 | int dma_channel = (int)this->private; |
| 391 | 393 | ||
| 392 | if (!mxs_dma_is_apbh(chan)) | 394 | if (!mxs_dma_is_apbh(chan)) |
| 393 | return false; | 395 | return false; |
| @@ -399,7 +401,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param) | |||
| 399 | * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 | 401 | * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 |
| 400 | * (These eight channels share the same IRQ!) | 402 | * (These eight channels share the same IRQ!) |
| 401 | */ | 403 | */ |
| 402 | if (r->start <= chan->chan_id && chan->chan_id <= r->end) { | 404 | if (dma_channel == chan->chan_id) { |
| 403 | chan->private = &this->dma_data; | 405 | chan->private = &this->dma_data; |
| 404 | return true; | 406 | return true; |
| 405 | } | 407 | } |
| @@ -419,57 +421,45 @@ static void release_dma_channels(struct gpmi_nand_data *this) | |||
| 419 | static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) | 421 | static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) |
| 420 | { | 422 | { |
| 421 | struct platform_device *pdev = this->pdev; | 423 | struct platform_device *pdev = this->pdev; |
| 422 | struct gpmi_nand_platform_data *pdata = this->pdata; | 424 | struct resource *r_dma; |
| 423 | struct resources *res = &this->resources; | 425 | struct device_node *dn; |
| 424 | struct resource *r, *r_dma; | 426 | int dma_channel; |
| 425 | unsigned int i; | 427 | unsigned int ret; |
| 428 | struct dma_chan *dma_chan; | ||
| 429 | dma_cap_mask_t mask; | ||
| 430 | |||
| 431 | /* dma channel, we only use the first one. */ | ||
| 432 | dn = pdev->dev.of_node; | ||
| 433 | ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel); | ||
| 434 | if (ret) { | ||
| 435 | pr_err("unable to get DMA channel from dt.\n"); | ||
| 436 | goto acquire_err; | ||
| 437 | } | ||
| 438 | this->private = (void *)dma_channel; | ||
| 426 | 439 | ||
| 427 | r = platform_get_resource_byname(pdev, IORESOURCE_DMA, | 440 | /* gpmi dma interrupt */ |
| 428 | GPMI_NAND_DMA_CHANNELS_RES_NAME); | ||
| 429 | r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | 441 | r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, |
| 430 | GPMI_NAND_DMA_INTERRUPT_RES_NAME); | 442 | GPMI_NAND_DMA_INTERRUPT_RES_NAME); |
| 431 | if (!r || !r_dma) { | 443 | if (!r_dma) { |
| 432 | pr_err("Can't get resource for DMA\n"); | 444 | pr_err("Can't get resource for DMA\n"); |
| 433 | return -ENXIO; | 445 | goto acquire_err; |
| 434 | } | 446 | } |
| 447 | this->dma_data.chan_irq = r_dma->start; | ||
| 435 | 448 | ||
| 436 | /* used in gpmi_dma_filter() */ | 449 | /* request dma channel */ |
| 437 | this->private = r; | 450 | dma_cap_zero(mask); |
| 438 | 451 | dma_cap_set(DMA_SLAVE, mask); | |
| 439 | for (i = r->start; i <= r->end; i++) { | ||
| 440 | struct dma_chan *dma_chan; | ||
| 441 | dma_cap_mask_t mask; | ||
| 442 | 452 | ||
| 443 | if (i - r->start >= pdata->max_chip_count) | 453 | dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); |
| 444 | break; | 454 | if (!dma_chan) { |
| 445 | 455 | pr_err("dma_request_channel failed.\n"); | |
| 446 | dma_cap_zero(mask); | 456 | goto acquire_err; |
| 447 | dma_cap_set(DMA_SLAVE, mask); | ||
| 448 | |||
| 449 | /* get the DMA interrupt */ | ||
| 450 | if (r_dma->start == r_dma->end) { | ||
| 451 | /* only register the first. */ | ||
| 452 | if (i == r->start) | ||
| 453 | this->dma_data.chan_irq = r_dma->start; | ||
| 454 | else | ||
| 455 | this->dma_data.chan_irq = NO_IRQ; | ||
| 456 | } else | ||
| 457 | this->dma_data.chan_irq = r_dma->start + (i - r->start); | ||
| 458 | |||
| 459 | dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); | ||
| 460 | if (!dma_chan) | ||
| 461 | goto acquire_err; | ||
| 462 | |||
| 463 | /* fill the first empty item */ | ||
| 464 | this->dma_chans[i - r->start] = dma_chan; | ||
| 465 | } | 457 | } |
| 466 | 458 | ||
| 467 | res->dma_low_channel = r->start; | 459 | this->dma_chans[0] = dma_chan; |
| 468 | res->dma_high_channel = i; | ||
| 469 | return 0; | 460 | return 0; |
| 470 | 461 | ||
| 471 | acquire_err: | 462 | acquire_err: |
| 472 | pr_err("Can't acquire DMA channel %u\n", i); | ||
| 473 | release_dma_channels(this); | 463 | release_dma_channels(this); |
| 474 | return -EINVAL; | 464 | return -EINVAL; |
| 475 | } | 465 | } |
| @@ -851,7 +841,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this, | |||
| 851 | } | 841 | } |
| 852 | 842 | ||
| 853 | static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, | 843 | static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 854 | uint8_t *buf, int page) | 844 | uint8_t *buf, int oob_required, int page) |
| 855 | { | 845 | { |
| 856 | struct gpmi_nand_data *this = chip->priv; | 846 | struct gpmi_nand_data *this = chip->priv; |
| 857 | struct bch_geometry *nfc_geo = &this->bch_geometry; | 847 | struct bch_geometry *nfc_geo = &this->bch_geometry; |
| @@ -917,28 +907,31 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 917 | mtd->ecc_stats.corrected += corrected; | 907 | mtd->ecc_stats.corrected += corrected; |
| 918 | } | 908 | } |
| 919 | 909 | ||
| 920 | /* | 910 | if (oob_required) { |
| 921 | * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for | 911 | /* |
| 922 | * details about our policy for delivering the OOB. | 912 | * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() |
| 923 | * | 913 | * for details about our policy for delivering the OOB. |
| 924 | * We fill the caller's buffer with set bits, and then copy the block | 914 | * |
| 925 | * mark to th caller's buffer. Note that, if block mark swapping was | 915 | * We fill the caller's buffer with set bits, and then copy the |
| 926 | * necessary, it has already been done, so we can rely on the first | 916 | * block mark to th caller's buffer. Note that, if block mark |
| 927 | * byte of the auxiliary buffer to contain the block mark. | 917 | * swapping was necessary, it has already been done, so we can |
| 928 | */ | 918 | * rely on the first byte of the auxiliary buffer to contain |
| 929 | memset(chip->oob_poi, ~0, mtd->oobsize); | 919 | * the block mark. |
| 930 | chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; | 920 | */ |
| 921 | memset(chip->oob_poi, ~0, mtd->oobsize); | ||
| 922 | chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; | ||
| 931 | 923 | ||
| 932 | read_page_swap_end(this, buf, mtd->writesize, | 924 | read_page_swap_end(this, buf, mtd->writesize, |
| 933 | this->payload_virt, this->payload_phys, | 925 | this->payload_virt, this->payload_phys, |
| 934 | nfc_geo->payload_size, | 926 | nfc_geo->payload_size, |
| 935 | payload_virt, payload_phys); | 927 | payload_virt, payload_phys); |
| 928 | } | ||
| 936 | exit_nfc: | 929 | exit_nfc: |
| 937 | return ret; | 930 | return ret; |
| 938 | } | 931 | } |
| 939 | 932 | ||
| 940 | static void gpmi_ecc_write_page(struct mtd_info *mtd, | 933 | static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 941 | struct nand_chip *chip, const uint8_t *buf) | 934 | const uint8_t *buf, int oob_required) |
| 942 | { | 935 | { |
| 943 | struct gpmi_nand_data *this = chip->priv; | 936 | struct gpmi_nand_data *this = chip->priv; |
| 944 | struct bch_geometry *nfc_geo = &this->bch_geometry; | 937 | struct bch_geometry *nfc_geo = &this->bch_geometry; |
| @@ -1077,7 +1070,7 @@ exit_auxiliary: | |||
| 1077 | * this driver. | 1070 | * this driver. |
| 1078 | */ | 1071 | */ |
| 1079 | static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | 1072 | static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
| 1080 | int page, int sndcmd) | 1073 | int page) |
| 1081 | { | 1074 | { |
| 1082 | struct gpmi_nand_data *this = chip->priv; | 1075 | struct gpmi_nand_data *this = chip->priv; |
| 1083 | 1076 | ||
| @@ -1100,11 +1093,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1100 | chip->oob_poi[0] = chip->read_byte(mtd); | 1093 | chip->oob_poi[0] = chip->read_byte(mtd); |
| 1101 | } | 1094 | } |
| 1102 | 1095 | ||
| 1103 | /* | 1096 | return 0; |
| 1104 | * Return true, indicating that the next call to this function must send | ||
| 1105 | * a command. | ||
| 1106 | */ | ||
| 1107 | return true; | ||
| 1108 | } | 1097 | } |
| 1109 | 1098 | ||
| 1110 | static int | 1099 | static int |
| @@ -1318,7 +1307,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) | |||
| 1318 | /* Write the first page of the current stride. */ | 1307 | /* Write the first page of the current stride. */ |
| 1319 | dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); | 1308 | dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); |
| 1320 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); | 1309 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); |
| 1321 | chip->ecc.write_page_raw(mtd, chip, buffer); | 1310 | chip->ecc.write_page_raw(mtd, chip, buffer, 0); |
| 1322 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | 1311 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); |
| 1323 | 1312 | ||
| 1324 | /* Wait for the write to finish. */ | 1313 | /* Wait for the write to finish. */ |
| @@ -1444,6 +1433,10 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) | |||
| 1444 | if (ret) | 1433 | if (ret) |
| 1445 | return ret; | 1434 | return ret; |
| 1446 | 1435 | ||
| 1436 | /* Adjust the ECC strength according to the chip. */ | ||
| 1437 | this->nand.ecc.strength = this->bch_geometry.ecc_strength; | ||
| 1438 | this->mtd.ecc_strength = this->bch_geometry.ecc_strength; | ||
| 1439 | |||
| 1447 | /* NAND boot init, depends on the gpmi_set_geometry(). */ | 1440 | /* NAND boot init, depends on the gpmi_set_geometry(). */ |
| 1448 | return nand_boot_init(this); | 1441 | return nand_boot_init(this); |
| 1449 | } | 1442 | } |
| @@ -1471,9 +1464,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this) | |||
| 1471 | 1464 | ||
| 1472 | static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) | 1465 | static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) |
| 1473 | { | 1466 | { |
| 1474 | struct gpmi_nand_platform_data *pdata = this->pdata; | ||
| 1475 | struct mtd_info *mtd = &this->mtd; | 1467 | struct mtd_info *mtd = &this->mtd; |
| 1476 | struct nand_chip *chip = &this->nand; | 1468 | struct nand_chip *chip = &this->nand; |
| 1469 | struct mtd_part_parser_data ppdata = {}; | ||
| 1477 | int ret; | 1470 | int ret; |
| 1478 | 1471 | ||
| 1479 | /* init current chip */ | 1472 | /* init current chip */ |
| @@ -1502,6 +1495,7 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) | |||
| 1502 | chip->options |= NAND_NO_SUBPAGE_WRITE; | 1495 | chip->options |= NAND_NO_SUBPAGE_WRITE; |
| 1503 | chip->ecc.mode = NAND_ECC_HW; | 1496 | chip->ecc.mode = NAND_ECC_HW; |
| 1504 | chip->ecc.size = 1; | 1497 | chip->ecc.size = 1; |
| 1498 | chip->ecc.strength = 8; | ||
| 1505 | chip->ecc.layout = &gpmi_hw_ecclayout; | 1499 | chip->ecc.layout = &gpmi_hw_ecclayout; |
| 1506 | 1500 | ||
| 1507 | /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ | 1501 | /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ |
| @@ -1511,14 +1505,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) | |||
| 1511 | if (ret) | 1505 | if (ret) |
| 1512 | goto err_out; | 1506 | goto err_out; |
| 1513 | 1507 | ||
| 1514 | ret = nand_scan(mtd, pdata->max_chip_count); | 1508 | ret = nand_scan(mtd, 1); |
| 1515 | if (ret) { | 1509 | if (ret) { |
| 1516 | pr_err("Chip scan failed\n"); | 1510 | pr_err("Chip scan failed\n"); |
| 1517 | goto err_out; | 1511 | goto err_out; |
| 1518 | } | 1512 | } |
| 1519 | 1513 | ||
| 1520 | ret = mtd_device_parse_register(mtd, NULL, NULL, | 1514 | ppdata.of_node = this->pdev->dev.of_node; |
| 1521 | pdata->partitions, pdata->partition_count); | 1515 | ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); |
| 1522 | if (ret) | 1516 | if (ret) |
| 1523 | goto err_out; | 1517 | goto err_out; |
| 1524 | return 0; | 1518 | return 0; |
| @@ -1528,12 +1522,41 @@ err_out: | |||
| 1528 | return ret; | 1522 | return ret; |
| 1529 | } | 1523 | } |
| 1530 | 1524 | ||
| 1525 | static const struct platform_device_id gpmi_ids[] = { | ||
| 1526 | { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, }, | ||
| 1527 | { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, }, | ||
| 1528 | { .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, }, | ||
| 1529 | {}, | ||
| 1530 | }; | ||
| 1531 | |||
| 1532 | static const struct of_device_id gpmi_nand_id_table[] = { | ||
| 1533 | { | ||
| 1534 | .compatible = "fsl,imx23-gpmi-nand", | ||
| 1535 | .data = (void *)&gpmi_ids[IS_MX23] | ||
| 1536 | }, { | ||
| 1537 | .compatible = "fsl,imx28-gpmi-nand", | ||
| 1538 | .data = (void *)&gpmi_ids[IS_MX28] | ||
| 1539 | }, { | ||
| 1540 | .compatible = "fsl,imx6q-gpmi-nand", | ||
| 1541 | .data = (void *)&gpmi_ids[IS_MX6Q] | ||
| 1542 | }, {} | ||
| 1543 | }; | ||
| 1544 | MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); | ||
| 1545 | |||
| 1531 | static int __devinit gpmi_nand_probe(struct platform_device *pdev) | 1546 | static int __devinit gpmi_nand_probe(struct platform_device *pdev) |
| 1532 | { | 1547 | { |
| 1533 | struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data; | ||
| 1534 | struct gpmi_nand_data *this; | 1548 | struct gpmi_nand_data *this; |
| 1549 | const struct of_device_id *of_id; | ||
| 1535 | int ret; | 1550 | int ret; |
| 1536 | 1551 | ||
| 1552 | of_id = of_match_device(gpmi_nand_id_table, &pdev->dev); | ||
| 1553 | if (of_id) { | ||
| 1554 | pdev->id_entry = of_id->data; | ||
| 1555 | } else { | ||
| 1556 | pr_err("Failed to find the right device id.\n"); | ||
| 1557 | return -ENOMEM; | ||
| 1558 | } | ||
| 1559 | |||
| 1537 | this = kzalloc(sizeof(*this), GFP_KERNEL); | 1560 | this = kzalloc(sizeof(*this), GFP_KERNEL); |
| 1538 | if (!this) { | 1561 | if (!this) { |
| 1539 | pr_err("Failed to allocate per-device memory\n"); | 1562 | pr_err("Failed to allocate per-device memory\n"); |
| @@ -1543,13 +1566,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev) | |||
| 1543 | platform_set_drvdata(pdev, this); | 1566 | platform_set_drvdata(pdev, this); |
| 1544 | this->pdev = pdev; | 1567 | this->pdev = pdev; |
| 1545 | this->dev = &pdev->dev; | 1568 | this->dev = &pdev->dev; |
| 1546 | this->pdata = pdata; | ||
| 1547 | |||
| 1548 | if (pdata->platform_init) { | ||
| 1549 | ret = pdata->platform_init(); | ||
| 1550 | if (ret) | ||
| 1551 | goto platform_init_error; | ||
| 1552 | } | ||
| 1553 | 1569 | ||
| 1554 | ret = acquire_resources(this); | 1570 | ret = acquire_resources(this); |
| 1555 | if (ret) | 1571 | if (ret) |
| @@ -1567,7 +1583,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev) | |||
| 1567 | 1583 | ||
| 1568 | exit_nfc_init: | 1584 | exit_nfc_init: |
| 1569 | release_resources(this); | 1585 | release_resources(this); |
| 1570 | platform_init_error: | ||
| 1571 | exit_acquire_resources: | 1586 | exit_acquire_resources: |
| 1572 | platform_set_drvdata(pdev, NULL); | 1587 | platform_set_drvdata(pdev, NULL); |
| 1573 | kfree(this); | 1588 | kfree(this); |
| @@ -1585,19 +1600,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev) | |||
| 1585 | return 0; | 1600 | return 0; |
| 1586 | } | 1601 | } |
| 1587 | 1602 | ||
| 1588 | static const struct platform_device_id gpmi_ids[] = { | ||
| 1589 | { | ||
| 1590 | .name = "imx23-gpmi-nand", | ||
| 1591 | .driver_data = IS_MX23, | ||
| 1592 | }, { | ||
| 1593 | .name = "imx28-gpmi-nand", | ||
| 1594 | .driver_data = IS_MX28, | ||
| 1595 | }, {}, | ||
| 1596 | }; | ||
| 1597 | |||
| 1598 | static struct platform_driver gpmi_nand_driver = { | 1603 | static struct platform_driver gpmi_nand_driver = { |
| 1599 | .driver = { | 1604 | .driver = { |
| 1600 | .name = "gpmi-nand", | 1605 | .name = "gpmi-nand", |
| 1606 | .of_match_table = gpmi_nand_id_table, | ||
| 1601 | }, | 1607 | }, |
| 1602 | .probe = gpmi_nand_probe, | 1608 | .probe = gpmi_nand_probe, |
| 1603 | .remove = __exit_p(gpmi_nand_remove), | 1609 | .remove = __exit_p(gpmi_nand_remove), |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index ec6180d4ff8f..ce5daa160920 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h | |||
| @@ -266,8 +266,10 @@ extern int gpmi_read_page(struct gpmi_nand_data *, | |||
| 266 | #define STATUS_UNCORRECTABLE 0xfe | 266 | #define STATUS_UNCORRECTABLE 0xfe |
| 267 | 267 | ||
| 268 | /* Use the platform_id to distinguish different Archs. */ | 268 | /* Use the platform_id to distinguish different Archs. */ |
| 269 | #define IS_MX23 0x1 | 269 | #define IS_MX23 0x0 |
| 270 | #define IS_MX28 0x2 | 270 | #define IS_MX28 0x1 |
| 271 | #define IS_MX6Q 0x2 | ||
| 271 | #define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) | 272 | #define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) |
| 272 | #define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) | 273 | #define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) |
| 274 | #define GPMI_IS_MX6Q(x) ((x)->pdev->id_entry->driver_data == IS_MX6Q) | ||
| 273 | #endif | 275 | #endif |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 9bf5ce5fa22d..50166e93ba96 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
| @@ -124,7 +124,6 @@ static int __init h1910_init(void) | |||
| 124 | /* 15 us command delay time */ | 124 | /* 15 us command delay time */ |
| 125 | this->chip_delay = 50; | 125 | this->chip_delay = 50; |
| 126 | this->ecc.mode = NAND_ECC_SOFT; | 126 | this->ecc.mode = NAND_ECC_SOFT; |
| 127 | this->options = NAND_NO_AUTOINCR; | ||
| 128 | 127 | ||
| 129 | /* Scan to find existence of the device */ | 128 | /* Scan to find existence of the device */ |
| 130 | if (nand_scan(h1910_nand_mtd, 1)) { | 129 | if (nand_scan(h1910_nand_mtd, 1)) { |
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index e4147e8acb7c..a6fa884ae49b 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c | |||
| @@ -332,11 +332,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) | |||
| 332 | chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; | 332 | chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; |
| 333 | chip->ecc.size = 512; | 333 | chip->ecc.size = 512; |
| 334 | chip->ecc.bytes = 9; | 334 | chip->ecc.bytes = 9; |
| 335 | chip->ecc.strength = 2; | 335 | chip->ecc.strength = 4; |
| 336 | /* | ||
| 337 | * FIXME: ecc_strength value of 2 bits per 512 bytes of data is a | ||
| 338 | * conservative guess, given 9 ecc bytes and reed-solomon alg. | ||
| 339 | */ | ||
| 340 | 336 | ||
| 341 | if (pdata) | 337 | if (pdata) |
| 342 | chip->ecc.layout = pdata->ecc_layout; | 338 | chip->ecc.layout = pdata->ecc_layout; |
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index c240cf1af961..c259c24d7986 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c | |||
| @@ -734,7 +734,6 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) | |||
| 734 | chip->write_buf = mpc5121_nfc_write_buf; | 734 | chip->write_buf = mpc5121_nfc_write_buf; |
| 735 | chip->verify_buf = mpc5121_nfc_verify_buf; | 735 | chip->verify_buf = mpc5121_nfc_verify_buf; |
| 736 | chip->select_chip = mpc5121_nfc_select_chip; | 736 | chip->select_chip = mpc5121_nfc_select_chip; |
| 737 | chip->options = NAND_NO_AUTOINCR; | ||
| 738 | chip->bbt_options = NAND_BBT_USE_FLASH; | 737 | chip->bbt_options = NAND_BBT_USE_FLASH; |
| 739 | chip->ecc.mode = NAND_ECC_SOFT; | 738 | chip->ecc.mode = NAND_ECC_SOFT; |
| 740 | 739 | ||
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 9e374e9bd296..c58e6a93f445 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
| @@ -32,6 +32,8 @@ | |||
| 32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
| 33 | #include <linux/irq.h> | 33 | #include <linux/irq.h> |
| 34 | #include <linux/completion.h> | 34 | #include <linux/completion.h> |
| 35 | #include <linux/of_device.h> | ||
| 36 | #include <linux/of_mtd.h> | ||
| 35 | 37 | ||
| 36 | #include <asm/mach/flash.h> | 38 | #include <asm/mach/flash.h> |
| 37 | #include <mach/mxc_nand.h> | 39 | #include <mach/mxc_nand.h> |
| @@ -140,13 +142,47 @@ | |||
| 140 | 142 | ||
| 141 | #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) | 143 | #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) |
| 142 | 144 | ||
| 145 | struct mxc_nand_host; | ||
| 146 | |||
| 147 | struct mxc_nand_devtype_data { | ||
| 148 | void (*preset)(struct mtd_info *); | ||
| 149 | void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); | ||
| 150 | void (*send_addr)(struct mxc_nand_host *, uint16_t, int); | ||
| 151 | void (*send_page)(struct mtd_info *, unsigned int); | ||
| 152 | void (*send_read_id)(struct mxc_nand_host *); | ||
| 153 | uint16_t (*get_dev_status)(struct mxc_nand_host *); | ||
| 154 | int (*check_int)(struct mxc_nand_host *); | ||
| 155 | void (*irq_control)(struct mxc_nand_host *, int); | ||
| 156 | u32 (*get_ecc_status)(struct mxc_nand_host *); | ||
| 157 | struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k; | ||
| 158 | void (*select_chip)(struct mtd_info *mtd, int chip); | ||
| 159 | int (*correct_data)(struct mtd_info *mtd, u_char *dat, | ||
| 160 | u_char *read_ecc, u_char *calc_ecc); | ||
| 161 | |||
| 162 | /* | ||
| 163 | * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked | ||
| 164 | * (CONFIG1:INT_MSK is set). To handle this the driver uses | ||
| 165 | * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK | ||
| 166 | */ | ||
| 167 | int irqpending_quirk; | ||
| 168 | int needs_ip; | ||
| 169 | |||
| 170 | size_t regs_offset; | ||
| 171 | size_t spare0_offset; | ||
| 172 | size_t axi_offset; | ||
| 173 | |||
| 174 | int spare_len; | ||
| 175 | int eccbytes; | ||
| 176 | int eccsize; | ||
| 177 | }; | ||
| 178 | |||
| 143 | struct mxc_nand_host { | 179 | struct mxc_nand_host { |
| 144 | struct mtd_info mtd; | 180 | struct mtd_info mtd; |
| 145 | struct nand_chip nand; | 181 | struct nand_chip nand; |
| 146 | struct device *dev; | 182 | struct device *dev; |
| 147 | 183 | ||
| 148 | void *spare0; | 184 | void __iomem *spare0; |
| 149 | void *main_area0; | 185 | void __iomem *main_area0; |
| 150 | 186 | ||
| 151 | void __iomem *base; | 187 | void __iomem *base; |
| 152 | void __iomem *regs; | 188 | void __iomem *regs; |
| @@ -163,16 +199,9 @@ struct mxc_nand_host { | |||
| 163 | 199 | ||
| 164 | uint8_t *data_buf; | 200 | uint8_t *data_buf; |
| 165 | unsigned int buf_start; | 201 | unsigned int buf_start; |
| 166 | int spare_len; | 202 | |
| 167 | 203 | const struct mxc_nand_devtype_data *devtype_data; | |
| 168 | void (*preset)(struct mtd_info *); | 204 | struct mxc_nand_platform_data pdata; |
| 169 | void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); | ||
| 170 | void (*send_addr)(struct mxc_nand_host *, uint16_t, int); | ||
| 171 | void (*send_page)(struct mtd_info *, unsigned int); | ||
| 172 | void (*send_read_id)(struct mxc_nand_host *); | ||
| 173 | uint16_t (*get_dev_status)(struct mxc_nand_host *); | ||
| 174 | int (*check_int)(struct mxc_nand_host *); | ||
| 175 | void (*irq_control)(struct mxc_nand_host *, int); | ||
| 176 | }; | 205 | }; |
| 177 | 206 | ||
| 178 | /* OOB placement block for use with hardware ecc generation */ | 207 | /* OOB placement block for use with hardware ecc generation */ |
| @@ -242,21 +271,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { | |||
| 242 | } | 271 | } |
| 243 | }; | 272 | }; |
| 244 | 273 | ||
| 245 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 274 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL }; |
| 246 | |||
| 247 | static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | ||
| 248 | { | ||
| 249 | struct mxc_nand_host *host = dev_id; | ||
| 250 | |||
| 251 | if (!host->check_int(host)) | ||
| 252 | return IRQ_NONE; | ||
| 253 | |||
| 254 | host->irq_control(host, 0); | ||
| 255 | |||
| 256 | complete(&host->op_completion); | ||
| 257 | |||
| 258 | return IRQ_HANDLED; | ||
| 259 | } | ||
| 260 | 275 | ||
| 261 | static int check_int_v3(struct mxc_nand_host *host) | 276 | static int check_int_v3(struct mxc_nand_host *host) |
| 262 | { | 277 | { |
| @@ -280,26 +295,12 @@ static int check_int_v1_v2(struct mxc_nand_host *host) | |||
| 280 | if (!(tmp & NFC_V1_V2_CONFIG2_INT)) | 295 | if (!(tmp & NFC_V1_V2_CONFIG2_INT)) |
| 281 | return 0; | 296 | return 0; |
| 282 | 297 | ||
| 283 | if (!cpu_is_mx21()) | 298 | if (!host->devtype_data->irqpending_quirk) |
| 284 | writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); | 299 | writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); |
| 285 | 300 | ||
| 286 | return 1; | 301 | return 1; |
| 287 | } | 302 | } |
| 288 | 303 | ||
| 289 | /* | ||
| 290 | * It has been observed that the i.MX21 cannot read the CONFIG2:INT bit | ||
| 291 | * if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the | ||
| 292 | * driver can enable/disable the irq line rather than simply masking the | ||
| 293 | * interrupts. | ||
| 294 | */ | ||
| 295 | static void irq_control_mx21(struct mxc_nand_host *host, int activate) | ||
| 296 | { | ||
| 297 | if (activate) | ||
| 298 | enable_irq(host->irq); | ||
| 299 | else | ||
| 300 | disable_irq_nosync(host->irq); | ||
| 301 | } | ||
| 302 | |||
| 303 | static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) | 304 | static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) |
| 304 | { | 305 | { |
| 305 | uint16_t tmp; | 306 | uint16_t tmp; |
| @@ -328,6 +329,47 @@ static void irq_control_v3(struct mxc_nand_host *host, int activate) | |||
| 328 | writel(tmp, NFC_V3_CONFIG2); | 329 | writel(tmp, NFC_V3_CONFIG2); |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 332 | static void irq_control(struct mxc_nand_host *host, int activate) | ||
| 333 | { | ||
| 334 | if (host->devtype_data->irqpending_quirk) { | ||
| 335 | if (activate) | ||
| 336 | enable_irq(host->irq); | ||
| 337 | else | ||
| 338 | disable_irq_nosync(host->irq); | ||
| 339 | } else { | ||
| 340 | host->devtype_data->irq_control(host, activate); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | static u32 get_ecc_status_v1(struct mxc_nand_host *host) | ||
| 345 | { | ||
| 346 | return readw(NFC_V1_V2_ECC_STATUS_RESULT); | ||
| 347 | } | ||
| 348 | |||
| 349 | static u32 get_ecc_status_v2(struct mxc_nand_host *host) | ||
| 350 | { | ||
| 351 | return readl(NFC_V1_V2_ECC_STATUS_RESULT); | ||
| 352 | } | ||
| 353 | |||
| 354 | static u32 get_ecc_status_v3(struct mxc_nand_host *host) | ||
| 355 | { | ||
| 356 | return readl(NFC_V3_ECC_STATUS_RESULT); | ||
| 357 | } | ||
| 358 | |||
| 359 | static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | ||
| 360 | { | ||
| 361 | struct mxc_nand_host *host = dev_id; | ||
| 362 | |||
| 363 | if (!host->devtype_data->check_int(host)) | ||
| 364 | return IRQ_NONE; | ||
| 365 | |||
| 366 | irq_control(host, 0); | ||
| 367 | |||
| 368 | complete(&host->op_completion); | ||
| 369 | |||
| 370 | return IRQ_HANDLED; | ||
| 371 | } | ||
| 372 | |||
| 331 | /* This function polls the NANDFC to wait for the basic operation to | 373 | /* This function polls the NANDFC to wait for the basic operation to |
| 332 | * complete by checking the INT bit of config2 register. | 374 | * complete by checking the INT bit of config2 register. |
| 333 | */ | 375 | */ |
| @@ -336,14 +378,14 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) | |||
| 336 | int max_retries = 8000; | 378 | int max_retries = 8000; |
| 337 | 379 | ||
| 338 | if (useirq) { | 380 | if (useirq) { |
| 339 | if (!host->check_int(host)) { | 381 | if (!host->devtype_data->check_int(host)) { |
| 340 | INIT_COMPLETION(host->op_completion); | 382 | INIT_COMPLETION(host->op_completion); |
| 341 | host->irq_control(host, 1); | 383 | irq_control(host, 1); |
| 342 | wait_for_completion(&host->op_completion); | 384 | wait_for_completion(&host->op_completion); |
| 343 | } | 385 | } |
| 344 | } else { | 386 | } else { |
| 345 | while (max_retries-- > 0) { | 387 | while (max_retries-- > 0) { |
| 346 | if (host->check_int(host)) | 388 | if (host->devtype_data->check_int(host)) |
| 347 | break; | 389 | break; |
| 348 | 390 | ||
| 349 | udelay(1); | 391 | udelay(1); |
| @@ -374,7 +416,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
| 374 | writew(cmd, NFC_V1_V2_FLASH_CMD); | 416 | writew(cmd, NFC_V1_V2_FLASH_CMD); |
| 375 | writew(NFC_CMD, NFC_V1_V2_CONFIG2); | 417 | writew(NFC_CMD, NFC_V1_V2_CONFIG2); |
| 376 | 418 | ||
| 377 | if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { | 419 | if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) { |
| 378 | int max_retries = 100; | 420 | int max_retries = 100; |
| 379 | /* Reset completion is indicated by NFC_CONFIG2 */ | 421 | /* Reset completion is indicated by NFC_CONFIG2 */ |
| 380 | /* being set to 0 */ | 422 | /* being set to 0 */ |
| @@ -433,13 +475,27 @@ static void send_page_v3(struct mtd_info *mtd, unsigned int ops) | |||
| 433 | wait_op_done(host, false); | 475 | wait_op_done(host, false); |
| 434 | } | 476 | } |
| 435 | 477 | ||
| 436 | static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops) | 478 | static void send_page_v2(struct mtd_info *mtd, unsigned int ops) |
| 479 | { | ||
| 480 | struct nand_chip *nand_chip = mtd->priv; | ||
| 481 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 482 | |||
| 483 | /* NANDFC buffer 0 is used for page read/write */ | ||
| 484 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); | ||
| 485 | |||
| 486 | writew(ops, NFC_V1_V2_CONFIG2); | ||
| 487 | |||
| 488 | /* Wait for operation to complete */ | ||
| 489 | wait_op_done(host, true); | ||
| 490 | } | ||
| 491 | |||
| 492 | static void send_page_v1(struct mtd_info *mtd, unsigned int ops) | ||
| 437 | { | 493 | { |
| 438 | struct nand_chip *nand_chip = mtd->priv; | 494 | struct nand_chip *nand_chip = mtd->priv; |
| 439 | struct mxc_nand_host *host = nand_chip->priv; | 495 | struct mxc_nand_host *host = nand_chip->priv; |
| 440 | int bufs, i; | 496 | int bufs, i; |
| 441 | 497 | ||
| 442 | if (nfc_is_v1() && mtd->writesize > 512) | 498 | if (mtd->writesize > 512) |
| 443 | bufs = 4; | 499 | bufs = 4; |
| 444 | else | 500 | else |
| 445 | bufs = 1; | 501 | bufs = 1; |
| @@ -463,7 +519,7 @@ static void send_read_id_v3(struct mxc_nand_host *host) | |||
| 463 | 519 | ||
| 464 | wait_op_done(host, true); | 520 | wait_op_done(host, true); |
| 465 | 521 | ||
| 466 | memcpy(host->data_buf, host->main_area0, 16); | 522 | memcpy_fromio(host->data_buf, host->main_area0, 16); |
| 467 | } | 523 | } |
| 468 | 524 | ||
| 469 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 525 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
| @@ -479,7 +535,7 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) | |||
| 479 | /* Wait for operation to complete */ | 535 | /* Wait for operation to complete */ |
| 480 | wait_op_done(host, true); | 536 | wait_op_done(host, true); |
| 481 | 537 | ||
| 482 | memcpy(host->data_buf, host->main_area0, 16); | 538 | memcpy_fromio(host->data_buf, host->main_area0, 16); |
| 483 | 539 | ||
| 484 | if (this->options & NAND_BUSWIDTH_16) { | 540 | if (this->options & NAND_BUSWIDTH_16) { |
| 485 | /* compress the ID info */ | 541 | /* compress the ID info */ |
| @@ -555,7 +611,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, | |||
| 555 | * additional correction. 2-Bit errors cannot be corrected by | 611 | * additional correction. 2-Bit errors cannot be corrected by |
| 556 | * HW ECC, so we need to return failure | 612 | * HW ECC, so we need to return failure |
| 557 | */ | 613 | */ |
| 558 | uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT); | 614 | uint16_t ecc_status = get_ecc_status_v1(host); |
| 559 | 615 | ||
| 560 | if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { | 616 | if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { |
| 561 | pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); | 617 | pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); |
| @@ -580,10 +636,7 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, | |||
| 580 | 636 | ||
| 581 | no_subpages = mtd->writesize >> 9; | 637 | no_subpages = mtd->writesize >> 9; |
| 582 | 638 | ||
| 583 | if (nfc_is_v21()) | 639 | ecc_stat = host->devtype_data->get_ecc_status(host); |
| 584 | ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT); | ||
| 585 | else | ||
| 586 | ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT); | ||
| 587 | 640 | ||
| 588 | do { | 641 | do { |
| 589 | err = ecc_stat & ecc_bit_mask; | 642 | err = ecc_stat & ecc_bit_mask; |
| @@ -616,7 +669,7 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
| 616 | 669 | ||
| 617 | /* Check for status request */ | 670 | /* Check for status request */ |
| 618 | if (host->status_request) | 671 | if (host->status_request) |
| 619 | return host->get_dev_status(host) & 0xFF; | 672 | return host->devtype_data->get_dev_status(host) & 0xFF; |
| 620 | 673 | ||
| 621 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | 674 | ret = *(uint8_t *)(host->data_buf + host->buf_start); |
| 622 | host->buf_start++; | 675 | host->buf_start++; |
| @@ -682,7 +735,7 @@ static int mxc_nand_verify_buf(struct mtd_info *mtd, | |||
| 682 | 735 | ||
| 683 | /* This function is used by upper layer for select and | 736 | /* This function is used by upper layer for select and |
| 684 | * deselect of the NAND chip */ | 737 | * deselect of the NAND chip */ |
| 685 | static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | 738 | static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) |
| 686 | { | 739 | { |
| 687 | struct nand_chip *nand_chip = mtd->priv; | 740 | struct nand_chip *nand_chip = mtd->priv; |
| 688 | struct mxc_nand_host *host = nand_chip->priv; | 741 | struct mxc_nand_host *host = nand_chip->priv; |
| @@ -701,11 +754,30 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | |||
| 701 | clk_prepare_enable(host->clk); | 754 | clk_prepare_enable(host->clk); |
| 702 | host->clk_act = 1; | 755 | host->clk_act = 1; |
| 703 | } | 756 | } |
| 757 | } | ||
| 704 | 758 | ||
| 705 | if (nfc_is_v21()) { | 759 | static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) |
| 706 | host->active_cs = chip; | 760 | { |
| 707 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); | 761 | struct nand_chip *nand_chip = mtd->priv; |
| 762 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 763 | |||
| 764 | if (chip == -1) { | ||
| 765 | /* Disable the NFC clock */ | ||
| 766 | if (host->clk_act) { | ||
| 767 | clk_disable(host->clk); | ||
| 768 | host->clk_act = 0; | ||
| 769 | } | ||
| 770 | return; | ||
| 771 | } | ||
| 772 | |||
| 773 | if (!host->clk_act) { | ||
| 774 | /* Enable the NFC clock */ | ||
| 775 | clk_enable(host->clk); | ||
| 776 | host->clk_act = 1; | ||
| 708 | } | 777 | } |
| 778 | |||
| 779 | host->active_cs = chip; | ||
| 780 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); | ||
| 709 | } | 781 | } |
| 710 | 782 | ||
| 711 | /* | 783 | /* |
| @@ -718,23 +790,23 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) | |||
| 718 | u16 i, j; | 790 | u16 i, j; |
| 719 | u16 n = mtd->writesize >> 9; | 791 | u16 n = mtd->writesize >> 9; |
| 720 | u8 *d = host->data_buf + mtd->writesize; | 792 | u8 *d = host->data_buf + mtd->writesize; |
| 721 | u8 *s = host->spare0; | 793 | u8 __iomem *s = host->spare0; |
| 722 | u16 t = host->spare_len; | 794 | u16 t = host->devtype_data->spare_len; |
| 723 | 795 | ||
| 724 | j = (mtd->oobsize / n >> 1) << 1; | 796 | j = (mtd->oobsize / n >> 1) << 1; |
| 725 | 797 | ||
| 726 | if (bfrom) { | 798 | if (bfrom) { |
| 727 | for (i = 0; i < n - 1; i++) | 799 | for (i = 0; i < n - 1; i++) |
| 728 | memcpy(d + i * j, s + i * t, j); | 800 | memcpy_fromio(d + i * j, s + i * t, j); |
| 729 | 801 | ||
| 730 | /* the last section */ | 802 | /* the last section */ |
| 731 | memcpy(d + i * j, s + i * t, mtd->oobsize - i * j); | 803 | memcpy_fromio(d + i * j, s + i * t, mtd->oobsize - i * j); |
| 732 | } else { | 804 | } else { |
| 733 | for (i = 0; i < n - 1; i++) | 805 | for (i = 0; i < n - 1; i++) |
| 734 | memcpy(&s[i * t], &d[i * j], j); | 806 | memcpy_toio(&s[i * t], &d[i * j], j); |
| 735 | 807 | ||
| 736 | /* the last section */ | 808 | /* the last section */ |
| 737 | memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j); | 809 | memcpy_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j); |
| 738 | } | 810 | } |
| 739 | } | 811 | } |
| 740 | 812 | ||
| @@ -751,34 +823,44 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | |||
| 751 | * perform a read/write buf operation, the saved column | 823 | * perform a read/write buf operation, the saved column |
| 752 | * address is used to index into the full page. | 824 | * address is used to index into the full page. |
| 753 | */ | 825 | */ |
| 754 | host->send_addr(host, 0, page_addr == -1); | 826 | host->devtype_data->send_addr(host, 0, page_addr == -1); |
| 755 | if (mtd->writesize > 512) | 827 | if (mtd->writesize > 512) |
| 756 | /* another col addr cycle for 2k page */ | 828 | /* another col addr cycle for 2k page */ |
| 757 | host->send_addr(host, 0, false); | 829 | host->devtype_data->send_addr(host, 0, false); |
| 758 | } | 830 | } |
| 759 | 831 | ||
| 760 | /* Write out page address, if necessary */ | 832 | /* Write out page address, if necessary */ |
| 761 | if (page_addr != -1) { | 833 | if (page_addr != -1) { |
| 762 | /* paddr_0 - p_addr_7 */ | 834 | /* paddr_0 - p_addr_7 */ |
| 763 | host->send_addr(host, (page_addr & 0xff), false); | 835 | host->devtype_data->send_addr(host, (page_addr & 0xff), false); |
| 764 | 836 | ||
| 765 | if (mtd->writesize > 512) { | 837 | if (mtd->writesize > 512) { |
| 766 | if (mtd->size >= 0x10000000) { | 838 | if (mtd->size >= 0x10000000) { |
| 767 | /* paddr_8 - paddr_15 */ | 839 | /* paddr_8 - paddr_15 */ |
| 768 | host->send_addr(host, (page_addr >> 8) & 0xff, false); | 840 | host->devtype_data->send_addr(host, |
| 769 | host->send_addr(host, (page_addr >> 16) & 0xff, true); | 841 | (page_addr >> 8) & 0xff, |
| 842 | false); | ||
| 843 | host->devtype_data->send_addr(host, | ||
| 844 | (page_addr >> 16) & 0xff, | ||
| 845 | true); | ||
| 770 | } else | 846 | } else |
| 771 | /* paddr_8 - paddr_15 */ | 847 | /* paddr_8 - paddr_15 */ |
| 772 | host->send_addr(host, (page_addr >> 8) & 0xff, true); | 848 | host->devtype_data->send_addr(host, |
| 849 | (page_addr >> 8) & 0xff, true); | ||
| 773 | } else { | 850 | } else { |
| 774 | /* One more address cycle for higher density devices */ | 851 | /* One more address cycle for higher density devices */ |
| 775 | if (mtd->size >= 0x4000000) { | 852 | if (mtd->size >= 0x4000000) { |
| 776 | /* paddr_8 - paddr_15 */ | 853 | /* paddr_8 - paddr_15 */ |
| 777 | host->send_addr(host, (page_addr >> 8) & 0xff, false); | 854 | host->devtype_data->send_addr(host, |
| 778 | host->send_addr(host, (page_addr >> 16) & 0xff, true); | 855 | (page_addr >> 8) & 0xff, |
| 856 | false); | ||
| 857 | host->devtype_data->send_addr(host, | ||
| 858 | (page_addr >> 16) & 0xff, | ||
| 859 | true); | ||
| 779 | } else | 860 | } else |
| 780 | /* paddr_8 - paddr_15 */ | 861 | /* paddr_8 - paddr_15 */ |
| 781 | host->send_addr(host, (page_addr >> 8) & 0xff, true); | 862 | host->devtype_data->send_addr(host, |
| 863 | (page_addr >> 8) & 0xff, true); | ||
| 782 | } | 864 | } |
| 783 | } | 865 | } |
| 784 | } | 866 | } |
| @@ -800,7 +882,35 @@ static int get_eccsize(struct mtd_info *mtd) | |||
| 800 | return 8; | 882 | return 8; |
| 801 | } | 883 | } |
| 802 | 884 | ||
| 803 | static void preset_v1_v2(struct mtd_info *mtd) | 885 | static void preset_v1(struct mtd_info *mtd) |
| 886 | { | ||
| 887 | struct nand_chip *nand_chip = mtd->priv; | ||
| 888 | struct mxc_nand_host *host = nand_chip->priv; | ||
| 889 | uint16_t config1 = 0; | ||
| 890 | |||
| 891 | if (nand_chip->ecc.mode == NAND_ECC_HW) | ||
| 892 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | ||
| 893 | |||
| 894 | if (!host->devtype_data->irqpending_quirk) | ||
| 895 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; | ||
| 896 | |||
| 897 | host->eccsize = 1; | ||
| 898 | |||
| 899 | writew(config1, NFC_V1_V2_CONFIG1); | ||
| 900 | /* preset operation */ | ||
| 901 | |||
| 902 | /* Unlock the internal RAM Buffer */ | ||
| 903 | writew(0x2, NFC_V1_V2_CONFIG); | ||
| 904 | |||
| 905 | /* Blocks to be unlocked */ | ||
| 906 | writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); | ||
| 907 | writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); | ||
| 908 | |||
| 909 | /* Unlock Block Command for given address range */ | ||
| 910 | writew(0x4, NFC_V1_V2_WRPROT); | ||
| 911 | } | ||
| 912 | |||
| 913 | static void preset_v2(struct mtd_info *mtd) | ||
| 804 | { | 914 | { |
| 805 | struct nand_chip *nand_chip = mtd->priv; | 915 | struct nand_chip *nand_chip = mtd->priv; |
| 806 | struct mxc_nand_host *host = nand_chip->priv; | 916 | struct mxc_nand_host *host = nand_chip->priv; |
| @@ -809,13 +919,12 @@ static void preset_v1_v2(struct mtd_info *mtd) | |||
| 809 | if (nand_chip->ecc.mode == NAND_ECC_HW) | 919 | if (nand_chip->ecc.mode == NAND_ECC_HW) |
| 810 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | 920 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; |
| 811 | 921 | ||
| 812 | if (nfc_is_v21()) | 922 | config1 |= NFC_V2_CONFIG1_FP_INT; |
| 813 | config1 |= NFC_V2_CONFIG1_FP_INT; | ||
| 814 | 923 | ||
| 815 | if (!cpu_is_mx21()) | 924 | if (!host->devtype_data->irqpending_quirk) |
| 816 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; | 925 | config1 |= NFC_V1_V2_CONFIG1_INT_MSK; |
| 817 | 926 | ||
| 818 | if (nfc_is_v21() && mtd->writesize) { | 927 | if (mtd->writesize) { |
| 819 | uint16_t pages_per_block = mtd->erasesize / mtd->writesize; | 928 | uint16_t pages_per_block = mtd->erasesize / mtd->writesize; |
| 820 | 929 | ||
| 821 | host->eccsize = get_eccsize(mtd); | 930 | host->eccsize = get_eccsize(mtd); |
| @@ -834,20 +943,14 @@ static void preset_v1_v2(struct mtd_info *mtd) | |||
| 834 | writew(0x2, NFC_V1_V2_CONFIG); | 943 | writew(0x2, NFC_V1_V2_CONFIG); |
| 835 | 944 | ||
| 836 | /* Blocks to be unlocked */ | 945 | /* Blocks to be unlocked */ |
| 837 | if (nfc_is_v21()) { | 946 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0); |
| 838 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0); | 947 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1); |
| 839 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1); | 948 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2); |
| 840 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2); | 949 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3); |
| 841 | writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3); | 950 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0); |
| 842 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0); | 951 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1); |
| 843 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1); | 952 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2); |
| 844 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2); | 953 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); |
| 845 | writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); | ||
| 846 | } else if (nfc_is_v1()) { | ||
| 847 | writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); | ||
| 848 | writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); | ||
| 849 | } else | ||
| 850 | BUG(); | ||
| 851 | 954 | ||
| 852 | /* Unlock Block Command for given address range */ | 955 | /* Unlock Block Command for given address range */ |
| 853 | writew(0x4, NFC_V1_V2_WRPROT); | 956 | writew(0x4, NFC_V1_V2_WRPROT); |
| @@ -937,15 +1040,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 937 | /* Command pre-processing step */ | 1040 | /* Command pre-processing step */ |
| 938 | switch (command) { | 1041 | switch (command) { |
| 939 | case NAND_CMD_RESET: | 1042 | case NAND_CMD_RESET: |
| 940 | host->preset(mtd); | 1043 | host->devtype_data->preset(mtd); |
| 941 | host->send_cmd(host, command, false); | 1044 | host->devtype_data->send_cmd(host, command, false); |
| 942 | break; | 1045 | break; |
| 943 | 1046 | ||
| 944 | case NAND_CMD_STATUS: | 1047 | case NAND_CMD_STATUS: |
| 945 | host->buf_start = 0; | 1048 | host->buf_start = 0; |
| 946 | host->status_request = true; | 1049 | host->status_request = true; |
| 947 | 1050 | ||
| 948 | host->send_cmd(host, command, true); | 1051 | host->devtype_data->send_cmd(host, command, true); |
| 949 | mxc_do_addr_cycle(mtd, column, page_addr); | 1052 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 950 | break; | 1053 | break; |
| 951 | 1054 | ||
| @@ -958,15 +1061,16 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 958 | 1061 | ||
| 959 | command = NAND_CMD_READ0; /* only READ0 is valid */ | 1062 | command = NAND_CMD_READ0; /* only READ0 is valid */ |
| 960 | 1063 | ||
| 961 | host->send_cmd(host, command, false); | 1064 | host->devtype_data->send_cmd(host, command, false); |
| 962 | mxc_do_addr_cycle(mtd, column, page_addr); | 1065 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 963 | 1066 | ||
| 964 | if (mtd->writesize > 512) | 1067 | if (mtd->writesize > 512) |
| 965 | host->send_cmd(host, NAND_CMD_READSTART, true); | 1068 | host->devtype_data->send_cmd(host, |
| 1069 | NAND_CMD_READSTART, true); | ||
| 966 | 1070 | ||
| 967 | host->send_page(mtd, NFC_OUTPUT); | 1071 | host->devtype_data->send_page(mtd, NFC_OUTPUT); |
| 968 | 1072 | ||
| 969 | memcpy(host->data_buf, host->main_area0, mtd->writesize); | 1073 | memcpy_fromio(host->data_buf, host->main_area0, mtd->writesize); |
| 970 | copy_spare(mtd, true); | 1074 | copy_spare(mtd, true); |
| 971 | break; | 1075 | break; |
| 972 | 1076 | ||
| @@ -977,28 +1081,28 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 977 | 1081 | ||
| 978 | host->buf_start = column; | 1082 | host->buf_start = column; |
| 979 | 1083 | ||
| 980 | host->send_cmd(host, command, false); | 1084 | host->devtype_data->send_cmd(host, command, false); |
| 981 | mxc_do_addr_cycle(mtd, column, page_addr); | 1085 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 982 | break; | 1086 | break; |
| 983 | 1087 | ||
| 984 | case NAND_CMD_PAGEPROG: | 1088 | case NAND_CMD_PAGEPROG: |
| 985 | memcpy(host->main_area0, host->data_buf, mtd->writesize); | 1089 | memcpy_toio(host->main_area0, host->data_buf, mtd->writesize); |
| 986 | copy_spare(mtd, false); | 1090 | copy_spare(mtd, false); |
| 987 | host->send_page(mtd, NFC_INPUT); | 1091 | host->devtype_data->send_page(mtd, NFC_INPUT); |
| 988 | host->send_cmd(host, command, true); | 1092 | host->devtype_data->send_cmd(host, command, true); |
| 989 | mxc_do_addr_cycle(mtd, column, page_addr); | 1093 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 990 | break; | 1094 | break; |
| 991 | 1095 | ||
| 992 | case NAND_CMD_READID: | 1096 | case NAND_CMD_READID: |
| 993 | host->send_cmd(host, command, true); | 1097 | host->devtype_data->send_cmd(host, command, true); |
| 994 | mxc_do_addr_cycle(mtd, column, page_addr); | 1098 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 995 | host->send_read_id(host); | 1099 | host->devtype_data->send_read_id(host); |
| 996 | host->buf_start = column; | 1100 | host->buf_start = column; |
| 997 | break; | 1101 | break; |
| 998 | 1102 | ||
| 999 | case NAND_CMD_ERASE1: | 1103 | case NAND_CMD_ERASE1: |
| 1000 | case NAND_CMD_ERASE2: | 1104 | case NAND_CMD_ERASE2: |
| 1001 | host->send_cmd(host, command, false); | 1105 | host->devtype_data->send_cmd(host, command, false); |
| 1002 | mxc_do_addr_cycle(mtd, column, page_addr); | 1106 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 1003 | 1107 | ||
| 1004 | break; | 1108 | break; |
| @@ -1032,15 +1136,191 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
| 1032 | .pattern = mirror_pattern, | 1136 | .pattern = mirror_pattern, |
| 1033 | }; | 1137 | }; |
| 1034 | 1138 | ||
| 1139 | /* v1 + irqpending_quirk: i.MX21 */ | ||
| 1140 | static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { | ||
| 1141 | .preset = preset_v1, | ||
| 1142 | .send_cmd = send_cmd_v1_v2, | ||
| 1143 | .send_addr = send_addr_v1_v2, | ||
| 1144 | .send_page = send_page_v1, | ||
| 1145 | .send_read_id = send_read_id_v1_v2, | ||
| 1146 | .get_dev_status = get_dev_status_v1_v2, | ||
| 1147 | .check_int = check_int_v1_v2, | ||
| 1148 | .irq_control = irq_control_v1_v2, | ||
| 1149 | .get_ecc_status = get_ecc_status_v1, | ||
| 1150 | .ecclayout_512 = &nandv1_hw_eccoob_smallpage, | ||
| 1151 | .ecclayout_2k = &nandv1_hw_eccoob_largepage, | ||
| 1152 | .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ | ||
| 1153 | .select_chip = mxc_nand_select_chip_v1_v3, | ||
| 1154 | .correct_data = mxc_nand_correct_data_v1, | ||
| 1155 | .irqpending_quirk = 1, | ||
| 1156 | .needs_ip = 0, | ||
| 1157 | .regs_offset = 0xe00, | ||
| 1158 | .spare0_offset = 0x800, | ||
| 1159 | .spare_len = 16, | ||
| 1160 | .eccbytes = 3, | ||
| 1161 | .eccsize = 1, | ||
| 1162 | }; | ||
| 1163 | |||
| 1164 | /* v1 + !irqpending_quirk: i.MX27, i.MX31 */ | ||
| 1165 | static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { | ||
| 1166 | .preset = preset_v1, | ||
| 1167 | .send_cmd = send_cmd_v1_v2, | ||
| 1168 | .send_addr = send_addr_v1_v2, | ||
| 1169 | .send_page = send_page_v1, | ||
| 1170 | .send_read_id = send_read_id_v1_v2, | ||
| 1171 | .get_dev_status = get_dev_status_v1_v2, | ||
| 1172 | .check_int = check_int_v1_v2, | ||
| 1173 | .irq_control = irq_control_v1_v2, | ||
| 1174 | .get_ecc_status = get_ecc_status_v1, | ||
| 1175 | .ecclayout_512 = &nandv1_hw_eccoob_smallpage, | ||
| 1176 | .ecclayout_2k = &nandv1_hw_eccoob_largepage, | ||
| 1177 | .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ | ||
| 1178 | .select_chip = mxc_nand_select_chip_v1_v3, | ||
| 1179 | .correct_data = mxc_nand_correct_data_v1, | ||
| 1180 | .irqpending_quirk = 0, | ||
| 1181 | .needs_ip = 0, | ||
| 1182 | .regs_offset = 0xe00, | ||
| 1183 | .spare0_offset = 0x800, | ||
| 1184 | .axi_offset = 0, | ||
| 1185 | .spare_len = 16, | ||
| 1186 | .eccbytes = 3, | ||
| 1187 | .eccsize = 1, | ||
| 1188 | }; | ||
| 1189 | |||
| 1190 | /* v21: i.MX25, i.MX35 */ | ||
| 1191 | static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { | ||
| 1192 | .preset = preset_v2, | ||
| 1193 | .send_cmd = send_cmd_v1_v2, | ||
| 1194 | .send_addr = send_addr_v1_v2, | ||
| 1195 | .send_page = send_page_v2, | ||
| 1196 | .send_read_id = send_read_id_v1_v2, | ||
| 1197 | .get_dev_status = get_dev_status_v1_v2, | ||
| 1198 | .check_int = check_int_v1_v2, | ||
| 1199 | .irq_control = irq_control_v1_v2, | ||
| 1200 | .get_ecc_status = get_ecc_status_v2, | ||
| 1201 | .ecclayout_512 = &nandv2_hw_eccoob_smallpage, | ||
| 1202 | .ecclayout_2k = &nandv2_hw_eccoob_largepage, | ||
| 1203 | .ecclayout_4k = &nandv2_hw_eccoob_4k, | ||
| 1204 | .select_chip = mxc_nand_select_chip_v2, | ||
| 1205 | .correct_data = mxc_nand_correct_data_v2_v3, | ||
| 1206 | .irqpending_quirk = 0, | ||
| 1207 | .needs_ip = 0, | ||
| 1208 | .regs_offset = 0x1e00, | ||
| 1209 | .spare0_offset = 0x1000, | ||
| 1210 | .axi_offset = 0, | ||
| 1211 | .spare_len = 64, | ||
| 1212 | .eccbytes = 9, | ||
| 1213 | .eccsize = 0, | ||
| 1214 | }; | ||
| 1215 | |||
| 1216 | /* v3: i.MX51, i.MX53 */ | ||
| 1217 | static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { | ||
| 1218 | .preset = preset_v3, | ||
| 1219 | .send_cmd = send_cmd_v3, | ||
| 1220 | .send_addr = send_addr_v3, | ||
| 1221 | .send_page = send_page_v3, | ||
| 1222 | .send_read_id = send_read_id_v3, | ||
| 1223 | .get_dev_status = get_dev_status_v3, | ||
| 1224 | .check_int = check_int_v3, | ||
| 1225 | .irq_control = irq_control_v3, | ||
| 1226 | .get_ecc_status = get_ecc_status_v3, | ||
| 1227 | .ecclayout_512 = &nandv2_hw_eccoob_smallpage, | ||
| 1228 | .ecclayout_2k = &nandv2_hw_eccoob_largepage, | ||
| 1229 | .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */ | ||
| 1230 | .select_chip = mxc_nand_select_chip_v1_v3, | ||
| 1231 | .correct_data = mxc_nand_correct_data_v2_v3, | ||
| 1232 | .irqpending_quirk = 0, | ||
| 1233 | .needs_ip = 1, | ||
| 1234 | .regs_offset = 0, | ||
| 1235 | .spare0_offset = 0x1000, | ||
| 1236 | .axi_offset = 0x1e00, | ||
| 1237 | .spare_len = 64, | ||
| 1238 | .eccbytes = 0, | ||
| 1239 | .eccsize = 0, | ||
| 1240 | }; | ||
| 1241 | |||
| 1242 | #ifdef CONFIG_OF_MTD | ||
| 1243 | static const struct of_device_id mxcnd_dt_ids[] = { | ||
| 1244 | { | ||
| 1245 | .compatible = "fsl,imx21-nand", | ||
| 1246 | .data = &imx21_nand_devtype_data, | ||
| 1247 | }, { | ||
| 1248 | .compatible = "fsl,imx27-nand", | ||
| 1249 | .data = &imx27_nand_devtype_data, | ||
| 1250 | }, { | ||
| 1251 | .compatible = "fsl,imx25-nand", | ||
| 1252 | .data = &imx25_nand_devtype_data, | ||
| 1253 | }, { | ||
| 1254 | .compatible = "fsl,imx51-nand", | ||
| 1255 | .data = &imx51_nand_devtype_data, | ||
| 1256 | }, | ||
| 1257 | { /* sentinel */ } | ||
| 1258 | }; | ||
| 1259 | |||
| 1260 | static int __init mxcnd_probe_dt(struct mxc_nand_host *host) | ||
| 1261 | { | ||
| 1262 | struct device_node *np = host->dev->of_node; | ||
| 1263 | struct mxc_nand_platform_data *pdata = &host->pdata; | ||
| 1264 | const struct of_device_id *of_id = | ||
| 1265 | of_match_device(mxcnd_dt_ids, host->dev); | ||
| 1266 | int buswidth; | ||
| 1267 | |||
| 1268 | if (!np) | ||
| 1269 | return 1; | ||
| 1270 | |||
| 1271 | if (of_get_nand_ecc_mode(np) >= 0) | ||
| 1272 | pdata->hw_ecc = 1; | ||
| 1273 | |||
| 1274 | pdata->flash_bbt = of_get_nand_on_flash_bbt(np); | ||
| 1275 | |||
| 1276 | buswidth = of_get_nand_bus_width(np); | ||
| 1277 | if (buswidth < 0) | ||
| 1278 | return buswidth; | ||
| 1279 | |||
| 1280 | pdata->width = buswidth / 8; | ||
| 1281 | |||
| 1282 | host->devtype_data = of_id->data; | ||
| 1283 | |||
| 1284 | return 0; | ||
| 1285 | } | ||
| 1286 | #else | ||
| 1287 | static int __init mxcnd_probe_dt(struct mxc_nand_host *host) | ||
| 1288 | { | ||
| 1289 | return 1; | ||
| 1290 | } | ||
| 1291 | #endif | ||
| 1292 | |||
| 1293 | static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) | ||
| 1294 | { | ||
| 1295 | struct mxc_nand_platform_data *pdata = host->dev->platform_data; | ||
| 1296 | |||
| 1297 | if (!pdata) | ||
| 1298 | return -ENODEV; | ||
| 1299 | |||
| 1300 | host->pdata = *pdata; | ||
| 1301 | |||
| 1302 | if (nfc_is_v1()) { | ||
| 1303 | if (cpu_is_mx21()) | ||
| 1304 | host->devtype_data = &imx21_nand_devtype_data; | ||
| 1305 | else | ||
| 1306 | host->devtype_data = &imx27_nand_devtype_data; | ||
| 1307 | } else if (nfc_is_v21()) { | ||
| 1308 | host->devtype_data = &imx25_nand_devtype_data; | ||
| 1309 | } else if (nfc_is_v3_2()) { | ||
| 1310 | host->devtype_data = &imx51_nand_devtype_data; | ||
| 1311 | } else | ||
| 1312 | BUG(); | ||
| 1313 | |||
| 1314 | return 0; | ||
| 1315 | } | ||
| 1316 | |||
| 1035 | static int __init mxcnd_probe(struct platform_device *pdev) | 1317 | static int __init mxcnd_probe(struct platform_device *pdev) |
| 1036 | { | 1318 | { |
| 1037 | struct nand_chip *this; | 1319 | struct nand_chip *this; |
| 1038 | struct mtd_info *mtd; | 1320 | struct mtd_info *mtd; |
| 1039 | struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; | ||
| 1040 | struct mxc_nand_host *host; | 1321 | struct mxc_nand_host *host; |
| 1041 | struct resource *res; | 1322 | struct resource *res; |
| 1042 | int err = 0; | 1323 | int err = 0; |
| 1043 | struct nand_ecclayout *oob_smallpage, *oob_largepage; | ||
| 1044 | 1324 | ||
| 1045 | /* Allocate memory for MTD device structure and private data */ | 1325 | /* Allocate memory for MTD device structure and private data */ |
| 1046 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + | 1326 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + |
| @@ -1065,7 +1345,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1065 | this->priv = host; | 1345 | this->priv = host; |
| 1066 | this->dev_ready = mxc_nand_dev_ready; | 1346 | this->dev_ready = mxc_nand_dev_ready; |
| 1067 | this->cmdfunc = mxc_nand_command; | 1347 | this->cmdfunc = mxc_nand_command; |
| 1068 | this->select_chip = mxc_nand_select_chip; | ||
| 1069 | this->read_byte = mxc_nand_read_byte; | 1348 | this->read_byte = mxc_nand_read_byte; |
| 1070 | this->read_word = mxc_nand_read_word; | 1349 | this->read_word = mxc_nand_read_word; |
| 1071 | this->write_buf = mxc_nand_write_buf; | 1350 | this->write_buf = mxc_nand_write_buf; |
| @@ -1095,36 +1374,26 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1095 | 1374 | ||
| 1096 | host->main_area0 = host->base; | 1375 | host->main_area0 = host->base; |
| 1097 | 1376 | ||
| 1098 | if (nfc_is_v1() || nfc_is_v21()) { | 1377 | err = mxcnd_probe_dt(host); |
| 1099 | host->preset = preset_v1_v2; | 1378 | if (err > 0) |
| 1100 | host->send_cmd = send_cmd_v1_v2; | 1379 | err = mxcnd_probe_pdata(host); |
| 1101 | host->send_addr = send_addr_v1_v2; | 1380 | if (err < 0) |
| 1102 | host->send_page = send_page_v1_v2; | 1381 | goto eirq; |
| 1103 | host->send_read_id = send_read_id_v1_v2; | ||
| 1104 | host->get_dev_status = get_dev_status_v1_v2; | ||
| 1105 | host->check_int = check_int_v1_v2; | ||
| 1106 | if (cpu_is_mx21()) | ||
| 1107 | host->irq_control = irq_control_mx21; | ||
| 1108 | else | ||
| 1109 | host->irq_control = irq_control_v1_v2; | ||
| 1110 | } | ||
| 1111 | 1382 | ||
| 1112 | if (nfc_is_v21()) { | 1383 | if (host->devtype_data->regs_offset) |
| 1113 | host->regs = host->base + 0x1e00; | 1384 | host->regs = host->base + host->devtype_data->regs_offset; |
| 1114 | host->spare0 = host->base + 0x1000; | 1385 | host->spare0 = host->base + host->devtype_data->spare0_offset; |
| 1115 | host->spare_len = 64; | 1386 | if (host->devtype_data->axi_offset) |
| 1116 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | 1387 | host->regs_axi = host->base + host->devtype_data->axi_offset; |
| 1117 | oob_largepage = &nandv2_hw_eccoob_largepage; | 1388 | |
| 1118 | this->ecc.bytes = 9; | 1389 | this->ecc.bytes = host->devtype_data->eccbytes; |
| 1119 | } else if (nfc_is_v1()) { | 1390 | host->eccsize = host->devtype_data->eccsize; |
| 1120 | host->regs = host->base + 0xe00; | 1391 | |
| 1121 | host->spare0 = host->base + 0x800; | 1392 | this->select_chip = host->devtype_data->select_chip; |
| 1122 | host->spare_len = 16; | 1393 | this->ecc.size = 512; |
| 1123 | oob_smallpage = &nandv1_hw_eccoob_smallpage; | 1394 | this->ecc.layout = host->devtype_data->ecclayout_512; |
| 1124 | oob_largepage = &nandv1_hw_eccoob_largepage; | 1395 | |
| 1125 | this->ecc.bytes = 3; | 1396 | if (host->devtype_data->needs_ip) { |
| 1126 | host->eccsize = 1; | ||
| 1127 | } else if (nfc_is_v3_2()) { | ||
| 1128 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1397 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 1129 | if (!res) { | 1398 | if (!res) { |
| 1130 | err = -ENODEV; | 1399 | err = -ENODEV; |
| @@ -1135,42 +1404,22 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1135 | err = -ENOMEM; | 1404 | err = -ENOMEM; |
| 1136 | goto eirq; | 1405 | goto eirq; |
| 1137 | } | 1406 | } |
| 1138 | host->regs_axi = host->base + 0x1e00; | 1407 | } |
| 1139 | host->spare0 = host->base + 0x1000; | ||
| 1140 | host->spare_len = 64; | ||
| 1141 | host->preset = preset_v3; | ||
| 1142 | host->send_cmd = send_cmd_v3; | ||
| 1143 | host->send_addr = send_addr_v3; | ||
| 1144 | host->send_page = send_page_v3; | ||
| 1145 | host->send_read_id = send_read_id_v3; | ||
| 1146 | host->check_int = check_int_v3; | ||
| 1147 | host->get_dev_status = get_dev_status_v3; | ||
| 1148 | host->irq_control = irq_control_v3; | ||
| 1149 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
| 1150 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
| 1151 | } else | ||
| 1152 | BUG(); | ||
| 1153 | |||
| 1154 | this->ecc.size = 512; | ||
| 1155 | this->ecc.layout = oob_smallpage; | ||
| 1156 | 1408 | ||
| 1157 | if (pdata->hw_ecc) { | 1409 | if (host->pdata.hw_ecc) { |
| 1158 | this->ecc.calculate = mxc_nand_calculate_ecc; | 1410 | this->ecc.calculate = mxc_nand_calculate_ecc; |
| 1159 | this->ecc.hwctl = mxc_nand_enable_hwecc; | 1411 | this->ecc.hwctl = mxc_nand_enable_hwecc; |
| 1160 | if (nfc_is_v1()) | 1412 | this->ecc.correct = host->devtype_data->correct_data; |
| 1161 | this->ecc.correct = mxc_nand_correct_data_v1; | ||
| 1162 | else | ||
| 1163 | this->ecc.correct = mxc_nand_correct_data_v2_v3; | ||
| 1164 | this->ecc.mode = NAND_ECC_HW; | 1413 | this->ecc.mode = NAND_ECC_HW; |
| 1165 | } else { | 1414 | } else { |
| 1166 | this->ecc.mode = NAND_ECC_SOFT; | 1415 | this->ecc.mode = NAND_ECC_SOFT; |
| 1167 | } | 1416 | } |
| 1168 | 1417 | ||
| 1169 | /* NAND bus width determines access funtions used by upper layer */ | 1418 | /* NAND bus width determines access functions used by upper layer */ |
| 1170 | if (pdata->width == 2) | 1419 | if (host->pdata.width == 2) |
| 1171 | this->options |= NAND_BUSWIDTH_16; | 1420 | this->options |= NAND_BUSWIDTH_16; |
| 1172 | 1421 | ||
| 1173 | if (pdata->flash_bbt) { | 1422 | if (host->pdata.flash_bbt) { |
| 1174 | this->bbt_td = &bbt_main_descr; | 1423 | this->bbt_td = &bbt_main_descr; |
| 1175 | this->bbt_md = &bbt_mirror_descr; | 1424 | this->bbt_md = &bbt_mirror_descr; |
| 1176 | /* update flash based bbt */ | 1425 | /* update flash based bbt */ |
| @@ -1182,28 +1431,25 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1182 | host->irq = platform_get_irq(pdev, 0); | 1431 | host->irq = platform_get_irq(pdev, 0); |
| 1183 | 1432 | ||
| 1184 | /* | 1433 | /* |
| 1185 | * mask the interrupt. For i.MX21 explicitely call | 1434 | * Use host->devtype_data->irq_control() here instead of irq_control() |
| 1186 | * irq_control_v1_v2 to use the mask bit. We can't call | 1435 | * because we must not disable_irq_nosync without having requested the |
| 1187 | * disable_irq_nosync() for an interrupt we do not own yet. | 1436 | * irq. |
| 1188 | */ | 1437 | */ |
| 1189 | if (cpu_is_mx21()) | 1438 | host->devtype_data->irq_control(host, 0); |
| 1190 | irq_control_v1_v2(host, 0); | ||
| 1191 | else | ||
| 1192 | host->irq_control(host, 0); | ||
| 1193 | 1439 | ||
| 1194 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); | 1440 | err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); |
| 1195 | if (err) | 1441 | if (err) |
| 1196 | goto eirq; | 1442 | goto eirq; |
| 1197 | 1443 | ||
| 1198 | host->irq_control(host, 0); | ||
| 1199 | |||
| 1200 | /* | 1444 | /* |
| 1201 | * Now that the interrupt is disabled make sure the interrupt | 1445 | * Now that we "own" the interrupt make sure the interrupt mask bit is |
| 1202 | * mask bit is cleared on i.MX21. Otherwise we can't read | 1446 | * cleared on i.MX21. Otherwise we can't read the interrupt status bit |
| 1203 | * the interrupt status bit on this machine. | 1447 | * on this machine. |
| 1204 | */ | 1448 | */ |
| 1205 | if (cpu_is_mx21()) | 1449 | if (host->devtype_data->irqpending_quirk) { |
| 1206 | irq_control_v1_v2(host, 1); | 1450 | disable_irq_nosync(host->irq); |
| 1451 | host->devtype_data->irq_control(host, 1); | ||
| 1452 | } | ||
| 1207 | 1453 | ||
| 1208 | /* first scan to find the device and get the page size */ | 1454 | /* first scan to find the device and get the page size */ |
| 1209 | if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { | 1455 | if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { |
| @@ -1212,18 +1458,12 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1212 | } | 1458 | } |
| 1213 | 1459 | ||
| 1214 | /* Call preset again, with correct writesize this time */ | 1460 | /* Call preset again, with correct writesize this time */ |
| 1215 | host->preset(mtd); | 1461 | host->devtype_data->preset(mtd); |
| 1216 | 1462 | ||
| 1217 | if (mtd->writesize == 2048) | 1463 | if (mtd->writesize == 2048) |
| 1218 | this->ecc.layout = oob_largepage; | 1464 | this->ecc.layout = host->devtype_data->ecclayout_2k; |
| 1219 | if (nfc_is_v21() && mtd->writesize == 4096) | 1465 | else if (mtd->writesize == 4096) |
| 1220 | this->ecc.layout = &nandv2_hw_eccoob_4k; | 1466 | this->ecc.layout = host->devtype_data->ecclayout_4k; |
| 1221 | |||
| 1222 | /* second phase scan */ | ||
| 1223 | if (nand_scan_tail(mtd)) { | ||
| 1224 | err = -ENXIO; | ||
| 1225 | goto escan; | ||
| 1226 | } | ||
| 1227 | 1467 | ||
| 1228 | if (this->ecc.mode == NAND_ECC_HW) { | 1468 | if (this->ecc.mode == NAND_ECC_HW) { |
| 1229 | if (nfc_is_v1()) | 1469 | if (nfc_is_v1()) |
| @@ -1232,9 +1472,19 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
| 1232 | this->ecc.strength = (host->eccsize == 4) ? 4 : 8; | 1472 | this->ecc.strength = (host->eccsize == 4) ? 4 : 8; |
| 1233 | } | 1473 | } |
| 1234 | 1474 | ||
| 1475 | /* second phase scan */ | ||
| 1476 | if (nand_scan_tail(mtd)) { | ||
| 1477 | err = -ENXIO; | ||
| 1478 | goto escan; | ||
| 1479 | } | ||
| 1480 | |||
| 1235 | /* Register the partitions */ | 1481 | /* Register the partitions */ |
| 1236 | mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, | 1482 | mtd_device_parse_register(mtd, part_probes, |
| 1237 | pdata->nr_parts); | 1483 | &(struct mtd_part_parser_data){ |
| 1484 | .of_node = pdev->dev.of_node, | ||
| 1485 | }, | ||
| 1486 | host->pdata.parts, | ||
| 1487 | host->pdata.nr_parts); | ||
| 1238 | 1488 | ||
| 1239 | platform_set_drvdata(pdev, host); | 1489 | platform_set_drvdata(pdev, host); |
| 1240 | 1490 | ||
| @@ -1275,6 +1525,8 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) | |||
| 1275 | static struct platform_driver mxcnd_driver = { | 1525 | static struct platform_driver mxcnd_driver = { |
| 1276 | .driver = { | 1526 | .driver = { |
| 1277 | .name = DRIVER_NAME, | 1527 | .name = DRIVER_NAME, |
| 1528 | .owner = THIS_MODULE, | ||
| 1529 | .of_match_table = of_match_ptr(mxcnd_dt_ids), | ||
| 1278 | }, | 1530 | }, |
| 1279 | .remove = __devexit_p(mxcnd_remove), | 1531 | .remove = __devexit_p(mxcnd_remove), |
| 1280 | }; | 1532 | }; |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 47b19c0bb070..d47586cf64ce 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -1066,15 +1066,17 @@ EXPORT_SYMBOL(nand_lock); | |||
| 1066 | * @mtd: mtd info structure | 1066 | * @mtd: mtd info structure |
| 1067 | * @chip: nand chip info structure | 1067 | * @chip: nand chip info structure |
| 1068 | * @buf: buffer to store read data | 1068 | * @buf: buffer to store read data |
| 1069 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
| 1069 | * @page: page number to read | 1070 | * @page: page number to read |
| 1070 | * | 1071 | * |
| 1071 | * Not for syndrome calculating ECC controllers, which use a special oob layout. | 1072 | * Not for syndrome calculating ECC controllers, which use a special oob layout. |
| 1072 | */ | 1073 | */ |
| 1073 | static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 1074 | static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
| 1074 | uint8_t *buf, int page) | 1075 | uint8_t *buf, int oob_required, int page) |
| 1075 | { | 1076 | { |
| 1076 | chip->read_buf(mtd, buf, mtd->writesize); | 1077 | chip->read_buf(mtd, buf, mtd->writesize); |
| 1077 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 1078 | if (oob_required) |
| 1079 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 1078 | return 0; | 1080 | return 0; |
| 1079 | } | 1081 | } |
| 1080 | 1082 | ||
| @@ -1083,13 +1085,14 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1083 | * @mtd: mtd info structure | 1085 | * @mtd: mtd info structure |
| 1084 | * @chip: nand chip info structure | 1086 | * @chip: nand chip info structure |
| 1085 | * @buf: buffer to store read data | 1087 | * @buf: buffer to store read data |
| 1088 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
| 1086 | * @page: page number to read | 1089 | * @page: page number to read |
| 1087 | * | 1090 | * |
| 1088 | * We need a special oob layout and handling even when OOB isn't used. | 1091 | * We need a special oob layout and handling even when OOB isn't used. |
| 1089 | */ | 1092 | */ |
| 1090 | static int nand_read_page_raw_syndrome(struct mtd_info *mtd, | 1093 | static int nand_read_page_raw_syndrome(struct mtd_info *mtd, |
| 1091 | struct nand_chip *chip, | 1094 | struct nand_chip *chip, uint8_t *buf, |
| 1092 | uint8_t *buf, int page) | 1095 | int oob_required, int page) |
| 1093 | { | 1096 | { |
| 1094 | int eccsize = chip->ecc.size; | 1097 | int eccsize = chip->ecc.size; |
| 1095 | int eccbytes = chip->ecc.bytes; | 1098 | int eccbytes = chip->ecc.bytes; |
| @@ -1126,10 +1129,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, | |||
| 1126 | * @mtd: mtd info structure | 1129 | * @mtd: mtd info structure |
| 1127 | * @chip: nand chip info structure | 1130 | * @chip: nand chip info structure |
| 1128 | * @buf: buffer to store read data | 1131 | * @buf: buffer to store read data |
| 1132 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
| 1129 | * @page: page number to read | 1133 | * @page: page number to read |
| 1130 | */ | 1134 | */ |
| 1131 | static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | 1135 | static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 1132 | uint8_t *buf, int page) | 1136 | uint8_t *buf, int oob_required, int page) |
| 1133 | { | 1137 | { |
| 1134 | int i, eccsize = chip->ecc.size; | 1138 | int i, eccsize = chip->ecc.size; |
| 1135 | int eccbytes = chip->ecc.bytes; | 1139 | int eccbytes = chip->ecc.bytes; |
| @@ -1138,8 +1142,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1138 | uint8_t *ecc_calc = chip->buffers->ecccalc; | 1142 | uint8_t *ecc_calc = chip->buffers->ecccalc; |
| 1139 | uint8_t *ecc_code = chip->buffers->ecccode; | 1143 | uint8_t *ecc_code = chip->buffers->ecccode; |
| 1140 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 1144 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
| 1145 | unsigned int max_bitflips = 0; | ||
| 1141 | 1146 | ||
| 1142 | chip->ecc.read_page_raw(mtd, chip, buf, page); | 1147 | chip->ecc.read_page_raw(mtd, chip, buf, 1, page); |
| 1143 | 1148 | ||
| 1144 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | 1149 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) |
| 1145 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | 1150 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
| @@ -1154,12 +1159,14 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1154 | int stat; | 1159 | int stat; |
| 1155 | 1160 | ||
| 1156 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); | 1161 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); |
| 1157 | if (stat < 0) | 1162 | if (stat < 0) { |
| 1158 | mtd->ecc_stats.failed++; | 1163 | mtd->ecc_stats.failed++; |
| 1159 | else | 1164 | } else { |
| 1160 | mtd->ecc_stats.corrected += stat; | 1165 | mtd->ecc_stats.corrected += stat; |
| 1166 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 1167 | } | ||
| 1161 | } | 1168 | } |
| 1162 | return 0; | 1169 | return max_bitflips; |
| 1163 | } | 1170 | } |
| 1164 | 1171 | ||
| 1165 | /** | 1172 | /** |
| @@ -1180,6 +1187,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1180 | int datafrag_len, eccfrag_len, aligned_len, aligned_pos; | 1187 | int datafrag_len, eccfrag_len, aligned_len, aligned_pos; |
| 1181 | int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; | 1188 | int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; |
| 1182 | int index = 0; | 1189 | int index = 0; |
| 1190 | unsigned int max_bitflips = 0; | ||
| 1183 | 1191 | ||
| 1184 | /* Column address within the page aligned to ECC size (256bytes) */ | 1192 | /* Column address within the page aligned to ECC size (256bytes) */ |
| 1185 | start_step = data_offs / chip->ecc.size; | 1193 | start_step = data_offs / chip->ecc.size; |
| @@ -1244,12 +1252,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1244 | 1252 | ||
| 1245 | stat = chip->ecc.correct(mtd, p, | 1253 | stat = chip->ecc.correct(mtd, p, |
| 1246 | &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); | 1254 | &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); |
| 1247 | if (stat < 0) | 1255 | if (stat < 0) { |
| 1248 | mtd->ecc_stats.failed++; | 1256 | mtd->ecc_stats.failed++; |
| 1249 | else | 1257 | } else { |
| 1250 | mtd->ecc_stats.corrected += stat; | 1258 | mtd->ecc_stats.corrected += stat; |
| 1259 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 1260 | } | ||
| 1251 | } | 1261 | } |
| 1252 | return 0; | 1262 | return max_bitflips; |
| 1253 | } | 1263 | } |
| 1254 | 1264 | ||
| 1255 | /** | 1265 | /** |
| @@ -1257,12 +1267,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1257 | * @mtd: mtd info structure | 1267 | * @mtd: mtd info structure |
| 1258 | * @chip: nand chip info structure | 1268 | * @chip: nand chip info structure |
| 1259 | * @buf: buffer to store read data | 1269 | * @buf: buffer to store read data |
| 1270 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
| 1260 | * @page: page number to read | 1271 | * @page: page number to read |
| 1261 | * | 1272 | * |
| 1262 | * Not for syndrome calculating ECC controllers which need a special oob layout. | 1273 | * Not for syndrome calculating ECC controllers which need a special oob layout. |
| 1263 | */ | 1274 | */ |
| 1264 | static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 1275 | static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 1265 | uint8_t *buf, int page) | 1276 | uint8_t *buf, int oob_required, int page) |
| 1266 | { | 1277 | { |
| 1267 | int i, eccsize = chip->ecc.size; | 1278 | int i, eccsize = chip->ecc.size; |
| 1268 | int eccbytes = chip->ecc.bytes; | 1279 | int eccbytes = chip->ecc.bytes; |
| @@ -1271,6 +1282,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1271 | uint8_t *ecc_calc = chip->buffers->ecccalc; | 1282 | uint8_t *ecc_calc = chip->buffers->ecccalc; |
| 1272 | uint8_t *ecc_code = chip->buffers->ecccode; | 1283 | uint8_t *ecc_code = chip->buffers->ecccode; |
| 1273 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 1284 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
| 1285 | unsigned int max_bitflips = 0; | ||
| 1274 | 1286 | ||
| 1275 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | 1287 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
| 1276 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | 1288 | chip->ecc.hwctl(mtd, NAND_ECC_READ); |
| @@ -1289,12 +1301,14 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1289 | int stat; | 1301 | int stat; |
| 1290 | 1302 | ||
| 1291 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); | 1303 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); |
| 1292 | if (stat < 0) | 1304 | if (stat < 0) { |
| 1293 | mtd->ecc_stats.failed++; | 1305 | mtd->ecc_stats.failed++; |
| 1294 | else | 1306 | } else { |
| 1295 | mtd->ecc_stats.corrected += stat; | 1307 | mtd->ecc_stats.corrected += stat; |
| 1308 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 1309 | } | ||
| 1296 | } | 1310 | } |
| 1297 | return 0; | 1311 | return max_bitflips; |
| 1298 | } | 1312 | } |
| 1299 | 1313 | ||
| 1300 | /** | 1314 | /** |
| @@ -1302,6 +1316,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1302 | * @mtd: mtd info structure | 1316 | * @mtd: mtd info structure |
| 1303 | * @chip: nand chip info structure | 1317 | * @chip: nand chip info structure |
| 1304 | * @buf: buffer to store read data | 1318 | * @buf: buffer to store read data |
| 1319 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
| 1305 | * @page: page number to read | 1320 | * @page: page number to read |
| 1306 | * | 1321 | * |
| 1307 | * Hardware ECC for large page chips, require OOB to be read first. For this | 1322 | * Hardware ECC for large page chips, require OOB to be read first. For this |
| @@ -1311,7 +1326,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1311 | * the data area, by overwriting the NAND manufacturer bad block markings. | 1326 | * the data area, by overwriting the NAND manufacturer bad block markings. |
| 1312 | */ | 1327 | */ |
| 1313 | static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, | 1328 | static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, |
| 1314 | struct nand_chip *chip, uint8_t *buf, int page) | 1329 | struct nand_chip *chip, uint8_t *buf, int oob_required, int page) |
| 1315 | { | 1330 | { |
| 1316 | int i, eccsize = chip->ecc.size; | 1331 | int i, eccsize = chip->ecc.size; |
| 1317 | int eccbytes = chip->ecc.bytes; | 1332 | int eccbytes = chip->ecc.bytes; |
| @@ -1320,6 +1335,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, | |||
| 1320 | uint8_t *ecc_code = chip->buffers->ecccode; | 1335 | uint8_t *ecc_code = chip->buffers->ecccode; |
| 1321 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 1336 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
| 1322 | uint8_t *ecc_calc = chip->buffers->ecccalc; | 1337 | uint8_t *ecc_calc = chip->buffers->ecccalc; |
| 1338 | unsigned int max_bitflips = 0; | ||
| 1323 | 1339 | ||
| 1324 | /* Read the OOB area first */ | 1340 | /* Read the OOB area first */ |
| 1325 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | 1341 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); |
| @@ -1337,12 +1353,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, | |||
| 1337 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | 1353 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
| 1338 | 1354 | ||
| 1339 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); | 1355 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); |
| 1340 | if (stat < 0) | 1356 | if (stat < 0) { |
| 1341 | mtd->ecc_stats.failed++; | 1357 | mtd->ecc_stats.failed++; |
| 1342 | else | 1358 | } else { |
| 1343 | mtd->ecc_stats.corrected += stat; | 1359 | mtd->ecc_stats.corrected += stat; |
| 1360 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 1361 | } | ||
| 1344 | } | 1362 | } |
| 1345 | return 0; | 1363 | return max_bitflips; |
| 1346 | } | 1364 | } |
| 1347 | 1365 | ||
| 1348 | /** | 1366 | /** |
| @@ -1350,19 +1368,21 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, | |||
| 1350 | * @mtd: mtd info structure | 1368 | * @mtd: mtd info structure |
| 1351 | * @chip: nand chip info structure | 1369 | * @chip: nand chip info structure |
| 1352 | * @buf: buffer to store read data | 1370 | * @buf: buffer to store read data |
| 1371 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
| 1353 | * @page: page number to read | 1372 | * @page: page number to read |
| 1354 | * | 1373 | * |
| 1355 | * The hw generator calculates the error syndrome automatically. Therefore we | 1374 | * The hw generator calculates the error syndrome automatically. Therefore we |
| 1356 | * need a special oob layout and handling. | 1375 | * need a special oob layout and handling. |
| 1357 | */ | 1376 | */ |
| 1358 | static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 1377 | static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, |
| 1359 | uint8_t *buf, int page) | 1378 | uint8_t *buf, int oob_required, int page) |
| 1360 | { | 1379 | { |
| 1361 | int i, eccsize = chip->ecc.size; | 1380 | int i, eccsize = chip->ecc.size; |
| 1362 | int eccbytes = chip->ecc.bytes; | 1381 | int eccbytes = chip->ecc.bytes; |
| 1363 | int eccsteps = chip->ecc.steps; | 1382 | int eccsteps = chip->ecc.steps; |
| 1364 | uint8_t *p = buf; | 1383 | uint8_t *p = buf; |
| 1365 | uint8_t *oob = chip->oob_poi; | 1384 | uint8_t *oob = chip->oob_poi; |
| 1385 | unsigned int max_bitflips = 0; | ||
| 1366 | 1386 | ||
| 1367 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | 1387 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |
| 1368 | int stat; | 1388 | int stat; |
| @@ -1379,10 +1399,12 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1379 | chip->read_buf(mtd, oob, eccbytes); | 1399 | chip->read_buf(mtd, oob, eccbytes); |
| 1380 | stat = chip->ecc.correct(mtd, p, oob, NULL); | 1400 | stat = chip->ecc.correct(mtd, p, oob, NULL); |
| 1381 | 1401 | ||
| 1382 | if (stat < 0) | 1402 | if (stat < 0) { |
| 1383 | mtd->ecc_stats.failed++; | 1403 | mtd->ecc_stats.failed++; |
| 1384 | else | 1404 | } else { |
| 1385 | mtd->ecc_stats.corrected += stat; | 1405 | mtd->ecc_stats.corrected += stat; |
| 1406 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
| 1407 | } | ||
| 1386 | 1408 | ||
| 1387 | oob += eccbytes; | 1409 | oob += eccbytes; |
| 1388 | 1410 | ||
| @@ -1397,7 +1419,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1397 | if (i) | 1419 | if (i) |
| 1398 | chip->read_buf(mtd, oob, i); | 1420 | chip->read_buf(mtd, oob, i); |
| 1399 | 1421 | ||
| 1400 | return 0; | 1422 | return max_bitflips; |
| 1401 | } | 1423 | } |
| 1402 | 1424 | ||
| 1403 | /** | 1425 | /** |
| @@ -1459,11 +1481,9 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | |||
| 1459 | static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | 1481 | static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, |
| 1460 | struct mtd_oob_ops *ops) | 1482 | struct mtd_oob_ops *ops) |
| 1461 | { | 1483 | { |
| 1462 | int chipnr, page, realpage, col, bytes, aligned; | 1484 | int chipnr, page, realpage, col, bytes, aligned, oob_required; |
| 1463 | struct nand_chip *chip = mtd->priv; | 1485 | struct nand_chip *chip = mtd->priv; |
| 1464 | struct mtd_ecc_stats stats; | 1486 | struct mtd_ecc_stats stats; |
| 1465 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | ||
| 1466 | int sndcmd = 1; | ||
| 1467 | int ret = 0; | 1487 | int ret = 0; |
| 1468 | uint32_t readlen = ops->len; | 1488 | uint32_t readlen = ops->len; |
| 1469 | uint32_t oobreadlen = ops->ooblen; | 1489 | uint32_t oobreadlen = ops->ooblen; |
| @@ -1471,6 +1491,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1471 | mtd->oobavail : mtd->oobsize; | 1491 | mtd->oobavail : mtd->oobsize; |
| 1472 | 1492 | ||
| 1473 | uint8_t *bufpoi, *oob, *buf; | 1493 | uint8_t *bufpoi, *oob, *buf; |
| 1494 | unsigned int max_bitflips = 0; | ||
| 1474 | 1495 | ||
| 1475 | stats = mtd->ecc_stats; | 1496 | stats = mtd->ecc_stats; |
| 1476 | 1497 | ||
| @@ -1484,6 +1505,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1484 | 1505 | ||
| 1485 | buf = ops->datbuf; | 1506 | buf = ops->datbuf; |
| 1486 | oob = ops->oobbuf; | 1507 | oob = ops->oobbuf; |
| 1508 | oob_required = oob ? 1 : 0; | ||
| 1487 | 1509 | ||
| 1488 | while (1) { | 1510 | while (1) { |
| 1489 | bytes = min(mtd->writesize - col, readlen); | 1511 | bytes = min(mtd->writesize - col, readlen); |
| @@ -1493,21 +1515,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1493 | if (realpage != chip->pagebuf || oob) { | 1515 | if (realpage != chip->pagebuf || oob) { |
| 1494 | bufpoi = aligned ? buf : chip->buffers->databuf; | 1516 | bufpoi = aligned ? buf : chip->buffers->databuf; |
| 1495 | 1517 | ||
| 1496 | if (likely(sndcmd)) { | 1518 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); |
| 1497 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); | ||
| 1498 | sndcmd = 0; | ||
| 1499 | } | ||
| 1500 | 1519 | ||
| 1501 | /* Now read the page into the buffer */ | 1520 | /* |
| 1521 | * Now read the page into the buffer. Absent an error, | ||
| 1522 | * the read methods return max bitflips per ecc step. | ||
| 1523 | */ | ||
| 1502 | if (unlikely(ops->mode == MTD_OPS_RAW)) | 1524 | if (unlikely(ops->mode == MTD_OPS_RAW)) |
| 1503 | ret = chip->ecc.read_page_raw(mtd, chip, | 1525 | ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, |
| 1504 | bufpoi, page); | 1526 | oob_required, |
| 1527 | page); | ||
| 1505 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) | 1528 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) |
| 1506 | ret = chip->ecc.read_subpage(mtd, chip, | 1529 | ret = chip->ecc.read_subpage(mtd, chip, |
| 1507 | col, bytes, bufpoi); | 1530 | col, bytes, bufpoi); |
| 1508 | else | 1531 | else |
| 1509 | ret = chip->ecc.read_page(mtd, chip, bufpoi, | 1532 | ret = chip->ecc.read_page(mtd, chip, bufpoi, |
| 1510 | page); | 1533 | oob_required, page); |
| 1511 | if (ret < 0) { | 1534 | if (ret < 0) { |
| 1512 | if (!aligned) | 1535 | if (!aligned) |
| 1513 | /* Invalidate page cache */ | 1536 | /* Invalidate page cache */ |
| @@ -1515,22 +1538,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1515 | break; | 1538 | break; |
| 1516 | } | 1539 | } |
| 1517 | 1540 | ||
| 1541 | max_bitflips = max_t(unsigned int, max_bitflips, ret); | ||
| 1542 | |||
| 1518 | /* Transfer not aligned data */ | 1543 | /* Transfer not aligned data */ |
| 1519 | if (!aligned) { | 1544 | if (!aligned) { |
| 1520 | if (!NAND_SUBPAGE_READ(chip) && !oob && | 1545 | if (!NAND_SUBPAGE_READ(chip) && !oob && |
| 1521 | !(mtd->ecc_stats.failed - stats.failed) && | 1546 | !(mtd->ecc_stats.failed - stats.failed) && |
| 1522 | (ops->mode != MTD_OPS_RAW)) | 1547 | (ops->mode != MTD_OPS_RAW)) { |
| 1523 | chip->pagebuf = realpage; | 1548 | chip->pagebuf = realpage; |
| 1524 | else | 1549 | chip->pagebuf_bitflips = ret; |
| 1550 | } else { | ||
| 1525 | /* Invalidate page cache */ | 1551 | /* Invalidate page cache */ |
| 1526 | chip->pagebuf = -1; | 1552 | chip->pagebuf = -1; |
| 1553 | } | ||
| 1527 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1554 | memcpy(buf, chip->buffers->databuf + col, bytes); |
| 1528 | } | 1555 | } |
| 1529 | 1556 | ||
| 1530 | buf += bytes; | 1557 | buf += bytes; |
| 1531 | 1558 | ||
| 1532 | if (unlikely(oob)) { | 1559 | if (unlikely(oob)) { |
| 1533 | |||
| 1534 | int toread = min(oobreadlen, max_oobsize); | 1560 | int toread = min(oobreadlen, max_oobsize); |
| 1535 | 1561 | ||
| 1536 | if (toread) { | 1562 | if (toread) { |
| @@ -1541,13 +1567,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1541 | } | 1567 | } |
| 1542 | 1568 | ||
| 1543 | if (!(chip->options & NAND_NO_READRDY)) { | 1569 | if (!(chip->options & NAND_NO_READRDY)) { |
| 1544 | /* | 1570 | /* Apply delay or wait for ready/busy pin */ |
| 1545 | * Apply delay or wait for ready/busy pin. Do | ||
| 1546 | * this before the AUTOINCR check, so no | ||
| 1547 | * problems arise if a chip which does auto | ||
| 1548 | * increment is marked as NOAUTOINCR by the | ||
| 1549 | * board driver. | ||
| 1550 | */ | ||
| 1551 | if (!chip->dev_ready) | 1571 | if (!chip->dev_ready) |
| 1552 | udelay(chip->chip_delay); | 1572 | udelay(chip->chip_delay); |
| 1553 | else | 1573 | else |
| @@ -1556,6 +1576,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1556 | } else { | 1576 | } else { |
| 1557 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1577 | memcpy(buf, chip->buffers->databuf + col, bytes); |
| 1558 | buf += bytes; | 1578 | buf += bytes; |
| 1579 | max_bitflips = max_t(unsigned int, max_bitflips, | ||
| 1580 | chip->pagebuf_bitflips); | ||
| 1559 | } | 1581 | } |
| 1560 | 1582 | ||
| 1561 | readlen -= bytes; | 1583 | readlen -= bytes; |
| @@ -1575,26 +1597,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1575 | chip->select_chip(mtd, -1); | 1597 | chip->select_chip(mtd, -1); |
| 1576 | chip->select_chip(mtd, chipnr); | 1598 | chip->select_chip(mtd, chipnr); |
| 1577 | } | 1599 | } |
| 1578 | |||
| 1579 | /* | ||
| 1580 | * Check, if the chip supports auto page increment or if we | ||
| 1581 | * have hit a block boundary. | ||
| 1582 | */ | ||
| 1583 | if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) | ||
| 1584 | sndcmd = 1; | ||
| 1585 | } | 1600 | } |
| 1586 | 1601 | ||
| 1587 | ops->retlen = ops->len - (size_t) readlen; | 1602 | ops->retlen = ops->len - (size_t) readlen; |
| 1588 | if (oob) | 1603 | if (oob) |
| 1589 | ops->oobretlen = ops->ooblen - oobreadlen; | 1604 | ops->oobretlen = ops->ooblen - oobreadlen; |
| 1590 | 1605 | ||
| 1591 | if (ret) | 1606 | if (ret < 0) |
| 1592 | return ret; | 1607 | return ret; |
| 1593 | 1608 | ||
| 1594 | if (mtd->ecc_stats.failed - stats.failed) | 1609 | if (mtd->ecc_stats.failed - stats.failed) |
| 1595 | return -EBADMSG; | 1610 | return -EBADMSG; |
| 1596 | 1611 | ||
| 1597 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 1612 | return max_bitflips; |
| 1598 | } | 1613 | } |
| 1599 | 1614 | ||
| 1600 | /** | 1615 | /** |
| @@ -1630,17 +1645,13 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 1630 | * @mtd: mtd info structure | 1645 | * @mtd: mtd info structure |
| 1631 | * @chip: nand chip info structure | 1646 | * @chip: nand chip info structure |
| 1632 | * @page: page number to read | 1647 | * @page: page number to read |
| 1633 | * @sndcmd: flag whether to issue read command or not | ||
| 1634 | */ | 1648 | */ |
| 1635 | static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, | 1649 | static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, |
| 1636 | int page, int sndcmd) | 1650 | int page) |
| 1637 | { | 1651 | { |
| 1638 | if (sndcmd) { | 1652 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); |
| 1639 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
| 1640 | sndcmd = 0; | ||
| 1641 | } | ||
| 1642 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 1653 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
| 1643 | return sndcmd; | 1654 | return 0; |
| 1644 | } | 1655 | } |
| 1645 | 1656 | ||
| 1646 | /** | 1657 | /** |
| @@ -1649,10 +1660,9 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1649 | * @mtd: mtd info structure | 1660 | * @mtd: mtd info structure |
| 1650 | * @chip: nand chip info structure | 1661 | * @chip: nand chip info structure |
| 1651 | * @page: page number to read | 1662 | * @page: page number to read |
| 1652 | * @sndcmd: flag whether to issue read command or not | ||
| 1653 | */ | 1663 | */ |
| 1654 | static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 1664 | static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, |
| 1655 | int page, int sndcmd) | 1665 | int page) |
| 1656 | { | 1666 | { |
| 1657 | uint8_t *buf = chip->oob_poi; | 1667 | uint8_t *buf = chip->oob_poi; |
| 1658 | int length = mtd->oobsize; | 1668 | int length = mtd->oobsize; |
| @@ -1679,7 +1689,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1679 | if (length > 0) | 1689 | if (length > 0) |
| 1680 | chip->read_buf(mtd, bufpoi, length); | 1690 | chip->read_buf(mtd, bufpoi, length); |
| 1681 | 1691 | ||
| 1682 | return 1; | 1692 | return 0; |
| 1683 | } | 1693 | } |
| 1684 | 1694 | ||
| 1685 | /** | 1695 | /** |
| @@ -1775,13 +1785,13 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, | |||
| 1775 | static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | 1785 | static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, |
| 1776 | struct mtd_oob_ops *ops) | 1786 | struct mtd_oob_ops *ops) |
| 1777 | { | 1787 | { |
| 1778 | int page, realpage, chipnr, sndcmd = 1; | 1788 | int page, realpage, chipnr; |
| 1779 | struct nand_chip *chip = mtd->priv; | 1789 | struct nand_chip *chip = mtd->priv; |
| 1780 | struct mtd_ecc_stats stats; | 1790 | struct mtd_ecc_stats stats; |
| 1781 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | ||
| 1782 | int readlen = ops->ooblen; | 1791 | int readlen = ops->ooblen; |
| 1783 | int len; | 1792 | int len; |
| 1784 | uint8_t *buf = ops->oobbuf; | 1793 | uint8_t *buf = ops->oobbuf; |
| 1794 | int ret = 0; | ||
| 1785 | 1795 | ||
| 1786 | pr_debug("%s: from = 0x%08Lx, len = %i\n", | 1796 | pr_debug("%s: from = 0x%08Lx, len = %i\n", |
| 1787 | __func__, (unsigned long long)from, readlen); | 1797 | __func__, (unsigned long long)from, readlen); |
| @@ -1817,20 +1827,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 1817 | 1827 | ||
| 1818 | while (1) { | 1828 | while (1) { |
| 1819 | if (ops->mode == MTD_OPS_RAW) | 1829 | if (ops->mode == MTD_OPS_RAW) |
| 1820 | sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); | 1830 | ret = chip->ecc.read_oob_raw(mtd, chip, page); |
| 1821 | else | 1831 | else |
| 1822 | sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); | 1832 | ret = chip->ecc.read_oob(mtd, chip, page); |
| 1833 | |||
| 1834 | if (ret < 0) | ||
| 1835 | break; | ||
| 1823 | 1836 | ||
| 1824 | len = min(len, readlen); | 1837 | len = min(len, readlen); |
| 1825 | buf = nand_transfer_oob(chip, buf, ops, len); | 1838 | buf = nand_transfer_oob(chip, buf, ops, len); |
| 1826 | 1839 | ||
| 1827 | if (!(chip->options & NAND_NO_READRDY)) { | 1840 | if (!(chip->options & NAND_NO_READRDY)) { |
| 1828 | /* | 1841 | /* Apply delay or wait for ready/busy pin */ |
| 1829 | * Apply delay or wait for ready/busy pin. Do this | ||
| 1830 | * before the AUTOINCR check, so no problems arise if a | ||
| 1831 | * chip which does auto increment is marked as | ||
| 1832 | * NOAUTOINCR by the board driver. | ||
| 1833 | */ | ||
| 1834 | if (!chip->dev_ready) | 1842 | if (!chip->dev_ready) |
| 1835 | udelay(chip->chip_delay); | 1843 | udelay(chip->chip_delay); |
| 1836 | else | 1844 | else |
| @@ -1851,16 +1859,12 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 1851 | chip->select_chip(mtd, -1); | 1859 | chip->select_chip(mtd, -1); |
| 1852 | chip->select_chip(mtd, chipnr); | 1860 | chip->select_chip(mtd, chipnr); |
| 1853 | } | 1861 | } |
| 1854 | |||
| 1855 | /* | ||
| 1856 | * Check, if the chip supports auto page increment or if we | ||
| 1857 | * have hit a block boundary. | ||
| 1858 | */ | ||
| 1859 | if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) | ||
| 1860 | sndcmd = 1; | ||
| 1861 | } | 1862 | } |
| 1862 | 1863 | ||
| 1863 | ops->oobretlen = ops->ooblen; | 1864 | ops->oobretlen = ops->ooblen - readlen; |
| 1865 | |||
| 1866 | if (ret < 0) | ||
| 1867 | return ret; | ||
| 1864 | 1868 | ||
| 1865 | if (mtd->ecc_stats.failed - stats.failed) | 1869 | if (mtd->ecc_stats.failed - stats.failed) |
| 1866 | return -EBADMSG; | 1870 | return -EBADMSG; |
| @@ -1919,14 +1923,16 @@ out: | |||
| 1919 | * @mtd: mtd info structure | 1923 | * @mtd: mtd info structure |
| 1920 | * @chip: nand chip info structure | 1924 | * @chip: nand chip info structure |
| 1921 | * @buf: data buffer | 1925 | * @buf: data buffer |
| 1926 | * @oob_required: must write chip->oob_poi to OOB | ||
| 1922 | * | 1927 | * |
| 1923 | * Not for syndrome calculating ECC controllers, which use a special oob layout. | 1928 | * Not for syndrome calculating ECC controllers, which use a special oob layout. |
| 1924 | */ | 1929 | */ |
| 1925 | static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 1930 | static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
| 1926 | const uint8_t *buf) | 1931 | const uint8_t *buf, int oob_required) |
| 1927 | { | 1932 | { |
| 1928 | chip->write_buf(mtd, buf, mtd->writesize); | 1933 | chip->write_buf(mtd, buf, mtd->writesize); |
| 1929 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | 1934 | if (oob_required) |
| 1935 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 1930 | } | 1936 | } |
| 1931 | 1937 | ||
| 1932 | /** | 1938 | /** |
| @@ -1934,12 +1940,13 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1934 | * @mtd: mtd info structure | 1940 | * @mtd: mtd info structure |
| 1935 | * @chip: nand chip info structure | 1941 | * @chip: nand chip info structure |
| 1936 | * @buf: data buffer | 1942 | * @buf: data buffer |
| 1943 | * @oob_required: must write chip->oob_poi to OOB | ||
| 1937 | * | 1944 | * |
| 1938 | * We need a special oob layout and handling even when ECC isn't checked. | 1945 | * We need a special oob layout and handling even when ECC isn't checked. |
| 1939 | */ | 1946 | */ |
| 1940 | static void nand_write_page_raw_syndrome(struct mtd_info *mtd, | 1947 | static void nand_write_page_raw_syndrome(struct mtd_info *mtd, |
| 1941 | struct nand_chip *chip, | 1948 | struct nand_chip *chip, |
| 1942 | const uint8_t *buf) | 1949 | const uint8_t *buf, int oob_required) |
| 1943 | { | 1950 | { |
| 1944 | int eccsize = chip->ecc.size; | 1951 | int eccsize = chip->ecc.size; |
| 1945 | int eccbytes = chip->ecc.bytes; | 1952 | int eccbytes = chip->ecc.bytes; |
| @@ -1973,9 +1980,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, | |||
| 1973 | * @mtd: mtd info structure | 1980 | * @mtd: mtd info structure |
| 1974 | * @chip: nand chip info structure | 1981 | * @chip: nand chip info structure |
| 1975 | * @buf: data buffer | 1982 | * @buf: data buffer |
| 1983 | * @oob_required: must write chip->oob_poi to OOB | ||
| 1976 | */ | 1984 | */ |
| 1977 | static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | 1985 | static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 1978 | const uint8_t *buf) | 1986 | const uint8_t *buf, int oob_required) |
| 1979 | { | 1987 | { |
| 1980 | int i, eccsize = chip->ecc.size; | 1988 | int i, eccsize = chip->ecc.size; |
| 1981 | int eccbytes = chip->ecc.bytes; | 1989 | int eccbytes = chip->ecc.bytes; |
| @@ -1991,7 +1999,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1991 | for (i = 0; i < chip->ecc.total; i++) | 1999 | for (i = 0; i < chip->ecc.total; i++) |
| 1992 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; | 2000 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; |
| 1993 | 2001 | ||
| 1994 | chip->ecc.write_page_raw(mtd, chip, buf); | 2002 | chip->ecc.write_page_raw(mtd, chip, buf, 1); |
| 1995 | } | 2003 | } |
| 1996 | 2004 | ||
| 1997 | /** | 2005 | /** |
| @@ -1999,9 +2007,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 1999 | * @mtd: mtd info structure | 2007 | * @mtd: mtd info structure |
| 2000 | * @chip: nand chip info structure | 2008 | * @chip: nand chip info structure |
| 2001 | * @buf: data buffer | 2009 | * @buf: data buffer |
| 2010 | * @oob_required: must write chip->oob_poi to OOB | ||
| 2002 | */ | 2011 | */ |
| 2003 | static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 2012 | static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 2004 | const uint8_t *buf) | 2013 | const uint8_t *buf, int oob_required) |
| 2005 | { | 2014 | { |
| 2006 | int i, eccsize = chip->ecc.size; | 2015 | int i, eccsize = chip->ecc.size; |
| 2007 | int eccbytes = chip->ecc.bytes; | 2016 | int eccbytes = chip->ecc.bytes; |
| @@ -2027,12 +2036,14 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 2027 | * @mtd: mtd info structure | 2036 | * @mtd: mtd info structure |
| 2028 | * @chip: nand chip info structure | 2037 | * @chip: nand chip info structure |
| 2029 | * @buf: data buffer | 2038 | * @buf: data buffer |
| 2039 | * @oob_required: must write chip->oob_poi to OOB | ||
| 2030 | * | 2040 | * |
| 2031 | * The hw generator calculates the error syndrome automatically. Therefore we | 2041 | * The hw generator calculates the error syndrome automatically. Therefore we |
| 2032 | * need a special oob layout and handling. | 2042 | * need a special oob layout and handling. |
| 2033 | */ | 2043 | */ |
| 2034 | static void nand_write_page_syndrome(struct mtd_info *mtd, | 2044 | static void nand_write_page_syndrome(struct mtd_info *mtd, |
| 2035 | struct nand_chip *chip, const uint8_t *buf) | 2045 | struct nand_chip *chip, |
| 2046 | const uint8_t *buf, int oob_required) | ||
| 2036 | { | 2047 | { |
| 2037 | int i, eccsize = chip->ecc.size; | 2048 | int i, eccsize = chip->ecc.size; |
| 2038 | int eccbytes = chip->ecc.bytes; | 2049 | int eccbytes = chip->ecc.bytes; |
| @@ -2071,21 +2082,23 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, | |||
| 2071 | * @mtd: MTD device structure | 2082 | * @mtd: MTD device structure |
| 2072 | * @chip: NAND chip descriptor | 2083 | * @chip: NAND chip descriptor |
| 2073 | * @buf: the data to write | 2084 | * @buf: the data to write |
| 2085 | * @oob_required: must write chip->oob_poi to OOB | ||
| 2074 | * @page: page number to write | 2086 | * @page: page number to write |
| 2075 | * @cached: cached programming | 2087 | * @cached: cached programming |
| 2076 | * @raw: use _raw version of write_page | 2088 | * @raw: use _raw version of write_page |
| 2077 | */ | 2089 | */ |
| 2078 | static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | 2090 | static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
| 2079 | const uint8_t *buf, int page, int cached, int raw) | 2091 | const uint8_t *buf, int oob_required, int page, |
| 2092 | int cached, int raw) | ||
| 2080 | { | 2093 | { |
| 2081 | int status; | 2094 | int status; |
| 2082 | 2095 | ||
| 2083 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); | 2096 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); |
| 2084 | 2097 | ||
| 2085 | if (unlikely(raw)) | 2098 | if (unlikely(raw)) |
| 2086 | chip->ecc.write_page_raw(mtd, chip, buf); | 2099 | chip->ecc.write_page_raw(mtd, chip, buf, oob_required); |
| 2087 | else | 2100 | else |
| 2088 | chip->ecc.write_page(mtd, chip, buf); | 2101 | chip->ecc.write_page(mtd, chip, buf, oob_required); |
| 2089 | 2102 | ||
| 2090 | /* | 2103 | /* |
| 2091 | * Cached progamming disabled for now. Not sure if it's worth the | 2104 | * Cached progamming disabled for now. Not sure if it's worth the |
| @@ -2118,6 +2131,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 2118 | 2131 | ||
| 2119 | if (chip->verify_buf(mtd, buf, mtd->writesize)) | 2132 | if (chip->verify_buf(mtd, buf, mtd->writesize)) |
| 2120 | return -EIO; | 2133 | return -EIO; |
| 2134 | |||
| 2135 | /* Make sure the next page prog is preceded by a status read */ | ||
| 2136 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | ||
| 2121 | #endif | 2137 | #endif |
| 2122 | return 0; | 2138 | return 0; |
| 2123 | } | 2139 | } |
| @@ -2202,6 +2218,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
| 2202 | uint8_t *oob = ops->oobbuf; | 2218 | uint8_t *oob = ops->oobbuf; |
| 2203 | uint8_t *buf = ops->datbuf; | 2219 | uint8_t *buf = ops->datbuf; |
| 2204 | int ret, subpage; | 2220 | int ret, subpage; |
| 2221 | int oob_required = oob ? 1 : 0; | ||
| 2205 | 2222 | ||
| 2206 | ops->retlen = 0; | 2223 | ops->retlen = 0; |
| 2207 | if (!writelen) | 2224 | if (!writelen) |
| @@ -2264,8 +2281,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
| 2264 | memset(chip->oob_poi, 0xff, mtd->oobsize); | 2281 | memset(chip->oob_poi, 0xff, mtd->oobsize); |
| 2265 | } | 2282 | } |
| 2266 | 2283 | ||
| 2267 | ret = chip->write_page(mtd, chip, wbuf, page, cached, | 2284 | ret = chip->write_page(mtd, chip, wbuf, oob_required, page, |
| 2268 | (ops->mode == MTD_OPS_RAW)); | 2285 | cached, (ops->mode == MTD_OPS_RAW)); |
| 2269 | if (ret) | 2286 | if (ret) |
| 2270 | break; | 2287 | break; |
| 2271 | 2288 | ||
| @@ -2898,8 +2915,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 2898 | *busw = NAND_BUSWIDTH_16; | 2915 | *busw = NAND_BUSWIDTH_16; |
| 2899 | 2916 | ||
| 2900 | chip->options &= ~NAND_CHIPOPTIONS_MSK; | 2917 | chip->options &= ~NAND_CHIPOPTIONS_MSK; |
| 2901 | chip->options |= (NAND_NO_READRDY | | 2918 | chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK; |
| 2902 | NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; | ||
| 2903 | 2919 | ||
| 2904 | pr_info("ONFI flash detected\n"); | 2920 | pr_info("ONFI flash detected\n"); |
| 2905 | return 1; | 2921 | return 1; |
| @@ -3076,11 +3092,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
| 3076 | chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | 3092 | chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; |
| 3077 | ident_done: | 3093 | ident_done: |
| 3078 | 3094 | ||
| 3079 | /* | ||
| 3080 | * Set chip as a default. Board drivers can override it, if necessary. | ||
| 3081 | */ | ||
| 3082 | chip->options |= NAND_NO_AUTOINCR; | ||
| 3083 | |||
| 3084 | /* Try to identify manufacturer */ | 3095 | /* Try to identify manufacturer */ |
| 3085 | for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { | 3096 | for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { |
| 3086 | if (nand_manuf_ids[maf_idx].id == *maf_id) | 3097 | if (nand_manuf_ids[maf_idx].id == *maf_id) |
| @@ -3154,10 +3165,11 @@ ident_done: | |||
| 3154 | if (mtd->writesize > 512 && chip->cmdfunc == nand_command) | 3165 | if (mtd->writesize > 512 && chip->cmdfunc == nand_command) |
| 3155 | chip->cmdfunc = nand_command_lp; | 3166 | chip->cmdfunc = nand_command_lp; |
| 3156 | 3167 | ||
| 3157 | pr_info("NAND device: Manufacturer ID:" | 3168 | pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," |
| 3158 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, | 3169 | " page size: %d, OOB size: %d\n", |
| 3159 | nand_manuf_ids[maf_idx].name, | 3170 | *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, |
| 3160 | chip->onfi_version ? chip->onfi_params.model : type->name); | 3171 | chip->onfi_version ? chip->onfi_params.model : type->name, |
| 3172 | mtd->writesize, mtd->oobsize); | ||
| 3161 | 3173 | ||
| 3162 | return type; | 3174 | return type; |
| 3163 | } | 3175 | } |
| @@ -3329,8 +3341,13 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 3329 | if (!chip->ecc.write_oob) | 3341 | if (!chip->ecc.write_oob) |
| 3330 | chip->ecc.write_oob = nand_write_oob_syndrome; | 3342 | chip->ecc.write_oob = nand_write_oob_syndrome; |
| 3331 | 3343 | ||
| 3332 | if (mtd->writesize >= chip->ecc.size) | 3344 | if (mtd->writesize >= chip->ecc.size) { |
| 3345 | if (!chip->ecc.strength) { | ||
| 3346 | pr_warn("Driver must set ecc.strength when using hardware ECC\n"); | ||
| 3347 | BUG(); | ||
| 3348 | } | ||
| 3333 | break; | 3349 | break; |
| 3350 | } | ||
| 3334 | pr_warn("%d byte HW ECC not possible on " | 3351 | pr_warn("%d byte HW ECC not possible on " |
| 3335 | "%d byte page size, fallback to SW ECC\n", | 3352 | "%d byte page size, fallback to SW ECC\n", |
| 3336 | chip->ecc.size, mtd->writesize); | 3353 | chip->ecc.size, mtd->writesize); |
| @@ -3385,7 +3402,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 3385 | BUG(); | 3402 | BUG(); |
| 3386 | } | 3403 | } |
| 3387 | chip->ecc.strength = | 3404 | chip->ecc.strength = |
| 3388 | chip->ecc.bytes*8 / fls(8*chip->ecc.size); | 3405 | chip->ecc.bytes * 8 / fls(8 * chip->ecc.size); |
| 3389 | break; | 3406 | break; |
| 3390 | 3407 | ||
| 3391 | case NAND_ECC_NONE: | 3408 | case NAND_ECC_NONE: |
| @@ -3483,7 +3500,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 3483 | 3500 | ||
| 3484 | /* propagate ecc info to mtd_info */ | 3501 | /* propagate ecc info to mtd_info */ |
| 3485 | mtd->ecclayout = chip->ecc.layout; | 3502 | mtd->ecclayout = chip->ecc.layout; |
| 3486 | mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps; | 3503 | mtd->ecc_strength = chip->ecc.strength; |
| 3487 | 3504 | ||
| 3488 | /* Check, if we should skip the bad block table scan */ | 3505 | /* Check, if we should skip the bad block table scan */ |
| 3489 | if (chip->options & NAND_SKIP_BBTSCAN) | 3506 | if (chip->options & NAND_SKIP_BBTSCAN) |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 20a112f591fe..30d1319ff065 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
| @@ -324,6 +324,7 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, | |||
| 324 | 324 | ||
| 325 | buf += mtd->oobsize + mtd->writesize; | 325 | buf += mtd->oobsize + mtd->writesize; |
| 326 | len -= mtd->writesize; | 326 | len -= mtd->writesize; |
| 327 | offs += mtd->writesize; | ||
| 327 | } | 328 | } |
| 328 | return 0; | 329 | return 0; |
| 329 | } | 330 | } |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index af4fe8ca7b5e..621b70b7a159 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
| @@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
| 70 | * These are the new chips with large page size. The pagesize and the | 70 | * These are the new chips with large page size. The pagesize and the |
| 71 | * erasesize is determined from the extended id bytes | 71 | * erasesize is determined from the extended id bytes |
| 72 | */ | 72 | */ |
| 73 | #define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) | 73 | #define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY) |
| 74 | #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) | 74 | #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) |
| 75 | 75 | ||
| 76 | /* 512 Megabit */ | 76 | /* 512 Megabit */ |
| @@ -157,9 +157,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
| 157 | * writes possible, but not implemented now | 157 | * writes possible, but not implemented now |
| 158 | */ | 158 | */ |
| 159 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, | 159 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, |
| 160 | NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | | 160 | NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, |
| 161 | BBT_AUTO_REFRESH | ||
| 162 | }, | ||
| 163 | 161 | ||
| 164 | {NULL,} | 162 | {NULL,} |
| 165 | }; | 163 | }; |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 261f478f8cc3..6cc8fbfabb8e 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
| @@ -268,7 +268,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " | |||
| 268 | #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ | 268 | #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ |
| 269 | #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ | 269 | #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ |
| 270 | #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ | 270 | #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ |
| 271 | #define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */ | ||
| 272 | #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ | 271 | #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ |
| 273 | #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ | 272 | #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ |
| 274 | #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ | 273 | #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ |
| @@ -594,7 +593,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 594 | ns->options |= OPT_PAGE256; | 593 | ns->options |= OPT_PAGE256; |
| 595 | } | 594 | } |
| 596 | else if (ns->geom.pgsz == 512) { | 595 | else if (ns->geom.pgsz == 512) { |
| 597 | ns->options |= (OPT_PAGE512 | OPT_AUTOINCR); | 596 | ns->options |= OPT_PAGE512; |
| 598 | if (ns->busw == 8) | 597 | if (ns->busw == 8) |
| 599 | ns->options |= OPT_PAGE512_8BIT; | 598 | ns->options |= OPT_PAGE512_8BIT; |
| 600 | } else if (ns->geom.pgsz == 2048) { | 599 | } else if (ns->geom.pgsz == 2048) { |
| @@ -663,8 +662,6 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 663 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 662 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
| 664 | if (second_id_byte != nand_flash_ids[i].id) | 663 | if (second_id_byte != nand_flash_ids[i].id) |
| 665 | continue; | 664 | continue; |
| 666 | if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR)) | ||
| 667 | ns->options |= OPT_AUTOINCR; | ||
| 668 | } | 665 | } |
| 669 | 666 | ||
| 670 | if (ns->busw == 16) | 667 | if (ns->busw == 16) |
| @@ -1936,20 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) | |||
| 1936 | if (ns->regs.count == ns->regs.num) { | 1933 | if (ns->regs.count == ns->regs.num) { |
| 1937 | NS_DBG("read_byte: all bytes were read\n"); | 1934 | NS_DBG("read_byte: all bytes were read\n"); |
| 1938 | 1935 | ||
| 1939 | /* | 1936 | if (NS_STATE(ns->nxstate) == STATE_READY) |
| 1940 | * The OPT_AUTOINCR allows to read next consecutive pages without | ||
| 1941 | * new read operation cycle. | ||
| 1942 | */ | ||
| 1943 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { | ||
| 1944 | ns->regs.count = 0; | ||
| 1945 | if (ns->regs.row + 1 < ns->geom.pgnum) | ||
| 1946 | ns->regs.row += 1; | ||
| 1947 | NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row); | ||
| 1948 | do_state_action(ns, ACTION_CPY); | ||
| 1949 | } | ||
| 1950 | else if (NS_STATE(ns->nxstate) == STATE_READY) | ||
| 1951 | switch_state(ns); | 1937 | switch_state(ns); |
| 1952 | |||
| 1953 | } | 1938 | } |
| 1954 | 1939 | ||
| 1955 | return outb; | 1940 | return outb; |
| @@ -2203,14 +2188,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
| 2203 | ns->regs.count += len; | 2188 | ns->regs.count += len; |
| 2204 | 2189 | ||
| 2205 | if (ns->regs.count == ns->regs.num) { | 2190 | if (ns->regs.count == ns->regs.num) { |
| 2206 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { | 2191 | if (NS_STATE(ns->nxstate) == STATE_READY) |
| 2207 | ns->regs.count = 0; | ||
| 2208 | if (ns->regs.row + 1 < ns->geom.pgnum) | ||
| 2209 | ns->regs.row += 1; | ||
| 2210 | NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row); | ||
| 2211 | do_state_action(ns, ACTION_CPY); | ||
| 2212 | } | ||
| 2213 | else if (NS_STATE(ns->nxstate) == STATE_READY) | ||
| 2214 | switch_state(ns); | 2192 | switch_state(ns); |
| 2215 | } | 2193 | } |
| 2216 | 2194 | ||
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index c2b0bba9d8b3..d7f681d0c9b9 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
| @@ -21,6 +21,10 @@ | |||
| 21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | 23 | ||
| 24 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
| 25 | #include <linux/bch.h> | ||
| 26 | #endif | ||
| 27 | |||
| 24 | #include <plat/dma.h> | 28 | #include <plat/dma.h> |
| 25 | #include <plat/gpmc.h> | 29 | #include <plat/gpmc.h> |
| 26 | #include <plat/nand.h> | 30 | #include <plat/nand.h> |
| @@ -127,6 +131,11 @@ struct omap_nand_info { | |||
| 127 | } iomode; | 131 | } iomode; |
| 128 | u_char *buf; | 132 | u_char *buf; |
| 129 | int buf_len; | 133 | int buf_len; |
| 134 | |||
| 135 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
| 136 | struct bch_control *bch; | ||
| 137 | struct nand_ecclayout ecclayout; | ||
| 138 | #endif | ||
| 130 | }; | 139 | }; |
| 131 | 140 | ||
| 132 | /** | 141 | /** |
| @@ -402,7 +411,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | |||
| 402 | PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); | 411 | PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); |
| 403 | if (ret) | 412 | if (ret) |
| 404 | /* PFPW engine is busy, use cpu copy method */ | 413 | /* PFPW engine is busy, use cpu copy method */ |
| 405 | goto out_copy; | 414 | goto out_copy_unmap; |
| 406 | 415 | ||
| 407 | init_completion(&info->comp); | 416 | init_completion(&info->comp); |
| 408 | 417 | ||
| @@ -421,6 +430,8 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | |||
| 421 | dma_unmap_single(&info->pdev->dev, dma_addr, len, dir); | 430 | dma_unmap_single(&info->pdev->dev, dma_addr, len, dir); |
| 422 | return 0; | 431 | return 0; |
| 423 | 432 | ||
| 433 | out_copy_unmap: | ||
| 434 | dma_unmap_single(&info->pdev->dev, dma_addr, len, dir); | ||
| 424 | out_copy: | 435 | out_copy: |
| 425 | if (info->nand.options & NAND_BUSWIDTH_16) | 436 | if (info->nand.options & NAND_BUSWIDTH_16) |
| 426 | is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len) | 437 | is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len) |
| @@ -879,7 +890,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
| 879 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 890 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
| 880 | mtd); | 891 | mtd); |
| 881 | unsigned long timeo = jiffies; | 892 | unsigned long timeo = jiffies; |
| 882 | int status = NAND_STATUS_FAIL, state = this->state; | 893 | int status, state = this->state; |
| 883 | 894 | ||
| 884 | if (state == FL_ERASING) | 895 | if (state == FL_ERASING) |
| 885 | timeo += (HZ * 400) / 1000; | 896 | timeo += (HZ * 400) / 1000; |
| @@ -894,6 +905,8 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
| 894 | break; | 905 | break; |
| 895 | cond_resched(); | 906 | cond_resched(); |
| 896 | } | 907 | } |
| 908 | |||
| 909 | status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); | ||
| 897 | return status; | 910 | return status; |
| 898 | } | 911 | } |
| 899 | 912 | ||
| @@ -925,6 +938,226 @@ static int omap_dev_ready(struct mtd_info *mtd) | |||
| 925 | return 1; | 938 | return 1; |
| 926 | } | 939 | } |
| 927 | 940 | ||
| 941 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
| 942 | |||
| 943 | /** | ||
| 944 | * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction | ||
| 945 | * @mtd: MTD device structure | ||
| 946 | * @mode: Read/Write mode | ||
| 947 | */ | ||
| 948 | static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | ||
| 949 | { | ||
| 950 | int nerrors; | ||
| 951 | unsigned int dev_width; | ||
| 952 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 953 | mtd); | ||
| 954 | struct nand_chip *chip = mtd->priv; | ||
| 955 | |||
| 956 | nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4; | ||
| 957 | dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; | ||
| 958 | /* | ||
| 959 | * Program GPMC to perform correction on one 512-byte sector at a time. | ||
| 960 | * Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and | ||
| 961 | * gives a slight (5%) performance gain (but requires additional code). | ||
| 962 | */ | ||
| 963 | (void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors); | ||
| 964 | } | ||
| 965 | |||
| 966 | /** | ||
| 967 | * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes | ||
| 968 | * @mtd: MTD device structure | ||
| 969 | * @dat: The pointer to data on which ecc is computed | ||
| 970 | * @ecc_code: The ecc_code buffer | ||
| 971 | */ | ||
| 972 | static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat, | ||
| 973 | u_char *ecc_code) | ||
| 974 | { | ||
| 975 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 976 | mtd); | ||
| 977 | return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code); | ||
| 978 | } | ||
| 979 | |||
| 980 | /** | ||
| 981 | * omap3_calculate_ecc_bch8 - Generate 13 bytes of ECC bytes | ||
| 982 | * @mtd: MTD device structure | ||
| 983 | * @dat: The pointer to data on which ecc is computed | ||
| 984 | * @ecc_code: The ecc_code buffer | ||
| 985 | */ | ||
| 986 | static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, | ||
| 987 | u_char *ecc_code) | ||
| 988 | { | ||
| 989 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 990 | mtd); | ||
| 991 | return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code); | ||
| 992 | } | ||
| 993 | |||
| 994 | /** | ||
| 995 | * omap3_correct_data_bch - Decode received data and correct errors | ||
| 996 | * @mtd: MTD device structure | ||
| 997 | * @data: page data | ||
| 998 | * @read_ecc: ecc read from nand flash | ||
| 999 | * @calc_ecc: ecc read from HW ECC registers | ||
| 1000 | */ | ||
| 1001 | static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data, | ||
| 1002 | u_char *read_ecc, u_char *calc_ecc) | ||
| 1003 | { | ||
| 1004 | int i, count; | ||
| 1005 | /* cannot correct more than 8 errors */ | ||
| 1006 | unsigned int errloc[8]; | ||
| 1007 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 1008 | mtd); | ||
| 1009 | |||
| 1010 | count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL, | ||
| 1011 | errloc); | ||
| 1012 | if (count > 0) { | ||
| 1013 | /* correct errors */ | ||
| 1014 | for (i = 0; i < count; i++) { | ||
| 1015 | /* correct data only, not ecc bytes */ | ||
| 1016 | if (errloc[i] < 8*512) | ||
| 1017 | data[errloc[i]/8] ^= 1 << (errloc[i] & 7); | ||
| 1018 | pr_debug("corrected bitflip %u\n", errloc[i]); | ||
| 1019 | } | ||
| 1020 | } else if (count < 0) { | ||
| 1021 | pr_err("ecc unrecoverable error\n"); | ||
| 1022 | } | ||
| 1023 | return count; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /** | ||
| 1027 | * omap3_free_bch - Release BCH ecc resources | ||
| 1028 | * @mtd: MTD device structure | ||
| 1029 | */ | ||
| 1030 | static void omap3_free_bch(struct mtd_info *mtd) | ||
| 1031 | { | ||
| 1032 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 1033 | mtd); | ||
| 1034 | if (info->bch) { | ||
| 1035 | free_bch(info->bch); | ||
| 1036 | info->bch = NULL; | ||
| 1037 | } | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | /** | ||
| 1041 | * omap3_init_bch - Initialize BCH ECC | ||
| 1042 | * @mtd: MTD device structure | ||
| 1043 | * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW) | ||
| 1044 | */ | ||
| 1045 | static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | ||
| 1046 | { | ||
| 1047 | int ret, max_errors; | ||
| 1048 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 1049 | mtd); | ||
| 1050 | #ifdef CONFIG_MTD_NAND_OMAP_BCH8 | ||
| 1051 | const int hw_errors = 8; | ||
| 1052 | #else | ||
| 1053 | const int hw_errors = 4; | ||
| 1054 | #endif | ||
| 1055 | info->bch = NULL; | ||
| 1056 | |||
| 1057 | max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? 8 : 4; | ||
| 1058 | if (max_errors != hw_errors) { | ||
| 1059 | pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported", | ||
| 1060 | max_errors, hw_errors); | ||
| 1061 | goto fail; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | /* initialize GPMC BCH engine */ | ||
| 1065 | ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors); | ||
| 1066 | if (ret) | ||
| 1067 | goto fail; | ||
| 1068 | |||
| 1069 | /* software bch library is only used to detect and locate errors */ | ||
| 1070 | info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */); | ||
| 1071 | if (!info->bch) | ||
| 1072 | goto fail; | ||
| 1073 | |||
| 1074 | info->nand.ecc.size = 512; | ||
| 1075 | info->nand.ecc.hwctl = omap3_enable_hwecc_bch; | ||
| 1076 | info->nand.ecc.correct = omap3_correct_data_bch; | ||
| 1077 | info->nand.ecc.mode = NAND_ECC_HW; | ||
| 1078 | |||
| 1079 | /* | ||
| 1080 | * The number of corrected errors in an ecc block that will trigger | ||
| 1081 | * block scrubbing defaults to the ecc strength (4 or 8). | ||
| 1082 | * Set mtd->bitflip_threshold here to define a custom threshold. | ||
| 1083 | */ | ||
| 1084 | |||
| 1085 | if (max_errors == 8) { | ||
| 1086 | info->nand.ecc.strength = 8; | ||
| 1087 | info->nand.ecc.bytes = 13; | ||
| 1088 | info->nand.ecc.calculate = omap3_calculate_ecc_bch8; | ||
| 1089 | } else { | ||
| 1090 | info->nand.ecc.strength = 4; | ||
| 1091 | info->nand.ecc.bytes = 7; | ||
| 1092 | info->nand.ecc.calculate = omap3_calculate_ecc_bch4; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors); | ||
| 1096 | return 0; | ||
| 1097 | fail: | ||
| 1098 | omap3_free_bch(mtd); | ||
| 1099 | return -1; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | /** | ||
| 1103 | * omap3_init_bch_tail - Build an oob layout for BCH ECC correction. | ||
| 1104 | * @mtd: MTD device structure | ||
| 1105 | */ | ||
| 1106 | static int omap3_init_bch_tail(struct mtd_info *mtd) | ||
| 1107 | { | ||
| 1108 | int i, steps; | ||
| 1109 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
| 1110 | mtd); | ||
| 1111 | struct nand_ecclayout *layout = &info->ecclayout; | ||
| 1112 | |||
| 1113 | /* build oob layout */ | ||
| 1114 | steps = mtd->writesize/info->nand.ecc.size; | ||
| 1115 | layout->eccbytes = steps*info->nand.ecc.bytes; | ||
| 1116 | |||
| 1117 | /* do not bother creating special oob layouts for small page devices */ | ||
| 1118 | if (mtd->oobsize < 64) { | ||
| 1119 | pr_err("BCH ecc is not supported on small page devices\n"); | ||
| 1120 | goto fail; | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | /* reserve 2 bytes for bad block marker */ | ||
| 1124 | if (layout->eccbytes+2 > mtd->oobsize) { | ||
| 1125 | pr_err("no oob layout available for oobsize %d eccbytes %u\n", | ||
| 1126 | mtd->oobsize, layout->eccbytes); | ||
| 1127 | goto fail; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | /* put ecc bytes at oob tail */ | ||
| 1131 | for (i = 0; i < layout->eccbytes; i++) | ||
| 1132 | layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; | ||
| 1133 | |||
| 1134 | layout->oobfree[0].offset = 2; | ||
| 1135 | layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; | ||
| 1136 | info->nand.ecc.layout = layout; | ||
| 1137 | |||
| 1138 | if (!(info->nand.options & NAND_BUSWIDTH_16)) | ||
| 1139 | info->nand.badblock_pattern = &bb_descrip_flashbased; | ||
| 1140 | return 0; | ||
| 1141 | fail: | ||
| 1142 | omap3_free_bch(mtd); | ||
| 1143 | return -1; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | #else | ||
| 1147 | static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | ||
| 1148 | { | ||
| 1149 | pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n"); | ||
| 1150 | return -1; | ||
| 1151 | } | ||
| 1152 | static int omap3_init_bch_tail(struct mtd_info *mtd) | ||
| 1153 | { | ||
| 1154 | return -1; | ||
| 1155 | } | ||
| 1156 | static void omap3_free_bch(struct mtd_info *mtd) | ||
| 1157 | { | ||
| 1158 | } | ||
| 1159 | #endif /* CONFIG_MTD_NAND_OMAP_BCH */ | ||
| 1160 | |||
| 928 | static int __devinit omap_nand_probe(struct platform_device *pdev) | 1161 | static int __devinit omap_nand_probe(struct platform_device *pdev) |
| 929 | { | 1162 | { |
| 930 | struct omap_nand_info *info; | 1163 | struct omap_nand_info *info; |
| @@ -1063,6 +1296,13 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
| 1063 | info->nand.ecc.hwctl = omap_enable_hwecc; | 1296 | info->nand.ecc.hwctl = omap_enable_hwecc; |
| 1064 | info->nand.ecc.correct = omap_correct_data; | 1297 | info->nand.ecc.correct = omap_correct_data; |
| 1065 | info->nand.ecc.mode = NAND_ECC_HW; | 1298 | info->nand.ecc.mode = NAND_ECC_HW; |
| 1299 | } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || | ||
| 1300 | (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { | ||
| 1301 | err = omap3_init_bch(&info->mtd, pdata->ecc_opt); | ||
| 1302 | if (err) { | ||
| 1303 | err = -EINVAL; | ||
| 1304 | goto out_release_mem_region; | ||
| 1305 | } | ||
| 1066 | } | 1306 | } |
| 1067 | 1307 | ||
| 1068 | /* DIP switches on some boards change between 8 and 16 bit | 1308 | /* DIP switches on some boards change between 8 and 16 bit |
| @@ -1094,6 +1334,14 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
| 1094 | (offset + omap_oobinfo.eccbytes); | 1334 | (offset + omap_oobinfo.eccbytes); |
| 1095 | 1335 | ||
| 1096 | info->nand.ecc.layout = &omap_oobinfo; | 1336 | info->nand.ecc.layout = &omap_oobinfo; |
| 1337 | } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || | ||
| 1338 | (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { | ||
| 1339 | /* build OOB layout for BCH ECC correction */ | ||
| 1340 | err = omap3_init_bch_tail(&info->mtd); | ||
| 1341 | if (err) { | ||
| 1342 | err = -EINVAL; | ||
| 1343 | goto out_release_mem_region; | ||
| 1344 | } | ||
| 1097 | } | 1345 | } |
| 1098 | 1346 | ||
| 1099 | /* second phase scan */ | 1347 | /* second phase scan */ |
| @@ -1122,6 +1370,7 @@ static int omap_nand_remove(struct platform_device *pdev) | |||
| 1122 | struct mtd_info *mtd = platform_get_drvdata(pdev); | 1370 | struct mtd_info *mtd = platform_get_drvdata(pdev); |
| 1123 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1371 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
| 1124 | mtd); | 1372 | mtd); |
| 1373 | omap3_free_bch(&info->mtd); | ||
| 1125 | 1374 | ||
| 1126 | platform_set_drvdata(pdev, NULL); | 1375 | platform_set_drvdata(pdev, NULL); |
| 1127 | if (info->dma_ch != -1) | 1376 | if (info->dma_ch != -1) |
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 974dbf8251c9..1440e51cedcc 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c | |||
| @@ -155,7 +155,6 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) | |||
| 155 | chip->ecc.mode = NAND_ECC_SOFT; | 155 | chip->ecc.mode = NAND_ECC_SOFT; |
| 156 | 156 | ||
| 157 | /* Enable the following for a flash based bad block table */ | 157 | /* Enable the following for a flash based bad block table */ |
| 158 | chip->options = NAND_NO_AUTOINCR; | ||
| 159 | chip->bbt_options = NAND_BBT_USE_FLASH; | 158 | chip->bbt_options = NAND_BBT_USE_FLASH; |
| 160 | 159 | ||
| 161 | /* Scan to find existence of the device */ | 160 | /* Scan to find existence of the device */ |
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 6404e6e81b10..1bcb52040422 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c | |||
| @@ -23,14 +23,18 @@ struct plat_nand_data { | |||
| 23 | void __iomem *io_base; | 23 | void __iomem *io_base; |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | static const char *part_probe_types[] = { "cmdlinepart", NULL }; | ||
| 27 | |||
| 26 | /* | 28 | /* |
| 27 | * Probe for the NAND device. | 29 | * Probe for the NAND device. |
| 28 | */ | 30 | */ |
| 29 | static int __devinit plat_nand_probe(struct platform_device *pdev) | 31 | static int __devinit plat_nand_probe(struct platform_device *pdev) |
| 30 | { | 32 | { |
| 31 | struct platform_nand_data *pdata = pdev->dev.platform_data; | 33 | struct platform_nand_data *pdata = pdev->dev.platform_data; |
| 34 | struct mtd_part_parser_data ppdata; | ||
| 32 | struct plat_nand_data *data; | 35 | struct plat_nand_data *data; |
| 33 | struct resource *res; | 36 | struct resource *res; |
| 37 | const char **part_types; | ||
| 34 | int err = 0; | 38 | int err = 0; |
| 35 | 39 | ||
| 36 | if (pdata->chip.nr_chips < 1) { | 40 | if (pdata->chip.nr_chips < 1) { |
| @@ -75,6 +79,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) | |||
| 75 | data->chip.select_chip = pdata->ctrl.select_chip; | 79 | data->chip.select_chip = pdata->ctrl.select_chip; |
| 76 | data->chip.write_buf = pdata->ctrl.write_buf; | 80 | data->chip.write_buf = pdata->ctrl.write_buf; |
| 77 | data->chip.read_buf = pdata->ctrl.read_buf; | 81 | data->chip.read_buf = pdata->ctrl.read_buf; |
| 82 | data->chip.read_byte = pdata->ctrl.read_byte; | ||
| 78 | data->chip.chip_delay = pdata->chip.chip_delay; | 83 | data->chip.chip_delay = pdata->chip.chip_delay; |
| 79 | data->chip.options |= pdata->chip.options; | 84 | data->chip.options |= pdata->chip.options; |
| 80 | data->chip.bbt_options |= pdata->chip.bbt_options; | 85 | data->chip.bbt_options |= pdata->chip.bbt_options; |
| @@ -98,8 +103,10 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) | |||
| 98 | goto out; | 103 | goto out; |
| 99 | } | 104 | } |
| 100 | 105 | ||
| 101 | err = mtd_device_parse_register(&data->mtd, | 106 | part_types = pdata->chip.part_probe_types ? : part_probe_types; |
| 102 | pdata->chip.part_probe_types, NULL, | 107 | |
| 108 | ppdata.of_node = pdev->dev.of_node; | ||
| 109 | err = mtd_device_parse_register(&data->mtd, part_types, &ppdata, | ||
| 103 | pdata->chip.partitions, | 110 | pdata->chip.partitions, |
| 104 | pdata->chip.nr_partitions); | 111 | pdata->chip.nr_partitions); |
| 105 | 112 | ||
| @@ -140,12 +147,19 @@ static int __devexit plat_nand_remove(struct platform_device *pdev) | |||
| 140 | return 0; | 147 | return 0; |
| 141 | } | 148 | } |
| 142 | 149 | ||
| 150 | static const struct of_device_id plat_nand_match[] = { | ||
| 151 | { .compatible = "gen_nand" }, | ||
| 152 | {}, | ||
| 153 | }; | ||
| 154 | MODULE_DEVICE_TABLE(of, plat_nand_match); | ||
| 155 | |||
| 143 | static struct platform_driver plat_nand_driver = { | 156 | static struct platform_driver plat_nand_driver = { |
| 144 | .probe = plat_nand_probe, | 157 | .probe = plat_nand_probe, |
| 145 | .remove = __devexit_p(plat_nand_remove), | 158 | .remove = __devexit_p(plat_nand_remove), |
| 146 | .driver = { | 159 | .driver = { |
| 147 | .name = "gen_nand", | 160 | .name = "gen_nand", |
| 148 | .owner = THIS_MODULE, | 161 | .owner = THIS_MODULE, |
| 162 | .of_match_table = plat_nand_match, | ||
| 149 | }, | 163 | }, |
| 150 | }; | 164 | }; |
| 151 | 165 | ||
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index def50caa6f84..252aaefcacfa 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
| @@ -682,14 +682,15 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
| 682 | } | 682 | } |
| 683 | 683 | ||
| 684 | static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, | 684 | static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, |
| 685 | struct nand_chip *chip, const uint8_t *buf) | 685 | struct nand_chip *chip, const uint8_t *buf, int oob_required) |
| 686 | { | 686 | { |
| 687 | chip->write_buf(mtd, buf, mtd->writesize); | 687 | chip->write_buf(mtd, buf, mtd->writesize); |
| 688 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | 688 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, | 691 | static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, |
| 692 | struct nand_chip *chip, uint8_t *buf, int page) | 692 | struct nand_chip *chip, uint8_t *buf, int oob_required, |
| 693 | int page) | ||
| 693 | { | 694 | { |
| 694 | struct pxa3xx_nand_host *host = mtd->priv; | 695 | struct pxa3xx_nand_host *host = mtd->priv; |
| 695 | struct pxa3xx_nand_info *info = host->info_data; | 696 | struct pxa3xx_nand_info *info = host->info_data; |
| @@ -1004,7 +1005,6 @@ KEEP_CONFIG: | |||
| 1004 | chip->ecc.size = host->page_size; | 1005 | chip->ecc.size = host->page_size; |
| 1005 | chip->ecc.strength = 1; | 1006 | chip->ecc.strength = 1; |
| 1006 | 1007 | ||
| 1007 | chip->options = NAND_NO_AUTOINCR; | ||
| 1008 | chip->options |= NAND_NO_READRDY; | 1008 | chip->options |= NAND_NO_READRDY; |
| 1009 | if (host->reg_ndcr & NDCR_DWIDTH_M) | 1009 | if (host->reg_ndcr & NDCR_DWIDTH_M) |
| 1010 | chip->options |= NAND_BUSWIDTH_16; | 1010 | chip->options |= NAND_BUSWIDTH_16; |
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index c2040187c813..8cb627751c9c 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c | |||
| @@ -539,14 +539,11 @@ exit: | |||
| 539 | * nand_read_oob_syndrome assumes we can send column address - we can't | 539 | * nand_read_oob_syndrome assumes we can send column address - we can't |
| 540 | */ | 540 | */ |
| 541 | static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | 541 | static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
| 542 | int page, int sndcmd) | 542 | int page) |
| 543 | { | 543 | { |
| 544 | if (sndcmd) { | 544 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); |
| 545 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
| 546 | sndcmd = 0; | ||
| 547 | } | ||
| 548 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 545 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
| 549 | return sndcmd; | 546 | return 0; |
| 550 | } | 547 | } |
| 551 | 548 | ||
| 552 | /* | 549 | /* |
| @@ -1104,18 +1101,7 @@ static struct pci_driver r852_pci_driver = { | |||
| 1104 | .driver.pm = &r852_pm_ops, | 1101 | .driver.pm = &r852_pm_ops, |
| 1105 | }; | 1102 | }; |
| 1106 | 1103 | ||
| 1107 | static __init int r852_module_init(void) | 1104 | module_pci_driver(r852_pci_driver); |
| 1108 | { | ||
| 1109 | return pci_register_driver(&r852_pci_driver); | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | static void __exit r852_module_exit(void) | ||
| 1113 | { | ||
| 1114 | pci_unregister_driver(&r852_pci_driver); | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | module_init(r852_module_init); | ||
| 1118 | module_exit(r852_module_exit); | ||
| 1119 | 1105 | ||
| 1120 | MODULE_LICENSE("GPL"); | 1106 | MODULE_LICENSE("GPL"); |
| 1121 | MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>"); | 1107 | MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>"); |
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index e9b2b260de3a..aa9b8a5e0b8f 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
| @@ -344,7 +344,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va | |||
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 346 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 347 | uint8_t *buf, int page) | 347 | uint8_t *buf, int oob_required, int page) |
| 348 | { | 348 | { |
| 349 | int i, eccsize = chip->ecc.size; | 349 | int i, eccsize = chip->ecc.size; |
| 350 | int eccbytes = chip->ecc.bytes; | 350 | int eccbytes = chip->ecc.bytes; |
| @@ -359,14 +359,14 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 359 | if (flctl->hwecc_cant_correct[i]) | 359 | if (flctl->hwecc_cant_correct[i]) |
| 360 | mtd->ecc_stats.failed++; | 360 | mtd->ecc_stats.failed++; |
| 361 | else | 361 | else |
| 362 | mtd->ecc_stats.corrected += 0; | 362 | mtd->ecc_stats.corrected += 0; /* FIXME */ |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | return 0; | 365 | return 0; |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 368 | static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
| 369 | const uint8_t *buf) | 369 | const uint8_t *buf, int oob_required) |
| 370 | { | 370 | { |
| 371 | int i, eccsize = chip->ecc.size; | 371 | int i, eccsize = chip->ecc.size; |
| 372 | int eccbytes = chip->ecc.bytes; | 372 | int eccbytes = chip->ecc.bytes; |
| @@ -881,8 +881,6 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
| 881 | flctl->hwecc = pdata->has_hwecc; | 881 | flctl->hwecc = pdata->has_hwecc; |
| 882 | flctl->holden = pdata->use_holden; | 882 | flctl->holden = pdata->use_holden; |
| 883 | 883 | ||
| 884 | nand->options = NAND_NO_AUTOINCR; | ||
| 885 | |||
| 886 | /* Set address of hardware control function */ | 884 | /* Set address of hardware control function */ |
| 887 | /* 20 us command delay time */ | 885 | /* 20 us command delay time */ |
| 888 | nand->chip_delay = 20; | 886 | nand->chip_delay = 20; |
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index 774c3c266713..082bcdcd6bcf 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c | |||
| @@ -94,17 +94,16 @@ static struct nand_flash_dev nand_smartmedia_flash_ids[] = { | |||
| 94 | {NULL,} | 94 | {NULL,} |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | #define XD_TYPEM (NAND_NO_AUTOINCR | NAND_BROKEN_XD) | ||
| 98 | static struct nand_flash_dev nand_xd_flash_ids[] = { | 97 | static struct nand_flash_dev nand_xd_flash_ids[] = { |
| 99 | 98 | ||
| 100 | {"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, | 99 | {"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, |
| 101 | {"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, | 100 | {"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, |
| 102 | {"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, | 101 | {"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, |
| 103 | {"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, | 102 | {"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, |
| 104 | {"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, XD_TYPEM}, | 103 | {"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, NAND_BROKEN_XD}, |
| 105 | {"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, XD_TYPEM}, | 104 | {"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, NAND_BROKEN_XD}, |
| 106 | {"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, XD_TYPEM}, | 105 | {"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, NAND_BROKEN_XD}, |
| 107 | {"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, XD_TYPEM}, | 106 | {"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, NAND_BROKEN_XD}, |
| 108 | {NULL,} | 107 | {NULL,} |
| 109 | }; | 108 | }; |
| 110 | 109 | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index b3ce12ef359e..7153e0d27101 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
| @@ -1201,7 +1201,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
| 1201 | if (mtd->ecc_stats.failed - stats.failed) | 1201 | if (mtd->ecc_stats.failed - stats.failed) |
| 1202 | return -EBADMSG; | 1202 | return -EBADMSG; |
| 1203 | 1203 | ||
| 1204 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 1204 | /* return max bitflips per ecc step; ONENANDs correct 1 bit only */ |
| 1205 | return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0; | ||
| 1205 | } | 1206 | } |
| 1206 | 1207 | ||
| 1207 | /** | 1208 | /** |
| @@ -1333,7 +1334,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
| 1333 | if (mtd->ecc_stats.failed - stats.failed) | 1334 | if (mtd->ecc_stats.failed - stats.failed) |
| 1334 | return -EBADMSG; | 1335 | return -EBADMSG; |
| 1335 | 1336 | ||
| 1336 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 1337 | /* return max bitflips per ecc step; ONENANDs correct 1 bit only */ |
| 1338 | return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0; | ||
| 1337 | } | 1339 | } |
| 1338 | 1340 | ||
| 1339 | /** | 1341 | /** |
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index b8e01c3eaa95..b26395d16347 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
| 25 | #include <linux/irqdomain.h> | 25 | #include <linux/irqdomain.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/of_device.h> | ||
| 27 | #include <linux/pinctrl/pinctrl.h> | 28 | #include <linux/pinctrl/pinctrl.h> |
| 28 | #include <linux/pinctrl/pinmux.h> | 29 | #include <linux/pinctrl/pinmux.h> |
| 29 | #include <linux/pinctrl/pinconf.h> | 30 | #include <linux/pinctrl/pinconf.h> |
| @@ -1688,18 +1689,34 @@ static struct pinctrl_desc nmk_pinctrl_desc = { | |||
| 1688 | .owner = THIS_MODULE, | 1689 | .owner = THIS_MODULE, |
| 1689 | }; | 1690 | }; |
| 1690 | 1691 | ||
| 1692 | static const struct of_device_id nmk_pinctrl_match[] = { | ||
| 1693 | { | ||
| 1694 | .compatible = "stericsson,nmk_pinctrl", | ||
| 1695 | .data = (void *)PINCTRL_NMK_DB8500, | ||
| 1696 | }, | ||
| 1697 | {}, | ||
| 1698 | }; | ||
| 1699 | |||
| 1691 | static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) | 1700 | static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) |
| 1692 | { | 1701 | { |
| 1693 | const struct platform_device_id *platid = platform_get_device_id(pdev); | 1702 | const struct platform_device_id *platid = platform_get_device_id(pdev); |
| 1703 | struct device_node *np = pdev->dev.of_node; | ||
| 1694 | struct nmk_pinctrl *npct; | 1704 | struct nmk_pinctrl *npct; |
| 1705 | unsigned int version = 0; | ||
| 1695 | int i; | 1706 | int i; |
| 1696 | 1707 | ||
| 1697 | npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); | 1708 | npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); |
| 1698 | if (!npct) | 1709 | if (!npct) |
| 1699 | return -ENOMEM; | 1710 | return -ENOMEM; |
| 1700 | 1711 | ||
| 1712 | if (platid) | ||
| 1713 | version = platid->driver_data; | ||
| 1714 | else if (np) | ||
| 1715 | version = (unsigned int) | ||
| 1716 | of_match_device(nmk_pinctrl_match, &pdev->dev)->data; | ||
| 1717 | |||
| 1701 | /* Poke in other ASIC variants here */ | 1718 | /* Poke in other ASIC variants here */ |
| 1702 | if (platid->driver_data == PINCTRL_NMK_DB8500) | 1719 | if (version == PINCTRL_NMK_DB8500) |
| 1703 | nmk_pinctrl_db8500_init(&npct->soc); | 1720 | nmk_pinctrl_db8500_init(&npct->soc); |
| 1704 | 1721 | ||
| 1705 | /* | 1722 | /* |
| @@ -1758,6 +1775,7 @@ static struct platform_driver nmk_pinctrl_driver = { | |||
| 1758 | .driver = { | 1775 | .driver = { |
| 1759 | .owner = THIS_MODULE, | 1776 | .owner = THIS_MODULE, |
| 1760 | .name = "pinctrl-nomadik", | 1777 | .name = "pinctrl-nomadik", |
| 1778 | .of_match_table = nmk_pinctrl_match, | ||
| 1761 | }, | 1779 | }, |
| 1762 | .probe = nmk_pinctrl_probe, | 1780 | .probe = nmk_pinctrl_probe, |
| 1763 | .id_table = nmk_pinctrl_id, | 1781 | .id_table = nmk_pinctrl_id, |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c1a3fd8e1243..ce875dc365e5 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
| @@ -523,6 +523,30 @@ static const struct dmi_system_id video_vendor_dmi_table[] = { | |||
| 523 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), | 523 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), |
| 524 | }, | 524 | }, |
| 525 | }, | 525 | }, |
| 526 | { | ||
| 527 | .callback = video_set_backlight_video_vendor, | ||
| 528 | .ident = "Acer Extensa 5235", | ||
| 529 | .matches = { | ||
| 530 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), | ||
| 531 | DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), | ||
| 532 | }, | ||
| 533 | }, | ||
| 534 | { | ||
| 535 | .callback = video_set_backlight_video_vendor, | ||
| 536 | .ident = "Acer TravelMate 5760", | ||
| 537 | .matches = { | ||
| 538 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), | ||
| 539 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), | ||
| 540 | }, | ||
| 541 | }, | ||
| 542 | { | ||
| 543 | .callback = video_set_backlight_video_vendor, | ||
| 544 | .ident = "Acer Aspire 5750", | ||
| 545 | .matches = { | ||
| 546 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), | ||
| 547 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), | ||
| 548 | }, | ||
| 549 | }, | ||
| 526 | {} | 550 | {} |
| 527 | }; | 551 | }; |
| 528 | 552 | ||
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 8a582bdfdc76..694a15a56230 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c | |||
| @@ -87,6 +87,9 @@ static int gmux_update_status(struct backlight_device *bd) | |||
| 87 | struct apple_gmux_data *gmux_data = bl_get_data(bd); | 87 | struct apple_gmux_data *gmux_data = bl_get_data(bd); |
| 88 | u32 brightness = bd->props.brightness; | 88 | u32 brightness = bd->props.brightness; |
| 89 | 89 | ||
| 90 | if (bd->props.state & BL_CORE_SUSPENDED) | ||
| 91 | return 0; | ||
| 92 | |||
| 90 | /* | 93 | /* |
| 91 | * Older gmux versions require writing out lower bytes first then | 94 | * Older gmux versions require writing out lower bytes first then |
| 92 | * setting the upper byte to 0 to flush the values. Newer versions | 95 | * setting the upper byte to 0 to flush the values. Newer versions |
| @@ -102,6 +105,7 @@ static int gmux_update_status(struct backlight_device *bd) | |||
| 102 | } | 105 | } |
| 103 | 106 | ||
| 104 | static const struct backlight_ops gmux_bl_ops = { | 107 | static const struct backlight_ops gmux_bl_ops = { |
| 108 | .options = BL_CORE_SUSPENDRESUME, | ||
| 105 | .get_brightness = gmux_get_brightness, | 109 | .get_brightness = gmux_get_brightness, |
| 106 | .update_status = gmux_update_status, | 110 | .update_status = gmux_update_status, |
| 107 | }; | 111 | }; |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index e6c08ee8d46c..5f78aac9b163 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
| 22 | #include <linux/dmi.h> | 22 | #include <linux/dmi.h> |
| 23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 24 | #include <linux/rfkill.h> | ||
| 25 | #include <linux/power_supply.h> | 24 | #include <linux/power_supply.h> |
| 26 | #include <linux/acpi.h> | 25 | #include <linux/acpi.h> |
| 27 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
| @@ -90,11 +89,8 @@ static struct platform_driver platform_driver = { | |||
| 90 | 89 | ||
| 91 | static struct platform_device *platform_device; | 90 | static struct platform_device *platform_device; |
| 92 | static struct backlight_device *dell_backlight_device; | 91 | static struct backlight_device *dell_backlight_device; |
| 93 | static struct rfkill *wifi_rfkill; | ||
| 94 | static struct rfkill *bluetooth_rfkill; | ||
| 95 | static struct rfkill *wwan_rfkill; | ||
| 96 | 92 | ||
| 97 | static const struct dmi_system_id __initdata dell_device_table[] = { | 93 | static const struct dmi_system_id dell_device_table[] __initconst = { |
| 98 | { | 94 | { |
| 99 | .ident = "Dell laptop", | 95 | .ident = "Dell laptop", |
| 100 | .matches = { | 96 | .matches = { |
| @@ -119,96 +115,94 @@ static const struct dmi_system_id __initdata dell_device_table[] = { | |||
| 119 | }; | 115 | }; |
| 120 | MODULE_DEVICE_TABLE(dmi, dell_device_table); | 116 | MODULE_DEVICE_TABLE(dmi, dell_device_table); |
| 121 | 117 | ||
| 122 | static struct dmi_system_id __devinitdata dell_blacklist[] = { | 118 | static struct dmi_system_id __devinitdata dell_quirks[] = { |
| 123 | /* Supported by compal-laptop */ | ||
| 124 | { | ||
| 125 | .ident = "Dell Mini 9", | ||
| 126 | .matches = { | ||
| 127 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 128 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"), | ||
| 129 | }, | ||
| 130 | }, | ||
| 131 | { | 119 | { |
| 132 | .ident = "Dell Mini 10", | 120 | .callback = dmi_matched, |
| 121 | .ident = "Dell Vostro V130", | ||
| 133 | .matches = { | 122 | .matches = { |
| 134 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 123 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 135 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), | 124 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"), |
| 136 | }, | 125 | }, |
| 126 | .driver_data = &quirk_dell_vostro_v130, | ||
| 137 | }, | 127 | }, |
| 138 | { | 128 | { |
| 139 | .ident = "Dell Mini 10v", | 129 | .callback = dmi_matched, |
| 130 | .ident = "Dell Vostro V131", | ||
| 140 | .matches = { | 131 | .matches = { |
| 141 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 132 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 142 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), | 133 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), |
| 143 | }, | 134 | }, |
| 135 | .driver_data = &quirk_dell_vostro_v130, | ||
| 144 | }, | 136 | }, |
| 145 | { | 137 | { |
| 146 | .ident = "Dell Mini 1012", | 138 | .callback = dmi_matched, |
| 139 | .ident = "Dell Vostro 3350", | ||
| 147 | .matches = { | 140 | .matches = { |
| 148 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 141 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 149 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), | 142 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), |
| 150 | }, | 143 | }, |
| 144 | .driver_data = &quirk_dell_vostro_v130, | ||
| 151 | }, | 145 | }, |
| 152 | { | 146 | { |
| 153 | .ident = "Dell Inspiron 11z", | 147 | .callback = dmi_matched, |
| 148 | .ident = "Dell Vostro 3555", | ||
| 154 | .matches = { | 149 | .matches = { |
| 155 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 150 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 156 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), | 151 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"), |
| 157 | }, | 152 | }, |
| 153 | .driver_data = &quirk_dell_vostro_v130, | ||
| 158 | }, | 154 | }, |
| 159 | { | 155 | { |
| 160 | .ident = "Dell Mini 12", | 156 | .callback = dmi_matched, |
| 157 | .ident = "Dell Inspiron N311z", | ||
| 161 | .matches = { | 158 | .matches = { |
| 162 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 159 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 163 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), | 160 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"), |
| 164 | }, | 161 | }, |
| 162 | .driver_data = &quirk_dell_vostro_v130, | ||
| 165 | }, | 163 | }, |
| 166 | {} | ||
| 167 | }; | ||
| 168 | |||
| 169 | static struct dmi_system_id __devinitdata dell_quirks[] = { | ||
| 170 | { | 164 | { |
| 171 | .callback = dmi_matched, | 165 | .callback = dmi_matched, |
| 172 | .ident = "Dell Vostro V130", | 166 | .ident = "Dell Inspiron M5110", |
| 173 | .matches = { | 167 | .matches = { |
| 174 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 168 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 175 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"), | 169 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), |
| 176 | }, | 170 | }, |
| 177 | .driver_data = &quirk_dell_vostro_v130, | 171 | .driver_data = &quirk_dell_vostro_v130, |
| 178 | }, | 172 | }, |
| 179 | { | 173 | { |
| 180 | .callback = dmi_matched, | 174 | .callback = dmi_matched, |
| 181 | .ident = "Dell Vostro V131", | 175 | .ident = "Dell Vostro 3360", |
| 182 | .matches = { | 176 | .matches = { |
| 183 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 177 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 184 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), | 178 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3360"), |
| 185 | }, | 179 | }, |
| 186 | .driver_data = &quirk_dell_vostro_v130, | 180 | .driver_data = &quirk_dell_vostro_v130, |
| 187 | }, | 181 | }, |
| 188 | { | 182 | { |
| 189 | .callback = dmi_matched, | 183 | .callback = dmi_matched, |
| 190 | .ident = "Dell Vostro 3555", | 184 | .ident = "Dell Vostro 3460", |
| 191 | .matches = { | 185 | .matches = { |
| 192 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 186 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 193 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"), | 187 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3460"), |
| 194 | }, | 188 | }, |
| 195 | .driver_data = &quirk_dell_vostro_v130, | 189 | .driver_data = &quirk_dell_vostro_v130, |
| 196 | }, | 190 | }, |
| 197 | { | 191 | { |
| 198 | .callback = dmi_matched, | 192 | .callback = dmi_matched, |
| 199 | .ident = "Dell Inspiron N311z", | 193 | .ident = "Dell Vostro 3560", |
| 200 | .matches = { | 194 | .matches = { |
| 201 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 195 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 202 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"), | 196 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3560"), |
| 203 | }, | 197 | }, |
| 204 | .driver_data = &quirk_dell_vostro_v130, | 198 | .driver_data = &quirk_dell_vostro_v130, |
| 205 | }, | 199 | }, |
| 206 | { | 200 | { |
| 207 | .callback = dmi_matched, | 201 | .callback = dmi_matched, |
| 208 | .ident = "Dell Inspiron M5110", | 202 | .ident = "Dell Vostro 3450", |
| 209 | .matches = { | 203 | .matches = { |
| 210 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 204 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 211 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), | 205 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell System Vostro 3450"), |
| 212 | }, | 206 | }, |
| 213 | .driver_data = &quirk_dell_vostro_v130, | 207 | .driver_data = &quirk_dell_vostro_v130, |
| 214 | }, | 208 | }, |
| @@ -305,94 +299,6 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
| 305 | return buffer; | 299 | return buffer; |
| 306 | } | 300 | } |
| 307 | 301 | ||
| 308 | /* Derived from information in DellWirelessCtl.cpp: | ||
| 309 | Class 17, select 11 is radio control. It returns an array of 32-bit values. | ||
| 310 | |||
| 311 | Input byte 0 = 0: Wireless information | ||
| 312 | |||
| 313 | result[0]: return code | ||
| 314 | result[1]: | ||
| 315 | Bit 0: Hardware switch supported | ||
| 316 | Bit 1: Wifi locator supported | ||
| 317 | Bit 2: Wifi is supported | ||
| 318 | Bit 3: Bluetooth is supported | ||
| 319 | Bit 4: WWAN is supported | ||
| 320 | Bit 5: Wireless keyboard supported | ||
| 321 | Bits 6-7: Reserved | ||
| 322 | Bit 8: Wifi is installed | ||
| 323 | Bit 9: Bluetooth is installed | ||
| 324 | Bit 10: WWAN is installed | ||
| 325 | Bits 11-15: Reserved | ||
| 326 | Bit 16: Hardware switch is on | ||
| 327 | Bit 17: Wifi is blocked | ||
| 328 | Bit 18: Bluetooth is blocked | ||
| 329 | Bit 19: WWAN is blocked | ||
| 330 | Bits 20-31: Reserved | ||
| 331 | result[2]: NVRAM size in bytes | ||
| 332 | result[3]: NVRAM format version number | ||
| 333 | |||
| 334 | Input byte 0 = 2: Wireless switch configuration | ||
| 335 | result[0]: return code | ||
| 336 | result[1]: | ||
| 337 | Bit 0: Wifi controlled by switch | ||
| 338 | Bit 1: Bluetooth controlled by switch | ||
| 339 | Bit 2: WWAN controlled by switch | ||
| 340 | Bits 3-6: Reserved | ||
| 341 | Bit 7: Wireless switch config locked | ||
| 342 | Bit 8: Wifi locator enabled | ||
| 343 | Bits 9-14: Reserved | ||
| 344 | Bit 15: Wifi locator setting locked | ||
| 345 | Bits 16-31: Reserved | ||
| 346 | */ | ||
| 347 | |||
| 348 | static int dell_rfkill_set(void *data, bool blocked) | ||
| 349 | { | ||
| 350 | int disable = blocked ? 1 : 0; | ||
| 351 | unsigned long radio = (unsigned long)data; | ||
| 352 | int hwswitch_bit = (unsigned long)data - 1; | ||
| 353 | int ret = 0; | ||
| 354 | |||
| 355 | get_buffer(); | ||
| 356 | dell_send_request(buffer, 17, 11); | ||
| 357 | |||
| 358 | /* If the hardware switch controls this radio, and the hardware | ||
| 359 | switch is disabled, don't allow changing the software state */ | ||
| 360 | if ((hwswitch_state & BIT(hwswitch_bit)) && | ||
| 361 | !(buffer->output[1] & BIT(16))) { | ||
| 362 | ret = -EINVAL; | ||
| 363 | goto out; | ||
| 364 | } | ||
| 365 | |||
| 366 | buffer->input[0] = (1 | (radio<<8) | (disable << 16)); | ||
| 367 | dell_send_request(buffer, 17, 11); | ||
| 368 | |||
| 369 | out: | ||
| 370 | release_buffer(); | ||
| 371 | return ret; | ||
| 372 | } | ||
| 373 | |||
| 374 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) | ||
| 375 | { | ||
| 376 | int status; | ||
| 377 | int bit = (unsigned long)data + 16; | ||
| 378 | int hwswitch_bit = (unsigned long)data - 1; | ||
| 379 | |||
| 380 | get_buffer(); | ||
| 381 | dell_send_request(buffer, 17, 11); | ||
| 382 | status = buffer->output[1]; | ||
| 383 | release_buffer(); | ||
| 384 | |||
| 385 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); | ||
| 386 | |||
| 387 | if (hwswitch_state & (BIT(hwswitch_bit))) | ||
| 388 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); | ||
| 389 | } | ||
| 390 | |||
| 391 | static const struct rfkill_ops dell_rfkill_ops = { | ||
| 392 | .set_block = dell_rfkill_set, | ||
| 393 | .query = dell_rfkill_query, | ||
| 394 | }; | ||
| 395 | |||
| 396 | static struct dentry *dell_laptop_dir; | 302 | static struct dentry *dell_laptop_dir; |
| 397 | 303 | ||
| 398 | static int dell_debugfs_show(struct seq_file *s, void *data) | 304 | static int dell_debugfs_show(struct seq_file *s, void *data) |
| @@ -462,108 +368,6 @@ static const struct file_operations dell_debugfs_fops = { | |||
| 462 | .release = single_release, | 368 | .release = single_release, |
| 463 | }; | 369 | }; |
| 464 | 370 | ||
| 465 | static void dell_update_rfkill(struct work_struct *ignored) | ||
| 466 | { | ||
| 467 | if (wifi_rfkill) | ||
| 468 | dell_rfkill_query(wifi_rfkill, (void *)1); | ||
| 469 | if (bluetooth_rfkill) | ||
| 470 | dell_rfkill_query(bluetooth_rfkill, (void *)2); | ||
| 471 | if (wwan_rfkill) | ||
| 472 | dell_rfkill_query(wwan_rfkill, (void *)3); | ||
| 473 | } | ||
| 474 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | ||
| 475 | |||
| 476 | |||
| 477 | static int __init dell_setup_rfkill(void) | ||
| 478 | { | ||
| 479 | int status; | ||
| 480 | int ret; | ||
| 481 | |||
| 482 | if (dmi_check_system(dell_blacklist)) { | ||
| 483 | pr_info("Blacklisted hardware detected - not enabling rfkill\n"); | ||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | get_buffer(); | ||
| 488 | dell_send_request(buffer, 17, 11); | ||
| 489 | status = buffer->output[1]; | ||
| 490 | buffer->input[0] = 0x2; | ||
| 491 | dell_send_request(buffer, 17, 11); | ||
| 492 | hwswitch_state = buffer->output[1]; | ||
| 493 | release_buffer(); | ||
| 494 | |||
| 495 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | ||
| 496 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, | ||
| 497 | RFKILL_TYPE_WLAN, | ||
| 498 | &dell_rfkill_ops, (void *) 1); | ||
| 499 | if (!wifi_rfkill) { | ||
| 500 | ret = -ENOMEM; | ||
| 501 | goto err_wifi; | ||
| 502 | } | ||
| 503 | ret = rfkill_register(wifi_rfkill); | ||
| 504 | if (ret) | ||
| 505 | goto err_wifi; | ||
| 506 | } | ||
| 507 | |||
| 508 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | ||
| 509 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", | ||
| 510 | &platform_device->dev, | ||
| 511 | RFKILL_TYPE_BLUETOOTH, | ||
| 512 | &dell_rfkill_ops, (void *) 2); | ||
| 513 | if (!bluetooth_rfkill) { | ||
| 514 | ret = -ENOMEM; | ||
| 515 | goto err_bluetooth; | ||
| 516 | } | ||
| 517 | ret = rfkill_register(bluetooth_rfkill); | ||
| 518 | if (ret) | ||
| 519 | goto err_bluetooth; | ||
| 520 | } | ||
| 521 | |||
| 522 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | ||
| 523 | wwan_rfkill = rfkill_alloc("dell-wwan", | ||
| 524 | &platform_device->dev, | ||
| 525 | RFKILL_TYPE_WWAN, | ||
| 526 | &dell_rfkill_ops, (void *) 3); | ||
| 527 | if (!wwan_rfkill) { | ||
| 528 | ret = -ENOMEM; | ||
| 529 | goto err_wwan; | ||
| 530 | } | ||
| 531 | ret = rfkill_register(wwan_rfkill); | ||
| 532 | if (ret) | ||
| 533 | goto err_wwan; | ||
| 534 | } | ||
| 535 | |||
| 536 | return 0; | ||
| 537 | err_wwan: | ||
| 538 | rfkill_destroy(wwan_rfkill); | ||
| 539 | if (bluetooth_rfkill) | ||
| 540 | rfkill_unregister(bluetooth_rfkill); | ||
| 541 | err_bluetooth: | ||
| 542 | rfkill_destroy(bluetooth_rfkill); | ||
| 543 | if (wifi_rfkill) | ||
| 544 | rfkill_unregister(wifi_rfkill); | ||
| 545 | err_wifi: | ||
| 546 | rfkill_destroy(wifi_rfkill); | ||
| 547 | |||
| 548 | return ret; | ||
| 549 | } | ||
| 550 | |||
| 551 | static void dell_cleanup_rfkill(void) | ||
| 552 | { | ||
| 553 | if (wifi_rfkill) { | ||
| 554 | rfkill_unregister(wifi_rfkill); | ||
| 555 | rfkill_destroy(wifi_rfkill); | ||
| 556 | } | ||
| 557 | if (bluetooth_rfkill) { | ||
| 558 | rfkill_unregister(bluetooth_rfkill); | ||
| 559 | rfkill_destroy(bluetooth_rfkill); | ||
| 560 | } | ||
| 561 | if (wwan_rfkill) { | ||
| 562 | rfkill_unregister(wwan_rfkill); | ||
| 563 | rfkill_destroy(wwan_rfkill); | ||
| 564 | } | ||
| 565 | } | ||
| 566 | |||
| 567 | static int dell_send_intensity(struct backlight_device *bd) | 371 | static int dell_send_intensity(struct backlight_device *bd) |
| 568 | { | 372 | { |
| 569 | int ret = 0; | 373 | int ret = 0; |
| @@ -655,30 +459,6 @@ static void touchpad_led_exit(void) | |||
| 655 | led_classdev_unregister(&touchpad_led); | 459 | led_classdev_unregister(&touchpad_led); |
| 656 | } | 460 | } |
| 657 | 461 | ||
| 658 | static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, | ||
| 659 | struct serio *port) | ||
| 660 | { | ||
| 661 | static bool extended; | ||
| 662 | |||
| 663 | if (str & 0x20) | ||
| 664 | return false; | ||
| 665 | |||
| 666 | if (unlikely(data == 0xe0)) { | ||
| 667 | extended = true; | ||
| 668 | return false; | ||
| 669 | } else if (unlikely(extended)) { | ||
| 670 | switch (data) { | ||
| 671 | case 0x8: | ||
| 672 | schedule_delayed_work(&dell_rfkill_work, | ||
| 673 | round_jiffies_relative(HZ)); | ||
| 674 | break; | ||
| 675 | } | ||
| 676 | extended = false; | ||
| 677 | } | ||
| 678 | |||
| 679 | return false; | ||
| 680 | } | ||
| 681 | |||
| 682 | static int __init dell_init(void) | 462 | static int __init dell_init(void) |
| 683 | { | 463 | { |
| 684 | int max_intensity = 0; | 464 | int max_intensity = 0; |
| @@ -720,26 +500,10 @@ static int __init dell_init(void) | |||
| 720 | goto fail_buffer; | 500 | goto fail_buffer; |
| 721 | buffer = page_address(bufferpage); | 501 | buffer = page_address(bufferpage); |
| 722 | 502 | ||
| 723 | ret = dell_setup_rfkill(); | ||
| 724 | |||
| 725 | if (ret) { | ||
| 726 | pr_warn("Unable to setup rfkill\n"); | ||
| 727 | goto fail_rfkill; | ||
| 728 | } | ||
| 729 | |||
| 730 | ret = i8042_install_filter(dell_laptop_i8042_filter); | ||
| 731 | if (ret) { | ||
| 732 | pr_warn("Unable to install key filter\n"); | ||
| 733 | goto fail_filter; | ||
| 734 | } | ||
| 735 | |||
| 736 | if (quirks && quirks->touchpad_led) | 503 | if (quirks && quirks->touchpad_led) |
| 737 | touchpad_led_init(&platform_device->dev); | 504 | touchpad_led_init(&platform_device->dev); |
| 738 | 505 | ||
| 739 | dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); | 506 | dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); |
| 740 | if (dell_laptop_dir != NULL) | ||
| 741 | debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, | ||
| 742 | &dell_debugfs_fops); | ||
| 743 | 507 | ||
| 744 | #ifdef CONFIG_ACPI | 508 | #ifdef CONFIG_ACPI |
| 745 | /* In the event of an ACPI backlight being available, don't | 509 | /* In the event of an ACPI backlight being available, don't |
| @@ -782,11 +546,6 @@ static int __init dell_init(void) | |||
| 782 | return 0; | 546 | return 0; |
| 783 | 547 | ||
| 784 | fail_backlight: | 548 | fail_backlight: |
| 785 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
| 786 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
| 787 | fail_filter: | ||
| 788 | dell_cleanup_rfkill(); | ||
| 789 | fail_rfkill: | ||
| 790 | free_page((unsigned long)bufferpage); | 549 | free_page((unsigned long)bufferpage); |
| 791 | fail_buffer: | 550 | fail_buffer: |
| 792 | platform_device_del(platform_device); | 551 | platform_device_del(platform_device); |
| @@ -804,10 +563,7 @@ static void __exit dell_exit(void) | |||
| 804 | debugfs_remove_recursive(dell_laptop_dir); | 563 | debugfs_remove_recursive(dell_laptop_dir); |
| 805 | if (quirks && quirks->touchpad_led) | 564 | if (quirks && quirks->touchpad_led) |
| 806 | touchpad_led_exit(); | 565 | touchpad_led_exit(); |
| 807 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
| 808 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
| 809 | backlight_device_unregister(dell_backlight_device); | 566 | backlight_device_unregister(dell_backlight_device); |
| 810 | dell_cleanup_rfkill(); | ||
| 811 | if (platform_device) { | 567 | if (platform_device) { |
| 812 | platform_device_unregister(platform_device); | 568 | platform_device_unregister(platform_device); |
| 813 | platform_driver_unregister(&platform_driver); | 569 | platform_driver_unregister(&platform_driver); |
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c index 580d80a73c3a..da267eae8ba8 100644 --- a/drivers/platform/x86/fujitsu-tablet.c +++ b/drivers/platform/x86/fujitsu-tablet.c | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. | 16 | * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 20 | |||
| 19 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 20 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 21 | #include <linux/init.h> | 23 | #include <linux/init.h> |
| @@ -34,7 +36,8 @@ | |||
| 34 | #define ACPI_FUJITSU_CLASS "fujitsu" | 36 | #define ACPI_FUJITSU_CLASS "fujitsu" |
| 35 | 37 | ||
| 36 | #define INVERT_TABLET_MODE_BIT 0x01 | 38 | #define INVERT_TABLET_MODE_BIT 0x01 |
| 37 | #define FORCE_TABLET_MODE_IF_UNDOCK 0x02 | 39 | #define INVERT_DOCK_STATE_BIT 0x02 |
| 40 | #define FORCE_TABLET_MODE_IF_UNDOCK 0x04 | ||
| 38 | 41 | ||
| 39 | #define KEYMAP_LEN 16 | 42 | #define KEYMAP_LEN 16 |
| 40 | 43 | ||
| @@ -161,6 +164,8 @@ static void fujitsu_send_state(void) | |||
| 161 | state = fujitsu_read_register(0xdd); | 164 | state = fujitsu_read_register(0xdd); |
| 162 | 165 | ||
| 163 | dock = state & 0x02; | 166 | dock = state & 0x02; |
| 167 | if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT) | ||
| 168 | dock = !dock; | ||
| 164 | 169 | ||
| 165 | if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { | 170 | if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { |
| 166 | tablet_mode = 1; | 171 | tablet_mode = 1; |
| @@ -221,9 +226,6 @@ static int __devinit input_fujitsu_setup(struct device *parent, | |||
| 221 | input_set_capability(idev, EV_SW, SW_DOCK); | 226 | input_set_capability(idev, EV_SW, SW_DOCK); |
| 222 | input_set_capability(idev, EV_SW, SW_TABLET_MODE); | 227 | input_set_capability(idev, EV_SW, SW_TABLET_MODE); |
| 223 | 228 | ||
| 224 | input_set_capability(idev, EV_SW, SW_DOCK); | ||
| 225 | input_set_capability(idev, EV_SW, SW_TABLET_MODE); | ||
| 226 | |||
| 227 | error = input_register_device(idev); | 229 | error = input_register_device(idev); |
| 228 | if (error) { | 230 | if (error) { |
| 229 | input_free_device(idev); | 231 | input_free_device(idev); |
| @@ -275,25 +277,31 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id) | |||
| 275 | return IRQ_HANDLED; | 277 | return IRQ_HANDLED; |
| 276 | } | 278 | } |
| 277 | 279 | ||
| 278 | static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) | 280 | static void __devinit fujitsu_dmi_common(const struct dmi_system_id *dmi) |
| 279 | { | 281 | { |
| 280 | printk(KERN_INFO MODULENAME ": %s\n", dmi->ident); | 282 | pr_info("%s\n", dmi->ident); |
| 281 | memcpy(fujitsu.config.keymap, dmi->driver_data, | 283 | memcpy(fujitsu.config.keymap, dmi->driver_data, |
| 282 | sizeof(fujitsu.config.keymap)); | 284 | sizeof(fujitsu.config.keymap)); |
| 285 | } | ||
| 286 | |||
| 287 | static int __devinit fujitsu_dmi_lifebook(const struct dmi_system_id *dmi) | ||
| 288 | { | ||
| 289 | fujitsu_dmi_common(dmi); | ||
| 290 | fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; | ||
| 283 | return 1; | 291 | return 1; |
| 284 | } | 292 | } |
| 285 | 293 | ||
| 286 | static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) | 294 | static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) |
| 287 | { | 295 | { |
| 288 | fujitsu_dmi_default(dmi); | 296 | fujitsu_dmi_common(dmi); |
| 289 | fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; | 297 | fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; |
| 290 | fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; | 298 | fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT; |
| 291 | return 1; | 299 | return 1; |
| 292 | } | 300 | } |
| 293 | 301 | ||
| 294 | static struct dmi_system_id dmi_ids[] __initconst = { | 302 | static struct dmi_system_id dmi_ids[] __initconst = { |
| 295 | { | 303 | { |
| 296 | .callback = fujitsu_dmi_default, | 304 | .callback = fujitsu_dmi_lifebook, |
| 297 | .ident = "Fujitsu Siemens P/T Series", | 305 | .ident = "Fujitsu Siemens P/T Series", |
| 298 | .matches = { | 306 | .matches = { |
| 299 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 307 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
| @@ -302,7 +310,7 @@ static struct dmi_system_id dmi_ids[] __initconst = { | |||
| 302 | .driver_data = keymap_Lifebook_Tseries | 310 | .driver_data = keymap_Lifebook_Tseries |
| 303 | }, | 311 | }, |
| 304 | { | 312 | { |
| 305 | .callback = fujitsu_dmi_default, | 313 | .callback = fujitsu_dmi_lifebook, |
| 306 | .ident = "Fujitsu Lifebook T Series", | 314 | .ident = "Fujitsu Lifebook T Series", |
| 307 | .matches = { | 315 | .matches = { |
| 308 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 316 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
| @@ -320,7 +328,7 @@ static struct dmi_system_id dmi_ids[] __initconst = { | |||
| 320 | .driver_data = keymap_Stylistic_Tseries | 328 | .driver_data = keymap_Stylistic_Tseries |
| 321 | }, | 329 | }, |
| 322 | { | 330 | { |
| 323 | .callback = fujitsu_dmi_default, | 331 | .callback = fujitsu_dmi_lifebook, |
| 324 | .ident = "Fujitsu LifeBook U810", | 332 | .ident = "Fujitsu LifeBook U810", |
| 325 | .matches = { | 333 | .matches = { |
| 326 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 334 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
| @@ -347,7 +355,7 @@ static struct dmi_system_id dmi_ids[] __initconst = { | |||
| 347 | .driver_data = keymap_Stylistic_ST5xxx | 355 | .driver_data = keymap_Stylistic_ST5xxx |
| 348 | }, | 356 | }, |
| 349 | { | 357 | { |
| 350 | .callback = fujitsu_dmi_default, | 358 | .callback = fujitsu_dmi_lifebook, |
| 351 | .ident = "Unknown (using defaults)", | 359 | .ident = "Unknown (using defaults)", |
| 352 | .matches = { | 360 | .matches = { |
| 353 | DMI_MATCH(DMI_SYS_VENDOR, ""), | 361 | DMI_MATCH(DMI_SYS_VENDOR, ""), |
| @@ -473,6 +481,6 @@ module_exit(fujitsu_module_exit); | |||
| 473 | MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); | 481 | MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); |
| 474 | MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); | 482 | MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); |
| 475 | MODULE_LICENSE("GPL"); | 483 | MODULE_LICENSE("GPL"); |
| 476 | MODULE_VERSION("2.4"); | 484 | MODULE_VERSION("2.5"); |
| 477 | 485 | ||
| 478 | MODULE_DEVICE_TABLE(acpi, fujitsu_ids); | 486 | MODULE_DEVICE_TABLE(acpi, fujitsu_ids); |
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c index 7387f97a2941..24a3ae065f1b 100644 --- a/drivers/platform/x86/hdaps.c +++ b/drivers/platform/x86/hdaps.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * hdaps.c - driver for IBM's Hard Drive Active Protection System | 2 | * hdaps.c - driver for IBM's Hard Drive Active Protection System |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2005 Robert Love <rml@novell.com> | 4 | * Copyright (C) 2005 Robert Love <rml@novell.com> |
| 5 | * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com> | 5 | * Copyright (C) 2005 Jesper Juhl <jj@chaosbits.net> |
| 6 | * | 6 | * |
| 7 | * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads | 7 | * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads |
| 8 | * starting with the R40, T41, and X40. It provides a basic two-axis | 8 | * starting with the R40, T41, and X40. It provides a basic two-axis |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index e2faa3cbb792..387183a2d6dd 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
| @@ -634,6 +634,8 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) | |||
| 634 | RFKILL_TYPE_WLAN, | 634 | RFKILL_TYPE_WLAN, |
| 635 | &hp_wmi_rfkill_ops, | 635 | &hp_wmi_rfkill_ops, |
| 636 | (void *) HPWMI_WIFI); | 636 | (void *) HPWMI_WIFI); |
| 637 | if (!wifi_rfkill) | ||
| 638 | return -ENOMEM; | ||
| 637 | rfkill_init_sw_state(wifi_rfkill, | 639 | rfkill_init_sw_state(wifi_rfkill, |
| 638 | hp_wmi_get_sw_state(HPWMI_WIFI)); | 640 | hp_wmi_get_sw_state(HPWMI_WIFI)); |
| 639 | rfkill_set_hw_state(wifi_rfkill, | 641 | rfkill_set_hw_state(wifi_rfkill, |
| @@ -648,6 +650,10 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) | |||
| 648 | RFKILL_TYPE_BLUETOOTH, | 650 | RFKILL_TYPE_BLUETOOTH, |
| 649 | &hp_wmi_rfkill_ops, | 651 | &hp_wmi_rfkill_ops, |
| 650 | (void *) HPWMI_BLUETOOTH); | 652 | (void *) HPWMI_BLUETOOTH); |
| 653 | if (!bluetooth_rfkill) { | ||
| 654 | err = -ENOMEM; | ||
| 655 | goto register_wifi_error; | ||
| 656 | } | ||
| 651 | rfkill_init_sw_state(bluetooth_rfkill, | 657 | rfkill_init_sw_state(bluetooth_rfkill, |
| 652 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); | 658 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); |
| 653 | rfkill_set_hw_state(bluetooth_rfkill, | 659 | rfkill_set_hw_state(bluetooth_rfkill, |
| @@ -662,6 +668,10 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) | |||
| 662 | RFKILL_TYPE_WWAN, | 668 | RFKILL_TYPE_WWAN, |
| 663 | &hp_wmi_rfkill_ops, | 669 | &hp_wmi_rfkill_ops, |
| 664 | (void *) HPWMI_WWAN); | 670 | (void *) HPWMI_WWAN); |
| 671 | if (!wwan_rfkill) { | ||
| 672 | err = -ENOMEM; | ||
| 673 | goto register_bluetooth_error; | ||
| 674 | } | ||
| 665 | rfkill_init_sw_state(wwan_rfkill, | 675 | rfkill_init_sw_state(wwan_rfkill, |
| 666 | hp_wmi_get_sw_state(HPWMI_WWAN)); | 676 | hp_wmi_get_sw_state(HPWMI_WWAN)); |
| 667 | rfkill_set_hw_state(wwan_rfkill, | 677 | rfkill_set_hw_state(wwan_rfkill, |
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index ac902f7a9baa..4f20f8dd3d7c 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
| @@ -194,7 +194,6 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) | |||
| 194 | /* | 194 | /* |
| 195 | * debugfs | 195 | * debugfs |
| 196 | */ | 196 | */ |
| 197 | #define DEBUGFS_EVENT_LEN (4096) | ||
| 198 | static int debugfs_status_show(struct seq_file *s, void *data) | 197 | static int debugfs_status_show(struct seq_file *s, void *data) |
| 199 | { | 198 | { |
| 200 | unsigned long value; | 199 | unsigned long value; |
| @@ -315,7 +314,7 @@ static int __devinit ideapad_debugfs_init(struct ideapad_private *priv) | |||
| 315 | node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL, | 314 | node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL, |
| 316 | &debugfs_status_fops); | 315 | &debugfs_status_fops); |
| 317 | if (!node) { | 316 | if (!node) { |
| 318 | pr_err("failed to create event in debugfs"); | 317 | pr_err("failed to create status in debugfs"); |
| 319 | goto errout; | 318 | goto errout; |
| 320 | } | 319 | } |
| 321 | 320 | ||
| @@ -785,6 +784,10 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) | |||
| 785 | case 9: | 784 | case 9: |
| 786 | ideapad_sync_rfk_state(priv); | 785 | ideapad_sync_rfk_state(priv); |
| 787 | break; | 786 | break; |
| 787 | case 13: | ||
| 788 | case 6: | ||
| 789 | ideapad_input_report(priv, vpc_bit); | ||
| 790 | break; | ||
| 788 | case 4: | 791 | case 4: |
| 789 | ideapad_backlight_notify_brightness(priv); | 792 | ideapad_backlight_notify_brightness(priv); |
| 790 | break; | 793 | break; |
| @@ -795,7 +798,7 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) | |||
| 795 | ideapad_backlight_notify_power(priv); | 798 | ideapad_backlight_notify_power(priv); |
| 796 | break; | 799 | break; |
| 797 | default: | 800 | default: |
| 798 | ideapad_input_report(priv, vpc_bit); | 801 | pr_info("Unknown event: %lu\n", vpc_bit); |
| 799 | } | 802 | } |
| 800 | } | 803 | } |
| 801 | } | 804 | } |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 8a51795aa02a..210d4ae547c2 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
| @@ -141,6 +141,27 @@ MODULE_PARM_DESC(kbd_backlight_timeout, | |||
| 141 | "(default: 0)"); | 141 | "(default: 0)"); |
| 142 | 142 | ||
| 143 | static void sony_nc_kbd_backlight_resume(void); | 143 | static void sony_nc_kbd_backlight_resume(void); |
| 144 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd, | ||
| 145 | unsigned int handle); | ||
| 146 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd); | ||
| 147 | |||
| 148 | static int sony_nc_battery_care_setup(struct platform_device *pd, | ||
| 149 | unsigned int handle); | ||
| 150 | static void sony_nc_battery_care_cleanup(struct platform_device *pd); | ||
| 151 | |||
| 152 | static int sony_nc_thermal_setup(struct platform_device *pd); | ||
| 153 | static void sony_nc_thermal_cleanup(struct platform_device *pd); | ||
| 154 | static void sony_nc_thermal_resume(void); | ||
| 155 | |||
| 156 | static int sony_nc_lid_resume_setup(struct platform_device *pd); | ||
| 157 | static void sony_nc_lid_resume_cleanup(struct platform_device *pd); | ||
| 158 | |||
| 159 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd); | ||
| 160 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); | ||
| 161 | |||
| 162 | static int sony_nc_touchpad_setup(struct platform_device *pd, | ||
| 163 | unsigned int handle); | ||
| 164 | static void sony_nc_touchpad_cleanup(struct platform_device *pd); | ||
| 144 | 165 | ||
| 145 | enum sony_nc_rfkill { | 166 | enum sony_nc_rfkill { |
| 146 | SONY_WIFI, | 167 | SONY_WIFI, |
| @@ -153,6 +174,9 @@ enum sony_nc_rfkill { | |||
| 153 | static int sony_rfkill_handle; | 174 | static int sony_rfkill_handle; |
| 154 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; | 175 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
| 155 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; | 176 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
| 177 | static int sony_nc_rfkill_setup(struct acpi_device *device, | ||
| 178 | unsigned int handle); | ||
| 179 | static void sony_nc_rfkill_cleanup(void); | ||
| 156 | static void sony_nc_rfkill_update(void); | 180 | static void sony_nc_rfkill_update(void); |
| 157 | 181 | ||
| 158 | /*********** Input Devices ***********/ | 182 | /*********** Input Devices ***********/ |
| @@ -691,59 +715,97 @@ static struct acpi_device *sony_nc_acpi_device = NULL; | |||
| 691 | 715 | ||
| 692 | /* | 716 | /* |
| 693 | * acpi_evaluate_object wrappers | 717 | * acpi_evaluate_object wrappers |
| 718 | * all useful calls into SNC methods take one or zero parameters and return | ||
| 719 | * integers or arrays. | ||
| 694 | */ | 720 | */ |
| 695 | static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) | 721 | static union acpi_object *__call_snc_method(acpi_handle handle, char *method, |
| 722 | u64 *value) | ||
| 696 | { | 723 | { |
| 697 | struct acpi_buffer output; | 724 | union acpi_object *result = NULL; |
| 698 | union acpi_object out_obj; | 725 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 699 | acpi_status status; | 726 | acpi_status status; |
| 700 | 727 | ||
| 701 | output.length = sizeof(out_obj); | 728 | if (value) { |
| 702 | output.pointer = &out_obj; | 729 | struct acpi_object_list params; |
| 730 | union acpi_object in; | ||
| 731 | in.type = ACPI_TYPE_INTEGER; | ||
| 732 | in.integer.value = *value; | ||
| 733 | params.count = 1; | ||
| 734 | params.pointer = ∈ | ||
| 735 | status = acpi_evaluate_object(handle, method, ¶ms, &output); | ||
| 736 | dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method, | ||
| 737 | (unsigned int)(*value >> 32), | ||
| 738 | (unsigned int)*value & 0xffffffff); | ||
| 739 | } else { | ||
| 740 | status = acpi_evaluate_object(handle, method, NULL, &output); | ||
| 741 | dprintk("__call_snc_method: [%s]\n", method); | ||
| 742 | } | ||
| 703 | 743 | ||
| 704 | status = acpi_evaluate_object(handle, name, NULL, &output); | 744 | if (ACPI_FAILURE(status)) { |
| 705 | if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { | 745 | pr_err("Failed to evaluate [%s]\n", method); |
| 706 | *result = out_obj.integer.value; | 746 | return NULL; |
| 707 | return 0; | ||
| 708 | } | 747 | } |
| 709 | 748 | ||
| 710 | pr_warn("acpi_callreadfunc failed\n"); | 749 | result = (union acpi_object *) output.pointer; |
| 750 | if (!result) | ||
| 751 | dprintk("No return object [%s]\n", method); | ||
| 711 | 752 | ||
| 712 | return -1; | 753 | return result; |
| 713 | } | 754 | } |
| 714 | 755 | ||
| 715 | static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | 756 | static int sony_nc_int_call(acpi_handle handle, char *name, int *value, |
| 716 | int *result) | 757 | int *result) |
| 717 | { | 758 | { |
| 718 | struct acpi_object_list params; | 759 | union acpi_object *object = NULL; |
| 719 | union acpi_object in_obj; | 760 | if (value) { |
| 720 | struct acpi_buffer output; | 761 | u64 v = *value; |
| 721 | union acpi_object out_obj; | 762 | object = __call_snc_method(handle, name, &v); |
| 722 | acpi_status status; | 763 | } else |
| 723 | 764 | object = __call_snc_method(handle, name, NULL); | |
| 724 | params.count = 1; | ||
| 725 | params.pointer = &in_obj; | ||
| 726 | in_obj.type = ACPI_TYPE_INTEGER; | ||
| 727 | in_obj.integer.value = value; | ||
| 728 | 765 | ||
| 729 | output.length = sizeof(out_obj); | 766 | if (!object) |
| 730 | output.pointer = &out_obj; | 767 | return -EINVAL; |
| 731 | 768 | ||
| 732 | status = acpi_evaluate_object(handle, name, ¶ms, &output); | 769 | if (object->type != ACPI_TYPE_INTEGER) { |
| 733 | if (status == AE_OK) { | 770 | pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", |
| 734 | if (result != NULL) { | 771 | ACPI_TYPE_INTEGER, object->type); |
| 735 | if (out_obj.type != ACPI_TYPE_INTEGER) { | 772 | kfree(object); |
| 736 | pr_warn("acpi_evaluate_object bad return type\n"); | 773 | return -EINVAL; |
| 737 | return -1; | ||
| 738 | } | ||
| 739 | *result = out_obj.integer.value; | ||
| 740 | } | ||
| 741 | return 0; | ||
| 742 | } | 774 | } |
| 743 | 775 | ||
| 744 | pr_warn("acpi_evaluate_object failed\n"); | 776 | if (result) |
| 777 | *result = object->integer.value; | ||
| 778 | |||
| 779 | kfree(object); | ||
| 780 | return 0; | ||
| 781 | } | ||
| 782 | |||
| 783 | #define MIN(a, b) (a > b ? b : a) | ||
| 784 | static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, | ||
| 785 | void *buffer, size_t buflen) | ||
| 786 | { | ||
| 787 | size_t len = len; | ||
| 788 | union acpi_object *object = __call_snc_method(handle, name, value); | ||
| 789 | |||
| 790 | if (!object) | ||
| 791 | return -EINVAL; | ||
| 792 | |||
| 793 | if (object->type == ACPI_TYPE_BUFFER) | ||
| 794 | len = MIN(buflen, object->buffer.length); | ||
| 795 | |||
| 796 | else if (object->type == ACPI_TYPE_INTEGER) | ||
| 797 | len = MIN(buflen, sizeof(object->integer.value)); | ||
| 798 | |||
| 799 | else { | ||
| 800 | pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", | ||
| 801 | ACPI_TYPE_BUFFER, object->type); | ||
| 802 | kfree(object); | ||
| 803 | return -EINVAL; | ||
| 804 | } | ||
| 745 | 805 | ||
| 746 | return -1; | 806 | memcpy(buffer, object->buffer.pointer, len); |
| 807 | kfree(object); | ||
| 808 | return 0; | ||
| 747 | } | 809 | } |
| 748 | 810 | ||
| 749 | struct sony_nc_handles { | 811 | struct sony_nc_handles { |
| @@ -770,16 +832,17 @@ static ssize_t sony_nc_handles_show(struct device *dev, | |||
| 770 | 832 | ||
| 771 | static int sony_nc_handles_setup(struct platform_device *pd) | 833 | static int sony_nc_handles_setup(struct platform_device *pd) |
| 772 | { | 834 | { |
| 773 | int i; | 835 | int i, r, result, arg; |
| 774 | int result; | ||
| 775 | 836 | ||
| 776 | handles = kzalloc(sizeof(*handles), GFP_KERNEL); | 837 | handles = kzalloc(sizeof(*handles), GFP_KERNEL); |
| 777 | if (!handles) | 838 | if (!handles) |
| 778 | return -ENOMEM; | 839 | return -ENOMEM; |
| 779 | 840 | ||
| 780 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | 841 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { |
| 781 | if (!acpi_callsetfunc(sony_nc_acpi_handle, | 842 | arg = i + 0x20; |
| 782 | "SN00", i + 0x20, &result)) { | 843 | r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, |
| 844 | &result); | ||
| 845 | if (!r) { | ||
| 783 | dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", | 846 | dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", |
| 784 | result, i); | 847 | result, i); |
| 785 | handles->cap[i] = result; | 848 | handles->cap[i] = result; |
| @@ -819,8 +882,8 @@ static int sony_find_snc_handle(int handle) | |||
| 819 | int i; | 882 | int i; |
| 820 | 883 | ||
| 821 | /* not initialized yet, return early */ | 884 | /* not initialized yet, return early */ |
| 822 | if (!handles) | 885 | if (!handles || !handle) |
| 823 | return -1; | 886 | return -EINVAL; |
| 824 | 887 | ||
| 825 | for (i = 0; i < 0x10; i++) { | 888 | for (i = 0; i < 0x10; i++) { |
| 826 | if (handles->cap[i] == handle) { | 889 | if (handles->cap[i] == handle) { |
| @@ -830,21 +893,20 @@ static int sony_find_snc_handle(int handle) | |||
| 830 | } | 893 | } |
| 831 | } | 894 | } |
| 832 | dprintk("handle 0x%.4x not found\n", handle); | 895 | dprintk("handle 0x%.4x not found\n", handle); |
| 833 | return -1; | 896 | return -EINVAL; |
| 834 | } | 897 | } |
| 835 | 898 | ||
| 836 | static int sony_call_snc_handle(int handle, int argument, int *result) | 899 | static int sony_call_snc_handle(int handle, int argument, int *result) |
| 837 | { | 900 | { |
| 838 | int ret = 0; | 901 | int arg, ret = 0; |
| 839 | int offset = sony_find_snc_handle(handle); | 902 | int offset = sony_find_snc_handle(handle); |
| 840 | 903 | ||
| 841 | if (offset < 0) | 904 | if (offset < 0) |
| 842 | return -1; | 905 | return offset; |
| 843 | 906 | ||
| 844 | ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, | 907 | arg = offset | argument; |
| 845 | result); | 908 | ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result); |
| 846 | dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, | 909 | dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result); |
| 847 | *result); | ||
| 848 | return ret; | 910 | return ret; |
| 849 | } | 911 | } |
| 850 | 912 | ||
| @@ -889,14 +951,16 @@ static int boolean_validate(const int direction, const int value) | |||
| 889 | static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, | 951 | static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, |
| 890 | char *buffer) | 952 | char *buffer) |
| 891 | { | 953 | { |
| 892 | int value; | 954 | int value, ret = 0; |
| 893 | struct sony_nc_value *item = | 955 | struct sony_nc_value *item = |
| 894 | container_of(attr, struct sony_nc_value, devattr); | 956 | container_of(attr, struct sony_nc_value, devattr); |
| 895 | 957 | ||
| 896 | if (!*item->acpiget) | 958 | if (!*item->acpiget) |
| 897 | return -EIO; | 959 | return -EIO; |
| 898 | 960 | ||
| 899 | if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) | 961 | ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL, |
| 962 | &value); | ||
| 963 | if (ret < 0) | ||
| 900 | return -EIO; | 964 | return -EIO; |
| 901 | 965 | ||
| 902 | if (item->validate) | 966 | if (item->validate) |
| @@ -909,7 +973,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, | |||
| 909 | struct device_attribute *attr, | 973 | struct device_attribute *attr, |
| 910 | const char *buffer, size_t count) | 974 | const char *buffer, size_t count) |
| 911 | { | 975 | { |
| 912 | int value; | 976 | unsigned long value = 0; |
| 977 | int ret = 0; | ||
| 913 | struct sony_nc_value *item = | 978 | struct sony_nc_value *item = |
| 914 | container_of(attr, struct sony_nc_value, devattr); | 979 | container_of(attr, struct sony_nc_value, devattr); |
| 915 | 980 | ||
| @@ -919,7 +984,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, | |||
| 919 | if (count > 31) | 984 | if (count > 31) |
| 920 | return -EINVAL; | 985 | return -EINVAL; |
| 921 | 986 | ||
| 922 | value = simple_strtoul(buffer, NULL, 10); | 987 | if (kstrtoul(buffer, 10, &value)) |
| 988 | return -EINVAL; | ||
| 923 | 989 | ||
| 924 | if (item->validate) | 990 | if (item->validate) |
| 925 | value = item->validate(SNC_VALIDATE_IN, value); | 991 | value = item->validate(SNC_VALIDATE_IN, value); |
| @@ -927,8 +993,11 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, | |||
| 927 | if (value < 0) | 993 | if (value < 0) |
| 928 | return value; | 994 | return value; |
| 929 | 995 | ||
| 930 | if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) | 996 | ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, |
| 997 | (int *)&value, NULL); | ||
| 998 | if (ret < 0) | ||
| 931 | return -EIO; | 999 | return -EIO; |
| 1000 | |||
| 932 | item->value = value; | 1001 | item->value = value; |
| 933 | item->valid = 1; | 1002 | item->valid = 1; |
| 934 | return count; | 1003 | return count; |
| @@ -948,15 +1017,15 @@ struct sony_backlight_props sony_bl_props; | |||
| 948 | 1017 | ||
| 949 | static int sony_backlight_update_status(struct backlight_device *bd) | 1018 | static int sony_backlight_update_status(struct backlight_device *bd) |
| 950 | { | 1019 | { |
| 951 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", | 1020 | int arg = bd->props.brightness + 1; |
| 952 | bd->props.brightness + 1, NULL); | 1021 | return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL); |
| 953 | } | 1022 | } |
| 954 | 1023 | ||
| 955 | static int sony_backlight_get_brightness(struct backlight_device *bd) | 1024 | static int sony_backlight_get_brightness(struct backlight_device *bd) |
| 956 | { | 1025 | { |
| 957 | int value; | 1026 | int value; |
| 958 | 1027 | ||
| 959 | if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) | 1028 | if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value)) |
| 960 | return 0; | 1029 | return 0; |
| 961 | /* brightness levels are 1-based, while backlight ones are 0-based */ | 1030 | /* brightness levels are 1-based, while backlight ones are 0-based */ |
| 962 | return value - 1; | 1031 | return value - 1; |
| @@ -1024,10 +1093,14 @@ static struct sony_nc_event sony_100_events[] = { | |||
| 1024 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, | 1093 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, |
| 1025 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, | 1094 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, |
| 1026 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, | 1095 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, |
| 1096 | { 0x88, SONYPI_EVENT_FNKEY_F8 }, | ||
| 1097 | { 0x08, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 1027 | { 0x89, SONYPI_EVENT_FNKEY_F9 }, | 1098 | { 0x89, SONYPI_EVENT_FNKEY_F9 }, |
| 1028 | { 0x09, SONYPI_EVENT_FNKEY_RELEASED }, | 1099 | { 0x09, SONYPI_EVENT_FNKEY_RELEASED }, |
| 1029 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, | 1100 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, |
| 1030 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, | 1101 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, |
| 1102 | { 0x8B, SONYPI_EVENT_FNKEY_F11 }, | ||
| 1103 | { 0x0B, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 1031 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, | 1104 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, |
| 1032 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | 1105 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, |
| 1033 | { 0x9d, SONYPI_EVENT_ZOOM_PRESSED }, | 1106 | { 0x9d, SONYPI_EVENT_ZOOM_PRESSED }, |
| @@ -1063,63 +1136,116 @@ static struct sony_nc_event sony_127_events[] = { | |||
| 1063 | { 0, 0 }, | 1136 | { 0, 0 }, |
| 1064 | }; | 1137 | }; |
| 1065 | 1138 | ||
| 1139 | static int sony_nc_hotkeys_decode(u32 event, unsigned int handle) | ||
| 1140 | { | ||
| 1141 | int ret = -EINVAL; | ||
| 1142 | unsigned int result = 0; | ||
| 1143 | struct sony_nc_event *key_event; | ||
| 1144 | |||
| 1145 | if (sony_call_snc_handle(handle, 0x200, &result)) { | ||
| 1146 | dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle, | ||
| 1147 | event); | ||
| 1148 | return -EINVAL; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | result &= 0xFF; | ||
| 1152 | |||
| 1153 | if (handle == 0x0100) | ||
| 1154 | key_event = sony_100_events; | ||
| 1155 | else | ||
| 1156 | key_event = sony_127_events; | ||
| 1157 | |||
| 1158 | for (; key_event->data; key_event++) { | ||
| 1159 | if (key_event->data == result) { | ||
| 1160 | ret = key_event->event; | ||
| 1161 | break; | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | if (!key_event->data) | ||
| 1166 | pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n", | ||
| 1167 | event, result, handle); | ||
| 1168 | |||
| 1169 | return ret; | ||
| 1170 | } | ||
| 1171 | |||
| 1066 | /* | 1172 | /* |
| 1067 | * ACPI callbacks | 1173 | * ACPI callbacks |
| 1068 | */ | 1174 | */ |
| 1069 | static void sony_nc_notify(struct acpi_device *device, u32 event) | 1175 | static void sony_nc_notify(struct acpi_device *device, u32 event) |
| 1070 | { | 1176 | { |
| 1071 | u32 ev = event; | 1177 | u32 real_ev = event; |
| 1178 | u8 ev_type = 0; | ||
| 1179 | dprintk("sony_nc_notify, event: 0x%.2x\n", event); | ||
| 1180 | |||
| 1181 | if (event >= 0x90) { | ||
| 1182 | unsigned int result = 0; | ||
| 1183 | unsigned int arg = 0; | ||
| 1184 | unsigned int handle = 0; | ||
| 1185 | unsigned int offset = event - 0x90; | ||
| 1186 | |||
| 1187 | if (offset >= ARRAY_SIZE(handles->cap)) { | ||
| 1188 | pr_err("Event 0x%x outside of capabilities list\n", | ||
| 1189 | event); | ||
| 1190 | return; | ||
| 1191 | } | ||
| 1192 | handle = handles->cap[offset]; | ||
| 1193 | |||
| 1194 | /* list of handles known for generating events */ | ||
| 1195 | switch (handle) { | ||
| 1196 | /* hotkey event */ | ||
| 1197 | case 0x0100: | ||
| 1198 | case 0x0127: | ||
| 1199 | ev_type = 1; | ||
| 1200 | real_ev = sony_nc_hotkeys_decode(event, handle); | ||
| 1201 | |||
| 1202 | if (real_ev > 0) | ||
| 1203 | sony_laptop_report_input_event(real_ev); | ||
| 1204 | else | ||
| 1205 | /* restore the original event for reporting */ | ||
| 1206 | real_ev = event; | ||
| 1072 | 1207 | ||
| 1073 | if (ev >= 0x90) { | 1208 | break; |
| 1074 | /* New-style event */ | ||
| 1075 | int result; | ||
| 1076 | int key_handle = 0; | ||
| 1077 | ev -= 0x90; | ||
| 1078 | |||
| 1079 | if (sony_find_snc_handle(0x100) == ev) | ||
| 1080 | key_handle = 0x100; | ||
| 1081 | if (sony_find_snc_handle(0x127) == ev) | ||
| 1082 | key_handle = 0x127; | ||
| 1083 | |||
| 1084 | if (key_handle) { | ||
| 1085 | struct sony_nc_event *key_event; | ||
| 1086 | |||
| 1087 | if (sony_call_snc_handle(key_handle, 0x200, &result)) { | ||
| 1088 | dprintk("sony_nc_notify, unable to decode" | ||
| 1089 | " event 0x%.2x 0x%.2x\n", key_handle, | ||
| 1090 | ev); | ||
| 1091 | /* restore the original event */ | ||
| 1092 | ev = event; | ||
| 1093 | } else { | ||
| 1094 | ev = result & 0xFF; | ||
| 1095 | |||
| 1096 | if (key_handle == 0x100) | ||
| 1097 | key_event = sony_100_events; | ||
| 1098 | else | ||
| 1099 | key_event = sony_127_events; | ||
| 1100 | |||
| 1101 | for (; key_event->data; key_event++) { | ||
| 1102 | if (key_event->data == ev) { | ||
| 1103 | ev = key_event->event; | ||
| 1104 | break; | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | 1209 | ||
| 1108 | if (!key_event->data) | 1210 | /* wlan switch */ |
| 1109 | pr_info("Unknown event: 0x%x 0x%x\n", | 1211 | case 0x0124: |
| 1110 | key_handle, ev); | 1212 | case 0x0135: |
| 1111 | else | 1213 | /* events on this handle are reported when the |
| 1112 | sony_laptop_report_input_event(ev); | 1214 | * switch changes position or for battery |
| 1113 | } | 1215 | * events. We'll notify both of them but only |
| 1114 | } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) { | 1216 | * update the rfkill device status when the |
| 1115 | sony_nc_rfkill_update(); | 1217 | * switch is moved. |
| 1116 | return; | 1218 | */ |
| 1219 | ev_type = 2; | ||
| 1220 | sony_call_snc_handle(handle, 0x0100, &result); | ||
| 1221 | real_ev = result & 0x03; | ||
| 1222 | |||
| 1223 | /* hw switch event */ | ||
| 1224 | if (real_ev == 1) | ||
| 1225 | sony_nc_rfkill_update(); | ||
| 1226 | |||
| 1227 | break; | ||
| 1228 | |||
| 1229 | default: | ||
| 1230 | dprintk("Unknown event 0x%x for handle 0x%x\n", | ||
| 1231 | event, handle); | ||
| 1232 | break; | ||
| 1117 | } | 1233 | } |
| 1118 | } else | ||
| 1119 | sony_laptop_report_input_event(ev); | ||
| 1120 | 1234 | ||
| 1121 | dprintk("sony_nc_notify, event: 0x%.2x\n", ev); | 1235 | /* clear the event (and the event reason when present) */ |
| 1122 | acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); | 1236 | arg = 1 << offset; |
| 1237 | sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result); | ||
| 1238 | |||
| 1239 | } else { | ||
| 1240 | /* old style event */ | ||
| 1241 | ev_type = 1; | ||
| 1242 | sony_laptop_report_input_event(real_ev); | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev); | ||
| 1246 | |||
| 1247 | acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, | ||
| 1248 | dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); | ||
| 1123 | } | 1249 | } |
| 1124 | 1250 | ||
| 1125 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | 1251 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, |
| @@ -1140,20 +1266,190 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | |||
| 1140 | /* | 1266 | /* |
| 1141 | * ACPI device | 1267 | * ACPI device |
| 1142 | */ | 1268 | */ |
| 1143 | static int sony_nc_function_setup(struct acpi_device *device) | 1269 | static void sony_nc_function_setup(struct acpi_device *device, |
| 1270 | struct platform_device *pf_device) | ||
| 1144 | { | 1271 | { |
| 1145 | int result; | 1272 | unsigned int i, result, bitmask, arg; |
| 1273 | |||
| 1274 | if (!handles) | ||
| 1275 | return; | ||
| 1276 | |||
| 1277 | /* setup found handles here */ | ||
| 1278 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
| 1279 | unsigned int handle = handles->cap[i]; | ||
| 1280 | |||
| 1281 | if (!handle) | ||
| 1282 | continue; | ||
| 1283 | |||
| 1284 | dprintk("setting up handle 0x%.4x\n", handle); | ||
| 1285 | |||
| 1286 | switch (handle) { | ||
| 1287 | case 0x0100: | ||
| 1288 | case 0x0101: | ||
| 1289 | case 0x0127: | ||
| 1290 | /* setup hotkeys */ | ||
| 1291 | sony_call_snc_handle(handle, 0, &result); | ||
| 1292 | break; | ||
| 1293 | case 0x0102: | ||
| 1294 | /* setup hotkeys */ | ||
| 1295 | sony_call_snc_handle(handle, 0x100, &result); | ||
| 1296 | break; | ||
| 1297 | case 0x0105: | ||
| 1298 | case 0x0148: | ||
| 1299 | /* touchpad enable/disable */ | ||
| 1300 | result = sony_nc_touchpad_setup(pf_device, handle); | ||
| 1301 | if (result) | ||
| 1302 | pr_err("couldn't set up touchpad control function (%d)\n", | ||
| 1303 | result); | ||
| 1304 | break; | ||
| 1305 | case 0x0115: | ||
| 1306 | case 0x0136: | ||
| 1307 | case 0x013f: | ||
| 1308 | result = sony_nc_battery_care_setup(pf_device, handle); | ||
| 1309 | if (result) | ||
| 1310 | pr_err("couldn't set up battery care function (%d)\n", | ||
| 1311 | result); | ||
| 1312 | break; | ||
| 1313 | case 0x0119: | ||
| 1314 | result = sony_nc_lid_resume_setup(pf_device); | ||
| 1315 | if (result) | ||
| 1316 | pr_err("couldn't set up lid resume function (%d)\n", | ||
| 1317 | result); | ||
| 1318 | break; | ||
| 1319 | case 0x0122: | ||
| 1320 | result = sony_nc_thermal_setup(pf_device); | ||
| 1321 | if (result) | ||
| 1322 | pr_err("couldn't set up thermal profile function (%d)\n", | ||
| 1323 | result); | ||
| 1324 | break; | ||
| 1325 | case 0x0131: | ||
| 1326 | result = sony_nc_highspeed_charging_setup(pf_device); | ||
| 1327 | if (result) | ||
| 1328 | pr_err("couldn't set up high speed charging function (%d)\n", | ||
| 1329 | result); | ||
| 1330 | break; | ||
| 1331 | case 0x0124: | ||
| 1332 | case 0x0135: | ||
| 1333 | result = sony_nc_rfkill_setup(device, handle); | ||
| 1334 | if (result) | ||
| 1335 | pr_err("couldn't set up rfkill support (%d)\n", | ||
| 1336 | result); | ||
| 1337 | break; | ||
| 1338 | case 0x0137: | ||
| 1339 | case 0x0143: | ||
| 1340 | result = sony_nc_kbd_backlight_setup(pf_device, handle); | ||
| 1341 | if (result) | ||
| 1342 | pr_err("couldn't set up keyboard backlight function (%d)\n", | ||
| 1343 | result); | ||
| 1344 | break; | ||
| 1345 | default: | ||
| 1346 | continue; | ||
| 1347 | } | ||
| 1348 | } | ||
| 1146 | 1349 | ||
| 1147 | /* Enable all events */ | 1350 | /* Enable all events */ |
| 1148 | acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result); | 1351 | arg = 0x10; |
| 1352 | if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask)) | ||
| 1353 | sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask, | ||
| 1354 | &result); | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | static void sony_nc_function_cleanup(struct platform_device *pd) | ||
| 1358 | { | ||
| 1359 | unsigned int i, result, bitmask, handle; | ||
| 1149 | 1360 | ||
| 1150 | /* Setup hotkeys */ | 1361 | /* get enabled events and disable them */ |
| 1151 | sony_call_snc_handle(0x0100, 0, &result); | 1362 | sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask); |
| 1152 | sony_call_snc_handle(0x0101, 0, &result); | 1363 | sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result); |
| 1153 | sony_call_snc_handle(0x0102, 0x100, &result); | ||
| 1154 | sony_call_snc_handle(0x0127, 0, &result); | ||
| 1155 | 1364 | ||
| 1156 | return 0; | 1365 | /* cleanup handles here */ |
| 1366 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
| 1367 | |||
| 1368 | handle = handles->cap[i]; | ||
| 1369 | |||
| 1370 | if (!handle) | ||
| 1371 | continue; | ||
| 1372 | |||
| 1373 | switch (handle) { | ||
| 1374 | case 0x0105: | ||
| 1375 | case 0x0148: | ||
| 1376 | sony_nc_touchpad_cleanup(pd); | ||
| 1377 | break; | ||
| 1378 | case 0x0115: | ||
| 1379 | case 0x0136: | ||
| 1380 | case 0x013f: | ||
| 1381 | sony_nc_battery_care_cleanup(pd); | ||
| 1382 | break; | ||
| 1383 | case 0x0119: | ||
| 1384 | sony_nc_lid_resume_cleanup(pd); | ||
| 1385 | break; | ||
| 1386 | case 0x0122: | ||
| 1387 | sony_nc_thermal_cleanup(pd); | ||
| 1388 | break; | ||
| 1389 | case 0x0131: | ||
| 1390 | sony_nc_highspeed_charging_cleanup(pd); | ||
| 1391 | break; | ||
| 1392 | case 0x0124: | ||
| 1393 | case 0x0135: | ||
| 1394 | sony_nc_rfkill_cleanup(); | ||
| 1395 | break; | ||
| 1396 | case 0x0137: | ||
| 1397 | case 0x0143: | ||
| 1398 | sony_nc_kbd_backlight_cleanup(pd); | ||
| 1399 | break; | ||
| 1400 | default: | ||
| 1401 | continue; | ||
| 1402 | } | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | /* finally cleanup the handles list */ | ||
| 1406 | sony_nc_handles_cleanup(pd); | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | static void sony_nc_function_resume(void) | ||
| 1410 | { | ||
| 1411 | unsigned int i, result, bitmask, arg; | ||
| 1412 | |||
| 1413 | dprintk("Resuming SNC device\n"); | ||
| 1414 | |||
| 1415 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
| 1416 | unsigned int handle = handles->cap[i]; | ||
| 1417 | |||
| 1418 | if (!handle) | ||
| 1419 | continue; | ||
| 1420 | |||
| 1421 | switch (handle) { | ||
| 1422 | case 0x0100: | ||
| 1423 | case 0x0101: | ||
| 1424 | case 0x0127: | ||
| 1425 | /* re-enable hotkeys */ | ||
| 1426 | sony_call_snc_handle(handle, 0, &result); | ||
| 1427 | break; | ||
| 1428 | case 0x0102: | ||
| 1429 | /* re-enable hotkeys */ | ||
| 1430 | sony_call_snc_handle(handle, 0x100, &result); | ||
| 1431 | break; | ||
| 1432 | case 0x0122: | ||
| 1433 | sony_nc_thermal_resume(); | ||
| 1434 | break; | ||
| 1435 | case 0x0124: | ||
| 1436 | case 0x0135: | ||
| 1437 | sony_nc_rfkill_update(); | ||
| 1438 | break; | ||
| 1439 | case 0x0137: | ||
| 1440 | case 0x0143: | ||
| 1441 | sony_nc_kbd_backlight_resume(); | ||
| 1442 | break; | ||
| 1443 | default: | ||
| 1444 | continue; | ||
| 1445 | } | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | /* Enable all events */ | ||
| 1449 | arg = 0x10; | ||
| 1450 | if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask)) | ||
| 1451 | sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask, | ||
| 1452 | &result); | ||
| 1157 | } | 1453 | } |
| 1158 | 1454 | ||
| 1159 | static int sony_nc_resume(struct acpi_device *device) | 1455 | static int sony_nc_resume(struct acpi_device *device) |
| @@ -1166,8 +1462,8 @@ static int sony_nc_resume(struct acpi_device *device) | |||
| 1166 | 1462 | ||
| 1167 | if (!item->valid) | 1463 | if (!item->valid) |
| 1168 | continue; | 1464 | continue; |
| 1169 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, | 1465 | ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, |
| 1170 | item->value, NULL); | 1466 | &item->value, NULL); |
| 1171 | if (ret < 0) { | 1467 | if (ret < 0) { |
| 1172 | pr_err("%s: %d\n", __func__, ret); | 1468 | pr_err("%s: %d\n", __func__, ret); |
| 1173 | break; | 1469 | break; |
| @@ -1176,21 +1472,14 @@ static int sony_nc_resume(struct acpi_device *device) | |||
| 1176 | 1472 | ||
| 1177 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", | 1473 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", |
| 1178 | &handle))) { | 1474 | &handle))) { |
| 1179 | if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) | 1475 | int arg = 1; |
| 1476 | if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL)) | ||
| 1180 | dprintk("ECON Method failed\n"); | 1477 | dprintk("ECON Method failed\n"); |
| 1181 | } | 1478 | } |
| 1182 | 1479 | ||
| 1183 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", | 1480 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", |
| 1184 | &handle))) { | 1481 | &handle))) |
| 1185 | dprintk("Doing SNC setup\n"); | 1482 | sony_nc_function_resume(); |
| 1186 | sony_nc_function_setup(device); | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | /* re-read rfkill state */ | ||
| 1190 | sony_nc_rfkill_update(); | ||
| 1191 | |||
| 1192 | /* restore kbd backlight states */ | ||
| 1193 | sony_nc_kbd_backlight_resume(); | ||
| 1194 | 1483 | ||
| 1195 | return 0; | 1484 | return 0; |
| 1196 | } | 1485 | } |
| @@ -1213,7 +1502,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked) | |||
| 1213 | int argument = sony_rfkill_address[(long) data] + 0x100; | 1502 | int argument = sony_rfkill_address[(long) data] + 0x100; |
| 1214 | 1503 | ||
| 1215 | if (!blocked) | 1504 | if (!blocked) |
| 1216 | argument |= 0xff0000; | 1505 | argument |= 0x030000; |
| 1217 | 1506 | ||
| 1218 | return sony_call_snc_handle(sony_rfkill_handle, argument, &result); | 1507 | return sony_call_snc_handle(sony_rfkill_handle, argument, &result); |
| 1219 | } | 1508 | } |
| @@ -1230,7 +1519,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, | |||
| 1230 | enum rfkill_type type; | 1519 | enum rfkill_type type; |
| 1231 | const char *name; | 1520 | const char *name; |
| 1232 | int result; | 1521 | int result; |
| 1233 | bool hwblock; | 1522 | bool hwblock, swblock; |
| 1234 | 1523 | ||
| 1235 | switch (nc_type) { | 1524 | switch (nc_type) { |
| 1236 | case SONY_WIFI: | 1525 | case SONY_WIFI: |
| @@ -1258,8 +1547,21 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, | |||
| 1258 | if (!rfk) | 1547 | if (!rfk) |
| 1259 | return -ENOMEM; | 1548 | return -ENOMEM; |
| 1260 | 1549 | ||
| 1261 | sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); | 1550 | if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) { |
| 1551 | rfkill_destroy(rfk); | ||
| 1552 | return -1; | ||
| 1553 | } | ||
| 1262 | hwblock = !(result & 0x1); | 1554 | hwblock = !(result & 0x1); |
| 1555 | |||
| 1556 | if (sony_call_snc_handle(sony_rfkill_handle, | ||
| 1557 | sony_rfkill_address[nc_type], | ||
| 1558 | &result) < 0) { | ||
| 1559 | rfkill_destroy(rfk); | ||
| 1560 | return -1; | ||
| 1561 | } | ||
| 1562 | swblock = !(result & 0x2); | ||
| 1563 | |||
| 1564 | rfkill_init_sw_state(rfk, swblock); | ||
| 1263 | rfkill_set_hw_state(rfk, hwblock); | 1565 | rfkill_set_hw_state(rfk, hwblock); |
| 1264 | 1566 | ||
| 1265 | err = rfkill_register(rfk); | 1567 | err = rfkill_register(rfk); |
| @@ -1295,101 +1597,79 @@ static void sony_nc_rfkill_update(void) | |||
| 1295 | 1597 | ||
| 1296 | sony_call_snc_handle(sony_rfkill_handle, argument, &result); | 1598 | sony_call_snc_handle(sony_rfkill_handle, argument, &result); |
| 1297 | rfkill_set_states(sony_rfkill_devices[i], | 1599 | rfkill_set_states(sony_rfkill_devices[i], |
| 1298 | !(result & 0xf), false); | 1600 | !(result & 0x2), false); |
| 1299 | } | 1601 | } |
| 1300 | } | 1602 | } |
| 1301 | 1603 | ||
| 1302 | static void sony_nc_rfkill_setup(struct acpi_device *device) | 1604 | static int sony_nc_rfkill_setup(struct acpi_device *device, |
| 1605 | unsigned int handle) | ||
| 1303 | { | 1606 | { |
| 1304 | int offset; | 1607 | u64 offset; |
| 1305 | u8 dev_code, i; | 1608 | int i; |
| 1306 | acpi_status status; | 1609 | unsigned char buffer[32] = { 0 }; |
| 1307 | struct acpi_object_list params; | ||
| 1308 | union acpi_object in_obj; | ||
| 1309 | union acpi_object *device_enum; | ||
| 1310 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1311 | |||
| 1312 | offset = sony_find_snc_handle(0x124); | ||
| 1313 | if (offset == -1) { | ||
| 1314 | offset = sony_find_snc_handle(0x135); | ||
| 1315 | if (offset == -1) | ||
| 1316 | return; | ||
| 1317 | else | ||
| 1318 | sony_rfkill_handle = 0x135; | ||
| 1319 | } else | ||
| 1320 | sony_rfkill_handle = 0x124; | ||
| 1321 | dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle); | ||
| 1322 | |||
| 1323 | /* need to read the whole buffer returned by the acpi call to SN06 | ||
| 1324 | * here otherwise we may miss some features | ||
| 1325 | */ | ||
| 1326 | params.count = 1; | ||
| 1327 | params.pointer = &in_obj; | ||
| 1328 | in_obj.type = ACPI_TYPE_INTEGER; | ||
| 1329 | in_obj.integer.value = offset; | ||
| 1330 | status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, | ||
| 1331 | &buffer); | ||
| 1332 | if (ACPI_FAILURE(status)) { | ||
| 1333 | dprintk("Radio device enumeration failed\n"); | ||
| 1334 | return; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | device_enum = (union acpi_object *) buffer.pointer; | ||
| 1338 | if (!device_enum) { | ||
| 1339 | pr_err("No SN06 return object\n"); | ||
| 1340 | goto out_no_enum; | ||
| 1341 | } | ||
| 1342 | if (device_enum->type != ACPI_TYPE_BUFFER) { | ||
| 1343 | pr_err("Invalid SN06 return object 0x%.2x\n", | ||
| 1344 | device_enum->type); | ||
| 1345 | goto out_no_enum; | ||
| 1346 | } | ||
| 1347 | 1610 | ||
| 1348 | /* the buffer is filled with magic numbers describing the devices | 1611 | offset = sony_find_snc_handle(handle); |
| 1349 | * available, 0xff terminates the enumeration | 1612 | sony_rfkill_handle = handle; |
| 1613 | |||
| 1614 | i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer, | ||
| 1615 | 32); | ||
| 1616 | if (i < 0) | ||
| 1617 | return i; | ||
| 1618 | |||
| 1619 | /* The buffer is filled with magic numbers describing the devices | ||
| 1620 | * available, 0xff terminates the enumeration. | ||
| 1621 | * Known codes: | ||
| 1622 | * 0x00 WLAN | ||
| 1623 | * 0x10 BLUETOOTH | ||
| 1624 | * 0x20 WWAN GPRS-EDGE | ||
| 1625 | * 0x21 WWAN HSDPA | ||
| 1626 | * 0x22 WWAN EV-DO | ||
| 1627 | * 0x23 WWAN GPS | ||
| 1628 | * 0x25 Gobi WWAN no GPS | ||
| 1629 | * 0x26 Gobi WWAN + GPS | ||
| 1630 | * 0x28 Gobi WWAN no GPS | ||
| 1631 | * 0x29 Gobi WWAN + GPS | ||
| 1632 | * 0x30 WIMAX | ||
| 1633 | * 0x50 Gobi WWAN no GPS | ||
| 1634 | * 0x51 Gobi WWAN + GPS | ||
| 1635 | * 0x70 no SIM card slot | ||
| 1636 | * 0x71 SIM card slot | ||
| 1350 | */ | 1637 | */ |
| 1351 | for (i = 0; i < device_enum->buffer.length; i++) { | 1638 | for (i = 0; i < ARRAY_SIZE(buffer); i++) { |
| 1352 | 1639 | ||
| 1353 | dev_code = *(device_enum->buffer.pointer + i); | 1640 | if (buffer[i] == 0xff) |
| 1354 | if (dev_code == 0xff) | ||
| 1355 | break; | 1641 | break; |
| 1356 | 1642 | ||
| 1357 | dprintk("Radio devices, looking at 0x%.2x\n", dev_code); | 1643 | dprintk("Radio devices, found 0x%.2x\n", buffer[i]); |
| 1358 | 1644 | ||
| 1359 | if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) | 1645 | if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI]) |
| 1360 | sony_nc_setup_rfkill(device, SONY_WIFI); | 1646 | sony_nc_setup_rfkill(device, SONY_WIFI); |
| 1361 | 1647 | ||
| 1362 | if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) | 1648 | if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) |
| 1363 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); | 1649 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); |
| 1364 | 1650 | ||
| 1365 | if ((0xf0 & dev_code) == 0x20 && | 1651 | if (((0xf0 & buffer[i]) == 0x20 || |
| 1652 | (0xf0 & buffer[i]) == 0x50) && | ||
| 1366 | !sony_rfkill_devices[SONY_WWAN]) | 1653 | !sony_rfkill_devices[SONY_WWAN]) |
| 1367 | sony_nc_setup_rfkill(device, SONY_WWAN); | 1654 | sony_nc_setup_rfkill(device, SONY_WWAN); |
| 1368 | 1655 | ||
| 1369 | if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) | 1656 | if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) |
| 1370 | sony_nc_setup_rfkill(device, SONY_WIMAX); | 1657 | sony_nc_setup_rfkill(device, SONY_WIMAX); |
| 1371 | } | 1658 | } |
| 1372 | 1659 | return 0; | |
| 1373 | out_no_enum: | ||
| 1374 | kfree(buffer.pointer); | ||
| 1375 | return; | ||
| 1376 | } | 1660 | } |
| 1377 | 1661 | ||
| 1378 | /* Keyboard backlight feature */ | 1662 | /* Keyboard backlight feature */ |
| 1379 | #define KBDBL_HANDLER 0x137 | ||
| 1380 | #define KBDBL_PRESENT 0xB00 | ||
| 1381 | #define SET_MODE 0xC00 | ||
| 1382 | #define SET_STATE 0xD00 | ||
| 1383 | #define SET_TIMEOUT 0xE00 | ||
| 1384 | |||
| 1385 | struct kbd_backlight { | 1663 | struct kbd_backlight { |
| 1386 | int mode; | 1664 | unsigned int handle; |
| 1387 | int timeout; | 1665 | unsigned int base; |
| 1666 | unsigned int mode; | ||
| 1667 | unsigned int timeout; | ||
| 1388 | struct device_attribute mode_attr; | 1668 | struct device_attribute mode_attr; |
| 1389 | struct device_attribute timeout_attr; | 1669 | struct device_attribute timeout_attr; |
| 1390 | }; | 1670 | }; |
| 1391 | 1671 | ||
| 1392 | static struct kbd_backlight *kbdbl_handle; | 1672 | static struct kbd_backlight *kbdbl_ctl; |
| 1393 | 1673 | ||
| 1394 | static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) | 1674 | static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) |
| 1395 | { | 1675 | { |
| @@ -1398,15 +1678,15 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) | |||
| 1398 | if (value > 1) | 1678 | if (value > 1) |
| 1399 | return -EINVAL; | 1679 | return -EINVAL; |
| 1400 | 1680 | ||
| 1401 | if (sony_call_snc_handle(KBDBL_HANDLER, | 1681 | if (sony_call_snc_handle(kbdbl_ctl->handle, |
| 1402 | (value << 0x10) | SET_MODE, &result)) | 1682 | (value << 0x10) | (kbdbl_ctl->base), &result)) |
| 1403 | return -EIO; | 1683 | return -EIO; |
| 1404 | 1684 | ||
| 1405 | /* Try to turn the light on/off immediately */ | 1685 | /* Try to turn the light on/off immediately */ |
| 1406 | sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, | 1686 | sony_call_snc_handle(kbdbl_ctl->handle, |
| 1407 | &result); | 1687 | (value << 0x10) | (kbdbl_ctl->base + 0x100), &result); |
| 1408 | 1688 | ||
| 1409 | kbdbl_handle->mode = value; | 1689 | kbdbl_ctl->mode = value; |
| 1410 | 1690 | ||
| 1411 | return 0; | 1691 | return 0; |
| 1412 | } | 1692 | } |
| @@ -1421,7 +1701,7 @@ static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, | |||
| 1421 | if (count > 31) | 1701 | if (count > 31) |
| 1422 | return -EINVAL; | 1702 | return -EINVAL; |
| 1423 | 1703 | ||
| 1424 | if (strict_strtoul(buffer, 10, &value)) | 1704 | if (kstrtoul(buffer, 10, &value)) |
| 1425 | return -EINVAL; | 1705 | return -EINVAL; |
| 1426 | 1706 | ||
| 1427 | ret = __sony_nc_kbd_backlight_mode_set(value); | 1707 | ret = __sony_nc_kbd_backlight_mode_set(value); |
| @@ -1435,7 +1715,7 @@ static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, | |||
| 1435 | struct device_attribute *attr, char *buffer) | 1715 | struct device_attribute *attr, char *buffer) |
| 1436 | { | 1716 | { |
| 1437 | ssize_t count = 0; | 1717 | ssize_t count = 0; |
| 1438 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); | 1718 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode); |
| 1439 | return count; | 1719 | return count; |
| 1440 | } | 1720 | } |
| 1441 | 1721 | ||
| @@ -1446,11 +1726,11 @@ static int __sony_nc_kbd_backlight_timeout_set(u8 value) | |||
| 1446 | if (value > 3) | 1726 | if (value > 3) |
| 1447 | return -EINVAL; | 1727 | return -EINVAL; |
| 1448 | 1728 | ||
| 1449 | if (sony_call_snc_handle(KBDBL_HANDLER, | 1729 | if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) | |
| 1450 | (value << 0x10) | SET_TIMEOUT, &result)) | 1730 | (kbdbl_ctl->base + 0x200), &result)) |
| 1451 | return -EIO; | 1731 | return -EIO; |
| 1452 | 1732 | ||
| 1453 | kbdbl_handle->timeout = value; | 1733 | kbdbl_ctl->timeout = value; |
| 1454 | 1734 | ||
| 1455 | return 0; | 1735 | return 0; |
| 1456 | } | 1736 | } |
| @@ -1465,7 +1745,7 @@ static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, | |||
| 1465 | if (count > 31) | 1745 | if (count > 31) |
| 1466 | return -EINVAL; | 1746 | return -EINVAL; |
| 1467 | 1747 | ||
| 1468 | if (strict_strtoul(buffer, 10, &value)) | 1748 | if (kstrtoul(buffer, 10, &value)) |
| 1469 | return -EINVAL; | 1749 | return -EINVAL; |
| 1470 | 1750 | ||
| 1471 | ret = __sony_nc_kbd_backlight_timeout_set(value); | 1751 | ret = __sony_nc_kbd_backlight_timeout_set(value); |
| @@ -1479,39 +1759,58 @@ static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, | |||
| 1479 | struct device_attribute *attr, char *buffer) | 1759 | struct device_attribute *attr, char *buffer) |
| 1480 | { | 1760 | { |
| 1481 | ssize_t count = 0; | 1761 | ssize_t count = 0; |
| 1482 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); | 1762 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout); |
| 1483 | return count; | 1763 | return count; |
| 1484 | } | 1764 | } |
| 1485 | 1765 | ||
| 1486 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd) | 1766 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd, |
| 1767 | unsigned int handle) | ||
| 1487 | { | 1768 | { |
| 1488 | int result; | 1769 | int result; |
| 1770 | int ret = 0; | ||
| 1489 | 1771 | ||
| 1490 | if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) | 1772 | /* verify the kbd backlight presence, these handles are not used for |
| 1491 | return 0; | 1773 | * keyboard backlight only |
| 1492 | if (!(result & 0x02)) | 1774 | */ |
| 1775 | ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100, | ||
| 1776 | &result); | ||
| 1777 | if (ret) | ||
| 1778 | return ret; | ||
| 1779 | |||
| 1780 | if ((handle == 0x0137 && !(result & 0x02)) || | ||
| 1781 | !(result & 0x01)) { | ||
| 1782 | dprintk("no backlight keyboard found\n"); | ||
| 1493 | return 0; | 1783 | return 0; |
| 1784 | } | ||
| 1494 | 1785 | ||
| 1495 | kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); | 1786 | kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL); |
| 1496 | if (!kbdbl_handle) | 1787 | if (!kbdbl_ctl) |
| 1497 | return -ENOMEM; | 1788 | return -ENOMEM; |
| 1498 | 1789 | ||
| 1499 | sysfs_attr_init(&kbdbl_handle->mode_attr.attr); | 1790 | kbdbl_ctl->handle = handle; |
| 1500 | kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; | 1791 | if (handle == 0x0137) |
| 1501 | kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; | 1792 | kbdbl_ctl->base = 0x0C00; |
| 1502 | kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; | 1793 | else |
| 1503 | kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; | 1794 | kbdbl_ctl->base = 0x4000; |
| 1795 | |||
| 1796 | sysfs_attr_init(&kbdbl_ctl->mode_attr.attr); | ||
| 1797 | kbdbl_ctl->mode_attr.attr.name = "kbd_backlight"; | ||
| 1798 | kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
| 1799 | kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show; | ||
| 1800 | kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store; | ||
| 1504 | 1801 | ||
| 1505 | sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); | 1802 | sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr); |
| 1506 | kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; | 1803 | kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout"; |
| 1507 | kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; | 1804 | kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; |
| 1508 | kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; | 1805 | kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; |
| 1509 | kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; | 1806 | kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; |
| 1510 | 1807 | ||
| 1511 | if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) | 1808 | ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr); |
| 1809 | if (ret) | ||
| 1512 | goto outkzalloc; | 1810 | goto outkzalloc; |
| 1513 | 1811 | ||
| 1514 | if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) | 1812 | ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr); |
| 1813 | if (ret) | ||
| 1515 | goto outmode; | 1814 | goto outmode; |
| 1516 | 1815 | ||
| 1517 | __sony_nc_kbd_backlight_mode_set(kbd_backlight); | 1816 | __sony_nc_kbd_backlight_mode_set(kbd_backlight); |
| @@ -1520,57 +1819,661 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd) | |||
| 1520 | return 0; | 1819 | return 0; |
| 1521 | 1820 | ||
| 1522 | outmode: | 1821 | outmode: |
| 1523 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | 1822 | device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); |
| 1524 | outkzalloc: | 1823 | outkzalloc: |
| 1525 | kfree(kbdbl_handle); | 1824 | kfree(kbdbl_ctl); |
| 1526 | kbdbl_handle = NULL; | 1825 | kbdbl_ctl = NULL; |
| 1527 | return -1; | 1826 | return ret; |
| 1528 | } | 1827 | } |
| 1529 | 1828 | ||
| 1530 | static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | 1829 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) |
| 1531 | { | 1830 | { |
| 1532 | if (kbdbl_handle) { | 1831 | if (kbdbl_ctl) { |
| 1533 | int result; | 1832 | int result; |
| 1534 | 1833 | ||
| 1535 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | 1834 | device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); |
| 1536 | device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); | 1835 | device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); |
| 1537 | 1836 | ||
| 1538 | /* restore the default hw behaviour */ | 1837 | /* restore the default hw behaviour */ |
| 1539 | sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); | 1838 | sony_call_snc_handle(kbdbl_ctl->handle, |
| 1540 | sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); | 1839 | kbdbl_ctl->base | 0x10000, &result); |
| 1840 | sony_call_snc_handle(kbdbl_ctl->handle, | ||
| 1841 | kbdbl_ctl->base + 0x200, &result); | ||
| 1541 | 1842 | ||
| 1542 | kfree(kbdbl_handle); | 1843 | kfree(kbdbl_ctl); |
| 1844 | kbdbl_ctl = NULL; | ||
| 1543 | } | 1845 | } |
| 1544 | return 0; | ||
| 1545 | } | 1846 | } |
| 1546 | 1847 | ||
| 1547 | static void sony_nc_kbd_backlight_resume(void) | 1848 | static void sony_nc_kbd_backlight_resume(void) |
| 1548 | { | 1849 | { |
| 1549 | int ignore = 0; | 1850 | int ignore = 0; |
| 1550 | 1851 | ||
| 1551 | if (!kbdbl_handle) | 1852 | if (!kbdbl_ctl) |
| 1552 | return; | 1853 | return; |
| 1553 | 1854 | ||
| 1554 | if (kbdbl_handle->mode == 0) | 1855 | if (kbdbl_ctl->mode == 0) |
| 1555 | sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); | 1856 | sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base, |
| 1556 | |||
| 1557 | if (kbdbl_handle->timeout != 0) | ||
| 1558 | sony_call_snc_handle(KBDBL_HANDLER, | ||
| 1559 | (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT, | ||
| 1560 | &ignore); | 1857 | &ignore); |
| 1858 | |||
| 1859 | if (kbdbl_ctl->timeout != 0) | ||
| 1860 | sony_call_snc_handle(kbdbl_ctl->handle, | ||
| 1861 | (kbdbl_ctl->base + 0x200) | | ||
| 1862 | (kbdbl_ctl->timeout << 0x10), &ignore); | ||
| 1863 | } | ||
| 1864 | |||
| 1865 | struct battery_care_control { | ||
| 1866 | struct device_attribute attrs[2]; | ||
| 1867 | unsigned int handle; | ||
| 1868 | }; | ||
| 1869 | static struct battery_care_control *bcare_ctl; | ||
| 1870 | |||
| 1871 | static ssize_t sony_nc_battery_care_limit_store(struct device *dev, | ||
| 1872 | struct device_attribute *attr, | ||
| 1873 | const char *buffer, size_t count) | ||
| 1874 | { | ||
| 1875 | unsigned int result, cmd; | ||
| 1876 | unsigned long value; | ||
| 1877 | |||
| 1878 | if (count > 31) | ||
| 1879 | return -EINVAL; | ||
| 1880 | |||
| 1881 | if (kstrtoul(buffer, 10, &value)) | ||
| 1882 | return -EINVAL; | ||
| 1883 | |||
| 1884 | /* limit values (2 bits): | ||
| 1885 | * 00 - none | ||
| 1886 | * 01 - 80% | ||
| 1887 | * 10 - 50% | ||
| 1888 | * 11 - 100% | ||
| 1889 | * | ||
| 1890 | * bit 0: 0 disable BCL, 1 enable BCL | ||
| 1891 | * bit 1: 1 tell to store the battery limit (see bits 6,7) too | ||
| 1892 | * bits 2,3: reserved | ||
| 1893 | * bits 4,5: store the limit into the EC | ||
| 1894 | * bits 6,7: store the limit into the battery | ||
| 1895 | */ | ||
| 1896 | |||
| 1897 | /* | ||
| 1898 | * handle 0x0115 should allow storing on battery too; | ||
| 1899 | * handle 0x0136 same as 0x0115 + health status; | ||
| 1900 | * handle 0x013f, same as 0x0136 but no storing on the battery | ||
| 1901 | * | ||
| 1902 | * Store only inside the EC for now, regardless the handle number | ||
| 1903 | */ | ||
| 1904 | if (value == 0) | ||
| 1905 | /* disable limits */ | ||
| 1906 | cmd = 0x0; | ||
| 1907 | |||
| 1908 | else if (value <= 50) | ||
| 1909 | cmd = 0x21; | ||
| 1910 | |||
| 1911 | else if (value <= 80) | ||
| 1912 | cmd = 0x11; | ||
| 1913 | |||
| 1914 | else if (value <= 100) | ||
| 1915 | cmd = 0x31; | ||
| 1916 | |||
| 1917 | else | ||
| 1918 | return -EINVAL; | ||
| 1919 | |||
| 1920 | if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100, | ||
| 1921 | &result)) | ||
| 1922 | return -EIO; | ||
| 1923 | |||
| 1924 | return count; | ||
| 1925 | } | ||
| 1926 | |||
| 1927 | static ssize_t sony_nc_battery_care_limit_show(struct device *dev, | ||
| 1928 | struct device_attribute *attr, char *buffer) | ||
| 1929 | { | ||
| 1930 | unsigned int result, status; | ||
| 1931 | |||
| 1932 | if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result)) | ||
| 1933 | return -EIO; | ||
| 1934 | |||
| 1935 | status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0; | ||
| 1936 | switch (status) { | ||
| 1937 | case 1: | ||
| 1938 | status = 80; | ||
| 1939 | break; | ||
| 1940 | case 2: | ||
| 1941 | status = 50; | ||
| 1942 | break; | ||
| 1943 | case 3: | ||
| 1944 | status = 100; | ||
| 1945 | break; | ||
| 1946 | default: | ||
| 1947 | status = 0; | ||
| 1948 | break; | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | return snprintf(buffer, PAGE_SIZE, "%d\n", status); | ||
| 1952 | } | ||
| 1953 | |||
| 1954 | static ssize_t sony_nc_battery_care_health_show(struct device *dev, | ||
| 1955 | struct device_attribute *attr, char *buffer) | ||
| 1956 | { | ||
| 1957 | ssize_t count = 0; | ||
| 1958 | unsigned int health; | ||
| 1959 | |||
| 1960 | if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health)) | ||
| 1961 | return -EIO; | ||
| 1962 | |||
| 1963 | count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff); | ||
| 1964 | |||
| 1965 | return count; | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | static int sony_nc_battery_care_setup(struct platform_device *pd, | ||
| 1969 | unsigned int handle) | ||
| 1970 | { | ||
| 1971 | int ret = 0; | ||
| 1972 | |||
| 1973 | bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL); | ||
| 1974 | if (!bcare_ctl) | ||
| 1975 | return -ENOMEM; | ||
| 1976 | |||
| 1977 | bcare_ctl->handle = handle; | ||
| 1978 | |||
| 1979 | sysfs_attr_init(&bcare_ctl->attrs[0].attr); | ||
| 1980 | bcare_ctl->attrs[0].attr.name = "battery_care_limiter"; | ||
| 1981 | bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; | ||
| 1982 | bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show; | ||
| 1983 | bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store; | ||
| 1984 | |||
| 1985 | ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]); | ||
| 1986 | if (ret) | ||
| 1987 | goto outkzalloc; | ||
| 1988 | |||
| 1989 | /* 0x0115 is for models with no health reporting capability */ | ||
| 1990 | if (handle == 0x0115) | ||
| 1991 | return 0; | ||
| 1992 | |||
| 1993 | sysfs_attr_init(&bcare_ctl->attrs[1].attr); | ||
| 1994 | bcare_ctl->attrs[1].attr.name = "battery_care_health"; | ||
| 1995 | bcare_ctl->attrs[1].attr.mode = S_IRUGO; | ||
| 1996 | bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show; | ||
| 1997 | |||
| 1998 | ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]); | ||
| 1999 | if (ret) | ||
| 2000 | goto outlimiter; | ||
| 2001 | |||
| 2002 | return 0; | ||
| 2003 | |||
| 2004 | outlimiter: | ||
| 2005 | device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); | ||
| 2006 | |||
| 2007 | outkzalloc: | ||
| 2008 | kfree(bcare_ctl); | ||
| 2009 | bcare_ctl = NULL; | ||
| 2010 | |||
| 2011 | return ret; | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | static void sony_nc_battery_care_cleanup(struct platform_device *pd) | ||
| 2015 | { | ||
| 2016 | if (bcare_ctl) { | ||
| 2017 | device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); | ||
| 2018 | if (bcare_ctl->handle != 0x0115) | ||
| 2019 | device_remove_file(&pd->dev, &bcare_ctl->attrs[1]); | ||
| 2020 | |||
| 2021 | kfree(bcare_ctl); | ||
| 2022 | bcare_ctl = NULL; | ||
| 2023 | } | ||
| 2024 | } | ||
| 2025 | |||
| 2026 | struct snc_thermal_ctrl { | ||
| 2027 | unsigned int mode; | ||
| 2028 | unsigned int profiles; | ||
| 2029 | struct device_attribute mode_attr; | ||
| 2030 | struct device_attribute profiles_attr; | ||
| 2031 | }; | ||
| 2032 | static struct snc_thermal_ctrl *th_handle; | ||
| 2033 | |||
| 2034 | #define THM_PROFILE_MAX 3 | ||
| 2035 | static const char * const snc_thermal_profiles[] = { | ||
| 2036 | "balanced", | ||
| 2037 | "silent", | ||
| 2038 | "performance" | ||
| 2039 | }; | ||
| 2040 | |||
| 2041 | static int sony_nc_thermal_mode_set(unsigned short mode) | ||
| 2042 | { | ||
| 2043 | unsigned int result; | ||
| 2044 | |||
| 2045 | /* the thermal profile seems to be a two bit bitmask: | ||
| 2046 | * lsb -> silent | ||
| 2047 | * msb -> performance | ||
| 2048 | * no bit set is the normal operation and is always valid | ||
| 2049 | * Some vaio models only have "balanced" and "performance" | ||
| 2050 | */ | ||
| 2051 | if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX) | ||
| 2052 | return -EINVAL; | ||
| 2053 | |||
| 2054 | if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result)) | ||
| 2055 | return -EIO; | ||
| 2056 | |||
| 2057 | th_handle->mode = mode; | ||
| 2058 | |||
| 2059 | return 0; | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | static int sony_nc_thermal_mode_get(void) | ||
| 2063 | { | ||
| 2064 | unsigned int result; | ||
| 2065 | |||
| 2066 | if (sony_call_snc_handle(0x0122, 0x0100, &result)) | ||
| 2067 | return -EIO; | ||
| 2068 | |||
| 2069 | return result & 0xff; | ||
| 2070 | } | ||
| 2071 | |||
| 2072 | static ssize_t sony_nc_thermal_profiles_show(struct device *dev, | ||
| 2073 | struct device_attribute *attr, char *buffer) | ||
| 2074 | { | ||
| 2075 | short cnt; | ||
| 2076 | size_t idx = 0; | ||
| 2077 | |||
| 2078 | for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) { | ||
| 2079 | if (!cnt || (th_handle->profiles & cnt)) | ||
| 2080 | idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ", | ||
| 2081 | snc_thermal_profiles[cnt]); | ||
| 2082 | } | ||
| 2083 | idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n"); | ||
| 2084 | |||
| 2085 | return idx; | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | static ssize_t sony_nc_thermal_mode_store(struct device *dev, | ||
| 2089 | struct device_attribute *attr, | ||
| 2090 | const char *buffer, size_t count) | ||
| 2091 | { | ||
| 2092 | unsigned short cmd; | ||
| 2093 | size_t len = count; | ||
| 2094 | |||
| 2095 | if (count == 0) | ||
| 2096 | return -EINVAL; | ||
| 2097 | |||
| 2098 | /* skip the newline if present */ | ||
| 2099 | if (buffer[len - 1] == '\n') | ||
| 2100 | len--; | ||
| 2101 | |||
| 2102 | for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++) | ||
| 2103 | if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0) | ||
| 2104 | break; | ||
| 2105 | |||
| 2106 | if (sony_nc_thermal_mode_set(cmd)) | ||
| 2107 | return -EIO; | ||
| 2108 | |||
| 2109 | return count; | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | static ssize_t sony_nc_thermal_mode_show(struct device *dev, | ||
| 2113 | struct device_attribute *attr, char *buffer) | ||
| 2114 | { | ||
| 2115 | ssize_t count = 0; | ||
| 2116 | unsigned int mode = sony_nc_thermal_mode_get(); | ||
| 2117 | |||
| 2118 | if (mode < 0) | ||
| 2119 | return mode; | ||
| 2120 | |||
| 2121 | count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]); | ||
| 2122 | |||
| 2123 | return count; | ||
| 2124 | } | ||
| 2125 | |||
| 2126 | static int sony_nc_thermal_setup(struct platform_device *pd) | ||
| 2127 | { | ||
| 2128 | int ret = 0; | ||
| 2129 | th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL); | ||
| 2130 | if (!th_handle) | ||
| 2131 | return -ENOMEM; | ||
| 2132 | |||
| 2133 | ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles); | ||
| 2134 | if (ret) { | ||
| 2135 | pr_warn("couldn't to read the thermal profiles\n"); | ||
| 2136 | goto outkzalloc; | ||
| 2137 | } | ||
| 2138 | |||
| 2139 | ret = sony_nc_thermal_mode_get(); | ||
| 2140 | if (ret < 0) { | ||
| 2141 | pr_warn("couldn't to read the current thermal profile"); | ||
| 2142 | goto outkzalloc; | ||
| 2143 | } | ||
| 2144 | th_handle->mode = ret; | ||
| 2145 | |||
| 2146 | sysfs_attr_init(&th_handle->profiles_attr.attr); | ||
| 2147 | th_handle->profiles_attr.attr.name = "thermal_profiles"; | ||
| 2148 | th_handle->profiles_attr.attr.mode = S_IRUGO; | ||
| 2149 | th_handle->profiles_attr.show = sony_nc_thermal_profiles_show; | ||
| 2150 | |||
| 2151 | sysfs_attr_init(&th_handle->mode_attr.attr); | ||
| 2152 | th_handle->mode_attr.attr.name = "thermal_control"; | ||
| 2153 | th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
| 2154 | th_handle->mode_attr.show = sony_nc_thermal_mode_show; | ||
| 2155 | th_handle->mode_attr.store = sony_nc_thermal_mode_store; | ||
| 2156 | |||
| 2157 | ret = device_create_file(&pd->dev, &th_handle->profiles_attr); | ||
| 2158 | if (ret) | ||
| 2159 | goto outkzalloc; | ||
| 2160 | |||
| 2161 | ret = device_create_file(&pd->dev, &th_handle->mode_attr); | ||
| 2162 | if (ret) | ||
| 2163 | goto outprofiles; | ||
| 2164 | |||
| 2165 | return 0; | ||
| 2166 | |||
| 2167 | outprofiles: | ||
| 2168 | device_remove_file(&pd->dev, &th_handle->profiles_attr); | ||
| 2169 | outkzalloc: | ||
| 2170 | kfree(th_handle); | ||
| 2171 | th_handle = NULL; | ||
| 2172 | return ret; | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | static void sony_nc_thermal_cleanup(struct platform_device *pd) | ||
| 2176 | { | ||
| 2177 | if (th_handle) { | ||
| 2178 | device_remove_file(&pd->dev, &th_handle->profiles_attr); | ||
| 2179 | device_remove_file(&pd->dev, &th_handle->mode_attr); | ||
| 2180 | kfree(th_handle); | ||
| 2181 | th_handle = NULL; | ||
| 2182 | } | ||
| 2183 | } | ||
| 2184 | |||
| 2185 | static void sony_nc_thermal_resume(void) | ||
| 2186 | { | ||
| 2187 | unsigned int status = sony_nc_thermal_mode_get(); | ||
| 2188 | |||
| 2189 | if (status != th_handle->mode) | ||
| 2190 | sony_nc_thermal_mode_set(th_handle->mode); | ||
| 2191 | } | ||
| 2192 | |||
| 2193 | /* resume on LID open */ | ||
| 2194 | struct snc_lid_resume_control { | ||
| 2195 | struct device_attribute attrs[3]; | ||
| 2196 | unsigned int status; | ||
| 2197 | }; | ||
| 2198 | static struct snc_lid_resume_control *lid_ctl; | ||
| 2199 | |||
| 2200 | static ssize_t sony_nc_lid_resume_store(struct device *dev, | ||
| 2201 | struct device_attribute *attr, | ||
| 2202 | const char *buffer, size_t count) | ||
| 2203 | { | ||
| 2204 | unsigned int result, pos; | ||
| 2205 | unsigned long value; | ||
| 2206 | if (count > 31) | ||
| 2207 | return -EINVAL; | ||
| 2208 | |||
| 2209 | if (kstrtoul(buffer, 10, &value) || value > 1) | ||
| 2210 | return -EINVAL; | ||
| 2211 | |||
| 2212 | /* the value we have to write to SNC is a bitmask: | ||
| 2213 | * +--------------+ | ||
| 2214 | * | S3 | S4 | S5 | | ||
| 2215 | * +--------------+ | ||
| 2216 | * 2 1 0 | ||
| 2217 | */ | ||
| 2218 | if (strcmp(attr->attr.name, "lid_resume_S3") == 0) | ||
| 2219 | pos = 2; | ||
| 2220 | else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) | ||
| 2221 | pos = 1; | ||
| 2222 | else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) | ||
| 2223 | pos = 0; | ||
| 2224 | else | ||
| 2225 | return -EINVAL; | ||
| 2226 | |||
| 2227 | if (value) | ||
| 2228 | value = lid_ctl->status | (1 << pos); | ||
| 2229 | else | ||
| 2230 | value = lid_ctl->status & ~(1 << pos); | ||
| 2231 | |||
| 2232 | if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result)) | ||
| 2233 | return -EIO; | ||
| 2234 | |||
| 2235 | lid_ctl->status = value; | ||
| 2236 | |||
| 2237 | return count; | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | static ssize_t sony_nc_lid_resume_show(struct device *dev, | ||
| 2241 | struct device_attribute *attr, char *buffer) | ||
| 2242 | { | ||
| 2243 | unsigned int pos; | ||
| 2244 | |||
| 2245 | if (strcmp(attr->attr.name, "lid_resume_S3") == 0) | ||
| 2246 | pos = 2; | ||
| 2247 | else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) | ||
| 2248 | pos = 1; | ||
| 2249 | else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) | ||
| 2250 | pos = 0; | ||
| 2251 | else | ||
| 2252 | return -EINVAL; | ||
| 2253 | |||
| 2254 | return snprintf(buffer, PAGE_SIZE, "%d\n", | ||
| 2255 | (lid_ctl->status >> pos) & 0x01); | ||
| 2256 | } | ||
| 2257 | |||
| 2258 | static int sony_nc_lid_resume_setup(struct platform_device *pd) | ||
| 2259 | { | ||
| 2260 | unsigned int result; | ||
| 2261 | int i; | ||
| 2262 | |||
| 2263 | if (sony_call_snc_handle(0x0119, 0x0000, &result)) | ||
| 2264 | return -EIO; | ||
| 2265 | |||
| 2266 | lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL); | ||
| 2267 | if (!lid_ctl) | ||
| 2268 | return -ENOMEM; | ||
| 2269 | |||
| 2270 | lid_ctl->status = result & 0x7; | ||
| 2271 | |||
| 2272 | sysfs_attr_init(&lid_ctl->attrs[0].attr); | ||
| 2273 | lid_ctl->attrs[0].attr.name = "lid_resume_S3"; | ||
| 2274 | lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; | ||
| 2275 | lid_ctl->attrs[0].show = sony_nc_lid_resume_show; | ||
| 2276 | lid_ctl->attrs[0].store = sony_nc_lid_resume_store; | ||
| 2277 | |||
| 2278 | sysfs_attr_init(&lid_ctl->attrs[1].attr); | ||
| 2279 | lid_ctl->attrs[1].attr.name = "lid_resume_S4"; | ||
| 2280 | lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR; | ||
| 2281 | lid_ctl->attrs[1].show = sony_nc_lid_resume_show; | ||
| 2282 | lid_ctl->attrs[1].store = sony_nc_lid_resume_store; | ||
| 2283 | |||
| 2284 | sysfs_attr_init(&lid_ctl->attrs[2].attr); | ||
| 2285 | lid_ctl->attrs[2].attr.name = "lid_resume_S5"; | ||
| 2286 | lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR; | ||
| 2287 | lid_ctl->attrs[2].show = sony_nc_lid_resume_show; | ||
| 2288 | lid_ctl->attrs[2].store = sony_nc_lid_resume_store; | ||
| 2289 | |||
| 2290 | for (i = 0; i < 3; i++) { | ||
| 2291 | result = device_create_file(&pd->dev, &lid_ctl->attrs[i]); | ||
| 2292 | if (result) | ||
| 2293 | goto liderror; | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | return 0; | ||
| 2297 | |||
| 2298 | liderror: | ||
| 2299 | for (; i > 0; i--) | ||
| 2300 | device_remove_file(&pd->dev, &lid_ctl->attrs[i]); | ||
| 2301 | |||
| 2302 | kfree(lid_ctl); | ||
| 2303 | lid_ctl = NULL; | ||
| 2304 | |||
| 2305 | return result; | ||
| 2306 | } | ||
| 2307 | |||
| 2308 | static void sony_nc_lid_resume_cleanup(struct platform_device *pd) | ||
| 2309 | { | ||
| 2310 | int i; | ||
| 2311 | |||
| 2312 | if (lid_ctl) { | ||
| 2313 | for (i = 0; i < 3; i++) | ||
| 2314 | device_remove_file(&pd->dev, &lid_ctl->attrs[i]); | ||
| 2315 | |||
| 2316 | kfree(lid_ctl); | ||
| 2317 | lid_ctl = NULL; | ||
| 2318 | } | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | /* High speed charging function */ | ||
| 2322 | static struct device_attribute *hsc_handle; | ||
| 2323 | |||
| 2324 | static ssize_t sony_nc_highspeed_charging_store(struct device *dev, | ||
| 2325 | struct device_attribute *attr, | ||
| 2326 | const char *buffer, size_t count) | ||
| 2327 | { | ||
| 2328 | unsigned int result; | ||
| 2329 | unsigned long value; | ||
| 2330 | |||
| 2331 | if (count > 31) | ||
| 2332 | return -EINVAL; | ||
| 2333 | |||
| 2334 | if (kstrtoul(buffer, 10, &value) || value > 1) | ||
| 2335 | return -EINVAL; | ||
| 2336 | |||
| 2337 | if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result)) | ||
| 2338 | return -EIO; | ||
| 2339 | |||
| 2340 | return count; | ||
| 2341 | } | ||
| 2342 | |||
| 2343 | static ssize_t sony_nc_highspeed_charging_show(struct device *dev, | ||
| 2344 | struct device_attribute *attr, char *buffer) | ||
| 2345 | { | ||
| 2346 | unsigned int result; | ||
| 2347 | |||
| 2348 | if (sony_call_snc_handle(0x0131, 0x0100, &result)) | ||
| 2349 | return -EIO; | ||
| 2350 | |||
| 2351 | return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); | ||
| 2352 | } | ||
| 2353 | |||
| 2354 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd) | ||
| 2355 | { | ||
| 2356 | unsigned int result; | ||
| 2357 | |||
| 2358 | if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) { | ||
| 2359 | /* some models advertise the handle but have no implementation | ||
| 2360 | * for it | ||
| 2361 | */ | ||
| 2362 | pr_info("No High Speed Charging capability found\n"); | ||
| 2363 | return 0; | ||
| 2364 | } | ||
| 2365 | |||
| 2366 | hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); | ||
| 2367 | if (!hsc_handle) | ||
| 2368 | return -ENOMEM; | ||
| 2369 | |||
| 2370 | sysfs_attr_init(&hsc_handle->attr); | ||
| 2371 | hsc_handle->attr.name = "battery_highspeed_charging"; | ||
| 2372 | hsc_handle->attr.mode = S_IRUGO | S_IWUSR; | ||
| 2373 | hsc_handle->show = sony_nc_highspeed_charging_show; | ||
| 2374 | hsc_handle->store = sony_nc_highspeed_charging_store; | ||
| 2375 | |||
| 2376 | result = device_create_file(&pd->dev, hsc_handle); | ||
| 2377 | if (result) { | ||
| 2378 | kfree(hsc_handle); | ||
| 2379 | hsc_handle = NULL; | ||
| 2380 | return result; | ||
| 2381 | } | ||
| 2382 | |||
| 2383 | return 0; | ||
| 2384 | } | ||
| 2385 | |||
| 2386 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd) | ||
| 2387 | { | ||
| 2388 | if (hsc_handle) { | ||
| 2389 | device_remove_file(&pd->dev, hsc_handle); | ||
| 2390 | kfree(hsc_handle); | ||
| 2391 | hsc_handle = NULL; | ||
| 2392 | } | ||
| 2393 | } | ||
| 2394 | |||
| 2395 | /* Touchpad enable/disable */ | ||
| 2396 | struct touchpad_control { | ||
| 2397 | struct device_attribute attr; | ||
| 2398 | int handle; | ||
| 2399 | }; | ||
| 2400 | static struct touchpad_control *tp_ctl; | ||
| 2401 | |||
| 2402 | static ssize_t sony_nc_touchpad_store(struct device *dev, | ||
| 2403 | struct device_attribute *attr, const char *buffer, size_t count) | ||
| 2404 | { | ||
| 2405 | unsigned int result; | ||
| 2406 | unsigned long value; | ||
| 2407 | |||
| 2408 | if (count > 31) | ||
| 2409 | return -EINVAL; | ||
| 2410 | |||
| 2411 | if (kstrtoul(buffer, 10, &value) || value > 1) | ||
| 2412 | return -EINVAL; | ||
| 2413 | |||
| 2414 | /* sysfs: 0 disabled, 1 enabled | ||
| 2415 | * EC: 0 enabled, 1 disabled | ||
| 2416 | */ | ||
| 2417 | if (sony_call_snc_handle(tp_ctl->handle, | ||
| 2418 | (!value << 0x10) | 0x100, &result)) | ||
| 2419 | return -EIO; | ||
| 2420 | |||
| 2421 | return count; | ||
| 2422 | } | ||
| 2423 | |||
| 2424 | static ssize_t sony_nc_touchpad_show(struct device *dev, | ||
| 2425 | struct device_attribute *attr, char *buffer) | ||
| 2426 | { | ||
| 2427 | unsigned int result; | ||
| 2428 | |||
| 2429 | if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result)) | ||
| 2430 | return -EINVAL; | ||
| 2431 | |||
| 2432 | return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01)); | ||
| 2433 | } | ||
| 2434 | |||
| 2435 | static int sony_nc_touchpad_setup(struct platform_device *pd, | ||
| 2436 | unsigned int handle) | ||
| 2437 | { | ||
| 2438 | int ret = 0; | ||
| 2439 | |||
| 2440 | tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL); | ||
| 2441 | if (!tp_ctl) | ||
| 2442 | return -ENOMEM; | ||
| 2443 | |||
| 2444 | tp_ctl->handle = handle; | ||
| 2445 | |||
| 2446 | sysfs_attr_init(&tp_ctl->attr.attr); | ||
| 2447 | tp_ctl->attr.attr.name = "touchpad"; | ||
| 2448 | tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR; | ||
| 2449 | tp_ctl->attr.show = sony_nc_touchpad_show; | ||
| 2450 | tp_ctl->attr.store = sony_nc_touchpad_store; | ||
| 2451 | |||
| 2452 | ret = device_create_file(&pd->dev, &tp_ctl->attr); | ||
| 2453 | if (ret) { | ||
| 2454 | kfree(tp_ctl); | ||
| 2455 | tp_ctl = NULL; | ||
| 2456 | } | ||
| 2457 | |||
| 2458 | return ret; | ||
| 2459 | } | ||
| 2460 | |||
| 2461 | static void sony_nc_touchpad_cleanup(struct platform_device *pd) | ||
| 2462 | { | ||
| 2463 | if (tp_ctl) { | ||
| 2464 | device_remove_file(&pd->dev, &tp_ctl->attr); | ||
| 2465 | kfree(tp_ctl); | ||
| 2466 | tp_ctl = NULL; | ||
| 2467 | } | ||
| 1561 | } | 2468 | } |
| 1562 | 2469 | ||
| 1563 | static void sony_nc_backlight_ng_read_limits(int handle, | 2470 | static void sony_nc_backlight_ng_read_limits(int handle, |
| 1564 | struct sony_backlight_props *props) | 2471 | struct sony_backlight_props *props) |
| 1565 | { | 2472 | { |
| 1566 | int offset; | 2473 | u64 offset; |
| 1567 | acpi_status status; | 2474 | int i; |
| 1568 | u8 brlvl, i; | ||
| 1569 | u8 min = 0xff, max = 0x00; | 2475 | u8 min = 0xff, max = 0x00; |
| 1570 | struct acpi_object_list params; | 2476 | unsigned char buffer[32] = { 0 }; |
| 1571 | union acpi_object in_obj; | ||
| 1572 | union acpi_object *lvl_enum; | ||
| 1573 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1574 | 2477 | ||
| 1575 | props->handle = handle; | 2478 | props->handle = handle; |
| 1576 | props->offset = 0; | 2479 | props->offset = 0; |
| @@ -1583,50 +2486,31 @@ static void sony_nc_backlight_ng_read_limits(int handle, | |||
| 1583 | /* try to read the boundaries from ACPI tables, if we fail the above | 2486 | /* try to read the boundaries from ACPI tables, if we fail the above |
| 1584 | * defaults should be reasonable | 2487 | * defaults should be reasonable |
| 1585 | */ | 2488 | */ |
| 1586 | params.count = 1; | 2489 | i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer, |
| 1587 | params.pointer = &in_obj; | 2490 | 32); |
| 1588 | in_obj.type = ACPI_TYPE_INTEGER; | 2491 | if (i < 0) |
| 1589 | in_obj.integer.value = offset; | ||
| 1590 | status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, | ||
| 1591 | &buffer); | ||
| 1592 | if (ACPI_FAILURE(status)) | ||
| 1593 | return; | 2492 | return; |
| 1594 | 2493 | ||
| 1595 | lvl_enum = (union acpi_object *) buffer.pointer; | ||
| 1596 | if (!lvl_enum) { | ||
| 1597 | pr_err("No SN06 return object."); | ||
| 1598 | return; | ||
| 1599 | } | ||
| 1600 | if (lvl_enum->type != ACPI_TYPE_BUFFER) { | ||
| 1601 | pr_err("Invalid SN06 return object 0x%.2x\n", | ||
| 1602 | lvl_enum->type); | ||
| 1603 | goto out_invalid; | ||
| 1604 | } | ||
| 1605 | |||
| 1606 | /* the buffer lists brightness levels available, brightness levels are | 2494 | /* the buffer lists brightness levels available, brightness levels are |
| 1607 | * from 0 to 8 in the array, other values are used by ALS control. | 2495 | * from position 0 to 8 in the array, other values are used by ALS |
| 2496 | * control. | ||
| 1608 | */ | 2497 | */ |
| 1609 | for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { | 2498 | for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) { |
| 1610 | 2499 | ||
| 1611 | brlvl = *(lvl_enum->buffer.pointer + i); | 2500 | dprintk("Brightness level: %d\n", buffer[i]); |
| 1612 | dprintk("Brightness level: %d\n", brlvl); | ||
| 1613 | 2501 | ||
| 1614 | if (!brlvl) | 2502 | if (!buffer[i]) |
| 1615 | break; | 2503 | break; |
| 1616 | 2504 | ||
| 1617 | if (brlvl > max) | 2505 | if (buffer[i] > max) |
| 1618 | max = brlvl; | 2506 | max = buffer[i]; |
| 1619 | if (brlvl < min) | 2507 | if (buffer[i] < min) |
| 1620 | min = brlvl; | 2508 | min = buffer[i]; |
| 1621 | } | 2509 | } |
| 1622 | props->offset = min; | 2510 | props->offset = min; |
| 1623 | props->maxlvl = max; | 2511 | props->maxlvl = max; |
| 1624 | dprintk("Brightness levels: min=%d max=%d\n", props->offset, | 2512 | dprintk("Brightness levels: min=%d max=%d\n", props->offset, |
| 1625 | props->maxlvl); | 2513 | props->maxlvl); |
| 1626 | |||
| 1627 | out_invalid: | ||
| 1628 | kfree(buffer.pointer); | ||
| 1629 | return; | ||
| 1630 | } | 2514 | } |
| 1631 | 2515 | ||
| 1632 | static void sony_nc_backlight_setup(void) | 2516 | static void sony_nc_backlight_setup(void) |
| @@ -1715,28 +2599,25 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1715 | 2599 | ||
| 1716 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", | 2600 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", |
| 1717 | &handle))) { | 2601 | &handle))) { |
| 1718 | if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) | 2602 | int arg = 1; |
| 2603 | if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL)) | ||
| 1719 | dprintk("ECON Method failed\n"); | 2604 | dprintk("ECON Method failed\n"); |
| 1720 | } | 2605 | } |
| 1721 | 2606 | ||
| 1722 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", | 2607 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", |
| 1723 | &handle))) { | 2608 | &handle))) { |
| 1724 | dprintk("Doing SNC setup\n"); | 2609 | dprintk("Doing SNC setup\n"); |
| 2610 | /* retrieve the available handles */ | ||
| 1725 | result = sony_nc_handles_setup(sony_pf_device); | 2611 | result = sony_nc_handles_setup(sony_pf_device); |
| 1726 | if (result) | 2612 | if (!result) |
| 1727 | goto outpresent; | 2613 | sony_nc_function_setup(device, sony_pf_device); |
| 1728 | result = sony_nc_kbd_backlight_setup(sony_pf_device); | ||
| 1729 | if (result) | ||
| 1730 | goto outsnc; | ||
| 1731 | sony_nc_function_setup(device); | ||
| 1732 | sony_nc_rfkill_setup(device); | ||
| 1733 | } | 2614 | } |
| 1734 | 2615 | ||
| 1735 | /* setup input devices and helper fifo */ | 2616 | /* setup input devices and helper fifo */ |
| 1736 | result = sony_laptop_setup_input(device); | 2617 | result = sony_laptop_setup_input(device); |
| 1737 | if (result) { | 2618 | if (result) { |
| 1738 | pr_err("Unable to create input devices\n"); | 2619 | pr_err("Unable to create input devices\n"); |
| 1739 | goto outkbdbacklight; | 2620 | goto outsnc; |
| 1740 | } | 2621 | } |
| 1741 | 2622 | ||
| 1742 | if (acpi_video_backlight_support()) { | 2623 | if (acpi_video_backlight_support()) { |
| @@ -1794,10 +2675,8 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1794 | 2675 | ||
| 1795 | sony_laptop_remove_input(); | 2676 | sony_laptop_remove_input(); |
| 1796 | 2677 | ||
| 1797 | outkbdbacklight: | ||
| 1798 | sony_nc_kbd_backlight_cleanup(sony_pf_device); | ||
| 1799 | |||
| 1800 | outsnc: | 2678 | outsnc: |
| 2679 | sony_nc_function_cleanup(sony_pf_device); | ||
| 1801 | sony_nc_handles_cleanup(sony_pf_device); | 2680 | sony_nc_handles_cleanup(sony_pf_device); |
| 1802 | 2681 | ||
| 1803 | outpresent: | 2682 | outpresent: |
| @@ -1820,11 +2699,10 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
| 1820 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 2699 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
| 1821 | } | 2700 | } |
| 1822 | 2701 | ||
| 1823 | sony_nc_kbd_backlight_cleanup(sony_pf_device); | 2702 | sony_nc_function_cleanup(sony_pf_device); |
| 1824 | sony_nc_handles_cleanup(sony_pf_device); | 2703 | sony_nc_handles_cleanup(sony_pf_device); |
| 1825 | sony_pf_remove(); | 2704 | sony_pf_remove(); |
| 1826 | sony_laptop_remove_input(); | 2705 | sony_laptop_remove_input(); |
| 1827 | sony_nc_rfkill_cleanup(); | ||
| 1828 | dprintk(SONY_NC_DRIVER_NAME " removed.\n"); | 2706 | dprintk(SONY_NC_DRIVER_NAME " removed.\n"); |
| 1829 | 2707 | ||
| 1830 | return 0; | 2708 | return 0; |
| @@ -2437,7 +3315,9 @@ static ssize_t sony_pic_wwanpower_store(struct device *dev, | |||
| 2437 | if (count > 31) | 3315 | if (count > 31) |
| 2438 | return -EINVAL; | 3316 | return -EINVAL; |
| 2439 | 3317 | ||
| 2440 | value = simple_strtoul(buffer, NULL, 10); | 3318 | if (kstrtoul(buffer, 10, &value)) |
| 3319 | return -EINVAL; | ||
| 3320 | |||
| 2441 | mutex_lock(&spic_dev.lock); | 3321 | mutex_lock(&spic_dev.lock); |
| 2442 | __sony_pic_set_wwanpower(value); | 3322 | __sony_pic_set_wwanpower(value); |
| 2443 | mutex_unlock(&spic_dev.lock); | 3323 | mutex_unlock(&spic_dev.lock); |
| @@ -2474,7 +3354,9 @@ static ssize_t sony_pic_bluetoothpower_store(struct device *dev, | |||
| 2474 | if (count > 31) | 3354 | if (count > 31) |
| 2475 | return -EINVAL; | 3355 | return -EINVAL; |
| 2476 | 3356 | ||
| 2477 | value = simple_strtoul(buffer, NULL, 10); | 3357 | if (kstrtoul(buffer, 10, &value)) |
| 3358 | return -EINVAL; | ||
| 3359 | |||
| 2478 | mutex_lock(&spic_dev.lock); | 3360 | mutex_lock(&spic_dev.lock); |
| 2479 | __sony_pic_set_bluetoothpower(value); | 3361 | __sony_pic_set_bluetoothpower(value); |
| 2480 | mutex_unlock(&spic_dev.lock); | 3362 | mutex_unlock(&spic_dev.lock); |
| @@ -2513,7 +3395,9 @@ static ssize_t sony_pic_fanspeed_store(struct device *dev, | |||
| 2513 | if (count > 31) | 3395 | if (count > 31) |
| 2514 | return -EINVAL; | 3396 | return -EINVAL; |
| 2515 | 3397 | ||
| 2516 | value = simple_strtoul(buffer, NULL, 10); | 3398 | if (kstrtoul(buffer, 10, &value)) |
| 3399 | return -EINVAL; | ||
| 3400 | |||
| 2517 | if (sony_pic_set_fanspeed(value)) | 3401 | if (sony_pic_set_fanspeed(value)) |
| 2518 | return -EIO; | 3402 | return -EIO; |
| 2519 | 3403 | ||
| @@ -2671,7 +3555,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
| 2671 | ret = -EIO; | 3555 | ret = -EIO; |
| 2672 | break; | 3556 | break; |
| 2673 | } | 3557 | } |
| 2674 | if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { | 3558 | if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, |
| 3559 | &value)) { | ||
| 2675 | ret = -EIO; | 3560 | ret = -EIO; |
| 2676 | break; | 3561 | break; |
| 2677 | } | 3562 | } |
| @@ -2688,8 +3573,9 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
| 2688 | ret = -EFAULT; | 3573 | ret = -EFAULT; |
| 2689 | break; | 3574 | break; |
| 2690 | } | 3575 | } |
| 2691 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", | 3576 | value = (val8 >> 5) + 1; |
| 2692 | (val8 >> 5) + 1, NULL)) { | 3577 | if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value, |
| 3578 | NULL)) { | ||
| 2693 | ret = -EIO; | 3579 | ret = -EIO; |
| 2694 | break; | 3580 | break; |
| 2695 | } | 3581 | } |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d68c0002f4a2..8b5610d88418 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -3402,7 +3402,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3402 | /* Do not issue duplicate brightness change events to | 3402 | /* Do not issue duplicate brightness change events to |
| 3403 | * userspace. tpacpi_detect_brightness_capabilities() must have | 3403 | * userspace. tpacpi_detect_brightness_capabilities() must have |
| 3404 | * been called before this point */ | 3404 | * been called before this point */ |
| 3405 | if (tp_features.bright_acpimode && acpi_video_backlight_support()) { | 3405 | if (acpi_video_backlight_support()) { |
| 3406 | pr_info("This ThinkPad has standard ACPI backlight " | 3406 | pr_info("This ThinkPad has standard ACPI backlight " |
| 3407 | "brightness control, supported by the ACPI " | 3407 | "brightness control, supported by the ACPI " |
| 3408 | "video driver\n"); | 3408 | "video driver\n"); |
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 57787d87d9a4..dab10f6edcd4 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
| @@ -95,6 +95,7 @@ MODULE_LICENSE("GPL"); | |||
| 95 | 95 | ||
| 96 | /* registers */ | 96 | /* registers */ |
| 97 | #define HCI_FAN 0x0004 | 97 | #define HCI_FAN 0x0004 |
| 98 | #define HCI_TR_BACKLIGHT 0x0005 | ||
| 98 | #define HCI_SYSTEM_EVENT 0x0016 | 99 | #define HCI_SYSTEM_EVENT 0x0016 |
| 99 | #define HCI_VIDEO_OUT 0x001c | 100 | #define HCI_VIDEO_OUT 0x001c |
| 100 | #define HCI_HOTKEY_EVENT 0x001e | 101 | #define HCI_HOTKEY_EVENT 0x001e |
| @@ -134,6 +135,7 @@ struct toshiba_acpi_dev { | |||
| 134 | unsigned int system_event_supported:1; | 135 | unsigned int system_event_supported:1; |
| 135 | unsigned int ntfy_supported:1; | 136 | unsigned int ntfy_supported:1; |
| 136 | unsigned int info_supported:1; | 137 | unsigned int info_supported:1; |
| 138 | unsigned int tr_backlight_supported:1; | ||
| 137 | 139 | ||
| 138 | struct mutex mutex; | 140 | struct mutex mutex; |
| 139 | }; | 141 | }; |
| @@ -478,34 +480,70 @@ static const struct rfkill_ops toshiba_rfk_ops = { | |||
| 478 | .poll = bt_rfkill_poll, | 480 | .poll = bt_rfkill_poll, |
| 479 | }; | 481 | }; |
| 480 | 482 | ||
| 483 | static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) | ||
| 484 | { | ||
| 485 | u32 hci_result; | ||
| 486 | u32 status; | ||
| 487 | |||
| 488 | hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result); | ||
| 489 | *enabled = !status; | ||
| 490 | return hci_result == HCI_SUCCESS ? 0 : -EIO; | ||
| 491 | } | ||
| 492 | |||
| 493 | static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) | ||
| 494 | { | ||
| 495 | u32 hci_result; | ||
| 496 | u32 value = !enable; | ||
| 497 | |||
| 498 | hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result); | ||
| 499 | return hci_result == HCI_SUCCESS ? 0 : -EIO; | ||
| 500 | } | ||
| 501 | |||
| 481 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; | 502 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; |
| 482 | 503 | ||
| 483 | static int get_lcd(struct backlight_device *bd) | 504 | static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) |
| 484 | { | 505 | { |
| 485 | struct toshiba_acpi_dev *dev = bl_get_data(bd); | ||
| 486 | u32 hci_result; | 506 | u32 hci_result; |
| 487 | u32 value; | 507 | u32 value; |
| 508 | int brightness = 0; | ||
| 509 | |||
| 510 | if (dev->tr_backlight_supported) { | ||
| 511 | bool enabled; | ||
| 512 | int ret = get_tr_backlight_status(dev, &enabled); | ||
| 513 | if (ret) | ||
| 514 | return ret; | ||
| 515 | if (enabled) | ||
| 516 | return 0; | ||
| 517 | brightness++; | ||
| 518 | } | ||
| 488 | 519 | ||
| 489 | hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); | 520 | hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); |
| 490 | if (hci_result == HCI_SUCCESS) | 521 | if (hci_result == HCI_SUCCESS) |
| 491 | return (value >> HCI_LCD_BRIGHTNESS_SHIFT); | 522 | return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); |
| 492 | 523 | ||
| 493 | return -EIO; | 524 | return -EIO; |
| 494 | } | 525 | } |
| 495 | 526 | ||
| 527 | static int get_lcd_brightness(struct backlight_device *bd) | ||
| 528 | { | ||
| 529 | struct toshiba_acpi_dev *dev = bl_get_data(bd); | ||
| 530 | return __get_lcd_brightness(dev); | ||
| 531 | } | ||
| 532 | |||
| 496 | static int lcd_proc_show(struct seq_file *m, void *v) | 533 | static int lcd_proc_show(struct seq_file *m, void *v) |
| 497 | { | 534 | { |
| 498 | struct toshiba_acpi_dev *dev = m->private; | 535 | struct toshiba_acpi_dev *dev = m->private; |
| 499 | int value; | 536 | int value; |
| 537 | int levels; | ||
| 500 | 538 | ||
| 501 | if (!dev->backlight_dev) | 539 | if (!dev->backlight_dev) |
| 502 | return -ENODEV; | 540 | return -ENODEV; |
| 503 | 541 | ||
| 504 | value = get_lcd(dev->backlight_dev); | 542 | levels = dev->backlight_dev->props.max_brightness + 1; |
| 543 | value = get_lcd_brightness(dev->backlight_dev); | ||
| 505 | if (value >= 0) { | 544 | if (value >= 0) { |
| 506 | seq_printf(m, "brightness: %d\n", value); | 545 | seq_printf(m, "brightness: %d\n", value); |
| 507 | seq_printf(m, "brightness_levels: %d\n", | 546 | seq_printf(m, "brightness_levels: %d\n", levels); |
| 508 | HCI_LCD_BRIGHTNESS_LEVELS); | ||
| 509 | return 0; | 547 | return 0; |
| 510 | } | 548 | } |
| 511 | 549 | ||
| @@ -518,10 +556,19 @@ static int lcd_proc_open(struct inode *inode, struct file *file) | |||
| 518 | return single_open(file, lcd_proc_show, PDE(inode)->data); | 556 | return single_open(file, lcd_proc_show, PDE(inode)->data); |
| 519 | } | 557 | } |
| 520 | 558 | ||
| 521 | static int set_lcd(struct toshiba_acpi_dev *dev, int value) | 559 | static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) |
| 522 | { | 560 | { |
| 523 | u32 hci_result; | 561 | u32 hci_result; |
| 524 | 562 | ||
| 563 | if (dev->tr_backlight_supported) { | ||
| 564 | bool enable = !value; | ||
| 565 | int ret = set_tr_backlight_status(dev, enable); | ||
| 566 | if (ret) | ||
| 567 | return ret; | ||
| 568 | if (value) | ||
| 569 | value--; | ||
| 570 | } | ||
| 571 | |||
| 525 | value = value << HCI_LCD_BRIGHTNESS_SHIFT; | 572 | value = value << HCI_LCD_BRIGHTNESS_SHIFT; |
| 526 | hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); | 573 | hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); |
| 527 | return hci_result == HCI_SUCCESS ? 0 : -EIO; | 574 | return hci_result == HCI_SUCCESS ? 0 : -EIO; |
| @@ -530,7 +577,7 @@ static int set_lcd(struct toshiba_acpi_dev *dev, int value) | |||
| 530 | static int set_lcd_status(struct backlight_device *bd) | 577 | static int set_lcd_status(struct backlight_device *bd) |
| 531 | { | 578 | { |
| 532 | struct toshiba_acpi_dev *dev = bl_get_data(bd); | 579 | struct toshiba_acpi_dev *dev = bl_get_data(bd); |
| 533 | return set_lcd(dev, bd->props.brightness); | 580 | return set_lcd_brightness(dev, bd->props.brightness); |
| 534 | } | 581 | } |
| 535 | 582 | ||
| 536 | static ssize_t lcd_proc_write(struct file *file, const char __user *buf, | 583 | static ssize_t lcd_proc_write(struct file *file, const char __user *buf, |
| @@ -541,6 +588,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, | |||
| 541 | size_t len; | 588 | size_t len; |
| 542 | int value; | 589 | int value; |
| 543 | int ret; | 590 | int ret; |
| 591 | int levels = dev->backlight_dev->props.max_brightness + 1; | ||
| 544 | 592 | ||
| 545 | len = min(count, sizeof(cmd) - 1); | 593 | len = min(count, sizeof(cmd) - 1); |
| 546 | if (copy_from_user(cmd, buf, len)) | 594 | if (copy_from_user(cmd, buf, len)) |
| @@ -548,8 +596,8 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, | |||
| 548 | cmd[len] = '\0'; | 596 | cmd[len] = '\0'; |
| 549 | 597 | ||
| 550 | if (sscanf(cmd, " brightness : %i", &value) == 1 && | 598 | if (sscanf(cmd, " brightness : %i", &value) == 1 && |
| 551 | value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { | 599 | value >= 0 && value < levels) { |
| 552 | ret = set_lcd(dev, value); | 600 | ret = set_lcd_brightness(dev, value); |
| 553 | if (ret == 0) | 601 | if (ret == 0) |
| 554 | ret = count; | 602 | ret = count; |
| 555 | } else { | 603 | } else { |
| @@ -860,8 +908,9 @@ static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) | |||
| 860 | } | 908 | } |
| 861 | 909 | ||
| 862 | static const struct backlight_ops toshiba_backlight_data = { | 910 | static const struct backlight_ops toshiba_backlight_data = { |
| 863 | .get_brightness = get_lcd, | 911 | .options = BL_CORE_SUSPENDRESUME, |
| 864 | .update_status = set_lcd_status, | 912 | .get_brightness = get_lcd_brightness, |
| 913 | .update_status = set_lcd_status, | ||
| 865 | }; | 914 | }; |
| 866 | 915 | ||
| 867 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, | 916 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, |
| @@ -1020,6 +1069,56 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
| 1020 | return error; | 1069 | return error; |
| 1021 | } | 1070 | } |
| 1022 | 1071 | ||
| 1072 | static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) | ||
| 1073 | { | ||
| 1074 | struct backlight_properties props; | ||
| 1075 | int brightness; | ||
| 1076 | int ret; | ||
| 1077 | bool enabled; | ||
| 1078 | |||
| 1079 | /* | ||
| 1080 | * Some machines don't support the backlight methods at all, and | ||
| 1081 | * others support it read-only. Either of these is pretty useless, | ||
| 1082 | * so only register the backlight device if the backlight method | ||
| 1083 | * supports both reads and writes. | ||
| 1084 | */ | ||
| 1085 | brightness = __get_lcd_brightness(dev); | ||
| 1086 | if (brightness < 0) | ||
| 1087 | return 0; | ||
| 1088 | ret = set_lcd_brightness(dev, brightness); | ||
| 1089 | if (ret) { | ||
| 1090 | pr_debug("Backlight method is read-only, disabling backlight support\n"); | ||
| 1091 | return 0; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | /* Determine whether or not BIOS supports transflective backlight */ | ||
| 1095 | ret = get_tr_backlight_status(dev, &enabled); | ||
| 1096 | dev->tr_backlight_supported = !ret; | ||
| 1097 | |||
| 1098 | memset(&props, 0, sizeof(props)); | ||
| 1099 | props.type = BACKLIGHT_PLATFORM; | ||
| 1100 | props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; | ||
| 1101 | |||
| 1102 | /* adding an extra level and having 0 change to transflective mode */ | ||
| 1103 | if (dev->tr_backlight_supported) | ||
| 1104 | props.max_brightness++; | ||
| 1105 | |||
| 1106 | dev->backlight_dev = backlight_device_register("toshiba", | ||
| 1107 | &dev->acpi_dev->dev, | ||
| 1108 | dev, | ||
| 1109 | &toshiba_backlight_data, | ||
| 1110 | &props); | ||
| 1111 | if (IS_ERR(dev->backlight_dev)) { | ||
| 1112 | ret = PTR_ERR(dev->backlight_dev); | ||
| 1113 | pr_err("Could not register toshiba backlight device\n"); | ||
| 1114 | dev->backlight_dev = NULL; | ||
| 1115 | return ret; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | dev->backlight_dev->props.brightness = brightness; | ||
| 1119 | return 0; | ||
| 1120 | } | ||
| 1121 | |||
| 1023 | static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) | 1122 | static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) |
| 1024 | { | 1123 | { |
| 1025 | struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); | 1124 | struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); |
| @@ -1078,7 +1177,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
| 1078 | u32 dummy; | 1177 | u32 dummy; |
| 1079 | bool bt_present; | 1178 | bool bt_present; |
| 1080 | int ret = 0; | 1179 | int ret = 0; |
| 1081 | struct backlight_properties props; | ||
| 1082 | 1180 | ||
| 1083 | if (toshiba_acpi) | 1181 | if (toshiba_acpi) |
| 1084 | return -EBUSY; | 1182 | return -EBUSY; |
| @@ -1104,22 +1202,9 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
| 1104 | 1202 | ||
| 1105 | mutex_init(&dev->mutex); | 1203 | mutex_init(&dev->mutex); |
| 1106 | 1204 | ||
| 1107 | memset(&props, 0, sizeof(props)); | 1205 | ret = toshiba_acpi_setup_backlight(dev); |
| 1108 | props.type = BACKLIGHT_PLATFORM; | 1206 | if (ret) |
| 1109 | props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; | ||
| 1110 | dev->backlight_dev = backlight_device_register("toshiba", | ||
| 1111 | &acpi_dev->dev, | ||
| 1112 | dev, | ||
| 1113 | &toshiba_backlight_data, | ||
| 1114 | &props); | ||
| 1115 | if (IS_ERR(dev->backlight_dev)) { | ||
| 1116 | ret = PTR_ERR(dev->backlight_dev); | ||
| 1117 | |||
| 1118 | pr_err("Could not register toshiba backlight device\n"); | ||
| 1119 | dev->backlight_dev = NULL; | ||
| 1120 | goto error; | 1207 | goto error; |
| 1121 | } | ||
| 1122 | dev->backlight_dev->props.brightness = get_lcd(dev->backlight_dev); | ||
| 1123 | 1208 | ||
| 1124 | /* Register rfkill switch for Bluetooth */ | 1209 | /* Register rfkill switch for Bluetooth */ |
| 1125 | if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) { | 1210 | if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) { |
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c index 41781ed8301c..b57ad8641480 100644 --- a/drivers/platform/x86/xo1-rfkill.c +++ b/drivers/platform/x86/xo1-rfkill.c | |||
| @@ -15,15 +15,26 @@ | |||
| 15 | 15 | ||
| 16 | #include <asm/olpc.h> | 16 | #include <asm/olpc.h> |
| 17 | 17 | ||
| 18 | static bool card_blocked; | ||
| 19 | |||
| 18 | static int rfkill_set_block(void *data, bool blocked) | 20 | static int rfkill_set_block(void *data, bool blocked) |
| 19 | { | 21 | { |
| 20 | unsigned char cmd; | 22 | unsigned char cmd; |
| 23 | int r; | ||
| 24 | |||
| 25 | if (blocked == card_blocked) | ||
| 26 | return 0; | ||
| 27 | |||
| 21 | if (blocked) | 28 | if (blocked) |
| 22 | cmd = EC_WLAN_ENTER_RESET; | 29 | cmd = EC_WLAN_ENTER_RESET; |
| 23 | else | 30 | else |
| 24 | cmd = EC_WLAN_LEAVE_RESET; | 31 | cmd = EC_WLAN_LEAVE_RESET; |
| 25 | 32 | ||
| 26 | return olpc_ec_cmd(cmd, NULL, 0, NULL, 0); | 33 | r = olpc_ec_cmd(cmd, NULL, 0, NULL, 0); |
| 34 | if (r == 0) | ||
| 35 | card_blocked = blocked; | ||
| 36 | |||
| 37 | return r; | ||
| 27 | } | 38 | } |
| 28 | 39 | ||
| 29 | static const struct rfkill_ops rfkill_ops = { | 40 | static const struct rfkill_ops rfkill_ops = { |
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig index bc8719238793..6194d35ebb97 100644 --- a/drivers/rapidio/Kconfig +++ b/drivers/rapidio/Kconfig | |||
| @@ -22,6 +22,20 @@ config RAPIDIO_ENABLE_RX_TX_PORTS | |||
| 22 | ports for Input/Output direction to allow other traffic | 22 | ports for Input/Output direction to allow other traffic |
| 23 | than Maintenance transfers. | 23 | than Maintenance transfers. |
| 24 | 24 | ||
| 25 | config RAPIDIO_DMA_ENGINE | ||
| 26 | bool "DMA Engine support for RapidIO" | ||
| 27 | depends on RAPIDIO | ||
| 28 | select DMADEVICES | ||
| 29 | select DMA_ENGINE | ||
| 30 | help | ||
| 31 | Say Y here if you want to use DMA Engine frameork for RapidIO data | ||
| 32 | transfers to/from target RIO devices. RapidIO uses NREAD and | ||
| 33 | NWRITE (NWRITE_R, SWRITE) requests to transfer data between local | ||
| 34 | memory and memory on remote target device. You need a DMA controller | ||
| 35 | capable to perform data transfers to/from RapidIO. | ||
| 36 | |||
| 37 | If you are unsure about this, say Y here. | ||
| 38 | |||
| 25 | config RAPIDIO_DEBUG | 39 | config RAPIDIO_DEBUG |
| 26 | bool "RapidIO subsystem debug messages" | 40 | bool "RapidIO subsystem debug messages" |
| 27 | depends on RAPIDIO | 41 | depends on RAPIDIO |
diff --git a/drivers/rapidio/devices/Makefile b/drivers/rapidio/devices/Makefile index 3b7b4e2dff7c..7b62860f34f8 100644 --- a/drivers/rapidio/devices/Makefile +++ b/drivers/rapidio/devices/Makefile | |||
| @@ -3,3 +3,6 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_RAPIDIO_TSI721) += tsi721.o | 5 | obj-$(CONFIG_RAPIDIO_TSI721) += tsi721.o |
| 6 | ifeq ($(CONFIG_RAPIDIO_DMA_ENGINE),y) | ||
| 7 | obj-$(CONFIG_RAPIDIO_TSI721) += tsi721_dma.o | ||
| 8 | endif | ||
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 30d2072f480b..722246cf20ab 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c | |||
| @@ -108,6 +108,7 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, | |||
| 108 | u16 destid, u8 hopcount, u32 offset, int len, | 108 | u16 destid, u8 hopcount, u32 offset, int len, |
| 109 | u32 *data, int do_wr) | 109 | u32 *data, int do_wr) |
| 110 | { | 110 | { |
| 111 | void __iomem *regs = priv->regs + TSI721_DMAC_BASE(priv->mdma.ch_id); | ||
| 111 | struct tsi721_dma_desc *bd_ptr; | 112 | struct tsi721_dma_desc *bd_ptr; |
| 112 | u32 rd_count, swr_ptr, ch_stat; | 113 | u32 rd_count, swr_ptr, ch_stat; |
| 113 | int i, err = 0; | 114 | int i, err = 0; |
| @@ -116,10 +117,9 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, | |||
| 116 | if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32))) | 117 | if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32))) |
| 117 | return -EINVAL; | 118 | return -EINVAL; |
| 118 | 119 | ||
| 119 | bd_ptr = priv->bdma[TSI721_DMACH_MAINT].bd_base; | 120 | bd_ptr = priv->mdma.bd_base; |
| 120 | 121 | ||
| 121 | rd_count = ioread32( | 122 | rd_count = ioread32(regs + TSI721_DMAC_DRDCNT); |
| 122 | priv->regs + TSI721_DMAC_DRDCNT(TSI721_DMACH_MAINT)); | ||
| 123 | 123 | ||
| 124 | /* Initialize DMA descriptor */ | 124 | /* Initialize DMA descriptor */ |
| 125 | bd_ptr[0].type_id = cpu_to_le32((DTYPE2 << 29) | (op << 19) | destid); | 125 | bd_ptr[0].type_id = cpu_to_le32((DTYPE2 << 29) | (op << 19) | destid); |
| @@ -134,19 +134,18 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, | |||
| 134 | mb(); | 134 | mb(); |
| 135 | 135 | ||
| 136 | /* Start DMA operation */ | 136 | /* Start DMA operation */ |
| 137 | iowrite32(rd_count + 2, | 137 | iowrite32(rd_count + 2, regs + TSI721_DMAC_DWRCNT); |
| 138 | priv->regs + TSI721_DMAC_DWRCNT(TSI721_DMACH_MAINT)); | 138 | ioread32(regs + TSI721_DMAC_DWRCNT); |
| 139 | ioread32(priv->regs + TSI721_DMAC_DWRCNT(TSI721_DMACH_MAINT)); | ||
| 140 | i = 0; | 139 | i = 0; |
| 141 | 140 | ||
| 142 | /* Wait until DMA transfer is finished */ | 141 | /* Wait until DMA transfer is finished */ |
| 143 | while ((ch_stat = ioread32(priv->regs + | 142 | while ((ch_stat = ioread32(regs + TSI721_DMAC_STS)) |
| 144 | TSI721_DMAC_STS(TSI721_DMACH_MAINT))) & TSI721_DMAC_STS_RUN) { | 143 | & TSI721_DMAC_STS_RUN) { |
| 145 | udelay(1); | 144 | udelay(1); |
| 146 | if (++i >= 5000000) { | 145 | if (++i >= 5000000) { |
| 147 | dev_dbg(&priv->pdev->dev, | 146 | dev_dbg(&priv->pdev->dev, |
| 148 | "%s : DMA[%d] read timeout ch_status=%x\n", | 147 | "%s : DMA[%d] read timeout ch_status=%x\n", |
| 149 | __func__, TSI721_DMACH_MAINT, ch_stat); | 148 | __func__, priv->mdma.ch_id, ch_stat); |
| 150 | if (!do_wr) | 149 | if (!do_wr) |
| 151 | *data = 0xffffffff; | 150 | *data = 0xffffffff; |
| 152 | err = -EIO; | 151 | err = -EIO; |
| @@ -162,13 +161,10 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, | |||
| 162 | __func__, ch_stat); | 161 | __func__, ch_stat); |
| 163 | dev_dbg(&priv->pdev->dev, "OP=%d : destid=%x hc=%x off=%x\n", | 162 | dev_dbg(&priv->pdev->dev, "OP=%d : destid=%x hc=%x off=%x\n", |
| 164 | do_wr ? MAINT_WR : MAINT_RD, destid, hopcount, offset); | 163 | do_wr ? MAINT_WR : MAINT_RD, destid, hopcount, offset); |
| 165 | iowrite32(TSI721_DMAC_INT_ALL, | 164 | iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT); |
| 166 | priv->regs + TSI721_DMAC_INT(TSI721_DMACH_MAINT)); | 165 | iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); |
| 167 | iowrite32(TSI721_DMAC_CTL_INIT, | ||
| 168 | priv->regs + TSI721_DMAC_CTL(TSI721_DMACH_MAINT)); | ||
| 169 | udelay(10); | 166 | udelay(10); |
| 170 | iowrite32(0, priv->regs + | 167 | iowrite32(0, regs + TSI721_DMAC_DWRCNT); |
| 171 | TSI721_DMAC_DWRCNT(TSI721_DMACH_MAINT)); | ||
| 172 | udelay(1); | 168 | udelay(1); |
| 173 | if (!do_wr) | 169 | if (!do_wr) |
| 174 | *data = 0xffffffff; | 170 | *data = 0xffffffff; |
| @@ -184,8 +180,8 @@ static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, | |||
| 184 | * NOTE: Skipping check and clear FIFO entries because we are waiting | 180 | * NOTE: Skipping check and clear FIFO entries because we are waiting |
| 185 | * for transfer to be completed. | 181 | * for transfer to be completed. |
| 186 | */ | 182 | */ |
| 187 | swr_ptr = ioread32(priv->regs + TSI721_DMAC_DSWP(TSI721_DMACH_MAINT)); | 183 | swr_ptr = ioread32(regs + TSI721_DMAC_DSWP); |
| 188 | iowrite32(swr_ptr, priv->regs + TSI721_DMAC_DSRP(TSI721_DMACH_MAINT)); | 184 | iowrite32(swr_ptr, regs + TSI721_DMAC_DSRP); |
| 189 | err_out: | 185 | err_out: |
| 190 | 186 | ||
| 191 | return err; | 187 | return err; |
| @@ -541,6 +537,22 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr) | |||
| 541 | tsi721_pw_handler(mport); | 537 | tsi721_pw_handler(mport); |
| 542 | } | 538 | } |
| 543 | 539 | ||
| 540 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 541 | if (dev_int & TSI721_DEV_INT_BDMA_CH) { | ||
| 542 | int ch; | ||
| 543 | |||
| 544 | if (dev_ch_int & TSI721_INT_BDMA_CHAN_M) { | ||
| 545 | dev_dbg(&priv->pdev->dev, | ||
| 546 | "IRQ from DMA channel 0x%08x\n", dev_ch_int); | ||
| 547 | |||
| 548 | for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) { | ||
| 549 | if (!(dev_ch_int & TSI721_INT_BDMA_CHAN(ch))) | ||
| 550 | continue; | ||
| 551 | tsi721_bdma_handler(&priv->bdma[ch]); | ||
| 552 | } | ||
| 553 | } | ||
| 554 | } | ||
| 555 | #endif | ||
| 544 | return IRQ_HANDLED; | 556 | return IRQ_HANDLED; |
| 545 | } | 557 | } |
| 546 | 558 | ||
| @@ -553,18 +565,26 @@ static void tsi721_interrupts_init(struct tsi721_device *priv) | |||
| 553 | priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); | 565 | priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); |
| 554 | iowrite32(TSI721_SR_CHINT_IDBQRCV, | 566 | iowrite32(TSI721_SR_CHINT_IDBQRCV, |
| 555 | priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); | 567 | priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); |
| 556 | iowrite32(TSI721_INT_SR2PC_CHAN(IDB_QUEUE), | ||
| 557 | priv->regs + TSI721_DEV_CHAN_INTE); | ||
| 558 | 568 | ||
| 559 | /* Enable SRIO MAC interrupts */ | 569 | /* Enable SRIO MAC interrupts */ |
| 560 | iowrite32(TSI721_RIO_EM_DEV_INT_EN_INT, | 570 | iowrite32(TSI721_RIO_EM_DEV_INT_EN_INT, |
| 561 | priv->regs + TSI721_RIO_EM_DEV_INT_EN); | 571 | priv->regs + TSI721_RIO_EM_DEV_INT_EN); |
| 562 | 572 | ||
| 573 | /* Enable interrupts from channels in use */ | ||
| 574 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 575 | intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE) | | ||
| 576 | (TSI721_INT_BDMA_CHAN_M & | ||
| 577 | ~TSI721_INT_BDMA_CHAN(TSI721_DMACH_MAINT)); | ||
| 578 | #else | ||
| 579 | intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE); | ||
| 580 | #endif | ||
| 581 | iowrite32(intr, priv->regs + TSI721_DEV_CHAN_INTE); | ||
| 582 | |||
| 563 | if (priv->flags & TSI721_USING_MSIX) | 583 | if (priv->flags & TSI721_USING_MSIX) |
| 564 | intr = TSI721_DEV_INT_SRIO; | 584 | intr = TSI721_DEV_INT_SRIO; |
| 565 | else | 585 | else |
| 566 | intr = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | | 586 | intr = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | |
| 567 | TSI721_DEV_INT_SMSG_CH; | 587 | TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH; |
| 568 | 588 | ||
| 569 | iowrite32(intr, priv->regs + TSI721_DEV_INTE); | 589 | iowrite32(intr, priv->regs + TSI721_DEV_INTE); |
| 570 | ioread32(priv->regs + TSI721_DEV_INTE); | 590 | ioread32(priv->regs + TSI721_DEV_INTE); |
| @@ -715,12 +735,29 @@ static int tsi721_enable_msix(struct tsi721_device *priv) | |||
| 715 | TSI721_MSIX_OMSG_INT(i); | 735 | TSI721_MSIX_OMSG_INT(i); |
| 716 | } | 736 | } |
| 717 | 737 | ||
| 738 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 739 | /* | ||
| 740 | * Initialize MSI-X entries for Block DMA Engine: | ||
| 741 | * this driver supports XXX DMA channels | ||
| 742 | * (one is reserved for SRIO maintenance transactions) | ||
| 743 | */ | ||
| 744 | for (i = 0; i < TSI721_DMA_CHNUM; i++) { | ||
| 745 | entries[TSI721_VECT_DMA0_DONE + i].entry = | ||
| 746 | TSI721_MSIX_DMACH_DONE(i); | ||
| 747 | entries[TSI721_VECT_DMA0_INT + i].entry = | ||
| 748 | TSI721_MSIX_DMACH_INT(i); | ||
| 749 | } | ||
| 750 | #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ | ||
| 751 | |||
| 718 | err = pci_enable_msix(priv->pdev, entries, ARRAY_SIZE(entries)); | 752 | err = pci_enable_msix(priv->pdev, entries, ARRAY_SIZE(entries)); |
| 719 | if (err) { | 753 | if (err) { |
| 720 | if (err > 0) | 754 | if (err > 0) |
| 721 | dev_info(&priv->pdev->dev, | 755 | dev_info(&priv->pdev->dev, |
| 722 | "Only %d MSI-X vectors available, " | 756 | "Only %d MSI-X vectors available, " |
| 723 | "not using MSI-X\n", err); | 757 | "not using MSI-X\n", err); |
| 758 | else | ||
| 759 | dev_err(&priv->pdev->dev, | ||
| 760 | "Failed to enable MSI-X (err=%d)\n", err); | ||
| 724 | return err; | 761 | return err; |
| 725 | } | 762 | } |
| 726 | 763 | ||
| @@ -760,6 +797,22 @@ static int tsi721_enable_msix(struct tsi721_device *priv) | |||
| 760 | i, pci_name(priv->pdev)); | 797 | i, pci_name(priv->pdev)); |
| 761 | } | 798 | } |
| 762 | 799 | ||
| 800 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 801 | for (i = 0; i < TSI721_DMA_CHNUM; i++) { | ||
| 802 | priv->msix[TSI721_VECT_DMA0_DONE + i].vector = | ||
| 803 | entries[TSI721_VECT_DMA0_DONE + i].vector; | ||
| 804 | snprintf(priv->msix[TSI721_VECT_DMA0_DONE + i].irq_name, | ||
| 805 | IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmad%d@pci:%s", | ||
| 806 | i, pci_name(priv->pdev)); | ||
| 807 | |||
| 808 | priv->msix[TSI721_VECT_DMA0_INT + i].vector = | ||
| 809 | entries[TSI721_VECT_DMA0_INT + i].vector; | ||
| 810 | snprintf(priv->msix[TSI721_VECT_DMA0_INT + i].irq_name, | ||
| 811 | IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmai%d@pci:%s", | ||
| 812 | i, pci_name(priv->pdev)); | ||
| 813 | } | ||
| 814 | #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ | ||
| 815 | |||
| 763 | return 0; | 816 | return 0; |
| 764 | } | 817 | } |
| 765 | #endif /* CONFIG_PCI_MSI */ | 818 | #endif /* CONFIG_PCI_MSI */ |
| @@ -888,20 +941,34 @@ static void tsi721_doorbell_free(struct tsi721_device *priv) | |||
| 888 | priv->idb_base = NULL; | 941 | priv->idb_base = NULL; |
| 889 | } | 942 | } |
| 890 | 943 | ||
| 891 | static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) | 944 | /** |
| 945 | * tsi721_bdma_maint_init - Initialize maintenance request BDMA channel. | ||
| 946 | * @priv: pointer to tsi721 private data | ||
| 947 | * | ||
| 948 | * Initialize BDMA channel allocated for RapidIO maintenance read/write | ||
| 949 | * request generation | ||
| 950 | * Returns %0 on success or %-ENOMEM on failure. | ||
| 951 | */ | ||
| 952 | static int tsi721_bdma_maint_init(struct tsi721_device *priv) | ||
| 892 | { | 953 | { |
| 893 | struct tsi721_dma_desc *bd_ptr; | 954 | struct tsi721_dma_desc *bd_ptr; |
| 894 | u64 *sts_ptr; | 955 | u64 *sts_ptr; |
| 895 | dma_addr_t bd_phys, sts_phys; | 956 | dma_addr_t bd_phys, sts_phys; |
| 896 | int sts_size; | 957 | int sts_size; |
| 897 | int bd_num = priv->bdma[chnum].bd_num; | 958 | int bd_num = 2; |
| 959 | void __iomem *regs; | ||
| 898 | 960 | ||
| 899 | dev_dbg(&priv->pdev->dev, "Init Block DMA Engine, CH%d\n", chnum); | 961 | dev_dbg(&priv->pdev->dev, |
| 962 | "Init Block DMA Engine for Maintenance requests, CH%d\n", | ||
| 963 | TSI721_DMACH_MAINT); | ||
| 900 | 964 | ||
| 901 | /* | 965 | /* |
| 902 | * Initialize DMA channel for maintenance requests | 966 | * Initialize DMA channel for maintenance requests |
| 903 | */ | 967 | */ |
| 904 | 968 | ||
| 969 | priv->mdma.ch_id = TSI721_DMACH_MAINT; | ||
| 970 | regs = priv->regs + TSI721_DMAC_BASE(TSI721_DMACH_MAINT); | ||
| 971 | |||
| 905 | /* Allocate space for DMA descriptors */ | 972 | /* Allocate space for DMA descriptors */ |
| 906 | bd_ptr = dma_zalloc_coherent(&priv->pdev->dev, | 973 | bd_ptr = dma_zalloc_coherent(&priv->pdev->dev, |
| 907 | bd_num * sizeof(struct tsi721_dma_desc), | 974 | bd_num * sizeof(struct tsi721_dma_desc), |
| @@ -909,8 +976,9 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) | |||
| 909 | if (!bd_ptr) | 976 | if (!bd_ptr) |
| 910 | return -ENOMEM; | 977 | return -ENOMEM; |
| 911 | 978 | ||
| 912 | priv->bdma[chnum].bd_phys = bd_phys; | 979 | priv->mdma.bd_num = bd_num; |
| 913 | priv->bdma[chnum].bd_base = bd_ptr; | 980 | priv->mdma.bd_phys = bd_phys; |
| 981 | priv->mdma.bd_base = bd_ptr; | ||
| 914 | 982 | ||
| 915 | dev_dbg(&priv->pdev->dev, "DMA descriptors @ %p (phys = %llx)\n", | 983 | dev_dbg(&priv->pdev->dev, "DMA descriptors @ %p (phys = %llx)\n", |
| 916 | bd_ptr, (unsigned long long)bd_phys); | 984 | bd_ptr, (unsigned long long)bd_phys); |
| @@ -927,13 +995,13 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) | |||
| 927 | dma_free_coherent(&priv->pdev->dev, | 995 | dma_free_coherent(&priv->pdev->dev, |
| 928 | bd_num * sizeof(struct tsi721_dma_desc), | 996 | bd_num * sizeof(struct tsi721_dma_desc), |
| 929 | bd_ptr, bd_phys); | 997 | bd_ptr, bd_phys); |
| 930 | priv->bdma[chnum].bd_base = NULL; | 998 | priv->mdma.bd_base = NULL; |
| 931 | return -ENOMEM; | 999 | return -ENOMEM; |
| 932 | } | 1000 | } |
| 933 | 1001 | ||
| 934 | priv->bdma[chnum].sts_phys = sts_phys; | 1002 | priv->mdma.sts_phys = sts_phys; |
| 935 | priv->bdma[chnum].sts_base = sts_ptr; | 1003 | priv->mdma.sts_base = sts_ptr; |
| 936 | priv->bdma[chnum].sts_size = sts_size; | 1004 | priv->mdma.sts_size = sts_size; |
| 937 | 1005 | ||
| 938 | dev_dbg(&priv->pdev->dev, | 1006 | dev_dbg(&priv->pdev->dev, |
| 939 | "desc status FIFO @ %p (phys = %llx) size=0x%x\n", | 1007 | "desc status FIFO @ %p (phys = %llx) size=0x%x\n", |
| @@ -946,83 +1014,61 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) | |||
| 946 | bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32); | 1014 | bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32); |
| 947 | 1015 | ||
| 948 | /* Setup DMA descriptor pointers */ | 1016 | /* Setup DMA descriptor pointers */ |
| 949 | iowrite32(((u64)bd_phys >> 32), | 1017 | iowrite32(((u64)bd_phys >> 32), regs + TSI721_DMAC_DPTRH); |
| 950 | priv->regs + TSI721_DMAC_DPTRH(chnum)); | ||
| 951 | iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK), | 1018 | iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK), |
| 952 | priv->regs + TSI721_DMAC_DPTRL(chnum)); | 1019 | regs + TSI721_DMAC_DPTRL); |
| 953 | 1020 | ||
| 954 | /* Setup descriptor status FIFO */ | 1021 | /* Setup descriptor status FIFO */ |
| 955 | iowrite32(((u64)sts_phys >> 32), | 1022 | iowrite32(((u64)sts_phys >> 32), regs + TSI721_DMAC_DSBH); |
| 956 | priv->regs + TSI721_DMAC_DSBH(chnum)); | ||
| 957 | iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK), | 1023 | iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK), |
| 958 | priv->regs + TSI721_DMAC_DSBL(chnum)); | 1024 | regs + TSI721_DMAC_DSBL); |
| 959 | iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size), | 1025 | iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size), |
| 960 | priv->regs + TSI721_DMAC_DSSZ(chnum)); | 1026 | regs + TSI721_DMAC_DSSZ); |
| 961 | 1027 | ||
| 962 | /* Clear interrupt bits */ | 1028 | /* Clear interrupt bits */ |
| 963 | iowrite32(TSI721_DMAC_INT_ALL, | 1029 | iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT); |
| 964 | priv->regs + TSI721_DMAC_INT(chnum)); | ||
| 965 | 1030 | ||
| 966 | ioread32(priv->regs + TSI721_DMAC_INT(chnum)); | 1031 | ioread32(regs + TSI721_DMAC_INT); |
| 967 | 1032 | ||
| 968 | /* Toggle DMA channel initialization */ | 1033 | /* Toggle DMA channel initialization */ |
| 969 | iowrite32(TSI721_DMAC_CTL_INIT, priv->regs + TSI721_DMAC_CTL(chnum)); | 1034 | iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); |
| 970 | ioread32(priv->regs + TSI721_DMAC_CTL(chnum)); | 1035 | ioread32(regs + TSI721_DMAC_CTL); |
| 971 | udelay(10); | 1036 | udelay(10); |
| 972 | 1037 | ||
| 973 | return 0; | 1038 | return 0; |
| 974 | } | 1039 | } |
| 975 | 1040 | ||
| 976 | static int tsi721_bdma_ch_free(struct tsi721_device *priv, int chnum) | 1041 | static int tsi721_bdma_maint_free(struct tsi721_device *priv) |
| 977 | { | 1042 | { |
| 978 | u32 ch_stat; | 1043 | u32 ch_stat; |
| 1044 | struct tsi721_bdma_maint *mdma = &priv->mdma; | ||
| 1045 | void __iomem *regs = priv->regs + TSI721_DMAC_BASE(mdma->ch_id); | ||
| 979 | 1046 | ||
| 980 | if (priv->bdma[chnum].bd_base == NULL) | 1047 | if (mdma->bd_base == NULL) |
| 981 | return 0; | 1048 | return 0; |
| 982 | 1049 | ||
| 983 | /* Check if DMA channel still running */ | 1050 | /* Check if DMA channel still running */ |
| 984 | ch_stat = ioread32(priv->regs + TSI721_DMAC_STS(chnum)); | 1051 | ch_stat = ioread32(regs + TSI721_DMAC_STS); |
| 985 | if (ch_stat & TSI721_DMAC_STS_RUN) | 1052 | if (ch_stat & TSI721_DMAC_STS_RUN) |
| 986 | return -EFAULT; | 1053 | return -EFAULT; |
| 987 | 1054 | ||
| 988 | /* Put DMA channel into init state */ | 1055 | /* Put DMA channel into init state */ |
| 989 | iowrite32(TSI721_DMAC_CTL_INIT, | 1056 | iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); |
| 990 | priv->regs + TSI721_DMAC_CTL(chnum)); | ||
| 991 | 1057 | ||
| 992 | /* Free space allocated for DMA descriptors */ | 1058 | /* Free space allocated for DMA descriptors */ |
| 993 | dma_free_coherent(&priv->pdev->dev, | 1059 | dma_free_coherent(&priv->pdev->dev, |
| 994 | priv->bdma[chnum].bd_num * sizeof(struct tsi721_dma_desc), | 1060 | mdma->bd_num * sizeof(struct tsi721_dma_desc), |
| 995 | priv->bdma[chnum].bd_base, priv->bdma[chnum].bd_phys); | 1061 | mdma->bd_base, mdma->bd_phys); |
| 996 | priv->bdma[chnum].bd_base = NULL; | 1062 | mdma->bd_base = NULL; |
| 997 | 1063 | ||
| 998 | /* Free space allocated for status FIFO */ | 1064 | /* Free space allocated for status FIFO */ |
| 999 | dma_free_coherent(&priv->pdev->dev, | 1065 | dma_free_coherent(&priv->pdev->dev, |
| 1000 | priv->bdma[chnum].sts_size * sizeof(struct tsi721_dma_sts), | 1066 | mdma->sts_size * sizeof(struct tsi721_dma_sts), |
| 1001 | priv->bdma[chnum].sts_base, priv->bdma[chnum].sts_phys); | 1067 | mdma->sts_base, mdma->sts_phys); |
| 1002 | priv->bdma[chnum].sts_base = NULL; | 1068 | mdma->sts_base = NULL; |
| 1003 | return 0; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | static int tsi721_bdma_init(struct tsi721_device *priv) | ||
| 1007 | { | ||
| 1008 | /* Initialize BDMA channel allocated for RapidIO maintenance read/write | ||
| 1009 | * request generation | ||
| 1010 | */ | ||
| 1011 | priv->bdma[TSI721_DMACH_MAINT].bd_num = 2; | ||
| 1012 | if (tsi721_bdma_ch_init(priv, TSI721_DMACH_MAINT)) { | ||
| 1013 | dev_err(&priv->pdev->dev, "Unable to initialize maintenance DMA" | ||
| 1014 | " channel %d, aborting\n", TSI721_DMACH_MAINT); | ||
| 1015 | return -ENOMEM; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | return 0; | 1069 | return 0; |
| 1019 | } | 1070 | } |
| 1020 | 1071 | ||
| 1021 | static void tsi721_bdma_free(struct tsi721_device *priv) | ||
| 1022 | { | ||
| 1023 | tsi721_bdma_ch_free(priv, TSI721_DMACH_MAINT); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /* Enable Inbound Messaging Interrupts */ | 1072 | /* Enable Inbound Messaging Interrupts */ |
| 1027 | static void | 1073 | static void |
| 1028 | tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch, | 1074 | tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch, |
| @@ -2035,7 +2081,8 @@ static void tsi721_disable_ints(struct tsi721_device *priv) | |||
| 2035 | 2081 | ||
| 2036 | /* Disable all BDMA Channel interrupts */ | 2082 | /* Disable all BDMA Channel interrupts */ |
| 2037 | for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) | 2083 | for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) |
| 2038 | iowrite32(0, priv->regs + TSI721_DMAC_INTE(ch)); | 2084 | iowrite32(0, |
| 2085 | priv->regs + TSI721_DMAC_BASE(ch) + TSI721_DMAC_INTE); | ||
| 2039 | 2086 | ||
| 2040 | /* Disable all general BDMA interrupts */ | 2087 | /* Disable all general BDMA interrupts */ |
| 2041 | iowrite32(0, priv->regs + TSI721_BDMA_INTE); | 2088 | iowrite32(0, priv->regs + TSI721_BDMA_INTE); |
| @@ -2104,6 +2151,7 @@ static int __devinit tsi721_setup_mport(struct tsi721_device *priv) | |||
| 2104 | mport->phy_type = RIO_PHY_SERIAL; | 2151 | mport->phy_type = RIO_PHY_SERIAL; |
| 2105 | mport->priv = (void *)priv; | 2152 | mport->priv = (void *)priv; |
| 2106 | mport->phys_efptr = 0x100; | 2153 | mport->phys_efptr = 0x100; |
| 2154 | priv->mport = mport; | ||
| 2107 | 2155 | ||
| 2108 | INIT_LIST_HEAD(&mport->dbells); | 2156 | INIT_LIST_HEAD(&mport->dbells); |
| 2109 | 2157 | ||
| @@ -2129,17 +2177,21 @@ static int __devinit tsi721_setup_mport(struct tsi721_device *priv) | |||
| 2129 | if (!err) { | 2177 | if (!err) { |
| 2130 | tsi721_interrupts_init(priv); | 2178 | tsi721_interrupts_init(priv); |
| 2131 | ops->pwenable = tsi721_pw_enable; | 2179 | ops->pwenable = tsi721_pw_enable; |
| 2132 | } else | 2180 | } else { |
| 2133 | dev_err(&pdev->dev, "Unable to get assigned PCI IRQ " | 2181 | dev_err(&pdev->dev, "Unable to get assigned PCI IRQ " |
| 2134 | "vector %02X err=0x%x\n", pdev->irq, err); | 2182 | "vector %02X err=0x%x\n", pdev->irq, err); |
| 2183 | goto err_exit; | ||
| 2184 | } | ||
| 2135 | 2185 | ||
| 2186 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 2187 | tsi721_register_dma(priv); | ||
| 2188 | #endif | ||
| 2136 | /* Enable SRIO link */ | 2189 | /* Enable SRIO link */ |
| 2137 | iowrite32(ioread32(priv->regs + TSI721_DEVCTL) | | 2190 | iowrite32(ioread32(priv->regs + TSI721_DEVCTL) | |
| 2138 | TSI721_DEVCTL_SRBOOT_CMPL, | 2191 | TSI721_DEVCTL_SRBOOT_CMPL, |
| 2139 | priv->regs + TSI721_DEVCTL); | 2192 | priv->regs + TSI721_DEVCTL); |
| 2140 | 2193 | ||
| 2141 | rio_register_mport(mport); | 2194 | rio_register_mport(mport); |
| 2142 | priv->mport = mport; | ||
| 2143 | 2195 | ||
| 2144 | if (mport->host_deviceid >= 0) | 2196 | if (mport->host_deviceid >= 0) |
| 2145 | iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER | | 2197 | iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER | |
| @@ -2149,6 +2201,11 @@ static int __devinit tsi721_setup_mport(struct tsi721_device *priv) | |||
| 2149 | iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR)); | 2201 | iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR)); |
| 2150 | 2202 | ||
| 2151 | return 0; | 2203 | return 0; |
| 2204 | |||
| 2205 | err_exit: | ||
| 2206 | kfree(mport); | ||
| 2207 | kfree(ops); | ||
| 2208 | return err; | ||
| 2152 | } | 2209 | } |
| 2153 | 2210 | ||
| 2154 | static int __devinit tsi721_probe(struct pci_dev *pdev, | 2211 | static int __devinit tsi721_probe(struct pci_dev *pdev, |
| @@ -2294,7 +2351,7 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, | |||
| 2294 | tsi721_init_pc2sr_mapping(priv); | 2351 | tsi721_init_pc2sr_mapping(priv); |
| 2295 | tsi721_init_sr2pc_mapping(priv); | 2352 | tsi721_init_sr2pc_mapping(priv); |
| 2296 | 2353 | ||
| 2297 | if (tsi721_bdma_init(priv)) { | 2354 | if (tsi721_bdma_maint_init(priv)) { |
| 2298 | dev_err(&pdev->dev, "BDMA initialization failed, aborting\n"); | 2355 | dev_err(&pdev->dev, "BDMA initialization failed, aborting\n"); |
| 2299 | err = -ENOMEM; | 2356 | err = -ENOMEM; |
| 2300 | goto err_unmap_bars; | 2357 | goto err_unmap_bars; |
| @@ -2319,7 +2376,7 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, | |||
| 2319 | err_free_consistent: | 2376 | err_free_consistent: |
| 2320 | tsi721_doorbell_free(priv); | 2377 | tsi721_doorbell_free(priv); |
| 2321 | err_free_bdma: | 2378 | err_free_bdma: |
| 2322 | tsi721_bdma_free(priv); | 2379 | tsi721_bdma_maint_free(priv); |
| 2323 | err_unmap_bars: | 2380 | err_unmap_bars: |
| 2324 | if (priv->regs) | 2381 | if (priv->regs) |
| 2325 | iounmap(priv->regs); | 2382 | iounmap(priv->regs); |
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h index 1c226b31af13..59de9d7be346 100644 --- a/drivers/rapidio/devices/tsi721.h +++ b/drivers/rapidio/devices/tsi721.h | |||
| @@ -167,6 +167,8 @@ | |||
| 167 | #define TSI721_DEV_INTE 0x29840 | 167 | #define TSI721_DEV_INTE 0x29840 |
| 168 | #define TSI721_DEV_INT 0x29844 | 168 | #define TSI721_DEV_INT 0x29844 |
| 169 | #define TSI721_DEV_INTSET 0x29848 | 169 | #define TSI721_DEV_INTSET 0x29848 |
| 170 | #define TSI721_DEV_INT_BDMA_CH 0x00002000 | ||
| 171 | #define TSI721_DEV_INT_BDMA_NCH 0x00001000 | ||
| 170 | #define TSI721_DEV_INT_SMSG_CH 0x00000800 | 172 | #define TSI721_DEV_INT_SMSG_CH 0x00000800 |
| 171 | #define TSI721_DEV_INT_SMSG_NCH 0x00000400 | 173 | #define TSI721_DEV_INT_SMSG_NCH 0x00000400 |
| 172 | #define TSI721_DEV_INT_SR2PC_CH 0x00000200 | 174 | #define TSI721_DEV_INT_SR2PC_CH 0x00000200 |
| @@ -181,6 +183,8 @@ | |||
| 181 | #define TSI721_INT_IMSG_CHAN(x) (1 << (16 + (x))) | 183 | #define TSI721_INT_IMSG_CHAN(x) (1 << (16 + (x))) |
| 182 | #define TSI721_INT_OMSG_CHAN_M 0x0000ff00 | 184 | #define TSI721_INT_OMSG_CHAN_M 0x0000ff00 |
| 183 | #define TSI721_INT_OMSG_CHAN(x) (1 << (8 + (x))) | 185 | #define TSI721_INT_OMSG_CHAN(x) (1 << (8 + (x))) |
| 186 | #define TSI721_INT_BDMA_CHAN_M 0x000000ff | ||
| 187 | #define TSI721_INT_BDMA_CHAN(x) (1 << (x)) | ||
| 184 | 188 | ||
| 185 | /* | 189 | /* |
| 186 | * PC2SR block registers | 190 | * PC2SR block registers |
| @@ -235,14 +239,16 @@ | |||
| 235 | * x = 0..7 | 239 | * x = 0..7 |
| 236 | */ | 240 | */ |
| 237 | 241 | ||
| 238 | #define TSI721_DMAC_DWRCNT(x) (0x51000 + (x) * 0x1000) | 242 | #define TSI721_DMAC_BASE(x) (0x51000 + (x) * 0x1000) |
| 239 | #define TSI721_DMAC_DRDCNT(x) (0x51004 + (x) * 0x1000) | ||
| 240 | 243 | ||
| 241 | #define TSI721_DMAC_CTL(x) (0x51008 + (x) * 0x1000) | 244 | #define TSI721_DMAC_DWRCNT 0x000 |
| 245 | #define TSI721_DMAC_DRDCNT 0x004 | ||
| 246 | |||
| 247 | #define TSI721_DMAC_CTL 0x008 | ||
| 242 | #define TSI721_DMAC_CTL_SUSP 0x00000002 | 248 | #define TSI721_DMAC_CTL_SUSP 0x00000002 |
| 243 | #define TSI721_DMAC_CTL_INIT 0x00000001 | 249 | #define TSI721_DMAC_CTL_INIT 0x00000001 |
| 244 | 250 | ||
| 245 | #define TSI721_DMAC_INT(x) (0x5100c + (x) * 0x1000) | 251 | #define TSI721_DMAC_INT 0x00c |
| 246 | #define TSI721_DMAC_INT_STFULL 0x00000010 | 252 | #define TSI721_DMAC_INT_STFULL 0x00000010 |
| 247 | #define TSI721_DMAC_INT_DONE 0x00000008 | 253 | #define TSI721_DMAC_INT_DONE 0x00000008 |
| 248 | #define TSI721_DMAC_INT_SUSP 0x00000004 | 254 | #define TSI721_DMAC_INT_SUSP 0x00000004 |
| @@ -250,34 +256,33 @@ | |||
| 250 | #define TSI721_DMAC_INT_IOFDONE 0x00000001 | 256 | #define TSI721_DMAC_INT_IOFDONE 0x00000001 |
| 251 | #define TSI721_DMAC_INT_ALL 0x0000001f | 257 | #define TSI721_DMAC_INT_ALL 0x0000001f |
| 252 | 258 | ||
| 253 | #define TSI721_DMAC_INTSET(x) (0x51010 + (x) * 0x1000) | 259 | #define TSI721_DMAC_INTSET 0x010 |
| 254 | 260 | ||
| 255 | #define TSI721_DMAC_STS(x) (0x51014 + (x) * 0x1000) | 261 | #define TSI721_DMAC_STS 0x014 |
| 256 | #define TSI721_DMAC_STS_ABORT 0x00400000 | 262 | #define TSI721_DMAC_STS_ABORT 0x00400000 |
| 257 | #define TSI721_DMAC_STS_RUN 0x00200000 | 263 | #define TSI721_DMAC_STS_RUN 0x00200000 |
| 258 | #define TSI721_DMAC_STS_CS 0x001f0000 | 264 | #define TSI721_DMAC_STS_CS 0x001f0000 |
| 259 | 265 | ||
| 260 | #define TSI721_DMAC_INTE(x) (0x51018 + (x) * 0x1000) | 266 | #define TSI721_DMAC_INTE 0x018 |
| 261 | 267 | ||
| 262 | #define TSI721_DMAC_DPTRL(x) (0x51024 + (x) * 0x1000) | 268 | #define TSI721_DMAC_DPTRL 0x024 |
| 263 | #define TSI721_DMAC_DPTRL_MASK 0xffffffe0 | 269 | #define TSI721_DMAC_DPTRL_MASK 0xffffffe0 |
| 264 | 270 | ||
| 265 | #define TSI721_DMAC_DPTRH(x) (0x51028 + (x) * 0x1000) | 271 | #define TSI721_DMAC_DPTRH 0x028 |
| 266 | 272 | ||
| 267 | #define TSI721_DMAC_DSBL(x) (0x5102c + (x) * 0x1000) | 273 | #define TSI721_DMAC_DSBL 0x02c |
| 268 | #define TSI721_DMAC_DSBL_MASK 0xffffffc0 | 274 | #define TSI721_DMAC_DSBL_MASK 0xffffffc0 |
| 269 | 275 | ||
| 270 | #define TSI721_DMAC_DSBH(x) (0x51030 + (x) * 0x1000) | 276 | #define TSI721_DMAC_DSBH 0x030 |
| 271 | 277 | ||
| 272 | #define TSI721_DMAC_DSSZ(x) (0x51034 + (x) * 0x1000) | 278 | #define TSI721_DMAC_DSSZ 0x034 |
| 273 | #define TSI721_DMAC_DSSZ_SIZE_M 0x0000000f | 279 | #define TSI721_DMAC_DSSZ_SIZE_M 0x0000000f |
| 274 | #define TSI721_DMAC_DSSZ_SIZE(size) (__fls(size) - 4) | 280 | #define TSI721_DMAC_DSSZ_SIZE(size) (__fls(size) - 4) |
| 275 | 281 | ||
| 276 | 282 | #define TSI721_DMAC_DSRP 0x038 | |
| 277 | #define TSI721_DMAC_DSRP(x) (0x51038 + (x) * 0x1000) | ||
| 278 | #define TSI721_DMAC_DSRP_MASK 0x0007ffff | 283 | #define TSI721_DMAC_DSRP_MASK 0x0007ffff |
| 279 | 284 | ||
| 280 | #define TSI721_DMAC_DSWP(x) (0x5103c + (x) * 0x1000) | 285 | #define TSI721_DMAC_DSWP 0x03c |
| 281 | #define TSI721_DMAC_DSWP_MASK 0x0007ffff | 286 | #define TSI721_DMAC_DSWP_MASK 0x0007ffff |
| 282 | 287 | ||
| 283 | #define TSI721_BDMA_INTE 0x5f000 | 288 | #define TSI721_BDMA_INTE 0x5f000 |
| @@ -612,6 +617,8 @@ enum dma_rtype { | |||
| 612 | #define TSI721_DMACH_MAINT 0 /* DMA channel for maint requests */ | 617 | #define TSI721_DMACH_MAINT 0 /* DMA channel for maint requests */ |
| 613 | #define TSI721_DMACH_MAINT_NBD 32 /* Number of BDs for maint requests */ | 618 | #define TSI721_DMACH_MAINT_NBD 32 /* Number of BDs for maint requests */ |
| 614 | 619 | ||
| 620 | #define TSI721_DMACH_DMA 1 /* DMA channel for data transfers */ | ||
| 621 | |||
| 615 | #define MSG_DMA_ENTRY_INX_TO_SIZE(x) ((0x10 << (x)) & 0xFFFF0) | 622 | #define MSG_DMA_ENTRY_INX_TO_SIZE(x) ((0x10 << (x)) & 0xFFFF0) |
| 616 | 623 | ||
| 617 | enum tsi721_smsg_int_flag { | 624 | enum tsi721_smsg_int_flag { |
| @@ -626,7 +633,48 @@ enum tsi721_smsg_int_flag { | |||
| 626 | 633 | ||
| 627 | /* Structures */ | 634 | /* Structures */ |
| 628 | 635 | ||
| 636 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 637 | |||
| 638 | struct tsi721_tx_desc { | ||
| 639 | struct dma_async_tx_descriptor txd; | ||
| 640 | struct tsi721_dma_desc *hw_desc; | ||
| 641 | u16 destid; | ||
| 642 | /* low 64-bits of 66-bit RIO address */ | ||
| 643 | u64 rio_addr; | ||
| 644 | /* upper 2-bits of 66-bit RIO address */ | ||
| 645 | u8 rio_addr_u; | ||
| 646 | bool interrupt; | ||
| 647 | struct list_head desc_node; | ||
| 648 | struct list_head tx_list; | ||
| 649 | }; | ||
| 650 | |||
| 629 | struct tsi721_bdma_chan { | 651 | struct tsi721_bdma_chan { |
| 652 | int id; | ||
| 653 | void __iomem *regs; | ||
| 654 | int bd_num; /* number of buffer descriptors */ | ||
| 655 | void *bd_base; /* start of DMA descriptors */ | ||
| 656 | dma_addr_t bd_phys; | ||
| 657 | void *sts_base; /* start of DMA BD status FIFO */ | ||
| 658 | dma_addr_t sts_phys; | ||
| 659 | int sts_size; | ||
| 660 | u32 sts_rdptr; | ||
| 661 | u32 wr_count; | ||
| 662 | u32 wr_count_next; | ||
| 663 | |||
| 664 | struct dma_chan dchan; | ||
| 665 | struct tsi721_tx_desc *tx_desc; | ||
| 666 | spinlock_t lock; | ||
| 667 | struct list_head active_list; | ||
| 668 | struct list_head queue; | ||
| 669 | struct list_head free_list; | ||
| 670 | dma_cookie_t completed_cookie; | ||
| 671 | struct tasklet_struct tasklet; | ||
| 672 | }; | ||
| 673 | |||
| 674 | #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ | ||
| 675 | |||
| 676 | struct tsi721_bdma_maint { | ||
| 677 | int ch_id; /* BDMA channel number */ | ||
| 630 | int bd_num; /* number of buffer descriptors */ | 678 | int bd_num; /* number of buffer descriptors */ |
| 631 | void *bd_base; /* start of DMA descriptors */ | 679 | void *bd_base; /* start of DMA descriptors */ |
| 632 | dma_addr_t bd_phys; | 680 | dma_addr_t bd_phys; |
| @@ -721,6 +769,24 @@ enum tsi721_msix_vect { | |||
| 721 | TSI721_VECT_IMB1_INT, | 769 | TSI721_VECT_IMB1_INT, |
| 722 | TSI721_VECT_IMB2_INT, | 770 | TSI721_VECT_IMB2_INT, |
| 723 | TSI721_VECT_IMB3_INT, | 771 | TSI721_VECT_IMB3_INT, |
| 772 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 773 | TSI721_VECT_DMA0_DONE, | ||
| 774 | TSI721_VECT_DMA1_DONE, | ||
| 775 | TSI721_VECT_DMA2_DONE, | ||
| 776 | TSI721_VECT_DMA3_DONE, | ||
| 777 | TSI721_VECT_DMA4_DONE, | ||
| 778 | TSI721_VECT_DMA5_DONE, | ||
| 779 | TSI721_VECT_DMA6_DONE, | ||
| 780 | TSI721_VECT_DMA7_DONE, | ||
| 781 | TSI721_VECT_DMA0_INT, | ||
| 782 | TSI721_VECT_DMA1_INT, | ||
| 783 | TSI721_VECT_DMA2_INT, | ||
| 784 | TSI721_VECT_DMA3_INT, | ||
| 785 | TSI721_VECT_DMA4_INT, | ||
| 786 | TSI721_VECT_DMA5_INT, | ||
| 787 | TSI721_VECT_DMA6_INT, | ||
| 788 | TSI721_VECT_DMA7_INT, | ||
| 789 | #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ | ||
| 724 | TSI721_VECT_MAX | 790 | TSI721_VECT_MAX |
| 725 | }; | 791 | }; |
| 726 | 792 | ||
| @@ -754,7 +820,11 @@ struct tsi721_device { | |||
| 754 | u32 pw_discard_count; | 820 | u32 pw_discard_count; |
| 755 | 821 | ||
| 756 | /* BDMA Engine */ | 822 | /* BDMA Engine */ |
| 823 | struct tsi721_bdma_maint mdma; /* Maintenance rd/wr request channel */ | ||
| 824 | |||
| 825 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 757 | struct tsi721_bdma_chan bdma[TSI721_DMA_CHNUM]; | 826 | struct tsi721_bdma_chan bdma[TSI721_DMA_CHNUM]; |
| 827 | #endif | ||
| 758 | 828 | ||
| 759 | /* Inbound Messaging */ | 829 | /* Inbound Messaging */ |
| 760 | int imsg_init[TSI721_IMSG_CHNUM]; | 830 | int imsg_init[TSI721_IMSG_CHNUM]; |
| @@ -765,4 +835,9 @@ struct tsi721_device { | |||
| 765 | struct tsi721_omsg_ring omsg_ring[TSI721_OMSG_CHNUM]; | 835 | struct tsi721_omsg_ring omsg_ring[TSI721_OMSG_CHNUM]; |
| 766 | }; | 836 | }; |
| 767 | 837 | ||
| 838 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 839 | extern void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan); | ||
| 840 | extern int __devinit tsi721_register_dma(struct tsi721_device *priv); | ||
| 841 | #endif | ||
| 842 | |||
| 768 | #endif | 843 | #endif |
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c new file mode 100644 index 000000000000..92e06a5c62ec --- /dev/null +++ b/drivers/rapidio/devices/tsi721_dma.c | |||
| @@ -0,0 +1,823 @@ | |||
| 1 | /* | ||
| 2 | * DMA Engine support for Tsi721 PCIExpress-to-SRIO bridge | ||
| 3 | * | ||
| 4 | * Copyright 2011 Integrated Device Technology, Inc. | ||
| 5 | * Alexandre Bounine <alexandre.bounine@idt.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the Free | ||
| 9 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 10 | * any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 15 | * more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along with | ||
| 18 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 19 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/io.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/ioport.h> | ||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/pci.h> | ||
| 29 | #include <linux/rio.h> | ||
| 30 | #include <linux/rio_drv.h> | ||
| 31 | #include <linux/dma-mapping.h> | ||
| 32 | #include <linux/interrupt.h> | ||
| 33 | #include <linux/kfifo.h> | ||
| 34 | #include <linux/delay.h> | ||
| 35 | |||
| 36 | #include "tsi721.h" | ||
| 37 | |||
| 38 | static inline struct tsi721_bdma_chan *to_tsi721_chan(struct dma_chan *chan) | ||
| 39 | { | ||
| 40 | return container_of(chan, struct tsi721_bdma_chan, dchan); | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline struct tsi721_device *to_tsi721(struct dma_device *ddev) | ||
| 44 | { | ||
| 45 | return container_of(ddev, struct rio_mport, dma)->priv; | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline | ||
| 49 | struct tsi721_tx_desc *to_tsi721_desc(struct dma_async_tx_descriptor *txd) | ||
| 50 | { | ||
| 51 | return container_of(txd, struct tsi721_tx_desc, txd); | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline | ||
| 55 | struct tsi721_tx_desc *tsi721_dma_first_active( | ||
| 56 | struct tsi721_bdma_chan *bdma_chan) | ||
| 57 | { | ||
| 58 | return list_first_entry(&bdma_chan->active_list, | ||
| 59 | struct tsi721_tx_desc, desc_node); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int tsi721_bdma_ch_init(struct tsi721_bdma_chan *bdma_chan) | ||
| 63 | { | ||
| 64 | struct tsi721_dma_desc *bd_ptr; | ||
| 65 | struct device *dev = bdma_chan->dchan.device->dev; | ||
| 66 | u64 *sts_ptr; | ||
| 67 | dma_addr_t bd_phys; | ||
| 68 | dma_addr_t sts_phys; | ||
| 69 | int sts_size; | ||
| 70 | int bd_num = bdma_chan->bd_num; | ||
| 71 | |||
| 72 | dev_dbg(dev, "Init Block DMA Engine, CH%d\n", bdma_chan->id); | ||
| 73 | |||
| 74 | /* Allocate space for DMA descriptors */ | ||
| 75 | bd_ptr = dma_zalloc_coherent(dev, | ||
| 76 | bd_num * sizeof(struct tsi721_dma_desc), | ||
| 77 | &bd_phys, GFP_KERNEL); | ||
| 78 | if (!bd_ptr) | ||
| 79 | return -ENOMEM; | ||
| 80 | |||
| 81 | bdma_chan->bd_phys = bd_phys; | ||
| 82 | bdma_chan->bd_base = bd_ptr; | ||
| 83 | |||
| 84 | dev_dbg(dev, "DMA descriptors @ %p (phys = %llx)\n", | ||
| 85 | bd_ptr, (unsigned long long)bd_phys); | ||
| 86 | |||
| 87 | /* Allocate space for descriptor status FIFO */ | ||
| 88 | sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ? | ||
| 89 | bd_num : TSI721_DMA_MINSTSSZ; | ||
| 90 | sts_size = roundup_pow_of_two(sts_size); | ||
| 91 | sts_ptr = dma_zalloc_coherent(dev, | ||
| 92 | sts_size * sizeof(struct tsi721_dma_sts), | ||
| 93 | &sts_phys, GFP_KERNEL); | ||
| 94 | if (!sts_ptr) { | ||
| 95 | /* Free space allocated for DMA descriptors */ | ||
| 96 | dma_free_coherent(dev, | ||
| 97 | bd_num * sizeof(struct tsi721_dma_desc), | ||
| 98 | bd_ptr, bd_phys); | ||
| 99 | bdma_chan->bd_base = NULL; | ||
| 100 | return -ENOMEM; | ||
| 101 | } | ||
| 102 | |||
| 103 | bdma_chan->sts_phys = sts_phys; | ||
| 104 | bdma_chan->sts_base = sts_ptr; | ||
| 105 | bdma_chan->sts_size = sts_size; | ||
| 106 | |||
| 107 | dev_dbg(dev, | ||
| 108 | "desc status FIFO @ %p (phys = %llx) size=0x%x\n", | ||
| 109 | sts_ptr, (unsigned long long)sts_phys, sts_size); | ||
| 110 | |||
| 111 | /* Initialize DMA descriptors ring */ | ||
| 112 | bd_ptr[bd_num - 1].type_id = cpu_to_le32(DTYPE3 << 29); | ||
| 113 | bd_ptr[bd_num - 1].next_lo = cpu_to_le32((u64)bd_phys & | ||
| 114 | TSI721_DMAC_DPTRL_MASK); | ||
| 115 | bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32); | ||
| 116 | |||
| 117 | /* Setup DMA descriptor pointers */ | ||
| 118 | iowrite32(((u64)bd_phys >> 32), | ||
| 119 | bdma_chan->regs + TSI721_DMAC_DPTRH); | ||
| 120 | iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK), | ||
| 121 | bdma_chan->regs + TSI721_DMAC_DPTRL); | ||
| 122 | |||
| 123 | /* Setup descriptor status FIFO */ | ||
| 124 | iowrite32(((u64)sts_phys >> 32), | ||
| 125 | bdma_chan->regs + TSI721_DMAC_DSBH); | ||
| 126 | iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK), | ||
| 127 | bdma_chan->regs + TSI721_DMAC_DSBL); | ||
| 128 | iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size), | ||
| 129 | bdma_chan->regs + TSI721_DMAC_DSSZ); | ||
| 130 | |||
| 131 | /* Clear interrupt bits */ | ||
| 132 | iowrite32(TSI721_DMAC_INT_ALL, | ||
| 133 | bdma_chan->regs + TSI721_DMAC_INT); | ||
| 134 | |||
| 135 | ioread32(bdma_chan->regs + TSI721_DMAC_INT); | ||
| 136 | |||
| 137 | /* Toggle DMA channel initialization */ | ||
| 138 | iowrite32(TSI721_DMAC_CTL_INIT, bdma_chan->regs + TSI721_DMAC_CTL); | ||
| 139 | ioread32(bdma_chan->regs + TSI721_DMAC_CTL); | ||
| 140 | bdma_chan->wr_count = bdma_chan->wr_count_next = 0; | ||
| 141 | bdma_chan->sts_rdptr = 0; | ||
| 142 | udelay(10); | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int tsi721_bdma_ch_free(struct tsi721_bdma_chan *bdma_chan) | ||
| 148 | { | ||
| 149 | u32 ch_stat; | ||
| 150 | |||
| 151 | if (bdma_chan->bd_base == NULL) | ||
| 152 | return 0; | ||
| 153 | |||
| 154 | /* Check if DMA channel still running */ | ||
| 155 | ch_stat = ioread32(bdma_chan->regs + TSI721_DMAC_STS); | ||
| 156 | if (ch_stat & TSI721_DMAC_STS_RUN) | ||
| 157 | return -EFAULT; | ||
| 158 | |||
| 159 | /* Put DMA channel into init state */ | ||
| 160 | iowrite32(TSI721_DMAC_CTL_INIT, bdma_chan->regs + TSI721_DMAC_CTL); | ||
| 161 | |||
| 162 | /* Free space allocated for DMA descriptors */ | ||
| 163 | dma_free_coherent(bdma_chan->dchan.device->dev, | ||
| 164 | bdma_chan->bd_num * sizeof(struct tsi721_dma_desc), | ||
| 165 | bdma_chan->bd_base, bdma_chan->bd_phys); | ||
| 166 | bdma_chan->bd_base = NULL; | ||
| 167 | |||
| 168 | /* Free space allocated for status FIFO */ | ||
| 169 | dma_free_coherent(bdma_chan->dchan.device->dev, | ||
| 170 | bdma_chan->sts_size * sizeof(struct tsi721_dma_sts), | ||
| 171 | bdma_chan->sts_base, bdma_chan->sts_phys); | ||
| 172 | bdma_chan->sts_base = NULL; | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | static void | ||
| 177 | tsi721_bdma_interrupt_enable(struct tsi721_bdma_chan *bdma_chan, int enable) | ||
| 178 | { | ||
| 179 | if (enable) { | ||
| 180 | /* Clear pending BDMA channel interrupts */ | ||
| 181 | iowrite32(TSI721_DMAC_INT_ALL, | ||
| 182 | bdma_chan->regs + TSI721_DMAC_INT); | ||
| 183 | ioread32(bdma_chan->regs + TSI721_DMAC_INT); | ||
| 184 | /* Enable BDMA channel interrupts */ | ||
| 185 | iowrite32(TSI721_DMAC_INT_ALL, | ||
| 186 | bdma_chan->regs + TSI721_DMAC_INTE); | ||
| 187 | } else { | ||
| 188 | /* Disable BDMA channel interrupts */ | ||
| 189 | iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE); | ||
| 190 | /* Clear pending BDMA channel interrupts */ | ||
| 191 | iowrite32(TSI721_DMAC_INT_ALL, | ||
| 192 | bdma_chan->regs + TSI721_DMAC_INT); | ||
| 193 | } | ||
| 194 | |||
| 195 | } | ||
| 196 | |||
| 197 | static bool tsi721_dma_is_idle(struct tsi721_bdma_chan *bdma_chan) | ||
| 198 | { | ||
| 199 | u32 sts; | ||
| 200 | |||
| 201 | sts = ioread32(bdma_chan->regs + TSI721_DMAC_STS); | ||
| 202 | return ((sts & TSI721_DMAC_STS_RUN) == 0); | ||
| 203 | } | ||
| 204 | |||
| 205 | void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan) | ||
| 206 | { | ||
| 207 | /* Disable BDMA channel interrupts */ | ||
| 208 | iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE); | ||
| 209 | |||
| 210 | tasklet_schedule(&bdma_chan->tasklet); | ||
| 211 | } | ||
| 212 | |||
| 213 | #ifdef CONFIG_PCI_MSI | ||
| 214 | /** | ||
| 215 | * tsi721_omsg_msix - MSI-X interrupt handler for BDMA channels | ||
| 216 | * @irq: Linux interrupt number | ||
| 217 | * @ptr: Pointer to interrupt-specific data (BDMA channel structure) | ||
| 218 | * | ||
| 219 | * Handles BDMA channel interrupts signaled using MSI-X. | ||
| 220 | */ | ||
| 221 | static irqreturn_t tsi721_bdma_msix(int irq, void *ptr) | ||
| 222 | { | ||
| 223 | struct tsi721_bdma_chan *bdma_chan = ptr; | ||
| 224 | |||
| 225 | tsi721_bdma_handler(bdma_chan); | ||
| 226 | return IRQ_HANDLED; | ||
| 227 | } | ||
| 228 | #endif /* CONFIG_PCI_MSI */ | ||
| 229 | |||
| 230 | /* Must be called with the spinlock held */ | ||
| 231 | static void tsi721_start_dma(struct tsi721_bdma_chan *bdma_chan) | ||
| 232 | { | ||
| 233 | if (!tsi721_dma_is_idle(bdma_chan)) { | ||
| 234 | dev_err(bdma_chan->dchan.device->dev, | ||
| 235 | "BUG: Attempt to start non-idle channel\n"); | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 239 | if (bdma_chan->wr_count == bdma_chan->wr_count_next) { | ||
| 240 | dev_err(bdma_chan->dchan.device->dev, | ||
| 241 | "BUG: Attempt to start DMA with no BDs ready\n"); | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | |||
| 245 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 246 | "tx_chan: %p, chan: %d, regs: %p\n", | ||
| 247 | bdma_chan, bdma_chan->dchan.chan_id, bdma_chan->regs); | ||
| 248 | |||
| 249 | iowrite32(bdma_chan->wr_count_next, | ||
| 250 | bdma_chan->regs + TSI721_DMAC_DWRCNT); | ||
| 251 | ioread32(bdma_chan->regs + TSI721_DMAC_DWRCNT); | ||
| 252 | |||
| 253 | bdma_chan->wr_count = bdma_chan->wr_count_next; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void tsi721_desc_put(struct tsi721_bdma_chan *bdma_chan, | ||
| 257 | struct tsi721_tx_desc *desc) | ||
| 258 | { | ||
| 259 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 260 | "Put desc: %p into free list\n", desc); | ||
| 261 | |||
| 262 | if (desc) { | ||
| 263 | spin_lock_bh(&bdma_chan->lock); | ||
| 264 | list_splice_init(&desc->tx_list, &bdma_chan->free_list); | ||
| 265 | list_add(&desc->desc_node, &bdma_chan->free_list); | ||
| 266 | bdma_chan->wr_count_next = bdma_chan->wr_count; | ||
| 267 | spin_unlock_bh(&bdma_chan->lock); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | static | ||
| 272 | struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan) | ||
| 273 | { | ||
| 274 | struct tsi721_tx_desc *tx_desc, *_tx_desc; | ||
| 275 | struct tsi721_tx_desc *ret = NULL; | ||
| 276 | int i; | ||
| 277 | |||
| 278 | spin_lock_bh(&bdma_chan->lock); | ||
| 279 | list_for_each_entry_safe(tx_desc, _tx_desc, | ||
| 280 | &bdma_chan->free_list, desc_node) { | ||
| 281 | if (async_tx_test_ack(&tx_desc->txd)) { | ||
| 282 | list_del(&tx_desc->desc_node); | ||
| 283 | ret = tx_desc; | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 287 | "desc %p not ACKed\n", tx_desc); | ||
| 288 | } | ||
| 289 | |||
| 290 | i = bdma_chan->wr_count_next % bdma_chan->bd_num; | ||
| 291 | if (i == bdma_chan->bd_num - 1) { | ||
| 292 | i = 0; | ||
| 293 | bdma_chan->wr_count_next++; /* skip link descriptor */ | ||
| 294 | } | ||
| 295 | |||
| 296 | bdma_chan->wr_count_next++; | ||
| 297 | tx_desc->txd.phys = bdma_chan->bd_phys + | ||
| 298 | i * sizeof(struct tsi721_dma_desc); | ||
| 299 | tx_desc->hw_desc = &((struct tsi721_dma_desc *)bdma_chan->bd_base)[i]; | ||
| 300 | |||
| 301 | spin_unlock_bh(&bdma_chan->lock); | ||
| 302 | |||
| 303 | return ret; | ||
| 304 | } | ||
| 305 | |||
| 306 | static int | ||
| 307 | tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan, | ||
| 308 | struct tsi721_tx_desc *desc, struct scatterlist *sg, | ||
| 309 | enum dma_rtype rtype, u32 sys_size) | ||
| 310 | { | ||
| 311 | struct tsi721_dma_desc *bd_ptr = desc->hw_desc; | ||
| 312 | u64 rio_addr; | ||
| 313 | |||
| 314 | if (sg_dma_len(sg) > TSI721_DMAD_BCOUNT1 + 1) { | ||
| 315 | dev_err(bdma_chan->dchan.device->dev, | ||
| 316 | "SG element is too large\n"); | ||
| 317 | return -EINVAL; | ||
| 318 | } | ||
| 319 | |||
| 320 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 321 | "desc: 0x%llx, addr: 0x%llx len: 0x%x\n", | ||
| 322 | (u64)desc->txd.phys, (unsigned long long)sg_dma_address(sg), | ||
| 323 | sg_dma_len(sg)); | ||
| 324 | |||
| 325 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 326 | "bd_ptr = %p did=%d raddr=0x%llx\n", | ||
| 327 | bd_ptr, desc->destid, desc->rio_addr); | ||
| 328 | |||
| 329 | /* Initialize DMA descriptor */ | ||
| 330 | bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) | | ||
| 331 | (rtype << 19) | desc->destid); | ||
| 332 | if (desc->interrupt) | ||
| 333 | bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF); | ||
| 334 | bd_ptr->bcount = cpu_to_le32(((desc->rio_addr & 0x3) << 30) | | ||
| 335 | (sys_size << 26) | sg_dma_len(sg)); | ||
| 336 | rio_addr = (desc->rio_addr >> 2) | | ||
| 337 | ((u64)(desc->rio_addr_u & 0x3) << 62); | ||
| 338 | bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff); | ||
| 339 | bd_ptr->raddr_hi = cpu_to_le32(rio_addr >> 32); | ||
| 340 | bd_ptr->t1.bufptr_lo = cpu_to_le32( | ||
| 341 | (u64)sg_dma_address(sg) & 0xffffffff); | ||
| 342 | bd_ptr->t1.bufptr_hi = cpu_to_le32((u64)sg_dma_address(sg) >> 32); | ||
| 343 | bd_ptr->t1.s_dist = 0; | ||
| 344 | bd_ptr->t1.s_size = 0; | ||
| 345 | |||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 349 | static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan, | ||
| 350 | struct tsi721_tx_desc *desc) | ||
| 351 | { | ||
| 352 | struct dma_async_tx_descriptor *txd = &desc->txd; | ||
| 353 | dma_async_tx_callback callback = txd->callback; | ||
| 354 | void *param = txd->callback_param; | ||
| 355 | |||
| 356 | list_splice_init(&desc->tx_list, &bdma_chan->free_list); | ||
| 357 | list_move(&desc->desc_node, &bdma_chan->free_list); | ||
| 358 | bdma_chan->completed_cookie = txd->cookie; | ||
| 359 | |||
| 360 | if (callback) | ||
| 361 | callback(param); | ||
| 362 | } | ||
| 363 | |||
| 364 | static void tsi721_dma_complete_all(struct tsi721_bdma_chan *bdma_chan) | ||
| 365 | { | ||
| 366 | struct tsi721_tx_desc *desc, *_d; | ||
| 367 | LIST_HEAD(list); | ||
| 368 | |||
| 369 | BUG_ON(!tsi721_dma_is_idle(bdma_chan)); | ||
| 370 | |||
| 371 | if (!list_empty(&bdma_chan->queue)) | ||
| 372 | tsi721_start_dma(bdma_chan); | ||
| 373 | |||
| 374 | list_splice_init(&bdma_chan->active_list, &list); | ||
| 375 | list_splice_init(&bdma_chan->queue, &bdma_chan->active_list); | ||
| 376 | |||
| 377 | list_for_each_entry_safe(desc, _d, &list, desc_node) | ||
| 378 | tsi721_dma_chain_complete(bdma_chan, desc); | ||
| 379 | } | ||
| 380 | |||
| 381 | static void tsi721_clr_stat(struct tsi721_bdma_chan *bdma_chan) | ||
| 382 | { | ||
| 383 | u32 srd_ptr; | ||
| 384 | u64 *sts_ptr; | ||
| 385 | int i, j; | ||
| 386 | |||
| 387 | /* Check and clear descriptor status FIFO entries */ | ||
| 388 | srd_ptr = bdma_chan->sts_rdptr; | ||
| 389 | sts_ptr = bdma_chan->sts_base; | ||
| 390 | j = srd_ptr * 8; | ||
| 391 | while (sts_ptr[j]) { | ||
| 392 | for (i = 0; i < 8 && sts_ptr[j]; i++, j++) | ||
| 393 | sts_ptr[j] = 0; | ||
| 394 | |||
| 395 | ++srd_ptr; | ||
| 396 | srd_ptr %= bdma_chan->sts_size; | ||
| 397 | j = srd_ptr * 8; | ||
| 398 | } | ||
| 399 | |||
| 400 | iowrite32(srd_ptr, bdma_chan->regs + TSI721_DMAC_DSRP); | ||
| 401 | bdma_chan->sts_rdptr = srd_ptr; | ||
| 402 | } | ||
| 403 | |||
| 404 | static void tsi721_advance_work(struct tsi721_bdma_chan *bdma_chan) | ||
| 405 | { | ||
| 406 | if (list_empty(&bdma_chan->active_list) || | ||
| 407 | list_is_singular(&bdma_chan->active_list)) { | ||
| 408 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 409 | "%s: Active_list empty\n", __func__); | ||
| 410 | tsi721_dma_complete_all(bdma_chan); | ||
| 411 | } else { | ||
| 412 | dev_dbg(bdma_chan->dchan.device->dev, | ||
| 413 | "%s: Active_list NOT empty\n", __func__); | ||
| 414 | tsi721_dma_chain_complete(bdma_chan, | ||
| 415 | tsi721_dma_first_active(bdma_chan)); | ||
| 416 | tsi721_start_dma(bdma_chan); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | static void tsi721_dma_tasklet(unsigned long data) | ||
| 421 | { | ||
| 422 | struct tsi721_bdma_chan *bdma_chan = (struct tsi721_bdma_chan *)data; | ||
| 423 | u32 dmac_int, dmac_sts; | ||
| 424 | |||
| 425 | dmac_int = ioread32(bdma_chan->regs + TSI721_DMAC_INT); | ||
| 426 | dev_dbg(bdma_chan->dchan.device->dev, "%s: DMAC%d_INT = 0x%x\n", | ||
| 427 | __func__, bdma_chan->id, dmac_int); | ||
| 428 | /* Clear channel interrupts */ | ||
| 429 | iowrite32(dmac_int, bdma_chan->regs + TSI721_DMAC_INT); | ||
| 430 | |||
| 431 | if (dmac_int & TSI721_DMAC_INT_ERR) { | ||
| 432 | dmac_sts = ioread32(bdma_chan->regs + TSI721_DMAC_STS); | ||
| 433 | dev_err(bdma_chan->dchan.device->dev, | ||
| 434 | "%s: DMA ERROR - DMAC%d_STS = 0x%x\n", | ||
| 435 | __func__, bdma_chan->id, dmac_sts); | ||
| 436 | } | ||
| 437 | |||
| 438 | if (dmac_int & TSI721_DMAC_INT_STFULL) { | ||
| 439 | dev_err(bdma_chan->dchan.device->dev, | ||
| 440 | "%s: DMAC%d descriptor status FIFO is full\n", | ||
| 441 | __func__, bdma_chan->id); | ||
| 442 | } | ||
| 443 | |||
| 444 | if (dmac_int & (TSI721_DMAC_INT_DONE | TSI721_DMAC_INT_IOFDONE)) { | ||
| 445 | tsi721_clr_stat(bdma_chan); | ||
| 446 | spin_lock(&bdma_chan->lock); | ||
| 447 | tsi721_advance_work(bdma_chan); | ||
| 448 | spin_unlock(&bdma_chan->lock); | ||
| 449 | } | ||
| 450 | |||
| 451 | /* Re-Enable BDMA channel interrupts */ | ||
| 452 | iowrite32(TSI721_DMAC_INT_ALL, bdma_chan->regs + TSI721_DMAC_INTE); | ||
| 453 | } | ||
| 454 | |||
| 455 | static dma_cookie_t tsi721_tx_submit(struct dma_async_tx_descriptor *txd) | ||
| 456 | { | ||
| 457 | struct tsi721_tx_desc *desc = to_tsi721_desc(txd); | ||
| 458 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(txd->chan); | ||
| 459 | dma_cookie_t cookie; | ||
| 460 | |||
| 461 | spin_lock_bh(&bdma_chan->lock); | ||
| 462 | |||
| 463 | cookie = txd->chan->cookie; | ||
| 464 | if (++cookie < 0) | ||
| 465 | cookie = 1; | ||
| 466 | txd->chan->cookie = cookie; | ||
| 467 | txd->cookie = cookie; | ||
| 468 | |||
| 469 | if (list_empty(&bdma_chan->active_list)) { | ||
| 470 | list_add_tail(&desc->desc_node, &bdma_chan->active_list); | ||
| 471 | tsi721_start_dma(bdma_chan); | ||
| 472 | } else { | ||
| 473 | list_add_tail(&desc->desc_node, &bdma_chan->queue); | ||
| 474 | } | ||
| 475 | |||
| 476 | spin_unlock_bh(&bdma_chan->lock); | ||
| 477 | return cookie; | ||
| 478 | } | ||
| 479 | |||
| 480 | static int tsi721_alloc_chan_resources(struct dma_chan *dchan) | ||
| 481 | { | ||
| 482 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | ||
| 483 | #ifdef CONFIG_PCI_MSI | ||
| 484 | struct tsi721_device *priv = to_tsi721(dchan->device); | ||
| 485 | #endif | ||
| 486 | struct tsi721_tx_desc *desc = NULL; | ||
| 487 | LIST_HEAD(tmp_list); | ||
| 488 | int i; | ||
| 489 | int rc; | ||
| 490 | |||
| 491 | if (bdma_chan->bd_base) | ||
| 492 | return bdma_chan->bd_num - 1; | ||
| 493 | |||
| 494 | /* Initialize BDMA channel */ | ||
| 495 | if (tsi721_bdma_ch_init(bdma_chan)) { | ||
| 496 | dev_err(dchan->device->dev, "Unable to initialize data DMA" | ||
| 497 | " channel %d, aborting\n", bdma_chan->id); | ||
| 498 | return -ENOMEM; | ||
| 499 | } | ||
| 500 | |||
| 501 | /* Alocate matching number of logical descriptors */ | ||
| 502 | desc = kcalloc((bdma_chan->bd_num - 1), sizeof(struct tsi721_tx_desc), | ||
| 503 | GFP_KERNEL); | ||
| 504 | if (!desc) { | ||
| 505 | dev_err(dchan->device->dev, | ||
| 506 | "Failed to allocate logical descriptors\n"); | ||
| 507 | rc = -ENOMEM; | ||
| 508 | goto err_out; | ||
| 509 | } | ||
| 510 | |||
| 511 | bdma_chan->tx_desc = desc; | ||
| 512 | |||
| 513 | for (i = 0; i < bdma_chan->bd_num - 1; i++) { | ||
| 514 | dma_async_tx_descriptor_init(&desc[i].txd, dchan); | ||
| 515 | desc[i].txd.tx_submit = tsi721_tx_submit; | ||
| 516 | desc[i].txd.flags = DMA_CTRL_ACK; | ||
| 517 | INIT_LIST_HEAD(&desc[i].tx_list); | ||
| 518 | list_add_tail(&desc[i].desc_node, &tmp_list); | ||
| 519 | } | ||
| 520 | |||
| 521 | spin_lock_bh(&bdma_chan->lock); | ||
| 522 | list_splice(&tmp_list, &bdma_chan->free_list); | ||
| 523 | bdma_chan->completed_cookie = dchan->cookie = 1; | ||
| 524 | spin_unlock_bh(&bdma_chan->lock); | ||
| 525 | |||
| 526 | #ifdef CONFIG_PCI_MSI | ||
| 527 | if (priv->flags & TSI721_USING_MSIX) { | ||
| 528 | /* Request interrupt service if we are in MSI-X mode */ | ||
| 529 | rc = request_irq( | ||
| 530 | priv->msix[TSI721_VECT_DMA0_DONE + | ||
| 531 | bdma_chan->id].vector, | ||
| 532 | tsi721_bdma_msix, 0, | ||
| 533 | priv->msix[TSI721_VECT_DMA0_DONE + | ||
| 534 | bdma_chan->id].irq_name, | ||
| 535 | (void *)bdma_chan); | ||
| 536 | |||
| 537 | if (rc) { | ||
| 538 | dev_dbg(dchan->device->dev, | ||
| 539 | "Unable to allocate MSI-X interrupt for " | ||
| 540 | "BDMA%d-DONE\n", bdma_chan->id); | ||
| 541 | goto err_out; | ||
| 542 | } | ||
| 543 | |||
| 544 | rc = request_irq(priv->msix[TSI721_VECT_DMA0_INT + | ||
| 545 | bdma_chan->id].vector, | ||
| 546 | tsi721_bdma_msix, 0, | ||
| 547 | priv->msix[TSI721_VECT_DMA0_INT + | ||
| 548 | bdma_chan->id].irq_name, | ||
| 549 | (void *)bdma_chan); | ||
| 550 | |||
| 551 | if (rc) { | ||
| 552 | dev_dbg(dchan->device->dev, | ||
| 553 | "Unable to allocate MSI-X interrupt for " | ||
| 554 | "BDMA%d-INT\n", bdma_chan->id); | ||
| 555 | free_irq( | ||
| 556 | priv->msix[TSI721_VECT_DMA0_DONE + | ||
| 557 | bdma_chan->id].vector, | ||
| 558 | (void *)bdma_chan); | ||
| 559 | rc = -EIO; | ||
| 560 | goto err_out; | ||
| 561 | } | ||
| 562 | } | ||
| 563 | #endif /* CONFIG_PCI_MSI */ | ||
| 564 | |||
| 565 | tasklet_enable(&bdma_chan->tasklet); | ||
| 566 | tsi721_bdma_interrupt_enable(bdma_chan, 1); | ||
| 567 | |||
| 568 | return bdma_chan->bd_num - 1; | ||
| 569 | |||
| 570 | err_out: | ||
| 571 | kfree(desc); | ||
| 572 | tsi721_bdma_ch_free(bdma_chan); | ||
| 573 | return rc; | ||
| 574 | } | ||
| 575 | |||
| 576 | static void tsi721_free_chan_resources(struct dma_chan *dchan) | ||
| 577 | { | ||
| 578 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | ||
| 579 | #ifdef CONFIG_PCI_MSI | ||
| 580 | struct tsi721_device *priv = to_tsi721(dchan->device); | ||
| 581 | #endif | ||
| 582 | LIST_HEAD(list); | ||
| 583 | |||
| 584 | dev_dbg(dchan->device->dev, "%s: Entry\n", __func__); | ||
| 585 | |||
| 586 | if (bdma_chan->bd_base == NULL) | ||
| 587 | return; | ||
| 588 | |||
| 589 | BUG_ON(!list_empty(&bdma_chan->active_list)); | ||
| 590 | BUG_ON(!list_empty(&bdma_chan->queue)); | ||
| 591 | |||
| 592 | tasklet_disable(&bdma_chan->tasklet); | ||
| 593 | |||
| 594 | spin_lock_bh(&bdma_chan->lock); | ||
| 595 | list_splice_init(&bdma_chan->free_list, &list); | ||
| 596 | spin_unlock_bh(&bdma_chan->lock); | ||
| 597 | |||
| 598 | tsi721_bdma_interrupt_enable(bdma_chan, 0); | ||
| 599 | |||
| 600 | #ifdef CONFIG_PCI_MSI | ||
| 601 | if (priv->flags & TSI721_USING_MSIX) { | ||
| 602 | free_irq(priv->msix[TSI721_VECT_DMA0_DONE + | ||
| 603 | bdma_chan->id].vector, (void *)bdma_chan); | ||
| 604 | free_irq(priv->msix[TSI721_VECT_DMA0_INT + | ||
| 605 | bdma_chan->id].vector, (void *)bdma_chan); | ||
| 606 | } | ||
| 607 | #endif /* CONFIG_PCI_MSI */ | ||
| 608 | |||
| 609 | tsi721_bdma_ch_free(bdma_chan); | ||
| 610 | kfree(bdma_chan->tx_desc); | ||
| 611 | } | ||
| 612 | |||
| 613 | static | ||
| 614 | enum dma_status tsi721_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, | ||
| 615 | struct dma_tx_state *txstate) | ||
| 616 | { | ||
| 617 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | ||
| 618 | dma_cookie_t last_used; | ||
| 619 | dma_cookie_t last_completed; | ||
| 620 | int ret; | ||
| 621 | |||
| 622 | spin_lock_bh(&bdma_chan->lock); | ||
| 623 | last_completed = bdma_chan->completed_cookie; | ||
| 624 | last_used = dchan->cookie; | ||
| 625 | spin_unlock_bh(&bdma_chan->lock); | ||
| 626 | |||
| 627 | ret = dma_async_is_complete(cookie, last_completed, last_used); | ||
| 628 | |||
| 629 | dma_set_tx_state(txstate, last_completed, last_used, 0); | ||
| 630 | |||
| 631 | dev_dbg(dchan->device->dev, | ||
| 632 | "%s: exit, ret: %d, last_completed: %d, last_used: %d\n", | ||
| 633 | __func__, ret, last_completed, last_used); | ||
| 634 | |||
| 635 | return ret; | ||
| 636 | } | ||
| 637 | |||
| 638 | static void tsi721_issue_pending(struct dma_chan *dchan) | ||
| 639 | { | ||
| 640 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | ||
| 641 | |||
| 642 | dev_dbg(dchan->device->dev, "%s: Entry\n", __func__); | ||
| 643 | |||
| 644 | if (tsi721_dma_is_idle(bdma_chan)) { | ||
| 645 | spin_lock_bh(&bdma_chan->lock); | ||
| 646 | tsi721_advance_work(bdma_chan); | ||
| 647 | spin_unlock_bh(&bdma_chan->lock); | ||
| 648 | } else | ||
| 649 | dev_dbg(dchan->device->dev, | ||
| 650 | "%s: DMA channel still busy\n", __func__); | ||
| 651 | } | ||
| 652 | |||
| 653 | static | ||
| 654 | struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan, | ||
| 655 | struct scatterlist *sgl, unsigned int sg_len, | ||
| 656 | enum dma_transfer_direction dir, unsigned long flags, | ||
| 657 | void *tinfo) | ||
| 658 | { | ||
| 659 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | ||
| 660 | struct tsi721_tx_desc *desc = NULL; | ||
| 661 | struct tsi721_tx_desc *first = NULL; | ||
| 662 | struct scatterlist *sg; | ||
| 663 | struct rio_dma_ext *rext = tinfo; | ||
| 664 | u64 rio_addr = rext->rio_addr; /* limited to 64-bit rio_addr for now */ | ||
| 665 | unsigned int i; | ||
| 666 | u32 sys_size = dma_to_mport(dchan->device)->sys_size; | ||
| 667 | enum dma_rtype rtype; | ||
| 668 | |||
| 669 | if (!sgl || !sg_len) { | ||
| 670 | dev_err(dchan->device->dev, "%s: No SG list\n", __func__); | ||
| 671 | return NULL; | ||
| 672 | } | ||
| 673 | |||
| 674 | if (dir == DMA_DEV_TO_MEM) | ||
| 675 | rtype = NREAD; | ||
| 676 | else if (dir == DMA_MEM_TO_DEV) { | ||
| 677 | switch (rext->wr_type) { | ||
| 678 | case RDW_ALL_NWRITE: | ||
| 679 | rtype = ALL_NWRITE; | ||
| 680 | break; | ||
| 681 | case RDW_ALL_NWRITE_R: | ||
| 682 | rtype = ALL_NWRITE_R; | ||
| 683 | break; | ||
| 684 | case RDW_LAST_NWRITE_R: | ||
| 685 | default: | ||
| 686 | rtype = LAST_NWRITE_R; | ||
| 687 | break; | ||
| 688 | } | ||
| 689 | } else { | ||
| 690 | dev_err(dchan->device->dev, | ||
| 691 | "%s: Unsupported DMA direction option\n", __func__); | ||
| 692 | return NULL; | ||
| 693 | } | ||
| 694 | |||
| 695 | for_each_sg(sgl, sg, sg_len, i) { | ||
| 696 | int err; | ||
| 697 | |||
| 698 | dev_dbg(dchan->device->dev, "%s: sg #%d\n", __func__, i); | ||
| 699 | desc = tsi721_desc_get(bdma_chan); | ||
| 700 | if (!desc) { | ||
| 701 | dev_err(dchan->device->dev, | ||
| 702 | "Not enough descriptors available\n"); | ||
| 703 | goto err_desc_get; | ||
| 704 | } | ||
| 705 | |||
| 706 | if (sg_is_last(sg)) | ||
| 707 | desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0; | ||
| 708 | else | ||
| 709 | desc->interrupt = false; | ||
| 710 | |||
| 711 | desc->destid = rext->destid; | ||
| 712 | desc->rio_addr = rio_addr; | ||
| 713 | desc->rio_addr_u = 0; | ||
| 714 | |||
| 715 | err = tsi721_fill_desc(bdma_chan, desc, sg, rtype, sys_size); | ||
| 716 | if (err) { | ||
| 717 | dev_err(dchan->device->dev, | ||
| 718 | "Failed to build desc: %d\n", err); | ||
| 719 | goto err_desc_get; | ||
| 720 | } | ||
| 721 | |||
| 722 | rio_addr += sg_dma_len(sg); | ||
| 723 | |||
| 724 | if (!first) | ||
| 725 | first = desc; | ||
| 726 | else | ||
| 727 | list_add_tail(&desc->desc_node, &first->tx_list); | ||
| 728 | } | ||
| 729 | |||
| 730 | first->txd.cookie = -EBUSY; | ||
| 731 | desc->txd.flags = flags; | ||
| 732 | |||
| 733 | return &first->txd; | ||
| 734 | |||
| 735 | err_desc_get: | ||
| 736 | tsi721_desc_put(bdma_chan, first); | ||
| 737 | return NULL; | ||
| 738 | } | ||
| 739 | |||
| 740 | static int tsi721_device_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, | ||
| 741 | unsigned long arg) | ||
| 742 | { | ||
| 743 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | ||
| 744 | struct tsi721_tx_desc *desc, *_d; | ||
| 745 | LIST_HEAD(list); | ||
| 746 | |||
| 747 | dev_dbg(dchan->device->dev, "%s: Entry\n", __func__); | ||
| 748 | |||
| 749 | if (cmd != DMA_TERMINATE_ALL) | ||
| 750 | return -ENXIO; | ||
| 751 | |||
| 752 | spin_lock_bh(&bdma_chan->lock); | ||
| 753 | |||
| 754 | /* make sure to stop the transfer */ | ||
| 755 | iowrite32(TSI721_DMAC_CTL_SUSP, bdma_chan->regs + TSI721_DMAC_CTL); | ||
| 756 | |||
| 757 | list_splice_init(&bdma_chan->active_list, &list); | ||
| 758 | list_splice_init(&bdma_chan->queue, &list); | ||
| 759 | |||
| 760 | list_for_each_entry_safe(desc, _d, &list, desc_node) | ||
| 761 | tsi721_dma_chain_complete(bdma_chan, desc); | ||
| 762 | |||
| 763 | spin_unlock_bh(&bdma_chan->lock); | ||
| 764 | |||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | int __devinit tsi721_register_dma(struct tsi721_device *priv) | ||
| 769 | { | ||
| 770 | int i; | ||
| 771 | int nr_channels = TSI721_DMA_MAXCH; | ||
| 772 | int err; | ||
| 773 | struct rio_mport *mport = priv->mport; | ||
| 774 | |||
| 775 | mport->dma.dev = &priv->pdev->dev; | ||
| 776 | mport->dma.chancnt = nr_channels; | ||
| 777 | |||
| 778 | INIT_LIST_HEAD(&mport->dma.channels); | ||
| 779 | |||
| 780 | for (i = 0; i < nr_channels; i++) { | ||
| 781 | struct tsi721_bdma_chan *bdma_chan = &priv->bdma[i]; | ||
| 782 | |||
| 783 | if (i == TSI721_DMACH_MAINT) | ||
| 784 | continue; | ||
| 785 | |||
| 786 | bdma_chan->bd_num = 64; | ||
| 787 | bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i); | ||
| 788 | |||
| 789 | bdma_chan->dchan.device = &mport->dma; | ||
| 790 | bdma_chan->dchan.cookie = 1; | ||
| 791 | bdma_chan->dchan.chan_id = i; | ||
| 792 | bdma_chan->id = i; | ||
| 793 | |||
| 794 | spin_lock_init(&bdma_chan->lock); | ||
| 795 | |||
| 796 | INIT_LIST_HEAD(&bdma_chan->active_list); | ||
| 797 | INIT_LIST_HEAD(&bdma_chan->queue); | ||
| 798 | INIT_LIST_HEAD(&bdma_chan->free_list); | ||
| 799 | |||
| 800 | tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet, | ||
| 801 | (unsigned long)bdma_chan); | ||
| 802 | tasklet_disable(&bdma_chan->tasklet); | ||
| 803 | list_add_tail(&bdma_chan->dchan.device_node, | ||
| 804 | &mport->dma.channels); | ||
| 805 | } | ||
| 806 | |||
| 807 | dma_cap_zero(mport->dma.cap_mask); | ||
| 808 | dma_cap_set(DMA_PRIVATE, mport->dma.cap_mask); | ||
| 809 | dma_cap_set(DMA_SLAVE, mport->dma.cap_mask); | ||
| 810 | |||
| 811 | mport->dma.device_alloc_chan_resources = tsi721_alloc_chan_resources; | ||
| 812 | mport->dma.device_free_chan_resources = tsi721_free_chan_resources; | ||
| 813 | mport->dma.device_tx_status = tsi721_tx_status; | ||
| 814 | mport->dma.device_issue_pending = tsi721_issue_pending; | ||
| 815 | mport->dma.device_prep_slave_sg = tsi721_prep_rio_sg; | ||
| 816 | mport->dma.device_control = tsi721_device_control; | ||
| 817 | |||
| 818 | err = dma_async_device_register(&mport->dma); | ||
| 819 | if (err) | ||
| 820 | dev_err(&priv->pdev->dev, "Failed to register DMA device\n"); | ||
| 821 | |||
| 822 | return err; | ||
| 823 | } | ||
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 86c9a091a2ff..c40665a4fa33 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
| @@ -1121,6 +1121,87 @@ int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, | |||
| 1121 | return 0; | 1121 | return 0; |
| 1122 | } | 1122 | } |
| 1123 | 1123 | ||
| 1124 | #ifdef CONFIG_RAPIDIO_DMA_ENGINE | ||
| 1125 | |||
| 1126 | static bool rio_chan_filter(struct dma_chan *chan, void *arg) | ||
| 1127 | { | ||
| 1128 | struct rio_dev *rdev = arg; | ||
| 1129 | |||
| 1130 | /* Check that DMA device belongs to the right MPORT */ | ||
| 1131 | return (rdev->net->hport == | ||
| 1132 | container_of(chan->device, struct rio_mport, dma)); | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | /** | ||
| 1136 | * rio_request_dma - request RapidIO capable DMA channel that supports | ||
| 1137 | * specified target RapidIO device. | ||
| 1138 | * @rdev: RIO device control structure | ||
| 1139 | * | ||
| 1140 | * Returns pointer to allocated DMA channel or NULL if failed. | ||
| 1141 | */ | ||
| 1142 | struct dma_chan *rio_request_dma(struct rio_dev *rdev) | ||
| 1143 | { | ||
| 1144 | dma_cap_mask_t mask; | ||
| 1145 | struct dma_chan *dchan; | ||
| 1146 | |||
| 1147 | dma_cap_zero(mask); | ||
| 1148 | dma_cap_set(DMA_SLAVE, mask); | ||
| 1149 | dchan = dma_request_channel(mask, rio_chan_filter, rdev); | ||
| 1150 | |||
| 1151 | return dchan; | ||
| 1152 | } | ||
| 1153 | EXPORT_SYMBOL_GPL(rio_request_dma); | ||
| 1154 | |||
| 1155 | /** | ||
| 1156 | * rio_release_dma - release specified DMA channel | ||
| 1157 | * @dchan: DMA channel to release | ||
| 1158 | */ | ||
| 1159 | void rio_release_dma(struct dma_chan *dchan) | ||
| 1160 | { | ||
| 1161 | dma_release_channel(dchan); | ||
| 1162 | } | ||
| 1163 | EXPORT_SYMBOL_GPL(rio_release_dma); | ||
| 1164 | |||
| 1165 | /** | ||
| 1166 | * rio_dma_prep_slave_sg - RapidIO specific wrapper | ||
| 1167 | * for device_prep_slave_sg callback defined by DMAENGINE. | ||
| 1168 | * @rdev: RIO device control structure | ||
| 1169 | * @dchan: DMA channel to configure | ||
| 1170 | * @data: RIO specific data descriptor | ||
| 1171 | * @direction: DMA data transfer direction (TO or FROM the device) | ||
| 1172 | * @flags: dmaengine defined flags | ||
| 1173 | * | ||
| 1174 | * Initializes RapidIO capable DMA channel for the specified data transfer. | ||
| 1175 | * Uses DMA channel private extension to pass information related to remote | ||
| 1176 | * target RIO device. | ||
| 1177 | * Returns pointer to DMA transaction descriptor or NULL if failed. | ||
| 1178 | */ | ||
| 1179 | struct dma_async_tx_descriptor *rio_dma_prep_slave_sg(struct rio_dev *rdev, | ||
| 1180 | struct dma_chan *dchan, struct rio_dma_data *data, | ||
| 1181 | enum dma_transfer_direction direction, unsigned long flags) | ||
| 1182 | { | ||
| 1183 | struct dma_async_tx_descriptor *txd = NULL; | ||
| 1184 | struct rio_dma_ext rio_ext; | ||
| 1185 | |||
| 1186 | if (dchan->device->device_prep_slave_sg == NULL) { | ||
| 1187 | pr_err("%s: prep_rio_sg == NULL\n", __func__); | ||
| 1188 | return NULL; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | rio_ext.destid = rdev->destid; | ||
| 1192 | rio_ext.rio_addr_u = data->rio_addr_u; | ||
| 1193 | rio_ext.rio_addr = data->rio_addr; | ||
| 1194 | rio_ext.wr_type = data->wr_type; | ||
| 1195 | |||
| 1196 | txd = dmaengine_prep_rio_sg(dchan, data->sg, data->sg_len, | ||
| 1197 | direction, flags, &rio_ext); | ||
| 1198 | |||
| 1199 | return txd; | ||
| 1200 | } | ||
| 1201 | EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); | ||
| 1202 | |||
| 1203 | #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ | ||
| 1204 | |||
| 1124 | static void rio_fixup_device(struct rio_dev *dev) | 1205 | static void rio_fixup_device(struct rio_dev *dev) |
| 1125 | { | 1206 | { |
| 1126 | } | 1207 | } |
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 35819e312624..6cc4358f68c1 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c | |||
| @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, | |||
| 1033 | if (!retinfo) | 1033 | if (!retinfo) |
| 1034 | return -EFAULT; | 1034 | return -EFAULT; |
| 1035 | memset(&tmp, 0, sizeof(tmp)); | 1035 | memset(&tmp, 0, sizeof(tmp)); |
| 1036 | tty_lock(tty); | 1036 | tty_lock(); |
| 1037 | tmp.line = tty->index; | 1037 | tmp.line = tty->index; |
| 1038 | tmp.port = state->port; | 1038 | tmp.port = state->port; |
| 1039 | tmp.flags = state->tport.flags; | 1039 | tmp.flags = state->tport.flags; |
| @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, | |||
| 1042 | tmp.close_delay = state->tport.close_delay; | 1042 | tmp.close_delay = state->tport.close_delay; |
| 1043 | tmp.closing_wait = state->tport.closing_wait; | 1043 | tmp.closing_wait = state->tport.closing_wait; |
| 1044 | tmp.custom_divisor = state->custom_divisor; | 1044 | tmp.custom_divisor = state->custom_divisor; |
| 1045 | tty_unlock(tty); | 1045 | tty_unlock(); |
| 1046 | if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) | 1046 | if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) |
| 1047 | return -EFAULT; | 1047 | return -EFAULT; |
| 1048 | return 0; | 1048 | return 0; |
| @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, | |||
| 1059 | if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) | 1059 | if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) |
| 1060 | return -EFAULT; | 1060 | return -EFAULT; |
| 1061 | 1061 | ||
| 1062 | tty_lock(tty); | 1062 | tty_lock(); |
| 1063 | change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || | 1063 | change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || |
| 1064 | new_serial.custom_divisor != state->custom_divisor; | 1064 | new_serial.custom_divisor != state->custom_divisor; |
| 1065 | if (new_serial.irq || new_serial.port != state->port || | 1065 | if (new_serial.irq || new_serial.port != state->port || |
| 1066 | new_serial.xmit_fifo_size != state->xmit_fifo_size) { | 1066 | new_serial.xmit_fifo_size != state->xmit_fifo_size) { |
| 1067 | tty_unlock(tty); | 1067 | tty_unlock(); |
| 1068 | return -EINVAL; | 1068 | return -EINVAL; |
| 1069 | } | 1069 | } |
| 1070 | 1070 | ||
| @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, | |||
| 1074 | (new_serial.xmit_fifo_size != state->xmit_fifo_size) || | 1074 | (new_serial.xmit_fifo_size != state->xmit_fifo_size) || |
| 1075 | ((new_serial.flags & ~ASYNC_USR_MASK) != | 1075 | ((new_serial.flags & ~ASYNC_USR_MASK) != |
| 1076 | (port->flags & ~ASYNC_USR_MASK))) { | 1076 | (port->flags & ~ASYNC_USR_MASK))) { |
| 1077 | tty_unlock(tty); | 1077 | tty_unlock(); |
| 1078 | return -EPERM; | 1078 | return -EPERM; |
| 1079 | } | 1079 | } |
| 1080 | port->flags = ((port->flags & ~ASYNC_USR_MASK) | | 1080 | port->flags = ((port->flags & ~ASYNC_USR_MASK) | |
| @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, | |||
| 1084 | } | 1084 | } |
| 1085 | 1085 | ||
| 1086 | if (new_serial.baud_base < 9600) { | 1086 | if (new_serial.baud_base < 9600) { |
| 1087 | tty_unlock(tty); | 1087 | tty_unlock(); |
| 1088 | return -EINVAL; | 1088 | return -EINVAL; |
| 1089 | } | 1089 | } |
| 1090 | 1090 | ||
| @@ -1116,7 +1116,7 @@ check_and_exit: | |||
| 1116 | } | 1116 | } |
| 1117 | } else | 1117 | } else |
| 1118 | retval = startup(tty, state); | 1118 | retval = startup(tty, state); |
| 1119 | tty_unlock(tty); | 1119 | tty_unlock(); |
| 1120 | return retval; | 1120 | return retval; |
| 1121 | } | 1121 | } |
| 1122 | 1122 | ||
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 6984e1a2686a..e61cabdd69df 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c | |||
| @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) | |||
| 1599 | * If the port is the middle of closing, bail out now | 1599 | * If the port is the middle of closing, bail out now |
| 1600 | */ | 1600 | */ |
| 1601 | if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { | 1601 | if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { |
| 1602 | wait_event_interruptible_tty(tty, info->port.close_wait, | 1602 | wait_event_interruptible_tty(info->port.close_wait, |
| 1603 | !(info->port.flags & ASYNC_CLOSING)); | 1603 | !(info->port.flags & ASYNC_CLOSING)); |
| 1604 | return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; | 1604 | return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; |
| 1605 | } | 1605 | } |
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 656ad93bbc96..5c6c31459a2f 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c | |||
| @@ -1065,8 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | |||
| 1065 | 1065 | ||
| 1066 | TRACE_L("read()"); | 1066 | TRACE_L("read()"); |
| 1067 | 1067 | ||
| 1068 | /* FIXME: should use a private lock */ | 1068 | tty_lock(); |
| 1069 | tty_lock(tty); | ||
| 1070 | 1069 | ||
| 1071 | pClient = findClient(pInfo, task_pid(current)); | 1070 | pClient = findClient(pInfo, task_pid(current)); |
| 1072 | if (pClient) { | 1071 | if (pClient) { |
| @@ -1078,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | |||
| 1078 | goto unlock; | 1077 | goto unlock; |
| 1079 | } | 1078 | } |
| 1080 | /* block until there is a message: */ | 1079 | /* block until there is a message: */ |
| 1081 | wait_event_interruptible_tty(tty, pInfo->read_wait, | 1080 | wait_event_interruptible_tty(pInfo->read_wait, |
| 1082 | (pMsg = remove_msg(pInfo, pClient))); | 1081 | (pMsg = remove_msg(pInfo, pClient))); |
| 1083 | } | 1082 | } |
| 1084 | 1083 | ||
| @@ -1108,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | |||
| 1108 | } | 1107 | } |
| 1109 | ret = -EPERM; | 1108 | ret = -EPERM; |
| 1110 | unlock: | 1109 | unlock: |
| 1111 | tty_unlock(tty); | 1110 | tty_unlock(); |
| 1112 | return ret; | 1111 | return ret; |
| 1113 | } | 1112 | } |
| 1114 | 1113 | ||
| @@ -1157,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, | |||
| 1157 | pHeader->locks = 0; | 1156 | pHeader->locks = 0; |
| 1158 | pHeader->owner = NULL; | 1157 | pHeader->owner = NULL; |
| 1159 | 1158 | ||
| 1160 | tty_lock(tty); | 1159 | tty_lock(); |
| 1161 | 1160 | ||
| 1162 | pClient = findClient(pInfo, task_pid(current)); | 1161 | pClient = findClient(pInfo, task_pid(current)); |
| 1163 | if (pClient) { | 1162 | if (pClient) { |
| @@ -1176,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, | |||
| 1176 | add_tx_queue(pInfo, pHeader); | 1175 | add_tx_queue(pInfo, pHeader); |
| 1177 | trigger_transmit(pInfo); | 1176 | trigger_transmit(pInfo); |
| 1178 | 1177 | ||
| 1179 | tty_unlock(tty); | 1178 | tty_unlock(); |
| 1180 | 1179 | ||
| 1181 | return 0; | 1180 | return 0; |
| 1182 | } | 1181 | } |
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 65c7c62c7aae..5505ffc91da4 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c | |||
| @@ -47,7 +47,6 @@ static void pty_close(struct tty_struct *tty, struct file *filp) | |||
| 47 | wake_up_interruptible(&tty->read_wait); | 47 | wake_up_interruptible(&tty->read_wait); |
| 48 | wake_up_interruptible(&tty->write_wait); | 48 | wake_up_interruptible(&tty->write_wait); |
| 49 | tty->packet = 0; | 49 | tty->packet = 0; |
| 50 | /* Review - krefs on tty_link ?? */ | ||
| 51 | if (!tty->link) | 50 | if (!tty->link) |
| 52 | return; | 51 | return; |
| 53 | tty->link->packet = 0; | 52 | tty->link->packet = 0; |
| @@ -63,9 +62,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) | |||
| 63 | mutex_unlock(&devpts_mutex); | 62 | mutex_unlock(&devpts_mutex); |
| 64 | } | 63 | } |
| 65 | #endif | 64 | #endif |
| 66 | tty_unlock(tty); | 65 | tty_unlock(); |
| 67 | tty_vhangup(tty->link); | 66 | tty_vhangup(tty->link); |
| 68 | tty_lock(tty); | 67 | tty_lock(); |
| 69 | } | 68 | } |
| 70 | } | 69 | } |
| 71 | 70 | ||
| @@ -623,27 +622,26 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
| 623 | return retval; | 622 | return retval; |
| 624 | 623 | ||
| 625 | /* find a device that is not in use. */ | 624 | /* find a device that is not in use. */ |
| 626 | mutex_lock(&devpts_mutex); | 625 | tty_lock(); |
| 627 | index = devpts_new_index(inode); | 626 | index = devpts_new_index(inode); |
| 627 | tty_unlock(); | ||
| 628 | if (index < 0) { | 628 | if (index < 0) { |
| 629 | retval = index; | 629 | retval = index; |
| 630 | goto err_file; | 630 | goto err_file; |
| 631 | } | 631 | } |
| 632 | 632 | ||
| 633 | mutex_unlock(&devpts_mutex); | ||
| 634 | |||
| 635 | mutex_lock(&tty_mutex); | 633 | mutex_lock(&tty_mutex); |
| 634 | mutex_lock(&devpts_mutex); | ||
| 636 | tty = tty_init_dev(ptm_driver, index); | 635 | tty = tty_init_dev(ptm_driver, index); |
| 636 | mutex_unlock(&devpts_mutex); | ||
| 637 | tty_lock(); | ||
| 638 | mutex_unlock(&tty_mutex); | ||
| 637 | 639 | ||
| 638 | if (IS_ERR(tty)) { | 640 | if (IS_ERR(tty)) { |
| 639 | retval = PTR_ERR(tty); | 641 | retval = PTR_ERR(tty); |
| 640 | goto out; | 642 | goto out; |
| 641 | } | 643 | } |
| 642 | 644 | ||
| 643 | /* The tty returned here is locked so we can safely | ||
| 644 | drop the mutex */ | ||
| 645 | mutex_unlock(&tty_mutex); | ||
| 646 | |||
| 647 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | 645 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ |
| 648 | 646 | ||
| 649 | tty_add_file(tty, filp); | 647 | tty_add_file(tty, filp); |
| @@ -656,17 +654,16 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
| 656 | if (retval) | 654 | if (retval) |
| 657 | goto err_release; | 655 | goto err_release; |
| 658 | 656 | ||
| 659 | tty_unlock(tty); | 657 | tty_unlock(); |
| 660 | return 0; | 658 | return 0; |
| 661 | err_release: | 659 | err_release: |
| 662 | tty_unlock(tty); | 660 | tty_unlock(); |
| 663 | tty_release(inode, filp); | 661 | tty_release(inode, filp); |
| 664 | return retval; | 662 | return retval; |
| 665 | out: | 663 | out: |
| 666 | mutex_unlock(&tty_mutex); | ||
| 667 | devpts_kill_index(inode, index); | 664 | devpts_kill_index(inode, index); |
| 665 | tty_unlock(); | ||
| 668 | err_file: | 666 | err_file: |
| 669 | mutex_unlock(&devpts_mutex); | ||
| 670 | tty_free_file(filp); | 667 | tty_free_file(filp); |
| 671 | return retval; | 668 | return retval; |
| 672 | } | 669 | } |
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 7264d4d26717..80b6b1b1f725 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c | |||
| @@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, | |||
| 3976 | */ | 3976 | */ |
| 3977 | if (tty_hung_up_p(filp) || | 3977 | if (tty_hung_up_p(filp) || |
| 3978 | (info->flags & ASYNC_CLOSING)) { | 3978 | (info->flags & ASYNC_CLOSING)) { |
| 3979 | wait_event_interruptible_tty(tty, info->close_wait, | 3979 | wait_event_interruptible_tty(info->close_wait, |
| 3980 | !(info->flags & ASYNC_CLOSING)); | 3980 | !(info->flags & ASYNC_CLOSING)); |
| 3981 | #ifdef SERIAL_DO_RESTART | 3981 | #ifdef SERIAL_DO_RESTART |
| 3982 | if (info->flags & ASYNC_HUP_NOTIFY) | 3982 | if (info->flags & ASYNC_HUP_NOTIFY) |
| @@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, | |||
| 4052 | printk("block_til_ready blocking: ttyS%d, count = %d\n", | 4052 | printk("block_til_ready blocking: ttyS%d, count = %d\n", |
| 4053 | info->line, info->count); | 4053 | info->line, info->count); |
| 4054 | #endif | 4054 | #endif |
| 4055 | tty_unlock(tty); | 4055 | tty_unlock(); |
| 4056 | schedule(); | 4056 | schedule(); |
| 4057 | tty_lock(tty); | 4057 | tty_lock(); |
| 4058 | } | 4058 | } |
| 4059 | set_current_state(TASK_RUNNING); | 4059 | set_current_state(TASK_RUNNING); |
| 4060 | remove_wait_queue(&info->open_wait, &wait); | 4060 | remove_wait_queue(&info->open_wait, &wait); |
| @@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp) | |||
| 4115 | */ | 4115 | */ |
| 4116 | if (tty_hung_up_p(filp) || | 4116 | if (tty_hung_up_p(filp) || |
| 4117 | (info->flags & ASYNC_CLOSING)) { | 4117 | (info->flags & ASYNC_CLOSING)) { |
| 4118 | wait_event_interruptible_tty(tty, info->close_wait, | 4118 | wait_event_interruptible_tty(info->close_wait, |
| 4119 | !(info->flags & ASYNC_CLOSING)); | 4119 | !(info->flags & ASYNC_CLOSING)); |
| 4120 | #ifdef SERIAL_DO_RESTART | 4120 | #ifdef SERIAL_DO_RESTART |
| 4121 | return ((info->flags & ASYNC_HUP_NOTIFY) ? | 4121 | return ((info->flags & ASYNC_HUP_NOTIFY) ? |
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 5ed0daae6564..593d40ad0a6b 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c | |||
| @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
| 3338 | printk("%s(%d):block_til_ready blocking on %s count=%d\n", | 3338 | printk("%s(%d):block_til_ready blocking on %s count=%d\n", |
| 3339 | __FILE__,__LINE__, tty->driver->name, port->count ); | 3339 | __FILE__,__LINE__, tty->driver->name, port->count ); |
| 3340 | 3340 | ||
| 3341 | tty_unlock(tty); | 3341 | tty_unlock(); |
| 3342 | schedule(); | 3342 | schedule(); |
| 3343 | tty_lock(tty); | 3343 | tty_lock(); |
| 3344 | } | 3344 | } |
| 3345 | 3345 | ||
| 3346 | set_current_state(TASK_RUNNING); | 3346 | set_current_state(TASK_RUNNING); |
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 45b43f11ca39..aa1debf97cc7 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c | |||
| @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
| 3336 | } | 3336 | } |
| 3337 | 3337 | ||
| 3338 | DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); | 3338 | DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); |
| 3339 | tty_unlock(tty); | 3339 | tty_unlock(); |
| 3340 | schedule(); | 3340 | schedule(); |
| 3341 | tty_lock(tty); | 3341 | tty_lock(); |
| 3342 | } | 3342 | } |
| 3343 | 3343 | ||
| 3344 | set_current_state(TASK_RUNNING); | 3344 | set_current_state(TASK_RUNNING); |
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 4a1e4f07765b..a3dddc12d2fe 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c | |||
| @@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, | |||
| 3357 | printk("%s(%d):%s block_til_ready() count=%d\n", | 3357 | printk("%s(%d):%s block_til_ready() count=%d\n", |
| 3358 | __FILE__,__LINE__, tty->driver->name, port->count ); | 3358 | __FILE__,__LINE__, tty->driver->name, port->count ); |
| 3359 | 3359 | ||
| 3360 | tty_unlock(tty); | 3360 | tty_unlock(); |
| 3361 | schedule(); | 3361 | schedule(); |
| 3362 | tty_lock(tty); | 3362 | tty_lock(); |
| 3363 | } | 3363 | } |
| 3364 | 3364 | ||
| 3365 | set_current_state(TASK_RUNNING); | 3365 | set_current_state(TASK_RUNNING); |
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 9e930c009bf2..b425c79675ad 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c | |||
| @@ -185,7 +185,6 @@ void free_tty_struct(struct tty_struct *tty) | |||
| 185 | put_device(tty->dev); | 185 | put_device(tty->dev); |
| 186 | kfree(tty->write_buf); | 186 | kfree(tty->write_buf); |
| 187 | tty_buffer_free_all(tty); | 187 | tty_buffer_free_all(tty); |
| 188 | tty->magic = 0xDEADDEAD; | ||
| 189 | kfree(tty); | 188 | kfree(tty); |
| 190 | } | 189 | } |
| 191 | 190 | ||
| @@ -574,7 +573,7 @@ void __tty_hangup(struct tty_struct *tty) | |||
| 574 | } | 573 | } |
| 575 | spin_unlock(&redirect_lock); | 574 | spin_unlock(&redirect_lock); |
| 576 | 575 | ||
| 577 | tty_lock(tty); | 576 | tty_lock(); |
| 578 | 577 | ||
| 579 | /* some functions below drop BTM, so we need this bit */ | 578 | /* some functions below drop BTM, so we need this bit */ |
| 580 | set_bit(TTY_HUPPING, &tty->flags); | 579 | set_bit(TTY_HUPPING, &tty->flags); |
| @@ -667,7 +666,7 @@ void __tty_hangup(struct tty_struct *tty) | |||
| 667 | clear_bit(TTY_HUPPING, &tty->flags); | 666 | clear_bit(TTY_HUPPING, &tty->flags); |
| 668 | tty_ldisc_enable(tty); | 667 | tty_ldisc_enable(tty); |
| 669 | 668 | ||
| 670 | tty_unlock(tty); | 669 | tty_unlock(); |
| 671 | 670 | ||
| 672 | if (f) | 671 | if (f) |
| 673 | fput(f); | 672 | fput(f); |
| @@ -1104,12 +1103,12 @@ void tty_write_message(struct tty_struct *tty, char *msg) | |||
| 1104 | { | 1103 | { |
| 1105 | if (tty) { | 1104 | if (tty) { |
| 1106 | mutex_lock(&tty->atomic_write_lock); | 1105 | mutex_lock(&tty->atomic_write_lock); |
| 1107 | tty_lock(tty); | 1106 | tty_lock(); |
| 1108 | if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { | 1107 | if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { |
| 1109 | tty_unlock(tty); | 1108 | tty_unlock(); |
| 1110 | tty->ops->write(tty, msg, strlen(msg)); | 1109 | tty->ops->write(tty, msg, strlen(msg)); |
| 1111 | } else | 1110 | } else |
| 1112 | tty_unlock(tty); | 1111 | tty_unlock(); |
| 1113 | tty_write_unlock(tty); | 1112 | tty_write_unlock(tty); |
| 1114 | } | 1113 | } |
| 1115 | return; | 1114 | return; |
| @@ -1404,7 +1403,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) | |||
| 1404 | } | 1403 | } |
| 1405 | initialize_tty_struct(tty, driver, idx); | 1404 | initialize_tty_struct(tty, driver, idx); |
| 1406 | 1405 | ||
| 1407 | tty_lock(tty); | ||
| 1408 | retval = tty_driver_install_tty(driver, tty); | 1406 | retval = tty_driver_install_tty(driver, tty); |
| 1409 | if (retval < 0) | 1407 | if (retval < 0) |
| 1410 | goto err_deinit_tty; | 1408 | goto err_deinit_tty; |
| @@ -1417,11 +1415,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) | |||
| 1417 | retval = tty_ldisc_setup(tty, tty->link); | 1415 | retval = tty_ldisc_setup(tty, tty->link); |
| 1418 | if (retval) | 1416 | if (retval) |
| 1419 | goto err_release_tty; | 1417 | goto err_release_tty; |
| 1420 | /* Return the tty locked so that it cannot vanish under the caller */ | ||
| 1421 | return tty; | 1418 | return tty; |
| 1422 | 1419 | ||
| 1423 | err_deinit_tty: | 1420 | err_deinit_tty: |
| 1424 | tty_unlock(tty); | ||
| 1425 | deinitialize_tty_struct(tty); | 1421 | deinitialize_tty_struct(tty); |
| 1426 | free_tty_struct(tty); | 1422 | free_tty_struct(tty); |
| 1427 | err_module_put: | 1423 | err_module_put: |
| @@ -1430,7 +1426,6 @@ err_module_put: | |||
| 1430 | 1426 | ||
| 1431 | /* call the tty release_tty routine to clean out this slot */ | 1427 | /* call the tty release_tty routine to clean out this slot */ |
| 1432 | err_release_tty: | 1428 | err_release_tty: |
| 1433 | tty_unlock(tty); | ||
| 1434 | printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " | 1429 | printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " |
| 1435 | "clearing slot %d\n", idx); | 1430 | "clearing slot %d\n", idx); |
| 1436 | release_tty(tty, idx); | 1431 | release_tty(tty, idx); |
| @@ -1633,7 +1628,7 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1633 | if (tty_paranoia_check(tty, inode, __func__)) | 1628 | if (tty_paranoia_check(tty, inode, __func__)) |
| 1634 | return 0; | 1629 | return 0; |
| 1635 | 1630 | ||
| 1636 | tty_lock(tty); | 1631 | tty_lock(); |
| 1637 | check_tty_count(tty, __func__); | 1632 | check_tty_count(tty, __func__); |
| 1638 | 1633 | ||
| 1639 | __tty_fasync(-1, filp, 0); | 1634 | __tty_fasync(-1, filp, 0); |
| @@ -1642,11 +1637,10 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1642 | pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 1637 | pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
| 1643 | tty->driver->subtype == PTY_TYPE_MASTER); | 1638 | tty->driver->subtype == PTY_TYPE_MASTER); |
| 1644 | devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; | 1639 | devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; |
| 1645 | /* Review: parallel close */ | ||
| 1646 | o_tty = tty->link; | 1640 | o_tty = tty->link; |
| 1647 | 1641 | ||
| 1648 | if (tty_release_checks(tty, o_tty, idx)) { | 1642 | if (tty_release_checks(tty, o_tty, idx)) { |
| 1649 | tty_unlock(tty); | 1643 | tty_unlock(); |
| 1650 | return 0; | 1644 | return 0; |
| 1651 | } | 1645 | } |
| 1652 | 1646 | ||
| @@ -1658,7 +1652,7 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1658 | if (tty->ops->close) | 1652 | if (tty->ops->close) |
| 1659 | tty->ops->close(tty, filp); | 1653 | tty->ops->close(tty, filp); |
| 1660 | 1654 | ||
| 1661 | tty_unlock(tty); | 1655 | tty_unlock(); |
| 1662 | /* | 1656 | /* |
| 1663 | * Sanity check: if tty->count is going to zero, there shouldn't be | 1657 | * Sanity check: if tty->count is going to zero, there shouldn't be |
| 1664 | * any waiters on tty->read_wait or tty->write_wait. We test the | 1658 | * any waiters on tty->read_wait or tty->write_wait. We test the |
| @@ -1681,7 +1675,7 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1681 | opens on /dev/tty */ | 1675 | opens on /dev/tty */ |
| 1682 | 1676 | ||
| 1683 | mutex_lock(&tty_mutex); | 1677 | mutex_lock(&tty_mutex); |
| 1684 | tty_lock_pair(tty, o_tty); | 1678 | tty_lock(); |
| 1685 | tty_closing = tty->count <= 1; | 1679 | tty_closing = tty->count <= 1; |
| 1686 | o_tty_closing = o_tty && | 1680 | o_tty_closing = o_tty && |
| 1687 | (o_tty->count <= (pty_master ? 1 : 0)); | 1681 | (o_tty->count <= (pty_master ? 1 : 0)); |
| @@ -1712,7 +1706,7 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1712 | 1706 | ||
| 1713 | printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", | 1707 | printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", |
| 1714 | __func__, tty_name(tty, buf)); | 1708 | __func__, tty_name(tty, buf)); |
| 1715 | tty_unlock_pair(tty, o_tty); | 1709 | tty_unlock(); |
| 1716 | mutex_unlock(&tty_mutex); | 1710 | mutex_unlock(&tty_mutex); |
| 1717 | schedule(); | 1711 | schedule(); |
| 1718 | } | 1712 | } |
| @@ -1775,7 +1769,7 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1775 | 1769 | ||
| 1776 | /* check whether both sides are closing ... */ | 1770 | /* check whether both sides are closing ... */ |
| 1777 | if (!tty_closing || (o_tty && !o_tty_closing)) { | 1771 | if (!tty_closing || (o_tty && !o_tty_closing)) { |
| 1778 | tty_unlock_pair(tty, o_tty); | 1772 | tty_unlock(); |
| 1779 | return 0; | 1773 | return 0; |
| 1780 | } | 1774 | } |
| 1781 | 1775 | ||
| @@ -1788,16 +1782,14 @@ int tty_release(struct inode *inode, struct file *filp) | |||
| 1788 | tty_ldisc_release(tty, o_tty); | 1782 | tty_ldisc_release(tty, o_tty); |
| 1789 | /* | 1783 | /* |
| 1790 | * The release_tty function takes care of the details of clearing | 1784 | * The release_tty function takes care of the details of clearing |
| 1791 | * the slots and preserving the termios structure. The tty_unlock_pair | 1785 | * the slots and preserving the termios structure. |
| 1792 | * should be safe as we keep a kref while the tty is locked (so the | ||
| 1793 | * unlock never unlocks a freed tty). | ||
| 1794 | */ | 1786 | */ |
| 1795 | release_tty(tty, idx); | 1787 | release_tty(tty, idx); |
| 1796 | tty_unlock_pair(tty, o_tty); | ||
| 1797 | 1788 | ||
| 1798 | /* Make this pty number available for reallocation */ | 1789 | /* Make this pty number available for reallocation */ |
| 1799 | if (devpts) | 1790 | if (devpts) |
| 1800 | devpts_kill_index(inode, idx); | 1791 | devpts_kill_index(inode, idx); |
| 1792 | tty_unlock(); | ||
| 1801 | return 0; | 1793 | return 0; |
| 1802 | } | 1794 | } |
| 1803 | 1795 | ||
| @@ -1901,9 +1893,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, | |||
| 1901 | * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. | 1893 | * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. |
| 1902 | * tty->count should protect the rest. | 1894 | * tty->count should protect the rest. |
| 1903 | * ->siglock protects ->signal/->sighand | 1895 | * ->siglock protects ->signal/->sighand |
| 1904 | * | ||
| 1905 | * Note: the tty_unlock/lock cases without a ref are only safe due to | ||
| 1906 | * tty_mutex | ||
| 1907 | */ | 1896 | */ |
| 1908 | 1897 | ||
| 1909 | static int tty_open(struct inode *inode, struct file *filp) | 1898 | static int tty_open(struct inode *inode, struct file *filp) |
| @@ -1927,7 +1916,8 @@ retry_open: | |||
| 1927 | retval = 0; | 1916 | retval = 0; |
| 1928 | 1917 | ||
| 1929 | mutex_lock(&tty_mutex); | 1918 | mutex_lock(&tty_mutex); |
| 1930 | /* This is protected by the tty_mutex */ | 1919 | tty_lock(); |
| 1920 | |||
| 1931 | tty = tty_open_current_tty(device, filp); | 1921 | tty = tty_open_current_tty(device, filp); |
| 1932 | if (IS_ERR(tty)) { | 1922 | if (IS_ERR(tty)) { |
| 1933 | retval = PTR_ERR(tty); | 1923 | retval = PTR_ERR(tty); |
| @@ -1948,19 +1938,17 @@ retry_open: | |||
| 1948 | } | 1938 | } |
| 1949 | 1939 | ||
| 1950 | if (tty) { | 1940 | if (tty) { |
| 1951 | tty_lock(tty); | ||
| 1952 | retval = tty_reopen(tty); | 1941 | retval = tty_reopen(tty); |
| 1953 | if (retval < 0) { | 1942 | if (retval) |
| 1954 | tty_unlock(tty); | ||
| 1955 | tty = ERR_PTR(retval); | 1943 | tty = ERR_PTR(retval); |
| 1956 | } | 1944 | } else |
| 1957 | } else /* Returns with the tty_lock held for now */ | ||
| 1958 | tty = tty_init_dev(driver, index); | 1945 | tty = tty_init_dev(driver, index); |
| 1959 | 1946 | ||
| 1960 | mutex_unlock(&tty_mutex); | 1947 | mutex_unlock(&tty_mutex); |
| 1961 | if (driver) | 1948 | if (driver) |
| 1962 | tty_driver_kref_put(driver); | 1949 | tty_driver_kref_put(driver); |
| 1963 | if (IS_ERR(tty)) { | 1950 | if (IS_ERR(tty)) { |
| 1951 | tty_unlock(); | ||
| 1964 | retval = PTR_ERR(tty); | 1952 | retval = PTR_ERR(tty); |
| 1965 | goto err_file; | 1953 | goto err_file; |
| 1966 | } | 1954 | } |
| @@ -1989,7 +1977,7 @@ retry_open: | |||
| 1989 | printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, | 1977 | printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, |
| 1990 | retval, tty->name); | 1978 | retval, tty->name); |
| 1991 | #endif | 1979 | #endif |
| 1992 | tty_unlock(tty); /* need to call tty_release without BTM */ | 1980 | tty_unlock(); /* need to call tty_release without BTM */ |
| 1993 | tty_release(inode, filp); | 1981 | tty_release(inode, filp); |
| 1994 | if (retval != -ERESTARTSYS) | 1982 | if (retval != -ERESTARTSYS) |
| 1995 | return retval; | 1983 | return retval; |
| @@ -2001,15 +1989,17 @@ retry_open: | |||
| 2001 | /* | 1989 | /* |
| 2002 | * Need to reset f_op in case a hangup happened. | 1990 | * Need to reset f_op in case a hangup happened. |
| 2003 | */ | 1991 | */ |
| 1992 | tty_lock(); | ||
| 2004 | if (filp->f_op == &hung_up_tty_fops) | 1993 | if (filp->f_op == &hung_up_tty_fops) |
| 2005 | filp->f_op = &tty_fops; | 1994 | filp->f_op = &tty_fops; |
| 1995 | tty_unlock(); | ||
| 2006 | goto retry_open; | 1996 | goto retry_open; |
| 2007 | } | 1997 | } |
| 2008 | tty_unlock(tty); | 1998 | tty_unlock(); |
| 2009 | 1999 | ||
| 2010 | 2000 | ||
| 2011 | mutex_lock(&tty_mutex); | 2001 | mutex_lock(&tty_mutex); |
| 2012 | tty_lock(tty); | 2002 | tty_lock(); |
| 2013 | spin_lock_irq(¤t->sighand->siglock); | 2003 | spin_lock_irq(¤t->sighand->siglock); |
| 2014 | if (!noctty && | 2004 | if (!noctty && |
| 2015 | current->signal->leader && | 2005 | current->signal->leader && |
| @@ -2017,10 +2007,11 @@ retry_open: | |||
| 2017 | tty->session == NULL) | 2007 | tty->session == NULL) |
| 2018 | __proc_set_tty(current, tty); | 2008 | __proc_set_tty(current, tty); |
| 2019 | spin_unlock_irq(¤t->sighand->siglock); | 2009 | spin_unlock_irq(¤t->sighand->siglock); |
| 2020 | tty_unlock(tty); | 2010 | tty_unlock(); |
| 2021 | mutex_unlock(&tty_mutex); | 2011 | mutex_unlock(&tty_mutex); |
| 2022 | return 0; | 2012 | return 0; |
| 2023 | err_unlock: | 2013 | err_unlock: |
| 2014 | tty_unlock(); | ||
| 2024 | mutex_unlock(&tty_mutex); | 2015 | mutex_unlock(&tty_mutex); |
| 2025 | /* after locks to avoid deadlock */ | 2016 | /* after locks to avoid deadlock */ |
| 2026 | if (!IS_ERR_OR_NULL(driver)) | 2017 | if (!IS_ERR_OR_NULL(driver)) |
| @@ -2103,13 +2094,10 @@ out: | |||
| 2103 | 2094 | ||
| 2104 | static int tty_fasync(int fd, struct file *filp, int on) | 2095 | static int tty_fasync(int fd, struct file *filp, int on) |
| 2105 | { | 2096 | { |
| 2106 | struct tty_struct *tty = file_tty(filp); | ||
| 2107 | int retval; | 2097 | int retval; |
| 2108 | 2098 | tty_lock(); | |
| 2109 | tty_lock(tty); | ||
| 2110 | retval = __tty_fasync(fd, filp, on); | 2099 | retval = __tty_fasync(fd, filp, on); |
| 2111 | tty_unlock(tty); | 2100 | tty_unlock(); |
| 2112 | |||
| 2113 | return retval; | 2101 | return retval; |
| 2114 | } | 2102 | } |
| 2115 | 2103 | ||
| @@ -2946,7 +2934,6 @@ void initialize_tty_struct(struct tty_struct *tty, | |||
| 2946 | tty->pgrp = NULL; | 2934 | tty->pgrp = NULL; |
| 2947 | tty->overrun_time = jiffies; | 2935 | tty->overrun_time = jiffies; |
| 2948 | tty_buffer_init(tty); | 2936 | tty_buffer_init(tty); |
| 2949 | mutex_init(&tty->legacy_mutex); | ||
| 2950 | mutex_init(&tty->termios_mutex); | 2937 | mutex_init(&tty->termios_mutex); |
| 2951 | mutex_init(&tty->ldisc_mutex); | 2938 | mutex_init(&tty->ldisc_mutex); |
| 2952 | init_waitqueue_head(&tty->write_wait); | 2939 | init_waitqueue_head(&tty->write_wait); |
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index ba8be396a621..9911eb6b34cd 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
| @@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 568 | if (IS_ERR(new_ldisc)) | 568 | if (IS_ERR(new_ldisc)) |
| 569 | return PTR_ERR(new_ldisc); | 569 | return PTR_ERR(new_ldisc); |
| 570 | 570 | ||
| 571 | tty_lock(tty); | 571 | tty_lock(); |
| 572 | /* | 572 | /* |
| 573 | * We need to look at the tty locking here for pty/tty pairs | 573 | * We need to look at the tty locking here for pty/tty pairs |
| 574 | * when both sides try to change in parallel. | 574 | * when both sides try to change in parallel. |
| @@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 582 | */ | 582 | */ |
| 583 | 583 | ||
| 584 | if (tty->ldisc->ops->num == ldisc) { | 584 | if (tty->ldisc->ops->num == ldisc) { |
| 585 | tty_unlock(tty); | 585 | tty_unlock(); |
| 586 | tty_ldisc_put(new_ldisc); | 586 | tty_ldisc_put(new_ldisc); |
| 587 | return 0; | 587 | return 0; |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | tty_unlock(tty); | 590 | tty_unlock(); |
| 591 | /* | 591 | /* |
| 592 | * Problem: What do we do if this blocks ? | 592 | * Problem: What do we do if this blocks ? |
| 593 | * We could deadlock here | 593 | * We could deadlock here |
| @@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 595 | 595 | ||
| 596 | tty_wait_until_sent(tty, 0); | 596 | tty_wait_until_sent(tty, 0); |
| 597 | 597 | ||
| 598 | tty_lock(tty); | 598 | tty_lock(); |
| 599 | mutex_lock(&tty->ldisc_mutex); | 599 | mutex_lock(&tty->ldisc_mutex); |
| 600 | 600 | ||
| 601 | /* | 601 | /* |
| @@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 605 | 605 | ||
| 606 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | 606 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { |
| 607 | mutex_unlock(&tty->ldisc_mutex); | 607 | mutex_unlock(&tty->ldisc_mutex); |
| 608 | tty_unlock(tty); | 608 | tty_unlock(); |
| 609 | wait_event(tty_ldisc_wait, | 609 | wait_event(tty_ldisc_wait, |
| 610 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); | 610 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); |
| 611 | tty_lock(tty); | 611 | tty_lock(); |
| 612 | mutex_lock(&tty->ldisc_mutex); | 612 | mutex_lock(&tty->ldisc_mutex); |
| 613 | } | 613 | } |
| 614 | 614 | ||
| @@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 623 | 623 | ||
| 624 | o_ldisc = tty->ldisc; | 624 | o_ldisc = tty->ldisc; |
| 625 | 625 | ||
| 626 | tty_unlock(tty); | 626 | tty_unlock(); |
| 627 | /* | 627 | /* |
| 628 | * Make sure we don't change while someone holds a | 628 | * Make sure we don't change while someone holds a |
| 629 | * reference to the line discipline. The TTY_LDISC bit | 629 | * reference to the line discipline. The TTY_LDISC bit |
| @@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 650 | 650 | ||
| 651 | retval = tty_ldisc_wait_idle(tty, 5 * HZ); | 651 | retval = tty_ldisc_wait_idle(tty, 5 * HZ); |
| 652 | 652 | ||
| 653 | tty_lock(tty); | 653 | tty_lock(); |
| 654 | mutex_lock(&tty->ldisc_mutex); | 654 | mutex_lock(&tty->ldisc_mutex); |
| 655 | 655 | ||
| 656 | /* handle wait idle failure locked */ | 656 | /* handle wait idle failure locked */ |
| @@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 665 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | 665 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); |
| 666 | mutex_unlock(&tty->ldisc_mutex); | 666 | mutex_unlock(&tty->ldisc_mutex); |
| 667 | tty_ldisc_put(new_ldisc); | 667 | tty_ldisc_put(new_ldisc); |
| 668 | tty_unlock(tty); | 668 | tty_unlock(); |
| 669 | return -EIO; | 669 | return -EIO; |
| 670 | } | 670 | } |
| 671 | 671 | ||
| @@ -708,7 +708,7 @@ enable: | |||
| 708 | if (o_work) | 708 | if (o_work) |
| 709 | schedule_work(&o_tty->buf.work); | 709 | schedule_work(&o_tty->buf.work); |
| 710 | mutex_unlock(&tty->ldisc_mutex); | 710 | mutex_unlock(&tty->ldisc_mutex); |
| 711 | tty_unlock(tty); | 711 | tty_unlock(); |
| 712 | return retval; | 712 | return retval; |
| 713 | } | 713 | } |
| 714 | 714 | ||
| @@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
| 816 | * need to wait for another function taking the BTM | 816 | * need to wait for another function taking the BTM |
| 817 | */ | 817 | */ |
| 818 | clear_bit(TTY_LDISC, &tty->flags); | 818 | clear_bit(TTY_LDISC, &tty->flags); |
| 819 | tty_unlock(tty); | 819 | tty_unlock(); |
| 820 | cancel_work_sync(&tty->buf.work); | 820 | cancel_work_sync(&tty->buf.work); |
| 821 | mutex_unlock(&tty->ldisc_mutex); | 821 | mutex_unlock(&tty->ldisc_mutex); |
| 822 | retry: | 822 | retry: |
| 823 | tty_lock(tty); | 823 | tty_lock(); |
| 824 | mutex_lock(&tty->ldisc_mutex); | 824 | mutex_lock(&tty->ldisc_mutex); |
| 825 | 825 | ||
| 826 | /* At this point we have a closed ldisc and we want to | 826 | /* At this point we have a closed ldisc and we want to |
| @@ -831,7 +831,7 @@ retry: | |||
| 831 | if (atomic_read(&tty->ldisc->users) != 1) { | 831 | if (atomic_read(&tty->ldisc->users) != 1) { |
| 832 | char cur_n[TASK_COMM_LEN], tty_n[64]; | 832 | char cur_n[TASK_COMM_LEN], tty_n[64]; |
| 833 | long timeout = 3 * HZ; | 833 | long timeout = 3 * HZ; |
| 834 | tty_unlock(tty); | 834 | tty_unlock(); |
| 835 | 835 | ||
| 836 | while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { | 836 | while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { |
| 837 | timeout = MAX_SCHEDULE_TIMEOUT; | 837 | timeout = MAX_SCHEDULE_TIMEOUT; |
| @@ -894,23 +894,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | |||
| 894 | tty_ldisc_enable(tty); | 894 | tty_ldisc_enable(tty); |
| 895 | return 0; | 895 | return 0; |
| 896 | } | 896 | } |
| 897 | |||
| 898 | static void tty_ldisc_kill(struct tty_struct *tty) | ||
| 899 | { | ||
| 900 | mutex_lock(&tty->ldisc_mutex); | ||
| 901 | /* | ||
| 902 | * Now kill off the ldisc | ||
| 903 | */ | ||
| 904 | tty_ldisc_close(tty, tty->ldisc); | ||
| 905 | tty_ldisc_put(tty->ldisc); | ||
| 906 | /* Force an oops if we mess this up */ | ||
| 907 | tty->ldisc = NULL; | ||
| 908 | |||
| 909 | /* Ensure the next open requests the N_TTY ldisc */ | ||
| 910 | tty_set_termios_ldisc(tty, N_TTY); | ||
| 911 | mutex_unlock(&tty->ldisc_mutex); | ||
| 912 | } | ||
| 913 | |||
| 914 | /** | 897 | /** |
| 915 | * tty_ldisc_release - release line discipline | 898 | * tty_ldisc_release - release line discipline |
| 916 | * @tty: tty being shut down | 899 | * @tty: tty being shut down |
| @@ -929,19 +912,27 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
| 929 | * race with the set_ldisc code path. | 912 | * race with the set_ldisc code path. |
| 930 | */ | 913 | */ |
| 931 | 914 | ||
| 932 | tty_unlock_pair(tty, o_tty); | 915 | tty_unlock(); |
| 933 | tty_ldisc_halt(tty); | 916 | tty_ldisc_halt(tty); |
| 934 | tty_ldisc_flush_works(tty); | 917 | tty_ldisc_flush_works(tty); |
| 935 | if (o_tty) { | 918 | tty_lock(); |
| 936 | tty_ldisc_halt(o_tty); | ||
| 937 | tty_ldisc_flush_works(o_tty); | ||
| 938 | } | ||
| 939 | tty_lock_pair(tty, o_tty); | ||
| 940 | 919 | ||
| 920 | mutex_lock(&tty->ldisc_mutex); | ||
| 921 | /* | ||
| 922 | * Now kill off the ldisc | ||
| 923 | */ | ||
| 924 | tty_ldisc_close(tty, tty->ldisc); | ||
| 925 | tty_ldisc_put(tty->ldisc); | ||
| 926 | /* Force an oops if we mess this up */ | ||
| 927 | tty->ldisc = NULL; | ||
| 928 | |||
| 929 | /* Ensure the next open requests the N_TTY ldisc */ | ||
| 930 | tty_set_termios_ldisc(tty, N_TTY); | ||
| 931 | mutex_unlock(&tty->ldisc_mutex); | ||
| 941 | 932 | ||
| 942 | tty_ldisc_kill(tty); | 933 | /* This will need doing differently if we need to lock */ |
| 943 | if (o_tty) | 934 | if (o_tty) |
| 944 | tty_ldisc_kill(o_tty); | 935 | tty_ldisc_release(o_tty, NULL); |
| 945 | 936 | ||
| 946 | /* And the memory resources remaining (buffers, termios) will be | 937 | /* And the memory resources remaining (buffers, termios) will be |
| 947 | disposed of when the kref hits zero */ | 938 | disposed of when the kref hits zero */ |
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 67feac9e6ebb..9ff986c32a21 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c | |||
| @@ -4,70 +4,29 @@ | |||
| 4 | #include <linux/semaphore.h> | 4 | #include <linux/semaphore.h> |
| 5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
| 6 | 6 | ||
| 7 | /* Legacy tty mutex glue */ | 7 | /* |
| 8 | 8 | * The 'big tty mutex' | |
| 9 | enum { | 9 | * |
| 10 | TTY_MUTEX_NORMAL, | 10 | * This mutex is taken and released by tty_lock() and tty_unlock(), |
| 11 | TTY_MUTEX_NESTED, | 11 | * replacing the older big kernel lock. |
| 12 | }; | 12 | * It can no longer be taken recursively, and does not get |
| 13 | * released implicitly while sleeping. | ||
| 14 | * | ||
| 15 | * Don't use in new code. | ||
| 16 | */ | ||
| 17 | static DEFINE_MUTEX(big_tty_mutex); | ||
| 13 | 18 | ||
| 14 | /* | 19 | /* |
| 15 | * Getting the big tty mutex. | 20 | * Getting the big tty mutex. |
| 16 | */ | 21 | */ |
| 17 | 22 | void __lockfunc tty_lock(void) | |
| 18 | static void __lockfunc tty_lock_nested(struct tty_struct *tty, | ||
| 19 | unsigned int subclass) | ||
| 20 | { | 23 | { |
| 21 | if (tty->magic != TTY_MAGIC) { | 24 | mutex_lock(&big_tty_mutex); |
| 22 | printk(KERN_ERR "L Bad %p\n", tty); | ||
| 23 | WARN_ON(1); | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | tty_kref_get(tty); | ||
| 27 | mutex_lock_nested(&tty->legacy_mutex, subclass); | ||
| 28 | } | ||
| 29 | |||
| 30 | void __lockfunc tty_lock(struct tty_struct *tty) | ||
| 31 | { | ||
| 32 | return tty_lock_nested(tty, TTY_MUTEX_NORMAL); | ||
| 33 | } | 25 | } |
| 34 | EXPORT_SYMBOL(tty_lock); | 26 | EXPORT_SYMBOL(tty_lock); |
| 35 | 27 | ||
| 36 | void __lockfunc tty_unlock(struct tty_struct *tty) | 28 | void __lockfunc tty_unlock(void) |
| 37 | { | 29 | { |
| 38 | if (tty->magic != TTY_MAGIC) { | 30 | mutex_unlock(&big_tty_mutex); |
| 39 | printk(KERN_ERR "U Bad %p\n", tty); | ||
| 40 | WARN_ON(1); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | mutex_unlock(&tty->legacy_mutex); | ||
| 44 | tty_kref_put(tty); | ||
| 45 | } | 31 | } |
| 46 | EXPORT_SYMBOL(tty_unlock); | 32 | EXPORT_SYMBOL(tty_unlock); |
| 47 | |||
| 48 | /* | ||
| 49 | * Getting the big tty mutex for a pair of ttys with lock ordering | ||
| 50 | * On a non pty/tty pair tty2 can be NULL which is just fine. | ||
| 51 | */ | ||
| 52 | void __lockfunc tty_lock_pair(struct tty_struct *tty, | ||
| 53 | struct tty_struct *tty2) | ||
| 54 | { | ||
| 55 | if (tty < tty2) { | ||
| 56 | tty_lock(tty); | ||
| 57 | tty_lock_nested(tty2, TTY_MUTEX_NESTED); | ||
| 58 | } else { | ||
| 59 | if (tty2 && tty2 != tty) | ||
| 60 | tty_lock(tty2); | ||
| 61 | tty_lock_nested(tty, TTY_MUTEX_NESTED); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL(tty_lock_pair); | ||
| 65 | |||
| 66 | void __lockfunc tty_unlock_pair(struct tty_struct *tty, | ||
| 67 | struct tty_struct *tty2) | ||
| 68 | { | ||
| 69 | tty_unlock(tty); | ||
| 70 | if (tty2 && tty2 != tty) | ||
| 71 | tty_unlock(tty2); | ||
| 72 | } | ||
| 73 | EXPORT_SYMBOL(tty_unlock_pair); | ||
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index d9cca95a5452..bf6e238146ae 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c | |||
| @@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port, | |||
| 230 | 230 | ||
| 231 | /* block if port is in the process of being closed */ | 231 | /* block if port is in the process of being closed */ |
| 232 | if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { | 232 | if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { |
| 233 | wait_event_interruptible_tty(tty, port->close_wait, | 233 | wait_event_interruptible_tty(port->close_wait, |
| 234 | !(port->flags & ASYNC_CLOSING)); | 234 | !(port->flags & ASYNC_CLOSING)); |
| 235 | if (port->flags & ASYNC_HUP_NOTIFY) | 235 | if (port->flags & ASYNC_HUP_NOTIFY) |
| 236 | return -EAGAIN; | 236 | return -EAGAIN; |
| @@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port, | |||
| 296 | retval = -ERESTARTSYS; | 296 | retval = -ERESTARTSYS; |
| 297 | break; | 297 | break; |
| 298 | } | 298 | } |
| 299 | tty_unlock(tty); | 299 | tty_unlock(); |
| 300 | schedule(); | 300 | schedule(); |
| 301 | tty_lock(tty); | 301 | tty_lock(); |
| 302 | } | 302 | } |
| 303 | finish_wait(&port->open_wait, &wait); | 303 | finish_wait(&port->open_wait, &wait); |
| 304 | 304 | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a290be51a1f4..0217f7415ef5 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
| @@ -2210,7 +2210,7 @@ config FB_XILINX | |||
| 2210 | 2210 | ||
| 2211 | config FB_COBALT | 2211 | config FB_COBALT |
| 2212 | tristate "Cobalt server LCD frame buffer support" | 2212 | tristate "Cobalt server LCD frame buffer support" |
| 2213 | depends on FB && MIPS_COBALT | 2213 | depends on FB && (MIPS_COBALT || MIPS_SEAD3) |
| 2214 | 2214 | ||
| 2215 | config FB_SH7760 | 2215 | config FB_SH7760 |
| 2216 | bool "SH7760/SH7763/SH7720/SH7721 LCDC support" | 2216 | bool "SH7760/SH7763/SH7720/SH7721 LCDC support" |
| @@ -2382,6 +2382,39 @@ config FB_BROADSHEET | |||
| 2382 | and could also have been called by other names when coupled with | 2382 | and could also have been called by other names when coupled with |
| 2383 | a bridge adapter. | 2383 | a bridge adapter. |
| 2384 | 2384 | ||
| 2385 | config FB_AUO_K190X | ||
| 2386 | tristate "AUO-K190X EPD controller support" | ||
| 2387 | depends on FB | ||
| 2388 | select FB_SYS_FILLRECT | ||
| 2389 | select FB_SYS_COPYAREA | ||
| 2390 | select FB_SYS_IMAGEBLIT | ||
| 2391 | select FB_SYS_FOPS | ||
| 2392 | select FB_DEFERRED_IO | ||
| 2393 | help | ||
| 2394 | Provides support for epaper controllers from the K190X series | ||
| 2395 | of AUO. These controllers can be used to drive epaper displays | ||
| 2396 | from Sipix. | ||
| 2397 | |||
| 2398 | This option enables the common support, shared by the individual | ||
| 2399 | controller drivers. You will also have to enable the driver | ||
| 2400 | for the controller type used in your device. | ||
| 2401 | |||
| 2402 | config FB_AUO_K1900 | ||
| 2403 | tristate "AUO-K1900 EPD controller support" | ||
| 2404 | depends on FB && FB_AUO_K190X | ||
| 2405 | help | ||
| 2406 | This driver implements support for the AUO K1900 epd-controller. | ||
| 2407 | This controller can drive Sipix epaper displays but can only do | ||
| 2408 | serial updates, reducing the number of possible frames per second. | ||
| 2409 | |||
| 2410 | config FB_AUO_K1901 | ||
| 2411 | tristate "AUO-K1901 EPD controller support" | ||
| 2412 | depends on FB && FB_AUO_K190X | ||
| 2413 | help | ||
| 2414 | This driver implements support for the AUO K1901 epd-controller. | ||
| 2415 | This controller can drive Sipix epaper displays and supports | ||
| 2416 | concurrent updates, making higher frames per second possible. | ||
| 2417 | |||
| 2385 | config FB_JZ4740 | 2418 | config FB_JZ4740 |
| 2386 | tristate "JZ4740 LCD framebuffer support" | 2419 | tristate "JZ4740 LCD framebuffer support" |
| 2387 | depends on FB && MACH_JZ4740 | 2420 | depends on FB && MACH_JZ4740 |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9356add945b3..ee8dafb69e36 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
| @@ -118,6 +118,9 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o | |||
| 118 | obj-$(CONFIG_FB_MAXINE) += maxinefb.o | 118 | obj-$(CONFIG_FB_MAXINE) += maxinefb.o |
| 119 | obj-$(CONFIG_FB_METRONOME) += metronomefb.o | 119 | obj-$(CONFIG_FB_METRONOME) += metronomefb.o |
| 120 | obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o | 120 | obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o |
| 121 | obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o | ||
| 122 | obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o | ||
| 123 | obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o | ||
| 121 | obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o | 124 | obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o |
| 122 | obj-$(CONFIG_FB_SH7760) += sh7760fb.o | 125 | obj-$(CONFIG_FB_SH7760) += sh7760fb.o |
| 123 | obj-$(CONFIG_FB_IMX) += imxfb.o | 126 | obj-$(CONFIG_FB_IMX) += imxfb.o |
diff --git a/drivers/video/auo_k1900fb.c b/drivers/video/auo_k1900fb.c new file mode 100644 index 000000000000..c36cf961dcb2 --- /dev/null +++ b/drivers/video/auo_k1900fb.c | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | /* | ||
| 2 | * auok190xfb.c -- FB driver for AUO-K1900 controllers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de> | ||
| 5 | * | ||
| 6 | * based on broadsheetfb.c | ||
| 7 | * | ||
| 8 | * Copyright (C) 2008, Jaya Kumar | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. | ||
| 15 | * | ||
| 16 | * This driver is written to be used with the AUO-K1900 display controller. | ||
| 17 | * | ||
| 18 | * It is intended to be architecture independent. A board specific driver | ||
| 19 | * must be used to perform all the physical IO interactions. | ||
| 20 | * | ||
| 21 | * The controller supports different update modes: | ||
| 22 | * mode0+1 16 step gray (4bit) | ||
| 23 | * mode2 4 step gray (2bit) - FIXME: add strange refresh | ||
| 24 | * mode3 2 step gray (1bit) - FIXME: add strange refresh | ||
| 25 | * mode4 handwriting mode (strange behaviour) | ||
| 26 | * mode5 automatic selection of update mode | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/kernel.h> | ||
| 31 | #include <linux/errno.h> | ||
| 32 | #include <linux/string.h> | ||
| 33 | #include <linux/mm.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/delay.h> | ||
| 36 | #include <linux/interrupt.h> | ||
| 37 | #include <linux/fb.h> | ||
| 38 | #include <linux/init.h> | ||
| 39 | #include <linux/platform_device.h> | ||
| 40 | #include <linux/list.h> | ||
| 41 | #include <linux/firmware.h> | ||
| 42 | #include <linux/gpio.h> | ||
| 43 | #include <linux/pm_runtime.h> | ||
| 44 | |||
| 45 | #include <video/auo_k190xfb.h> | ||
| 46 | |||
| 47 | #include "auo_k190x.h" | ||
| 48 | |||
| 49 | /* | ||
| 50 | * AUO-K1900 specific commands | ||
| 51 | */ | ||
| 52 | |||
| 53 | #define AUOK1900_CMD_PARTIALDISP 0x1001 | ||
| 54 | #define AUOK1900_CMD_ROTATION 0x1006 | ||
| 55 | #define AUOK1900_CMD_LUT_STOP 0x1009 | ||
| 56 | |||
| 57 | #define AUOK1900_INIT_TEMP_AVERAGE (1 << 13) | ||
| 58 | #define AUOK1900_INIT_ROTATE(_x) ((_x & 0x3) << 10) | ||
| 59 | #define AUOK1900_INIT_RESOLUTION(_res) ((_res & 0x7) << 2) | ||
| 60 | |||
| 61 | static void auok1900_init(struct auok190xfb_par *par) | ||
| 62 | { | ||
| 63 | struct auok190x_board *board = par->board; | ||
| 64 | u16 init_param = 0; | ||
| 65 | |||
| 66 | init_param |= AUOK1900_INIT_TEMP_AVERAGE; | ||
| 67 | init_param |= AUOK1900_INIT_ROTATE(par->rotation); | ||
| 68 | init_param |= AUOK190X_INIT_INVERSE_WHITE; | ||
| 69 | init_param |= AUOK190X_INIT_FORMAT0; | ||
| 70 | init_param |= AUOK1900_INIT_RESOLUTION(par->resolution); | ||
| 71 | init_param |= AUOK190X_INIT_SHIFT_RIGHT; | ||
| 72 | |||
| 73 | auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param); | ||
| 74 | |||
| 75 | /* let the controller finish */ | ||
| 76 | board->wait_for_rdy(par); | ||
| 77 | } | ||
| 78 | |||
| 79 | static void auok1900_update_region(struct auok190xfb_par *par, int mode, | ||
| 80 | u16 y1, u16 y2) | ||
| 81 | { | ||
| 82 | struct device *dev = par->info->device; | ||
| 83 | unsigned char *buf = (unsigned char *)par->info->screen_base; | ||
| 84 | int xres = par->info->var.xres; | ||
| 85 | u16 args[4]; | ||
| 86 | |||
| 87 | pm_runtime_get_sync(dev); | ||
| 88 | |||
| 89 | mutex_lock(&(par->io_lock)); | ||
| 90 | |||
| 91 | /* y1 and y2 must be a multiple of 2 so drop the lowest bit */ | ||
| 92 | y1 &= 0xfffe; | ||
| 93 | y2 &= 0xfffe; | ||
| 94 | |||
| 95 | dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n", | ||
| 96 | 1, y1+1, xres, y2-y1, mode); | ||
| 97 | |||
| 98 | /* to FIX handle different partial update modes */ | ||
| 99 | args[0] = mode | 1; | ||
| 100 | args[1] = y1 + 1; | ||
| 101 | args[2] = xres; | ||
| 102 | args[3] = y2 - y1; | ||
| 103 | buf += y1 * xres; | ||
| 104 | auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args, | ||
| 105 | ((y2 - y1) * xres)/2, (u16 *) buf); | ||
| 106 | auok190x_send_command(par, AUOK190X_CMD_DATA_STOP); | ||
| 107 | |||
| 108 | par->update_cnt++; | ||
| 109 | |||
| 110 | mutex_unlock(&(par->io_lock)); | ||
| 111 | |||
| 112 | pm_runtime_mark_last_busy(dev); | ||
| 113 | pm_runtime_put_autosuspend(dev); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void auok1900fb_dpy_update_pages(struct auok190xfb_par *par, | ||
| 117 | u16 y1, u16 y2) | ||
| 118 | { | ||
| 119 | int mode; | ||
| 120 | |||
| 121 | if (par->update_mode < 0) { | ||
| 122 | mode = AUOK190X_UPDATE_MODE(1); | ||
| 123 | par->last_mode = -1; | ||
| 124 | } else { | ||
| 125 | mode = AUOK190X_UPDATE_MODE(par->update_mode); | ||
| 126 | par->last_mode = par->update_mode; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (par->flash) | ||
| 130 | mode |= AUOK190X_UPDATE_NONFLASH; | ||
| 131 | |||
| 132 | auok1900_update_region(par, mode, y1, y2); | ||
| 133 | } | ||
| 134 | |||
| 135 | static void auok1900fb_dpy_update(struct auok190xfb_par *par) | ||
| 136 | { | ||
| 137 | int mode; | ||
| 138 | |||
| 139 | if (par->update_mode < 0) { | ||
| 140 | mode = AUOK190X_UPDATE_MODE(0); | ||
| 141 | par->last_mode = -1; | ||
| 142 | } else { | ||
| 143 | mode = AUOK190X_UPDATE_MODE(par->update_mode); | ||
| 144 | par->last_mode = par->update_mode; | ||
| 145 | } | ||
| 146 | |||
| 147 | if (par->flash) | ||
| 148 | mode |= AUOK190X_UPDATE_NONFLASH; | ||
| 149 | |||
| 150 | auok1900_update_region(par, mode, 0, par->info->var.yres); | ||
| 151 | par->update_cnt = 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | static bool auok1900fb_need_refresh(struct auok190xfb_par *par) | ||
| 155 | { | ||
| 156 | return (par->update_cnt > 10); | ||
| 157 | } | ||
| 158 | |||
| 159 | static int __devinit auok1900fb_probe(struct platform_device *pdev) | ||
| 160 | { | ||
| 161 | struct auok190x_init_data init; | ||
| 162 | struct auok190x_board *board; | ||
| 163 | |||
| 164 | /* pick up board specific routines */ | ||
| 165 | board = pdev->dev.platform_data; | ||
| 166 | if (!board) | ||
| 167 | return -EINVAL; | ||
| 168 | |||
| 169 | /* fill temporary init struct for common init */ | ||
| 170 | init.id = "auo_k1900fb"; | ||
| 171 | init.board = board; | ||
| 172 | init.update_partial = auok1900fb_dpy_update_pages; | ||
| 173 | init.update_all = auok1900fb_dpy_update; | ||
| 174 | init.need_refresh = auok1900fb_need_refresh; | ||
| 175 | init.init = auok1900_init; | ||
| 176 | |||
| 177 | return auok190x_common_probe(pdev, &init); | ||
| 178 | } | ||
| 179 | |||
| 180 | static int __devexit auok1900fb_remove(struct platform_device *pdev) | ||
| 181 | { | ||
| 182 | return auok190x_common_remove(pdev); | ||
| 183 | } | ||
| 184 | |||
| 185 | static struct platform_driver auok1900fb_driver = { | ||
| 186 | .probe = auok1900fb_probe, | ||
| 187 | .remove = __devexit_p(auok1900fb_remove), | ||
| 188 | .driver = { | ||
| 189 | .owner = THIS_MODULE, | ||
| 190 | .name = "auo_k1900fb", | ||
| 191 | .pm = &auok190x_pm, | ||
| 192 | }, | ||
| 193 | }; | ||
| 194 | module_platform_driver(auok1900fb_driver); | ||
| 195 | |||
| 196 | MODULE_DESCRIPTION("framebuffer driver for the AUO-K1900 EPD controller"); | ||
| 197 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); | ||
| 198 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/auo_k1901fb.c b/drivers/video/auo_k1901fb.c new file mode 100644 index 000000000000..1c054c18616e --- /dev/null +++ b/drivers/video/auo_k1901fb.c | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | /* | ||
| 2 | * auok190xfb.c -- FB driver for AUO-K1901 controllers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de> | ||
| 5 | * | ||
| 6 | * based on broadsheetfb.c | ||
| 7 | * | ||
| 8 | * Copyright (C) 2008, Jaya Kumar | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. | ||
| 15 | * | ||
| 16 | * This driver is written to be used with the AUO-K1901 display controller. | ||
| 17 | * | ||
| 18 | * It is intended to be architecture independent. A board specific driver | ||
| 19 | * must be used to perform all the physical IO interactions. | ||
| 20 | * | ||
| 21 | * The controller supports different update modes: | ||
| 22 | * mode0+1 16 step gray (4bit) | ||
| 23 | * mode2+3 4 step gray (2bit) | ||
| 24 | * mode4+5 2 step gray (1bit) | ||
| 25 | * - mode4 is described as "without LUT" | ||
| 26 | * mode7 automatic selection of update mode | ||
| 27 | * | ||
| 28 | * The most interesting difference to the K1900 is the ability to do screen | ||
| 29 | * updates in an asynchronous fashion. Where the K1900 needs to wait for the | ||
| 30 | * current update to complete, the K1901 can process later updates already. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/module.h> | ||
| 34 | #include <linux/kernel.h> | ||
| 35 | #include <linux/errno.h> | ||
| 36 | #include <linux/string.h> | ||
| 37 | #include <linux/mm.h> | ||
| 38 | #include <linux/slab.h> | ||
| 39 | #include <linux/delay.h> | ||
| 40 | #include <linux/interrupt.h> | ||
| 41 | #include <linux/fb.h> | ||
| 42 | #include <linux/init.h> | ||
| 43 | #include <linux/platform_device.h> | ||
| 44 | #include <linux/list.h> | ||
| 45 | #include <linux/firmware.h> | ||
| 46 | #include <linux/gpio.h> | ||
| 47 | #include <linux/pm_runtime.h> | ||
| 48 | |||
| 49 | #include <video/auo_k190xfb.h> | ||
| 50 | |||
| 51 | #include "auo_k190x.h" | ||
| 52 | |||
| 53 | /* | ||
| 54 | * AUO-K1901 specific commands | ||
| 55 | */ | ||
| 56 | |||
| 57 | #define AUOK1901_CMD_LUT_INTERFACE 0x0005 | ||
| 58 | #define AUOK1901_CMD_DMA_START 0x1001 | ||
| 59 | #define AUOK1901_CMD_CURSOR_START 0x1007 | ||
| 60 | #define AUOK1901_CMD_CURSOR_STOP AUOK190X_CMD_DATA_STOP | ||
| 61 | #define AUOK1901_CMD_DDMA_START 0x1009 | ||
| 62 | |||
| 63 | #define AUOK1901_INIT_GATE_PULSE_LOW (0 << 14) | ||
| 64 | #define AUOK1901_INIT_GATE_PULSE_HIGH (1 << 14) | ||
| 65 | #define AUOK1901_INIT_SINGLE_GATE (0 << 13) | ||
| 66 | #define AUOK1901_INIT_DOUBLE_GATE (1 << 13) | ||
| 67 | |||
| 68 | /* Bits to pixels | ||
| 69 | * Mode 15-12 11-8 7-4 3-0 | ||
| 70 | * format2 2 T 1 T | ||
| 71 | * format3 1 T 2 T | ||
| 72 | * format4 T 2 T 1 | ||
| 73 | * format5 T 1 T 2 | ||
| 74 | * | ||
| 75 | * halftone modes: | ||
| 76 | * format6 2 2 1 1 | ||
| 77 | * format7 1 1 2 2 | ||
| 78 | */ | ||
| 79 | #define AUOK1901_INIT_FORMAT2 (1 << 7) | ||
| 80 | #define AUOK1901_INIT_FORMAT3 ((1 << 7) | (1 << 6)) | ||
| 81 | #define AUOK1901_INIT_FORMAT4 (1 << 8) | ||
| 82 | #define AUOK1901_INIT_FORMAT5 ((1 << 8) | (1 << 6)) | ||
| 83 | #define AUOK1901_INIT_FORMAT6 ((1 << 8) | (1 << 7)) | ||
| 84 | #define AUOK1901_INIT_FORMAT7 ((1 << 8) | (1 << 7) | (1 << 6)) | ||
| 85 | |||
| 86 | /* res[4] to bit 10 | ||
| 87 | * res[3-0] to bits 5-2 | ||
| 88 | */ | ||
| 89 | #define AUOK1901_INIT_RESOLUTION(_res) (((_res & (1 << 4)) << 6) \ | ||
| 90 | | ((_res & 0xf) << 2)) | ||
| 91 | |||
| 92 | /* | ||
| 93 | * portrait / landscape orientation in AUOK1901_CMD_DMA_START | ||
| 94 | */ | ||
| 95 | #define AUOK1901_DMA_ROTATE90(_rot) ((_rot & 1) << 13) | ||
| 96 | |||
| 97 | /* | ||
| 98 | * equivalent to 1 << 11, needs the ~ to have same rotation like K1900 | ||
| 99 | */ | ||
| 100 | #define AUOK1901_DDMA_ROTATE180(_rot) ((~_rot & 2) << 10) | ||
| 101 | |||
| 102 | static void auok1901_init(struct auok190xfb_par *par) | ||
| 103 | { | ||
| 104 | struct auok190x_board *board = par->board; | ||
| 105 | u16 init_param = 0; | ||
| 106 | |||
| 107 | init_param |= AUOK190X_INIT_INVERSE_WHITE; | ||
| 108 | init_param |= AUOK190X_INIT_FORMAT0; | ||
| 109 | init_param |= AUOK1901_INIT_RESOLUTION(par->resolution); | ||
| 110 | init_param |= AUOK190X_INIT_SHIFT_LEFT; | ||
| 111 | |||
| 112 | auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param); | ||
| 113 | |||
| 114 | /* let the controller finish */ | ||
| 115 | board->wait_for_rdy(par); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void auok1901_update_region(struct auok190xfb_par *par, int mode, | ||
| 119 | u16 y1, u16 y2) | ||
| 120 | { | ||
| 121 | struct device *dev = par->info->device; | ||
| 122 | unsigned char *buf = (unsigned char *)par->info->screen_base; | ||
| 123 | int xres = par->info->var.xres; | ||
| 124 | u16 args[5]; | ||
| 125 | |||
| 126 | pm_runtime_get_sync(dev); | ||
| 127 | |||
| 128 | mutex_lock(&(par->io_lock)); | ||
| 129 | |||
| 130 | /* y1 and y2 must be a multiple of 2 so drop the lowest bit */ | ||
| 131 | y1 &= 0xfffe; | ||
| 132 | y2 &= 0xfffe; | ||
| 133 | |||
| 134 | dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n", | ||
| 135 | 1, y1+1, xres, y2-y1, mode); | ||
| 136 | |||
| 137 | /* K1901: first transfer the region data */ | ||
| 138 | args[0] = AUOK1901_DMA_ROTATE90(par->rotation) | 1; | ||
| 139 | args[1] = y1 + 1; | ||
| 140 | args[2] = xres; | ||
| 141 | args[3] = y2 - y1; | ||
| 142 | buf += y1 * xres; | ||
| 143 | auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4, | ||
| 144 | args, ((y2 - y1) * xres)/2, | ||
| 145 | (u16 *) buf); | ||
| 146 | auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP); | ||
| 147 | |||
| 148 | /* K1901: second tell the controller to update the region with mode */ | ||
| 149 | args[0] = mode | AUOK1901_DDMA_ROTATE180(par->rotation); | ||
| 150 | args[1] = 1; | ||
| 151 | args[2] = y1 + 1; | ||
| 152 | args[3] = xres; | ||
| 153 | args[4] = y2 - y1; | ||
| 154 | auok190x_send_cmdargs_nowait(par, AUOK1901_CMD_DDMA_START, 5, args); | ||
| 155 | |||
| 156 | par->update_cnt++; | ||
| 157 | |||
| 158 | mutex_unlock(&(par->io_lock)); | ||
| 159 | |||
| 160 | pm_runtime_mark_last_busy(dev); | ||
| 161 | pm_runtime_put_autosuspend(dev); | ||
| 162 | } | ||
| 163 | |||
| 164 | static void auok1901fb_dpy_update_pages(struct auok190xfb_par *par, | ||
| 165 | u16 y1, u16 y2) | ||
| 166 | { | ||
| 167 | int mode; | ||
| 168 | |||
| 169 | if (par->update_mode < 0) { | ||
| 170 | mode = AUOK190X_UPDATE_MODE(1); | ||
| 171 | par->last_mode = -1; | ||
| 172 | } else { | ||
| 173 | mode = AUOK190X_UPDATE_MODE(par->update_mode); | ||
| 174 | par->last_mode = par->update_mode; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (par->flash) | ||
| 178 | mode |= AUOK190X_UPDATE_NONFLASH; | ||
| 179 | |||
| 180 | auok1901_update_region(par, mode, y1, y2); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void auok1901fb_dpy_update(struct auok190xfb_par *par) | ||
| 184 | { | ||
| 185 | int mode; | ||
| 186 | |||
| 187 | /* When doing full updates, wait for the controller to be ready | ||
| 188 | * This will hopefully catch some hangs of the K1901 | ||
| 189 | */ | ||
| 190 | par->board->wait_for_rdy(par); | ||
| 191 | |||
| 192 | if (par->update_mode < 0) { | ||
| 193 | mode = AUOK190X_UPDATE_MODE(0); | ||
| 194 | par->last_mode = -1; | ||
| 195 | } else { | ||
| 196 | mode = AUOK190X_UPDATE_MODE(par->update_mode); | ||
| 197 | par->last_mode = par->update_mode; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (par->flash) | ||
| 201 | mode |= AUOK190X_UPDATE_NONFLASH; | ||
| 202 | |||
| 203 | auok1901_update_region(par, mode, 0, par->info->var.yres); | ||
| 204 | par->update_cnt = 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | static bool auok1901fb_need_refresh(struct auok190xfb_par *par) | ||
| 208 | { | ||
| 209 | return (par->update_cnt > 10); | ||
| 210 | } | ||
| 211 | |||
| 212 | static int __devinit auok1901fb_probe(struct platform_device *pdev) | ||
| 213 | { | ||
| 214 | struct auok190x_init_data init; | ||
| 215 | struct auok190x_board *board; | ||
| 216 | |||
| 217 | /* pick up board specific routines */ | ||
| 218 | board = pdev->dev.platform_data; | ||
| 219 | if (!board) | ||
| 220 | return -EINVAL; | ||
| 221 | |||
| 222 | /* fill temporary init struct for common init */ | ||
| 223 | init.id = "auo_k1901fb"; | ||
| 224 | init.board = board; | ||
| 225 | init.update_partial = auok1901fb_dpy_update_pages; | ||
| 226 | init.update_all = auok1901fb_dpy_update; | ||
| 227 | init.need_refresh = auok1901fb_need_refresh; | ||
| 228 | init.init = auok1901_init; | ||
| 229 | |||
| 230 | return auok190x_common_probe(pdev, &init); | ||
| 231 | } | ||
| 232 | |||
| 233 | static int __devexit auok1901fb_remove(struct platform_device *pdev) | ||
| 234 | { | ||
| 235 | return auok190x_common_remove(pdev); | ||
| 236 | } | ||
| 237 | |||
| 238 | static struct platform_driver auok1901fb_driver = { | ||
| 239 | .probe = auok1901fb_probe, | ||
| 240 | .remove = __devexit_p(auok1901fb_remove), | ||
| 241 | .driver = { | ||
| 242 | .owner = THIS_MODULE, | ||
| 243 | .name = "auo_k1901fb", | ||
| 244 | .pm = &auok190x_pm, | ||
| 245 | }, | ||
| 246 | }; | ||
| 247 | module_platform_driver(auok1901fb_driver); | ||
| 248 | |||
| 249 | MODULE_DESCRIPTION("framebuffer driver for the AUO-K1901 EPD controller"); | ||
| 250 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); | ||
| 251 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c new file mode 100644 index 000000000000..77da6a2f43dc --- /dev/null +++ b/drivers/video/auo_k190x.c | |||
| @@ -0,0 +1,1046 @@ | |||
| 1 | /* | ||
| 2 | * Common code for AUO-K190X framebuffer drivers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/gpio.h> | ||
| 14 | #include <linux/pm_runtime.h> | ||
| 15 | #include <linux/fb.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/uaccess.h> | ||
| 18 | #include <linux/vmalloc.h> | ||
| 19 | #include <linux/regulator/consumer.h> | ||
| 20 | |||
| 21 | #include <video/auo_k190xfb.h> | ||
| 22 | |||
| 23 | #include "auo_k190x.h" | ||
| 24 | |||
| 25 | struct panel_info { | ||
| 26 | int w; | ||
| 27 | int h; | ||
| 28 | }; | ||
| 29 | |||
| 30 | /* table of panel specific parameters to be indexed into by the board drivers */ | ||
| 31 | static struct panel_info panel_table[] = { | ||
| 32 | /* standard 6" */ | ||
| 33 | [AUOK190X_RESOLUTION_800_600] = { | ||
| 34 | .w = 800, | ||
| 35 | .h = 600, | ||
| 36 | }, | ||
| 37 | /* standard 9" */ | ||
| 38 | [AUOK190X_RESOLUTION_1024_768] = { | ||
| 39 | .w = 1024, | ||
| 40 | .h = 768, | ||
| 41 | }, | ||
| 42 | }; | ||
| 43 | |||
| 44 | /* | ||
| 45 | * private I80 interface to the board driver | ||
| 46 | */ | ||
| 47 | |||
| 48 | static void auok190x_issue_data(struct auok190xfb_par *par, u16 data) | ||
| 49 | { | ||
| 50 | par->board->set_ctl(par, AUOK190X_I80_WR, 0); | ||
| 51 | par->board->set_hdb(par, data); | ||
| 52 | par->board->set_ctl(par, AUOK190X_I80_WR, 1); | ||
| 53 | } | ||
| 54 | |||
| 55 | static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data) | ||
| 56 | { | ||
| 57 | par->board->set_ctl(par, AUOK190X_I80_DC, 0); | ||
| 58 | auok190x_issue_data(par, data); | ||
| 59 | par->board->set_ctl(par, AUOK190X_I80_DC, 1); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, | ||
| 63 | u16 *data) | ||
| 64 | { | ||
| 65 | struct device *dev = par->info->device; | ||
| 66 | int i; | ||
| 67 | u16 tmp; | ||
| 68 | |||
| 69 | if (size & 3) { | ||
| 70 | dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n", | ||
| 71 | size); | ||
| 72 | return -EINVAL; | ||
| 73 | } | ||
| 74 | |||
| 75 | for (i = 0; i < (size >> 1); i++) { | ||
| 76 | par->board->set_ctl(par, AUOK190X_I80_WR, 0); | ||
| 77 | |||
| 78 | /* simple reduction of 8bit staticgray to 4bit gray | ||
| 79 | * combines 4 * 4bit pixel values into a 16bit value | ||
| 80 | */ | ||
| 81 | tmp = (data[2*i] & 0xF0) >> 4; | ||
| 82 | tmp |= (data[2*i] & 0xF000) >> 8; | ||
| 83 | tmp |= (data[2*i+1] & 0xF0) << 4; | ||
| 84 | tmp |= (data[2*i+1] & 0xF000); | ||
| 85 | |||
| 86 | par->board->set_hdb(par, tmp); | ||
| 87 | par->board->set_ctl(par, AUOK190X_I80_WR, 1); | ||
| 88 | } | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static u16 auok190x_read_data(struct auok190xfb_par *par) | ||
| 94 | { | ||
| 95 | u16 data; | ||
| 96 | |||
| 97 | par->board->set_ctl(par, AUOK190X_I80_OE, 0); | ||
| 98 | data = par->board->get_hdb(par); | ||
| 99 | par->board->set_ctl(par, AUOK190X_I80_OE, 1); | ||
| 100 | |||
| 101 | return data; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Command interface for the controller drivers | ||
| 106 | */ | ||
| 107 | |||
| 108 | void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data) | ||
| 109 | { | ||
| 110 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
| 111 | auok190x_issue_cmd(par, data); | ||
| 112 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
| 113 | } | ||
| 114 | EXPORT_SYMBOL_GPL(auok190x_send_command_nowait); | ||
| 115 | |||
| 116 | void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, | ||
| 117 | int argc, u16 *argv) | ||
| 118 | { | ||
| 119 | int i; | ||
| 120 | |||
| 121 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
| 122 | auok190x_issue_cmd(par, cmd); | ||
| 123 | |||
| 124 | for (i = 0; i < argc; i++) | ||
| 125 | auok190x_issue_data(par, argv[i]); | ||
| 126 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
| 127 | } | ||
| 128 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait); | ||
| 129 | |||
| 130 | int auok190x_send_command(struct auok190xfb_par *par, u16 data) | ||
| 131 | { | ||
| 132 | int ret; | ||
| 133 | |||
| 134 | ret = par->board->wait_for_rdy(par); | ||
| 135 | if (ret) | ||
| 136 | return ret; | ||
| 137 | |||
| 138 | auok190x_send_command_nowait(par, data); | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL_GPL(auok190x_send_command); | ||
| 142 | |||
| 143 | int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
| 144 | int argc, u16 *argv) | ||
| 145 | { | ||
| 146 | int ret; | ||
| 147 | |||
| 148 | ret = par->board->wait_for_rdy(par); | ||
| 149 | if (ret) | ||
| 150 | return ret; | ||
| 151 | |||
| 152 | auok190x_send_cmdargs_nowait(par, cmd, argc, argv); | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs); | ||
| 156 | |||
| 157 | int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
| 158 | int argc, u16 *argv) | ||
| 159 | { | ||
| 160 | int i, ret; | ||
| 161 | |||
| 162 | ret = par->board->wait_for_rdy(par); | ||
| 163 | if (ret) | ||
| 164 | return ret; | ||
| 165 | |||
| 166 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
| 167 | auok190x_issue_cmd(par, cmd); | ||
| 168 | |||
| 169 | for (i = 0; i < argc; i++) | ||
| 170 | argv[i] = auok190x_read_data(par); | ||
| 171 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
| 172 | |||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | EXPORT_SYMBOL_GPL(auok190x_read_cmdargs); | ||
| 176 | |||
| 177 | void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd, | ||
| 178 | int argc, u16 *argv, int size, u16 *data) | ||
| 179 | { | ||
| 180 | int i; | ||
| 181 | |||
| 182 | par->board->set_ctl(par, AUOK190X_I80_CS, 0); | ||
| 183 | |||
| 184 | auok190x_issue_cmd(par, cmd); | ||
| 185 | |||
| 186 | for (i = 0; i < argc; i++) | ||
| 187 | auok190x_issue_data(par, argv[i]); | ||
| 188 | |||
| 189 | auok190x_issue_pixels(par, size, data); | ||
| 190 | |||
| 191 | par->board->set_ctl(par, AUOK190X_I80_CS, 1); | ||
| 192 | } | ||
| 193 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait); | ||
| 194 | |||
| 195 | int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, | ||
| 196 | int argc, u16 *argv, int size, u16 *data) | ||
| 197 | { | ||
| 198 | int ret; | ||
| 199 | |||
| 200 | ret = par->board->wait_for_rdy(par); | ||
| 201 | if (ret) | ||
| 202 | return ret; | ||
| 203 | |||
| 204 | auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data); | ||
| 205 | |||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels); | ||
| 209 | |||
| 210 | /* | ||
| 211 | * fbdefio callbacks - common on both controllers. | ||
| 212 | */ | ||
| 213 | |||
| 214 | static void auok190xfb_dpy_first_io(struct fb_info *info) | ||
| 215 | { | ||
| 216 | /* tell runtime-pm that we wish to use the device in a short time */ | ||
| 217 | pm_runtime_get(info->device); | ||
| 218 | } | ||
| 219 | |||
| 220 | /* this is called back from the deferred io workqueue */ | ||
| 221 | static void auok190xfb_dpy_deferred_io(struct fb_info *info, | ||
| 222 | struct list_head *pagelist) | ||
| 223 | { | ||
| 224 | struct fb_deferred_io *fbdefio = info->fbdefio; | ||
| 225 | struct auok190xfb_par *par = info->par; | ||
| 226 | u16 yres = info->var.yres; | ||
| 227 | u16 xres = info->var.xres; | ||
| 228 | u16 y1 = 0, h = 0; | ||
| 229 | int prev_index = -1; | ||
| 230 | struct page *cur; | ||
| 231 | int h_inc; | ||
| 232 | int threshold; | ||
| 233 | |||
| 234 | if (!list_empty(pagelist)) | ||
| 235 | /* the device resume should've been requested through first_io, | ||
| 236 | * if the resume did not finish until now, wait for it. | ||
| 237 | */ | ||
| 238 | pm_runtime_barrier(info->device); | ||
| 239 | else | ||
| 240 | /* We reached this via the fsync or some other way. | ||
| 241 | * In either case the first_io function did not run, | ||
| 242 | * so we runtime_resume the device here synchronously. | ||
| 243 | */ | ||
| 244 | pm_runtime_get_sync(info->device); | ||
| 245 | |||
| 246 | /* Do a full screen update every n updates to prevent | ||
| 247 | * excessive darkening of the Sipix display. | ||
| 248 | * If we do this, there is no need to walk the pages. | ||
| 249 | */ | ||
| 250 | if (par->need_refresh(par)) { | ||
| 251 | par->update_all(par); | ||
| 252 | goto out; | ||
| 253 | } | ||
| 254 | |||
| 255 | /* height increment is fixed per page */ | ||
| 256 | h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); | ||
| 257 | |||
| 258 | /* calculate number of pages from pixel height */ | ||
| 259 | threshold = par->consecutive_threshold / h_inc; | ||
| 260 | if (threshold < 1) | ||
| 261 | threshold = 1; | ||
| 262 | |||
| 263 | /* walk the written page list and swizzle the data */ | ||
| 264 | list_for_each_entry(cur, &fbdefio->pagelist, lru) { | ||
| 265 | if (prev_index < 0) { | ||
| 266 | /* just starting so assign first page */ | ||
| 267 | y1 = (cur->index << PAGE_SHIFT) / xres; | ||
| 268 | h = h_inc; | ||
| 269 | } else if ((cur->index - prev_index) <= threshold) { | ||
| 270 | /* page is within our threshold for single updates */ | ||
| 271 | h += h_inc * (cur->index - prev_index); | ||
| 272 | } else { | ||
| 273 | /* page not consecutive, issue previous update first */ | ||
| 274 | par->update_partial(par, y1, y1 + h); | ||
| 275 | |||
| 276 | /* start over with our non consecutive page */ | ||
| 277 | y1 = (cur->index << PAGE_SHIFT) / xres; | ||
| 278 | h = h_inc; | ||
| 279 | } | ||
| 280 | prev_index = cur->index; | ||
| 281 | } | ||
| 282 | |||
| 283 | /* if we still have any pages to update we do so now */ | ||
| 284 | if (h >= yres) | ||
| 285 | /* its a full screen update, just do it */ | ||
| 286 | par->update_all(par); | ||
| 287 | else | ||
| 288 | par->update_partial(par, y1, min((u16) (y1 + h), yres)); | ||
| 289 | |||
| 290 | out: | ||
| 291 | pm_runtime_mark_last_busy(info->device); | ||
| 292 | pm_runtime_put_autosuspend(info->device); | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * framebuffer operations | ||
| 297 | */ | ||
| 298 | |||
| 299 | /* | ||
| 300 | * this is the slow path from userspace. they can seek and write to | ||
| 301 | * the fb. it's inefficient to do anything less than a full screen draw | ||
| 302 | */ | ||
| 303 | static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf, | ||
| 304 | size_t count, loff_t *ppos) | ||
| 305 | { | ||
| 306 | struct auok190xfb_par *par = info->par; | ||
| 307 | unsigned long p = *ppos; | ||
| 308 | void *dst; | ||
| 309 | int err = 0; | ||
| 310 | unsigned long total_size; | ||
| 311 | |||
| 312 | if (info->state != FBINFO_STATE_RUNNING) | ||
| 313 | return -EPERM; | ||
| 314 | |||
| 315 | total_size = info->fix.smem_len; | ||
| 316 | |||
| 317 | if (p > total_size) | ||
| 318 | return -EFBIG; | ||
| 319 | |||
| 320 | if (count > total_size) { | ||
| 321 | err = -EFBIG; | ||
| 322 | count = total_size; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (count + p > total_size) { | ||
| 326 | if (!err) | ||
| 327 | err = -ENOSPC; | ||
| 328 | |||
| 329 | count = total_size - p; | ||
| 330 | } | ||
| 331 | |||
| 332 | dst = (void *)(info->screen_base + p); | ||
| 333 | |||
| 334 | if (copy_from_user(dst, buf, count)) | ||
| 335 | err = -EFAULT; | ||
| 336 | |||
| 337 | if (!err) | ||
| 338 | *ppos += count; | ||
| 339 | |||
| 340 | par->update_all(par); | ||
| 341 | |||
| 342 | return (err) ? err : count; | ||
| 343 | } | ||
| 344 | |||
| 345 | static void auok190xfb_fillrect(struct fb_info *info, | ||
| 346 | const struct fb_fillrect *rect) | ||
| 347 | { | ||
| 348 | struct auok190xfb_par *par = info->par; | ||
| 349 | |||
| 350 | sys_fillrect(info, rect); | ||
| 351 | |||
| 352 | par->update_all(par); | ||
| 353 | } | ||
| 354 | |||
| 355 | static void auok190xfb_copyarea(struct fb_info *info, | ||
| 356 | const struct fb_copyarea *area) | ||
| 357 | { | ||
| 358 | struct auok190xfb_par *par = info->par; | ||
| 359 | |||
| 360 | sys_copyarea(info, area); | ||
| 361 | |||
| 362 | par->update_all(par); | ||
| 363 | } | ||
| 364 | |||
| 365 | static void auok190xfb_imageblit(struct fb_info *info, | ||
| 366 | const struct fb_image *image) | ||
| 367 | { | ||
| 368 | struct auok190xfb_par *par = info->par; | ||
| 369 | |||
| 370 | sys_imageblit(info, image); | ||
| 371 | |||
| 372 | par->update_all(par); | ||
| 373 | } | ||
| 374 | |||
| 375 | static int auok190xfb_check_var(struct fb_var_screeninfo *var, | ||
| 376 | struct fb_info *info) | ||
| 377 | { | ||
| 378 | if (info->var.xres != var->xres || info->var.yres != var->yres || | ||
| 379 | info->var.xres_virtual != var->xres_virtual || | ||
| 380 | info->var.yres_virtual != var->yres_virtual) { | ||
| 381 | pr_info("%s: Resolution not supported: X%u x Y%u\n", | ||
| 382 | __func__, var->xres, var->yres); | ||
| 383 | return -EINVAL; | ||
| 384 | } | ||
| 385 | |||
| 386 | /* | ||
| 387 | * Memory limit | ||
| 388 | */ | ||
| 389 | |||
| 390 | if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { | ||
| 391 | pr_info("%s: Memory Limit requested yres_virtual = %u\n", | ||
| 392 | __func__, var->yres_virtual); | ||
| 393 | return -ENOMEM; | ||
| 394 | } | ||
| 395 | |||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static struct fb_ops auok190xfb_ops = { | ||
| 400 | .owner = THIS_MODULE, | ||
| 401 | .fb_read = fb_sys_read, | ||
| 402 | .fb_write = auok190xfb_write, | ||
| 403 | .fb_fillrect = auok190xfb_fillrect, | ||
| 404 | .fb_copyarea = auok190xfb_copyarea, | ||
| 405 | .fb_imageblit = auok190xfb_imageblit, | ||
| 406 | .fb_check_var = auok190xfb_check_var, | ||
| 407 | }; | ||
| 408 | |||
| 409 | /* | ||
| 410 | * Controller-functions common to both K1900 and K1901 | ||
| 411 | */ | ||
| 412 | |||
| 413 | static int auok190x_read_temperature(struct auok190xfb_par *par) | ||
| 414 | { | ||
| 415 | struct device *dev = par->info->device; | ||
| 416 | u16 data[4]; | ||
| 417 | int temp; | ||
| 418 | |||
| 419 | pm_runtime_get_sync(dev); | ||
| 420 | |||
| 421 | mutex_lock(&(par->io_lock)); | ||
| 422 | |||
| 423 | auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); | ||
| 424 | |||
| 425 | mutex_unlock(&(par->io_lock)); | ||
| 426 | |||
| 427 | pm_runtime_mark_last_busy(dev); | ||
| 428 | pm_runtime_put_autosuspend(dev); | ||
| 429 | |||
| 430 | /* sanitize and split of half-degrees for now */ | ||
| 431 | temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1); | ||
| 432 | |||
| 433 | /* handle positive and negative temperatures */ | ||
| 434 | if (temp >= 201) | ||
| 435 | return (255 - temp + 1) * (-1); | ||
| 436 | else | ||
| 437 | return temp; | ||
| 438 | } | ||
| 439 | |||
| 440 | static void auok190x_identify(struct auok190xfb_par *par) | ||
| 441 | { | ||
| 442 | struct device *dev = par->info->device; | ||
| 443 | u16 data[4]; | ||
| 444 | |||
| 445 | pm_runtime_get_sync(dev); | ||
| 446 | |||
| 447 | mutex_lock(&(par->io_lock)); | ||
| 448 | |||
| 449 | auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); | ||
| 450 | |||
| 451 | mutex_unlock(&(par->io_lock)); | ||
| 452 | |||
| 453 | par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK; | ||
| 454 | |||
| 455 | par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]); | ||
| 456 | par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]); | ||
| 457 | par->panel_model = AUOK190X_VERSION_MODEL(data[2]); | ||
| 458 | |||
| 459 | par->tcon_version = AUOK190X_VERSION_TCON(data[3]); | ||
| 460 | par->lut_version = AUOK190X_VERSION_LUT(data[3]); | ||
| 461 | |||
| 462 | dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x", | ||
| 463 | par->panel_size_int, par->panel_size_float, par->panel_model, | ||
| 464 | par->epd_type, par->tcon_version, par->lut_version); | ||
| 465 | |||
| 466 | pm_runtime_mark_last_busy(dev); | ||
| 467 | pm_runtime_put_autosuspend(dev); | ||
| 468 | } | ||
| 469 | |||
| 470 | /* | ||
| 471 | * Sysfs functions | ||
| 472 | */ | ||
| 473 | |||
| 474 | static ssize_t update_mode_show(struct device *dev, | ||
| 475 | struct device_attribute *attr, char *buf) | ||
| 476 | { | ||
| 477 | struct fb_info *info = dev_get_drvdata(dev); | ||
| 478 | struct auok190xfb_par *par = info->par; | ||
| 479 | |||
| 480 | return sprintf(buf, "%d\n", par->update_mode); | ||
| 481 | } | ||
| 482 | |||
| 483 | static ssize_t update_mode_store(struct device *dev, | ||
| 484 | struct device_attribute *attr, | ||
| 485 | const char *buf, size_t count) | ||
| 486 | { | ||
| 487 | struct fb_info *info = dev_get_drvdata(dev); | ||
| 488 | struct auok190xfb_par *par = info->par; | ||
| 489 | int mode, ret; | ||
| 490 | |||
| 491 | ret = kstrtoint(buf, 10, &mode); | ||
| 492 | if (ret) | ||
| 493 | return ret; | ||
| 494 | |||
| 495 | par->update_mode = mode; | ||
| 496 | |||
| 497 | /* if we enter a better mode, do a full update */ | ||
| 498 | if (par->last_mode > 1 && mode < par->last_mode) | ||
| 499 | par->update_all(par); | ||
| 500 | |||
| 501 | return count; | ||
| 502 | } | ||
| 503 | |||
| 504 | static ssize_t flash_show(struct device *dev, struct device_attribute *attr, | ||
| 505 | char *buf) | ||
| 506 | { | ||
| 507 | struct fb_info *info = dev_get_drvdata(dev); | ||
| 508 | struct auok190xfb_par *par = info->par; | ||
| 509 | |||
| 510 | return sprintf(buf, "%d\n", par->flash); | ||
| 511 | } | ||
| 512 | |||
| 513 | static ssize_t flash_store(struct device *dev, struct device_attribute *attr, | ||
| 514 | const char *buf, size_t count) | ||
| 515 | { | ||
| 516 | struct fb_info *info = dev_get_drvdata(dev); | ||
| 517 | struct auok190xfb_par *par = info->par; | ||
| 518 | int flash, ret; | ||
| 519 | |||
| 520 | ret = kstrtoint(buf, 10, &flash); | ||
| 521 | if (ret) | ||
| 522 | return ret; | ||
| 523 | |||
| 524 | if (flash > 0) | ||
| 525 | par->flash = 1; | ||
| 526 | else | ||
| 527 | par->flash = 0; | ||
| 528 | |||
| 529 | return count; | ||
| 530 | } | ||
| 531 | |||
| 532 | static ssize_t temp_show(struct device *dev, struct device_attribute *attr, | ||
| 533 | char *buf) | ||
| 534 | { | ||
| 535 | struct fb_info *info = dev_get_drvdata(dev); | ||
| 536 | struct auok190xfb_par *par = info->par; | ||
| 537 | int temp; | ||
| 538 | |||
| 539 | temp = auok190x_read_temperature(par); | ||
| 540 | return sprintf(buf, "%d\n", temp); | ||
| 541 | } | ||
| 542 | |||
| 543 | static DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store); | ||
| 544 | static DEVICE_ATTR(flash, 0644, flash_show, flash_store); | ||
| 545 | static DEVICE_ATTR(temp, 0644, temp_show, NULL); | ||
| 546 | |||
| 547 | static struct attribute *auok190x_attributes[] = { | ||
| 548 | &dev_attr_update_mode.attr, | ||
| 549 | &dev_attr_flash.attr, | ||
| 550 | &dev_attr_temp.attr, | ||
| 551 | NULL | ||
| 552 | }; | ||
| 553 | |||
| 554 | static const struct attribute_group auok190x_attr_group = { | ||
| 555 | .attrs = auok190x_attributes, | ||
| 556 | }; | ||
| 557 | |||
| 558 | static int auok190x_power(struct auok190xfb_par *par, bool on) | ||
| 559 | { | ||
| 560 | struct auok190x_board *board = par->board; | ||
| 561 | int ret; | ||
| 562 | |||
| 563 | if (on) { | ||
| 564 | /* We should maintain POWER up for at least 80ms before set | ||
| 565 | * RST_N and SLP_N to high (TCON spec 20100803_v35 p59) | ||
| 566 | */ | ||
| 567 | ret = regulator_enable(par->regulator); | ||
| 568 | if (ret) | ||
| 569 | return ret; | ||
| 570 | |||
| 571 | msleep(200); | ||
| 572 | gpio_set_value(board->gpio_nrst, 1); | ||
| 573 | gpio_set_value(board->gpio_nsleep, 1); | ||
| 574 | msleep(200); | ||
| 575 | } else { | ||
| 576 | regulator_disable(par->regulator); | ||
| 577 | gpio_set_value(board->gpio_nrst, 0); | ||
| 578 | gpio_set_value(board->gpio_nsleep, 0); | ||
| 579 | } | ||
| 580 | |||
| 581 | return 0; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Recovery - powercycle the controller | ||
| 586 | */ | ||
| 587 | |||
| 588 | static void auok190x_recover(struct auok190xfb_par *par) | ||
| 589 | { | ||
| 590 | auok190x_power(par, 0); | ||
| 591 | msleep(100); | ||
| 592 | auok190x_power(par, 1); | ||
| 593 | |||
| 594 | par->init(par); | ||
| 595 | |||
| 596 | /* wait for init to complete */ | ||
| 597 | par->board->wait_for_rdy(par); | ||
| 598 | } | ||
| 599 | |||
| 600 | /* | ||
| 601 | * Power-management | ||
| 602 | */ | ||
| 603 | |||
| 604 | #ifdef CONFIG_PM | ||
| 605 | static int auok190x_runtime_suspend(struct device *dev) | ||
| 606 | { | ||
| 607 | struct platform_device *pdev = to_platform_device(dev); | ||
| 608 | struct fb_info *info = platform_get_drvdata(pdev); | ||
| 609 | struct auok190xfb_par *par = info->par; | ||
| 610 | struct auok190x_board *board = par->board; | ||
| 611 | u16 standby_param; | ||
| 612 | |||
| 613 | /* take and keep the lock until we are resumed, as the controller | ||
| 614 | * will never reach the non-busy state when in standby mode | ||
| 615 | */ | ||
| 616 | mutex_lock(&(par->io_lock)); | ||
| 617 | |||
| 618 | if (par->standby) { | ||
| 619 | dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n"); | ||
| 620 | mutex_unlock(&(par->io_lock)); | ||
| 621 | return 0; | ||
| 622 | } | ||
| 623 | |||
| 624 | /* according to runtime_pm.txt runtime_suspend only means, that the | ||
| 625 | * device will not process data and will not communicate with the CPU | ||
| 626 | * As we hold the lock, this stays true even without standby | ||
| 627 | */ | ||
| 628 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
| 629 | dev_dbg(dev, "runtime suspend without standby\n"); | ||
| 630 | goto finish; | ||
| 631 | } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) { | ||
| 632 | /* for some TCON versions STANDBY expects a parameter (0) but | ||
| 633 | * it seems the real tcon version has to be determined yet. | ||
| 634 | */ | ||
| 635 | dev_dbg(dev, "runtime suspend with additional empty param\n"); | ||
| 636 | standby_param = 0; | ||
| 637 | auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1, | ||
| 638 | &standby_param); | ||
| 639 | } else { | ||
| 640 | dev_dbg(dev, "runtime suspend without param\n"); | ||
| 641 | auok190x_send_command(par, AUOK190X_CMD_STANDBY); | ||
| 642 | } | ||
| 643 | |||
| 644 | msleep(64); | ||
| 645 | |||
| 646 | finish: | ||
| 647 | par->standby = 1; | ||
| 648 | |||
| 649 | return 0; | ||
| 650 | } | ||
| 651 | |||
| 652 | static int auok190x_runtime_resume(struct device *dev) | ||
| 653 | { | ||
| 654 | struct platform_device *pdev = to_platform_device(dev); | ||
| 655 | struct fb_info *info = platform_get_drvdata(pdev); | ||
| 656 | struct auok190xfb_par *par = info->par; | ||
| 657 | struct auok190x_board *board = par->board; | ||
| 658 | |||
| 659 | if (!par->standby) { | ||
| 660 | dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n"); | ||
| 661 | return 0; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
| 665 | dev_dbg(dev, "runtime resume without standby\n"); | ||
| 666 | } else { | ||
| 667 | /* when in standby, controller is always busy | ||
| 668 | * and only accepts the wakeup command | ||
| 669 | */ | ||
| 670 | dev_dbg(dev, "runtime resume from standby\n"); | ||
| 671 | auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP); | ||
| 672 | |||
| 673 | msleep(160); | ||
| 674 | |||
| 675 | /* wait for the controller to be ready and release the lock */ | ||
| 676 | board->wait_for_rdy(par); | ||
| 677 | } | ||
| 678 | |||
| 679 | par->standby = 0; | ||
| 680 | |||
| 681 | mutex_unlock(&(par->io_lock)); | ||
| 682 | |||
| 683 | return 0; | ||
| 684 | } | ||
| 685 | |||
| 686 | static int auok190x_suspend(struct device *dev) | ||
| 687 | { | ||
| 688 | struct platform_device *pdev = to_platform_device(dev); | ||
| 689 | struct fb_info *info = platform_get_drvdata(pdev); | ||
| 690 | struct auok190xfb_par *par = info->par; | ||
| 691 | struct auok190x_board *board = par->board; | ||
| 692 | int ret; | ||
| 693 | |||
| 694 | dev_dbg(dev, "suspend\n"); | ||
| 695 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
| 696 | /* suspend via powering off the ic */ | ||
| 697 | dev_dbg(dev, "suspend with broken standby\n"); | ||
| 698 | |||
| 699 | auok190x_power(par, 0); | ||
| 700 | } else { | ||
| 701 | dev_dbg(dev, "suspend using sleep\n"); | ||
| 702 | |||
| 703 | /* the sleep state can only be entered from the standby state. | ||
| 704 | * pm_runtime_get_noresume gets called before the suspend call. | ||
| 705 | * So the devices usage count is >0 but it is not necessarily | ||
| 706 | * active. | ||
| 707 | */ | ||
| 708 | if (!pm_runtime_status_suspended(dev)) { | ||
| 709 | ret = auok190x_runtime_suspend(dev); | ||
| 710 | if (ret < 0) { | ||
| 711 | dev_err(dev, "auok190x_runtime_suspend failed with %d\n", | ||
| 712 | ret); | ||
| 713 | return ret; | ||
| 714 | } | ||
| 715 | par->manual_standby = 1; | ||
| 716 | } | ||
| 717 | |||
| 718 | gpio_direction_output(board->gpio_nsleep, 0); | ||
| 719 | } | ||
| 720 | |||
| 721 | msleep(100); | ||
| 722 | |||
| 723 | return 0; | ||
| 724 | } | ||
| 725 | |||
| 726 | static int auok190x_resume(struct device *dev) | ||
| 727 | { | ||
| 728 | struct platform_device *pdev = to_platform_device(dev); | ||
| 729 | struct fb_info *info = platform_get_drvdata(pdev); | ||
| 730 | struct auok190xfb_par *par = info->par; | ||
| 731 | struct auok190x_board *board = par->board; | ||
| 732 | |||
| 733 | dev_dbg(dev, "resume\n"); | ||
| 734 | if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { | ||
| 735 | dev_dbg(dev, "resume with broken standby\n"); | ||
| 736 | |||
| 737 | auok190x_power(par, 1); | ||
| 738 | |||
| 739 | par->init(par); | ||
| 740 | } else { | ||
| 741 | dev_dbg(dev, "resume from sleep\n"); | ||
| 742 | |||
| 743 | /* device should be in runtime suspend when we were suspended | ||
| 744 | * and pm_runtime_put_sync gets called after this function. | ||
| 745 | * So there is no need to touch the standby mode here at all. | ||
| 746 | */ | ||
| 747 | gpio_direction_output(board->gpio_nsleep, 1); | ||
| 748 | msleep(100); | ||
| 749 | |||
| 750 | /* an additional init call seems to be necessary after sleep */ | ||
| 751 | auok190x_runtime_resume(dev); | ||
| 752 | par->init(par); | ||
| 753 | |||
| 754 | /* if we were runtime-suspended before, suspend again*/ | ||
| 755 | if (!par->manual_standby) | ||
| 756 | auok190x_runtime_suspend(dev); | ||
| 757 | else | ||
| 758 | par->manual_standby = 0; | ||
| 759 | } | ||
| 760 | |||
| 761 | return 0; | ||
| 762 | } | ||
| 763 | #endif | ||
| 764 | |||
| 765 | const struct dev_pm_ops auok190x_pm = { | ||
| 766 | SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume, | ||
| 767 | NULL) | ||
| 768 | SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume) | ||
| 769 | }; | ||
| 770 | EXPORT_SYMBOL_GPL(auok190x_pm); | ||
| 771 | |||
| 772 | /* | ||
| 773 | * Common probe and remove code | ||
| 774 | */ | ||
| 775 | |||
| 776 | int __devinit auok190x_common_probe(struct platform_device *pdev, | ||
| 777 | struct auok190x_init_data *init) | ||
| 778 | { | ||
| 779 | struct auok190x_board *board = init->board; | ||
| 780 | struct auok190xfb_par *par; | ||
| 781 | struct fb_info *info; | ||
| 782 | struct panel_info *panel; | ||
| 783 | int videomemorysize, ret; | ||
| 784 | unsigned char *videomemory; | ||
| 785 | |||
| 786 | /* check board contents */ | ||
| 787 | if (!board->init || !board->cleanup || !board->wait_for_rdy | ||
| 788 | || !board->set_ctl || !board->set_hdb || !board->get_hdb | ||
| 789 | || !board->setup_irq) | ||
| 790 | return -EINVAL; | ||
| 791 | |||
| 792 | info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev); | ||
| 793 | if (!info) | ||
| 794 | return -ENOMEM; | ||
| 795 | |||
| 796 | par = info->par; | ||
| 797 | par->info = info; | ||
| 798 | par->board = board; | ||
| 799 | par->recover = auok190x_recover; | ||
| 800 | par->update_partial = init->update_partial; | ||
| 801 | par->update_all = init->update_all; | ||
| 802 | par->need_refresh = init->need_refresh; | ||
| 803 | par->init = init->init; | ||
| 804 | |||
| 805 | /* init update modes */ | ||
| 806 | par->update_cnt = 0; | ||
| 807 | par->update_mode = -1; | ||
| 808 | par->last_mode = -1; | ||
| 809 | par->flash = 0; | ||
| 810 | |||
| 811 | par->regulator = regulator_get(info->device, "vdd"); | ||
| 812 | if (IS_ERR(par->regulator)) { | ||
| 813 | ret = PTR_ERR(par->regulator); | ||
| 814 | dev_err(info->device, "Failed to get regulator: %d\n", ret); | ||
| 815 | goto err_reg; | ||
| 816 | } | ||
| 817 | |||
| 818 | ret = board->init(par); | ||
| 819 | if (ret) { | ||
| 820 | dev_err(info->device, "board init failed, %d\n", ret); | ||
| 821 | goto err_board; | ||
| 822 | } | ||
| 823 | |||
| 824 | ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep"); | ||
| 825 | if (ret) { | ||
| 826 | dev_err(info->device, "could not request sleep gpio, %d\n", | ||
| 827 | ret); | ||
| 828 | goto err_gpio1; | ||
| 829 | } | ||
| 830 | |||
| 831 | ret = gpio_direction_output(board->gpio_nsleep, 0); | ||
| 832 | if (ret) { | ||
| 833 | dev_err(info->device, "could not set sleep gpio, %d\n", ret); | ||
| 834 | goto err_gpio2; | ||
| 835 | } | ||
| 836 | |||
| 837 | ret = gpio_request(board->gpio_nrst, "AUOK190x reset"); | ||
| 838 | if (ret) { | ||
| 839 | dev_err(info->device, "could not request reset gpio, %d\n", | ||
| 840 | ret); | ||
| 841 | goto err_gpio2; | ||
| 842 | } | ||
| 843 | |||
| 844 | ret = gpio_direction_output(board->gpio_nrst, 0); | ||
| 845 | if (ret) { | ||
| 846 | dev_err(info->device, "could not set reset gpio, %d\n", ret); | ||
| 847 | goto err_gpio3; | ||
| 848 | } | ||
| 849 | |||
| 850 | ret = auok190x_power(par, 1); | ||
| 851 | if (ret) { | ||
| 852 | dev_err(info->device, "could not power on the device, %d\n", | ||
| 853 | ret); | ||
| 854 | goto err_gpio3; | ||
| 855 | } | ||
| 856 | |||
| 857 | mutex_init(&par->io_lock); | ||
| 858 | |||
| 859 | init_waitqueue_head(&par->waitq); | ||
| 860 | |||
| 861 | ret = par->board->setup_irq(par->info); | ||
| 862 | if (ret) { | ||
| 863 | dev_err(info->device, "could not setup ready-irq, %d\n", ret); | ||
| 864 | goto err_irq; | ||
| 865 | } | ||
| 866 | |||
| 867 | /* wait for init to complete */ | ||
| 868 | par->board->wait_for_rdy(par); | ||
| 869 | |||
| 870 | /* | ||
| 871 | * From here on the controller can talk to us | ||
| 872 | */ | ||
| 873 | |||
| 874 | /* initialise fix, var, resolution and rotation */ | ||
| 875 | |||
| 876 | strlcpy(info->fix.id, init->id, 16); | ||
| 877 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
| 878 | info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; | ||
| 879 | info->fix.xpanstep = 0; | ||
| 880 | info->fix.ypanstep = 0; | ||
| 881 | info->fix.ywrapstep = 0; | ||
| 882 | info->fix.accel = FB_ACCEL_NONE; | ||
| 883 | |||
| 884 | info->var.bits_per_pixel = 8; | ||
| 885 | info->var.grayscale = 1; | ||
| 886 | info->var.red.length = 8; | ||
| 887 | info->var.green.length = 8; | ||
| 888 | info->var.blue.length = 8; | ||
| 889 | |||
| 890 | panel = &panel_table[board->resolution]; | ||
| 891 | |||
| 892 | /* if 90 degree rotation, switch width and height */ | ||
| 893 | if (board->rotation & 1) { | ||
| 894 | info->var.xres = panel->h; | ||
| 895 | info->var.yres = panel->w; | ||
| 896 | info->var.xres_virtual = panel->h; | ||
| 897 | info->var.yres_virtual = panel->w; | ||
| 898 | info->fix.line_length = panel->h; | ||
| 899 | } else { | ||
| 900 | info->var.xres = panel->w; | ||
| 901 | info->var.yres = panel->h; | ||
| 902 | info->var.xres_virtual = panel->w; | ||
| 903 | info->var.yres_virtual = panel->h; | ||
| 904 | info->fix.line_length = panel->w; | ||
| 905 | } | ||
| 906 | |||
| 907 | par->resolution = board->resolution; | ||
| 908 | par->rotation = board->rotation; | ||
| 909 | |||
| 910 | /* videomemory handling */ | ||
| 911 | |||
| 912 | videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE); | ||
| 913 | videomemory = vmalloc(videomemorysize); | ||
| 914 | if (!videomemory) { | ||
| 915 | ret = -ENOMEM; | ||
| 916 | goto err_irq; | ||
| 917 | } | ||
| 918 | |||
| 919 | memset(videomemory, 0, videomemorysize); | ||
| 920 | info->screen_base = (char *)videomemory; | ||
| 921 | info->fix.smem_len = videomemorysize; | ||
| 922 | |||
| 923 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; | ||
| 924 | info->fbops = &auok190xfb_ops; | ||
| 925 | |||
| 926 | /* deferred io init */ | ||
| 927 | |||
| 928 | info->fbdefio = devm_kzalloc(info->device, | ||
| 929 | sizeof(struct fb_deferred_io), | ||
| 930 | GFP_KERNEL); | ||
| 931 | if (!info->fbdefio) { | ||
| 932 | dev_err(info->device, "Failed to allocate memory\n"); | ||
| 933 | ret = -ENOMEM; | ||
| 934 | goto err_defio; | ||
| 935 | } | ||
| 936 | |||
| 937 | dev_dbg(info->device, "targetting %d frames per second\n", board->fps); | ||
| 938 | info->fbdefio->delay = HZ / board->fps; | ||
| 939 | info->fbdefio->first_io = auok190xfb_dpy_first_io, | ||
| 940 | info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io, | ||
| 941 | fb_deferred_io_init(info); | ||
| 942 | |||
| 943 | /* color map */ | ||
| 944 | |||
| 945 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
| 946 | if (ret < 0) { | ||
| 947 | dev_err(info->device, "Failed to allocate colormap\n"); | ||
| 948 | goto err_cmap; | ||
| 949 | } | ||
| 950 | |||
| 951 | /* controller init */ | ||
| 952 | |||
| 953 | par->consecutive_threshold = 100; | ||
| 954 | par->init(par); | ||
| 955 | auok190x_identify(par); | ||
| 956 | |||
| 957 | platform_set_drvdata(pdev, info); | ||
| 958 | |||
| 959 | ret = register_framebuffer(info); | ||
| 960 | if (ret < 0) | ||
| 961 | goto err_regfb; | ||
| 962 | |||
| 963 | ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group); | ||
| 964 | if (ret) | ||
| 965 | goto err_sysfs; | ||
| 966 | |||
| 967 | dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n", | ||
| 968 | info->node, info->var.xres, info->var.yres, | ||
| 969 | videomemorysize >> 10); | ||
| 970 | |||
| 971 | /* increase autosuspend_delay when we use alternative methods | ||
| 972 | * for runtime_pm | ||
| 973 | */ | ||
| 974 | par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) | ||
| 975 | ? 1000 : 200; | ||
| 976 | |||
| 977 | pm_runtime_set_active(info->device); | ||
| 978 | pm_runtime_enable(info->device); | ||
| 979 | pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay); | ||
| 980 | pm_runtime_use_autosuspend(info->device); | ||
| 981 | |||
| 982 | return 0; | ||
| 983 | |||
| 984 | err_sysfs: | ||
| 985 | unregister_framebuffer(info); | ||
| 986 | err_regfb: | ||
| 987 | fb_dealloc_cmap(&info->cmap); | ||
| 988 | err_cmap: | ||
| 989 | fb_deferred_io_cleanup(info); | ||
| 990 | kfree(info->fbdefio); | ||
| 991 | err_defio: | ||
| 992 | vfree((void *)info->screen_base); | ||
| 993 | err_irq: | ||
| 994 | auok190x_power(par, 0); | ||
| 995 | err_gpio3: | ||
| 996 | gpio_free(board->gpio_nrst); | ||
| 997 | err_gpio2: | ||
| 998 | gpio_free(board->gpio_nsleep); | ||
| 999 | err_gpio1: | ||
| 1000 | board->cleanup(par); | ||
| 1001 | err_board: | ||
| 1002 | regulator_put(par->regulator); | ||
| 1003 | err_reg: | ||
| 1004 | framebuffer_release(info); | ||
| 1005 | |||
| 1006 | return ret; | ||
| 1007 | } | ||
| 1008 | EXPORT_SYMBOL_GPL(auok190x_common_probe); | ||
| 1009 | |||
| 1010 | int __devexit auok190x_common_remove(struct platform_device *pdev) | ||
| 1011 | { | ||
| 1012 | struct fb_info *info = platform_get_drvdata(pdev); | ||
| 1013 | struct auok190xfb_par *par = info->par; | ||
| 1014 | struct auok190x_board *board = par->board; | ||
| 1015 | |||
| 1016 | pm_runtime_disable(info->device); | ||
| 1017 | |||
| 1018 | sysfs_remove_group(&info->device->kobj, &auok190x_attr_group); | ||
| 1019 | |||
| 1020 | unregister_framebuffer(info); | ||
| 1021 | |||
| 1022 | fb_dealloc_cmap(&info->cmap); | ||
| 1023 | |||
| 1024 | fb_deferred_io_cleanup(info); | ||
| 1025 | kfree(info->fbdefio); | ||
| 1026 | |||
| 1027 | vfree((void *)info->screen_base); | ||
| 1028 | |||
| 1029 | auok190x_power(par, 0); | ||
| 1030 | |||
| 1031 | gpio_free(board->gpio_nrst); | ||
| 1032 | gpio_free(board->gpio_nsleep); | ||
| 1033 | |||
| 1034 | board->cleanup(par); | ||
| 1035 | |||
| 1036 | regulator_put(par->regulator); | ||
| 1037 | |||
| 1038 | framebuffer_release(info); | ||
| 1039 | |||
| 1040 | return 0; | ||
| 1041 | } | ||
| 1042 | EXPORT_SYMBOL_GPL(auok190x_common_remove); | ||
| 1043 | |||
| 1044 | MODULE_DESCRIPTION("Common code for AUO-K190X controllers"); | ||
| 1045 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); | ||
| 1046 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/auo_k190x.h b/drivers/video/auo_k190x.h new file mode 100644 index 000000000000..e35af1f51b28 --- /dev/null +++ b/drivers/video/auo_k190x.h | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | /* | ||
| 2 | * Private common definitions for AUO-K190X framebuffer drivers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * I80 interface specific defines | ||
| 13 | */ | ||
| 14 | |||
| 15 | #define AUOK190X_I80_CS 0x01 | ||
| 16 | #define AUOK190X_I80_DC 0x02 | ||
| 17 | #define AUOK190X_I80_WR 0x03 | ||
| 18 | #define AUOK190X_I80_OE 0x04 | ||
| 19 | |||
| 20 | /* | ||
| 21 | * AUOK190x commands, common to both controllers | ||
| 22 | */ | ||
| 23 | |||
| 24 | #define AUOK190X_CMD_INIT 0x0000 | ||
| 25 | #define AUOK190X_CMD_STANDBY 0x0001 | ||
| 26 | #define AUOK190X_CMD_WAKEUP 0x0002 | ||
| 27 | #define AUOK190X_CMD_TCON_RESET 0x0003 | ||
| 28 | #define AUOK190X_CMD_DATA_STOP 0x1002 | ||
| 29 | #define AUOK190X_CMD_LUT_START 0x1003 | ||
| 30 | #define AUOK190X_CMD_DISP_REFRESH 0x1004 | ||
| 31 | #define AUOK190X_CMD_DISP_RESET 0x1005 | ||
| 32 | #define AUOK190X_CMD_PRE_DISPLAY_START 0x100D | ||
| 33 | #define AUOK190X_CMD_PRE_DISPLAY_STOP 0x100F | ||
| 34 | #define AUOK190X_CMD_FLASH_W 0x2000 | ||
| 35 | #define AUOK190X_CMD_FLASH_E 0x2001 | ||
| 36 | #define AUOK190X_CMD_FLASH_STS 0x2002 | ||
| 37 | #define AUOK190X_CMD_FRAMERATE 0x3000 | ||
| 38 | #define AUOK190X_CMD_READ_VERSION 0x4000 | ||
| 39 | #define AUOK190X_CMD_READ_STATUS 0x4001 | ||
| 40 | #define AUOK190X_CMD_READ_LUT 0x4003 | ||
| 41 | #define AUOK190X_CMD_DRIVERTIMING 0x5000 | ||
| 42 | #define AUOK190X_CMD_LBALANCE 0x5001 | ||
| 43 | #define AUOK190X_CMD_AGINGMODE 0x6000 | ||
| 44 | #define AUOK190X_CMD_AGINGEXIT 0x6001 | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Common settings for AUOK190X_CMD_INIT | ||
| 48 | */ | ||
| 49 | |||
| 50 | #define AUOK190X_INIT_DATA_FILTER (0 << 12) | ||
| 51 | #define AUOK190X_INIT_DATA_BYPASS (1 << 12) | ||
| 52 | #define AUOK190X_INIT_INVERSE_WHITE (0 << 9) | ||
| 53 | #define AUOK190X_INIT_INVERSE_BLACK (1 << 9) | ||
| 54 | #define AUOK190X_INIT_SCAN_DOWN (0 << 1) | ||
| 55 | #define AUOK190X_INIT_SCAN_UP (1 << 1) | ||
| 56 | #define AUOK190X_INIT_SHIFT_LEFT (0 << 0) | ||
| 57 | #define AUOK190X_INIT_SHIFT_RIGHT (1 << 0) | ||
| 58 | |||
| 59 | /* Common bits to pixels | ||
| 60 | * Mode 15-12 11-8 7-4 3-0 | ||
| 61 | * format0 4 3 2 1 | ||
| 62 | * format1 3 4 1 2 | ||
| 63 | */ | ||
| 64 | |||
| 65 | #define AUOK190X_INIT_FORMAT0 0 | ||
| 66 | #define AUOK190X_INIT_FORMAT1 (1 << 6) | ||
| 67 | |||
| 68 | /* | ||
| 69 | * settings for AUOK190X_CMD_RESET | ||
| 70 | */ | ||
| 71 | |||
| 72 | #define AUOK190X_RESET_TCON (0 << 0) | ||
| 73 | #define AUOK190X_RESET_NORMAL (1 << 0) | ||
| 74 | #define AUOK190X_RESET_PON (1 << 1) | ||
| 75 | |||
| 76 | /* | ||
| 77 | * AUOK190X_CMD_VERSION | ||
| 78 | */ | ||
| 79 | |||
| 80 | #define AUOK190X_VERSION_TEMP_MASK (0x1ff) | ||
| 81 | #define AUOK190X_VERSION_EPD_MASK (0xff) | ||
| 82 | #define AUOK190X_VERSION_SIZE_INT(_val) ((_val & 0xfc00) >> 10) | ||
| 83 | #define AUOK190X_VERSION_SIZE_FLOAT(_val) ((_val & 0x3c0) >> 6) | ||
| 84 | #define AUOK190X_VERSION_MODEL(_val) (_val & 0x3f) | ||
| 85 | #define AUOK190X_VERSION_LUT(_val) (_val & 0xff) | ||
| 86 | #define AUOK190X_VERSION_TCON(_val) ((_val & 0xff00) >> 8) | ||
| 87 | |||
| 88 | /* | ||
| 89 | * update modes for CMD_PARTIALDISP on K1900 and CMD_DDMA on K1901 | ||
| 90 | */ | ||
| 91 | |||
| 92 | #define AUOK190X_UPDATE_MODE(_res) ((_res & 0x7) << 12) | ||
| 93 | #define AUOK190X_UPDATE_NONFLASH (1 << 15) | ||
| 94 | |||
| 95 | /* | ||
| 96 | * track panel specific parameters for common init | ||
| 97 | */ | ||
| 98 | |||
| 99 | struct auok190x_init_data { | ||
| 100 | char *id; | ||
| 101 | struct auok190x_board *board; | ||
| 102 | |||
| 103 | void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2); | ||
| 104 | void (*update_all)(struct auok190xfb_par *par); | ||
| 105 | bool (*need_refresh)(struct auok190xfb_par *par); | ||
| 106 | void (*init)(struct auok190xfb_par *par); | ||
| 107 | }; | ||
| 108 | |||
| 109 | |||
| 110 | extern void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data); | ||
| 111 | extern int auok190x_send_command(struct auok190xfb_par *par, u16 data); | ||
| 112 | extern void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, | ||
| 113 | int argc, u16 *argv); | ||
| 114 | extern int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
| 115 | int argc, u16 *argv); | ||
| 116 | extern void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, | ||
| 117 | u16 cmd, int argc, u16 *argv, | ||
| 118 | int size, u16 *data); | ||
| 119 | extern int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, | ||
| 120 | int argc, u16 *argv, int size, | ||
| 121 | u16 *data); | ||
| 122 | extern int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, | ||
| 123 | int argc, u16 *argv); | ||
| 124 | |||
| 125 | extern int auok190x_common_probe(struct platform_device *pdev, | ||
| 126 | struct auok190x_init_data *init); | ||
| 127 | extern int auok190x_common_remove(struct platform_device *pdev); | ||
| 128 | |||
| 129 | extern const struct dev_pm_ops auok190x_pm; | ||
diff --git a/drivers/video/bfin_adv7393fb.c b/drivers/video/bfin_adv7393fb.c index 1a268a294478..33ea874c87d2 100644 --- a/drivers/video/bfin_adv7393fb.c +++ b/drivers/video/bfin_adv7393fb.c | |||
| @@ -414,14 +414,14 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
| 414 | if (ret) { | 414 | if (ret) { |
| 415 | dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n"); | 415 | dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n"); |
| 416 | ret = -EBUSY; | 416 | ret = -EBUSY; |
| 417 | goto out_8; | 417 | goto free_fbdev; |
| 418 | } | 418 | } |
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | if (peripheral_request_list(ppi_pins, DRIVER_NAME)) { | 421 | if (peripheral_request_list(ppi_pins, DRIVER_NAME)) { |
| 422 | dev_err(&client->dev, "requesting PPI peripheral failed\n"); | 422 | dev_err(&client->dev, "requesting PPI peripheral failed\n"); |
| 423 | ret = -EFAULT; | 423 | ret = -EFAULT; |
| 424 | goto out_8; | 424 | goto free_gpio; |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | fbdev->fb_mem = | 427 | fbdev->fb_mem = |
| @@ -432,7 +432,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
| 432 | dev_err(&client->dev, "couldn't allocate dma buffer (%d bytes)\n", | 432 | dev_err(&client->dev, "couldn't allocate dma buffer (%d bytes)\n", |
| 433 | (u32) fbdev->fb_len); | 433 | (u32) fbdev->fb_len); |
| 434 | ret = -ENOMEM; | 434 | ret = -ENOMEM; |
| 435 | goto out_7; | 435 | goto free_ppi_pins; |
| 436 | } | 436 | } |
| 437 | 437 | ||
| 438 | fbdev->info.screen_base = (void *)fbdev->fb_mem; | 438 | fbdev->info.screen_base = (void *)fbdev->fb_mem; |
| @@ -464,27 +464,27 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
| 464 | if (!fbdev->info.pseudo_palette) { | 464 | if (!fbdev->info.pseudo_palette) { |
| 465 | dev_err(&client->dev, "failed to allocate pseudo_palette\n"); | 465 | dev_err(&client->dev, "failed to allocate pseudo_palette\n"); |
| 466 | ret = -ENOMEM; | 466 | ret = -ENOMEM; |
| 467 | goto out_6; | 467 | goto free_fb_mem; |
| 468 | } | 468 | } |
| 469 | 469 | ||
| 470 | if (fb_alloc_cmap(&fbdev->info.cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | 470 | if (fb_alloc_cmap(&fbdev->info.cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { |
| 471 | dev_err(&client->dev, "failed to allocate colormap (%d entries)\n", | 471 | dev_err(&client->dev, "failed to allocate colormap (%d entries)\n", |
| 472 | BFIN_LCD_NBR_PALETTE_ENTRIES); | 472 | BFIN_LCD_NBR_PALETTE_ENTRIES); |
| 473 | ret = -EFAULT; | 473 | ret = -EFAULT; |
| 474 | goto out_5; | 474 | goto free_palette; |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | if (request_dma(CH_PPI, "BF5xx_PPI_DMA") < 0) { | 477 | if (request_dma(CH_PPI, "BF5xx_PPI_DMA") < 0) { |
| 478 | dev_err(&client->dev, "unable to request PPI DMA\n"); | 478 | dev_err(&client->dev, "unable to request PPI DMA\n"); |
| 479 | ret = -EFAULT; | 479 | ret = -EFAULT; |
| 480 | goto out_4; | 480 | goto free_cmap; |
| 481 | } | 481 | } |
| 482 | 482 | ||
| 483 | if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, 0, | 483 | if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, 0, |
| 484 | "PPI ERROR", fbdev) < 0) { | 484 | "PPI ERROR", fbdev) < 0) { |
| 485 | dev_err(&client->dev, "unable to request PPI ERROR IRQ\n"); | 485 | dev_err(&client->dev, "unable to request PPI ERROR IRQ\n"); |
| 486 | ret = -EFAULT; | 486 | ret = -EFAULT; |
| 487 | goto out_3; | 487 | goto free_ch_ppi; |
| 488 | } | 488 | } |
| 489 | 489 | ||
| 490 | fbdev->open = 0; | 490 | fbdev->open = 0; |
| @@ -494,14 +494,14 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
| 494 | 494 | ||
| 495 | if (ret) { | 495 | if (ret) { |
| 496 | dev_err(&client->dev, "i2c attach: init error\n"); | 496 | dev_err(&client->dev, "i2c attach: init error\n"); |
| 497 | goto out_1; | 497 | goto free_irq_ppi; |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | 500 | ||
| 501 | if (register_framebuffer(&fbdev->info) < 0) { | 501 | if (register_framebuffer(&fbdev->info) < 0) { |
| 502 | dev_err(&client->dev, "unable to register framebuffer\n"); | 502 | dev_err(&client->dev, "unable to register framebuffer\n"); |
| 503 | ret = -EFAULT; | 503 | ret = -EFAULT; |
| 504 | goto out_1; | 504 | goto free_irq_ppi; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | dev_info(&client->dev, "fb%d: %s frame buffer device\n", | 507 | dev_info(&client->dev, "fb%d: %s frame buffer device\n", |
| @@ -512,7 +512,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
| 512 | if (!entry) { | 512 | if (!entry) { |
| 513 | dev_err(&client->dev, "unable to create /proc entry\n"); | 513 | dev_err(&client->dev, "unable to create /proc entry\n"); |
| 514 | ret = -EFAULT; | 514 | ret = -EFAULT; |
| 515 | goto out_0; | 515 | goto free_fb; |
| 516 | } | 516 | } |
| 517 | 517 | ||
| 518 | entry->read_proc = adv7393_read_proc; | 518 | entry->read_proc = adv7393_read_proc; |
| @@ -521,22 +521,25 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
| 521 | 521 | ||
| 522 | return 0; | 522 | return 0; |
| 523 | 523 | ||
| 524 | out_0: | 524 | free_fb: |
| 525 | unregister_framebuffer(&fbdev->info); | 525 | unregister_framebuffer(&fbdev->info); |
| 526 | out_1: | 526 | free_irq_ppi: |
| 527 | free_irq(IRQ_PPI_ERROR, fbdev); | 527 | free_irq(IRQ_PPI_ERROR, fbdev); |
| 528 | out_3: | 528 | free_ch_ppi: |
| 529 | free_dma(CH_PPI); | 529 | free_dma(CH_PPI); |
| 530 | out_4: | 530 | free_cmap: |
| 531 | dma_free_coherent(NULL, fbdev->fb_len, fbdev->fb_mem, | ||
| 532 | fbdev->dma_handle); | ||
| 533 | out_5: | ||
| 534 | fb_dealloc_cmap(&fbdev->info.cmap); | 531 | fb_dealloc_cmap(&fbdev->info.cmap); |
| 535 | out_6: | 532 | free_palette: |
| 536 | kfree(fbdev->info.pseudo_palette); | 533 | kfree(fbdev->info.pseudo_palette); |
| 537 | out_7: | 534 | free_fb_mem: |
| 535 | dma_free_coherent(NULL, fbdev->fb_len, fbdev->fb_mem, | ||
| 536 | fbdev->dma_handle); | ||
| 537 | free_ppi_pins: | ||
| 538 | peripheral_free_list(ppi_pins); | 538 | peripheral_free_list(ppi_pins); |
| 539 | out_8: | 539 | free_gpio: |
| 540 | if (ANOMALY_05000400) | ||
| 541 | gpio_free(P_IDENT(P_PPI0_FS3)); | ||
| 542 | free_fbdev: | ||
| 540 | kfree(fbdev); | 543 | kfree(fbdev); |
| 541 | 544 | ||
| 542 | return ret; | 545 | return ret; |
diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index f56699d8122a..eae46f6457e2 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Cobalt server LCD frame buffer driver. | 2 | * Cobalt/SEAD3 LCD frame buffer driver. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2008 Yoichi Yuasa <yuasa@linux-mips.org> | 4 | * Copyright (C) 2008 Yoichi Yuasa <yuasa@linux-mips.org> |
| 5 | * Copyright (C) 2012 MIPS Technologies, Inc. | ||
| 5 | * | 6 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
| @@ -62,6 +63,7 @@ | |||
| 62 | #define LCD_CUR_POS(x) ((x) & LCD_CUR_POS_MASK) | 63 | #define LCD_CUR_POS(x) ((x) & LCD_CUR_POS_MASK) |
| 63 | #define LCD_TEXT_POS(x) ((x) | LCD_TEXT_MODE) | 64 | #define LCD_TEXT_POS(x) ((x) | LCD_TEXT_MODE) |
| 64 | 65 | ||
| 66 | #ifdef CONFIG_MIPS_COBALT | ||
| 65 | static inline void lcd_write_control(struct fb_info *info, u8 control) | 67 | static inline void lcd_write_control(struct fb_info *info, u8 control) |
| 66 | { | 68 | { |
| 67 | writel((u32)control << 24, info->screen_base); | 69 | writel((u32)control << 24, info->screen_base); |
| @@ -81,6 +83,47 @@ static inline u8 lcd_read_data(struct fb_info *info) | |||
| 81 | { | 83 | { |
| 82 | return readl(info->screen_base + LCD_DATA_REG_OFFSET) >> 24; | 84 | return readl(info->screen_base + LCD_DATA_REG_OFFSET) >> 24; |
| 83 | } | 85 | } |
| 86 | #else | ||
| 87 | |||
| 88 | #define LCD_CTL 0x00 | ||
| 89 | #define LCD_DATA 0x08 | ||
| 90 | #define CPLD_STATUS 0x10 | ||
| 91 | #define CPLD_DATA 0x18 | ||
| 92 | |||
| 93 | static inline void cpld_wait(struct fb_info *info) | ||
| 94 | { | ||
| 95 | do { | ||
| 96 | } while (readl(info->screen_base + CPLD_STATUS) & 1); | ||
| 97 | } | ||
| 98 | |||
| 99 | static inline void lcd_write_control(struct fb_info *info, u8 control) | ||
| 100 | { | ||
| 101 | cpld_wait(info); | ||
| 102 | writel(control, info->screen_base + LCD_CTL); | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline u8 lcd_read_control(struct fb_info *info) | ||
| 106 | { | ||
| 107 | cpld_wait(info); | ||
| 108 | readl(info->screen_base + LCD_CTL); | ||
| 109 | cpld_wait(info); | ||
| 110 | return readl(info->screen_base + CPLD_DATA) & 0xff; | ||
| 111 | } | ||
| 112 | |||
| 113 | static inline void lcd_write_data(struct fb_info *info, u8 data) | ||
| 114 | { | ||
| 115 | cpld_wait(info); | ||
| 116 | writel(data, info->screen_base + LCD_DATA); | ||
| 117 | } | ||
| 118 | |||
| 119 | static inline u8 lcd_read_data(struct fb_info *info) | ||
| 120 | { | ||
| 121 | cpld_wait(info); | ||
| 122 | readl(info->screen_base + LCD_DATA); | ||
| 123 | cpld_wait(info); | ||
| 124 | return readl(info->screen_base + CPLD_DATA) & 0xff; | ||
| 125 | } | ||
| 126 | #endif | ||
| 84 | 127 | ||
| 85 | static int lcd_busy_wait(struct fb_info *info) | 128 | static int lcd_busy_wait(struct fb_info *info) |
| 86 | { | 129 | { |
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index f8babbeee275..345d96230978 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c | |||
| @@ -507,16 +507,16 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) | |||
| 507 | 507 | ||
| 508 | err = fb_alloc_cmap(&info->cmap, 256, 0); | 508 | err = fb_alloc_cmap(&info->cmap, 256, 0); |
| 509 | if (err) | 509 | if (err) |
| 510 | goto failed; | 510 | goto failed_cmap; |
| 511 | 511 | ||
| 512 | err = ep93xxfb_alloc_videomem(info); | 512 | err = ep93xxfb_alloc_videomem(info); |
| 513 | if (err) | 513 | if (err) |
| 514 | goto failed; | 514 | goto failed_videomem; |
| 515 | 515 | ||
| 516 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 516 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 517 | if (!res) { | 517 | if (!res) { |
| 518 | err = -ENXIO; | 518 | err = -ENXIO; |
| 519 | goto failed; | 519 | goto failed_resource; |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | /* | 522 | /* |
| @@ -532,7 +532,7 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) | |||
| 532 | fbi->mmio_base = ioremap(res->start, resource_size(res)); | 532 | fbi->mmio_base = ioremap(res->start, resource_size(res)); |
| 533 | if (!fbi->mmio_base) { | 533 | if (!fbi->mmio_base) { |
| 534 | err = -ENXIO; | 534 | err = -ENXIO; |
| 535 | goto failed; | 535 | goto failed_resource; |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | strcpy(info->fix.id, pdev->name); | 538 | strcpy(info->fix.id, pdev->name); |
| @@ -553,24 +553,24 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) | |||
| 553 | if (err == 0) { | 553 | if (err == 0) { |
| 554 | dev_err(info->dev, "No suitable video mode found\n"); | 554 | dev_err(info->dev, "No suitable video mode found\n"); |
| 555 | err = -EINVAL; | 555 | err = -EINVAL; |
| 556 | goto failed; | 556 | goto failed_mode; |
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | if (mach_info->setup) { | 559 | if (mach_info->setup) { |
| 560 | err = mach_info->setup(pdev); | 560 | err = mach_info->setup(pdev); |
| 561 | if (err) | 561 | if (err) |
| 562 | return err; | 562 | goto failed_mode; |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | err = ep93xxfb_check_var(&info->var, info); | 565 | err = ep93xxfb_check_var(&info->var, info); |
| 566 | if (err) | 566 | if (err) |
| 567 | goto failed; | 567 | goto failed_check; |
| 568 | 568 | ||
| 569 | fbi->clk = clk_get(info->dev, NULL); | 569 | fbi->clk = clk_get(info->dev, NULL); |
| 570 | if (IS_ERR(fbi->clk)) { | 570 | if (IS_ERR(fbi->clk)) { |
| 571 | err = PTR_ERR(fbi->clk); | 571 | err = PTR_ERR(fbi->clk); |
| 572 | fbi->clk = NULL; | 572 | fbi->clk = NULL; |
| 573 | goto failed; | 573 | goto failed_check; |
| 574 | } | 574 | } |
| 575 | 575 | ||
| 576 | ep93xxfb_set_par(info); | 576 | ep93xxfb_set_par(info); |
| @@ -585,15 +585,17 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) | |||
| 585 | return 0; | 585 | return 0; |
| 586 | 586 | ||
| 587 | failed: | 587 | failed: |
| 588 | if (fbi->clk) | 588 | clk_put(fbi->clk); |
| 589 | clk_put(fbi->clk); | 589 | failed_check: |
| 590 | if (fbi->mmio_base) | ||
| 591 | iounmap(fbi->mmio_base); | ||
| 592 | ep93xxfb_dealloc_videomem(info); | ||
| 593 | if (&info->cmap) | ||
| 594 | fb_dealloc_cmap(&info->cmap); | ||
| 595 | if (fbi->mach_info->teardown) | 590 | if (fbi->mach_info->teardown) |
| 596 | fbi->mach_info->teardown(pdev); | 591 | fbi->mach_info->teardown(pdev); |
| 592 | failed_mode: | ||
| 593 | iounmap(fbi->mmio_base); | ||
| 594 | failed_resource: | ||
| 595 | ep93xxfb_dealloc_videomem(info); | ||
| 596 | failed_videomem: | ||
| 597 | fb_dealloc_cmap(&info->cmap); | ||
| 598 | failed_cmap: | ||
| 597 | kfree(info); | 599 | kfree(info); |
| 598 | platform_set_drvdata(pdev, NULL); | 600 | platform_set_drvdata(pdev, NULL); |
| 599 | 601 | ||
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index 2a4481cf260c..a36b2d28280e 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c | |||
| @@ -21,14 +21,14 @@ | |||
| 21 | 21 | ||
| 22 | #include <video/exynos_dp.h> | 22 | #include <video/exynos_dp.h> |
| 23 | 23 | ||
| 24 | #include <plat/cpu.h> | ||
| 25 | |||
| 26 | #include "exynos_dp_core.h" | 24 | #include "exynos_dp_core.h" |
| 27 | 25 | ||
| 28 | static int exynos_dp_init_dp(struct exynos_dp_device *dp) | 26 | static int exynos_dp_init_dp(struct exynos_dp_device *dp) |
| 29 | { | 27 | { |
| 30 | exynos_dp_reset(dp); | 28 | exynos_dp_reset(dp); |
| 31 | 29 | ||
| 30 | exynos_dp_swreset(dp); | ||
| 31 | |||
| 32 | /* SW defined function Normal operation */ | 32 | /* SW defined function Normal operation */ |
| 33 | exynos_dp_enable_sw_function(dp); | 33 | exynos_dp_enable_sw_function(dp); |
| 34 | 34 | ||
| @@ -478,7 +478,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
| 478 | int lane_count; | 478 | int lane_count; |
| 479 | u8 buf[5]; | 479 | u8 buf[5]; |
| 480 | 480 | ||
| 481 | u8 *adjust_request; | 481 | u8 adjust_request[2]; |
| 482 | u8 voltage_swing; | 482 | u8 voltage_swing; |
| 483 | u8 pre_emphasis; | 483 | u8 pre_emphasis; |
| 484 | u8 training_lane; | 484 | u8 training_lane; |
| @@ -493,8 +493,8 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
| 493 | /* set training pattern 2 for EQ */ | 493 | /* set training pattern 2 for EQ */ |
| 494 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | 494 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); |
| 495 | 495 | ||
| 496 | adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1 | 496 | adjust_request[0] = link_status[4]; |
| 497 | - DPCD_ADDR_LANE0_1_STATUS); | 497 | adjust_request[1] = link_status[5]; |
| 498 | 498 | ||
| 499 | exynos_dp_get_adjust_train(dp, adjust_request); | 499 | exynos_dp_get_adjust_train(dp, adjust_request); |
| 500 | 500 | ||
| @@ -566,7 +566,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | |||
| 566 | u8 buf[5]; | 566 | u8 buf[5]; |
| 567 | u32 reg; | 567 | u32 reg; |
| 568 | 568 | ||
| 569 | u8 *adjust_request; | 569 | u8 adjust_request[2]; |
| 570 | 570 | ||
| 571 | udelay(400); | 571 | udelay(400); |
| 572 | 572 | ||
| @@ -575,8 +575,8 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | |||
| 575 | lane_count = dp->link_train.lane_count; | 575 | lane_count = dp->link_train.lane_count; |
| 576 | 576 | ||
| 577 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 577 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { |
| 578 | adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1 | 578 | adjust_request[0] = link_status[4]; |
| 579 | - DPCD_ADDR_LANE0_1_STATUS); | 579 | adjust_request[1] = link_status[5]; |
| 580 | 580 | ||
| 581 | if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { | 581 | if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { |
| 582 | /* traing pattern Set to Normal */ | 582 | /* traing pattern Set to Normal */ |
| @@ -770,7 +770,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp, | |||
| 770 | return -ETIMEDOUT; | 770 | return -ETIMEDOUT; |
| 771 | } | 771 | } |
| 772 | 772 | ||
| 773 | mdelay(100); | 773 | udelay(1); |
| 774 | } | 774 | } |
| 775 | 775 | ||
| 776 | /* Set to use the register calculated M/N video */ | 776 | /* Set to use the register calculated M/N video */ |
| @@ -804,7 +804,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp, | |||
| 804 | return -ETIMEDOUT; | 804 | return -ETIMEDOUT; |
| 805 | } | 805 | } |
| 806 | 806 | ||
| 807 | mdelay(100); | 807 | mdelay(1); |
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | if (retval != 0) | 810 | if (retval != 0) |
| @@ -860,7 +860,8 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 860 | return -EINVAL; | 860 | return -EINVAL; |
| 861 | } | 861 | } |
| 862 | 862 | ||
| 863 | dp = kzalloc(sizeof(struct exynos_dp_device), GFP_KERNEL); | 863 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), |
| 864 | GFP_KERNEL); | ||
| 864 | if (!dp) { | 865 | if (!dp) { |
| 865 | dev_err(&pdev->dev, "no memory for device data\n"); | 866 | dev_err(&pdev->dev, "no memory for device data\n"); |
| 866 | return -ENOMEM; | 867 | return -ENOMEM; |
| @@ -871,8 +872,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 871 | dp->clock = clk_get(&pdev->dev, "dp"); | 872 | dp->clock = clk_get(&pdev->dev, "dp"); |
| 872 | if (IS_ERR(dp->clock)) { | 873 | if (IS_ERR(dp->clock)) { |
| 873 | dev_err(&pdev->dev, "failed to get clock\n"); | 874 | dev_err(&pdev->dev, "failed to get clock\n"); |
| 874 | ret = PTR_ERR(dp->clock); | 875 | return PTR_ERR(dp->clock); |
| 875 | goto err_dp; | ||
| 876 | } | 876 | } |
| 877 | 877 | ||
| 878 | clk_enable(dp->clock); | 878 | clk_enable(dp->clock); |
| @@ -884,35 +884,25 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 884 | goto err_clock; | 884 | goto err_clock; |
| 885 | } | 885 | } |
| 886 | 886 | ||
| 887 | res = request_mem_region(res->start, resource_size(res), | 887 | dp->reg_base = devm_request_and_ioremap(&pdev->dev, res); |
| 888 | dev_name(&pdev->dev)); | ||
| 889 | if (!res) { | ||
| 890 | dev_err(&pdev->dev, "failed to request registers region\n"); | ||
| 891 | ret = -EINVAL; | ||
| 892 | goto err_clock; | ||
| 893 | } | ||
| 894 | |||
| 895 | dp->res = res; | ||
| 896 | |||
| 897 | dp->reg_base = ioremap(res->start, resource_size(res)); | ||
| 898 | if (!dp->reg_base) { | 888 | if (!dp->reg_base) { |
| 899 | dev_err(&pdev->dev, "failed to ioremap\n"); | 889 | dev_err(&pdev->dev, "failed to ioremap\n"); |
| 900 | ret = -ENOMEM; | 890 | ret = -ENOMEM; |
| 901 | goto err_req_region; | 891 | goto err_clock; |
| 902 | } | 892 | } |
| 903 | 893 | ||
| 904 | dp->irq = platform_get_irq(pdev, 0); | 894 | dp->irq = platform_get_irq(pdev, 0); |
| 905 | if (!dp->irq) { | 895 | if (!dp->irq) { |
| 906 | dev_err(&pdev->dev, "failed to get irq\n"); | 896 | dev_err(&pdev->dev, "failed to get irq\n"); |
| 907 | ret = -ENODEV; | 897 | ret = -ENODEV; |
| 908 | goto err_ioremap; | 898 | goto err_clock; |
| 909 | } | 899 | } |
| 910 | 900 | ||
| 911 | ret = request_irq(dp->irq, exynos_dp_irq_handler, 0, | 901 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, |
| 912 | "exynos-dp", dp); | 902 | "exynos-dp", dp); |
| 913 | if (ret) { | 903 | if (ret) { |
| 914 | dev_err(&pdev->dev, "failed to request irq\n"); | 904 | dev_err(&pdev->dev, "failed to request irq\n"); |
| 915 | goto err_ioremap; | 905 | goto err_clock; |
| 916 | } | 906 | } |
| 917 | 907 | ||
| 918 | dp->video_info = pdata->video_info; | 908 | dp->video_info = pdata->video_info; |
| @@ -924,7 +914,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 924 | ret = exynos_dp_detect_hpd(dp); | 914 | ret = exynos_dp_detect_hpd(dp); |
| 925 | if (ret) { | 915 | if (ret) { |
| 926 | dev_err(&pdev->dev, "unable to detect hpd\n"); | 916 | dev_err(&pdev->dev, "unable to detect hpd\n"); |
| 927 | goto err_irq; | 917 | goto err_clock; |
| 928 | } | 918 | } |
| 929 | 919 | ||
| 930 | exynos_dp_handle_edid(dp); | 920 | exynos_dp_handle_edid(dp); |
| @@ -933,7 +923,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 933 | dp->video_info->link_rate); | 923 | dp->video_info->link_rate); |
| 934 | if (ret) { | 924 | if (ret) { |
| 935 | dev_err(&pdev->dev, "unable to do link train\n"); | 925 | dev_err(&pdev->dev, "unable to do link train\n"); |
| 936 | goto err_irq; | 926 | goto err_clock; |
| 937 | } | 927 | } |
| 938 | 928 | ||
| 939 | exynos_dp_enable_scramble(dp, 1); | 929 | exynos_dp_enable_scramble(dp, 1); |
| @@ -947,23 +937,15 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 947 | ret = exynos_dp_config_video(dp, dp->video_info); | 937 | ret = exynos_dp_config_video(dp, dp->video_info); |
| 948 | if (ret) { | 938 | if (ret) { |
| 949 | dev_err(&pdev->dev, "unable to config video\n"); | 939 | dev_err(&pdev->dev, "unable to config video\n"); |
| 950 | goto err_irq; | 940 | goto err_clock; |
| 951 | } | 941 | } |
| 952 | 942 | ||
| 953 | platform_set_drvdata(pdev, dp); | 943 | platform_set_drvdata(pdev, dp); |
| 954 | 944 | ||
| 955 | return 0; | 945 | return 0; |
| 956 | 946 | ||
| 957 | err_irq: | ||
| 958 | free_irq(dp->irq, dp); | ||
| 959 | err_ioremap: | ||
| 960 | iounmap(dp->reg_base); | ||
| 961 | err_req_region: | ||
| 962 | release_mem_region(res->start, resource_size(res)); | ||
| 963 | err_clock: | 947 | err_clock: |
| 964 | clk_put(dp->clock); | 948 | clk_put(dp->clock); |
| 965 | err_dp: | ||
| 966 | kfree(dp); | ||
| 967 | 949 | ||
| 968 | return ret; | 950 | return ret; |
| 969 | } | 951 | } |
| @@ -976,16 +958,9 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev) | |||
| 976 | if (pdata && pdata->phy_exit) | 958 | if (pdata && pdata->phy_exit) |
| 977 | pdata->phy_exit(); | 959 | pdata->phy_exit(); |
| 978 | 960 | ||
| 979 | free_irq(dp->irq, dp); | ||
| 980 | iounmap(dp->reg_base); | ||
| 981 | |||
| 982 | clk_disable(dp->clock); | 961 | clk_disable(dp->clock); |
| 983 | clk_put(dp->clock); | 962 | clk_put(dp->clock); |
| 984 | 963 | ||
| 985 | release_mem_region(dp->res->start, resource_size(dp->res)); | ||
| 986 | |||
| 987 | kfree(dp); | ||
| 988 | |||
| 989 | return 0; | 964 | return 0; |
| 990 | } | 965 | } |
| 991 | 966 | ||
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 90ceaca0fa24..1e0f998e0c9f 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h | |||
| @@ -26,7 +26,6 @@ struct link_train { | |||
| 26 | 26 | ||
| 27 | struct exynos_dp_device { | 27 | struct exynos_dp_device { |
| 28 | struct device *dev; | 28 | struct device *dev; |
| 29 | struct resource *res; | ||
| 30 | struct clk *clock; | 29 | struct clk *clock; |
| 31 | unsigned int irq; | 30 | unsigned int irq; |
| 32 | void __iomem *reg_base; | 31 | void __iomem *reg_base; |
| @@ -39,8 +38,10 @@ struct exynos_dp_device { | |||
| 39 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable); | 38 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable); |
| 40 | void exynos_dp_stop_video(struct exynos_dp_device *dp); | 39 | void exynos_dp_stop_video(struct exynos_dp_device *dp); |
| 41 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable); | 40 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable); |
| 41 | void exynos_dp_init_analog_param(struct exynos_dp_device *dp); | ||
| 42 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp); | 42 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp); |
| 43 | void exynos_dp_reset(struct exynos_dp_device *dp); | 43 | void exynos_dp_reset(struct exynos_dp_device *dp); |
| 44 | void exynos_dp_swreset(struct exynos_dp_device *dp); | ||
| 44 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp); | 45 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp); |
| 45 | u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); | 46 | u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); |
| 46 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); | 47 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); |
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c index 6548afa0e3d2..6ce76d56c3a1 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/video/exynos/exynos_dp_reg.c | |||
| @@ -16,8 +16,6 @@ | |||
| 16 | 16 | ||
| 17 | #include <video/exynos_dp.h> | 17 | #include <video/exynos_dp.h> |
| 18 | 18 | ||
| 19 | #include <plat/cpu.h> | ||
| 20 | |||
| 21 | #include "exynos_dp_core.h" | 19 | #include "exynos_dp_core.h" |
| 22 | #include "exynos_dp_reg.h" | 20 | #include "exynos_dp_reg.h" |
| 23 | 21 | ||
| @@ -65,6 +63,28 @@ void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable) | |||
| 65 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP); | 63 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP); |
| 66 | } | 64 | } |
| 67 | 65 | ||
| 66 | void exynos_dp_init_analog_param(struct exynos_dp_device *dp) | ||
| 67 | { | ||
| 68 | u32 reg; | ||
| 69 | |||
| 70 | reg = TX_TERMINAL_CTRL_50_OHM; | ||
| 71 | writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1); | ||
| 72 | |||
| 73 | reg = SEL_24M | TX_DVDD_BIT_1_0625V; | ||
| 74 | writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2); | ||
| 75 | |||
| 76 | reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; | ||
| 77 | writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3); | ||
| 78 | |||
| 79 | reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | | ||
| 80 | TX_CUR1_2X | TX_CUR_8_MA; | ||
| 81 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1); | ||
| 82 | |||
| 83 | reg = CH3_AMP_400_MV | CH2_AMP_400_MV | | ||
| 84 | CH1_AMP_400_MV | CH0_AMP_400_MV; | ||
| 85 | writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL); | ||
| 86 | } | ||
| 87 | |||
| 68 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) | 88 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) |
| 69 | { | 89 | { |
| 70 | /* Set interrupt pin assertion polarity as high */ | 90 | /* Set interrupt pin assertion polarity as high */ |
| @@ -89,8 +109,6 @@ void exynos_dp_reset(struct exynos_dp_device *dp) | |||
| 89 | { | 109 | { |
| 90 | u32 reg; | 110 | u32 reg; |
| 91 | 111 | ||
| 92 | writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET); | ||
| 93 | |||
| 94 | exynos_dp_stop_video(dp); | 112 | exynos_dp_stop_video(dp); |
| 95 | exynos_dp_enable_video_mute(dp, 0); | 113 | exynos_dp_enable_video_mute(dp, 0); |
| 96 | 114 | ||
| @@ -131,9 +149,15 @@ void exynos_dp_reset(struct exynos_dp_device *dp) | |||
| 131 | 149 | ||
| 132 | writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | 150 | writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); |
| 133 | 151 | ||
| 152 | exynos_dp_init_analog_param(dp); | ||
| 134 | exynos_dp_init_interrupt(dp); | 153 | exynos_dp_init_interrupt(dp); |
| 135 | } | 154 | } |
| 136 | 155 | ||
| 156 | void exynos_dp_swreset(struct exynos_dp_device *dp) | ||
| 157 | { | ||
| 158 | writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET); | ||
| 159 | } | ||
| 160 | |||
| 137 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp) | 161 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp) |
| 138 | { | 162 | { |
| 139 | u32 reg; | 163 | u32 reg; |
| @@ -271,6 +295,7 @@ void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | |||
| 271 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | 295 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp) |
| 272 | { | 296 | { |
| 273 | u32 reg; | 297 | u32 reg; |
| 298 | int timeout_loop = 0; | ||
| 274 | 299 | ||
| 275 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); | 300 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); |
| 276 | 301 | ||
| @@ -282,9 +307,19 @@ void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | |||
| 282 | writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL); | 307 | writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL); |
| 283 | 308 | ||
| 284 | /* Power up PLL */ | 309 | /* Power up PLL */ |
| 285 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) | 310 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
| 286 | exynos_dp_set_pll_power_down(dp, 0); | 311 | exynos_dp_set_pll_power_down(dp, 0); |
| 287 | 312 | ||
| 313 | while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
| 314 | timeout_loop++; | ||
| 315 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
| 316 | dev_err(dp->dev, "failed to get pll lock status\n"); | ||
| 317 | return; | ||
| 318 | } | ||
| 319 | usleep_range(10, 20); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 288 | /* Enable Serdes FIFO function and Link symbol clock domain module */ | 323 | /* Enable Serdes FIFO function and Link symbol clock domain module */ |
| 289 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | 324 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); |
| 290 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | 325 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N |
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h index 42f608e2a43e..125b27cd57ae 100644 --- a/drivers/video/exynos/exynos_dp_reg.h +++ b/drivers/video/exynos/exynos_dp_reg.h | |||
| @@ -24,6 +24,12 @@ | |||
| 24 | 24 | ||
| 25 | #define EXYNOS_DP_LANE_MAP 0x35C | 25 | #define EXYNOS_DP_LANE_MAP 0x35C |
| 26 | 26 | ||
| 27 | #define EXYNOS_DP_ANALOG_CTL_1 0x370 | ||
| 28 | #define EXYNOS_DP_ANALOG_CTL_2 0x374 | ||
| 29 | #define EXYNOS_DP_ANALOG_CTL_3 0x378 | ||
| 30 | #define EXYNOS_DP_PLL_FILTER_CTL_1 0x37C | ||
| 31 | #define EXYNOS_DP_TX_AMP_TUNING_CTL 0x380 | ||
| 32 | |||
| 27 | #define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390 | 33 | #define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390 |
| 28 | 34 | ||
| 29 | #define EXYNOS_DP_COMMON_INT_STA_1 0x3C4 | 35 | #define EXYNOS_DP_COMMON_INT_STA_1 0x3C4 |
| @@ -166,6 +172,29 @@ | |||
| 166 | #define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) | 172 | #define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) |
| 167 | #define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) | 173 | #define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) |
| 168 | 174 | ||
| 175 | /* EXYNOS_DP_ANALOG_CTL_1 */ | ||
| 176 | #define TX_TERMINAL_CTRL_50_OHM (0x1 << 4) | ||
| 177 | |||
| 178 | /* EXYNOS_DP_ANALOG_CTL_2 */ | ||
| 179 | #define SEL_24M (0x1 << 3) | ||
| 180 | #define TX_DVDD_BIT_1_0625V (0x4 << 0) | ||
| 181 | |||
| 182 | /* EXYNOS_DP_ANALOG_CTL_3 */ | ||
| 183 | #define DRIVE_DVDD_BIT_1_0625V (0x4 << 5) | ||
| 184 | #define VCO_BIT_600_MICRO (0x5 << 0) | ||
| 185 | |||
| 186 | /* EXYNOS_DP_PLL_FILTER_CTL_1 */ | ||
| 187 | #define PD_RING_OSC (0x1 << 6) | ||
| 188 | #define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) | ||
| 189 | #define TX_CUR1_2X (0x1 << 2) | ||
| 190 | #define TX_CUR_8_MA (0x2 << 0) | ||
| 191 | |||
| 192 | /* EXYNOS_DP_TX_AMP_TUNING_CTL */ | ||
| 193 | #define CH3_AMP_400_MV (0x0 << 24) | ||
| 194 | #define CH2_AMP_400_MV (0x0 << 16) | ||
| 195 | #define CH1_AMP_400_MV (0x0 << 8) | ||
| 196 | #define CH0_AMP_400_MV (0x0 << 0) | ||
| 197 | |||
| 169 | /* EXYNOS_DP_AUX_HW_RETRY_CTL */ | 198 | /* EXYNOS_DP_AUX_HW_RETRY_CTL */ |
| 170 | #define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) | 199 | #define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) |
| 171 | #define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) | 200 | #define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) |
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 557091dc0e97..6c1f5c314a42 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c | |||
| @@ -58,7 +58,7 @@ static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device | |||
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static struct regulator_bulk_data supplies[] = { | 60 | static struct regulator_bulk_data supplies[] = { |
| 61 | { .supply = "vdd10", }, | 61 | { .supply = "vdd11", }, |
| 62 | { .supply = "vdd18", }, | 62 | { .supply = "vdd18", }, |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| @@ -102,6 +102,8 @@ static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim) | |||
| 102 | /* set display timing. */ | 102 | /* set display timing. */ |
| 103 | exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); | 103 | exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); |
| 104 | 104 | ||
| 105 | exynos_mipi_dsi_init_interrupt(dsim); | ||
| 106 | |||
| 105 | /* | 107 | /* |
| 106 | * data from Display controller(FIMD) is transferred in video mode | 108 | * data from Display controller(FIMD) is transferred in video mode |
| 107 | * but in case of command mode, all settigs is updated to registers. | 109 | * but in case of command mode, all settigs is updated to registers. |
| @@ -413,27 +415,30 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) | |||
| 413 | goto err_platform_get_irq; | 415 | goto err_platform_get_irq; |
| 414 | } | 416 | } |
| 415 | 417 | ||
| 418 | init_completion(&dsim_wr_comp); | ||
| 419 | init_completion(&dsim_rd_comp); | ||
| 420 | platform_set_drvdata(pdev, dsim); | ||
| 421 | |||
| 416 | ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler, | 422 | ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler, |
| 417 | IRQF_SHARED, pdev->name, dsim); | 423 | IRQF_SHARED, dev_name(&pdev->dev), dsim); |
| 418 | if (ret != 0) { | 424 | if (ret != 0) { |
| 419 | dev_err(&pdev->dev, "failed to request dsim irq\n"); | 425 | dev_err(&pdev->dev, "failed to request dsim irq\n"); |
| 420 | ret = -EINVAL; | 426 | ret = -EINVAL; |
| 421 | goto err_bind; | 427 | goto err_bind; |
| 422 | } | 428 | } |
| 423 | 429 | ||
| 424 | init_completion(&dsim_wr_comp); | 430 | /* enable interrupts */ |
| 425 | init_completion(&dsim_rd_comp); | ||
| 426 | |||
| 427 | /* enable interrupt */ | ||
| 428 | exynos_mipi_dsi_init_interrupt(dsim); | 431 | exynos_mipi_dsi_init_interrupt(dsim); |
| 429 | 432 | ||
| 430 | /* initialize mipi-dsi client(lcd panel). */ | 433 | /* initialize mipi-dsi client(lcd panel). */ |
| 431 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) | 434 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) |
| 432 | dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); | 435 | dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); |
| 433 | 436 | ||
| 434 | /* in case that mipi got enabled at bootloader. */ | 437 | /* in case mipi-dsi has been enabled by bootloader */ |
| 435 | if (dsim_pd->enabled) | 438 | if (dsim_pd->enabled) { |
| 436 | goto out; | 439 | exynos_mipi_regulator_enable(dsim); |
| 440 | goto done; | ||
| 441 | } | ||
| 437 | 442 | ||
| 438 | /* lcd panel power on. */ | 443 | /* lcd panel power on. */ |
| 439 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on) | 444 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on) |
| @@ -453,12 +458,11 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) | |||
| 453 | 458 | ||
| 454 | dsim->suspended = false; | 459 | dsim->suspended = false; |
| 455 | 460 | ||
| 456 | out: | 461 | done: |
| 457 | platform_set_drvdata(pdev, dsim); | 462 | platform_set_drvdata(pdev, dsim); |
| 458 | 463 | ||
| 459 | dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n", | 464 | dev_dbg(&pdev->dev, "%s() completed sucessfuly (%s mode)\n", __func__, |
| 460 | (dsim_config->e_interface == DSIM_COMMAND) ? | 465 | dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB"); |
| 461 | "CPU" : "RGB"); | ||
| 462 | 466 | ||
| 463 | return 0; | 467 | return 0; |
| 464 | 468 | ||
| @@ -515,10 +519,10 @@ static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev) | |||
| 515 | return 0; | 519 | return 0; |
| 516 | } | 520 | } |
| 517 | 521 | ||
| 518 | #ifdef CONFIG_PM | 522 | #ifdef CONFIG_PM_SLEEP |
| 519 | static int exynos_mipi_dsi_suspend(struct platform_device *pdev, | 523 | static int exynos_mipi_dsi_suspend(struct device *dev) |
| 520 | pm_message_t state) | ||
| 521 | { | 524 | { |
| 525 | struct platform_device *pdev = to_platform_device(dev); | ||
| 522 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); | 526 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); |
| 523 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; | 527 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; |
| 524 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; | 528 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; |
| @@ -544,8 +548,9 @@ static int exynos_mipi_dsi_suspend(struct platform_device *pdev, | |||
| 544 | return 0; | 548 | return 0; |
| 545 | } | 549 | } |
| 546 | 550 | ||
| 547 | static int exynos_mipi_dsi_resume(struct platform_device *pdev) | 551 | static int exynos_mipi_dsi_resume(struct device *dev) |
| 548 | { | 552 | { |
| 553 | struct platform_device *pdev = to_platform_device(dev); | ||
| 549 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); | 554 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); |
| 550 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; | 555 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; |
| 551 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; | 556 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; |
| @@ -577,19 +582,19 @@ static int exynos_mipi_dsi_resume(struct platform_device *pdev) | |||
| 577 | 582 | ||
| 578 | return 0; | 583 | return 0; |
| 579 | } | 584 | } |
| 580 | #else | ||
| 581 | #define exynos_mipi_dsi_suspend NULL | ||
| 582 | #define exynos_mipi_dsi_resume NULL | ||
| 583 | #endif | 585 | #endif |
| 584 | 586 | ||
| 587 | static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = { | ||
| 588 | SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume) | ||
| 589 | }; | ||
| 590 | |||
| 585 | static struct platform_driver exynos_mipi_dsi_driver = { | 591 | static struct platform_driver exynos_mipi_dsi_driver = { |
| 586 | .probe = exynos_mipi_dsi_probe, | 592 | .probe = exynos_mipi_dsi_probe, |
| 587 | .remove = __devexit_p(exynos_mipi_dsi_remove), | 593 | .remove = __devexit_p(exynos_mipi_dsi_remove), |
| 588 | .suspend = exynos_mipi_dsi_suspend, | ||
| 589 | .resume = exynos_mipi_dsi_resume, | ||
| 590 | .driver = { | 594 | .driver = { |
| 591 | .name = "exynos-mipi-dsim", | 595 | .name = "exynos-mipi-dsim", |
| 592 | .owner = THIS_MODULE, | 596 | .owner = THIS_MODULE, |
| 597 | .pm = &exynos_mipi_dsi_pm_ops, | ||
| 593 | }, | 598 | }, |
| 594 | }; | 599 | }; |
| 595 | 600 | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index 14909c1d3832..47b533a183be 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c | |||
| @@ -76,33 +76,25 @@ static unsigned int dpll_table[15] = { | |||
| 76 | 76 | ||
| 77 | irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id) | 77 | irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id) |
| 78 | { | 78 | { |
| 79 | unsigned int intsrc = 0; | 79 | struct mipi_dsim_device *dsim = dev_id; |
| 80 | unsigned int intmsk = 0; | 80 | unsigned int intsrc, intmsk; |
| 81 | struct mipi_dsim_device *dsim = NULL; | 81 | |
| 82 | 82 | if (dsim == NULL) { | |
| 83 | dsim = dev_id; | 83 | dev_err(dsim->dev, "%s: wrong parameter\n", __func__); |
| 84 | if (!dsim) { | 84 | return IRQ_NONE; |
| 85 | dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n", | ||
| 86 | __func__); | ||
| 87 | return IRQ_HANDLED; | ||
| 88 | } | 85 | } |
| 89 | 86 | ||
| 90 | intsrc = exynos_mipi_dsi_read_interrupt(dsim); | 87 | intsrc = exynos_mipi_dsi_read_interrupt(dsim); |
| 91 | intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim); | 88 | intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim); |
| 89 | intmsk = ~intmsk & intsrc; | ||
| 92 | 90 | ||
| 93 | intmsk = ~(intmsk) & intsrc; | 91 | if (intsrc & INTMSK_RX_DONE) { |
| 94 | |||
| 95 | switch (intmsk) { | ||
| 96 | case INTMSK_RX_DONE: | ||
| 97 | complete(&dsim_rd_comp); | 92 | complete(&dsim_rd_comp); |
| 98 | dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n"); | 93 | dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n"); |
| 99 | break; | 94 | } |
| 100 | case INTMSK_FIFO_EMPTY: | 95 | if (intsrc & INTMSK_FIFO_EMPTY) { |
| 101 | complete(&dsim_wr_comp); | 96 | complete(&dsim_wr_comp); |
| 102 | dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n"); | 97 | dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n"); |
| 103 | break; | ||
| 104 | default: | ||
| 105 | break; | ||
| 106 | } | 98 | } |
| 107 | 99 | ||
| 108 | exynos_mipi_dsi_clear_interrupt(dsim, intmsk); | 100 | exynos_mipi_dsi_clear_interrupt(dsim, intmsk); |
| @@ -738,11 +730,11 @@ int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, | |||
| 738 | if (dsim_config->auto_vertical_cnt == 0) { | 730 | if (dsim_config->auto_vertical_cnt == 0) { |
| 739 | exynos_mipi_dsi_set_main_disp_vporch(dsim, | 731 | exynos_mipi_dsi_set_main_disp_vporch(dsim, |
| 740 | dsim_config->cmd_allow, | 732 | dsim_config->cmd_allow, |
| 741 | timing->upper_margin, | 733 | timing->lower_margin, |
| 742 | timing->lower_margin); | 734 | timing->upper_margin); |
| 743 | exynos_mipi_dsi_set_main_disp_hporch(dsim, | 735 | exynos_mipi_dsi_set_main_disp_hporch(dsim, |
| 744 | timing->left_margin, | 736 | timing->right_margin, |
| 745 | timing->right_margin); | 737 | timing->left_margin); |
| 746 | exynos_mipi_dsi_set_main_disp_sync_area(dsim, | 738 | exynos_mipi_dsi_set_main_disp_sync_area(dsim, |
| 747 | timing->vsync_len, | 739 | timing->vsync_len, |
| 748 | timing->hsync_len); | 740 | timing->hsync_len); |
diff --git a/drivers/video/exynos/s6e8ax0.c b/drivers/video/exynos/s6e8ax0.c index 4aa9ac6218bf..05d080b63bc0 100644 --- a/drivers/video/exynos/s6e8ax0.c +++ b/drivers/video/exynos/s6e8ax0.c | |||
| @@ -293,9 +293,20 @@ static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd) | |||
| 293 | 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0, | 293 | 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0, |
| 294 | 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8 | 294 | 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8 |
| 295 | }; | 295 | }; |
| 296 | static const unsigned char data_to_send_panel_reverse[] = { | ||
| 297 | 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d, | ||
| 298 | 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08, | ||
| 299 | 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0, | ||
| 300 | 0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1, 0xf6, 0xf6, 0xc1 | ||
| 301 | }; | ||
| 296 | 302 | ||
| 297 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | 303 | if (lcd->dsim_dev->panel_reverse) |
| 298 | data_to_send, ARRAY_SIZE(data_to_send)); | 304 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, |
| 305 | data_to_send_panel_reverse, | ||
| 306 | ARRAY_SIZE(data_to_send_panel_reverse)); | ||
| 307 | else | ||
| 308 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
| 309 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
| 299 | } | 310 | } |
| 300 | 311 | ||
| 301 | static void s6e8ax0_display_cond(struct s6e8ax0 *lcd) | 312 | static void s6e8ax0_display_cond(struct s6e8ax0 *lcd) |
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index c27e153d8882..1ddeb11659d4 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <linux/rmap.h> | 23 | #include <linux/rmap.h> |
| 24 | #include <linux/pagemap.h> | 24 | #include <linux/pagemap.h> |
| 25 | 25 | ||
| 26 | struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs) | 26 | static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs) |
| 27 | { | 27 | { |
| 28 | void *screen_base = (void __force *) info->screen_base; | 28 | void *screen_base = (void __force *) info->screen_base; |
| 29 | struct page *page; | 29 | struct page *page; |
| @@ -107,6 +107,10 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, | |||
| 107 | /* protect against the workqueue changing the page list */ | 107 | /* protect against the workqueue changing the page list */ |
| 108 | mutex_lock(&fbdefio->lock); | 108 | mutex_lock(&fbdefio->lock); |
| 109 | 109 | ||
| 110 | /* first write in this cycle, notify the driver */ | ||
| 111 | if (fbdefio->first_io && list_empty(&fbdefio->pagelist)) | ||
| 112 | fbdefio->first_io(info); | ||
| 113 | |||
| 110 | /* | 114 | /* |
| 111 | * We want the page to remain locked from ->page_mkwrite until | 115 | * We want the page to remain locked from ->page_mkwrite until |
| 112 | * the PTE is marked dirty to avoid page_mkclean() being called | 116 | * the PTE is marked dirty to avoid page_mkclean() being called |
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 67afa9c2289d..a55e3669d135 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c | |||
| @@ -80,6 +80,8 @@ EXPORT_SYMBOL(framebuffer_alloc); | |||
| 80 | */ | 80 | */ |
| 81 | void framebuffer_release(struct fb_info *info) | 81 | void framebuffer_release(struct fb_info *info) |
| 82 | { | 82 | { |
| 83 | if (!info) | ||
| 84 | return; | ||
| 83 | kfree(info->apertures); | 85 | kfree(info->apertures); |
| 84 | kfree(info); | 86 | kfree(info); |
| 85 | } | 87 | } |
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 6af3f16754f0..458c00664ade 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c | |||
| @@ -834,7 +834,6 @@ static void update_lcdc(struct fb_info *info) | |||
| 834 | diu_ops.set_pixel_clock(var->pixclock); | 834 | diu_ops.set_pixel_clock(var->pixclock); |
| 835 | 835 | ||
| 836 | out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ | 836 | out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ |
| 837 | out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ | ||
| 838 | out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ | 837 | out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ |
| 839 | out_be32(&hw->plut, 0x01F5F666); | 838 | out_be32(&hw->plut, 0x01F5F666); |
| 840 | 839 | ||
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 02fd2263610c..bdcbfbae2777 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c | |||
| @@ -680,6 +680,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, | |||
| 680 | + dinfo->fb.size); | 680 | + dinfo->fb.size); |
| 681 | if (!dinfo->aperture.virtual) { | 681 | if (!dinfo->aperture.virtual) { |
| 682 | ERR_MSG("Cannot remap FB region.\n"); | 682 | ERR_MSG("Cannot remap FB region.\n"); |
| 683 | agp_backend_release(bridge); | ||
| 683 | cleanup(dinfo); | 684 | cleanup(dinfo); |
| 684 | return -ENODEV; | 685 | return -ENODEV; |
| 685 | } | 686 | } |
| @@ -689,6 +690,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, | |||
| 689 | INTEL_REG_SIZE); | 690 | INTEL_REG_SIZE); |
| 690 | if (!dinfo->mmio_base) { | 691 | if (!dinfo->mmio_base) { |
| 691 | ERR_MSG("Cannot remap MMIO region.\n"); | 692 | ERR_MSG("Cannot remap MMIO region.\n"); |
| 693 | agp_backend_release(bridge); | ||
| 692 | cleanup(dinfo); | 694 | cleanup(dinfo); |
| 693 | return -ENODEV; | 695 | return -ENODEV; |
| 694 | } | 696 | } |
diff --git a/drivers/video/mb862xx/mb862xx-i2c.c b/drivers/video/mb862xx/mb862xx-i2c.c index 273769bb8deb..c87e17afb3e2 100644 --- a/drivers/video/mb862xx/mb862xx-i2c.c +++ b/drivers/video/mb862xx/mb862xx-i2c.c | |||
| @@ -68,7 +68,7 @@ static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last) | |||
| 68 | return 1; | 68 | return 1; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void mb862xx_i2c_stop(struct i2c_adapter *adap) | 71 | static void mb862xx_i2c_stop(struct i2c_adapter *adap) |
| 72 | { | 72 | { |
| 73 | struct mb862xxfb_par *par = adap->algo_data; | 73 | struct mb862xxfb_par *par = adap->algo_data; |
| 74 | 74 | ||
diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index 11a7a333701d..00ce1f34b496 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c | |||
| @@ -579,7 +579,7 @@ static ssize_t mb862xxfb_show_dispregs(struct device *dev, | |||
| 579 | 579 | ||
| 580 | static DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL); | 580 | static DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL); |
| 581 | 581 | ||
| 582 | irqreturn_t mb862xx_intr(int irq, void *dev_id) | 582 | static irqreturn_t mb862xx_intr(int irq, void *dev_id) |
| 583 | { | 583 | { |
| 584 | struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id; | 584 | struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id; |
| 585 | unsigned long reg_ist, mask; | 585 | unsigned long reg_ist, mask; |
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 55bf6196b7a0..ab0a8e527333 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c | |||
| @@ -950,7 +950,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev) | |||
| 950 | 950 | ||
| 951 | mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, | 951 | mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, |
| 952 | res_size(mfbi->fb_req)); | 952 | res_size(mfbi->fb_req)); |
| 953 | if (!mfbi->reg_virt_addr) { | 953 | if (!mfbi->fb_virt_addr) { |
| 954 | dev_err(&dev->dev, "failed to ioremap frame buffer\n"); | 954 | dev_err(&dev->dev, "failed to ioremap frame buffer\n"); |
| 955 | ret = -EINVAL; | 955 | ret = -EINVAL; |
| 956 | goto err4; | 956 | goto err4; |
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 6c6bc578d0fc..abbe691047bd 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c | |||
| @@ -889,6 +889,18 @@ static int __devexit mxsfb_remove(struct platform_device *pdev) | |||
| 889 | return 0; | 889 | return 0; |
| 890 | } | 890 | } |
| 891 | 891 | ||
| 892 | static void mxsfb_shutdown(struct platform_device *pdev) | ||
| 893 | { | ||
| 894 | struct fb_info *fb_info = platform_get_drvdata(pdev); | ||
| 895 | struct mxsfb_info *host = to_imxfb_host(fb_info); | ||
| 896 | |||
| 897 | /* | ||
| 898 | * Force stop the LCD controller as keeping it running during reboot | ||
| 899 | * might interfere with the BootROM's boot mode pads sampling. | ||
| 900 | */ | ||
| 901 | writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); | ||
| 902 | } | ||
| 903 | |||
| 892 | static struct platform_device_id mxsfb_devtype[] = { | 904 | static struct platform_device_id mxsfb_devtype[] = { |
| 893 | { | 905 | { |
| 894 | .name = "imx23-fb", | 906 | .name = "imx23-fb", |
| @@ -905,6 +917,7 @@ MODULE_DEVICE_TABLE(platform, mxsfb_devtype); | |||
| 905 | static struct platform_driver mxsfb_driver = { | 917 | static struct platform_driver mxsfb_driver = { |
| 906 | .probe = mxsfb_probe, | 918 | .probe = mxsfb_probe, |
| 907 | .remove = __devexit_p(mxsfb_remove), | 919 | .remove = __devexit_p(mxsfb_remove), |
| 920 | .shutdown = mxsfb_shutdown, | ||
| 908 | .id_table = mxsfb_devtype, | 921 | .id_table = mxsfb_devtype, |
| 909 | .driver = { | 922 | .driver = { |
| 910 | .name = DRIVER_NAME, | 923 | .name = DRIVER_NAME, |
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 1e7536d9a8fc..b48f95f0dfe2 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig | |||
| @@ -39,14 +39,6 @@ config FB_OMAP_LCD_MIPID | |||
| 39 | the Mobile Industry Processor Interface DBI-C/DCS | 39 | the Mobile Industry Processor Interface DBI-C/DCS |
| 40 | specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) | 40 | specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) |
| 41 | 41 | ||
| 42 | config FB_OMAP_BOOTLOADER_INIT | ||
| 43 | bool "Check bootloader initialization" | ||
| 44 | depends on FB_OMAP | ||
| 45 | help | ||
| 46 | Say Y here if you want to enable checking if the bootloader has | ||
| 47 | already initialized the display controller. In this case the | ||
| 48 | driver will skip the initialization. | ||
| 49 | |||
| 50 | config FB_OMAP_CONSISTENT_DMA_SIZE | 42 | config FB_OMAP_CONSISTENT_DMA_SIZE |
| 51 | int "Consistent DMA memory size (MB)" | 43 | int "Consistent DMA memory size (MB)" |
| 52 | depends on FB_OMAP | 44 | depends on FB_OMAP |
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index 74e7cf078505..ad741c3d1ae1 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
| @@ -739,12 +739,6 @@ static void acx_panel_set_timings(struct omap_dss_device *dssdev, | |||
| 739 | } | 739 | } |
| 740 | } | 740 | } |
| 741 | 741 | ||
| 742 | static void acx_panel_get_timings(struct omap_dss_device *dssdev, | ||
| 743 | struct omap_video_timings *timings) | ||
| 744 | { | ||
| 745 | *timings = dssdev->panel.timings; | ||
| 746 | } | ||
| 747 | |||
| 748 | static int acx_panel_check_timings(struct omap_dss_device *dssdev, | 742 | static int acx_panel_check_timings(struct omap_dss_device *dssdev, |
| 749 | struct omap_video_timings *timings) | 743 | struct omap_video_timings *timings) |
| 750 | { | 744 | { |
| @@ -762,7 +756,6 @@ static struct omap_dss_driver acx_panel_driver = { | |||
| 762 | .resume = acx_panel_resume, | 756 | .resume = acx_panel_resume, |
| 763 | 757 | ||
| 764 | .set_timings = acx_panel_set_timings, | 758 | .set_timings = acx_panel_set_timings, |
| 765 | .get_timings = acx_panel_get_timings, | ||
| 766 | .check_timings = acx_panel_check_timings, | 759 | .check_timings = acx_panel_check_timings, |
| 767 | 760 | ||
| 768 | .get_recommended_bpp = acx_get_recommended_bpp, | 761 | .get_recommended_bpp = acx_get_recommended_bpp, |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 30fe4dfeb227..e42f9dc22123 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
| @@ -386,6 +386,106 @@ static struct panel_config generic_dpi_panels[] = { | |||
| 386 | 386 | ||
| 387 | .name = "innolux_at080tn52", | 387 | .name = "innolux_at080tn52", |
| 388 | }, | 388 | }, |
| 389 | |||
| 390 | /* Mitsubishi AA084SB01 */ | ||
| 391 | { | ||
| 392 | { | ||
| 393 | .x_res = 800, | ||
| 394 | .y_res = 600, | ||
| 395 | .pixel_clock = 40000, | ||
| 396 | |||
| 397 | .hsw = 1, | ||
| 398 | .hfp = 254, | ||
| 399 | .hbp = 1, | ||
| 400 | |||
| 401 | .vsw = 1, | ||
| 402 | .vfp = 26, | ||
| 403 | .vbp = 1, | ||
| 404 | }, | ||
| 405 | .config = OMAP_DSS_LCD_TFT, | ||
| 406 | .name = "mitsubishi_aa084sb01", | ||
| 407 | }, | ||
| 408 | /* EDT ET0500G0DH6 */ | ||
| 409 | { | ||
| 410 | { | ||
| 411 | .x_res = 800, | ||
| 412 | .y_res = 480, | ||
| 413 | .pixel_clock = 33260, | ||
| 414 | |||
| 415 | .hsw = 128, | ||
| 416 | .hfp = 216, | ||
| 417 | .hbp = 40, | ||
| 418 | |||
| 419 | .vsw = 2, | ||
| 420 | .vfp = 35, | ||
| 421 | .vbp = 10, | ||
| 422 | }, | ||
| 423 | .config = OMAP_DSS_LCD_TFT, | ||
| 424 | .name = "edt_et0500g0dh6", | ||
| 425 | }, | ||
| 426 | |||
| 427 | /* Prime-View PD050VL1 */ | ||
| 428 | { | ||
| 429 | { | ||
| 430 | .x_res = 640, | ||
| 431 | .y_res = 480, | ||
| 432 | |||
| 433 | .pixel_clock = 25000, | ||
| 434 | |||
| 435 | .hsw = 96, | ||
| 436 | .hfp = 18, | ||
| 437 | .hbp = 46, | ||
| 438 | |||
| 439 | .vsw = 2, | ||
| 440 | .vfp = 10, | ||
| 441 | .vbp = 33, | ||
| 442 | }, | ||
| 443 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
| 444 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, | ||
| 445 | .name = "primeview_pd050vl1", | ||
| 446 | }, | ||
| 447 | |||
| 448 | /* Prime-View PM070WL4 */ | ||
| 449 | { | ||
| 450 | { | ||
| 451 | .x_res = 800, | ||
| 452 | .y_res = 480, | ||
| 453 | |||
| 454 | .pixel_clock = 32000, | ||
| 455 | |||
| 456 | .hsw = 128, | ||
| 457 | .hfp = 42, | ||
| 458 | .hbp = 86, | ||
| 459 | |||
| 460 | .vsw = 2, | ||
| 461 | .vfp = 10, | ||
| 462 | .vbp = 33, | ||
| 463 | }, | ||
| 464 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
| 465 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, | ||
| 466 | .name = "primeview_pm070wl4", | ||
| 467 | }, | ||
| 468 | |||
| 469 | /* Prime-View PD104SLF */ | ||
| 470 | { | ||
| 471 | { | ||
| 472 | .x_res = 800, | ||
| 473 | .y_res = 600, | ||
| 474 | |||
| 475 | .pixel_clock = 40000, | ||
| 476 | |||
| 477 | .hsw = 128, | ||
| 478 | .hfp = 42, | ||
| 479 | .hbp = 86, | ||
| 480 | |||
| 481 | .vsw = 4, | ||
| 482 | .vfp = 1, | ||
| 483 | .vbp = 23, | ||
| 484 | }, | ||
| 485 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
| 486 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, | ||
| 487 | .name = "primeview_pd104slf", | ||
| 488 | }, | ||
| 389 | }; | 489 | }; |
| 390 | 490 | ||
| 391 | struct panel_drv_data { | 491 | struct panel_drv_data { |
| @@ -549,12 +649,6 @@ static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | |||
| 549 | dpi_set_timings(dssdev, timings); | 649 | dpi_set_timings(dssdev, timings); |
| 550 | } | 650 | } |
| 551 | 651 | ||
| 552 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, | ||
| 553 | struct omap_video_timings *timings) | ||
| 554 | { | ||
| 555 | *timings = dssdev->panel.timings; | ||
| 556 | } | ||
| 557 | |||
| 558 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, | 652 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, |
| 559 | struct omap_video_timings *timings) | 653 | struct omap_video_timings *timings) |
| 560 | { | 654 | { |
| @@ -571,7 +665,6 @@ static struct omap_dss_driver dpi_driver = { | |||
| 571 | .resume = generic_dpi_panel_resume, | 665 | .resume = generic_dpi_panel_resume, |
| 572 | 666 | ||
| 573 | .set_timings = generic_dpi_panel_set_timings, | 667 | .set_timings = generic_dpi_panel_set_timings, |
| 574 | .get_timings = generic_dpi_panel_get_timings, | ||
| 575 | .check_timings = generic_dpi_panel_check_timings, | 668 | .check_timings = generic_dpi_panel_check_timings, |
| 576 | 669 | ||
| 577 | .driver = { | 670 | .driver = { |
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index dc9408dc93d1..4a34cdc1371b 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c | |||
| @@ -610,12 +610,6 @@ static int n8x0_panel_resume(struct omap_dss_device *dssdev) | |||
| 610 | return 0; | 610 | return 0; |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | static void n8x0_panel_get_timings(struct omap_dss_device *dssdev, | ||
| 614 | struct omap_video_timings *timings) | ||
| 615 | { | ||
| 616 | *timings = dssdev->panel.timings; | ||
| 617 | } | ||
| 618 | |||
| 619 | static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, | 613 | static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, |
| 620 | u16 *xres, u16 *yres) | 614 | u16 *xres, u16 *yres) |
| 621 | { | 615 | { |
| @@ -678,8 +672,6 @@ static struct omap_dss_driver n8x0_panel_driver = { | |||
| 678 | .get_resolution = n8x0_panel_get_resolution, | 672 | .get_resolution = n8x0_panel_get_resolution, |
| 679 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | 673 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, |
| 680 | 674 | ||
| 681 | .get_timings = n8x0_panel_get_timings, | ||
| 682 | |||
| 683 | .driver = { | 675 | .driver = { |
| 684 | .name = "n8x0_panel", | 676 | .name = "n8x0_panel", |
| 685 | .owner = THIS_MODULE, | 677 | .owner = THIS_MODULE, |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index b2dd88b48420..2ce9992f403b 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | #include <linux/gpio.h> | 30 | #include <linux/gpio.h> |
| 31 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
| 32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 33 | #include <linux/regulator/consumer.h> | ||
| 34 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
| 35 | 34 | ||
| 36 | #include <video/omapdss.h> | 35 | #include <video/omapdss.h> |
| @@ -55,73 +54,6 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); | |||
| 55 | 54 | ||
| 56 | static int taal_panel_reset(struct omap_dss_device *dssdev); | 55 | static int taal_panel_reset(struct omap_dss_device *dssdev); |
| 57 | 56 | ||
| 58 | struct panel_regulator { | ||
| 59 | struct regulator *regulator; | ||
| 60 | const char *name; | ||
| 61 | int min_uV; | ||
| 62 | int max_uV; | ||
| 63 | }; | ||
| 64 | |||
| 65 | static void free_regulators(struct panel_regulator *regulators, int n) | ||
| 66 | { | ||
| 67 | int i; | ||
| 68 | |||
| 69 | for (i = 0; i < n; i++) { | ||
| 70 | /* disable/put in reverse order */ | ||
| 71 | regulator_disable(regulators[n - i - 1].regulator); | ||
| 72 | regulator_put(regulators[n - i - 1].regulator); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | static int init_regulators(struct omap_dss_device *dssdev, | ||
| 77 | struct panel_regulator *regulators, int n) | ||
| 78 | { | ||
| 79 | int r, i, v; | ||
| 80 | |||
| 81 | for (i = 0; i < n; i++) { | ||
| 82 | struct regulator *reg; | ||
| 83 | |||
| 84 | reg = regulator_get(&dssdev->dev, regulators[i].name); | ||
| 85 | if (IS_ERR(reg)) { | ||
| 86 | dev_err(&dssdev->dev, "failed to get regulator %s\n", | ||
| 87 | regulators[i].name); | ||
| 88 | r = PTR_ERR(reg); | ||
| 89 | goto err; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* FIXME: better handling of fixed vs. variable regulators */ | ||
| 93 | v = regulator_get_voltage(reg); | ||
| 94 | if (v < regulators[i].min_uV || v > regulators[i].max_uV) { | ||
| 95 | r = regulator_set_voltage(reg, regulators[i].min_uV, | ||
| 96 | regulators[i].max_uV); | ||
| 97 | if (r) { | ||
| 98 | dev_err(&dssdev->dev, | ||
| 99 | "failed to set regulator %s voltage\n", | ||
| 100 | regulators[i].name); | ||
| 101 | regulator_put(reg); | ||
| 102 | goto err; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | r = regulator_enable(reg); | ||
| 107 | if (r) { | ||
| 108 | dev_err(&dssdev->dev, "failed to enable regulator %s\n", | ||
| 109 | regulators[i].name); | ||
| 110 | regulator_put(reg); | ||
| 111 | goto err; | ||
| 112 | } | ||
| 113 | |||
| 114 | regulators[i].regulator = reg; | ||
| 115 | } | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | |||
| 119 | err: | ||
| 120 | free_regulators(regulators, i); | ||
| 121 | |||
| 122 | return r; | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | 57 | /** |
| 126 | * struct panel_config - panel configuration | 58 | * struct panel_config - panel configuration |
| 127 | * @name: panel name | 59 | * @name: panel name |
| @@ -150,8 +82,6 @@ struct panel_config { | |||
| 150 | unsigned int low; | 82 | unsigned int low; |
| 151 | } reset_sequence; | 83 | } reset_sequence; |
| 152 | 84 | ||
| 153 | struct panel_regulator *regulators; | ||
| 154 | int num_regulators; | ||
| 155 | }; | 85 | }; |
| 156 | 86 | ||
| 157 | enum { | 87 | enum { |
| @@ -577,12 +507,6 @@ static const struct backlight_ops taal_bl_ops = { | |||
| 577 | .update_status = taal_bl_update_status, | 507 | .update_status = taal_bl_update_status, |
| 578 | }; | 508 | }; |
| 579 | 509 | ||
| 580 | static void taal_get_timings(struct omap_dss_device *dssdev, | ||
| 581 | struct omap_video_timings *timings) | ||
| 582 | { | ||
| 583 | *timings = dssdev->panel.timings; | ||
| 584 | } | ||
| 585 | |||
| 586 | static void taal_get_resolution(struct omap_dss_device *dssdev, | 510 | static void taal_get_resolution(struct omap_dss_device *dssdev, |
| 587 | u16 *xres, u16 *yres) | 511 | u16 *xres, u16 *yres) |
| 588 | { | 512 | { |
| @@ -977,11 +901,6 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
| 977 | 901 | ||
| 978 | atomic_set(&td->do_update, 0); | 902 | atomic_set(&td->do_update, 0); |
| 979 | 903 | ||
| 980 | r = init_regulators(dssdev, panel_config->regulators, | ||
| 981 | panel_config->num_regulators); | ||
| 982 | if (r) | ||
| 983 | goto err_reg; | ||
| 984 | |||
| 985 | td->workqueue = create_singlethread_workqueue("taal_esd"); | 904 | td->workqueue = create_singlethread_workqueue("taal_esd"); |
| 986 | if (td->workqueue == NULL) { | 905 | if (td->workqueue == NULL) { |
| 987 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); | 906 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); |
| @@ -1087,8 +1006,6 @@ err_bl: | |||
| 1087 | err_rst_gpio: | 1006 | err_rst_gpio: |
| 1088 | destroy_workqueue(td->workqueue); | 1007 | destroy_workqueue(td->workqueue); |
| 1089 | err_wq: | 1008 | err_wq: |
| 1090 | free_regulators(panel_config->regulators, panel_config->num_regulators); | ||
| 1091 | err_reg: | ||
| 1092 | kfree(td); | 1009 | kfree(td); |
| 1093 | err: | 1010 | err: |
| 1094 | return r; | 1011 | return r; |
| @@ -1125,9 +1042,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) | |||
| 1125 | /* reset, to be sure that the panel is in a valid state */ | 1042 | /* reset, to be sure that the panel is in a valid state */ |
| 1126 | taal_hw_reset(dssdev); | 1043 | taal_hw_reset(dssdev); |
| 1127 | 1044 | ||
| 1128 | free_regulators(td->panel_config->regulators, | ||
| 1129 | td->panel_config->num_regulators); | ||
| 1130 | |||
| 1131 | if (gpio_is_valid(panel_data->reset_gpio)) | 1045 | if (gpio_is_valid(panel_data->reset_gpio)) |
| 1132 | gpio_free(panel_data->reset_gpio); | 1046 | gpio_free(panel_data->reset_gpio); |
| 1133 | 1047 | ||
| @@ -1909,8 +1823,6 @@ static struct omap_dss_driver taal_driver = { | |||
| 1909 | .run_test = taal_run_test, | 1823 | .run_test = taal_run_test, |
| 1910 | .memory_read = taal_memory_read, | 1824 | .memory_read = taal_memory_read, |
| 1911 | 1825 | ||
| 1912 | .get_timings = taal_get_timings, | ||
| 1913 | |||
| 1914 | .driver = { | 1826 | .driver = { |
| 1915 | .name = "taal", | 1827 | .name = "taal", |
| 1916 | .owner = THIS_MODULE, | 1828 | .owner = THIS_MODULE, |
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 52637fa8fda8..bff306e041ca 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c | |||
| @@ -47,13 +47,9 @@ struct panel_drv_data { | |||
| 47 | struct mutex lock; | 47 | struct mutex lock; |
| 48 | 48 | ||
| 49 | int pd_gpio; | 49 | int pd_gpio; |
| 50 | }; | ||
| 51 | 50 | ||
| 52 | static inline struct tfp410_platform_data | 51 | struct i2c_adapter *i2c_adapter; |
| 53 | *get_pdata(const struct omap_dss_device *dssdev) | 52 | }; |
| 54 | { | ||
| 55 | return dssdev->data; | ||
| 56 | } | ||
| 57 | 53 | ||
| 58 | static int tfp410_power_on(struct omap_dss_device *dssdev) | 54 | static int tfp410_power_on(struct omap_dss_device *dssdev) |
| 59 | { | 55 | { |
| @@ -68,7 +64,7 @@ static int tfp410_power_on(struct omap_dss_device *dssdev) | |||
| 68 | goto err0; | 64 | goto err0; |
| 69 | 65 | ||
| 70 | if (gpio_is_valid(ddata->pd_gpio)) | 66 | if (gpio_is_valid(ddata->pd_gpio)) |
| 71 | gpio_set_value(ddata->pd_gpio, 1); | 67 | gpio_set_value_cansleep(ddata->pd_gpio, 1); |
| 72 | 68 | ||
| 73 | return 0; | 69 | return 0; |
| 74 | err0: | 70 | err0: |
| @@ -83,18 +79,18 @@ static void tfp410_power_off(struct omap_dss_device *dssdev) | |||
| 83 | return; | 79 | return; |
| 84 | 80 | ||
| 85 | if (gpio_is_valid(ddata->pd_gpio)) | 81 | if (gpio_is_valid(ddata->pd_gpio)) |
| 86 | gpio_set_value(ddata->pd_gpio, 0); | 82 | gpio_set_value_cansleep(ddata->pd_gpio, 0); |
| 87 | 83 | ||
| 88 | omapdss_dpi_display_disable(dssdev); | 84 | omapdss_dpi_display_disable(dssdev); |
| 89 | } | 85 | } |
| 90 | 86 | ||
| 91 | static int tfp410_probe(struct omap_dss_device *dssdev) | 87 | static int tfp410_probe(struct omap_dss_device *dssdev) |
| 92 | { | 88 | { |
| 93 | struct tfp410_platform_data *pdata = get_pdata(dssdev); | ||
| 94 | struct panel_drv_data *ddata; | 89 | struct panel_drv_data *ddata; |
| 95 | int r; | 90 | int r; |
| 91 | int i2c_bus_num; | ||
| 96 | 92 | ||
| 97 | ddata = kzalloc(sizeof(*ddata), GFP_KERNEL); | 93 | ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL); |
| 98 | if (!ddata) | 94 | if (!ddata) |
| 99 | return -ENOMEM; | 95 | return -ENOMEM; |
| 100 | 96 | ||
| @@ -104,10 +100,15 @@ static int tfp410_probe(struct omap_dss_device *dssdev) | |||
| 104 | ddata->dssdev = dssdev; | 100 | ddata->dssdev = dssdev; |
| 105 | mutex_init(&ddata->lock); | 101 | mutex_init(&ddata->lock); |
| 106 | 102 | ||
| 107 | if (pdata) | 103 | if (dssdev->data) { |
| 104 | struct tfp410_platform_data *pdata = dssdev->data; | ||
| 105 | |||
| 108 | ddata->pd_gpio = pdata->power_down_gpio; | 106 | ddata->pd_gpio = pdata->power_down_gpio; |
| 109 | else | 107 | i2c_bus_num = pdata->i2c_bus_num; |
| 108 | } else { | ||
| 110 | ddata->pd_gpio = -1; | 109 | ddata->pd_gpio = -1; |
| 110 | i2c_bus_num = -1; | ||
| 111 | } | ||
| 111 | 112 | ||
| 112 | if (gpio_is_valid(ddata->pd_gpio)) { | 113 | if (gpio_is_valid(ddata->pd_gpio)) { |
| 113 | r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW, | 114 | r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW, |
| @@ -115,13 +116,31 @@ static int tfp410_probe(struct omap_dss_device *dssdev) | |||
| 115 | if (r) { | 116 | if (r) { |
| 116 | dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", | 117 | dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", |
| 117 | ddata->pd_gpio); | 118 | ddata->pd_gpio); |
| 118 | ddata->pd_gpio = -1; | 119 | return r; |
| 119 | } | 120 | } |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 123 | if (i2c_bus_num != -1) { | ||
| 124 | struct i2c_adapter *adapter; | ||
| 125 | |||
| 126 | adapter = i2c_get_adapter(i2c_bus_num); | ||
| 127 | if (!adapter) { | ||
| 128 | dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", | ||
| 129 | i2c_bus_num); | ||
| 130 | r = -EINVAL; | ||
| 131 | goto err_i2c; | ||
| 132 | } | ||
| 133 | |||
| 134 | ddata->i2c_adapter = adapter; | ||
| 135 | } | ||
| 136 | |||
| 122 | dev_set_drvdata(&dssdev->dev, ddata); | 137 | dev_set_drvdata(&dssdev->dev, ddata); |
| 123 | 138 | ||
| 124 | return 0; | 139 | return 0; |
| 140 | err_i2c: | ||
| 141 | if (gpio_is_valid(ddata->pd_gpio)) | ||
| 142 | gpio_free(ddata->pd_gpio); | ||
| 143 | return r; | ||
| 125 | } | 144 | } |
| 126 | 145 | ||
| 127 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) | 146 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) |
| @@ -130,14 +149,15 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev) | |||
| 130 | 149 | ||
| 131 | mutex_lock(&ddata->lock); | 150 | mutex_lock(&ddata->lock); |
| 132 | 151 | ||
| 152 | if (ddata->i2c_adapter) | ||
| 153 | i2c_put_adapter(ddata->i2c_adapter); | ||
| 154 | |||
| 133 | if (gpio_is_valid(ddata->pd_gpio)) | 155 | if (gpio_is_valid(ddata->pd_gpio)) |
| 134 | gpio_free(ddata->pd_gpio); | 156 | gpio_free(ddata->pd_gpio); |
| 135 | 157 | ||
| 136 | dev_set_drvdata(&dssdev->dev, NULL); | 158 | dev_set_drvdata(&dssdev->dev, NULL); |
| 137 | 159 | ||
| 138 | mutex_unlock(&ddata->lock); | 160 | mutex_unlock(&ddata->lock); |
| 139 | |||
| 140 | kfree(ddata); | ||
| 141 | } | 161 | } |
| 142 | 162 | ||
| 143 | static int tfp410_enable(struct omap_dss_device *dssdev) | 163 | static int tfp410_enable(struct omap_dss_device *dssdev) |
| @@ -269,27 +289,17 @@ static int tfp410_read_edid(struct omap_dss_device *dssdev, | |||
| 269 | u8 *edid, int len) | 289 | u8 *edid, int len) |
| 270 | { | 290 | { |
| 271 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 291 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
| 272 | struct tfp410_platform_data *pdata = get_pdata(dssdev); | ||
| 273 | struct i2c_adapter *adapter; | ||
| 274 | int r, l, bytes_read; | 292 | int r, l, bytes_read; |
| 275 | 293 | ||
| 276 | mutex_lock(&ddata->lock); | 294 | mutex_lock(&ddata->lock); |
| 277 | 295 | ||
| 278 | if (pdata->i2c_bus_num == 0) { | 296 | if (!ddata->i2c_adapter) { |
| 279 | r = -ENODEV; | 297 | r = -ENODEV; |
| 280 | goto err; | 298 | goto err; |
| 281 | } | 299 | } |
| 282 | 300 | ||
| 283 | adapter = i2c_get_adapter(pdata->i2c_bus_num); | ||
| 284 | if (!adapter) { | ||
| 285 | dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", | ||
| 286 | pdata->i2c_bus_num); | ||
| 287 | r = -EINVAL; | ||
| 288 | goto err; | ||
| 289 | } | ||
| 290 | |||
| 291 | l = min(EDID_LENGTH, len); | 301 | l = min(EDID_LENGTH, len); |
| 292 | r = tfp410_ddc_read(adapter, edid, l, 0); | 302 | r = tfp410_ddc_read(ddata->i2c_adapter, edid, l, 0); |
| 293 | if (r) | 303 | if (r) |
| 294 | goto err; | 304 | goto err; |
| 295 | 305 | ||
| @@ -299,7 +309,7 @@ static int tfp410_read_edid(struct omap_dss_device *dssdev, | |||
| 299 | if (len > EDID_LENGTH && edid[0x7e] > 0) { | 309 | if (len > EDID_LENGTH && edid[0x7e] > 0) { |
| 300 | l = min(EDID_LENGTH, len - EDID_LENGTH); | 310 | l = min(EDID_LENGTH, len - EDID_LENGTH); |
| 301 | 311 | ||
| 302 | r = tfp410_ddc_read(adapter, edid + EDID_LENGTH, | 312 | r = tfp410_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH, |
| 303 | l, EDID_LENGTH); | 313 | l, EDID_LENGTH); |
| 304 | if (r) | 314 | if (r) |
| 305 | goto err; | 315 | goto err; |
| @@ -319,21 +329,15 @@ err: | |||
| 319 | static bool tfp410_detect(struct omap_dss_device *dssdev) | 329 | static bool tfp410_detect(struct omap_dss_device *dssdev) |
| 320 | { | 330 | { |
| 321 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 331 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
| 322 | struct tfp410_platform_data *pdata = get_pdata(dssdev); | ||
| 323 | struct i2c_adapter *adapter; | ||
| 324 | unsigned char out; | 332 | unsigned char out; |
| 325 | int r; | 333 | int r; |
| 326 | 334 | ||
| 327 | mutex_lock(&ddata->lock); | 335 | mutex_lock(&ddata->lock); |
| 328 | 336 | ||
| 329 | if (pdata->i2c_bus_num == 0) | 337 | if (!ddata->i2c_adapter) |
| 330 | goto out; | ||
| 331 | |||
| 332 | adapter = i2c_get_adapter(pdata->i2c_bus_num); | ||
| 333 | if (!adapter) | ||
| 334 | goto out; | 338 | goto out; |
| 335 | 339 | ||
| 336 | r = tfp410_ddc_read(adapter, &out, 1, 0); | 340 | r = tfp410_ddc_read(ddata->i2c_adapter, &out, 1, 0); |
| 337 | 341 | ||
| 338 | mutex_unlock(&ddata->lock); | 342 | mutex_unlock(&ddata->lock); |
| 339 | 343 | ||
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 32f3fcd7f0f0..4b6448b3c31f 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
| @@ -272,13 +272,16 @@ static const struct omap_video_timings tpo_td043_timings = { | |||
| 272 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | 272 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) |
| 273 | { | 273 | { |
| 274 | int nreset_gpio = tpo_td043->nreset_gpio; | 274 | int nreset_gpio = tpo_td043->nreset_gpio; |
| 275 | int r; | ||
| 275 | 276 | ||
| 276 | if (tpo_td043->powered_on) | 277 | if (tpo_td043->powered_on) |
| 277 | return 0; | 278 | return 0; |
| 278 | 279 | ||
| 279 | regulator_enable(tpo_td043->vcc_reg); | 280 | r = regulator_enable(tpo_td043->vcc_reg); |
| 281 | if (r != 0) | ||
| 282 | return r; | ||
| 280 | 283 | ||
| 281 | /* wait for regulator to stabilize */ | 284 | /* wait for panel to stabilize */ |
| 282 | msleep(160); | 285 | msleep(160); |
| 283 | 286 | ||
| 284 | if (gpio_is_valid(nreset_gpio)) | 287 | if (gpio_is_valid(nreset_gpio)) |
| @@ -470,6 +473,18 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev) | |||
| 470 | gpio_free(nreset_gpio); | 473 | gpio_free(nreset_gpio); |
| 471 | } | 474 | } |
| 472 | 475 | ||
| 476 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, | ||
| 477 | struct omap_video_timings *timings) | ||
| 478 | { | ||
| 479 | dpi_set_timings(dssdev, timings); | ||
| 480 | } | ||
| 481 | |||
| 482 | static int tpo_td043_check_timings(struct omap_dss_device *dssdev, | ||
| 483 | struct omap_video_timings *timings) | ||
| 484 | { | ||
| 485 | return dpi_check_timings(dssdev, timings); | ||
| 486 | } | ||
| 487 | |||
| 473 | static struct omap_dss_driver tpo_td043_driver = { | 488 | static struct omap_dss_driver tpo_td043_driver = { |
| 474 | .probe = tpo_td043_probe, | 489 | .probe = tpo_td043_probe, |
| 475 | .remove = tpo_td043_remove, | 490 | .remove = tpo_td043_remove, |
| @@ -481,6 +496,9 @@ static struct omap_dss_driver tpo_td043_driver = { | |||
| 481 | .set_mirror = tpo_td043_set_hmirror, | 496 | .set_mirror = tpo_td043_set_hmirror, |
| 482 | .get_mirror = tpo_td043_get_hmirror, | 497 | .get_mirror = tpo_td043_get_hmirror, |
| 483 | 498 | ||
| 499 | .set_timings = tpo_td043_set_timings, | ||
| 500 | .check_timings = tpo_td043_check_timings, | ||
| 501 | |||
| 484 | .driver = { | 502 | .driver = { |
| 485 | .name = "tpo_td043mtea1_panel", | 503 | .name = "tpo_td043mtea1_panel", |
| 486 | .owner = THIS_MODULE, | 504 | .owner = THIS_MODULE, |
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 7be7c06a249e..43324e5ed25f 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig | |||
| @@ -68,6 +68,10 @@ config OMAP4_DSS_HDMI | |||
| 68 | HDMI Interface. This adds the High Definition Multimedia Interface. | 68 | HDMI Interface. This adds the High Definition Multimedia Interface. |
| 69 | See http://www.hdmi.org/ for HDMI specification. | 69 | See http://www.hdmi.org/ for HDMI specification. |
| 70 | 70 | ||
| 71 | config OMAP4_DSS_HDMI_AUDIO | ||
| 72 | bool | ||
| 73 | depends on OMAP4_DSS_HDMI | ||
| 74 | |||
| 71 | config OMAP2_DSS_SDI | 75 | config OMAP2_DSS_SDI |
| 72 | bool "SDI support" | 76 | bool "SDI support" |
| 73 | depends on ARCH_OMAP3 | 77 | depends on ARCH_OMAP3 |
| @@ -90,15 +94,6 @@ config OMAP2_DSS_DSI | |||
| 90 | 94 | ||
| 91 | See http://www.mipi.org/ for DSI spesifications. | 95 | See http://www.mipi.org/ for DSI spesifications. |
| 92 | 96 | ||
| 93 | config OMAP2_DSS_FAKE_VSYNC | ||
| 94 | bool "Fake VSYNC irq from manual update displays" | ||
| 95 | default n | ||
| 96 | help | ||
| 97 | If this is selected, DSI will generate a fake DISPC VSYNC interrupt | ||
| 98 | when DSI has sent a frame. This is only needed with DSI or RFBI | ||
| 99 | displays using manual mode, and you want VSYNC to, for example, | ||
| 100 | time animation. | ||
| 101 | |||
| 102 | config OMAP2_DSS_MIN_FCK_PER_PCK | 97 | config OMAP2_DSS_MIN_FCK_PER_PCK |
| 103 | int "Minimum FCK/PCK ratio (for scaling)" | 98 | int "Minimum FCK/PCK ratio (for scaling)" |
| 104 | range 0 32 | 99 | range 0 32 |
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index b10b3bc1931e..ab22cc224f3e 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
| @@ -99,6 +99,11 @@ struct mgr_priv_data { | |||
| 99 | 99 | ||
| 100 | /* If true, a display is enabled using this manager */ | 100 | /* If true, a display is enabled using this manager */ |
| 101 | bool enabled; | 101 | bool enabled; |
| 102 | |||
| 103 | bool extra_info_dirty; | ||
| 104 | bool shadow_extra_info_dirty; | ||
| 105 | |||
| 106 | struct omap_video_timings timings; | ||
| 102 | }; | 107 | }; |
| 103 | 108 | ||
| 104 | static struct { | 109 | static struct { |
| @@ -176,7 +181,7 @@ static bool mgr_manual_update(struct omap_overlay_manager *mgr) | |||
| 176 | } | 181 | } |
| 177 | 182 | ||
| 178 | static int dss_check_settings_low(struct omap_overlay_manager *mgr, | 183 | static int dss_check_settings_low(struct omap_overlay_manager *mgr, |
| 179 | struct omap_dss_device *dssdev, bool applying) | 184 | bool applying) |
| 180 | { | 185 | { |
| 181 | struct omap_overlay_info *oi; | 186 | struct omap_overlay_info *oi; |
| 182 | struct omap_overlay_manager_info *mi; | 187 | struct omap_overlay_manager_info *mi; |
| @@ -187,6 +192,9 @@ static int dss_check_settings_low(struct omap_overlay_manager *mgr, | |||
| 187 | 192 | ||
| 188 | mp = get_mgr_priv(mgr); | 193 | mp = get_mgr_priv(mgr); |
| 189 | 194 | ||
| 195 | if (!mp->enabled) | ||
| 196 | return 0; | ||
| 197 | |||
| 190 | if (applying && mp->user_info_dirty) | 198 | if (applying && mp->user_info_dirty) |
| 191 | mi = &mp->user_info; | 199 | mi = &mp->user_info; |
| 192 | else | 200 | else |
| @@ -206,26 +214,24 @@ static int dss_check_settings_low(struct omap_overlay_manager *mgr, | |||
| 206 | ois[ovl->id] = oi; | 214 | ois[ovl->id] = oi; |
| 207 | } | 215 | } |
| 208 | 216 | ||
| 209 | return dss_mgr_check(mgr, dssdev, mi, ois); | 217 | return dss_mgr_check(mgr, mi, &mp->timings, ois); |
| 210 | } | 218 | } |
| 211 | 219 | ||
| 212 | /* | 220 | /* |
| 213 | * check manager and overlay settings using overlay_info from data->info | 221 | * check manager and overlay settings using overlay_info from data->info |
| 214 | */ | 222 | */ |
| 215 | static int dss_check_settings(struct omap_overlay_manager *mgr, | 223 | static int dss_check_settings(struct omap_overlay_manager *mgr) |
| 216 | struct omap_dss_device *dssdev) | ||
| 217 | { | 224 | { |
| 218 | return dss_check_settings_low(mgr, dssdev, false); | 225 | return dss_check_settings_low(mgr, false); |
| 219 | } | 226 | } |
| 220 | 227 | ||
| 221 | /* | 228 | /* |
| 222 | * check manager and overlay settings using overlay_info from ovl->info if | 229 | * check manager and overlay settings using overlay_info from ovl->info if |
| 223 | * dirty and from data->info otherwise | 230 | * dirty and from data->info otherwise |
| 224 | */ | 231 | */ |
| 225 | static int dss_check_settings_apply(struct omap_overlay_manager *mgr, | 232 | static int dss_check_settings_apply(struct omap_overlay_manager *mgr) |
| 226 | struct omap_dss_device *dssdev) | ||
| 227 | { | 233 | { |
| 228 | return dss_check_settings_low(mgr, dssdev, true); | 234 | return dss_check_settings_low(mgr, true); |
| 229 | } | 235 | } |
| 230 | 236 | ||
| 231 | static bool need_isr(void) | 237 | static bool need_isr(void) |
| @@ -261,6 +267,20 @@ static bool need_isr(void) | |||
| 261 | if (mp->shadow_info_dirty) | 267 | if (mp->shadow_info_dirty) |
| 262 | return true; | 268 | return true; |
| 263 | 269 | ||
| 270 | /* | ||
| 271 | * NOTE: we don't check extra_info flags for disabled | ||
| 272 | * managers, once the manager is enabled, the extra_info | ||
| 273 | * related manager changes will be taken in by HW. | ||
| 274 | */ | ||
| 275 | |||
| 276 | /* to write new values to registers */ | ||
| 277 | if (mp->extra_info_dirty) | ||
| 278 | return true; | ||
| 279 | |||
| 280 | /* to set GO bit */ | ||
| 281 | if (mp->shadow_extra_info_dirty) | ||
| 282 | return true; | ||
| 283 | |||
| 264 | list_for_each_entry(ovl, &mgr->overlays, list) { | 284 | list_for_each_entry(ovl, &mgr->overlays, list) { |
| 265 | struct ovl_priv_data *op; | 285 | struct ovl_priv_data *op; |
| 266 | 286 | ||
| @@ -305,7 +325,7 @@ static bool need_go(struct omap_overlay_manager *mgr) | |||
| 305 | 325 | ||
| 306 | mp = get_mgr_priv(mgr); | 326 | mp = get_mgr_priv(mgr); |
| 307 | 327 | ||
| 308 | if (mp->shadow_info_dirty) | 328 | if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty) |
| 309 | return true; | 329 | return true; |
| 310 | 330 | ||
| 311 | list_for_each_entry(ovl, &mgr->overlays, list) { | 331 | list_for_each_entry(ovl, &mgr->overlays, list) { |
| @@ -320,20 +340,16 @@ static bool need_go(struct omap_overlay_manager *mgr) | |||
| 320 | /* returns true if an extra_info field is currently being updated */ | 340 | /* returns true if an extra_info field is currently being updated */ |
| 321 | static bool extra_info_update_ongoing(void) | 341 | static bool extra_info_update_ongoing(void) |
| 322 | { | 342 | { |
| 323 | const int num_ovls = omap_dss_get_num_overlays(); | 343 | const int num_mgrs = dss_feat_get_num_mgrs(); |
| 324 | struct ovl_priv_data *op; | ||
| 325 | struct omap_overlay *ovl; | ||
| 326 | struct mgr_priv_data *mp; | ||
| 327 | int i; | 344 | int i; |
| 328 | 345 | ||
| 329 | for (i = 0; i < num_ovls; ++i) { | 346 | for (i = 0; i < num_mgrs; ++i) { |
| 330 | ovl = omap_dss_get_overlay(i); | 347 | struct omap_overlay_manager *mgr; |
| 331 | op = get_ovl_priv(ovl); | 348 | struct omap_overlay *ovl; |
| 332 | 349 | struct mgr_priv_data *mp; | |
| 333 | if (!ovl->manager) | ||
| 334 | continue; | ||
| 335 | 350 | ||
| 336 | mp = get_mgr_priv(ovl->manager); | 351 | mgr = omap_dss_get_overlay_manager(i); |
| 352 | mp = get_mgr_priv(mgr); | ||
| 337 | 353 | ||
| 338 | if (!mp->enabled) | 354 | if (!mp->enabled) |
| 339 | continue; | 355 | continue; |
| @@ -341,8 +357,15 @@ static bool extra_info_update_ongoing(void) | |||
| 341 | if (!mp->updating) | 357 | if (!mp->updating) |
| 342 | continue; | 358 | continue; |
| 343 | 359 | ||
| 344 | if (op->extra_info_dirty || op->shadow_extra_info_dirty) | 360 | if (mp->extra_info_dirty || mp->shadow_extra_info_dirty) |
| 345 | return true; | 361 | return true; |
| 362 | |||
| 363 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
| 364 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
| 365 | |||
| 366 | if (op->extra_info_dirty || op->shadow_extra_info_dirty) | ||
| 367 | return true; | ||
| 368 | } | ||
| 346 | } | 369 | } |
| 347 | 370 | ||
| 348 | return false; | 371 | return false; |
| @@ -525,11 +548,13 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) | |||
| 525 | 548 | ||
| 526 | oi = &op->info; | 549 | oi = &op->info; |
| 527 | 550 | ||
| 551 | mp = get_mgr_priv(ovl->manager); | ||
| 552 | |||
| 528 | replication = dss_use_replication(ovl->manager->device, oi->color_mode); | 553 | replication = dss_use_replication(ovl->manager->device, oi->color_mode); |
| 529 | 554 | ||
| 530 | ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; | 555 | ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; |
| 531 | 556 | ||
| 532 | r = dispc_ovl_setup(ovl->id, oi, ilace, replication); | 557 | r = dispc_ovl_setup(ovl->id, oi, ilace, replication, &mp->timings); |
| 533 | if (r) { | 558 | if (r) { |
| 534 | /* | 559 | /* |
| 535 | * We can't do much here, as this function can be called from | 560 | * We can't do much here, as this function can be called from |
| @@ -543,8 +568,6 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) | |||
| 543 | return; | 568 | return; |
| 544 | } | 569 | } |
| 545 | 570 | ||
| 546 | mp = get_mgr_priv(ovl->manager); | ||
| 547 | |||
| 548 | op->info_dirty = false; | 571 | op->info_dirty = false; |
| 549 | if (mp->updating) | 572 | if (mp->updating) |
| 550 | op->shadow_info_dirty = true; | 573 | op->shadow_info_dirty = true; |
| @@ -601,6 +624,22 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) | |||
| 601 | } | 624 | } |
| 602 | } | 625 | } |
| 603 | 626 | ||
| 627 | static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) | ||
| 628 | { | ||
| 629 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
| 630 | |||
| 631 | DSSDBGF("%d", mgr->id); | ||
| 632 | |||
| 633 | if (!mp->extra_info_dirty) | ||
| 634 | return; | ||
| 635 | |||
| 636 | dispc_mgr_set_timings(mgr->id, &mp->timings); | ||
| 637 | |||
| 638 | mp->extra_info_dirty = false; | ||
| 639 | if (mp->updating) | ||
| 640 | mp->shadow_extra_info_dirty = true; | ||
| 641 | } | ||
| 642 | |||
| 604 | static void dss_write_regs_common(void) | 643 | static void dss_write_regs_common(void) |
| 605 | { | 644 | { |
| 606 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | 645 | const int num_mgrs = omap_dss_get_num_overlay_managers(); |
| @@ -646,7 +685,7 @@ static void dss_write_regs(void) | |||
| 646 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | 685 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) |
| 647 | continue; | 686 | continue; |
| 648 | 687 | ||
| 649 | r = dss_check_settings(mgr, mgr->device); | 688 | r = dss_check_settings(mgr); |
| 650 | if (r) { | 689 | if (r) { |
| 651 | DSSERR("cannot write registers for manager %s: " | 690 | DSSERR("cannot write registers for manager %s: " |
| 652 | "illegal configuration\n", mgr->name); | 691 | "illegal configuration\n", mgr->name); |
| @@ -654,6 +693,7 @@ static void dss_write_regs(void) | |||
| 654 | } | 693 | } |
| 655 | 694 | ||
| 656 | dss_mgr_write_regs(mgr); | 695 | dss_mgr_write_regs(mgr); |
| 696 | dss_mgr_write_regs_extra(mgr); | ||
| 657 | } | 697 | } |
| 658 | } | 698 | } |
| 659 | 699 | ||
| @@ -693,6 +733,7 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | |||
| 693 | 733 | ||
| 694 | mp = get_mgr_priv(mgr); | 734 | mp = get_mgr_priv(mgr); |
| 695 | mp->shadow_info_dirty = false; | 735 | mp->shadow_info_dirty = false; |
| 736 | mp->shadow_extra_info_dirty = false; | ||
| 696 | 737 | ||
| 697 | list_for_each_entry(ovl, &mgr->overlays, list) { | 738 | list_for_each_entry(ovl, &mgr->overlays, list) { |
| 698 | op = get_ovl_priv(ovl); | 739 | op = get_ovl_priv(ovl); |
| @@ -711,7 +752,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
| 711 | 752 | ||
| 712 | WARN_ON(mp->updating); | 753 | WARN_ON(mp->updating); |
| 713 | 754 | ||
| 714 | r = dss_check_settings(mgr, mgr->device); | 755 | r = dss_check_settings(mgr); |
| 715 | if (r) { | 756 | if (r) { |
| 716 | DSSERR("cannot start manual update: illegal configuration\n"); | 757 | DSSERR("cannot start manual update: illegal configuration\n"); |
| 717 | spin_unlock_irqrestore(&data_lock, flags); | 758 | spin_unlock_irqrestore(&data_lock, flags); |
| @@ -719,6 +760,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
| 719 | } | 760 | } |
| 720 | 761 | ||
| 721 | dss_mgr_write_regs(mgr); | 762 | dss_mgr_write_regs(mgr); |
| 763 | dss_mgr_write_regs_extra(mgr); | ||
| 722 | 764 | ||
| 723 | dss_write_regs_common(); | 765 | dss_write_regs_common(); |
| 724 | 766 | ||
| @@ -857,7 +899,7 @@ int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | |||
| 857 | 899 | ||
| 858 | spin_lock_irqsave(&data_lock, flags); | 900 | spin_lock_irqsave(&data_lock, flags); |
| 859 | 901 | ||
| 860 | r = dss_check_settings_apply(mgr, mgr->device); | 902 | r = dss_check_settings_apply(mgr); |
| 861 | if (r) { | 903 | if (r) { |
| 862 | spin_unlock_irqrestore(&data_lock, flags); | 904 | spin_unlock_irqrestore(&data_lock, flags); |
| 863 | DSSERR("failed to apply settings: illegal configuration.\n"); | 905 | DSSERR("failed to apply settings: illegal configuration.\n"); |
| @@ -918,16 +960,13 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl, | |||
| 918 | bool use_fifo_merge) | 960 | bool use_fifo_merge) |
| 919 | { | 961 | { |
| 920 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 962 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| 921 | struct omap_dss_device *dssdev; | ||
| 922 | u32 fifo_low, fifo_high; | 963 | u32 fifo_low, fifo_high; |
| 923 | 964 | ||
| 924 | if (!op->enabled && !op->enabling) | 965 | if (!op->enabled && !op->enabling) |
| 925 | return; | 966 | return; |
| 926 | 967 | ||
| 927 | dssdev = ovl->manager->device; | ||
| 928 | |||
| 929 | dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, | 968 | dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, |
| 930 | use_fifo_merge); | 969 | use_fifo_merge, ovl_manual_update(ovl)); |
| 931 | 970 | ||
| 932 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); | 971 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); |
| 933 | } | 972 | } |
| @@ -1050,7 +1089,7 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
| 1050 | 1089 | ||
| 1051 | mp->enabled = true; | 1090 | mp->enabled = true; |
| 1052 | 1091 | ||
| 1053 | r = dss_check_settings(mgr, mgr->device); | 1092 | r = dss_check_settings(mgr); |
| 1054 | if (r) { | 1093 | if (r) { |
| 1055 | DSSERR("failed to enable manager %d: check_settings failed\n", | 1094 | DSSERR("failed to enable manager %d: check_settings failed\n", |
| 1056 | mgr->id); | 1095 | mgr->id); |
| @@ -1225,6 +1264,35 @@ err: | |||
| 1225 | return r; | 1264 | return r; |
| 1226 | } | 1265 | } |
| 1227 | 1266 | ||
| 1267 | static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, | ||
| 1268 | struct omap_video_timings *timings) | ||
| 1269 | { | ||
| 1270 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
| 1271 | |||
| 1272 | mp->timings = *timings; | ||
| 1273 | mp->extra_info_dirty = true; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | ||
| 1277 | struct omap_video_timings *timings) | ||
| 1278 | { | ||
| 1279 | unsigned long flags; | ||
| 1280 | |||
| 1281 | mutex_lock(&apply_lock); | ||
| 1282 | |||
| 1283 | spin_lock_irqsave(&data_lock, flags); | ||
| 1284 | |||
| 1285 | dss_apply_mgr_timings(mgr, timings); | ||
| 1286 | |||
| 1287 | dss_write_regs(); | ||
| 1288 | dss_set_go_bits(); | ||
| 1289 | |||
| 1290 | spin_unlock_irqrestore(&data_lock, flags); | ||
| 1291 | |||
| 1292 | wait_pending_extra_info_updates(); | ||
| 1293 | |||
| 1294 | mutex_unlock(&apply_lock); | ||
| 1295 | } | ||
| 1228 | 1296 | ||
| 1229 | int dss_ovl_set_info(struct omap_overlay *ovl, | 1297 | int dss_ovl_set_info(struct omap_overlay *ovl, |
| 1230 | struct omap_overlay_info *info) | 1298 | struct omap_overlay_info *info) |
| @@ -1393,7 +1461,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
| 1393 | 1461 | ||
| 1394 | op->enabling = true; | 1462 | op->enabling = true; |
| 1395 | 1463 | ||
| 1396 | r = dss_check_settings(ovl->manager, ovl->manager->device); | 1464 | r = dss_check_settings(ovl->manager); |
| 1397 | if (r) { | 1465 | if (r) { |
| 1398 | DSSERR("failed to enable overlay %d: check_settings failed\n", | 1466 | DSSERR("failed to enable overlay %d: check_settings failed\n", |
| 1399 | ovl->id); | 1467 | ovl->id); |
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index e8a120771ac6..72ded9cd2cb0 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
| @@ -43,6 +43,8 @@ static struct { | |||
| 43 | 43 | ||
| 44 | struct regulator *vdds_dsi_reg; | 44 | struct regulator *vdds_dsi_reg; |
| 45 | struct regulator *vdds_sdi_reg; | 45 | struct regulator *vdds_sdi_reg; |
| 46 | |||
| 47 | const char *default_display_name; | ||
| 46 | } core; | 48 | } core; |
| 47 | 49 | ||
| 48 | static char *def_disp_name; | 50 | static char *def_disp_name; |
| @@ -54,9 +56,6 @@ bool dss_debug; | |||
| 54 | module_param_named(debug, dss_debug, bool, 0644); | 56 | module_param_named(debug, dss_debug, bool, 0644); |
| 55 | #endif | 57 | #endif |
| 56 | 58 | ||
| 57 | static int omap_dss_register_device(struct omap_dss_device *); | ||
| 58 | static void omap_dss_unregister_device(struct omap_dss_device *); | ||
| 59 | |||
| 60 | /* REGULATORS */ | 59 | /* REGULATORS */ |
| 61 | 60 | ||
| 62 | struct regulator *dss_get_vdds_dsi(void) | 61 | struct regulator *dss_get_vdds_dsi(void) |
| @@ -87,6 +86,51 @@ struct regulator *dss_get_vdds_sdi(void) | |||
| 87 | return reg; | 86 | return reg; |
| 88 | } | 87 | } |
| 89 | 88 | ||
| 89 | int dss_get_ctx_loss_count(struct device *dev) | ||
| 90 | { | ||
| 91 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | ||
| 92 | int cnt; | ||
| 93 | |||
| 94 | if (!board_data->get_context_loss_count) | ||
| 95 | return -ENOENT; | ||
| 96 | |||
| 97 | cnt = board_data->get_context_loss_count(dev); | ||
| 98 | |||
| 99 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
| 100 | |||
| 101 | return cnt; | ||
| 102 | } | ||
| 103 | |||
| 104 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) | ||
| 105 | { | ||
| 106 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | ||
| 107 | |||
| 108 | if (!board_data->dsi_enable_pads) | ||
| 109 | return -ENOENT; | ||
| 110 | |||
| 111 | return board_data->dsi_enable_pads(dsi_id, lane_mask); | ||
| 112 | } | ||
| 113 | |||
| 114 | void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) | ||
| 115 | { | ||
| 116 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | ||
| 117 | |||
| 118 | if (!board_data->dsi_enable_pads) | ||
| 119 | return; | ||
| 120 | |||
| 121 | return board_data->dsi_disable_pads(dsi_id, lane_mask); | ||
| 122 | } | ||
| 123 | |||
| 124 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput) | ||
| 125 | { | ||
| 126 | struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; | ||
| 127 | |||
| 128 | if (pdata->set_min_bus_tput) | ||
| 129 | return pdata->set_min_bus_tput(dev, tput); | ||
| 130 | else | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 90 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | 134 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) |
| 91 | static int dss_debug_show(struct seq_file *s, void *unused) | 135 | static int dss_debug_show(struct seq_file *s, void *unused) |
| 92 | { | 136 | { |
| @@ -121,34 +165,6 @@ static int dss_initialize_debugfs(void) | |||
| 121 | debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, | 165 | debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, |
| 122 | &dss_debug_dump_clocks, &dss_debug_fops); | 166 | &dss_debug_dump_clocks, &dss_debug_fops); |
| 123 | 167 | ||
| 124 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 125 | debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir, | ||
| 126 | &dispc_dump_irqs, &dss_debug_fops); | ||
| 127 | #endif | ||
| 128 | |||
| 129 | #if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS) | ||
| 130 | dsi_create_debugfs_files_irq(dss_debugfs_dir, &dss_debug_fops); | ||
| 131 | #endif | ||
| 132 | |||
| 133 | debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir, | ||
| 134 | &dss_dump_regs, &dss_debug_fops); | ||
| 135 | debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir, | ||
| 136 | &dispc_dump_regs, &dss_debug_fops); | ||
| 137 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
| 138 | debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir, | ||
| 139 | &rfbi_dump_regs, &dss_debug_fops); | ||
| 140 | #endif | ||
| 141 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 142 | dsi_create_debugfs_files_reg(dss_debugfs_dir, &dss_debug_fops); | ||
| 143 | #endif | ||
| 144 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
| 145 | debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir, | ||
| 146 | &venc_dump_regs, &dss_debug_fops); | ||
| 147 | #endif | ||
| 148 | #ifdef CONFIG_OMAP4_DSS_HDMI | ||
| 149 | debugfs_create_file("hdmi", S_IRUGO, dss_debugfs_dir, | ||
| 150 | &hdmi_dump_regs, &dss_debug_fops); | ||
| 151 | #endif | ||
| 152 | return 0; | 168 | return 0; |
| 153 | } | 169 | } |
| 154 | 170 | ||
| @@ -157,6 +173,19 @@ static void dss_uninitialize_debugfs(void) | |||
| 157 | if (dss_debugfs_dir) | 173 | if (dss_debugfs_dir) |
| 158 | debugfs_remove_recursive(dss_debugfs_dir); | 174 | debugfs_remove_recursive(dss_debugfs_dir); |
| 159 | } | 175 | } |
| 176 | |||
| 177 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) | ||
| 178 | { | ||
| 179 | struct dentry *d; | ||
| 180 | |||
| 181 | d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, | ||
| 182 | write, &dss_debug_fops); | ||
| 183 | |||
| 184 | if (IS_ERR(d)) | ||
| 185 | return PTR_ERR(d); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 160 | #else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ | 189 | #else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ |
| 161 | static inline int dss_initialize_debugfs(void) | 190 | static inline int dss_initialize_debugfs(void) |
| 162 | { | 191 | { |
| @@ -165,14 +194,18 @@ static inline int dss_initialize_debugfs(void) | |||
| 165 | static inline void dss_uninitialize_debugfs(void) | 194 | static inline void dss_uninitialize_debugfs(void) |
| 166 | { | 195 | { |
| 167 | } | 196 | } |
| 197 | static inline int dss_debugfs_create_file(const char *name, | ||
| 198 | void (*write)(struct seq_file *)) | ||
| 199 | { | ||
| 200 | return 0; | ||
| 201 | } | ||
| 168 | #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ | 202 | #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ |
| 169 | 203 | ||
| 170 | /* PLATFORM DEVICE */ | 204 | /* PLATFORM DEVICE */ |
| 171 | static int omap_dss_probe(struct platform_device *pdev) | 205 | static int __init omap_dss_probe(struct platform_device *pdev) |
| 172 | { | 206 | { |
| 173 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 207 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 174 | int r; | 208 | int r; |
| 175 | int i; | ||
| 176 | 209 | ||
| 177 | core.pdev = pdev; | 210 | core.pdev = pdev; |
| 178 | 211 | ||
| @@ -187,28 +220,13 @@ static int omap_dss_probe(struct platform_device *pdev) | |||
| 187 | if (r) | 220 | if (r) |
| 188 | goto err_debugfs; | 221 | goto err_debugfs; |
| 189 | 222 | ||
| 190 | for (i = 0; i < pdata->num_devices; ++i) { | 223 | if (def_disp_name) |
| 191 | struct omap_dss_device *dssdev = pdata->devices[i]; | 224 | core.default_display_name = def_disp_name; |
| 192 | 225 | else if (pdata->default_device) | |
| 193 | r = omap_dss_register_device(dssdev); | 226 | core.default_display_name = pdata->default_device->name; |
| 194 | if (r) { | ||
| 195 | DSSERR("device %d %s register failed %d\n", i, | ||
| 196 | dssdev->name ?: "unnamed", r); | ||
| 197 | |||
| 198 | while (--i >= 0) | ||
| 199 | omap_dss_unregister_device(pdata->devices[i]); | ||
| 200 | |||
| 201 | goto err_register; | ||
| 202 | } | ||
| 203 | |||
| 204 | if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0) | ||
| 205 | pdata->default_device = dssdev; | ||
| 206 | } | ||
| 207 | 227 | ||
| 208 | return 0; | 228 | return 0; |
| 209 | 229 | ||
| 210 | err_register: | ||
| 211 | dss_uninitialize_debugfs(); | ||
| 212 | err_debugfs: | 230 | err_debugfs: |
| 213 | 231 | ||
| 214 | return r; | 232 | return r; |
| @@ -216,17 +234,11 @@ err_debugfs: | |||
| 216 | 234 | ||
| 217 | static int omap_dss_remove(struct platform_device *pdev) | 235 | static int omap_dss_remove(struct platform_device *pdev) |
| 218 | { | 236 | { |
| 219 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 220 | int i; | ||
| 221 | |||
| 222 | dss_uninitialize_debugfs(); | 237 | dss_uninitialize_debugfs(); |
| 223 | 238 | ||
| 224 | dss_uninit_overlays(pdev); | 239 | dss_uninit_overlays(pdev); |
| 225 | dss_uninit_overlay_managers(pdev); | 240 | dss_uninit_overlay_managers(pdev); |
| 226 | 241 | ||
| 227 | for (i = 0; i < pdata->num_devices; ++i) | ||
| 228 | omap_dss_unregister_device(pdata->devices[i]); | ||
| 229 | |||
| 230 | return 0; | 242 | return 0; |
| 231 | } | 243 | } |
| 232 | 244 | ||
| @@ -251,7 +263,6 @@ static int omap_dss_resume(struct platform_device *pdev) | |||
| 251 | } | 263 | } |
| 252 | 264 | ||
| 253 | static struct platform_driver omap_dss_driver = { | 265 | static struct platform_driver omap_dss_driver = { |
| 254 | .probe = omap_dss_probe, | ||
| 255 | .remove = omap_dss_remove, | 266 | .remove = omap_dss_remove, |
| 256 | .shutdown = omap_dss_shutdown, | 267 | .shutdown = omap_dss_shutdown, |
| 257 | .suspend = omap_dss_suspend, | 268 | .suspend = omap_dss_suspend, |
| @@ -326,7 +337,6 @@ static int dss_driver_probe(struct device *dev) | |||
| 326 | int r; | 337 | int r; |
| 327 | struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); | 338 | struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); |
| 328 | struct omap_dss_device *dssdev = to_dss_device(dev); | 339 | struct omap_dss_device *dssdev = to_dss_device(dev); |
| 329 | struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; | ||
| 330 | bool force; | 340 | bool force; |
| 331 | 341 | ||
| 332 | DSSDBG("driver_probe: dev %s/%s, drv %s\n", | 342 | DSSDBG("driver_probe: dev %s/%s, drv %s\n", |
| @@ -335,7 +345,8 @@ static int dss_driver_probe(struct device *dev) | |||
| 335 | 345 | ||
| 336 | dss_init_device(core.pdev, dssdev); | 346 | dss_init_device(core.pdev, dssdev); |
| 337 | 347 | ||
| 338 | force = pdata->default_device == dssdev; | 348 | force = core.default_display_name && |
| 349 | strcmp(core.default_display_name, dssdev->name) == 0; | ||
| 339 | dss_recheck_connections(dssdev, force); | 350 | dss_recheck_connections(dssdev, force); |
| 340 | 351 | ||
| 341 | r = dssdrv->probe(dssdev); | 352 | r = dssdrv->probe(dssdev); |
| @@ -381,6 +392,8 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver) | |||
| 381 | if (dssdriver->get_recommended_bpp == NULL) | 392 | if (dssdriver->get_recommended_bpp == NULL) |
| 382 | dssdriver->get_recommended_bpp = | 393 | dssdriver->get_recommended_bpp = |
| 383 | omapdss_default_get_recommended_bpp; | 394 | omapdss_default_get_recommended_bpp; |
| 395 | if (dssdriver->get_timings == NULL) | ||
| 396 | dssdriver->get_timings = omapdss_default_get_timings; | ||
| 384 | 397 | ||
| 385 | return driver_register(&dssdriver->driver); | 398 | return driver_register(&dssdriver->driver); |
| 386 | } | 399 | } |
| @@ -427,27 +440,38 @@ static void omap_dss_dev_release(struct device *dev) | |||
| 427 | reset_device(dev, 0); | 440 | reset_device(dev, 0); |
| 428 | } | 441 | } |
| 429 | 442 | ||
| 430 | static int omap_dss_register_device(struct omap_dss_device *dssdev) | 443 | int omap_dss_register_device(struct omap_dss_device *dssdev, |
| 444 | struct device *parent, int disp_num) | ||
| 431 | { | 445 | { |
| 432 | static int dev_num; | ||
| 433 | |||
| 434 | WARN_ON(!dssdev->driver_name); | 446 | WARN_ON(!dssdev->driver_name); |
| 435 | 447 | ||
| 436 | reset_device(&dssdev->dev, 1); | 448 | reset_device(&dssdev->dev, 1); |
| 437 | dssdev->dev.bus = &dss_bus_type; | 449 | dssdev->dev.bus = &dss_bus_type; |
| 438 | dssdev->dev.parent = &dss_bus; | 450 | dssdev->dev.parent = parent; |
| 439 | dssdev->dev.release = omap_dss_dev_release; | 451 | dssdev->dev.release = omap_dss_dev_release; |
| 440 | dev_set_name(&dssdev->dev, "display%d", dev_num++); | 452 | dev_set_name(&dssdev->dev, "display%d", disp_num); |
| 441 | return device_register(&dssdev->dev); | 453 | return device_register(&dssdev->dev); |
| 442 | } | 454 | } |
| 443 | 455 | ||
| 444 | static void omap_dss_unregister_device(struct omap_dss_device *dssdev) | 456 | void omap_dss_unregister_device(struct omap_dss_device *dssdev) |
| 445 | { | 457 | { |
| 446 | device_unregister(&dssdev->dev); | 458 | device_unregister(&dssdev->dev); |
| 447 | } | 459 | } |
| 448 | 460 | ||
| 461 | static int dss_unregister_dss_dev(struct device *dev, void *data) | ||
| 462 | { | ||
| 463 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 464 | omap_dss_unregister_device(dssdev); | ||
| 465 | return 0; | ||
| 466 | } | ||
| 467 | |||
| 468 | void omap_dss_unregister_child_devices(struct device *parent) | ||
| 469 | { | ||
| 470 | device_for_each_child(parent, NULL, dss_unregister_dss_dev); | ||
| 471 | } | ||
| 472 | |||
| 449 | /* BUS */ | 473 | /* BUS */ |
| 450 | static int omap_dss_bus_register(void) | 474 | static int __init omap_dss_bus_register(void) |
| 451 | { | 475 | { |
| 452 | int r; | 476 | int r; |
| 453 | 477 | ||
| @@ -469,12 +493,56 @@ static int omap_dss_bus_register(void) | |||
| 469 | } | 493 | } |
| 470 | 494 | ||
| 471 | /* INIT */ | 495 | /* INIT */ |
| 496 | static int (*dss_output_drv_reg_funcs[])(void) __initdata = { | ||
| 497 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
| 498 | dpi_init_platform_driver, | ||
| 499 | #endif | ||
| 500 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
| 501 | sdi_init_platform_driver, | ||
| 502 | #endif | ||
| 503 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
| 504 | rfbi_init_platform_driver, | ||
| 505 | #endif | ||
| 506 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
| 507 | venc_init_platform_driver, | ||
| 508 | #endif | ||
| 509 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 510 | dsi_init_platform_driver, | ||
| 511 | #endif | ||
| 512 | #ifdef CONFIG_OMAP4_DSS_HDMI | ||
| 513 | hdmi_init_platform_driver, | ||
| 514 | #endif | ||
| 515 | }; | ||
| 516 | |||
| 517 | static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { | ||
| 518 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
| 519 | dpi_uninit_platform_driver, | ||
| 520 | #endif | ||
| 521 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
| 522 | sdi_uninit_platform_driver, | ||
| 523 | #endif | ||
| 524 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
| 525 | rfbi_uninit_platform_driver, | ||
| 526 | #endif | ||
| 527 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
| 528 | venc_uninit_platform_driver, | ||
| 529 | #endif | ||
| 530 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 531 | dsi_uninit_platform_driver, | ||
| 532 | #endif | ||
| 533 | #ifdef CONFIG_OMAP4_DSS_HDMI | ||
| 534 | hdmi_uninit_platform_driver, | ||
| 535 | #endif | ||
| 536 | }; | ||
| 537 | |||
| 538 | static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; | ||
| 472 | 539 | ||
| 473 | static int __init omap_dss_register_drivers(void) | 540 | static int __init omap_dss_register_drivers(void) |
| 474 | { | 541 | { |
| 475 | int r; | 542 | int r; |
| 543 | int i; | ||
| 476 | 544 | ||
| 477 | r = platform_driver_register(&omap_dss_driver); | 545 | r = platform_driver_probe(&omap_dss_driver, omap_dss_probe); |
| 478 | if (r) | 546 | if (r) |
| 479 | return r; | 547 | return r; |
| 480 | 548 | ||
| @@ -490,40 +558,18 @@ static int __init omap_dss_register_drivers(void) | |||
| 490 | goto err_dispc; | 558 | goto err_dispc; |
| 491 | } | 559 | } |
| 492 | 560 | ||
| 493 | r = rfbi_init_platform_driver(); | 561 | /* |
| 494 | if (r) { | 562 | * It's ok if the output-driver register fails. It happens, for example, |
| 495 | DSSERR("Failed to initialize rfbi platform driver\n"); | 563 | * when there is no output-device (e.g. SDI for OMAP4). |
| 496 | goto err_rfbi; | 564 | */ |
| 497 | } | 565 | for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { |
| 498 | 566 | r = dss_output_drv_reg_funcs[i](); | |
| 499 | r = venc_init_platform_driver(); | 567 | if (r == 0) |
| 500 | if (r) { | 568 | dss_output_drv_loaded[i] = true; |
| 501 | DSSERR("Failed to initialize venc platform driver\n"); | ||
| 502 | goto err_venc; | ||
| 503 | } | ||
| 504 | |||
| 505 | r = dsi_init_platform_driver(); | ||
| 506 | if (r) { | ||
| 507 | DSSERR("Failed to initialize DSI platform driver\n"); | ||
| 508 | goto err_dsi; | ||
| 509 | } | ||
| 510 | |||
| 511 | r = hdmi_init_platform_driver(); | ||
| 512 | if (r) { | ||
| 513 | DSSERR("Failed to initialize hdmi\n"); | ||
| 514 | goto err_hdmi; | ||
| 515 | } | 569 | } |
| 516 | 570 | ||
| 517 | return 0; | 571 | return 0; |
| 518 | 572 | ||
| 519 | err_hdmi: | ||
| 520 | dsi_uninit_platform_driver(); | ||
| 521 | err_dsi: | ||
| 522 | venc_uninit_platform_driver(); | ||
| 523 | err_venc: | ||
| 524 | rfbi_uninit_platform_driver(); | ||
| 525 | err_rfbi: | ||
| 526 | dispc_uninit_platform_driver(); | ||
| 527 | err_dispc: | 573 | err_dispc: |
| 528 | dss_uninit_platform_driver(); | 574 | dss_uninit_platform_driver(); |
| 529 | err_dss: | 575 | err_dss: |
| @@ -534,10 +580,13 @@ err_dss: | |||
| 534 | 580 | ||
| 535 | static void __exit omap_dss_unregister_drivers(void) | 581 | static void __exit omap_dss_unregister_drivers(void) |
| 536 | { | 582 | { |
| 537 | hdmi_uninit_platform_driver(); | 583 | int i; |
| 538 | dsi_uninit_platform_driver(); | 584 | |
| 539 | venc_uninit_platform_driver(); | 585 | for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { |
| 540 | rfbi_uninit_platform_driver(); | 586 | if (dss_output_drv_loaded[i]) |
| 587 | dss_output_drv_unreg_funcs[i](); | ||
| 588 | } | ||
| 589 | |||
| 541 | dispc_uninit_platform_driver(); | 590 | dispc_uninit_platform_driver(); |
| 542 | dss_uninit_platform_driver(); | 591 | dss_uninit_platform_driver(); |
| 543 | 592 | ||
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee30937482e1..4749ac356469 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
| @@ -131,23 +131,6 @@ static inline u32 dispc_read_reg(const u16 idx) | |||
| 131 | return __raw_readl(dispc.base + idx); | 131 | return __raw_readl(dispc.base + idx); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static int dispc_get_ctx_loss_count(void) | ||
| 135 | { | ||
| 136 | struct device *dev = &dispc.pdev->dev; | ||
| 137 | struct omap_display_platform_data *pdata = dev->platform_data; | ||
| 138 | struct omap_dss_board_info *board_data = pdata->board_data; | ||
| 139 | int cnt; | ||
| 140 | |||
| 141 | if (!board_data->get_context_loss_count) | ||
| 142 | return -ENOENT; | ||
| 143 | |||
| 144 | cnt = board_data->get_context_loss_count(dev); | ||
| 145 | |||
| 146 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
| 147 | |||
| 148 | return cnt; | ||
| 149 | } | ||
| 150 | |||
| 151 | #define SR(reg) \ | 134 | #define SR(reg) \ |
| 152 | dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) | 135 | dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) |
| 153 | #define RR(reg) \ | 136 | #define RR(reg) \ |
| @@ -251,7 +234,7 @@ static void dispc_save_context(void) | |||
| 251 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | 234 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) |
| 252 | SR(DIVISOR); | 235 | SR(DIVISOR); |
| 253 | 236 | ||
| 254 | dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); | 237 | dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev); |
| 255 | dispc.ctx_valid = true; | 238 | dispc.ctx_valid = true; |
| 256 | 239 | ||
| 257 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); | 240 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); |
| @@ -266,7 +249,7 @@ static void dispc_restore_context(void) | |||
| 266 | if (!dispc.ctx_valid) | 249 | if (!dispc.ctx_valid) |
| 267 | return; | 250 | return; |
| 268 | 251 | ||
| 269 | ctx = dispc_get_ctx_loss_count(); | 252 | ctx = dss_get_ctx_loss_count(&dispc.pdev->dev); |
| 270 | 253 | ||
| 271 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) | 254 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) |
| 272 | return; | 255 | return; |
| @@ -413,14 +396,6 @@ static inline bool dispc_mgr_is_lcd(enum omap_channel channel) | |||
| 413 | return false; | 396 | return false; |
| 414 | } | 397 | } |
| 415 | 398 | ||
| 416 | static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel) | ||
| 417 | { | ||
| 418 | struct omap_overlay_manager *mgr = | ||
| 419 | omap_dss_get_overlay_manager(channel); | ||
| 420 | |||
| 421 | return mgr ? mgr->device : NULL; | ||
| 422 | } | ||
| 423 | |||
| 424 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) | 399 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) |
| 425 | { | 400 | { |
| 426 | switch (channel) { | 401 | switch (channel) { |
| @@ -432,6 +407,7 @@ u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) | |||
| 432 | return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | 407 | return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; |
| 433 | default: | 408 | default: |
| 434 | BUG(); | 409 | BUG(); |
| 410 | return 0; | ||
| 435 | } | 411 | } |
| 436 | } | 412 | } |
| 437 | 413 | ||
| @@ -446,6 +422,7 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | |||
| 446 | return 0; | 422 | return 0; |
| 447 | default: | 423 | default: |
| 448 | BUG(); | 424 | BUG(); |
| 425 | return 0; | ||
| 449 | } | 426 | } |
| 450 | } | 427 | } |
| 451 | 428 | ||
| @@ -764,7 +741,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
| 764 | case OMAP_DSS_COLOR_XRGB16_1555: | 741 | case OMAP_DSS_COLOR_XRGB16_1555: |
| 765 | m = 0xf; break; | 742 | m = 0xf; break; |
| 766 | default: | 743 | default: |
| 767 | BUG(); break; | 744 | BUG(); return; |
| 768 | } | 745 | } |
| 769 | } else { | 746 | } else { |
| 770 | switch (color_mode) { | 747 | switch (color_mode) { |
| @@ -801,13 +778,25 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
| 801 | case OMAP_DSS_COLOR_XRGB16_1555: | 778 | case OMAP_DSS_COLOR_XRGB16_1555: |
| 802 | m = 0xf; break; | 779 | m = 0xf; break; |
| 803 | default: | 780 | default: |
| 804 | BUG(); break; | 781 | BUG(); return; |
| 805 | } | 782 | } |
| 806 | } | 783 | } |
| 807 | 784 | ||
| 808 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); | 785 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); |
| 809 | } | 786 | } |
| 810 | 787 | ||
| 788 | static void dispc_ovl_configure_burst_type(enum omap_plane plane, | ||
| 789 | enum omap_dss_rotation_type rotation_type) | ||
| 790 | { | ||
| 791 | if (dss_has_feature(FEAT_BURST_2D) == 0) | ||
| 792 | return; | ||
| 793 | |||
| 794 | if (rotation_type == OMAP_DSS_ROT_TILER) | ||
| 795 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); | ||
| 796 | else | ||
| 797 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); | ||
| 798 | } | ||
| 799 | |||
| 811 | void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | 800 | void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) |
| 812 | { | 801 | { |
| 813 | int shift; | 802 | int shift; |
| @@ -845,6 +834,7 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | |||
| 845 | break; | 834 | break; |
| 846 | default: | 835 | default: |
| 847 | BUG(); | 836 | BUG(); |
| 837 | return; | ||
| 848 | } | 838 | } |
| 849 | 839 | ||
| 850 | val = FLD_MOD(val, chan, shift, shift); | 840 | val = FLD_MOD(val, chan, shift, shift); |
| @@ -872,6 +862,7 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | |||
| 872 | break; | 862 | break; |
| 873 | default: | 863 | default: |
| 874 | BUG(); | 864 | BUG(); |
| 865 | return 0; | ||
| 875 | } | 866 | } |
| 876 | 867 | ||
| 877 | val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | 868 | val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); |
| @@ -983,20 +974,13 @@ static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) | |||
| 983 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); | 974 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); |
| 984 | } | 975 | } |
| 985 | 976 | ||
| 986 | void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height) | 977 | static void dispc_mgr_set_size(enum omap_channel channel, u16 width, |
| 978 | u16 height) | ||
| 987 | { | 979 | { |
| 988 | u32 val; | 980 | u32 val; |
| 989 | BUG_ON((width > (1 << 11)) || (height > (1 << 11))); | ||
| 990 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | ||
| 991 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); | ||
| 992 | } | ||
| 993 | 981 | ||
| 994 | void dispc_set_digit_size(u16 width, u16 height) | ||
| 995 | { | ||
| 996 | u32 val; | ||
| 997 | BUG_ON((width > (1 << 11)) || (height > (1 << 11))); | ||
| 998 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 982 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
| 999 | dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val); | 983 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); |
| 1000 | } | 984 | } |
| 1001 | 985 | ||
| 1002 | static void dispc_read_plane_fifo_sizes(void) | 986 | static void dispc_read_plane_fifo_sizes(void) |
| @@ -1063,7 +1047,8 @@ void dispc_enable_fifomerge(bool enable) | |||
| 1063 | } | 1047 | } |
| 1064 | 1048 | ||
| 1065 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | 1049 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, |
| 1066 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge) | 1050 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, |
| 1051 | bool manual_update) | ||
| 1067 | { | 1052 | { |
| 1068 | /* | 1053 | /* |
| 1069 | * All sizes are in bytes. Both the buffer and burst are made of | 1054 | * All sizes are in bytes. Both the buffer and burst are made of |
| @@ -1091,7 +1076,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | |||
| 1091 | * combined fifo size | 1076 | * combined fifo size |
| 1092 | */ | 1077 | */ |
| 1093 | 1078 | ||
| 1094 | if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { | 1079 | if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { |
| 1095 | *fifo_low = ovl_fifo_size - burst_size * 2; | 1080 | *fifo_low = ovl_fifo_size - burst_size * 2; |
| 1096 | *fifo_high = total_fifo_size - burst_size; | 1081 | *fifo_high = total_fifo_size - burst_size; |
| 1097 | } else { | 1082 | } else { |
| @@ -1185,6 +1170,94 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane, | |||
| 1185 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); | 1170 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); |
| 1186 | } | 1171 | } |
| 1187 | 1172 | ||
| 1173 | static void dispc_ovl_set_accu_uv(enum omap_plane plane, | ||
| 1174 | u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, | ||
| 1175 | bool ilace, enum omap_color_mode color_mode, u8 rotation) | ||
| 1176 | { | ||
| 1177 | int h_accu2_0, h_accu2_1; | ||
| 1178 | int v_accu2_0, v_accu2_1; | ||
| 1179 | int chroma_hinc, chroma_vinc; | ||
| 1180 | int idx; | ||
| 1181 | |||
| 1182 | struct accu { | ||
| 1183 | s8 h0_m, h0_n; | ||
| 1184 | s8 h1_m, h1_n; | ||
| 1185 | s8 v0_m, v0_n; | ||
| 1186 | s8 v1_m, v1_n; | ||
| 1187 | }; | ||
| 1188 | |||
| 1189 | const struct accu *accu_table; | ||
| 1190 | const struct accu *accu_val; | ||
| 1191 | |||
| 1192 | static const struct accu accu_nv12[4] = { | ||
| 1193 | { 0, 1, 0, 1 , -1, 2, 0, 1 }, | ||
| 1194 | { 1, 2, -3, 4 , 0, 1, 0, 1 }, | ||
| 1195 | { -1, 1, 0, 1 , -1, 2, 0, 1 }, | ||
| 1196 | { -1, 2, -1, 2 , -1, 1, 0, 1 }, | ||
| 1197 | }; | ||
| 1198 | |||
| 1199 | static const struct accu accu_nv12_ilace[4] = { | ||
| 1200 | { 0, 1, 0, 1 , -3, 4, -1, 4 }, | ||
| 1201 | { -1, 4, -3, 4 , 0, 1, 0, 1 }, | ||
| 1202 | { -1, 1, 0, 1 , -1, 4, -3, 4 }, | ||
| 1203 | { -3, 4, -3, 4 , -1, 1, 0, 1 }, | ||
| 1204 | }; | ||
| 1205 | |||
| 1206 | static const struct accu accu_yuv[4] = { | ||
| 1207 | { 0, 1, 0, 1, 0, 1, 0, 1 }, | ||
| 1208 | { 0, 1, 0, 1, 0, 1, 0, 1 }, | ||
| 1209 | { -1, 1, 0, 1, 0, 1, 0, 1 }, | ||
| 1210 | { 0, 1, 0, 1, -1, 1, 0, 1 }, | ||
| 1211 | }; | ||
| 1212 | |||
| 1213 | switch (rotation) { | ||
| 1214 | case OMAP_DSS_ROT_0: | ||
| 1215 | idx = 0; | ||
| 1216 | break; | ||
| 1217 | case OMAP_DSS_ROT_90: | ||
| 1218 | idx = 1; | ||
| 1219 | break; | ||
| 1220 | case OMAP_DSS_ROT_180: | ||
| 1221 | idx = 2; | ||
| 1222 | break; | ||
| 1223 | case OMAP_DSS_ROT_270: | ||
| 1224 | idx = 3; | ||
| 1225 | break; | ||
| 1226 | default: | ||
| 1227 | BUG(); | ||
| 1228 | return; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | switch (color_mode) { | ||
| 1232 | case OMAP_DSS_COLOR_NV12: | ||
| 1233 | if (ilace) | ||
| 1234 | accu_table = accu_nv12_ilace; | ||
| 1235 | else | ||
| 1236 | accu_table = accu_nv12; | ||
| 1237 | break; | ||
| 1238 | case OMAP_DSS_COLOR_YUV2: | ||
| 1239 | case OMAP_DSS_COLOR_UYVY: | ||
| 1240 | accu_table = accu_yuv; | ||
| 1241 | break; | ||
| 1242 | default: | ||
| 1243 | BUG(); | ||
| 1244 | return; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | accu_val = &accu_table[idx]; | ||
| 1248 | |||
| 1249 | chroma_hinc = 1024 * orig_width / out_width; | ||
| 1250 | chroma_vinc = 1024 * orig_height / out_height; | ||
| 1251 | |||
| 1252 | h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024; | ||
| 1253 | h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024; | ||
| 1254 | v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024; | ||
| 1255 | v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024; | ||
| 1256 | |||
| 1257 | dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0); | ||
| 1258 | dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1); | ||
| 1259 | } | ||
| 1260 | |||
| 1188 | static void dispc_ovl_set_scaling_common(enum omap_plane plane, | 1261 | static void dispc_ovl_set_scaling_common(enum omap_plane plane, |
| 1189 | u16 orig_width, u16 orig_height, | 1262 | u16 orig_width, u16 orig_height, |
| 1190 | u16 out_width, u16 out_height, | 1263 | u16 out_width, u16 out_height, |
| @@ -1258,6 +1331,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
| 1258 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); | 1331 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); |
| 1259 | return; | 1332 | return; |
| 1260 | } | 1333 | } |
| 1334 | |||
| 1335 | dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width, | ||
| 1336 | out_height, ilace, color_mode, rotation); | ||
| 1337 | |||
| 1261 | switch (color_mode) { | 1338 | switch (color_mode) { |
| 1262 | case OMAP_DSS_COLOR_NV12: | 1339 | case OMAP_DSS_COLOR_NV12: |
| 1263 | /* UV is subsampled by 2 vertically*/ | 1340 | /* UV is subsampled by 2 vertically*/ |
| @@ -1280,6 +1357,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
| 1280 | break; | 1357 | break; |
| 1281 | default: | 1358 | default: |
| 1282 | BUG(); | 1359 | BUG(); |
| 1360 | return; | ||
| 1283 | } | 1361 | } |
| 1284 | 1362 | ||
| 1285 | if (out_width != orig_width) | 1363 | if (out_width != orig_width) |
| @@ -1297,9 +1375,6 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
| 1297 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); | 1375 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); |
| 1298 | /* set V scaling */ | 1376 | /* set V scaling */ |
| 1299 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); | 1377 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); |
| 1300 | |||
| 1301 | dispc_ovl_set_vid_accu2_0(plane, 0x80, 0); | ||
| 1302 | dispc_ovl_set_vid_accu2_1(plane, 0x80, 0); | ||
| 1303 | } | 1378 | } |
| 1304 | 1379 | ||
| 1305 | static void dispc_ovl_set_scaling(enum omap_plane plane, | 1380 | static void dispc_ovl_set_scaling(enum omap_plane plane, |
| @@ -1410,6 +1485,7 @@ static int color_mode_to_bpp(enum omap_color_mode color_mode) | |||
| 1410 | return 32; | 1485 | return 32; |
| 1411 | default: | 1486 | default: |
| 1412 | BUG(); | 1487 | BUG(); |
| 1488 | return 0; | ||
| 1413 | } | 1489 | } |
| 1414 | } | 1490 | } |
| 1415 | 1491 | ||
| @@ -1423,6 +1499,7 @@ static s32 pixinc(int pixels, u8 ps) | |||
| 1423 | return 1 - (-pixels + 1) * ps; | 1499 | return 1 - (-pixels + 1) * ps; |
| 1424 | else | 1500 | else |
| 1425 | BUG(); | 1501 | BUG(); |
| 1502 | return 0; | ||
| 1426 | } | 1503 | } |
| 1427 | 1504 | ||
| 1428 | static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | 1505 | static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, |
| @@ -1431,7 +1508,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | |||
| 1431 | enum omap_color_mode color_mode, bool fieldmode, | 1508 | enum omap_color_mode color_mode, bool fieldmode, |
| 1432 | unsigned int field_offset, | 1509 | unsigned int field_offset, |
| 1433 | unsigned *offset0, unsigned *offset1, | 1510 | unsigned *offset0, unsigned *offset1, |
| 1434 | s32 *row_inc, s32 *pix_inc) | 1511 | s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) |
| 1435 | { | 1512 | { |
| 1436 | u8 ps; | 1513 | u8 ps; |
| 1437 | 1514 | ||
| @@ -1477,10 +1554,10 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | |||
| 1477 | else | 1554 | else |
| 1478 | *offset0 = 0; | 1555 | *offset0 = 0; |
| 1479 | 1556 | ||
| 1480 | *row_inc = pixinc(1 + (screen_width - width) + | 1557 | *row_inc = pixinc(1 + |
| 1481 | (fieldmode ? screen_width : 0), | 1558 | (y_predecim * screen_width - x_predecim * width) + |
| 1482 | ps); | 1559 | (fieldmode ? screen_width : 0), ps); |
| 1483 | *pix_inc = pixinc(1, ps); | 1560 | *pix_inc = pixinc(x_predecim, ps); |
| 1484 | break; | 1561 | break; |
| 1485 | 1562 | ||
| 1486 | case OMAP_DSS_ROT_0 + 4: | 1563 | case OMAP_DSS_ROT_0 + 4: |
| @@ -1498,14 +1575,15 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | |||
| 1498 | *offset0 = field_offset * screen_width * ps; | 1575 | *offset0 = field_offset * screen_width * ps; |
| 1499 | else | 1576 | else |
| 1500 | *offset0 = 0; | 1577 | *offset0 = 0; |
| 1501 | *row_inc = pixinc(1 - (screen_width + width) - | 1578 | *row_inc = pixinc(1 - |
| 1502 | (fieldmode ? screen_width : 0), | 1579 | (y_predecim * screen_width + x_predecim * width) - |
| 1503 | ps); | 1580 | (fieldmode ? screen_width : 0), ps); |
| 1504 | *pix_inc = pixinc(1, ps); | 1581 | *pix_inc = pixinc(x_predecim, ps); |
| 1505 | break; | 1582 | break; |
| 1506 | 1583 | ||
| 1507 | default: | 1584 | default: |
| 1508 | BUG(); | 1585 | BUG(); |
| 1586 | return; | ||
| 1509 | } | 1587 | } |
| 1510 | } | 1588 | } |
| 1511 | 1589 | ||
| @@ -1515,7 +1593,7 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1515 | enum omap_color_mode color_mode, bool fieldmode, | 1593 | enum omap_color_mode color_mode, bool fieldmode, |
| 1516 | unsigned int field_offset, | 1594 | unsigned int field_offset, |
| 1517 | unsigned *offset0, unsigned *offset1, | 1595 | unsigned *offset0, unsigned *offset1, |
| 1518 | s32 *row_inc, s32 *pix_inc) | 1596 | s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) |
| 1519 | { | 1597 | { |
| 1520 | u8 ps; | 1598 | u8 ps; |
| 1521 | u16 fbw, fbh; | 1599 | u16 fbw, fbh; |
| @@ -1557,10 +1635,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1557 | *offset0 = *offset1 + field_offset * screen_width * ps; | 1635 | *offset0 = *offset1 + field_offset * screen_width * ps; |
| 1558 | else | 1636 | else |
| 1559 | *offset0 = *offset1; | 1637 | *offset0 = *offset1; |
| 1560 | *row_inc = pixinc(1 + (screen_width - fbw) + | 1638 | *row_inc = pixinc(1 + |
| 1561 | (fieldmode ? screen_width : 0), | 1639 | (y_predecim * screen_width - fbw * x_predecim) + |
| 1562 | ps); | 1640 | (fieldmode ? screen_width : 0), ps); |
| 1563 | *pix_inc = pixinc(1, ps); | 1641 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
| 1642 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
| 1643 | *pix_inc = pixinc(x_predecim, 2 * ps); | ||
| 1644 | else | ||
| 1645 | *pix_inc = pixinc(x_predecim, ps); | ||
| 1564 | break; | 1646 | break; |
| 1565 | case OMAP_DSS_ROT_90: | 1647 | case OMAP_DSS_ROT_90: |
| 1566 | *offset1 = screen_width * (fbh - 1) * ps; | 1648 | *offset1 = screen_width * (fbh - 1) * ps; |
| @@ -1568,9 +1650,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1568 | *offset0 = *offset1 + field_offset * ps; | 1650 | *offset0 = *offset1 + field_offset * ps; |
| 1569 | else | 1651 | else |
| 1570 | *offset0 = *offset1; | 1652 | *offset0 = *offset1; |
| 1571 | *row_inc = pixinc(screen_width * (fbh - 1) + 1 + | 1653 | *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) + |
| 1572 | (fieldmode ? 1 : 0), ps); | 1654 | y_predecim + (fieldmode ? 1 : 0), ps); |
| 1573 | *pix_inc = pixinc(-screen_width, ps); | 1655 | *pix_inc = pixinc(-x_predecim * screen_width, ps); |
| 1574 | break; | 1656 | break; |
| 1575 | case OMAP_DSS_ROT_180: | 1657 | case OMAP_DSS_ROT_180: |
| 1576 | *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps; | 1658 | *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps; |
| @@ -1579,10 +1661,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1579 | else | 1661 | else |
| 1580 | *offset0 = *offset1; | 1662 | *offset0 = *offset1; |
| 1581 | *row_inc = pixinc(-1 - | 1663 | *row_inc = pixinc(-1 - |
| 1582 | (screen_width - fbw) - | 1664 | (y_predecim * screen_width - fbw * x_predecim) - |
| 1583 | (fieldmode ? screen_width : 0), | 1665 | (fieldmode ? screen_width : 0), ps); |
| 1584 | ps); | 1666 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
| 1585 | *pix_inc = pixinc(-1, ps); | 1667 | color_mode == OMAP_DSS_COLOR_UYVY) |
| 1668 | *pix_inc = pixinc(-x_predecim, 2 * ps); | ||
| 1669 | else | ||
| 1670 | *pix_inc = pixinc(-x_predecim, ps); | ||
| 1586 | break; | 1671 | break; |
| 1587 | case OMAP_DSS_ROT_270: | 1672 | case OMAP_DSS_ROT_270: |
| 1588 | *offset1 = (fbw - 1) * ps; | 1673 | *offset1 = (fbw - 1) * ps; |
| @@ -1590,9 +1675,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1590 | *offset0 = *offset1 - field_offset * ps; | 1675 | *offset0 = *offset1 - field_offset * ps; |
| 1591 | else | 1676 | else |
| 1592 | *offset0 = *offset1; | 1677 | *offset0 = *offset1; |
| 1593 | *row_inc = pixinc(-screen_width * (fbh - 1) - 1 - | 1678 | *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) - |
| 1594 | (fieldmode ? 1 : 0), ps); | 1679 | y_predecim - (fieldmode ? 1 : 0), ps); |
| 1595 | *pix_inc = pixinc(screen_width, ps); | 1680 | *pix_inc = pixinc(x_predecim * screen_width, ps); |
| 1596 | break; | 1681 | break; |
| 1597 | 1682 | ||
| 1598 | /* mirroring */ | 1683 | /* mirroring */ |
| @@ -1602,10 +1687,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1602 | *offset0 = *offset1 + field_offset * screen_width * ps; | 1687 | *offset0 = *offset1 + field_offset * screen_width * ps; |
| 1603 | else | 1688 | else |
| 1604 | *offset0 = *offset1; | 1689 | *offset0 = *offset1; |
| 1605 | *row_inc = pixinc(screen_width * 2 - 1 + | 1690 | *row_inc = pixinc(y_predecim * screen_width * 2 - 1 + |
| 1606 | (fieldmode ? screen_width : 0), | 1691 | (fieldmode ? screen_width : 0), |
| 1607 | ps); | 1692 | ps); |
| 1608 | *pix_inc = pixinc(-1, ps); | 1693 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
| 1694 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
| 1695 | *pix_inc = pixinc(-x_predecim, 2 * ps); | ||
| 1696 | else | ||
| 1697 | *pix_inc = pixinc(-x_predecim, ps); | ||
| 1609 | break; | 1698 | break; |
| 1610 | 1699 | ||
| 1611 | case OMAP_DSS_ROT_90 + 4: | 1700 | case OMAP_DSS_ROT_90 + 4: |
| @@ -1614,10 +1703,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1614 | *offset0 = *offset1 + field_offset * ps; | 1703 | *offset0 = *offset1 + field_offset * ps; |
| 1615 | else | 1704 | else |
| 1616 | *offset0 = *offset1; | 1705 | *offset0 = *offset1; |
| 1617 | *row_inc = pixinc(-screen_width * (fbh - 1) + 1 + | 1706 | *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) + |
| 1618 | (fieldmode ? 1 : 0), | 1707 | y_predecim + (fieldmode ? 1 : 0), |
| 1619 | ps); | 1708 | ps); |
| 1620 | *pix_inc = pixinc(screen_width, ps); | 1709 | *pix_inc = pixinc(x_predecim * screen_width, ps); |
| 1621 | break; | 1710 | break; |
| 1622 | 1711 | ||
| 1623 | case OMAP_DSS_ROT_180 + 4: | 1712 | case OMAP_DSS_ROT_180 + 4: |
| @@ -1626,10 +1715,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1626 | *offset0 = *offset1 - field_offset * screen_width * ps; | 1715 | *offset0 = *offset1 - field_offset * screen_width * ps; |
| 1627 | else | 1716 | else |
| 1628 | *offset0 = *offset1; | 1717 | *offset0 = *offset1; |
| 1629 | *row_inc = pixinc(1 - screen_width * 2 - | 1718 | *row_inc = pixinc(1 - y_predecim * screen_width * 2 - |
| 1630 | (fieldmode ? screen_width : 0), | 1719 | (fieldmode ? screen_width : 0), |
| 1631 | ps); | 1720 | ps); |
| 1632 | *pix_inc = pixinc(1, ps); | 1721 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
| 1722 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
| 1723 | *pix_inc = pixinc(x_predecim, 2 * ps); | ||
| 1724 | else | ||
| 1725 | *pix_inc = pixinc(x_predecim, ps); | ||
| 1633 | break; | 1726 | break; |
| 1634 | 1727 | ||
| 1635 | case OMAP_DSS_ROT_270 + 4: | 1728 | case OMAP_DSS_ROT_270 + 4: |
| @@ -1638,34 +1731,130 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
| 1638 | *offset0 = *offset1 - field_offset * ps; | 1731 | *offset0 = *offset1 - field_offset * ps; |
| 1639 | else | 1732 | else |
| 1640 | *offset0 = *offset1; | 1733 | *offset0 = *offset1; |
| 1641 | *row_inc = pixinc(screen_width * (fbh - 1) - 1 - | 1734 | *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) - |
| 1642 | (fieldmode ? 1 : 0), | 1735 | y_predecim - (fieldmode ? 1 : 0), |
| 1643 | ps); | 1736 | ps); |
| 1644 | *pix_inc = pixinc(-screen_width, ps); | 1737 | *pix_inc = pixinc(-x_predecim * screen_width, ps); |
| 1645 | break; | 1738 | break; |
| 1646 | 1739 | ||
| 1647 | default: | 1740 | default: |
| 1648 | BUG(); | 1741 | BUG(); |
| 1742 | return; | ||
| 1743 | } | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | static void calc_tiler_rotation_offset(u16 screen_width, u16 width, | ||
| 1747 | enum omap_color_mode color_mode, bool fieldmode, | ||
| 1748 | unsigned int field_offset, unsigned *offset0, unsigned *offset1, | ||
| 1749 | s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) | ||
| 1750 | { | ||
| 1751 | u8 ps; | ||
| 1752 | |||
| 1753 | switch (color_mode) { | ||
| 1754 | case OMAP_DSS_COLOR_CLUT1: | ||
| 1755 | case OMAP_DSS_COLOR_CLUT2: | ||
| 1756 | case OMAP_DSS_COLOR_CLUT4: | ||
| 1757 | case OMAP_DSS_COLOR_CLUT8: | ||
| 1758 | BUG(); | ||
| 1759 | return; | ||
| 1760 | default: | ||
| 1761 | ps = color_mode_to_bpp(color_mode) / 8; | ||
| 1762 | break; | ||
| 1649 | } | 1763 | } |
| 1764 | |||
| 1765 | DSSDBG("scrw %d, width %d\n", screen_width, width); | ||
| 1766 | |||
| 1767 | /* | ||
| 1768 | * field 0 = even field = bottom field | ||
| 1769 | * field 1 = odd field = top field | ||
| 1770 | */ | ||
| 1771 | *offset1 = 0; | ||
| 1772 | if (field_offset) | ||
| 1773 | *offset0 = *offset1 + field_offset * screen_width * ps; | ||
| 1774 | else | ||
| 1775 | *offset0 = *offset1; | ||
| 1776 | *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) + | ||
| 1777 | (fieldmode ? screen_width : 0), ps); | ||
| 1778 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | ||
| 1779 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
| 1780 | *pix_inc = pixinc(x_predecim, 2 * ps); | ||
| 1781 | else | ||
| 1782 | *pix_inc = pixinc(x_predecim, ps); | ||
| 1650 | } | 1783 | } |
| 1651 | 1784 | ||
| 1652 | static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, | 1785 | /* |
| 1786 | * This function is used to avoid synclosts in OMAP3, because of some | ||
| 1787 | * undocumented horizontal position and timing related limitations. | ||
| 1788 | */ | ||
| 1789 | static int check_horiz_timing_omap3(enum omap_channel channel, | ||
| 1790 | const struct omap_video_timings *t, u16 pos_x, | ||
| 1791 | u16 width, u16 height, u16 out_width, u16 out_height) | ||
| 1792 | { | ||
| 1793 | int DS = DIV_ROUND_UP(height, out_height); | ||
| 1794 | unsigned long nonactive, lclk, pclk; | ||
| 1795 | static const u8 limits[3] = { 8, 10, 20 }; | ||
| 1796 | u64 val, blank; | ||
| 1797 | int i; | ||
| 1798 | |||
| 1799 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; | ||
| 1800 | pclk = dispc_mgr_pclk_rate(channel); | ||
| 1801 | if (dispc_mgr_is_lcd(channel)) | ||
| 1802 | lclk = dispc_mgr_lclk_rate(channel); | ||
| 1803 | else | ||
| 1804 | lclk = dispc_fclk_rate(); | ||
| 1805 | |||
| 1806 | i = 0; | ||
| 1807 | if (out_height < height) | ||
| 1808 | i++; | ||
| 1809 | if (out_width < width) | ||
| 1810 | i++; | ||
| 1811 | blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk); | ||
| 1812 | DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]); | ||
| 1813 | if (blank <= limits[i]) | ||
| 1814 | return -EINVAL; | ||
| 1815 | |||
| 1816 | /* | ||
| 1817 | * Pixel data should be prepared before visible display point starts. | ||
| 1818 | * So, atleast DS-2 lines must have already been fetched by DISPC | ||
| 1819 | * during nonactive - pos_x period. | ||
| 1820 | */ | ||
| 1821 | val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); | ||
| 1822 | DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", | ||
| 1823 | val, max(0, DS - 2) * width); | ||
| 1824 | if (val < max(0, DS - 2) * width) | ||
| 1825 | return -EINVAL; | ||
| 1826 | |||
| 1827 | /* | ||
| 1828 | * All lines need to be refilled during the nonactive period of which | ||
| 1829 | * only one line can be loaded during the active period. So, atleast | ||
| 1830 | * DS - 1 lines should be loaded during nonactive period. | ||
| 1831 | */ | ||
| 1832 | val = div_u64((u64)nonactive * lclk, pclk); | ||
| 1833 | DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", | ||
| 1834 | val, max(0, DS - 1) * width); | ||
| 1835 | if (val < max(0, DS - 1) * width) | ||
| 1836 | return -EINVAL; | ||
| 1837 | |||
| 1838 | return 0; | ||
| 1839 | } | ||
| 1840 | |||
| 1841 | static unsigned long calc_core_clk_five_taps(enum omap_channel channel, | ||
| 1842 | const struct omap_video_timings *mgr_timings, u16 width, | ||
| 1653 | u16 height, u16 out_width, u16 out_height, | 1843 | u16 height, u16 out_width, u16 out_height, |
| 1654 | enum omap_color_mode color_mode) | 1844 | enum omap_color_mode color_mode) |
| 1655 | { | 1845 | { |
| 1656 | u32 fclk = 0; | 1846 | u32 core_clk = 0; |
| 1657 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); | 1847 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); |
| 1658 | 1848 | ||
| 1659 | if (height <= out_height && width <= out_width) | 1849 | if (height <= out_height && width <= out_width) |
| 1660 | return (unsigned long) pclk; | 1850 | return (unsigned long) pclk; |
| 1661 | 1851 | ||
| 1662 | if (height > out_height) { | 1852 | if (height > out_height) { |
| 1663 | struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); | 1853 | unsigned int ppl = mgr_timings->x_res; |
| 1664 | unsigned int ppl = dssdev->panel.timings.x_res; | ||
| 1665 | 1854 | ||
| 1666 | tmp = pclk * height * out_width; | 1855 | tmp = pclk * height * out_width; |
| 1667 | do_div(tmp, 2 * out_height * ppl); | 1856 | do_div(tmp, 2 * out_height * ppl); |
| 1668 | fclk = tmp; | 1857 | core_clk = tmp; |
| 1669 | 1858 | ||
| 1670 | if (height > 2 * out_height) { | 1859 | if (height > 2 * out_height) { |
| 1671 | if (ppl == out_width) | 1860 | if (ppl == out_width) |
| @@ -1673,23 +1862,23 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, | |||
| 1673 | 1862 | ||
| 1674 | tmp = pclk * (height - 2 * out_height) * out_width; | 1863 | tmp = pclk * (height - 2 * out_height) * out_width; |
| 1675 | do_div(tmp, 2 * out_height * (ppl - out_width)); | 1864 | do_div(tmp, 2 * out_height * (ppl - out_width)); |
| 1676 | fclk = max(fclk, (u32) tmp); | 1865 | core_clk = max_t(u32, core_clk, tmp); |
| 1677 | } | 1866 | } |
| 1678 | } | 1867 | } |
| 1679 | 1868 | ||
| 1680 | if (width > out_width) { | 1869 | if (width > out_width) { |
| 1681 | tmp = pclk * width; | 1870 | tmp = pclk * width; |
| 1682 | do_div(tmp, out_width); | 1871 | do_div(tmp, out_width); |
| 1683 | fclk = max(fclk, (u32) tmp); | 1872 | core_clk = max_t(u32, core_clk, tmp); |
| 1684 | 1873 | ||
| 1685 | if (color_mode == OMAP_DSS_COLOR_RGB24U) | 1874 | if (color_mode == OMAP_DSS_COLOR_RGB24U) |
| 1686 | fclk <<= 1; | 1875 | core_clk <<= 1; |
| 1687 | } | 1876 | } |
| 1688 | 1877 | ||
| 1689 | return fclk; | 1878 | return core_clk; |
| 1690 | } | 1879 | } |
| 1691 | 1880 | ||
| 1692 | static unsigned long calc_fclk(enum omap_channel channel, u16 width, | 1881 | static unsigned long calc_core_clk(enum omap_channel channel, u16 width, |
| 1693 | u16 height, u16 out_width, u16 out_height) | 1882 | u16 height, u16 out_width, u16 out_height) |
| 1694 | { | 1883 | { |
| 1695 | unsigned int hf, vf; | 1884 | unsigned int hf, vf; |
| @@ -1730,15 +1919,20 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, | |||
| 1730 | } | 1919 | } |
| 1731 | 1920 | ||
| 1732 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | 1921 | static int dispc_ovl_calc_scaling(enum omap_plane plane, |
| 1733 | enum omap_channel channel, u16 width, u16 height, | 1922 | enum omap_channel channel, |
| 1734 | u16 out_width, u16 out_height, | 1923 | const struct omap_video_timings *mgr_timings, |
| 1735 | enum omap_color_mode color_mode, bool *five_taps) | 1924 | u16 width, u16 height, u16 out_width, u16 out_height, |
| 1925 | enum omap_color_mode color_mode, bool *five_taps, | ||
| 1926 | int *x_predecim, int *y_predecim, u16 pos_x) | ||
| 1736 | { | 1927 | { |
| 1737 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 1928 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); |
| 1738 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | 1929 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); |
| 1739 | const int maxsinglelinewidth = | 1930 | const int maxsinglelinewidth = |
| 1740 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | 1931 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); |
| 1741 | unsigned long fclk = 0; | 1932 | const int max_decim_limit = 16; |
| 1933 | unsigned long core_clk = 0; | ||
| 1934 | int decim_x, decim_y, error, min_factor; | ||
| 1935 | u16 in_width, in_height, in_width_max = 0; | ||
| 1742 | 1936 | ||
| 1743 | if (width == out_width && height == out_height) | 1937 | if (width == out_width && height == out_height) |
| 1744 | return 0; | 1938 | return 0; |
| @@ -1746,64 +1940,154 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
| 1746 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) | 1940 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) |
| 1747 | return -EINVAL; | 1941 | return -EINVAL; |
| 1748 | 1942 | ||
| 1749 | if (out_width < width / maxdownscale || | 1943 | *x_predecim = max_decim_limit; |
| 1750 | out_width > width * 8) | 1944 | *y_predecim = max_decim_limit; |
| 1945 | |||
| 1946 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || | ||
| 1947 | color_mode == OMAP_DSS_COLOR_CLUT2 || | ||
| 1948 | color_mode == OMAP_DSS_COLOR_CLUT4 || | ||
| 1949 | color_mode == OMAP_DSS_COLOR_CLUT8) { | ||
| 1950 | *x_predecim = 1; | ||
| 1951 | *y_predecim = 1; | ||
| 1952 | *five_taps = false; | ||
| 1953 | return 0; | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); | ||
| 1957 | decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); | ||
| 1958 | |||
| 1959 | min_factor = min(decim_x, decim_y); | ||
| 1960 | |||
| 1961 | if (decim_x > *x_predecim || out_width > width * 8) | ||
| 1751 | return -EINVAL; | 1962 | return -EINVAL; |
| 1752 | 1963 | ||
| 1753 | if (out_height < height / maxdownscale || | 1964 | if (decim_y > *y_predecim || out_height > height * 8) |
| 1754 | out_height > height * 8) | ||
| 1755 | return -EINVAL; | 1965 | return -EINVAL; |
| 1756 | 1966 | ||
| 1757 | if (cpu_is_omap24xx()) { | 1967 | if (cpu_is_omap24xx()) { |
| 1758 | if (width > maxsinglelinewidth) | ||
| 1759 | DSSERR("Cannot scale max input width exceeded"); | ||
| 1760 | *five_taps = false; | 1968 | *five_taps = false; |
| 1761 | fclk = calc_fclk(channel, width, height, out_width, | 1969 | |
| 1762 | out_height); | 1970 | do { |
| 1971 | in_height = DIV_ROUND_UP(height, decim_y); | ||
| 1972 | in_width = DIV_ROUND_UP(width, decim_x); | ||
| 1973 | core_clk = calc_core_clk(channel, in_width, in_height, | ||
| 1974 | out_width, out_height); | ||
| 1975 | error = (in_width > maxsinglelinewidth || !core_clk || | ||
| 1976 | core_clk > dispc_core_clk_rate()); | ||
| 1977 | if (error) { | ||
| 1978 | if (decim_x == decim_y) { | ||
| 1979 | decim_x = min_factor; | ||
| 1980 | decim_y++; | ||
| 1981 | } else { | ||
| 1982 | swap(decim_x, decim_y); | ||
| 1983 | if (decim_x < decim_y) | ||
| 1984 | decim_x++; | ||
| 1985 | } | ||
| 1986 | } | ||
| 1987 | } while (decim_x <= *x_predecim && decim_y <= *y_predecim && | ||
| 1988 | error); | ||
| 1989 | |||
| 1990 | if (in_width > maxsinglelinewidth) { | ||
| 1991 | DSSERR("Cannot scale max input width exceeded"); | ||
| 1992 | return -EINVAL; | ||
| 1993 | } | ||
| 1763 | } else if (cpu_is_omap34xx()) { | 1994 | } else if (cpu_is_omap34xx()) { |
| 1764 | if (width > (maxsinglelinewidth * 2)) { | 1995 | |
| 1996 | do { | ||
| 1997 | in_height = DIV_ROUND_UP(height, decim_y); | ||
| 1998 | in_width = DIV_ROUND_UP(width, decim_x); | ||
| 1999 | core_clk = calc_core_clk_five_taps(channel, mgr_timings, | ||
| 2000 | in_width, in_height, out_width, out_height, | ||
| 2001 | color_mode); | ||
| 2002 | |||
| 2003 | error = check_horiz_timing_omap3(channel, mgr_timings, | ||
| 2004 | pos_x, in_width, in_height, out_width, | ||
| 2005 | out_height); | ||
| 2006 | |||
| 2007 | if (in_width > maxsinglelinewidth) | ||
| 2008 | if (in_height > out_height && | ||
| 2009 | in_height < out_height * 2) | ||
| 2010 | *five_taps = false; | ||
| 2011 | if (!*five_taps) | ||
| 2012 | core_clk = calc_core_clk(channel, in_width, | ||
| 2013 | in_height, out_width, out_height); | ||
| 2014 | error = (error || in_width > maxsinglelinewidth * 2 || | ||
| 2015 | (in_width > maxsinglelinewidth && *five_taps) || | ||
| 2016 | !core_clk || core_clk > dispc_core_clk_rate()); | ||
| 2017 | if (error) { | ||
| 2018 | if (decim_x == decim_y) { | ||
| 2019 | decim_x = min_factor; | ||
| 2020 | decim_y++; | ||
| 2021 | } else { | ||
| 2022 | swap(decim_x, decim_y); | ||
| 2023 | if (decim_x < decim_y) | ||
| 2024 | decim_x++; | ||
| 2025 | } | ||
| 2026 | } | ||
| 2027 | } while (decim_x <= *x_predecim && decim_y <= *y_predecim | ||
| 2028 | && error); | ||
| 2029 | |||
| 2030 | if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, | ||
| 2031 | height, out_width, out_height)){ | ||
| 2032 | DSSERR("horizontal timing too tight\n"); | ||
| 2033 | return -EINVAL; | ||
| 2034 | } | ||
| 2035 | |||
| 2036 | if (in_width > (maxsinglelinewidth * 2)) { | ||
| 1765 | DSSERR("Cannot setup scaling"); | 2037 | DSSERR("Cannot setup scaling"); |
| 1766 | DSSERR("width exceeds maximum width possible"); | 2038 | DSSERR("width exceeds maximum width possible"); |
| 1767 | return -EINVAL; | 2039 | return -EINVAL; |
| 1768 | } | 2040 | } |
| 1769 | fclk = calc_fclk_five_taps(channel, width, height, out_width, | 2041 | |
| 1770 | out_height, color_mode); | 2042 | if (in_width > maxsinglelinewidth && *five_taps) { |
| 1771 | if (width > maxsinglelinewidth) { | 2043 | DSSERR("cannot setup scaling with five taps"); |
| 1772 | if (height > out_height && height < out_height * 2) | 2044 | return -EINVAL; |
| 1773 | *five_taps = false; | ||
| 1774 | else { | ||
| 1775 | DSSERR("cannot setup scaling with five taps"); | ||
| 1776 | return -EINVAL; | ||
| 1777 | } | ||
| 1778 | } | 2045 | } |
| 1779 | if (!*five_taps) | ||
| 1780 | fclk = calc_fclk(channel, width, height, out_width, | ||
| 1781 | out_height); | ||
| 1782 | } else { | 2046 | } else { |
| 1783 | if (width > maxsinglelinewidth) { | 2047 | int decim_x_min = decim_x; |
| 2048 | in_height = DIV_ROUND_UP(height, decim_y); | ||
| 2049 | in_width_max = dispc_core_clk_rate() / | ||
| 2050 | DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), | ||
| 2051 | out_width); | ||
| 2052 | decim_x = DIV_ROUND_UP(width, in_width_max); | ||
| 2053 | |||
| 2054 | decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; | ||
| 2055 | if (decim_x > *x_predecim) | ||
| 2056 | return -EINVAL; | ||
| 2057 | |||
| 2058 | do { | ||
| 2059 | in_width = DIV_ROUND_UP(width, decim_x); | ||
| 2060 | } while (decim_x <= *x_predecim && | ||
| 2061 | in_width > maxsinglelinewidth && decim_x++); | ||
| 2062 | |||
| 2063 | if (in_width > maxsinglelinewidth) { | ||
| 1784 | DSSERR("Cannot scale width exceeds max line width"); | 2064 | DSSERR("Cannot scale width exceeds max line width"); |
| 1785 | return -EINVAL; | 2065 | return -EINVAL; |
| 1786 | } | 2066 | } |
| 1787 | fclk = calc_fclk(channel, width, height, out_width, | 2067 | |
| 1788 | out_height); | 2068 | core_clk = calc_core_clk(channel, in_width, in_height, |
| 2069 | out_width, out_height); | ||
| 1789 | } | 2070 | } |
| 1790 | 2071 | ||
| 1791 | DSSDBG("required fclk rate = %lu Hz\n", fclk); | 2072 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); |
| 1792 | DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); | 2073 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); |
| 1793 | 2074 | ||
| 1794 | if (!fclk || fclk > dispc_fclk_rate()) { | 2075 | if (!core_clk || core_clk > dispc_core_clk_rate()) { |
| 1795 | DSSERR("failed to set up scaling, " | 2076 | DSSERR("failed to set up scaling, " |
| 1796 | "required fclk rate = %lu Hz, " | 2077 | "required core clk rate = %lu Hz, " |
| 1797 | "current fclk rate = %lu Hz\n", | 2078 | "current core clk rate = %lu Hz\n", |
| 1798 | fclk, dispc_fclk_rate()); | 2079 | core_clk, dispc_core_clk_rate()); |
| 1799 | return -EINVAL; | 2080 | return -EINVAL; |
| 1800 | } | 2081 | } |
| 1801 | 2082 | ||
| 2083 | *x_predecim = decim_x; | ||
| 2084 | *y_predecim = decim_y; | ||
| 1802 | return 0; | 2085 | return 0; |
| 1803 | } | 2086 | } |
| 1804 | 2087 | ||
| 1805 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 2088 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
| 1806 | bool ilace, bool replication) | 2089 | bool ilace, bool replication, |
| 2090 | const struct omap_video_timings *mgr_timings) | ||
| 1807 | { | 2091 | { |
| 1808 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 2092 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); |
| 1809 | bool five_taps = true; | 2093 | bool five_taps = true; |
| @@ -1814,8 +2098,11 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
| 1814 | s32 pix_inc; | 2098 | s32 pix_inc; |
| 1815 | u16 frame_height = oi->height; | 2099 | u16 frame_height = oi->height; |
| 1816 | unsigned int field_offset = 0; | 2100 | unsigned int field_offset = 0; |
| 1817 | u16 outw, outh; | 2101 | u16 in_height = oi->height; |
| 2102 | u16 in_width = oi->width; | ||
| 2103 | u16 out_width, out_height; | ||
| 1818 | enum omap_channel channel; | 2104 | enum omap_channel channel; |
| 2105 | int x_predecim = 1, y_predecim = 1; | ||
| 1819 | 2106 | ||
| 1820 | channel = dispc_ovl_get_channel_out(plane); | 2107 | channel = dispc_ovl_get_channel_out(plane); |
| 1821 | 2108 | ||
| @@ -1829,32 +2116,35 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
| 1829 | if (oi->paddr == 0) | 2116 | if (oi->paddr == 0) |
| 1830 | return -EINVAL; | 2117 | return -EINVAL; |
| 1831 | 2118 | ||
| 1832 | outw = oi->out_width == 0 ? oi->width : oi->out_width; | 2119 | out_width = oi->out_width == 0 ? oi->width : oi->out_width; |
| 1833 | outh = oi->out_height == 0 ? oi->height : oi->out_height; | 2120 | out_height = oi->out_height == 0 ? oi->height : oi->out_height; |
| 1834 | 2121 | ||
| 1835 | if (ilace && oi->height == outh) | 2122 | if (ilace && oi->height == out_height) |
| 1836 | fieldmode = 1; | 2123 | fieldmode = 1; |
| 1837 | 2124 | ||
| 1838 | if (ilace) { | 2125 | if (ilace) { |
| 1839 | if (fieldmode) | 2126 | if (fieldmode) |
| 1840 | oi->height /= 2; | 2127 | in_height /= 2; |
| 1841 | oi->pos_y /= 2; | 2128 | oi->pos_y /= 2; |
| 1842 | outh /= 2; | 2129 | out_height /= 2; |
| 1843 | 2130 | ||
| 1844 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " | 2131 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " |
| 1845 | "out_height %d\n", | 2132 | "out_height %d\n", |
| 1846 | oi->height, oi->pos_y, outh); | 2133 | in_height, oi->pos_y, out_height); |
| 1847 | } | 2134 | } |
| 1848 | 2135 | ||
| 1849 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | 2136 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) |
| 1850 | return -EINVAL; | 2137 | return -EINVAL; |
| 1851 | 2138 | ||
| 1852 | r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, | 2139 | r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, |
| 1853 | outw, outh, oi->color_mode, | 2140 | in_height, out_width, out_height, oi->color_mode, |
| 1854 | &five_taps); | 2141 | &five_taps, &x_predecim, &y_predecim, oi->pos_x); |
| 1855 | if (r) | 2142 | if (r) |
| 1856 | return r; | 2143 | return r; |
| 1857 | 2144 | ||
| 2145 | in_width = DIV_ROUND_UP(in_width, x_predecim); | ||
| 2146 | in_height = DIV_ROUND_UP(in_height, y_predecim); | ||
| 2147 | |||
| 1858 | if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || | 2148 | if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || |
| 1859 | oi->color_mode == OMAP_DSS_COLOR_UYVY || | 2149 | oi->color_mode == OMAP_DSS_COLOR_UYVY || |
| 1860 | oi->color_mode == OMAP_DSS_COLOR_NV12) | 2150 | oi->color_mode == OMAP_DSS_COLOR_NV12) |
| @@ -1868,32 +2158,46 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
| 1868 | * so the integer part must be added to the base address of the | 2158 | * so the integer part must be added to the base address of the |
| 1869 | * bottom field. | 2159 | * bottom field. |
| 1870 | */ | 2160 | */ |
| 1871 | if (!oi->height || oi->height == outh) | 2161 | if (!in_height || in_height == out_height) |
| 1872 | field_offset = 0; | 2162 | field_offset = 0; |
| 1873 | else | 2163 | else |
| 1874 | field_offset = oi->height / outh / 2; | 2164 | field_offset = in_height / out_height / 2; |
| 1875 | } | 2165 | } |
| 1876 | 2166 | ||
| 1877 | /* Fields are independent but interleaved in memory. */ | 2167 | /* Fields are independent but interleaved in memory. */ |
| 1878 | if (fieldmode) | 2168 | if (fieldmode) |
| 1879 | field_offset = 1; | 2169 | field_offset = 1; |
| 1880 | 2170 | ||
| 1881 | if (oi->rotation_type == OMAP_DSS_ROT_DMA) | 2171 | offset0 = 0; |
| 2172 | offset1 = 0; | ||
| 2173 | row_inc = 0; | ||
| 2174 | pix_inc = 0; | ||
| 2175 | |||
| 2176 | if (oi->rotation_type == OMAP_DSS_ROT_TILER) | ||
| 2177 | calc_tiler_rotation_offset(oi->screen_width, in_width, | ||
| 2178 | oi->color_mode, fieldmode, field_offset, | ||
| 2179 | &offset0, &offset1, &row_inc, &pix_inc, | ||
| 2180 | x_predecim, y_predecim); | ||
| 2181 | else if (oi->rotation_type == OMAP_DSS_ROT_DMA) | ||
| 1882 | calc_dma_rotation_offset(oi->rotation, oi->mirror, | 2182 | calc_dma_rotation_offset(oi->rotation, oi->mirror, |
| 1883 | oi->screen_width, oi->width, frame_height, | 2183 | oi->screen_width, in_width, frame_height, |
| 1884 | oi->color_mode, fieldmode, field_offset, | 2184 | oi->color_mode, fieldmode, field_offset, |
| 1885 | &offset0, &offset1, &row_inc, &pix_inc); | 2185 | &offset0, &offset1, &row_inc, &pix_inc, |
| 2186 | x_predecim, y_predecim); | ||
| 1886 | else | 2187 | else |
| 1887 | calc_vrfb_rotation_offset(oi->rotation, oi->mirror, | 2188 | calc_vrfb_rotation_offset(oi->rotation, oi->mirror, |
| 1888 | oi->screen_width, oi->width, frame_height, | 2189 | oi->screen_width, in_width, frame_height, |
| 1889 | oi->color_mode, fieldmode, field_offset, | 2190 | oi->color_mode, fieldmode, field_offset, |
| 1890 | &offset0, &offset1, &row_inc, &pix_inc); | 2191 | &offset0, &offset1, &row_inc, &pix_inc, |
| 2192 | x_predecim, y_predecim); | ||
| 1891 | 2193 | ||
| 1892 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", | 2194 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", |
| 1893 | offset0, offset1, row_inc, pix_inc); | 2195 | offset0, offset1, row_inc, pix_inc); |
| 1894 | 2196 | ||
| 1895 | dispc_ovl_set_color_mode(plane, oi->color_mode); | 2197 | dispc_ovl_set_color_mode(plane, oi->color_mode); |
| 1896 | 2198 | ||
| 2199 | dispc_ovl_configure_burst_type(plane, oi->rotation_type); | ||
| 2200 | |||
| 1897 | dispc_ovl_set_ba0(plane, oi->paddr + offset0); | 2201 | dispc_ovl_set_ba0(plane, oi->paddr + offset0); |
| 1898 | dispc_ovl_set_ba1(plane, oi->paddr + offset1); | 2202 | dispc_ovl_set_ba1(plane, oi->paddr + offset1); |
| 1899 | 2203 | ||
| @@ -1906,19 +2210,18 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
| 1906 | dispc_ovl_set_row_inc(plane, row_inc); | 2210 | dispc_ovl_set_row_inc(plane, row_inc); |
| 1907 | dispc_ovl_set_pix_inc(plane, pix_inc); | 2211 | dispc_ovl_set_pix_inc(plane, pix_inc); |
| 1908 | 2212 | ||
| 1909 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, | 2213 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, |
| 1910 | oi->height, outw, outh); | 2214 | in_height, out_width, out_height); |
| 1911 | 2215 | ||
| 1912 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); | 2216 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); |
| 1913 | 2217 | ||
| 1914 | dispc_ovl_set_pic_size(plane, oi->width, oi->height); | 2218 | dispc_ovl_set_pic_size(plane, in_width, in_height); |
| 1915 | 2219 | ||
| 1916 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { | 2220 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { |
| 1917 | dispc_ovl_set_scaling(plane, oi->width, oi->height, | 2221 | dispc_ovl_set_scaling(plane, in_width, in_height, out_width, |
| 1918 | outw, outh, | 2222 | out_height, ilace, five_taps, fieldmode, |
| 1919 | ilace, five_taps, fieldmode, | ||
| 1920 | oi->color_mode, oi->rotation); | 2223 | oi->color_mode, oi->rotation); |
| 1921 | dispc_ovl_set_vid_size(plane, outw, outh); | 2224 | dispc_ovl_set_vid_size(plane, out_width, out_height); |
| 1922 | dispc_ovl_set_vid_color_conv(plane, cconv); | 2225 | dispc_ovl_set_vid_color_conv(plane, cconv); |
| 1923 | } | 2226 | } |
| 1924 | 2227 | ||
| @@ -2087,8 +2390,10 @@ bool dispc_mgr_is_enabled(enum omap_channel channel) | |||
| 2087 | return !!REG_GET(DISPC_CONTROL, 1, 1); | 2390 | return !!REG_GET(DISPC_CONTROL, 1, 1); |
| 2088 | else if (channel == OMAP_DSS_CHANNEL_LCD2) | 2391 | else if (channel == OMAP_DSS_CHANNEL_LCD2) |
| 2089 | return !!REG_GET(DISPC_CONTROL2, 0, 0); | 2392 | return !!REG_GET(DISPC_CONTROL2, 0, 0); |
| 2090 | else | 2393 | else { |
| 2091 | BUG(); | 2394 | BUG(); |
| 2395 | return false; | ||
| 2396 | } | ||
| 2092 | } | 2397 | } |
| 2093 | 2398 | ||
| 2094 | void dispc_mgr_enable(enum omap_channel channel, bool enable) | 2399 | void dispc_mgr_enable(enum omap_channel channel, bool enable) |
| @@ -2285,6 +2590,12 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) | |||
| 2285 | REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11); | 2590 | REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11); |
| 2286 | } | 2591 | } |
| 2287 | 2592 | ||
| 2593 | static bool _dispc_mgr_size_ok(u16 width, u16 height) | ||
| 2594 | { | ||
| 2595 | return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) && | ||
| 2596 | height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT); | ||
| 2597 | } | ||
| 2598 | |||
| 2288 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | 2599 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, |
| 2289 | int vsw, int vfp, int vbp) | 2600 | int vsw, int vfp, int vbp) |
| 2290 | { | 2601 | { |
| @@ -2309,11 +2620,20 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | |||
| 2309 | return true; | 2620 | return true; |
| 2310 | } | 2621 | } |
| 2311 | 2622 | ||
| 2312 | bool dispc_lcd_timings_ok(struct omap_video_timings *timings) | 2623 | bool dispc_mgr_timings_ok(enum omap_channel channel, |
| 2624 | const struct omap_video_timings *timings) | ||
| 2313 | { | 2625 | { |
| 2314 | return _dispc_lcd_timings_ok(timings->hsw, timings->hfp, | 2626 | bool timings_ok; |
| 2315 | timings->hbp, timings->vsw, | 2627 | |
| 2316 | timings->vfp, timings->vbp); | 2628 | timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); |
| 2629 | |||
| 2630 | if (dispc_mgr_is_lcd(channel)) | ||
| 2631 | timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw, | ||
| 2632 | timings->hfp, timings->hbp, | ||
| 2633 | timings->vsw, timings->vfp, | ||
| 2634 | timings->vbp); | ||
| 2635 | |||
| 2636 | return timings_ok; | ||
| 2317 | } | 2637 | } |
| 2318 | 2638 | ||
| 2319 | static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | 2639 | static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, |
| @@ -2340,37 +2660,45 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | |||
| 2340 | } | 2660 | } |
| 2341 | 2661 | ||
| 2342 | /* change name to mode? */ | 2662 | /* change name to mode? */ |
| 2343 | void dispc_mgr_set_lcd_timings(enum omap_channel channel, | 2663 | void dispc_mgr_set_timings(enum omap_channel channel, |
| 2344 | struct omap_video_timings *timings) | 2664 | struct omap_video_timings *timings) |
| 2345 | { | 2665 | { |
| 2346 | unsigned xtot, ytot; | 2666 | unsigned xtot, ytot; |
| 2347 | unsigned long ht, vt; | 2667 | unsigned long ht, vt; |
| 2668 | struct omap_video_timings t = *timings; | ||
| 2669 | |||
| 2670 | DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res); | ||
| 2348 | 2671 | ||
| 2349 | if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp, | 2672 | if (!dispc_mgr_timings_ok(channel, &t)) { |
| 2350 | timings->hbp, timings->vsw, | ||
| 2351 | timings->vfp, timings->vbp)) | ||
| 2352 | BUG(); | 2673 | BUG(); |
| 2674 | return; | ||
| 2675 | } | ||
| 2676 | |||
| 2677 | if (dispc_mgr_is_lcd(channel)) { | ||
| 2678 | _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw, | ||
| 2679 | t.vfp, t.vbp); | ||
| 2680 | |||
| 2681 | xtot = t.x_res + t.hfp + t.hsw + t.hbp; | ||
| 2682 | ytot = t.y_res + t.vfp + t.vsw + t.vbp; | ||
| 2353 | 2683 | ||
| 2354 | _dispc_mgr_set_lcd_timings(channel, timings->hsw, timings->hfp, | 2684 | ht = (timings->pixel_clock * 1000) / xtot; |
| 2355 | timings->hbp, timings->vsw, timings->vfp, | 2685 | vt = (timings->pixel_clock * 1000) / xtot / ytot; |
| 2356 | timings->vbp); | ||
| 2357 | 2686 | ||
| 2358 | dispc_mgr_set_lcd_size(channel, timings->x_res, timings->y_res); | 2687 | DSSDBG("pck %u\n", timings->pixel_clock); |
| 2688 | DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", | ||
| 2689 | t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp); | ||
| 2359 | 2690 | ||
| 2360 | xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp; | 2691 | DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); |
| 2361 | ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp; | 2692 | } else { |
| 2693 | enum dss_hdmi_venc_clk_source_select source; | ||
| 2362 | 2694 | ||
| 2363 | ht = (timings->pixel_clock * 1000) / xtot; | 2695 | source = dss_get_hdmi_venc_clk_source(); |
| 2364 | vt = (timings->pixel_clock * 1000) / xtot / ytot; | ||
| 2365 | 2696 | ||
| 2366 | DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res, | 2697 | if (source == DSS_VENC_TV_CLK) |
| 2367 | timings->y_res); | 2698 | t.y_res /= 2; |
| 2368 | DSSDBG("pck %u\n", timings->pixel_clock); | 2699 | } |
| 2369 | DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", | ||
| 2370 | timings->hsw, timings->hfp, timings->hbp, | ||
| 2371 | timings->vsw, timings->vfp, timings->vbp); | ||
| 2372 | 2700 | ||
| 2373 | DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); | 2701 | dispc_mgr_set_size(channel, t.x_res, t.y_res); |
| 2374 | } | 2702 | } |
| 2375 | 2703 | ||
| 2376 | static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, | 2704 | static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, |
| @@ -2411,6 +2739,7 @@ unsigned long dispc_fclk_rate(void) | |||
| 2411 | break; | 2739 | break; |
| 2412 | default: | 2740 | default: |
| 2413 | BUG(); | 2741 | BUG(); |
| 2742 | return 0; | ||
| 2414 | } | 2743 | } |
| 2415 | 2744 | ||
| 2416 | return r; | 2745 | return r; |
| @@ -2441,6 +2770,7 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) | |||
| 2441 | break; | 2770 | break; |
| 2442 | default: | 2771 | default: |
| 2443 | BUG(); | 2772 | BUG(); |
| 2773 | return 0; | ||
| 2444 | } | 2774 | } |
| 2445 | 2775 | ||
| 2446 | return r / lcd; | 2776 | return r / lcd; |
| @@ -2462,20 +2792,35 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) | |||
| 2462 | 2792 | ||
| 2463 | return r / pcd; | 2793 | return r / pcd; |
| 2464 | } else { | 2794 | } else { |
| 2465 | struct omap_dss_device *dssdev = | 2795 | enum dss_hdmi_venc_clk_source_select source; |
| 2466 | dispc_mgr_get_device(channel); | ||
| 2467 | 2796 | ||
| 2468 | switch (dssdev->type) { | 2797 | source = dss_get_hdmi_venc_clk_source(); |
| 2469 | case OMAP_DISPLAY_TYPE_VENC: | 2798 | |
| 2799 | switch (source) { | ||
| 2800 | case DSS_VENC_TV_CLK: | ||
| 2470 | return venc_get_pixel_clock(); | 2801 | return venc_get_pixel_clock(); |
| 2471 | case OMAP_DISPLAY_TYPE_HDMI: | 2802 | case DSS_HDMI_M_PCLK: |
| 2472 | return hdmi_get_pixel_clock(); | 2803 | return hdmi_get_pixel_clock(); |
| 2473 | default: | 2804 | default: |
| 2474 | BUG(); | 2805 | BUG(); |
| 2806 | return 0; | ||
| 2475 | } | 2807 | } |
| 2476 | } | 2808 | } |
| 2477 | } | 2809 | } |
| 2478 | 2810 | ||
| 2811 | unsigned long dispc_core_clk_rate(void) | ||
| 2812 | { | ||
| 2813 | int lcd; | ||
| 2814 | unsigned long fclk = dispc_fclk_rate(); | ||
| 2815 | |||
| 2816 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | ||
| 2817 | lcd = REG_GET(DISPC_DIVISOR, 23, 16); | ||
| 2818 | else | ||
| 2819 | lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16); | ||
| 2820 | |||
| 2821 | return fclk / lcd; | ||
| 2822 | } | ||
| 2823 | |||
| 2479 | void dispc_dump_clocks(struct seq_file *s) | 2824 | void dispc_dump_clocks(struct seq_file *s) |
| 2480 | { | 2825 | { |
| 2481 | int lcd, pcd; | 2826 | int lcd, pcd; |
| @@ -2588,7 +2933,7 @@ void dispc_dump_irqs(struct seq_file *s) | |||
| 2588 | } | 2933 | } |
| 2589 | #endif | 2934 | #endif |
| 2590 | 2935 | ||
| 2591 | void dispc_dump_regs(struct seq_file *s) | 2936 | static void dispc_dump_regs(struct seq_file *s) |
| 2592 | { | 2937 | { |
| 2593 | int i, j; | 2938 | int i, j; |
| 2594 | const char *mgr_names[] = { | 2939 | const char *mgr_names[] = { |
| @@ -3247,27 +3592,6 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | |||
| 3247 | return 0; | 3592 | return 0; |
| 3248 | } | 3593 | } |
| 3249 | 3594 | ||
| 3250 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
| 3251 | void dispc_fake_vsync_irq(void) | ||
| 3252 | { | ||
| 3253 | u32 irqstatus = DISPC_IRQ_VSYNC; | ||
| 3254 | int i; | ||
| 3255 | |||
| 3256 | WARN_ON(!in_interrupt()); | ||
| 3257 | |||
| 3258 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 3259 | struct omap_dispc_isr_data *isr_data; | ||
| 3260 | isr_data = &dispc.registered_isr[i]; | ||
| 3261 | |||
| 3262 | if (!isr_data->isr) | ||
| 3263 | continue; | ||
| 3264 | |||
| 3265 | if (isr_data->mask & irqstatus) | ||
| 3266 | isr_data->isr(isr_data->arg, irqstatus); | ||
| 3267 | } | ||
| 3268 | } | ||
| 3269 | #endif | ||
| 3270 | |||
| 3271 | static void _omap_dispc_initialize_irq(void) | 3595 | static void _omap_dispc_initialize_irq(void) |
| 3272 | { | 3596 | { |
| 3273 | unsigned long flags; | 3597 | unsigned long flags; |
| @@ -3330,7 +3654,7 @@ static void _omap_dispc_initial_config(void) | |||
| 3330 | } | 3654 | } |
| 3331 | 3655 | ||
| 3332 | /* DISPC HW IP initialisation */ | 3656 | /* DISPC HW IP initialisation */ |
| 3333 | static int omap_dispchw_probe(struct platform_device *pdev) | 3657 | static int __init omap_dispchw_probe(struct platform_device *pdev) |
| 3334 | { | 3658 | { |
| 3335 | u32 rev; | 3659 | u32 rev; |
| 3336 | int r = 0; | 3660 | int r = 0; |
| @@ -3399,6 +3723,11 @@ static int omap_dispchw_probe(struct platform_device *pdev) | |||
| 3399 | 3723 | ||
| 3400 | dispc_runtime_put(); | 3724 | dispc_runtime_put(); |
| 3401 | 3725 | ||
| 3726 | dss_debugfs_create_file("dispc", dispc_dump_regs); | ||
| 3727 | |||
| 3728 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 3729 | dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); | ||
| 3730 | #endif | ||
| 3402 | return 0; | 3731 | return 0; |
| 3403 | 3732 | ||
| 3404 | err_runtime_get: | 3733 | err_runtime_get: |
| @@ -3407,7 +3736,7 @@ err_runtime_get: | |||
| 3407 | return r; | 3736 | return r; |
| 3408 | } | 3737 | } |
| 3409 | 3738 | ||
| 3410 | static int omap_dispchw_remove(struct platform_device *pdev) | 3739 | static int __exit omap_dispchw_remove(struct platform_device *pdev) |
| 3411 | { | 3740 | { |
| 3412 | pm_runtime_disable(&pdev->dev); | 3741 | pm_runtime_disable(&pdev->dev); |
| 3413 | 3742 | ||
| @@ -3419,19 +3748,12 @@ static int omap_dispchw_remove(struct platform_device *pdev) | |||
| 3419 | static int dispc_runtime_suspend(struct device *dev) | 3748 | static int dispc_runtime_suspend(struct device *dev) |
| 3420 | { | 3749 | { |
| 3421 | dispc_save_context(); | 3750 | dispc_save_context(); |
| 3422 | dss_runtime_put(); | ||
| 3423 | 3751 | ||
| 3424 | return 0; | 3752 | return 0; |
| 3425 | } | 3753 | } |
| 3426 | 3754 | ||
| 3427 | static int dispc_runtime_resume(struct device *dev) | 3755 | static int dispc_runtime_resume(struct device *dev) |
| 3428 | { | 3756 | { |
| 3429 | int r; | ||
| 3430 | |||
| 3431 | r = dss_runtime_get(); | ||
| 3432 | if (r < 0) | ||
| 3433 | return r; | ||
| 3434 | |||
| 3435 | dispc_restore_context(); | 3757 | dispc_restore_context(); |
| 3436 | 3758 | ||
| 3437 | return 0; | 3759 | return 0; |
| @@ -3443,8 +3765,7 @@ static const struct dev_pm_ops dispc_pm_ops = { | |||
| 3443 | }; | 3765 | }; |
| 3444 | 3766 | ||
| 3445 | static struct platform_driver omap_dispchw_driver = { | 3767 | static struct platform_driver omap_dispchw_driver = { |
| 3446 | .probe = omap_dispchw_probe, | 3768 | .remove = __exit_p(omap_dispchw_remove), |
| 3447 | .remove = omap_dispchw_remove, | ||
| 3448 | .driver = { | 3769 | .driver = { |
| 3449 | .name = "omapdss_dispc", | 3770 | .name = "omapdss_dispc", |
| 3450 | .owner = THIS_MODULE, | 3771 | .owner = THIS_MODULE, |
| @@ -3452,12 +3773,12 @@ static struct platform_driver omap_dispchw_driver = { | |||
| 3452 | }, | 3773 | }, |
| 3453 | }; | 3774 | }; |
| 3454 | 3775 | ||
| 3455 | int dispc_init_platform_driver(void) | 3776 | int __init dispc_init_platform_driver(void) |
| 3456 | { | 3777 | { |
| 3457 | return platform_driver_register(&omap_dispchw_driver); | 3778 | return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe); |
| 3458 | } | 3779 | } |
| 3459 | 3780 | ||
| 3460 | void dispc_uninit_platform_driver(void) | 3781 | void __exit dispc_uninit_platform_driver(void) |
| 3461 | { | 3782 | { |
| 3462 | return platform_driver_unregister(&omap_dispchw_driver); | 3783 | platform_driver_unregister(&omap_dispchw_driver); |
| 3463 | } | 3784 | } |
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 5836bd1650f9..f278080e1063 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h | |||
| @@ -120,6 +120,7 @@ static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) | |||
| 120 | return 0x03AC; | 120 | return 0x03AC; |
| 121 | default: | 121 | default: |
| 122 | BUG(); | 122 | BUG(); |
| 123 | return 0; | ||
| 123 | } | 124 | } |
| 124 | } | 125 | } |
| 125 | 126 | ||
| @@ -134,6 +135,7 @@ static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel) | |||
| 134 | return 0x03B0; | 135 | return 0x03B0; |
| 135 | default: | 136 | default: |
| 136 | BUG(); | 137 | BUG(); |
| 138 | return 0; | ||
| 137 | } | 139 | } |
| 138 | } | 140 | } |
| 139 | 141 | ||
| @@ -144,10 +146,12 @@ static inline u16 DISPC_TIMING_H(enum omap_channel channel) | |||
| 144 | return 0x0064; | 146 | return 0x0064; |
| 145 | case OMAP_DSS_CHANNEL_DIGIT: | 147 | case OMAP_DSS_CHANNEL_DIGIT: |
| 146 | BUG(); | 148 | BUG(); |
| 149 | return 0; | ||
| 147 | case OMAP_DSS_CHANNEL_LCD2: | 150 | case OMAP_DSS_CHANNEL_LCD2: |
| 148 | return 0x0400; | 151 | return 0x0400; |
| 149 | default: | 152 | default: |
| 150 | BUG(); | 153 | BUG(); |
| 154 | return 0; | ||
| 151 | } | 155 | } |
| 152 | } | 156 | } |
| 153 | 157 | ||
| @@ -158,10 +162,12 @@ static inline u16 DISPC_TIMING_V(enum omap_channel channel) | |||
| 158 | return 0x0068; | 162 | return 0x0068; |
| 159 | case OMAP_DSS_CHANNEL_DIGIT: | 163 | case OMAP_DSS_CHANNEL_DIGIT: |
| 160 | BUG(); | 164 | BUG(); |
| 165 | return 0; | ||
| 161 | case OMAP_DSS_CHANNEL_LCD2: | 166 | case OMAP_DSS_CHANNEL_LCD2: |
| 162 | return 0x0404; | 167 | return 0x0404; |
| 163 | default: | 168 | default: |
| 164 | BUG(); | 169 | BUG(); |
| 170 | return 0; | ||
| 165 | } | 171 | } |
| 166 | } | 172 | } |
| 167 | 173 | ||
| @@ -172,10 +178,12 @@ static inline u16 DISPC_POL_FREQ(enum omap_channel channel) | |||
| 172 | return 0x006C; | 178 | return 0x006C; |
| 173 | case OMAP_DSS_CHANNEL_DIGIT: | 179 | case OMAP_DSS_CHANNEL_DIGIT: |
| 174 | BUG(); | 180 | BUG(); |
| 181 | return 0; | ||
| 175 | case OMAP_DSS_CHANNEL_LCD2: | 182 | case OMAP_DSS_CHANNEL_LCD2: |
| 176 | return 0x0408; | 183 | return 0x0408; |
| 177 | default: | 184 | default: |
| 178 | BUG(); | 185 | BUG(); |
| 186 | return 0; | ||
| 179 | } | 187 | } |
| 180 | } | 188 | } |
| 181 | 189 | ||
| @@ -186,10 +194,12 @@ static inline u16 DISPC_DIVISORo(enum omap_channel channel) | |||
| 186 | return 0x0070; | 194 | return 0x0070; |
| 187 | case OMAP_DSS_CHANNEL_DIGIT: | 195 | case OMAP_DSS_CHANNEL_DIGIT: |
| 188 | BUG(); | 196 | BUG(); |
| 197 | return 0; | ||
| 189 | case OMAP_DSS_CHANNEL_LCD2: | 198 | case OMAP_DSS_CHANNEL_LCD2: |
| 190 | return 0x040C; | 199 | return 0x040C; |
| 191 | default: | 200 | default: |
| 192 | BUG(); | 201 | BUG(); |
| 202 | return 0; | ||
| 193 | } | 203 | } |
| 194 | } | 204 | } |
| 195 | 205 | ||
| @@ -205,6 +215,7 @@ static inline u16 DISPC_SIZE_MGR(enum omap_channel channel) | |||
| 205 | return 0x03CC; | 215 | return 0x03CC; |
| 206 | default: | 216 | default: |
| 207 | BUG(); | 217 | BUG(); |
| 218 | return 0; | ||
| 208 | } | 219 | } |
| 209 | } | 220 | } |
| 210 | 221 | ||
| @@ -215,10 +226,12 @@ static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel) | |||
| 215 | return 0x01D4; | 226 | return 0x01D4; |
| 216 | case OMAP_DSS_CHANNEL_DIGIT: | 227 | case OMAP_DSS_CHANNEL_DIGIT: |
| 217 | BUG(); | 228 | BUG(); |
| 229 | return 0; | ||
| 218 | case OMAP_DSS_CHANNEL_LCD2: | 230 | case OMAP_DSS_CHANNEL_LCD2: |
| 219 | return 0x03C0; | 231 | return 0x03C0; |
| 220 | default: | 232 | default: |
| 221 | BUG(); | 233 | BUG(); |
| 234 | return 0; | ||
| 222 | } | 235 | } |
| 223 | } | 236 | } |
| 224 | 237 | ||
| @@ -229,10 +242,12 @@ static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel) | |||
| 229 | return 0x01D8; | 242 | return 0x01D8; |
| 230 | case OMAP_DSS_CHANNEL_DIGIT: | 243 | case OMAP_DSS_CHANNEL_DIGIT: |
| 231 | BUG(); | 244 | BUG(); |
| 245 | return 0; | ||
| 232 | case OMAP_DSS_CHANNEL_LCD2: | 246 | case OMAP_DSS_CHANNEL_LCD2: |
| 233 | return 0x03C4; | 247 | return 0x03C4; |
| 234 | default: | 248 | default: |
| 235 | BUG(); | 249 | BUG(); |
| 250 | return 0; | ||
| 236 | } | 251 | } |
| 237 | } | 252 | } |
| 238 | 253 | ||
| @@ -243,10 +258,12 @@ static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel) | |||
| 243 | return 0x01DC; | 258 | return 0x01DC; |
| 244 | case OMAP_DSS_CHANNEL_DIGIT: | 259 | case OMAP_DSS_CHANNEL_DIGIT: |
| 245 | BUG(); | 260 | BUG(); |
| 261 | return 0; | ||
| 246 | case OMAP_DSS_CHANNEL_LCD2: | 262 | case OMAP_DSS_CHANNEL_LCD2: |
| 247 | return 0x03C8; | 263 | return 0x03C8; |
| 248 | default: | 264 | default: |
| 249 | BUG(); | 265 | BUG(); |
| 266 | return 0; | ||
| 250 | } | 267 | } |
| 251 | } | 268 | } |
| 252 | 269 | ||
| @@ -257,10 +274,12 @@ static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel) | |||
| 257 | return 0x0220; | 274 | return 0x0220; |
| 258 | case OMAP_DSS_CHANNEL_DIGIT: | 275 | case OMAP_DSS_CHANNEL_DIGIT: |
| 259 | BUG(); | 276 | BUG(); |
| 277 | return 0; | ||
| 260 | case OMAP_DSS_CHANNEL_LCD2: | 278 | case OMAP_DSS_CHANNEL_LCD2: |
| 261 | return 0x03BC; | 279 | return 0x03BC; |
| 262 | default: | 280 | default: |
| 263 | BUG(); | 281 | BUG(); |
| 282 | return 0; | ||
| 264 | } | 283 | } |
| 265 | } | 284 | } |
| 266 | 285 | ||
| @@ -271,10 +290,12 @@ static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel) | |||
| 271 | return 0x0224; | 290 | return 0x0224; |
| 272 | case OMAP_DSS_CHANNEL_DIGIT: | 291 | case OMAP_DSS_CHANNEL_DIGIT: |
| 273 | BUG(); | 292 | BUG(); |
| 293 | return 0; | ||
| 274 | case OMAP_DSS_CHANNEL_LCD2: | 294 | case OMAP_DSS_CHANNEL_LCD2: |
| 275 | return 0x03B8; | 295 | return 0x03B8; |
| 276 | default: | 296 | default: |
| 277 | BUG(); | 297 | BUG(); |
| 298 | return 0; | ||
| 278 | } | 299 | } |
| 279 | } | 300 | } |
| 280 | 301 | ||
| @@ -285,10 +306,12 @@ static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel) | |||
| 285 | return 0x0228; | 306 | return 0x0228; |
| 286 | case OMAP_DSS_CHANNEL_DIGIT: | 307 | case OMAP_DSS_CHANNEL_DIGIT: |
| 287 | BUG(); | 308 | BUG(); |
| 309 | return 0; | ||
| 288 | case OMAP_DSS_CHANNEL_LCD2: | 310 | case OMAP_DSS_CHANNEL_LCD2: |
| 289 | return 0x03B4; | 311 | return 0x03B4; |
| 290 | default: | 312 | default: |
| 291 | BUG(); | 313 | BUG(); |
| 314 | return 0; | ||
| 292 | } | 315 | } |
| 293 | } | 316 | } |
| 294 | 317 | ||
| @@ -306,6 +329,7 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) | |||
| 306 | return 0x0300; | 329 | return 0x0300; |
| 307 | default: | 330 | default: |
| 308 | BUG(); | 331 | BUG(); |
| 332 | return 0; | ||
| 309 | } | 333 | } |
| 310 | } | 334 | } |
| 311 | 335 | ||
| @@ -321,6 +345,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) | |||
| 321 | return 0x0008; | 345 | return 0x0008; |
| 322 | default: | 346 | default: |
| 323 | BUG(); | 347 | BUG(); |
| 348 | return 0; | ||
| 324 | } | 349 | } |
| 325 | } | 350 | } |
| 326 | 351 | ||
| @@ -335,6 +360,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) | |||
| 335 | return 0x000C; | 360 | return 0x000C; |
| 336 | default: | 361 | default: |
| 337 | BUG(); | 362 | BUG(); |
| 363 | return 0; | ||
| 338 | } | 364 | } |
| 339 | } | 365 | } |
| 340 | 366 | ||
| @@ -343,6 +369,7 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) | |||
| 343 | switch (plane) { | 369 | switch (plane) { |
| 344 | case OMAP_DSS_GFX: | 370 | case OMAP_DSS_GFX: |
| 345 | BUG(); | 371 | BUG(); |
| 372 | return 0; | ||
| 346 | case OMAP_DSS_VIDEO1: | 373 | case OMAP_DSS_VIDEO1: |
| 347 | return 0x0544; | 374 | return 0x0544; |
| 348 | case OMAP_DSS_VIDEO2: | 375 | case OMAP_DSS_VIDEO2: |
| @@ -351,6 +378,7 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) | |||
| 351 | return 0x0310; | 378 | return 0x0310; |
| 352 | default: | 379 | default: |
| 353 | BUG(); | 380 | BUG(); |
| 381 | return 0; | ||
| 354 | } | 382 | } |
| 355 | } | 383 | } |
| 356 | 384 | ||
| @@ -359,6 +387,7 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) | |||
| 359 | switch (plane) { | 387 | switch (plane) { |
| 360 | case OMAP_DSS_GFX: | 388 | case OMAP_DSS_GFX: |
| 361 | BUG(); | 389 | BUG(); |
| 390 | return 0; | ||
| 362 | case OMAP_DSS_VIDEO1: | 391 | case OMAP_DSS_VIDEO1: |
| 363 | return 0x0548; | 392 | return 0x0548; |
| 364 | case OMAP_DSS_VIDEO2: | 393 | case OMAP_DSS_VIDEO2: |
| @@ -367,6 +396,7 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) | |||
| 367 | return 0x0314; | 396 | return 0x0314; |
| 368 | default: | 397 | default: |
| 369 | BUG(); | 398 | BUG(); |
| 399 | return 0; | ||
| 370 | } | 400 | } |
| 371 | } | 401 | } |
| 372 | 402 | ||
| @@ -381,6 +411,7 @@ static inline u16 DISPC_POS_OFFSET(enum omap_plane plane) | |||
| 381 | return 0x009C; | 411 | return 0x009C; |
| 382 | default: | 412 | default: |
| 383 | BUG(); | 413 | BUG(); |
| 414 | return 0; | ||
| 384 | } | 415 | } |
| 385 | } | 416 | } |
| 386 | 417 | ||
| @@ -395,6 +426,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) | |||
| 395 | return 0x00A8; | 426 | return 0x00A8; |
| 396 | default: | 427 | default: |
| 397 | BUG(); | 428 | BUG(); |
| 429 | return 0; | ||
| 398 | } | 430 | } |
| 399 | } | 431 | } |
| 400 | 432 | ||
| @@ -410,6 +442,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) | |||
| 410 | return 0x0070; | 442 | return 0x0070; |
| 411 | default: | 443 | default: |
| 412 | BUG(); | 444 | BUG(); |
| 445 | return 0; | ||
| 413 | } | 446 | } |
| 414 | } | 447 | } |
| 415 | 448 | ||
| @@ -418,6 +451,7 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) | |||
| 418 | switch (plane) { | 451 | switch (plane) { |
| 419 | case OMAP_DSS_GFX: | 452 | case OMAP_DSS_GFX: |
| 420 | BUG(); | 453 | BUG(); |
| 454 | return 0; | ||
| 421 | case OMAP_DSS_VIDEO1: | 455 | case OMAP_DSS_VIDEO1: |
| 422 | return 0x0568; | 456 | return 0x0568; |
| 423 | case OMAP_DSS_VIDEO2: | 457 | case OMAP_DSS_VIDEO2: |
| @@ -426,6 +460,7 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) | |||
| 426 | return 0x032C; | 460 | return 0x032C; |
| 427 | default: | 461 | default: |
| 428 | BUG(); | 462 | BUG(); |
| 463 | return 0; | ||
| 429 | } | 464 | } |
| 430 | } | 465 | } |
| 431 | 466 | ||
| @@ -441,6 +476,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) | |||
| 441 | return 0x008C; | 476 | return 0x008C; |
| 442 | default: | 477 | default: |
| 443 | BUG(); | 478 | BUG(); |
| 479 | return 0; | ||
| 444 | } | 480 | } |
| 445 | } | 481 | } |
| 446 | 482 | ||
| @@ -456,6 +492,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) | |||
| 456 | return 0x0088; | 492 | return 0x0088; |
| 457 | default: | 493 | default: |
| 458 | BUG(); | 494 | BUG(); |
| 495 | return 0; | ||
| 459 | } | 496 | } |
| 460 | } | 497 | } |
| 461 | 498 | ||
| @@ -471,6 +508,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) | |||
| 471 | return 0x00A4; | 508 | return 0x00A4; |
| 472 | default: | 509 | default: |
| 473 | BUG(); | 510 | BUG(); |
| 511 | return 0; | ||
| 474 | } | 512 | } |
| 475 | } | 513 | } |
| 476 | 514 | ||
| @@ -486,6 +524,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) | |||
| 486 | return 0x0098; | 524 | return 0x0098; |
| 487 | default: | 525 | default: |
| 488 | BUG(); | 526 | BUG(); |
| 527 | return 0; | ||
| 489 | } | 528 | } |
| 490 | } | 529 | } |
| 491 | 530 | ||
| @@ -498,8 +537,10 @@ static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane) | |||
| 498 | case OMAP_DSS_VIDEO2: | 537 | case OMAP_DSS_VIDEO2: |
| 499 | case OMAP_DSS_VIDEO3: | 538 | case OMAP_DSS_VIDEO3: |
| 500 | BUG(); | 539 | BUG(); |
| 540 | return 0; | ||
| 501 | default: | 541 | default: |
| 502 | BUG(); | 542 | BUG(); |
| 543 | return 0; | ||
| 503 | } | 544 | } |
| 504 | } | 545 | } |
| 505 | 546 | ||
| @@ -512,8 +553,10 @@ static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane) | |||
| 512 | case OMAP_DSS_VIDEO2: | 553 | case OMAP_DSS_VIDEO2: |
| 513 | case OMAP_DSS_VIDEO3: | 554 | case OMAP_DSS_VIDEO3: |
| 514 | BUG(); | 555 | BUG(); |
| 556 | return 0; | ||
| 515 | default: | 557 | default: |
| 516 | BUG(); | 558 | BUG(); |
| 559 | return 0; | ||
| 517 | } | 560 | } |
| 518 | } | 561 | } |
| 519 | 562 | ||
| @@ -522,6 +565,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) | |||
| 522 | switch (plane) { | 565 | switch (plane) { |
| 523 | case OMAP_DSS_GFX: | 566 | case OMAP_DSS_GFX: |
| 524 | BUG(); | 567 | BUG(); |
| 568 | return 0; | ||
| 525 | case OMAP_DSS_VIDEO1: | 569 | case OMAP_DSS_VIDEO1: |
| 526 | case OMAP_DSS_VIDEO2: | 570 | case OMAP_DSS_VIDEO2: |
| 527 | return 0x0024; | 571 | return 0x0024; |
| @@ -529,6 +573,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) | |||
| 529 | return 0x0090; | 573 | return 0x0090; |
| 530 | default: | 574 | default: |
| 531 | BUG(); | 575 | BUG(); |
| 576 | return 0; | ||
| 532 | } | 577 | } |
| 533 | } | 578 | } |
| 534 | 579 | ||
| @@ -537,6 +582,7 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) | |||
| 537 | switch (plane) { | 582 | switch (plane) { |
| 538 | case OMAP_DSS_GFX: | 583 | case OMAP_DSS_GFX: |
| 539 | BUG(); | 584 | BUG(); |
| 585 | return 0; | ||
| 540 | case OMAP_DSS_VIDEO1: | 586 | case OMAP_DSS_VIDEO1: |
| 541 | return 0x0580; | 587 | return 0x0580; |
| 542 | case OMAP_DSS_VIDEO2: | 588 | case OMAP_DSS_VIDEO2: |
| @@ -545,6 +591,7 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) | |||
| 545 | return 0x0424; | 591 | return 0x0424; |
| 546 | default: | 592 | default: |
| 547 | BUG(); | 593 | BUG(); |
| 594 | return 0; | ||
| 548 | } | 595 | } |
| 549 | } | 596 | } |
| 550 | 597 | ||
| @@ -553,6 +600,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) | |||
| 553 | switch (plane) { | 600 | switch (plane) { |
| 554 | case OMAP_DSS_GFX: | 601 | case OMAP_DSS_GFX: |
| 555 | BUG(); | 602 | BUG(); |
| 603 | return 0; | ||
| 556 | case OMAP_DSS_VIDEO1: | 604 | case OMAP_DSS_VIDEO1: |
| 557 | case OMAP_DSS_VIDEO2: | 605 | case OMAP_DSS_VIDEO2: |
| 558 | return 0x0028; | 606 | return 0x0028; |
| @@ -560,6 +608,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) | |||
| 560 | return 0x0094; | 608 | return 0x0094; |
| 561 | default: | 609 | default: |
| 562 | BUG(); | 610 | BUG(); |
| 611 | return 0; | ||
| 563 | } | 612 | } |
| 564 | } | 613 | } |
| 565 | 614 | ||
| @@ -569,6 +618,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) | |||
| 569 | switch (plane) { | 618 | switch (plane) { |
| 570 | case OMAP_DSS_GFX: | 619 | case OMAP_DSS_GFX: |
| 571 | BUG(); | 620 | BUG(); |
| 621 | return 0; | ||
| 572 | case OMAP_DSS_VIDEO1: | 622 | case OMAP_DSS_VIDEO1: |
| 573 | case OMAP_DSS_VIDEO2: | 623 | case OMAP_DSS_VIDEO2: |
| 574 | return 0x002C; | 624 | return 0x002C; |
| @@ -576,6 +626,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) | |||
| 576 | return 0x0000; | 626 | return 0x0000; |
| 577 | default: | 627 | default: |
| 578 | BUG(); | 628 | BUG(); |
| 629 | return 0; | ||
| 579 | } | 630 | } |
| 580 | } | 631 | } |
| 581 | 632 | ||
| @@ -584,6 +635,7 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) | |||
| 584 | switch (plane) { | 635 | switch (plane) { |
| 585 | case OMAP_DSS_GFX: | 636 | case OMAP_DSS_GFX: |
| 586 | BUG(); | 637 | BUG(); |
| 638 | return 0; | ||
| 587 | case OMAP_DSS_VIDEO1: | 639 | case OMAP_DSS_VIDEO1: |
| 588 | return 0x0584; | 640 | return 0x0584; |
| 589 | case OMAP_DSS_VIDEO2: | 641 | case OMAP_DSS_VIDEO2: |
| @@ -592,6 +644,7 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) | |||
| 592 | return 0x0428; | 644 | return 0x0428; |
| 593 | default: | 645 | default: |
| 594 | BUG(); | 646 | BUG(); |
| 647 | return 0; | ||
| 595 | } | 648 | } |
| 596 | } | 649 | } |
| 597 | 650 | ||
| @@ -600,6 +653,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) | |||
| 600 | switch (plane) { | 653 | switch (plane) { |
| 601 | case OMAP_DSS_GFX: | 654 | case OMAP_DSS_GFX: |
| 602 | BUG(); | 655 | BUG(); |
| 656 | return 0; | ||
| 603 | case OMAP_DSS_VIDEO1: | 657 | case OMAP_DSS_VIDEO1: |
| 604 | case OMAP_DSS_VIDEO2: | 658 | case OMAP_DSS_VIDEO2: |
| 605 | return 0x0030; | 659 | return 0x0030; |
| @@ -607,6 +661,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) | |||
| 607 | return 0x0004; | 661 | return 0x0004; |
| 608 | default: | 662 | default: |
| 609 | BUG(); | 663 | BUG(); |
| 664 | return 0; | ||
| 610 | } | 665 | } |
| 611 | } | 666 | } |
| 612 | 667 | ||
| @@ -615,6 +670,7 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) | |||
| 615 | switch (plane) { | 670 | switch (plane) { |
| 616 | case OMAP_DSS_GFX: | 671 | case OMAP_DSS_GFX: |
| 617 | BUG(); | 672 | BUG(); |
| 673 | return 0; | ||
| 618 | case OMAP_DSS_VIDEO1: | 674 | case OMAP_DSS_VIDEO1: |
| 619 | return 0x0588; | 675 | return 0x0588; |
| 620 | case OMAP_DSS_VIDEO2: | 676 | case OMAP_DSS_VIDEO2: |
| @@ -623,6 +679,7 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) | |||
| 623 | return 0x042C; | 679 | return 0x042C; |
| 624 | default: | 680 | default: |
| 625 | BUG(); | 681 | BUG(); |
| 682 | return 0; | ||
| 626 | } | 683 | } |
| 627 | } | 684 | } |
| 628 | 685 | ||
| @@ -632,6 +689,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) | |||
| 632 | switch (plane) { | 689 | switch (plane) { |
| 633 | case OMAP_DSS_GFX: | 690 | case OMAP_DSS_GFX: |
| 634 | BUG(); | 691 | BUG(); |
| 692 | return 0; | ||
| 635 | case OMAP_DSS_VIDEO1: | 693 | case OMAP_DSS_VIDEO1: |
| 636 | case OMAP_DSS_VIDEO2: | 694 | case OMAP_DSS_VIDEO2: |
| 637 | return 0x0034 + i * 0x8; | 695 | return 0x0034 + i * 0x8; |
| @@ -639,6 +697,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) | |||
| 639 | return 0x0010 + i * 0x8; | 697 | return 0x0010 + i * 0x8; |
| 640 | default: | 698 | default: |
| 641 | BUG(); | 699 | BUG(); |
| 700 | return 0; | ||
| 642 | } | 701 | } |
| 643 | } | 702 | } |
| 644 | 703 | ||
| @@ -648,6 +707,7 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) | |||
| 648 | switch (plane) { | 707 | switch (plane) { |
| 649 | case OMAP_DSS_GFX: | 708 | case OMAP_DSS_GFX: |
| 650 | BUG(); | 709 | BUG(); |
| 710 | return 0; | ||
| 651 | case OMAP_DSS_VIDEO1: | 711 | case OMAP_DSS_VIDEO1: |
| 652 | return 0x058C + i * 0x8; | 712 | return 0x058C + i * 0x8; |
| 653 | case OMAP_DSS_VIDEO2: | 713 | case OMAP_DSS_VIDEO2: |
| @@ -656,6 +716,7 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) | |||
| 656 | return 0x0430 + i * 0x8; | 716 | return 0x0430 + i * 0x8; |
| 657 | default: | 717 | default: |
| 658 | BUG(); | 718 | BUG(); |
| 719 | return 0; | ||
| 659 | } | 720 | } |
| 660 | } | 721 | } |
| 661 | 722 | ||
| @@ -665,6 +726,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) | |||
| 665 | switch (plane) { | 726 | switch (plane) { |
| 666 | case OMAP_DSS_GFX: | 727 | case OMAP_DSS_GFX: |
| 667 | BUG(); | 728 | BUG(); |
| 729 | return 0; | ||
| 668 | case OMAP_DSS_VIDEO1: | 730 | case OMAP_DSS_VIDEO1: |
| 669 | case OMAP_DSS_VIDEO2: | 731 | case OMAP_DSS_VIDEO2: |
| 670 | return 0x0038 + i * 0x8; | 732 | return 0x0038 + i * 0x8; |
| @@ -672,6 +734,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) | |||
| 672 | return 0x0014 + i * 0x8; | 734 | return 0x0014 + i * 0x8; |
| 673 | default: | 735 | default: |
| 674 | BUG(); | 736 | BUG(); |
| 737 | return 0; | ||
| 675 | } | 738 | } |
| 676 | } | 739 | } |
| 677 | 740 | ||
| @@ -681,6 +744,7 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) | |||
| 681 | switch (plane) { | 744 | switch (plane) { |
| 682 | case OMAP_DSS_GFX: | 745 | case OMAP_DSS_GFX: |
| 683 | BUG(); | 746 | BUG(); |
| 747 | return 0; | ||
| 684 | case OMAP_DSS_VIDEO1: | 748 | case OMAP_DSS_VIDEO1: |
| 685 | return 0x0590 + i * 8; | 749 | return 0x0590 + i * 8; |
| 686 | case OMAP_DSS_VIDEO2: | 750 | case OMAP_DSS_VIDEO2: |
| @@ -689,6 +753,7 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) | |||
| 689 | return 0x0434 + i * 0x8; | 753 | return 0x0434 + i * 0x8; |
| 690 | default: | 754 | default: |
| 691 | BUG(); | 755 | BUG(); |
| 756 | return 0; | ||
| 692 | } | 757 | } |
| 693 | } | 758 | } |
| 694 | 759 | ||
| @@ -698,12 +763,14 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) | |||
| 698 | switch (plane) { | 763 | switch (plane) { |
| 699 | case OMAP_DSS_GFX: | 764 | case OMAP_DSS_GFX: |
| 700 | BUG(); | 765 | BUG(); |
| 766 | return 0; | ||
| 701 | case OMAP_DSS_VIDEO1: | 767 | case OMAP_DSS_VIDEO1: |
| 702 | case OMAP_DSS_VIDEO2: | 768 | case OMAP_DSS_VIDEO2: |
| 703 | case OMAP_DSS_VIDEO3: | 769 | case OMAP_DSS_VIDEO3: |
| 704 | return 0x0074 + i * 0x4; | 770 | return 0x0074 + i * 0x4; |
| 705 | default: | 771 | default: |
| 706 | BUG(); | 772 | BUG(); |
| 773 | return 0; | ||
| 707 | } | 774 | } |
| 708 | } | 775 | } |
| 709 | 776 | ||
| @@ -713,6 +780,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) | |||
| 713 | switch (plane) { | 780 | switch (plane) { |
| 714 | case OMAP_DSS_GFX: | 781 | case OMAP_DSS_GFX: |
| 715 | BUG(); | 782 | BUG(); |
| 783 | return 0; | ||
| 716 | case OMAP_DSS_VIDEO1: | 784 | case OMAP_DSS_VIDEO1: |
| 717 | return 0x0124 + i * 0x4; | 785 | return 0x0124 + i * 0x4; |
| 718 | case OMAP_DSS_VIDEO2: | 786 | case OMAP_DSS_VIDEO2: |
| @@ -721,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) | |||
| 721 | return 0x0050 + i * 0x4; | 789 | return 0x0050 + i * 0x4; |
| 722 | default: | 790 | default: |
| 723 | BUG(); | 791 | BUG(); |
| 792 | return 0; | ||
| 724 | } | 793 | } |
| 725 | } | 794 | } |
| 726 | 795 | ||
| @@ -730,6 +799,7 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) | |||
| 730 | switch (plane) { | 799 | switch (plane) { |
| 731 | case OMAP_DSS_GFX: | 800 | case OMAP_DSS_GFX: |
| 732 | BUG(); | 801 | BUG(); |
| 802 | return 0; | ||
| 733 | case OMAP_DSS_VIDEO1: | 803 | case OMAP_DSS_VIDEO1: |
| 734 | return 0x05CC + i * 0x4; | 804 | return 0x05CC + i * 0x4; |
| 735 | case OMAP_DSS_VIDEO2: | 805 | case OMAP_DSS_VIDEO2: |
| @@ -738,6 +808,7 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) | |||
| 738 | return 0x0470 + i * 0x4; | 808 | return 0x0470 + i * 0x4; |
| 739 | default: | 809 | default: |
| 740 | BUG(); | 810 | BUG(); |
| 811 | return 0; | ||
| 741 | } | 812 | } |
| 742 | } | 813 | } |
| 743 | 814 | ||
| @@ -754,6 +825,7 @@ static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane) | |||
| 754 | return 0x00A0; | 825 | return 0x00A0; |
| 755 | default: | 826 | default: |
| 756 | BUG(); | 827 | BUG(); |
| 828 | return 0; | ||
| 757 | } | 829 | } |
| 758 | } | 830 | } |
| 759 | #endif | 831 | #endif |
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 4424c198dbcd..249010630370 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
| @@ -304,10 +304,18 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | |||
| 304 | return 24; | 304 | return 24; |
| 305 | default: | 305 | default: |
| 306 | BUG(); | 306 | BUG(); |
| 307 | return 0; | ||
| 307 | } | 308 | } |
| 308 | } | 309 | } |
| 309 | EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); | 310 | EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); |
| 310 | 311 | ||
| 312 | void omapdss_default_get_timings(struct omap_dss_device *dssdev, | ||
| 313 | struct omap_video_timings *timings) | ||
| 314 | { | ||
| 315 | *timings = dssdev->panel.timings; | ||
| 316 | } | ||
| 317 | EXPORT_SYMBOL(omapdss_default_get_timings); | ||
| 318 | |||
| 311 | /* Checks if replication logic should be used. Only use for active matrix, | 319 | /* Checks if replication logic should be used. Only use for active matrix, |
| 312 | * when overlay is in RGB12U or RGB16 mode, and LCD interface is | 320 | * when overlay is in RGB12U or RGB16 mode, and LCD interface is |
| 313 | * 18bpp or 24bpp */ | 321 | * 18bpp or 24bpp */ |
| @@ -340,6 +348,7 @@ bool dss_use_replication(struct omap_dss_device *dssdev, | |||
| 340 | break; | 348 | break; |
| 341 | default: | 349 | default: |
| 342 | BUG(); | 350 | BUG(); |
| 351 | return false; | ||
| 343 | } | 352 | } |
| 344 | 353 | ||
| 345 | return bpp > 16; | 354 | return bpp > 16; |
| @@ -352,46 +361,6 @@ void dss_init_device(struct platform_device *pdev, | |||
| 352 | int i; | 361 | int i; |
| 353 | int r; | 362 | int r; |
| 354 | 363 | ||
| 355 | switch (dssdev->type) { | ||
| 356 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
| 357 | case OMAP_DISPLAY_TYPE_DPI: | ||
| 358 | r = dpi_init_display(dssdev); | ||
| 359 | break; | ||
| 360 | #endif | ||
| 361 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
| 362 | case OMAP_DISPLAY_TYPE_DBI: | ||
| 363 | r = rfbi_init_display(dssdev); | ||
| 364 | break; | ||
| 365 | #endif | ||
| 366 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
| 367 | case OMAP_DISPLAY_TYPE_VENC: | ||
| 368 | r = venc_init_display(dssdev); | ||
| 369 | break; | ||
| 370 | #endif | ||
| 371 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
| 372 | case OMAP_DISPLAY_TYPE_SDI: | ||
| 373 | r = sdi_init_display(dssdev); | ||
| 374 | break; | ||
| 375 | #endif | ||
| 376 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 377 | case OMAP_DISPLAY_TYPE_DSI: | ||
| 378 | r = dsi_init_display(dssdev); | ||
| 379 | break; | ||
| 380 | #endif | ||
| 381 | case OMAP_DISPLAY_TYPE_HDMI: | ||
| 382 | r = hdmi_init_display(dssdev); | ||
| 383 | break; | ||
| 384 | default: | ||
| 385 | DSSERR("Support for display '%s' not compiled in.\n", | ||
| 386 | dssdev->name); | ||
| 387 | return; | ||
| 388 | } | ||
| 389 | |||
| 390 | if (r) { | ||
| 391 | DSSERR("failed to init display %s\n", dssdev->name); | ||
| 392 | return; | ||
| 393 | } | ||
| 394 | |||
| 395 | /* create device sysfs files */ | 364 | /* create device sysfs files */ |
| 396 | i = 0; | 365 | i = 0; |
| 397 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | 366 | while ((attr = display_sysfs_attrs[i++]) != NULL) { |
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index faaf305fda27..8c2056c9537b 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
| @@ -156,7 +156,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) | |||
| 156 | t->pixel_clock = pck; | 156 | t->pixel_clock = pck; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | dispc_mgr_set_lcd_timings(dssdev->manager->id, t); | 159 | dss_mgr_set_timings(dssdev->manager, t); |
| 160 | 160 | ||
| 161 | return 0; | 161 | return 0; |
| 162 | } | 162 | } |
| @@ -202,10 +202,6 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
| 202 | goto err_reg_enable; | 202 | goto err_reg_enable; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | r = dss_runtime_get(); | ||
| 206 | if (r) | ||
| 207 | goto err_get_dss; | ||
| 208 | |||
| 209 | r = dispc_runtime_get(); | 205 | r = dispc_runtime_get(); |
| 210 | if (r) | 206 | if (r) |
| 211 | goto err_get_dispc; | 207 | goto err_get_dispc; |
| @@ -244,8 +240,6 @@ err_dsi_pll_init: | |||
| 244 | err_get_dsi: | 240 | err_get_dsi: |
| 245 | dispc_runtime_put(); | 241 | dispc_runtime_put(); |
| 246 | err_get_dispc: | 242 | err_get_dispc: |
| 247 | dss_runtime_put(); | ||
| 248 | err_get_dss: | ||
| 249 | if (cpu_is_omap34xx()) | 243 | if (cpu_is_omap34xx()) |
| 250 | regulator_disable(dpi.vdds_dsi_reg); | 244 | regulator_disable(dpi.vdds_dsi_reg); |
| 251 | err_reg_enable: | 245 | err_reg_enable: |
| @@ -266,7 +260,6 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | |||
| 266 | } | 260 | } |
| 267 | 261 | ||
| 268 | dispc_runtime_put(); | 262 | dispc_runtime_put(); |
| 269 | dss_runtime_put(); | ||
| 270 | 263 | ||
| 271 | if (cpu_is_omap34xx()) | 264 | if (cpu_is_omap34xx()) |
| 272 | regulator_disable(dpi.vdds_dsi_reg); | 265 | regulator_disable(dpi.vdds_dsi_reg); |
| @@ -283,21 +276,15 @@ void dpi_set_timings(struct omap_dss_device *dssdev, | |||
| 283 | DSSDBG("dpi_set_timings\n"); | 276 | DSSDBG("dpi_set_timings\n"); |
| 284 | dssdev->panel.timings = *timings; | 277 | dssdev->panel.timings = *timings; |
| 285 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | 278 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { |
| 286 | r = dss_runtime_get(); | ||
| 287 | if (r) | ||
| 288 | return; | ||
| 289 | |||
| 290 | r = dispc_runtime_get(); | 279 | r = dispc_runtime_get(); |
| 291 | if (r) { | 280 | if (r) |
| 292 | dss_runtime_put(); | ||
| 293 | return; | 281 | return; |
| 294 | } | ||
| 295 | 282 | ||
| 296 | dpi_set_mode(dssdev); | 283 | dpi_set_mode(dssdev); |
| 297 | dispc_mgr_go(dssdev->manager->id); | ||
| 298 | 284 | ||
| 299 | dispc_runtime_put(); | 285 | dispc_runtime_put(); |
| 300 | dss_runtime_put(); | 286 | } else { |
| 287 | dss_mgr_set_timings(dssdev->manager, timings); | ||
| 301 | } | 288 | } |
| 302 | } | 289 | } |
| 303 | EXPORT_SYMBOL(dpi_set_timings); | 290 | EXPORT_SYMBOL(dpi_set_timings); |
| @@ -312,7 +299,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
| 312 | unsigned long pck; | 299 | unsigned long pck; |
| 313 | struct dispc_clock_info dispc_cinfo; | 300 | struct dispc_clock_info dispc_cinfo; |
| 314 | 301 | ||
| 315 | if (!dispc_lcd_timings_ok(timings)) | 302 | if (dss_mgr_check_timings(dssdev->manager, timings)) |
| 316 | return -EINVAL; | 303 | return -EINVAL; |
| 317 | 304 | ||
| 318 | if (timings->pixel_clock == 0) | 305 | if (timings->pixel_clock == 0) |
| @@ -352,7 +339,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
| 352 | } | 339 | } |
| 353 | EXPORT_SYMBOL(dpi_check_timings); | 340 | EXPORT_SYMBOL(dpi_check_timings); |
| 354 | 341 | ||
| 355 | int dpi_init_display(struct omap_dss_device *dssdev) | 342 | static int __init dpi_init_display(struct omap_dss_device *dssdev) |
| 356 | { | 343 | { |
| 357 | DSSDBG("init_display\n"); | 344 | DSSDBG("init_display\n"); |
| 358 | 345 | ||
| @@ -378,12 +365,58 @@ int dpi_init_display(struct omap_dss_device *dssdev) | |||
| 378 | return 0; | 365 | return 0; |
| 379 | } | 366 | } |
| 380 | 367 | ||
| 381 | int dpi_init(void) | 368 | static void __init dpi_probe_pdata(struct platform_device *pdev) |
| 382 | { | 369 | { |
| 370 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 371 | int i, r; | ||
| 372 | |||
| 373 | for (i = 0; i < pdata->num_devices; ++i) { | ||
| 374 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
| 375 | |||
| 376 | if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) | ||
| 377 | continue; | ||
| 378 | |||
| 379 | r = dpi_init_display(dssdev); | ||
| 380 | if (r) { | ||
| 381 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
| 382 | continue; | ||
| 383 | } | ||
| 384 | |||
| 385 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | ||
| 386 | if (r) | ||
| 387 | DSSERR("device %s register failed: %d\n", | ||
| 388 | dssdev->name, r); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | static int __init omap_dpi_probe(struct platform_device *pdev) | ||
| 393 | { | ||
| 394 | dpi_probe_pdata(pdev); | ||
| 395 | |||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int __exit omap_dpi_remove(struct platform_device *pdev) | ||
| 400 | { | ||
| 401 | omap_dss_unregister_child_devices(&pdev->dev); | ||
| 402 | |||
| 383 | return 0; | 403 | return 0; |
| 384 | } | 404 | } |
| 385 | 405 | ||
| 386 | void dpi_exit(void) | 406 | static struct platform_driver omap_dpi_driver = { |
| 407 | .remove = __exit_p(omap_dpi_remove), | ||
| 408 | .driver = { | ||
| 409 | .name = "omapdss_dpi", | ||
| 410 | .owner = THIS_MODULE, | ||
| 411 | }, | ||
| 412 | }; | ||
| 413 | |||
| 414 | int __init dpi_init_platform_driver(void) | ||
| 387 | { | 415 | { |
| 416 | return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe); | ||
| 388 | } | 417 | } |
| 389 | 418 | ||
| 419 | void __exit dpi_uninit_platform_driver(void) | ||
| 420 | { | ||
| 421 | platform_driver_unregister(&omap_dpi_driver); | ||
| 422 | } | ||
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 210a3c4f6150..ec363d8390ed 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
| @@ -256,14 +256,13 @@ struct dsi_data { | |||
| 256 | struct platform_device *pdev; | 256 | struct platform_device *pdev; |
| 257 | void __iomem *base; | 257 | void __iomem *base; |
| 258 | 258 | ||
| 259 | int module_id; | ||
| 260 | |||
| 259 | int irq; | 261 | int irq; |
| 260 | 262 | ||
| 261 | struct clk *dss_clk; | 263 | struct clk *dss_clk; |
| 262 | struct clk *sys_clk; | 264 | struct clk *sys_clk; |
| 263 | 265 | ||
| 264 | int (*enable_pads)(int dsi_id, unsigned lane_mask); | ||
| 265 | void (*disable_pads)(int dsi_id, unsigned lane_mask); | ||
| 266 | |||
| 267 | struct dsi_clock_info current_cinfo; | 266 | struct dsi_clock_info current_cinfo; |
| 268 | 267 | ||
| 269 | bool vdds_dsi_enabled; | 268 | bool vdds_dsi_enabled; |
| @@ -361,11 +360,6 @@ struct platform_device *dsi_get_dsidev_from_id(int module) | |||
| 361 | return dsi_pdev_map[module]; | 360 | return dsi_pdev_map[module]; |
| 362 | } | 361 | } |
| 363 | 362 | ||
| 364 | static inline int dsi_get_dsidev_id(struct platform_device *dsidev) | ||
| 365 | { | ||
| 366 | return dsidev->id; | ||
| 367 | } | ||
| 368 | |||
| 369 | static inline void dsi_write_reg(struct platform_device *dsidev, | 363 | static inline void dsi_write_reg(struct platform_device *dsidev, |
| 370 | const struct dsi_reg idx, u32 val) | 364 | const struct dsi_reg idx, u32 val) |
| 371 | { | 365 | { |
| @@ -452,6 +446,7 @@ u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) | |||
| 452 | return 16; | 446 | return 16; |
| 453 | default: | 447 | default: |
| 454 | BUG(); | 448 | BUG(); |
| 449 | return 0; | ||
| 455 | } | 450 | } |
| 456 | } | 451 | } |
| 457 | 452 | ||
| @@ -1184,10 +1179,9 @@ static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) | |||
| 1184 | static unsigned long dsi_fclk_rate(struct platform_device *dsidev) | 1179 | static unsigned long dsi_fclk_rate(struct platform_device *dsidev) |
| 1185 | { | 1180 | { |
| 1186 | unsigned long r; | 1181 | unsigned long r; |
| 1187 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
| 1188 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1182 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1189 | 1183 | ||
| 1190 | if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { | 1184 | if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) { |
| 1191 | /* DSI FCLK source is DSS_CLK_FCK */ | 1185 | /* DSI FCLK source is DSS_CLK_FCK */ |
| 1192 | r = clk_get_rate(dsi->dss_clk); | 1186 | r = clk_get_rate(dsi->dss_clk); |
| 1193 | } else { | 1187 | } else { |
| @@ -1279,10 +1273,9 @@ static int dsi_pll_power(struct platform_device *dsidev, | |||
| 1279 | } | 1273 | } |
| 1280 | 1274 | ||
| 1281 | /* calculate clock rates using dividers in cinfo */ | 1275 | /* calculate clock rates using dividers in cinfo */ |
| 1282 | static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, | 1276 | static int dsi_calc_clock_rates(struct platform_device *dsidev, |
| 1283 | struct dsi_clock_info *cinfo) | 1277 | struct dsi_clock_info *cinfo) |
| 1284 | { | 1278 | { |
| 1285 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
| 1286 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1279 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1287 | 1280 | ||
| 1288 | if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max) | 1281 | if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max) |
| @@ -1297,21 +1290,8 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, | |||
| 1297 | if (cinfo->regm_dsi > dsi->regm_dsi_max) | 1290 | if (cinfo->regm_dsi > dsi->regm_dsi_max) |
| 1298 | return -EINVAL; | 1291 | return -EINVAL; |
| 1299 | 1292 | ||
| 1300 | if (cinfo->use_sys_clk) { | 1293 | cinfo->clkin = clk_get_rate(dsi->sys_clk); |
| 1301 | cinfo->clkin = clk_get_rate(dsi->sys_clk); | 1294 | cinfo->fint = cinfo->clkin / cinfo->regn; |
| 1302 | /* XXX it is unclear if highfreq should be used | ||
| 1303 | * with DSS_SYS_CLK source also */ | ||
| 1304 | cinfo->highfreq = 0; | ||
| 1305 | } else { | ||
| 1306 | cinfo->clkin = dispc_mgr_pclk_rate(dssdev->manager->id); | ||
| 1307 | |||
| 1308 | if (cinfo->clkin < 32000000) | ||
| 1309 | cinfo->highfreq = 0; | ||
| 1310 | else | ||
| 1311 | cinfo->highfreq = 1; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1)); | ||
| 1315 | 1295 | ||
| 1316 | if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min) | 1296 | if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min) |
| 1317 | return -EINVAL; | 1297 | return -EINVAL; |
| @@ -1378,27 +1358,21 @@ retry: | |||
| 1378 | 1358 | ||
| 1379 | memset(&cur, 0, sizeof(cur)); | 1359 | memset(&cur, 0, sizeof(cur)); |
| 1380 | cur.clkin = dss_sys_clk; | 1360 | cur.clkin = dss_sys_clk; |
| 1381 | cur.use_sys_clk = 1; | ||
| 1382 | cur.highfreq = 0; | ||
| 1383 | 1361 | ||
| 1384 | /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ | 1362 | /* 0.75MHz < Fint = clkin / regn < 2.1MHz */ |
| 1385 | /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ | ||
| 1386 | /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ | 1363 | /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ |
| 1387 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { | 1364 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { |
| 1388 | if (cur.highfreq == 0) | 1365 | cur.fint = cur.clkin / cur.regn; |
| 1389 | cur.fint = cur.clkin / cur.regn; | ||
| 1390 | else | ||
| 1391 | cur.fint = cur.clkin / (2 * cur.regn); | ||
| 1392 | 1366 | ||
| 1393 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) | 1367 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) |
| 1394 | continue; | 1368 | continue; |
| 1395 | 1369 | ||
| 1396 | /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ | 1370 | /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ |
| 1397 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { | 1371 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { |
| 1398 | unsigned long a, b; | 1372 | unsigned long a, b; |
| 1399 | 1373 | ||
| 1400 | a = 2 * cur.regm * (cur.clkin/1000); | 1374 | a = 2 * cur.regm * (cur.clkin/1000); |
| 1401 | b = cur.regn * (cur.highfreq + 1); | 1375 | b = cur.regn; |
| 1402 | cur.clkin4ddr = a / b * 1000; | 1376 | cur.clkin4ddr = a / b * 1000; |
| 1403 | 1377 | ||
| 1404 | if (cur.clkin4ddr > 1800 * 1000 * 1000) | 1378 | if (cur.clkin4ddr > 1800 * 1000 * 1000) |
| @@ -1486,9 +1460,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
| 1486 | 1460 | ||
| 1487 | DSSDBGF(); | 1461 | DSSDBGF(); |
| 1488 | 1462 | ||
| 1489 | dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk; | 1463 | dsi->current_cinfo.clkin = cinfo->clkin; |
| 1490 | dsi->current_cinfo.highfreq = cinfo->highfreq; | ||
| 1491 | |||
| 1492 | dsi->current_cinfo.fint = cinfo->fint; | 1464 | dsi->current_cinfo.fint = cinfo->fint; |
| 1493 | dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr; | 1465 | dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr; |
| 1494 | dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk = | 1466 | dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk = |
| @@ -1503,17 +1475,13 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
| 1503 | 1475 | ||
| 1504 | DSSDBG("DSI Fint %ld\n", cinfo->fint); | 1476 | DSSDBG("DSI Fint %ld\n", cinfo->fint); |
| 1505 | 1477 | ||
| 1506 | DSSDBG("clkin (%s) rate %ld, highfreq %d\n", | 1478 | DSSDBG("clkin rate %ld\n", cinfo->clkin); |
| 1507 | cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree", | ||
| 1508 | cinfo->clkin, | ||
| 1509 | cinfo->highfreq); | ||
| 1510 | 1479 | ||
| 1511 | /* DSIPHY == CLKIN4DDR */ | 1480 | /* DSIPHY == CLKIN4DDR */ |
| 1512 | DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n", | 1481 | DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n", |
| 1513 | cinfo->regm, | 1482 | cinfo->regm, |
| 1514 | cinfo->regn, | 1483 | cinfo->regn, |
| 1515 | cinfo->clkin, | 1484 | cinfo->clkin, |
| 1516 | cinfo->highfreq + 1, | ||
| 1517 | cinfo->clkin4ddr); | 1485 | cinfo->clkin4ddr); |
| 1518 | 1486 | ||
| 1519 | DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", | 1487 | DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", |
| @@ -1568,10 +1536,6 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
| 1568 | 1536 | ||
| 1569 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) | 1537 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) |
| 1570 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ | 1538 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ |
| 1571 | l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1, | ||
| 1572 | 11, 11); /* DSI_PLL_CLKSEL */ | ||
| 1573 | l = FLD_MOD(l, cinfo->highfreq, | ||
| 1574 | 12, 12); /* DSI_PLL_HIGHFREQ */ | ||
| 1575 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ | 1539 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ |
| 1576 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ | 1540 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ |
| 1577 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ | 1541 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ |
| @@ -1716,7 +1680,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
| 1716 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1680 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1717 | struct dsi_clock_info *cinfo = &dsi->current_cinfo; | 1681 | struct dsi_clock_info *cinfo = &dsi->current_cinfo; |
| 1718 | enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; | 1682 | enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; |
| 1719 | int dsi_module = dsi_get_dsidev_id(dsidev); | 1683 | int dsi_module = dsi->module_id; |
| 1720 | 1684 | ||
| 1721 | dispc_clk_src = dss_get_dispc_clk_source(); | 1685 | dispc_clk_src = dss_get_dispc_clk_source(); |
| 1722 | dsi_clk_src = dss_get_dsi_clk_source(dsi_module); | 1686 | dsi_clk_src = dss_get_dsi_clk_source(dsi_module); |
| @@ -1726,8 +1690,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
| 1726 | 1690 | ||
| 1727 | seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); | 1691 | seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); |
| 1728 | 1692 | ||
| 1729 | seq_printf(s, "dsi pll source = %s\n", | 1693 | seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin); |
| 1730 | cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree"); | ||
| 1731 | 1694 | ||
| 1732 | seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); | 1695 | seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); |
| 1733 | 1696 | ||
| @@ -1789,7 +1752,6 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, | |||
| 1789 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1752 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1790 | unsigned long flags; | 1753 | unsigned long flags; |
| 1791 | struct dsi_irq_stats stats; | 1754 | struct dsi_irq_stats stats; |
| 1792 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
| 1793 | 1755 | ||
| 1794 | spin_lock_irqsave(&dsi->irq_stats_lock, flags); | 1756 | spin_lock_irqsave(&dsi->irq_stats_lock, flags); |
| 1795 | 1757 | ||
| @@ -1806,7 +1768,7 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, | |||
| 1806 | #define PIS(x) \ | 1768 | #define PIS(x) \ |
| 1807 | seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); | 1769 | seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); |
| 1808 | 1770 | ||
| 1809 | seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1); | 1771 | seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1); |
| 1810 | PIS(VC0); | 1772 | PIS(VC0); |
| 1811 | PIS(VC1); | 1773 | PIS(VC1); |
| 1812 | PIS(VC2); | 1774 | PIS(VC2); |
| @@ -1886,22 +1848,6 @@ static void dsi2_dump_irqs(struct seq_file *s) | |||
| 1886 | 1848 | ||
| 1887 | dsi_dump_dsidev_irqs(dsidev, s); | 1849 | dsi_dump_dsidev_irqs(dsidev, s); |
| 1888 | } | 1850 | } |
| 1889 | |||
| 1890 | void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, | ||
| 1891 | const struct file_operations *debug_fops) | ||
| 1892 | { | ||
| 1893 | struct platform_device *dsidev; | ||
| 1894 | |||
| 1895 | dsidev = dsi_get_dsidev_from_id(0); | ||
| 1896 | if (dsidev) | ||
| 1897 | debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir, | ||
| 1898 | &dsi1_dump_irqs, debug_fops); | ||
| 1899 | |||
| 1900 | dsidev = dsi_get_dsidev_from_id(1); | ||
| 1901 | if (dsidev) | ||
| 1902 | debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir, | ||
| 1903 | &dsi2_dump_irqs, debug_fops); | ||
| 1904 | } | ||
| 1905 | #endif | 1851 | #endif |
| 1906 | 1852 | ||
| 1907 | static void dsi_dump_dsidev_regs(struct platform_device *dsidev, | 1853 | static void dsi_dump_dsidev_regs(struct platform_device *dsidev, |
| @@ -2002,21 +1948,6 @@ static void dsi2_dump_regs(struct seq_file *s) | |||
| 2002 | dsi_dump_dsidev_regs(dsidev, s); | 1948 | dsi_dump_dsidev_regs(dsidev, s); |
| 2003 | } | 1949 | } |
| 2004 | 1950 | ||
| 2005 | void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, | ||
| 2006 | const struct file_operations *debug_fops) | ||
| 2007 | { | ||
| 2008 | struct platform_device *dsidev; | ||
| 2009 | |||
| 2010 | dsidev = dsi_get_dsidev_from_id(0); | ||
| 2011 | if (dsidev) | ||
| 2012 | debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir, | ||
| 2013 | &dsi1_dump_regs, debug_fops); | ||
| 2014 | |||
| 2015 | dsidev = dsi_get_dsidev_from_id(1); | ||
| 2016 | if (dsidev) | ||
| 2017 | debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir, | ||
| 2018 | &dsi2_dump_regs, debug_fops); | ||
| 2019 | } | ||
| 2020 | enum dsi_cio_power_state { | 1951 | enum dsi_cio_power_state { |
| 2021 | DSI_COMPLEXIO_POWER_OFF = 0x0, | 1952 | DSI_COMPLEXIO_POWER_OFF = 0x0, |
| 2022 | DSI_COMPLEXIO_POWER_ON = 0x1, | 1953 | DSI_COMPLEXIO_POWER_ON = 0x1, |
| @@ -2073,6 +2004,7 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
| 2073 | return 1365 * 3; /* 1365x24 bits */ | 2004 | return 1365 * 3; /* 1365x24 bits */ |
| 2074 | default: | 2005 | default: |
| 2075 | BUG(); | 2006 | BUG(); |
| 2007 | return 0; | ||
| 2076 | } | 2008 | } |
| 2077 | } | 2009 | } |
| 2078 | 2010 | ||
| @@ -2337,7 +2269,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
| 2337 | 2269 | ||
| 2338 | DSSDBGF(); | 2270 | DSSDBGF(); |
| 2339 | 2271 | ||
| 2340 | r = dsi->enable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); | 2272 | r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); |
| 2341 | if (r) | 2273 | if (r) |
| 2342 | return r; | 2274 | return r; |
| 2343 | 2275 | ||
| @@ -2447,7 +2379,7 @@ err_cio_pwr: | |||
| 2447 | dsi_cio_disable_lane_override(dsidev); | 2379 | dsi_cio_disable_lane_override(dsidev); |
| 2448 | err_scp_clk_dom: | 2380 | err_scp_clk_dom: |
| 2449 | dsi_disable_scp_clk(dsidev); | 2381 | dsi_disable_scp_clk(dsidev); |
| 2450 | dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); | 2382 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); |
| 2451 | return r; | 2383 | return r; |
| 2452 | } | 2384 | } |
| 2453 | 2385 | ||
| @@ -2461,7 +2393,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev) | |||
| 2461 | 2393 | ||
| 2462 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); | 2394 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); |
| 2463 | dsi_disable_scp_clk(dsidev); | 2395 | dsi_disable_scp_clk(dsidev); |
| 2464 | dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); | 2396 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); |
| 2465 | } | 2397 | } |
| 2466 | 2398 | ||
| 2467 | static void dsi_config_tx_fifo(struct platform_device *dsidev, | 2399 | static void dsi_config_tx_fifo(struct platform_device *dsidev, |
| @@ -2485,6 +2417,7 @@ static void dsi_config_tx_fifo(struct platform_device *dsidev, | |||
| 2485 | if (add + size > 4) { | 2417 | if (add + size > 4) { |
| 2486 | DSSERR("Illegal FIFO configuration\n"); | 2418 | DSSERR("Illegal FIFO configuration\n"); |
| 2487 | BUG(); | 2419 | BUG(); |
| 2420 | return; | ||
| 2488 | } | 2421 | } |
| 2489 | 2422 | ||
| 2490 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); | 2423 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); |
| @@ -2517,6 +2450,7 @@ static void dsi_config_rx_fifo(struct platform_device *dsidev, | |||
| 2517 | if (add + size > 4) { | 2450 | if (add + size > 4) { |
| 2518 | DSSERR("Illegal FIFO configuration\n"); | 2451 | DSSERR("Illegal FIFO configuration\n"); |
| 2519 | BUG(); | 2452 | BUG(); |
| 2453 | return; | ||
| 2520 | } | 2454 | } |
| 2521 | 2455 | ||
| 2522 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); | 2456 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); |
| @@ -2658,6 +2592,7 @@ static int dsi_sync_vc(struct platform_device *dsidev, int channel) | |||
| 2658 | return dsi_sync_vc_l4(dsidev, channel); | 2592 | return dsi_sync_vc_l4(dsidev, channel); |
| 2659 | default: | 2593 | default: |
| 2660 | BUG(); | 2594 | BUG(); |
| 2595 | return -EINVAL; | ||
| 2661 | } | 2596 | } |
| 2662 | } | 2597 | } |
| 2663 | 2598 | ||
| @@ -3226,6 +3161,7 @@ static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, | |||
| 3226 | data = reqdata[0] | (reqdata[1] << 8); | 3161 | data = reqdata[0] | (reqdata[1] << 8); |
| 3227 | } else { | 3162 | } else { |
| 3228 | BUG(); | 3163 | BUG(); |
| 3164 | return -EINVAL; | ||
| 3229 | } | 3165 | } |
| 3230 | 3166 | ||
| 3231 | r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); | 3167 | r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); |
| @@ -3340,7 +3276,6 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, | |||
| 3340 | goto err; | 3276 | goto err; |
| 3341 | } | 3277 | } |
| 3342 | 3278 | ||
| 3343 | BUG(); | ||
| 3344 | err: | 3279 | err: |
| 3345 | DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel, | 3280 | DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel, |
| 3346 | type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS"); | 3281 | type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS"); |
| @@ -3735,6 +3670,186 @@ static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) | |||
| 3735 | dsi_write_reg(dsidev, DSI_CTRL, r); | 3670 | dsi_write_reg(dsidev, DSI_CTRL, r); |
| 3736 | } | 3671 | } |
| 3737 | 3672 | ||
| 3673 | /* | ||
| 3674 | * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3 | ||
| 3675 | * results in maximum transition time for data and clock lanes to enter and | ||
| 3676 | * exit HS mode. Hence, this is the scenario where the least amount of command | ||
| 3677 | * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS | ||
| 3678 | * clock cycles that can be used to interleave command mode data in HS so that | ||
| 3679 | * all scenarios are satisfied. | ||
| 3680 | */ | ||
| 3681 | static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs, | ||
| 3682 | int exit_hs, int exiths_clk, int ddr_pre, int ddr_post) | ||
| 3683 | { | ||
| 3684 | int transition; | ||
| 3685 | |||
| 3686 | /* | ||
| 3687 | * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition | ||
| 3688 | * time of data lanes only, if it isn't set, we need to consider HS | ||
| 3689 | * transition time of both data and clock lanes. HS transition time | ||
| 3690 | * of Scenario 3 is considered. | ||
| 3691 | */ | ||
| 3692 | if (ddr_alwon) { | ||
| 3693 | transition = enter_hs + exit_hs + max(enter_hs, 2) + 1; | ||
| 3694 | } else { | ||
| 3695 | int trans1, trans2; | ||
| 3696 | trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1; | ||
| 3697 | trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre + | ||
| 3698 | enter_hs + 1; | ||
| 3699 | transition = max(trans1, trans2); | ||
| 3700 | } | ||
| 3701 | |||
| 3702 | return blank > transition ? blank - transition : 0; | ||
| 3703 | } | ||
| 3704 | |||
| 3705 | /* | ||
| 3706 | * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1 | ||
| 3707 | * results in maximum transition time for data lanes to enter and exit LP mode. | ||
| 3708 | * Hence, this is the scenario where the least amount of command mode data can | ||
| 3709 | * be interleaved. We program the minimum amount of bytes that can be | ||
| 3710 | * interleaved in LP so that all scenarios are satisfied. | ||
| 3711 | */ | ||
| 3712 | static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, | ||
| 3713 | int lp_clk_div, int tdsi_fclk) | ||
| 3714 | { | ||
| 3715 | int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */ | ||
| 3716 | int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */ | ||
| 3717 | int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */ | ||
| 3718 | int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */ | ||
| 3719 | int lp_inter; /* cmd mode data that can be interleaved, in bytes */ | ||
| 3720 | |||
| 3721 | /* maximum LP transition time according to Scenario 1 */ | ||
| 3722 | trans_lp = exit_hs + max(enter_hs, 2) + 1; | ||
| 3723 | |||
| 3724 | /* CLKIN4DDR = 16 * TXBYTECLKHS */ | ||
| 3725 | tlp_avail = thsbyte_clk * (blank - trans_lp); | ||
| 3726 | |||
| 3727 | ttxclkesc = tdsi_fclk / lp_clk_div; | ||
| 3728 | |||
| 3729 | lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc - | ||
| 3730 | 26) / 16; | ||
| 3731 | |||
| 3732 | return max(lp_inter, 0); | ||
| 3733 | } | ||
| 3734 | |||
| 3735 | static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | ||
| 3736 | { | ||
| 3737 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
| 3738 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 3739 | int blanking_mode; | ||
| 3740 | int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; | ||
| 3741 | int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div; | ||
| 3742 | int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; | ||
| 3743 | int tclk_trail, ths_exit, exiths_clk; | ||
| 3744 | bool ddr_alwon; | ||
| 3745 | struct omap_video_timings *timings = &dssdev->panel.timings; | ||
| 3746 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | ||
| 3747 | int ndl = dsi->num_lanes_used - 1; | ||
| 3748 | int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; | ||
| 3749 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; | ||
| 3750 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; | ||
| 3751 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; | ||
| 3752 | int bl_interleave_hs = 0, bl_interleave_lp = 0; | ||
| 3753 | u32 r; | ||
| 3754 | |||
| 3755 | r = dsi_read_reg(dsidev, DSI_CTRL); | ||
| 3756 | blanking_mode = FLD_GET(r, 20, 20); | ||
| 3757 | hfp_blanking_mode = FLD_GET(r, 21, 21); | ||
| 3758 | hbp_blanking_mode = FLD_GET(r, 22, 22); | ||
| 3759 | hsa_blanking_mode = FLD_GET(r, 23, 23); | ||
| 3760 | |||
| 3761 | r = dsi_read_reg(dsidev, DSI_VM_TIMING1); | ||
| 3762 | hbp = FLD_GET(r, 11, 0); | ||
| 3763 | hfp = FLD_GET(r, 23, 12); | ||
| 3764 | hsa = FLD_GET(r, 31, 24); | ||
| 3765 | |||
| 3766 | r = dsi_read_reg(dsidev, DSI_CLK_TIMING); | ||
| 3767 | ddr_clk_post = FLD_GET(r, 7, 0); | ||
| 3768 | ddr_clk_pre = FLD_GET(r, 15, 8); | ||
| 3769 | |||
| 3770 | r = dsi_read_reg(dsidev, DSI_VM_TIMING7); | ||
| 3771 | exit_hs_mode_lat = FLD_GET(r, 15, 0); | ||
| 3772 | enter_hs_mode_lat = FLD_GET(r, 31, 16); | ||
| 3773 | |||
| 3774 | r = dsi_read_reg(dsidev, DSI_CLK_CTRL); | ||
| 3775 | lp_clk_div = FLD_GET(r, 12, 0); | ||
| 3776 | ddr_alwon = FLD_GET(r, 13, 13); | ||
| 3777 | |||
| 3778 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); | ||
| 3779 | ths_exit = FLD_GET(r, 7, 0); | ||
| 3780 | |||
| 3781 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | ||
| 3782 | tclk_trail = FLD_GET(r, 15, 8); | ||
| 3783 | |||
| 3784 | exiths_clk = ths_exit + tclk_trail; | ||
| 3785 | |||
| 3786 | width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8); | ||
| 3787 | bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl); | ||
| 3788 | |||
| 3789 | if (!hsa_blanking_mode) { | ||
| 3790 | hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon, | ||
| 3791 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3792 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
| 3793 | hsa_interleave_lp = dsi_compute_interleave_lp(hsa, | ||
| 3794 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3795 | lp_clk_div, dsi_fclk_hsdiv); | ||
| 3796 | } | ||
| 3797 | |||
| 3798 | if (!hfp_blanking_mode) { | ||
| 3799 | hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon, | ||
| 3800 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3801 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
| 3802 | hfp_interleave_lp = dsi_compute_interleave_lp(hfp, | ||
| 3803 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3804 | lp_clk_div, dsi_fclk_hsdiv); | ||
| 3805 | } | ||
| 3806 | |||
| 3807 | if (!hbp_blanking_mode) { | ||
| 3808 | hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon, | ||
| 3809 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3810 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
| 3811 | |||
| 3812 | hbp_interleave_lp = dsi_compute_interleave_lp(hbp, | ||
| 3813 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3814 | lp_clk_div, dsi_fclk_hsdiv); | ||
| 3815 | } | ||
| 3816 | |||
| 3817 | if (!blanking_mode) { | ||
| 3818 | bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon, | ||
| 3819 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3820 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
| 3821 | |||
| 3822 | bl_interleave_lp = dsi_compute_interleave_lp(bllp, | ||
| 3823 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
| 3824 | lp_clk_div, dsi_fclk_hsdiv); | ||
| 3825 | } | ||
| 3826 | |||
| 3827 | DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n", | ||
| 3828 | hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs, | ||
| 3829 | bl_interleave_hs); | ||
| 3830 | |||
| 3831 | DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n", | ||
| 3832 | hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp, | ||
| 3833 | bl_interleave_lp); | ||
| 3834 | |||
| 3835 | r = dsi_read_reg(dsidev, DSI_VM_TIMING4); | ||
| 3836 | r = FLD_MOD(r, hsa_interleave_hs, 23, 16); | ||
| 3837 | r = FLD_MOD(r, hfp_interleave_hs, 15, 8); | ||
| 3838 | r = FLD_MOD(r, hbp_interleave_hs, 7, 0); | ||
| 3839 | dsi_write_reg(dsidev, DSI_VM_TIMING4, r); | ||
| 3840 | |||
| 3841 | r = dsi_read_reg(dsidev, DSI_VM_TIMING5); | ||
| 3842 | r = FLD_MOD(r, hsa_interleave_lp, 23, 16); | ||
| 3843 | r = FLD_MOD(r, hfp_interleave_lp, 15, 8); | ||
| 3844 | r = FLD_MOD(r, hbp_interleave_lp, 7, 0); | ||
| 3845 | dsi_write_reg(dsidev, DSI_VM_TIMING5, r); | ||
| 3846 | |||
| 3847 | r = dsi_read_reg(dsidev, DSI_VM_TIMING6); | ||
| 3848 | r = FLD_MOD(r, bl_interleave_hs, 31, 15); | ||
| 3849 | r = FLD_MOD(r, bl_interleave_lp, 16, 0); | ||
| 3850 | dsi_write_reg(dsidev, DSI_VM_TIMING6, r); | ||
| 3851 | } | ||
| 3852 | |||
| 3738 | static int dsi_proto_config(struct omap_dss_device *dssdev) | 3853 | static int dsi_proto_config(struct omap_dss_device *dssdev) |
| 3739 | { | 3854 | { |
| 3740 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3855 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
| @@ -3769,6 +3884,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
| 3769 | break; | 3884 | break; |
| 3770 | default: | 3885 | default: |
| 3771 | BUG(); | 3886 | BUG(); |
| 3887 | return -EINVAL; | ||
| 3772 | } | 3888 | } |
| 3773 | 3889 | ||
| 3774 | r = dsi_read_reg(dsidev, DSI_CTRL); | 3890 | r = dsi_read_reg(dsidev, DSI_CTRL); |
| @@ -3793,6 +3909,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
| 3793 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3909 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { |
| 3794 | dsi_config_vp_sync_events(dssdev); | 3910 | dsi_config_vp_sync_events(dssdev); |
| 3795 | dsi_config_blanking_modes(dssdev); | 3911 | dsi_config_blanking_modes(dssdev); |
| 3912 | dsi_config_cmd_mode_interleaving(dssdev); | ||
| 3796 | } | 3913 | } |
| 3797 | 3914 | ||
| 3798 | dsi_vc_initial_config(dsidev, 0); | 3915 | dsi_vc_initial_config(dsidev, 0); |
| @@ -4008,6 +4125,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | |||
| 4008 | break; | 4125 | break; |
| 4009 | default: | 4126 | default: |
| 4010 | BUG(); | 4127 | BUG(); |
| 4128 | return -EINVAL; | ||
| 4011 | }; | 4129 | }; |
| 4012 | 4130 | ||
| 4013 | dsi_if_enable(dsidev, false); | 4131 | dsi_if_enable(dsidev, false); |
| @@ -4192,10 +4310,6 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) | |||
| 4192 | __cancel_delayed_work(&dsi->framedone_timeout_work); | 4310 | __cancel_delayed_work(&dsi->framedone_timeout_work); |
| 4193 | 4311 | ||
| 4194 | dsi_handle_framedone(dsidev, 0); | 4312 | dsi_handle_framedone(dsidev, 0); |
| 4195 | |||
| 4196 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
| 4197 | dispc_fake_vsync_irq(); | ||
| 4198 | #endif | ||
| 4199 | } | 4313 | } |
| 4200 | 4314 | ||
| 4201 | int omap_dsi_update(struct omap_dss_device *dssdev, int channel, | 4315 | int omap_dsi_update(struct omap_dss_device *dssdev, int channel, |
| @@ -4259,13 +4373,12 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
| 4259 | dispc_mgr_enable_stallmode(dssdev->manager->id, true); | 4373 | dispc_mgr_enable_stallmode(dssdev->manager->id, true); |
| 4260 | dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1); | 4374 | dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1); |
| 4261 | 4375 | ||
| 4262 | dispc_mgr_set_lcd_timings(dssdev->manager->id, &timings); | 4376 | dss_mgr_set_timings(dssdev->manager, &timings); |
| 4263 | } else { | 4377 | } else { |
| 4264 | dispc_mgr_enable_stallmode(dssdev->manager->id, false); | 4378 | dispc_mgr_enable_stallmode(dssdev->manager->id, false); |
| 4265 | dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0); | 4379 | dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0); |
| 4266 | 4380 | ||
| 4267 | dispc_mgr_set_lcd_timings(dssdev->manager->id, | 4381 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); |
| 4268 | &dssdev->panel.timings); | ||
| 4269 | } | 4382 | } |
| 4270 | 4383 | ||
| 4271 | dispc_mgr_set_lcd_display_type(dssdev->manager->id, | 4384 | dispc_mgr_set_lcd_display_type(dssdev->manager->id, |
| @@ -4294,13 +4407,11 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | |||
| 4294 | struct dsi_clock_info cinfo; | 4407 | struct dsi_clock_info cinfo; |
| 4295 | int r; | 4408 | int r; |
| 4296 | 4409 | ||
| 4297 | /* we always use DSS_CLK_SYSCK as input clock */ | ||
| 4298 | cinfo.use_sys_clk = true; | ||
| 4299 | cinfo.regn = dssdev->clocks.dsi.regn; | 4410 | cinfo.regn = dssdev->clocks.dsi.regn; |
| 4300 | cinfo.regm = dssdev->clocks.dsi.regm; | 4411 | cinfo.regm = dssdev->clocks.dsi.regm; |
| 4301 | cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; | 4412 | cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; |
| 4302 | cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; | 4413 | cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; |
| 4303 | r = dsi_calc_clock_rates(dssdev, &cinfo); | 4414 | r = dsi_calc_clock_rates(dsidev, &cinfo); |
| 4304 | if (r) { | 4415 | if (r) { |
| 4305 | DSSERR("Failed to calc dsi clocks\n"); | 4416 | DSSERR("Failed to calc dsi clocks\n"); |
| 4306 | return r; | 4417 | return r; |
| @@ -4345,7 +4456,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) | |||
| 4345 | static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | 4456 | static int dsi_display_init_dsi(struct omap_dss_device *dssdev) |
| 4346 | { | 4457 | { |
| 4347 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4458 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
| 4348 | int dsi_module = dsi_get_dsidev_id(dsidev); | 4459 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4349 | int r; | 4460 | int r; |
| 4350 | 4461 | ||
| 4351 | r = dsi_pll_init(dsidev, true, true); | 4462 | r = dsi_pll_init(dsidev, true, true); |
| @@ -4357,7 +4468,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
| 4357 | goto err1; | 4468 | goto err1; |
| 4358 | 4469 | ||
| 4359 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | 4470 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); |
| 4360 | dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src); | 4471 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); |
| 4361 | dss_select_lcd_clk_source(dssdev->manager->id, | 4472 | dss_select_lcd_clk_source(dssdev->manager->id, |
| 4362 | dssdev->clocks.dispc.channel.lcd_clk_src); | 4473 | dssdev->clocks.dispc.channel.lcd_clk_src); |
| 4363 | 4474 | ||
| @@ -4396,7 +4507,7 @@ err3: | |||
| 4396 | dsi_cio_uninit(dssdev); | 4507 | dsi_cio_uninit(dssdev); |
| 4397 | err2: | 4508 | err2: |
| 4398 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 4509 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
| 4399 | dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); | 4510 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
| 4400 | dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); | 4511 | dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); |
| 4401 | 4512 | ||
| 4402 | err1: | 4513 | err1: |
| @@ -4410,7 +4521,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
| 4410 | { | 4521 | { |
| 4411 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4522 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
| 4412 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4523 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4413 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
| 4414 | 4524 | ||
| 4415 | if (enter_ulps && !dsi->ulps_enabled) | 4525 | if (enter_ulps && !dsi->ulps_enabled) |
| 4416 | dsi_enter_ulps(dsidev); | 4526 | dsi_enter_ulps(dsidev); |
| @@ -4423,7 +4533,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
| 4423 | dsi_vc_enable(dsidev, 3, 0); | 4533 | dsi_vc_enable(dsidev, 3, 0); |
| 4424 | 4534 | ||
| 4425 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 4535 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
| 4426 | dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); | 4536 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
| 4427 | dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); | 4537 | dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); |
| 4428 | dsi_cio_uninit(dssdev); | 4538 | dsi_cio_uninit(dssdev); |
| 4429 | dsi_pll_uninit(dsidev, disconnect_lanes); | 4539 | dsi_pll_uninit(dsidev, disconnect_lanes); |
| @@ -4527,7 +4637,7 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
| 4527 | } | 4637 | } |
| 4528 | EXPORT_SYMBOL(omapdss_dsi_enable_te); | 4638 | EXPORT_SYMBOL(omapdss_dsi_enable_te); |
| 4529 | 4639 | ||
| 4530 | int dsi_init_display(struct omap_dss_device *dssdev) | 4640 | static int __init dsi_init_display(struct omap_dss_device *dssdev) |
| 4531 | { | 4641 | { |
| 4532 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4642 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
| 4533 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4643 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| @@ -4680,13 +4790,39 @@ static void dsi_put_clocks(struct platform_device *dsidev) | |||
| 4680 | clk_put(dsi->sys_clk); | 4790 | clk_put(dsi->sys_clk); |
| 4681 | } | 4791 | } |
| 4682 | 4792 | ||
| 4793 | static void __init dsi_probe_pdata(struct platform_device *dsidev) | ||
| 4794 | { | ||
| 4795 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 4796 | struct omap_dss_board_info *pdata = dsidev->dev.platform_data; | ||
| 4797 | int i, r; | ||
| 4798 | |||
| 4799 | for (i = 0; i < pdata->num_devices; ++i) { | ||
| 4800 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
| 4801 | |||
| 4802 | if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) | ||
| 4803 | continue; | ||
| 4804 | |||
| 4805 | if (dssdev->phy.dsi.module != dsi->module_id) | ||
| 4806 | continue; | ||
| 4807 | |||
| 4808 | r = dsi_init_display(dssdev); | ||
| 4809 | if (r) { | ||
| 4810 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
| 4811 | continue; | ||
| 4812 | } | ||
| 4813 | |||
| 4814 | r = omap_dss_register_device(dssdev, &dsidev->dev, i); | ||
| 4815 | if (r) | ||
| 4816 | DSSERR("device %s register failed: %d\n", | ||
| 4817 | dssdev->name, r); | ||
| 4818 | } | ||
| 4819 | } | ||
| 4820 | |||
| 4683 | /* DSI1 HW IP initialisation */ | 4821 | /* DSI1 HW IP initialisation */ |
| 4684 | static int omap_dsihw_probe(struct platform_device *dsidev) | 4822 | static int __init omap_dsihw_probe(struct platform_device *dsidev) |
| 4685 | { | 4823 | { |
| 4686 | struct omap_display_platform_data *dss_plat_data; | ||
| 4687 | struct omap_dss_board_info *board_info; | ||
| 4688 | u32 rev; | 4824 | u32 rev; |
| 4689 | int r, i, dsi_module = dsi_get_dsidev_id(dsidev); | 4825 | int r, i; |
| 4690 | struct resource *dsi_mem; | 4826 | struct resource *dsi_mem; |
| 4691 | struct dsi_data *dsi; | 4827 | struct dsi_data *dsi; |
| 4692 | 4828 | ||
| @@ -4694,15 +4830,11 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
| 4694 | if (!dsi) | 4830 | if (!dsi) |
| 4695 | return -ENOMEM; | 4831 | return -ENOMEM; |
| 4696 | 4832 | ||
| 4833 | dsi->module_id = dsidev->id; | ||
| 4697 | dsi->pdev = dsidev; | 4834 | dsi->pdev = dsidev; |
| 4698 | dsi_pdev_map[dsi_module] = dsidev; | 4835 | dsi_pdev_map[dsi->module_id] = dsidev; |
| 4699 | dev_set_drvdata(&dsidev->dev, dsi); | 4836 | dev_set_drvdata(&dsidev->dev, dsi); |
| 4700 | 4837 | ||
| 4701 | dss_plat_data = dsidev->dev.platform_data; | ||
| 4702 | board_info = dss_plat_data->board_data; | ||
| 4703 | dsi->enable_pads = board_info->dsi_enable_pads; | ||
| 4704 | dsi->disable_pads = board_info->dsi_disable_pads; | ||
| 4705 | |||
| 4706 | spin_lock_init(&dsi->irq_lock); | 4838 | spin_lock_init(&dsi->irq_lock); |
| 4707 | spin_lock_init(&dsi->errors_lock); | 4839 | spin_lock_init(&dsi->errors_lock); |
| 4708 | dsi->errors = 0; | 4840 | dsi->errors = 0; |
| @@ -4780,8 +4912,21 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
| 4780 | else | 4912 | else |
| 4781 | dsi->num_lanes_supported = 3; | 4913 | dsi->num_lanes_supported = 3; |
| 4782 | 4914 | ||
| 4915 | dsi_probe_pdata(dsidev); | ||
| 4916 | |||
| 4783 | dsi_runtime_put(dsidev); | 4917 | dsi_runtime_put(dsidev); |
| 4784 | 4918 | ||
| 4919 | if (dsi->module_id == 0) | ||
| 4920 | dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs); | ||
| 4921 | else if (dsi->module_id == 1) | ||
| 4922 | dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs); | ||
| 4923 | |||
| 4924 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 4925 | if (dsi->module_id == 0) | ||
| 4926 | dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs); | ||
| 4927 | else if (dsi->module_id == 1) | ||
| 4928 | dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); | ||
| 4929 | #endif | ||
| 4785 | return 0; | 4930 | return 0; |
| 4786 | 4931 | ||
| 4787 | err_runtime_get: | 4932 | err_runtime_get: |
| @@ -4790,12 +4935,14 @@ err_runtime_get: | |||
| 4790 | return r; | 4935 | return r; |
| 4791 | } | 4936 | } |
| 4792 | 4937 | ||
| 4793 | static int omap_dsihw_remove(struct platform_device *dsidev) | 4938 | static int __exit omap_dsihw_remove(struct platform_device *dsidev) |
| 4794 | { | 4939 | { |
| 4795 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4940 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4796 | 4941 | ||
| 4797 | WARN_ON(dsi->scp_clk_refcount > 0); | 4942 | WARN_ON(dsi->scp_clk_refcount > 0); |
| 4798 | 4943 | ||
| 4944 | omap_dss_unregister_child_devices(&dsidev->dev); | ||
| 4945 | |||
| 4799 | pm_runtime_disable(&dsidev->dev); | 4946 | pm_runtime_disable(&dsidev->dev); |
| 4800 | 4947 | ||
| 4801 | dsi_put_clocks(dsidev); | 4948 | dsi_put_clocks(dsidev); |
| @@ -4816,7 +4963,6 @@ static int omap_dsihw_remove(struct platform_device *dsidev) | |||
| 4816 | static int dsi_runtime_suspend(struct device *dev) | 4963 | static int dsi_runtime_suspend(struct device *dev) |
| 4817 | { | 4964 | { |
| 4818 | dispc_runtime_put(); | 4965 | dispc_runtime_put(); |
| 4819 | dss_runtime_put(); | ||
| 4820 | 4966 | ||
| 4821 | return 0; | 4967 | return 0; |
| 4822 | } | 4968 | } |
| @@ -4825,20 +4971,11 @@ static int dsi_runtime_resume(struct device *dev) | |||
| 4825 | { | 4971 | { |
| 4826 | int r; | 4972 | int r; |
| 4827 | 4973 | ||
| 4828 | r = dss_runtime_get(); | ||
| 4829 | if (r) | ||
| 4830 | goto err_get_dss; | ||
| 4831 | |||
| 4832 | r = dispc_runtime_get(); | 4974 | r = dispc_runtime_get(); |
| 4833 | if (r) | 4975 | if (r) |
| 4834 | goto err_get_dispc; | 4976 | return r; |
| 4835 | 4977 | ||
| 4836 | return 0; | 4978 | return 0; |
| 4837 | |||
| 4838 | err_get_dispc: | ||
| 4839 | dss_runtime_put(); | ||
| 4840 | err_get_dss: | ||
| 4841 | return r; | ||
| 4842 | } | 4979 | } |
| 4843 | 4980 | ||
| 4844 | static const struct dev_pm_ops dsi_pm_ops = { | 4981 | static const struct dev_pm_ops dsi_pm_ops = { |
| @@ -4847,8 +4984,7 @@ static const struct dev_pm_ops dsi_pm_ops = { | |||
| 4847 | }; | 4984 | }; |
| 4848 | 4985 | ||
| 4849 | static struct platform_driver omap_dsihw_driver = { | 4986 | static struct platform_driver omap_dsihw_driver = { |
| 4850 | .probe = omap_dsihw_probe, | 4987 | .remove = __exit_p(omap_dsihw_remove), |
| 4851 | .remove = omap_dsihw_remove, | ||
| 4852 | .driver = { | 4988 | .driver = { |
| 4853 | .name = "omapdss_dsi", | 4989 | .name = "omapdss_dsi", |
| 4854 | .owner = THIS_MODULE, | 4990 | .owner = THIS_MODULE, |
| @@ -4856,12 +4992,12 @@ static struct platform_driver omap_dsihw_driver = { | |||
| 4856 | }, | 4992 | }, |
| 4857 | }; | 4993 | }; |
| 4858 | 4994 | ||
| 4859 | int dsi_init_platform_driver(void) | 4995 | int __init dsi_init_platform_driver(void) |
| 4860 | { | 4996 | { |
| 4861 | return platform_driver_register(&omap_dsihw_driver); | 4997 | return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe); |
| 4862 | } | 4998 | } |
| 4863 | 4999 | ||
| 4864 | void dsi_uninit_platform_driver(void) | 5000 | void __exit dsi_uninit_platform_driver(void) |
| 4865 | { | 5001 | { |
| 4866 | return platform_driver_unregister(&omap_dsihw_driver); | 5002 | platform_driver_unregister(&omap_dsihw_driver); |
| 4867 | } | 5003 | } |
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index bd2d5e159463..6ea1ff149f6f 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
| @@ -62,6 +62,9 @@ struct dss_reg { | |||
| 62 | #define REG_FLD_MOD(idx, val, start, end) \ | 62 | #define REG_FLD_MOD(idx, val, start, end) \ |
| 63 | dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) | 63 | dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) |
| 64 | 64 | ||
| 65 | static int dss_runtime_get(void); | ||
| 66 | static void dss_runtime_put(void); | ||
| 67 | |||
| 65 | static struct { | 68 | static struct { |
| 66 | struct platform_device *pdev; | 69 | struct platform_device *pdev; |
| 67 | void __iomem *base; | 70 | void __iomem *base; |
| @@ -277,7 +280,7 @@ void dss_dump_clocks(struct seq_file *s) | |||
| 277 | dss_runtime_put(); | 280 | dss_runtime_put(); |
| 278 | } | 281 | } |
| 279 | 282 | ||
| 280 | void dss_dump_regs(struct seq_file *s) | 283 | static void dss_dump_regs(struct seq_file *s) |
| 281 | { | 284 | { |
| 282 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) | 285 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) |
| 283 | 286 | ||
| @@ -322,6 +325,7 @@ void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | |||
| 322 | break; | 325 | break; |
| 323 | default: | 326 | default: |
| 324 | BUG(); | 327 | BUG(); |
| 328 | return; | ||
| 325 | } | 329 | } |
| 326 | 330 | ||
| 327 | dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); | 331 | dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); |
| @@ -335,7 +339,7 @@ void dss_select_dsi_clk_source(int dsi_module, | |||
| 335 | enum omap_dss_clk_source clk_src) | 339 | enum omap_dss_clk_source clk_src) |
| 336 | { | 340 | { |
| 337 | struct platform_device *dsidev; | 341 | struct platform_device *dsidev; |
| 338 | int b; | 342 | int b, pos; |
| 339 | 343 | ||
| 340 | switch (clk_src) { | 344 | switch (clk_src) { |
| 341 | case OMAP_DSS_CLK_SRC_FCK: | 345 | case OMAP_DSS_CLK_SRC_FCK: |
| @@ -355,9 +359,11 @@ void dss_select_dsi_clk_source(int dsi_module, | |||
| 355 | break; | 359 | break; |
| 356 | default: | 360 | default: |
| 357 | BUG(); | 361 | BUG(); |
| 362 | return; | ||
| 358 | } | 363 | } |
| 359 | 364 | ||
| 360 | REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ | 365 | pos = dsi_module == 0 ? 1 : 10; |
| 366 | REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ | ||
| 361 | 367 | ||
| 362 | dss.dsi_clk_source[dsi_module] = clk_src; | 368 | dss.dsi_clk_source[dsi_module] = clk_src; |
| 363 | } | 369 | } |
| @@ -389,6 +395,7 @@ void dss_select_lcd_clk_source(enum omap_channel channel, | |||
| 389 | break; | 395 | break; |
| 390 | default: | 396 | default: |
| 391 | BUG(); | 397 | BUG(); |
| 398 | return; | ||
| 392 | } | 399 | } |
| 393 | 400 | ||
| 394 | pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; | 401 | pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; |
| @@ -706,7 +713,7 @@ static void dss_put_clocks(void) | |||
| 706 | clk_put(dss.dss_clk); | 713 | clk_put(dss.dss_clk); |
| 707 | } | 714 | } |
| 708 | 715 | ||
| 709 | int dss_runtime_get(void) | 716 | static int dss_runtime_get(void) |
| 710 | { | 717 | { |
| 711 | int r; | 718 | int r; |
| 712 | 719 | ||
| @@ -717,7 +724,7 @@ int dss_runtime_get(void) | |||
| 717 | return r < 0 ? r : 0; | 724 | return r < 0 ? r : 0; |
| 718 | } | 725 | } |
| 719 | 726 | ||
| 720 | void dss_runtime_put(void) | 727 | static void dss_runtime_put(void) |
| 721 | { | 728 | { |
| 722 | int r; | 729 | int r; |
| 723 | 730 | ||
| @@ -740,7 +747,7 @@ void dss_debug_dump_clocks(struct seq_file *s) | |||
| 740 | #endif | 747 | #endif |
| 741 | 748 | ||
| 742 | /* DSS HW IP initialisation */ | 749 | /* DSS HW IP initialisation */ |
| 743 | static int omap_dsshw_probe(struct platform_device *pdev) | 750 | static int __init omap_dsshw_probe(struct platform_device *pdev) |
| 744 | { | 751 | { |
| 745 | struct resource *dss_mem; | 752 | struct resource *dss_mem; |
| 746 | u32 rev; | 753 | u32 rev; |
| @@ -785,40 +792,24 @@ static int omap_dsshw_probe(struct platform_device *pdev) | |||
| 785 | dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; | 792 | dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; |
| 786 | dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; | 793 | dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; |
| 787 | 794 | ||
| 788 | r = dpi_init(); | ||
| 789 | if (r) { | ||
| 790 | DSSERR("Failed to initialize DPI\n"); | ||
| 791 | goto err_dpi; | ||
| 792 | } | ||
| 793 | |||
| 794 | r = sdi_init(); | ||
| 795 | if (r) { | ||
| 796 | DSSERR("Failed to initialize SDI\n"); | ||
| 797 | goto err_sdi; | ||
| 798 | } | ||
| 799 | |||
| 800 | rev = dss_read_reg(DSS_REVISION); | 795 | rev = dss_read_reg(DSS_REVISION); |
| 801 | printk(KERN_INFO "OMAP DSS rev %d.%d\n", | 796 | printk(KERN_INFO "OMAP DSS rev %d.%d\n", |
| 802 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 797 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
| 803 | 798 | ||
| 804 | dss_runtime_put(); | 799 | dss_runtime_put(); |
| 805 | 800 | ||
| 801 | dss_debugfs_create_file("dss", dss_dump_regs); | ||
| 802 | |||
| 806 | return 0; | 803 | return 0; |
| 807 | err_sdi: | 804 | |
| 808 | dpi_exit(); | ||
| 809 | err_dpi: | ||
| 810 | dss_runtime_put(); | ||
| 811 | err_runtime_get: | 805 | err_runtime_get: |
| 812 | pm_runtime_disable(&pdev->dev); | 806 | pm_runtime_disable(&pdev->dev); |
| 813 | dss_put_clocks(); | 807 | dss_put_clocks(); |
| 814 | return r; | 808 | return r; |
| 815 | } | 809 | } |
| 816 | 810 | ||
| 817 | static int omap_dsshw_remove(struct platform_device *pdev) | 811 | static int __exit omap_dsshw_remove(struct platform_device *pdev) |
| 818 | { | 812 | { |
| 819 | dpi_exit(); | ||
| 820 | sdi_exit(); | ||
| 821 | |||
| 822 | pm_runtime_disable(&pdev->dev); | 813 | pm_runtime_disable(&pdev->dev); |
| 823 | 814 | ||
| 824 | dss_put_clocks(); | 815 | dss_put_clocks(); |
| @@ -829,11 +820,24 @@ static int omap_dsshw_remove(struct platform_device *pdev) | |||
| 829 | static int dss_runtime_suspend(struct device *dev) | 820 | static int dss_runtime_suspend(struct device *dev) |
| 830 | { | 821 | { |
| 831 | dss_save_context(); | 822 | dss_save_context(); |
| 823 | dss_set_min_bus_tput(dev, 0); | ||
| 832 | return 0; | 824 | return 0; |
| 833 | } | 825 | } |
| 834 | 826 | ||
| 835 | static int dss_runtime_resume(struct device *dev) | 827 | static int dss_runtime_resume(struct device *dev) |
| 836 | { | 828 | { |
| 829 | int r; | ||
| 830 | /* | ||
| 831 | * Set an arbitrarily high tput request to ensure OPP100. | ||
| 832 | * What we should really do is to make a request to stay in OPP100, | ||
| 833 | * without any tput requirements, but that is not currently possible | ||
| 834 | * via the PM layer. | ||
| 835 | */ | ||
| 836 | |||
| 837 | r = dss_set_min_bus_tput(dev, 1000000000); | ||
| 838 | if (r) | ||
| 839 | return r; | ||
| 840 | |||
| 837 | dss_restore_context(); | 841 | dss_restore_context(); |
| 838 | return 0; | 842 | return 0; |
| 839 | } | 843 | } |
| @@ -844,8 +848,7 @@ static const struct dev_pm_ops dss_pm_ops = { | |||
| 844 | }; | 848 | }; |
| 845 | 849 | ||
| 846 | static struct platform_driver omap_dsshw_driver = { | 850 | static struct platform_driver omap_dsshw_driver = { |
| 847 | .probe = omap_dsshw_probe, | 851 | .remove = __exit_p(omap_dsshw_remove), |
| 848 | .remove = omap_dsshw_remove, | ||
| 849 | .driver = { | 852 | .driver = { |
| 850 | .name = "omapdss_dss", | 853 | .name = "omapdss_dss", |
| 851 | .owner = THIS_MODULE, | 854 | .owner = THIS_MODULE, |
| @@ -853,12 +856,12 @@ static struct platform_driver omap_dsshw_driver = { | |||
| 853 | }, | 856 | }, |
| 854 | }; | 857 | }; |
| 855 | 858 | ||
| 856 | int dss_init_platform_driver(void) | 859 | int __init dss_init_platform_driver(void) |
| 857 | { | 860 | { |
| 858 | return platform_driver_register(&omap_dsshw_driver); | 861 | return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe); |
| 859 | } | 862 | } |
| 860 | 863 | ||
| 861 | void dss_uninit_platform_driver(void) | 864 | void dss_uninit_platform_driver(void) |
| 862 | { | 865 | { |
| 863 | return platform_driver_unregister(&omap_dsshw_driver); | 866 | platform_driver_unregister(&omap_dsshw_driver); |
| 864 | } | 867 | } |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index d4b3dff2ead3..dd1092ceaeef 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
| @@ -150,9 +150,6 @@ struct dsi_clock_info { | |||
| 150 | u16 regm_dsi; /* OMAP3: REGM4 | 150 | u16 regm_dsi; /* OMAP3: REGM4 |
| 151 | * OMAP4: REGM5 */ | 151 | * OMAP4: REGM5 */ |
| 152 | u16 lp_clk_div; | 152 | u16 lp_clk_div; |
| 153 | |||
| 154 | u8 highfreq; | ||
| 155 | bool use_sys_clk; | ||
| 156 | }; | 153 | }; |
| 157 | 154 | ||
| 158 | struct seq_file; | 155 | struct seq_file; |
| @@ -162,6 +159,16 @@ struct platform_device; | |||
| 162 | struct bus_type *dss_get_bus(void); | 159 | struct bus_type *dss_get_bus(void); |
| 163 | struct regulator *dss_get_vdds_dsi(void); | 160 | struct regulator *dss_get_vdds_dsi(void); |
| 164 | struct regulator *dss_get_vdds_sdi(void); | 161 | struct regulator *dss_get_vdds_sdi(void); |
| 162 | int dss_get_ctx_loss_count(struct device *dev); | ||
| 163 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask); | ||
| 164 | void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); | ||
| 165 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput); | ||
| 166 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); | ||
| 167 | |||
| 168 | int omap_dss_register_device(struct omap_dss_device *dssdev, | ||
| 169 | struct device *parent, int disp_num); | ||
| 170 | void omap_dss_unregister_device(struct omap_dss_device *dssdev); | ||
| 171 | void omap_dss_unregister_child_devices(struct device *parent); | ||
| 165 | 172 | ||
| 166 | /* apply */ | 173 | /* apply */ |
| 167 | void dss_apply_init(void); | 174 | void dss_apply_init(void); |
| @@ -179,6 +186,9 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, | |||
| 179 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | 186 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, |
| 180 | struct omap_dss_device *dssdev); | 187 | struct omap_dss_device *dssdev); |
| 181 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); | 188 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); |
| 189 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | ||
| 190 | struct omap_video_timings *timings); | ||
| 191 | const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); | ||
| 182 | 192 | ||
| 183 | bool dss_ovl_is_enabled(struct omap_overlay *ovl); | 193 | bool dss_ovl_is_enabled(struct omap_overlay *ovl); |
| 184 | int dss_ovl_enable(struct omap_overlay *ovl); | 194 | int dss_ovl_enable(struct omap_overlay *ovl); |
| @@ -208,9 +218,11 @@ int dss_init_overlay_managers(struct platform_device *pdev); | |||
| 208 | void dss_uninit_overlay_managers(struct platform_device *pdev); | 218 | void dss_uninit_overlay_managers(struct platform_device *pdev); |
| 209 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, | 219 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, |
| 210 | const struct omap_overlay_manager_info *info); | 220 | const struct omap_overlay_manager_info *info); |
| 221 | int dss_mgr_check_timings(struct omap_overlay_manager *mgr, | ||
| 222 | const struct omap_video_timings *timings); | ||
| 211 | int dss_mgr_check(struct omap_overlay_manager *mgr, | 223 | int dss_mgr_check(struct omap_overlay_manager *mgr, |
| 212 | struct omap_dss_device *dssdev, | ||
| 213 | struct omap_overlay_manager_info *info, | 224 | struct omap_overlay_manager_info *info, |
| 225 | const struct omap_video_timings *mgr_timings, | ||
| 214 | struct omap_overlay_info **overlay_infos); | 226 | struct omap_overlay_info **overlay_infos); |
| 215 | 227 | ||
| 216 | /* overlay */ | 228 | /* overlay */ |
| @@ -220,22 +232,18 @@ void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); | |||
| 220 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); | 232 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); |
| 221 | int dss_ovl_simple_check(struct omap_overlay *ovl, | 233 | int dss_ovl_simple_check(struct omap_overlay *ovl, |
| 222 | const struct omap_overlay_info *info); | 234 | const struct omap_overlay_info *info); |
| 223 | int dss_ovl_check(struct omap_overlay *ovl, | 235 | int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, |
| 224 | struct omap_overlay_info *info, struct omap_dss_device *dssdev); | 236 | const struct omap_video_timings *mgr_timings); |
| 225 | 237 | ||
| 226 | /* DSS */ | 238 | /* DSS */ |
| 227 | int dss_init_platform_driver(void); | 239 | int dss_init_platform_driver(void) __init; |
| 228 | void dss_uninit_platform_driver(void); | 240 | void dss_uninit_platform_driver(void); |
| 229 | 241 | ||
| 230 | int dss_runtime_get(void); | ||
| 231 | void dss_runtime_put(void); | ||
| 232 | |||
| 233 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); | 242 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); |
| 234 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); | 243 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); |
| 235 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); | 244 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); |
| 236 | void dss_dump_clocks(struct seq_file *s); | 245 | void dss_dump_clocks(struct seq_file *s); |
| 237 | 246 | ||
| 238 | void dss_dump_regs(struct seq_file *s); | ||
| 239 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | 247 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) |
| 240 | void dss_debug_dump_clocks(struct seq_file *s); | 248 | void dss_debug_dump_clocks(struct seq_file *s); |
| 241 | #endif | 249 | #endif |
| @@ -265,19 +273,8 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, | |||
| 265 | struct dispc_clock_info *dispc_cinfo); | 273 | struct dispc_clock_info *dispc_cinfo); |
| 266 | 274 | ||
| 267 | /* SDI */ | 275 | /* SDI */ |
| 268 | #ifdef CONFIG_OMAP2_DSS_SDI | 276 | int sdi_init_platform_driver(void) __init; |
| 269 | int sdi_init(void); | 277 | void sdi_uninit_platform_driver(void) __exit; |
| 270 | void sdi_exit(void); | ||
| 271 | int sdi_init_display(struct omap_dss_device *display); | ||
| 272 | #else | ||
| 273 | static inline int sdi_init(void) | ||
| 274 | { | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | static inline void sdi_exit(void) | ||
| 278 | { | ||
| 279 | } | ||
| 280 | #endif | ||
| 281 | 278 | ||
| 282 | /* DSI */ | 279 | /* DSI */ |
| 283 | #ifdef CONFIG_OMAP2_DSS_DSI | 280 | #ifdef CONFIG_OMAP2_DSS_DSI |
| @@ -285,19 +282,14 @@ static inline void sdi_exit(void) | |||
| 285 | struct dentry; | 282 | struct dentry; |
| 286 | struct file_operations; | 283 | struct file_operations; |
| 287 | 284 | ||
| 288 | int dsi_init_platform_driver(void); | 285 | int dsi_init_platform_driver(void) __init; |
| 289 | void dsi_uninit_platform_driver(void); | 286 | void dsi_uninit_platform_driver(void) __exit; |
| 290 | 287 | ||
| 291 | int dsi_runtime_get(struct platform_device *dsidev); | 288 | int dsi_runtime_get(struct platform_device *dsidev); |
| 292 | void dsi_runtime_put(struct platform_device *dsidev); | 289 | void dsi_runtime_put(struct platform_device *dsidev); |
| 293 | 290 | ||
| 294 | void dsi_dump_clocks(struct seq_file *s); | 291 | void dsi_dump_clocks(struct seq_file *s); |
| 295 | void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, | ||
| 296 | const struct file_operations *debug_fops); | ||
| 297 | void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, | ||
| 298 | const struct file_operations *debug_fops); | ||
| 299 | 292 | ||
| 300 | int dsi_init_display(struct omap_dss_device *display); | ||
| 301 | void dsi_irq_handler(void); | 293 | void dsi_irq_handler(void); |
| 302 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); | 294 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); |
| 303 | 295 | ||
| @@ -314,13 +306,6 @@ void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); | |||
| 314 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); | 306 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); |
| 315 | struct platform_device *dsi_get_dsidev_from_id(int module); | 307 | struct platform_device *dsi_get_dsidev_from_id(int module); |
| 316 | #else | 308 | #else |
| 317 | static inline int dsi_init_platform_driver(void) | ||
| 318 | { | ||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | static inline void dsi_uninit_platform_driver(void) | ||
| 322 | { | ||
| 323 | } | ||
| 324 | static inline int dsi_runtime_get(struct platform_device *dsidev) | 309 | static inline int dsi_runtime_get(struct platform_device *dsidev) |
| 325 | { | 310 | { |
| 326 | return 0; | 311 | return 0; |
| @@ -377,28 +362,14 @@ static inline struct platform_device *dsi_get_dsidev_from_id(int module) | |||
| 377 | #endif | 362 | #endif |
| 378 | 363 | ||
| 379 | /* DPI */ | 364 | /* DPI */ |
| 380 | #ifdef CONFIG_OMAP2_DSS_DPI | 365 | int dpi_init_platform_driver(void) __init; |
| 381 | int dpi_init(void); | 366 | void dpi_uninit_platform_driver(void) __exit; |
| 382 | void dpi_exit(void); | ||
| 383 | int dpi_init_display(struct omap_dss_device *dssdev); | ||
| 384 | #else | ||
| 385 | static inline int dpi_init(void) | ||
| 386 | { | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | static inline void dpi_exit(void) | ||
| 390 | { | ||
| 391 | } | ||
| 392 | #endif | ||
| 393 | 367 | ||
| 394 | /* DISPC */ | 368 | /* DISPC */ |
| 395 | int dispc_init_platform_driver(void); | 369 | int dispc_init_platform_driver(void) __init; |
| 396 | void dispc_uninit_platform_driver(void); | 370 | void dispc_uninit_platform_driver(void) __exit; |
| 397 | void dispc_dump_clocks(struct seq_file *s); | 371 | void dispc_dump_clocks(struct seq_file *s); |
| 398 | void dispc_dump_irqs(struct seq_file *s); | ||
| 399 | void dispc_dump_regs(struct seq_file *s); | ||
| 400 | void dispc_irq_handler(void); | 372 | void dispc_irq_handler(void); |
| 401 | void dispc_fake_vsync_irq(void); | ||
| 402 | 373 | ||
| 403 | int dispc_runtime_get(void); | 374 | int dispc_runtime_get(void); |
| 404 | void dispc_runtime_put(void); | 375 | void dispc_runtime_put(void); |
| @@ -409,12 +380,12 @@ void dispc_disable_sidle(void); | |||
| 409 | void dispc_lcd_enable_signal_polarity(bool act_high); | 380 | void dispc_lcd_enable_signal_polarity(bool act_high); |
| 410 | void dispc_lcd_enable_signal(bool enable); | 381 | void dispc_lcd_enable_signal(bool enable); |
| 411 | void dispc_pck_free_enable(bool enable); | 382 | void dispc_pck_free_enable(bool enable); |
| 412 | void dispc_set_digit_size(u16 width, u16 height); | ||
| 413 | void dispc_enable_fifomerge(bool enable); | 383 | void dispc_enable_fifomerge(bool enable); |
| 414 | void dispc_enable_gamma_table(bool enable); | 384 | void dispc_enable_gamma_table(bool enable); |
| 415 | void dispc_set_loadmode(enum omap_dss_load_mode mode); | 385 | void dispc_set_loadmode(enum omap_dss_load_mode mode); |
| 416 | 386 | ||
| 417 | bool dispc_lcd_timings_ok(struct omap_video_timings *timings); | 387 | bool dispc_mgr_timings_ok(enum omap_channel channel, |
| 388 | const struct omap_video_timings *timings); | ||
| 418 | unsigned long dispc_fclk_rate(void); | 389 | unsigned long dispc_fclk_rate(void); |
| 419 | void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, | 390 | void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, |
| 420 | struct dispc_clock_info *cinfo); | 391 | struct dispc_clock_info *cinfo); |
| @@ -424,15 +395,16 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
| 424 | 395 | ||
| 425 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | 396 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); |
| 426 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | 397 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, |
| 427 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge); | 398 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, |
| 399 | bool manual_update); | ||
| 428 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 400 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
| 429 | bool ilace, bool replication); | 401 | bool ilace, bool replication, |
| 402 | const struct omap_video_timings *mgr_timings); | ||
| 430 | int dispc_ovl_enable(enum omap_plane plane, bool enable); | 403 | int dispc_ovl_enable(enum omap_plane plane, bool enable); |
| 431 | void dispc_ovl_set_channel_out(enum omap_plane plane, | 404 | void dispc_ovl_set_channel_out(enum omap_plane plane, |
| 432 | enum omap_channel channel); | 405 | enum omap_channel channel); |
| 433 | 406 | ||
| 434 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); | 407 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); |
| 435 | void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); | ||
| 436 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); | 408 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); |
| 437 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); | 409 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); |
| 438 | bool dispc_mgr_go_busy(enum omap_channel channel); | 410 | bool dispc_mgr_go_busy(enum omap_channel channel); |
| @@ -445,12 +417,13 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); | |||
| 445 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); | 417 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); |
| 446 | void dispc_mgr_set_lcd_display_type(enum omap_channel channel, | 418 | void dispc_mgr_set_lcd_display_type(enum omap_channel channel, |
| 447 | enum omap_lcd_display_type type); | 419 | enum omap_lcd_display_type type); |
| 448 | void dispc_mgr_set_lcd_timings(enum omap_channel channel, | 420 | void dispc_mgr_set_timings(enum omap_channel channel, |
| 449 | struct omap_video_timings *timings); | 421 | struct omap_video_timings *timings); |
| 450 | void dispc_mgr_set_pol_freq(enum omap_channel channel, | 422 | void dispc_mgr_set_pol_freq(enum omap_channel channel, |
| 451 | enum omap_panel_config config, u8 acbi, u8 acb); | 423 | enum omap_panel_config config, u8 acbi, u8 acb); |
| 452 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); | 424 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); |
| 453 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); | 425 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); |
| 426 | unsigned long dispc_core_clk_rate(void); | ||
| 454 | int dispc_mgr_set_clock_div(enum omap_channel channel, | 427 | int dispc_mgr_set_clock_div(enum omap_channel channel, |
| 455 | struct dispc_clock_info *cinfo); | 428 | struct dispc_clock_info *cinfo); |
| 456 | int dispc_mgr_get_clock_div(enum omap_channel channel, | 429 | int dispc_mgr_get_clock_div(enum omap_channel channel, |
| @@ -460,19 +433,10 @@ void dispc_mgr_setup(enum omap_channel channel, | |||
| 460 | 433 | ||
| 461 | /* VENC */ | 434 | /* VENC */ |
| 462 | #ifdef CONFIG_OMAP2_DSS_VENC | 435 | #ifdef CONFIG_OMAP2_DSS_VENC |
| 463 | int venc_init_platform_driver(void); | 436 | int venc_init_platform_driver(void) __init; |
| 464 | void venc_uninit_platform_driver(void); | 437 | void venc_uninit_platform_driver(void) __exit; |
| 465 | void venc_dump_regs(struct seq_file *s); | ||
| 466 | int venc_init_display(struct omap_dss_device *display); | ||
| 467 | unsigned long venc_get_pixel_clock(void); | 438 | unsigned long venc_get_pixel_clock(void); |
| 468 | #else | 439 | #else |
| 469 | static inline int venc_init_platform_driver(void) | ||
| 470 | { | ||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | static inline void venc_uninit_platform_driver(void) | ||
| 474 | { | ||
| 475 | } | ||
| 476 | static inline unsigned long venc_get_pixel_clock(void) | 440 | static inline unsigned long venc_get_pixel_clock(void) |
| 477 | { | 441 | { |
| 478 | WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__); | 442 | WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__); |
| @@ -482,23 +446,10 @@ static inline unsigned long venc_get_pixel_clock(void) | |||
| 482 | 446 | ||
| 483 | /* HDMI */ | 447 | /* HDMI */ |
| 484 | #ifdef CONFIG_OMAP4_DSS_HDMI | 448 | #ifdef CONFIG_OMAP4_DSS_HDMI |
| 485 | int hdmi_init_platform_driver(void); | 449 | int hdmi_init_platform_driver(void) __init; |
| 486 | void hdmi_uninit_platform_driver(void); | 450 | void hdmi_uninit_platform_driver(void) __exit; |
| 487 | int hdmi_init_display(struct omap_dss_device *dssdev); | ||
| 488 | unsigned long hdmi_get_pixel_clock(void); | 451 | unsigned long hdmi_get_pixel_clock(void); |
| 489 | void hdmi_dump_regs(struct seq_file *s); | ||
| 490 | #else | 452 | #else |
| 491 | static inline int hdmi_init_display(struct omap_dss_device *dssdev) | ||
| 492 | { | ||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | static inline int hdmi_init_platform_driver(void) | ||
| 496 | { | ||
| 497 | return 0; | ||
| 498 | } | ||
| 499 | static inline void hdmi_uninit_platform_driver(void) | ||
| 500 | { | ||
| 501 | } | ||
| 502 | static inline unsigned long hdmi_get_pixel_clock(void) | 453 | static inline unsigned long hdmi_get_pixel_clock(void) |
| 503 | { | 454 | { |
| 504 | WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__); | 455 | WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__); |
| @@ -514,22 +465,18 @@ int omapdss_hdmi_read_edid(u8 *buf, int len); | |||
| 514 | bool omapdss_hdmi_detect(void); | 465 | bool omapdss_hdmi_detect(void); |
| 515 | int hdmi_panel_init(void); | 466 | int hdmi_panel_init(void); |
| 516 | void hdmi_panel_exit(void); | 467 | void hdmi_panel_exit(void); |
| 468 | #ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO | ||
| 469 | int hdmi_audio_enable(void); | ||
| 470 | void hdmi_audio_disable(void); | ||
| 471 | int hdmi_audio_start(void); | ||
| 472 | void hdmi_audio_stop(void); | ||
| 473 | bool hdmi_mode_has_audio(void); | ||
| 474 | int hdmi_audio_config(struct omap_dss_audio *audio); | ||
| 475 | #endif | ||
| 517 | 476 | ||
| 518 | /* RFBI */ | 477 | /* RFBI */ |
| 519 | #ifdef CONFIG_OMAP2_DSS_RFBI | 478 | int rfbi_init_platform_driver(void) __init; |
| 520 | int rfbi_init_platform_driver(void); | 479 | void rfbi_uninit_platform_driver(void) __exit; |
| 521 | void rfbi_uninit_platform_driver(void); | ||
| 522 | void rfbi_dump_regs(struct seq_file *s); | ||
| 523 | int rfbi_init_display(struct omap_dss_device *display); | ||
| 524 | #else | ||
| 525 | static inline int rfbi_init_platform_driver(void) | ||
| 526 | { | ||
| 527 | return 0; | ||
| 528 | } | ||
| 529 | static inline void rfbi_uninit_platform_driver(void) | ||
| 530 | { | ||
| 531 | } | ||
| 532 | #endif | ||
| 533 | 480 | ||
| 534 | 481 | ||
| 535 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 482 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index ce14aa6dd672..938709724f0c 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
| @@ -52,6 +52,8 @@ struct omap_dss_features { | |||
| 52 | const char * const *clksrc_names; | 52 | const char * const *clksrc_names; |
| 53 | const struct dss_param_range *dss_params; | 53 | const struct dss_param_range *dss_params; |
| 54 | 54 | ||
| 55 | const enum omap_dss_rotation_type supported_rotation_types; | ||
| 56 | |||
| 55 | const u32 buffer_size_unit; | 57 | const u32 buffer_size_unit; |
| 56 | const u32 burst_size_unit; | 58 | const u32 burst_size_unit; |
| 57 | }; | 59 | }; |
| @@ -311,6 +313,8 @@ static const struct dss_param_range omap2_dss_param_range[] = { | |||
| 311 | * scaler cannot scale a image with width more than 768. | 313 | * scaler cannot scale a image with width more than 768. |
| 312 | */ | 314 | */ |
| 313 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, | 315 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, |
| 316 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 317 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 314 | }; | 318 | }; |
| 315 | 319 | ||
| 316 | static const struct dss_param_range omap3_dss_param_range[] = { | 320 | static const struct dss_param_range omap3_dss_param_range[] = { |
| @@ -324,6 +328,8 @@ static const struct dss_param_range omap3_dss_param_range[] = { | |||
| 324 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, | 328 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, |
| 325 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 329 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| 326 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | 330 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, |
| 331 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 332 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 327 | }; | 333 | }; |
| 328 | 334 | ||
| 329 | static const struct dss_param_range omap4_dss_param_range[] = { | 335 | static const struct dss_param_range omap4_dss_param_range[] = { |
| @@ -337,6 +343,8 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
| 337 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 343 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
| 338 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 344 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| 339 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | 345 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, |
| 346 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 347 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 340 | }; | 348 | }; |
| 341 | 349 | ||
| 342 | static const enum dss_feat_id omap2_dss_feat_list[] = { | 350 | static const enum dss_feat_id omap2_dss_feat_list[] = { |
| @@ -399,6 +407,7 @@ static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = { | |||
| 399 | FEAT_FIR_COEF_V, | 407 | FEAT_FIR_COEF_V, |
| 400 | FEAT_ALPHA_FREE_ZORDER, | 408 | FEAT_ALPHA_FREE_ZORDER, |
| 401 | FEAT_FIFO_MERGE, | 409 | FEAT_FIFO_MERGE, |
| 410 | FEAT_BURST_2D, | ||
| 402 | }; | 411 | }; |
| 403 | 412 | ||
| 404 | static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = { | 413 | static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = { |
| @@ -416,6 +425,7 @@ static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = { | |||
| 416 | FEAT_FIR_COEF_V, | 425 | FEAT_FIR_COEF_V, |
| 417 | FEAT_ALPHA_FREE_ZORDER, | 426 | FEAT_ALPHA_FREE_ZORDER, |
| 418 | FEAT_FIFO_MERGE, | 427 | FEAT_FIFO_MERGE, |
| 428 | FEAT_BURST_2D, | ||
| 419 | }; | 429 | }; |
| 420 | 430 | ||
| 421 | static const enum dss_feat_id omap4_dss_feat_list[] = { | 431 | static const enum dss_feat_id omap4_dss_feat_list[] = { |
| @@ -434,6 +444,7 @@ static const enum dss_feat_id omap4_dss_feat_list[] = { | |||
| 434 | FEAT_FIR_COEF_V, | 444 | FEAT_FIR_COEF_V, |
| 435 | FEAT_ALPHA_FREE_ZORDER, | 445 | FEAT_ALPHA_FREE_ZORDER, |
| 436 | FEAT_FIFO_MERGE, | 446 | FEAT_FIFO_MERGE, |
| 447 | FEAT_BURST_2D, | ||
| 437 | }; | 448 | }; |
| 438 | 449 | ||
| 439 | /* OMAP2 DSS Features */ | 450 | /* OMAP2 DSS Features */ |
| @@ -451,6 +462,7 @@ static const struct omap_dss_features omap2_dss_features = { | |||
| 451 | .overlay_caps = omap2_dss_overlay_caps, | 462 | .overlay_caps = omap2_dss_overlay_caps, |
| 452 | .clksrc_names = omap2_dss_clk_source_names, | 463 | .clksrc_names = omap2_dss_clk_source_names, |
| 453 | .dss_params = omap2_dss_param_range, | 464 | .dss_params = omap2_dss_param_range, |
| 465 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
| 454 | .buffer_size_unit = 1, | 466 | .buffer_size_unit = 1, |
| 455 | .burst_size_unit = 8, | 467 | .burst_size_unit = 8, |
| 456 | }; | 468 | }; |
| @@ -470,6 +482,7 @@ static const struct omap_dss_features omap3430_dss_features = { | |||
| 470 | .overlay_caps = omap3430_dss_overlay_caps, | 482 | .overlay_caps = omap3430_dss_overlay_caps, |
| 471 | .clksrc_names = omap3_dss_clk_source_names, | 483 | .clksrc_names = omap3_dss_clk_source_names, |
| 472 | .dss_params = omap3_dss_param_range, | 484 | .dss_params = omap3_dss_param_range, |
| 485 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
| 473 | .buffer_size_unit = 1, | 486 | .buffer_size_unit = 1, |
| 474 | .burst_size_unit = 8, | 487 | .burst_size_unit = 8, |
| 475 | }; | 488 | }; |
| @@ -488,6 +501,7 @@ static const struct omap_dss_features omap3630_dss_features = { | |||
| 488 | .overlay_caps = omap3630_dss_overlay_caps, | 501 | .overlay_caps = omap3630_dss_overlay_caps, |
| 489 | .clksrc_names = omap3_dss_clk_source_names, | 502 | .clksrc_names = omap3_dss_clk_source_names, |
| 490 | .dss_params = omap3_dss_param_range, | 503 | .dss_params = omap3_dss_param_range, |
| 504 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
| 491 | .buffer_size_unit = 1, | 505 | .buffer_size_unit = 1, |
| 492 | .burst_size_unit = 8, | 506 | .burst_size_unit = 8, |
| 493 | }; | 507 | }; |
| @@ -508,6 +522,7 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { | |||
| 508 | .overlay_caps = omap4_dss_overlay_caps, | 522 | .overlay_caps = omap4_dss_overlay_caps, |
| 509 | .clksrc_names = omap4_dss_clk_source_names, | 523 | .clksrc_names = omap4_dss_clk_source_names, |
| 510 | .dss_params = omap4_dss_param_range, | 524 | .dss_params = omap4_dss_param_range, |
| 525 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
| 511 | .buffer_size_unit = 16, | 526 | .buffer_size_unit = 16, |
| 512 | .burst_size_unit = 16, | 527 | .burst_size_unit = 16, |
| 513 | }; | 528 | }; |
| @@ -527,6 +542,7 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { | |||
| 527 | .overlay_caps = omap4_dss_overlay_caps, | 542 | .overlay_caps = omap4_dss_overlay_caps, |
| 528 | .clksrc_names = omap4_dss_clk_source_names, | 543 | .clksrc_names = omap4_dss_clk_source_names, |
| 529 | .dss_params = omap4_dss_param_range, | 544 | .dss_params = omap4_dss_param_range, |
| 545 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
| 530 | .buffer_size_unit = 16, | 546 | .buffer_size_unit = 16, |
| 531 | .burst_size_unit = 16, | 547 | .burst_size_unit = 16, |
| 532 | }; | 548 | }; |
| @@ -546,6 +562,7 @@ static const struct omap_dss_features omap4_dss_features = { | |||
| 546 | .overlay_caps = omap4_dss_overlay_caps, | 562 | .overlay_caps = omap4_dss_overlay_caps, |
| 547 | .clksrc_names = omap4_dss_clk_source_names, | 563 | .clksrc_names = omap4_dss_clk_source_names, |
| 548 | .dss_params = omap4_dss_param_range, | 564 | .dss_params = omap4_dss_param_range, |
| 565 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
| 549 | .buffer_size_unit = 16, | 566 | .buffer_size_unit = 16, |
| 550 | .burst_size_unit = 16, | 567 | .burst_size_unit = 16, |
| 551 | }; | 568 | }; |
| @@ -562,13 +579,17 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | |||
| 562 | .pll_enable = ti_hdmi_4xxx_pll_enable, | 579 | .pll_enable = ti_hdmi_4xxx_pll_enable, |
| 563 | .pll_disable = ti_hdmi_4xxx_pll_disable, | 580 | .pll_disable = ti_hdmi_4xxx_pll_disable, |
| 564 | .video_enable = ti_hdmi_4xxx_wp_video_start, | 581 | .video_enable = ti_hdmi_4xxx_wp_video_start, |
| 582 | .video_disable = ti_hdmi_4xxx_wp_video_stop, | ||
| 565 | .dump_wrapper = ti_hdmi_4xxx_wp_dump, | 583 | .dump_wrapper = ti_hdmi_4xxx_wp_dump, |
| 566 | .dump_core = ti_hdmi_4xxx_core_dump, | 584 | .dump_core = ti_hdmi_4xxx_core_dump, |
| 567 | .dump_pll = ti_hdmi_4xxx_pll_dump, | 585 | .dump_pll = ti_hdmi_4xxx_pll_dump, |
| 568 | .dump_phy = ti_hdmi_4xxx_phy_dump, | 586 | .dump_phy = ti_hdmi_4xxx_phy_dump, |
| 569 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 587 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
| 570 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
| 571 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, | 588 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, |
| 589 | .audio_disable = ti_hdmi_4xxx_wp_audio_disable, | ||
| 590 | .audio_start = ti_hdmi_4xxx_audio_start, | ||
| 591 | .audio_stop = ti_hdmi_4xxx_audio_stop, | ||
| 592 | .audio_config = ti_hdmi_4xxx_audio_config, | ||
| 572 | #endif | 593 | #endif |
| 573 | 594 | ||
| 574 | }; | 595 | }; |
| @@ -662,6 +683,11 @@ void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) | |||
| 662 | *end = omap_current_dss_features->reg_fields[id].end; | 683 | *end = omap_current_dss_features->reg_fields[id].end; |
| 663 | } | 684 | } |
| 664 | 685 | ||
| 686 | bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type) | ||
| 687 | { | ||
| 688 | return omap_current_dss_features->supported_rotation_types & rot_type; | ||
| 689 | } | ||
| 690 | |||
| 665 | void dss_features_init(void) | 691 | void dss_features_init(void) |
| 666 | { | 692 | { |
| 667 | if (cpu_is_omap24xx()) | 693 | if (cpu_is_omap24xx()) |
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index c332e7ddfce1..bdf469f080e7 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
| @@ -62,6 +62,7 @@ enum dss_feat_id { | |||
| 62 | FEAT_FIFO_MERGE, | 62 | FEAT_FIFO_MERGE, |
| 63 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ | 63 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ |
| 64 | FEAT_OMAP3_DSI_FIFO_BUG, | 64 | FEAT_OMAP3_DSI_FIFO_BUG, |
| 65 | FEAT_BURST_2D, | ||
| 65 | }; | 66 | }; |
| 66 | 67 | ||
| 67 | /* DSS register field id */ | 68 | /* DSS register field id */ |
| @@ -91,6 +92,8 @@ enum dss_range_param { | |||
| 91 | FEAT_PARAM_DSIPLL_LPDIV, | 92 | FEAT_PARAM_DSIPLL_LPDIV, |
| 92 | FEAT_PARAM_DOWNSCALE, | 93 | FEAT_PARAM_DOWNSCALE, |
| 93 | FEAT_PARAM_LINEWIDTH, | 94 | FEAT_PARAM_LINEWIDTH, |
| 95 | FEAT_PARAM_MGR_WIDTH, | ||
| 96 | FEAT_PARAM_MGR_HEIGHT, | ||
| 94 | }; | 97 | }; |
| 95 | 98 | ||
| 96 | /* DSS Feature Functions */ | 99 | /* DSS Feature Functions */ |
| @@ -108,6 +111,8 @@ const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); | |||
| 108 | u32 dss_feat_get_buffer_size_unit(void); /* in bytes */ | 111 | u32 dss_feat_get_buffer_size_unit(void); /* in bytes */ |
| 109 | u32 dss_feat_get_burst_size_unit(void); /* in bytes */ | 112 | u32 dss_feat_get_burst_size_unit(void); /* in bytes */ |
| 110 | 113 | ||
| 114 | bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type); | ||
| 115 | |||
| 111 | bool dss_has_feature(enum dss_feat_id id); | 116 | bool dss_has_feature(enum dss_feat_id id); |
| 112 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); | 117 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); |
| 113 | void dss_features_init(void); | 118 | void dss_features_init(void); |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index c4b4f6950a92..8195c7166d20 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
| @@ -33,12 +33,6 @@ | |||
| 33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
| 34 | #include <linux/clk.h> | 34 | #include <linux/clk.h> |
| 35 | #include <video/omapdss.h> | 35 | #include <video/omapdss.h> |
| 36 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
| 37 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
| 38 | #include <sound/soc.h> | ||
| 39 | #include <sound/pcm_params.h> | ||
| 40 | #include "ti_hdmi_4xxx_ip.h" | ||
| 41 | #endif | ||
| 42 | 36 | ||
| 43 | #include "ti_hdmi.h" | 37 | #include "ti_hdmi.h" |
| 44 | #include "dss.h" | 38 | #include "dss.h" |
| @@ -63,7 +57,6 @@ | |||
| 63 | 57 | ||
| 64 | static struct { | 58 | static struct { |
| 65 | struct mutex lock; | 59 | struct mutex lock; |
| 66 | struct omap_display_platform_data *pdata; | ||
| 67 | struct platform_device *pdev; | 60 | struct platform_device *pdev; |
| 68 | struct hdmi_ip_data ip_data; | 61 | struct hdmi_ip_data ip_data; |
| 69 | 62 | ||
| @@ -130,25 +123,12 @@ static int hdmi_runtime_get(void) | |||
| 130 | 123 | ||
| 131 | DSSDBG("hdmi_runtime_get\n"); | 124 | DSSDBG("hdmi_runtime_get\n"); |
| 132 | 125 | ||
| 133 | /* | ||
| 134 | * HACK: Add dss_runtime_get() to ensure DSS clock domain is enabled. | ||
| 135 | * This should be removed later. | ||
| 136 | */ | ||
| 137 | r = dss_runtime_get(); | ||
| 138 | if (r < 0) | ||
| 139 | goto err_get_dss; | ||
| 140 | |||
| 141 | r = pm_runtime_get_sync(&hdmi.pdev->dev); | 126 | r = pm_runtime_get_sync(&hdmi.pdev->dev); |
| 142 | WARN_ON(r < 0); | 127 | WARN_ON(r < 0); |
| 143 | if (r < 0) | 128 | if (r < 0) |
| 144 | goto err_get_hdmi; | 129 | return r; |
| 145 | 130 | ||
| 146 | return 0; | 131 | return 0; |
| 147 | |||
| 148 | err_get_hdmi: | ||
| 149 | dss_runtime_put(); | ||
| 150 | err_get_dss: | ||
| 151 | return r; | ||
| 152 | } | 132 | } |
| 153 | 133 | ||
| 154 | static void hdmi_runtime_put(void) | 134 | static void hdmi_runtime_put(void) |
| @@ -159,15 +139,9 @@ static void hdmi_runtime_put(void) | |||
| 159 | 139 | ||
| 160 | r = pm_runtime_put_sync(&hdmi.pdev->dev); | 140 | r = pm_runtime_put_sync(&hdmi.pdev->dev); |
| 161 | WARN_ON(r < 0); | 141 | WARN_ON(r < 0); |
| 162 | |||
| 163 | /* | ||
| 164 | * HACK: This is added to complement the dss_runtime_get() call in | ||
| 165 | * hdmi_runtime_get(). This should be removed later. | ||
| 166 | */ | ||
| 167 | dss_runtime_put(); | ||
| 168 | } | 142 | } |
| 169 | 143 | ||
| 170 | int hdmi_init_display(struct omap_dss_device *dssdev) | 144 | static int __init hdmi_init_display(struct omap_dss_device *dssdev) |
| 171 | { | 145 | { |
| 172 | DSSDBG("init_display\n"); | 146 | DSSDBG("init_display\n"); |
| 173 | 147 | ||
| @@ -344,7 +318,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
| 344 | 318 | ||
| 345 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); | 319 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); |
| 346 | 320 | ||
| 347 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 321 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
| 348 | 322 | ||
| 349 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ | 323 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ |
| 350 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); | 324 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); |
| @@ -376,10 +350,11 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
| 376 | dispc_enable_gamma_table(0); | 350 | dispc_enable_gamma_table(0); |
| 377 | 351 | ||
| 378 | /* tv size */ | 352 | /* tv size */ |
| 379 | dispc_set_digit_size(dssdev->panel.timings.x_res, | 353 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); |
| 380 | dssdev->panel.timings.y_res); | ||
| 381 | 354 | ||
| 382 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); | 355 | r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); |
| 356 | if (r) | ||
| 357 | goto err_vid_enable; | ||
| 383 | 358 | ||
| 384 | r = dss_mgr_enable(dssdev->manager); | 359 | r = dss_mgr_enable(dssdev->manager); |
| 385 | if (r) | 360 | if (r) |
| @@ -388,7 +363,8 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
| 388 | return 0; | 363 | return 0; |
| 389 | 364 | ||
| 390 | err_mgr_enable: | 365 | err_mgr_enable: |
| 391 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 366 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
| 367 | err_vid_enable: | ||
| 392 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 368 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
| 393 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 369 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
| 394 | err: | 370 | err: |
| @@ -400,7 +376,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) | |||
| 400 | { | 376 | { |
| 401 | dss_mgr_disable(dssdev->manager); | 377 | dss_mgr_disable(dssdev->manager); |
| 402 | 378 | ||
| 403 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 379 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
| 404 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 380 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
| 405 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 381 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
| 406 | hdmi_runtime_put(); | 382 | hdmi_runtime_put(); |
| @@ -436,10 +412,12 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) | |||
| 436 | r = hdmi_power_on(dssdev); | 412 | r = hdmi_power_on(dssdev); |
| 437 | if (r) | 413 | if (r) |
| 438 | DSSERR("failed to power on device\n"); | 414 | DSSERR("failed to power on device\n"); |
| 415 | } else { | ||
| 416 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); | ||
| 439 | } | 417 | } |
| 440 | } | 418 | } |
| 441 | 419 | ||
| 442 | void hdmi_dump_regs(struct seq_file *s) | 420 | static void hdmi_dump_regs(struct seq_file *s) |
| 443 | { | 421 | { |
| 444 | mutex_lock(&hdmi.lock); | 422 | mutex_lock(&hdmi.lock); |
| 445 | 423 | ||
| @@ -555,248 +533,201 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
| 555 | mutex_unlock(&hdmi.lock); | 533 | mutex_unlock(&hdmi.lock); |
| 556 | } | 534 | } |
| 557 | 535 | ||
| 558 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 536 | static int hdmi_get_clocks(struct platform_device *pdev) |
| 559 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
| 560 | |||
| 561 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, | ||
| 562 | struct snd_soc_dai *dai) | ||
| 563 | { | 537 | { |
| 564 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 538 | struct clk *clk; |
| 565 | struct snd_soc_codec *codec = rtd->codec; | ||
| 566 | struct platform_device *pdev = to_platform_device(codec->dev); | ||
| 567 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
| 568 | int err = 0; | ||
| 569 | 539 | ||
| 570 | if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) { | 540 | clk = clk_get(&pdev->dev, "sys_clk"); |
| 571 | dev_err(&pdev->dev, "Cannot enable/disable audio\n"); | 541 | if (IS_ERR(clk)) { |
| 572 | return -ENODEV; | 542 | DSSERR("can't get sys_clk\n"); |
| 543 | return PTR_ERR(clk); | ||
| 573 | } | 544 | } |
| 574 | 545 | ||
| 575 | switch (cmd) { | 546 | hdmi.sys_clk = clk; |
| 576 | case SNDRV_PCM_TRIGGER_START: | 547 | |
| 577 | case SNDRV_PCM_TRIGGER_RESUME: | 548 | return 0; |
| 578 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 549 | } |
| 579 | ip_data->ops->audio_enable(ip_data, true); | 550 | |
| 580 | break; | 551 | static void hdmi_put_clocks(void) |
| 581 | case SNDRV_PCM_TRIGGER_STOP: | 552 | { |
| 582 | case SNDRV_PCM_TRIGGER_SUSPEND: | 553 | if (hdmi.sys_clk) |
| 583 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 554 | clk_put(hdmi.sys_clk); |
| 584 | ip_data->ops->audio_enable(ip_data, false); | 555 | } |
| 585 | break; | 556 | |
| 586 | default: | 557 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
| 587 | err = -EINVAL; | 558 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) |
| 588 | } | 559 | { |
| 589 | return err; | 560 | u32 deep_color; |
| 590 | } | 561 | bool deep_color_correct = false; |
| 591 | 562 | u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock; | |
| 592 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | 563 | |
| 593 | struct snd_pcm_hw_params *params, | 564 | if (n == NULL || cts == NULL) |
| 594 | struct snd_soc_dai *dai) | ||
| 595 | { | ||
| 596 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 597 | struct snd_soc_codec *codec = rtd->codec; | ||
| 598 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
| 599 | struct hdmi_audio_format audio_format; | ||
| 600 | struct hdmi_audio_dma audio_dma; | ||
| 601 | struct hdmi_core_audio_config core_cfg; | ||
| 602 | struct hdmi_core_infoframe_audio aud_if_cfg; | ||
| 603 | int err, n, cts; | ||
| 604 | enum hdmi_core_audio_sample_freq sample_freq; | ||
| 605 | |||
| 606 | switch (params_format(params)) { | ||
| 607 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 608 | core_cfg.i2s_cfg.word_max_length = | ||
| 609 | HDMI_AUDIO_I2S_MAX_WORD_20BITS; | ||
| 610 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; | ||
| 611 | core_cfg.i2s_cfg.in_length_bits = | ||
| 612 | HDMI_AUDIO_I2S_INPUT_LENGTH_16; | ||
| 613 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
| 614 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
| 615 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
| 616 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
| 617 | audio_dma.transfer_size = 0x10; | ||
| 618 | break; | ||
| 619 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 620 | core_cfg.i2s_cfg.word_max_length = | ||
| 621 | HDMI_AUDIO_I2S_MAX_WORD_24BITS; | ||
| 622 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; | ||
| 623 | core_cfg.i2s_cfg.in_length_bits = | ||
| 624 | HDMI_AUDIO_I2S_INPUT_LENGTH_24; | ||
| 625 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
| 626 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
| 627 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
| 628 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
| 629 | audio_dma.transfer_size = 0x20; | ||
| 630 | break; | ||
| 631 | default: | ||
| 632 | return -EINVAL; | 565 | return -EINVAL; |
| 633 | } | ||
| 634 | 566 | ||
| 635 | switch (params_rate(params)) { | 567 | /* TODO: When implemented, query deep color mode here. */ |
| 568 | deep_color = 100; | ||
| 569 | |||
| 570 | /* | ||
| 571 | * When using deep color, the default N value (as in the HDMI | ||
| 572 | * specification) yields to an non-integer CTS. Hence, we | ||
| 573 | * modify it while keeping the restrictions described in | ||
| 574 | * section 7.2.1 of the HDMI 1.4a specification. | ||
| 575 | */ | ||
| 576 | switch (sample_freq) { | ||
| 636 | case 32000: | 577 | case 32000: |
| 637 | sample_freq = HDMI_AUDIO_FS_32000; | 578 | case 48000: |
| 579 | case 96000: | ||
| 580 | case 192000: | ||
| 581 | if (deep_color == 125) | ||
| 582 | if (pclk == 27027 || pclk == 74250) | ||
| 583 | deep_color_correct = true; | ||
| 584 | if (deep_color == 150) | ||
| 585 | if (pclk == 27027) | ||
| 586 | deep_color_correct = true; | ||
| 638 | break; | 587 | break; |
| 639 | case 44100: | 588 | case 44100: |
| 640 | sample_freq = HDMI_AUDIO_FS_44100; | 589 | case 88200: |
| 641 | break; | 590 | case 176400: |
| 642 | case 48000: | 591 | if (deep_color == 125) |
| 643 | sample_freq = HDMI_AUDIO_FS_48000; | 592 | if (pclk == 27027) |
| 593 | deep_color_correct = true; | ||
| 644 | break; | 594 | break; |
| 645 | default: | 595 | default: |
| 646 | return -EINVAL; | 596 | return -EINVAL; |
| 647 | } | 597 | } |
| 648 | 598 | ||
| 649 | err = hdmi_config_audio_acr(ip_data, params_rate(params), &n, &cts); | 599 | if (deep_color_correct) { |
| 650 | if (err < 0) | 600 | switch (sample_freq) { |
| 651 | return err; | 601 | case 32000: |
| 652 | 602 | *n = 8192; | |
| 653 | /* Audio wrapper config */ | 603 | break; |
| 654 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | 604 | case 44100: |
| 655 | audio_format.active_chnnls_msk = 0x03; | 605 | *n = 12544; |
| 656 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | 606 | break; |
| 657 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | 607 | case 48000: |
| 658 | /* Disable start/stop signals of IEC 60958 blocks */ | 608 | *n = 8192; |
| 659 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; | 609 | break; |
| 610 | case 88200: | ||
| 611 | *n = 25088; | ||
| 612 | break; | ||
| 613 | case 96000: | ||
| 614 | *n = 16384; | ||
| 615 | break; | ||
| 616 | case 176400: | ||
| 617 | *n = 50176; | ||
| 618 | break; | ||
| 619 | case 192000: | ||
| 620 | *n = 32768; | ||
| 621 | break; | ||
| 622 | default: | ||
| 623 | return -EINVAL; | ||
| 624 | } | ||
| 625 | } else { | ||
| 626 | switch (sample_freq) { | ||
| 627 | case 32000: | ||
| 628 | *n = 4096; | ||
| 629 | break; | ||
| 630 | case 44100: | ||
| 631 | *n = 6272; | ||
| 632 | break; | ||
| 633 | case 48000: | ||
| 634 | *n = 6144; | ||
| 635 | break; | ||
| 636 | case 88200: | ||
| 637 | *n = 12544; | ||
| 638 | break; | ||
| 639 | case 96000: | ||
| 640 | *n = 12288; | ||
| 641 | break; | ||
| 642 | case 176400: | ||
| 643 | *n = 25088; | ||
| 644 | break; | ||
| 645 | case 192000: | ||
| 646 | *n = 24576; | ||
| 647 | break; | ||
| 648 | default: | ||
| 649 | return -EINVAL; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ | ||
| 653 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); | ||
| 660 | 654 | ||
| 661 | audio_dma.block_size = 0xC0; | 655 | return 0; |
| 662 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | 656 | } |
| 663 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
| 664 | 657 | ||
| 665 | hdmi_wp_audio_config_dma(ip_data, &audio_dma); | 658 | int hdmi_audio_enable(void) |
| 666 | hdmi_wp_audio_config_format(ip_data, &audio_format); | 659 | { |
| 660 | DSSDBG("audio_enable\n"); | ||
| 667 | 661 | ||
| 668 | /* | 662 | return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data); |
| 669 | * I2S config | 663 | } |
| 670 | */ | ||
| 671 | core_cfg.i2s_cfg.en_high_bitrate_aud = false; | ||
| 672 | /* Only used with high bitrate audio */ | ||
| 673 | core_cfg.i2s_cfg.cbit_order = false; | ||
| 674 | /* Serial data and word select should change on sck rising edge */ | ||
| 675 | core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
| 676 | core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
| 677 | /* Set I2S word select polarity */ | ||
| 678 | core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; | ||
| 679 | core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
| 680 | /* Set serial data to word select shift. See Phillips spec. */ | ||
| 681 | core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
| 682 | /* Enable one of the four available serial data channels */ | ||
| 683 | core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
| 684 | |||
| 685 | /* Core audio config */ | ||
| 686 | core_cfg.freq_sample = sample_freq; | ||
| 687 | core_cfg.n = n; | ||
| 688 | core_cfg.cts = cts; | ||
| 689 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | ||
| 690 | core_cfg.aud_par_busclk = 0; | ||
| 691 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
| 692 | core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); | ||
| 693 | } else { | ||
| 694 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
| 695 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
| 696 | core_cfg.use_mclk = true; | ||
| 697 | } | ||
| 698 | 664 | ||
| 699 | if (core_cfg.use_mclk) | 665 | void hdmi_audio_disable(void) |
| 700 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | 666 | { |
| 701 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | 667 | DSSDBG("audio_disable\n"); |
| 702 | core_cfg.en_spdif = false; | ||
| 703 | /* Use sample frequency from channel status word */ | ||
| 704 | core_cfg.fs_override = true; | ||
| 705 | /* Enable ACR packets */ | ||
| 706 | core_cfg.en_acr_pkt = true; | ||
| 707 | /* Disable direct streaming digital audio */ | ||
| 708 | core_cfg.en_dsd_audio = false; | ||
| 709 | /* Use parallel audio interface */ | ||
| 710 | core_cfg.en_parallel_aud_input = true; | ||
| 711 | |||
| 712 | hdmi_core_audio_config(ip_data, &core_cfg); | ||
| 713 | 668 | ||
| 714 | /* | 669 | hdmi.ip_data.ops->audio_disable(&hdmi.ip_data); |
| 715 | * Configure packet | ||
| 716 | * info frame audio see doc CEA861-D page 74 | ||
| 717 | */ | ||
| 718 | aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; | ||
| 719 | aud_if_cfg.db1_channel_count = 2; | ||
| 720 | aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; | ||
| 721 | aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; | ||
| 722 | aud_if_cfg.db4_channel_alloc = 0x00; | ||
| 723 | aud_if_cfg.db5_downmix_inh = false; | ||
| 724 | aud_if_cfg.db5_lsv = 0; | ||
| 725 | |||
| 726 | hdmi_core_audio_infoframe_config(ip_data, &aud_if_cfg); | ||
| 727 | return 0; | ||
| 728 | } | 670 | } |
| 729 | 671 | ||
| 730 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, | 672 | int hdmi_audio_start(void) |
| 731 | struct snd_soc_dai *dai) | ||
| 732 | { | 673 | { |
| 733 | if (!hdmi.ip_data.cfg.cm.mode) { | 674 | DSSDBG("audio_start\n"); |
| 734 | pr_err("Current video settings do not support audio.\n"); | 675 | |
| 735 | return -EIO; | 676 | return hdmi.ip_data.ops->audio_start(&hdmi.ip_data); |
| 736 | } | ||
| 737 | return 0; | ||
| 738 | } | 677 | } |
| 739 | 678 | ||
| 740 | static int hdmi_audio_codec_probe(struct snd_soc_codec *codec) | 679 | void hdmi_audio_stop(void) |
| 741 | { | 680 | { |
| 742 | struct hdmi_ip_data *priv = &hdmi.ip_data; | 681 | DSSDBG("audio_stop\n"); |
| 743 | 682 | ||
| 744 | snd_soc_codec_set_drvdata(codec, priv); | 683 | hdmi.ip_data.ops->audio_stop(&hdmi.ip_data); |
| 745 | return 0; | ||
| 746 | } | 684 | } |
| 747 | 685 | ||
| 748 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { | 686 | bool hdmi_mode_has_audio(void) |
| 749 | .probe = hdmi_audio_codec_probe, | 687 | { |
| 750 | }; | 688 | if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI) |
| 689 | return true; | ||
| 690 | else | ||
| 691 | return false; | ||
| 692 | } | ||
| 751 | 693 | ||
| 752 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { | 694 | int hdmi_audio_config(struct omap_dss_audio *audio) |
| 753 | .hw_params = hdmi_audio_hw_params, | 695 | { |
| 754 | .trigger = hdmi_audio_trigger, | 696 | return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio); |
| 755 | .startup = hdmi_audio_startup, | 697 | } |
| 756 | }; | ||
| 757 | 698 | ||
| 758 | static struct snd_soc_dai_driver hdmi_codec_dai_drv = { | ||
| 759 | .name = "hdmi-audio-codec", | ||
| 760 | .playback = { | ||
| 761 | .channels_min = 2, | ||
| 762 | .channels_max = 2, | ||
| 763 | .rates = SNDRV_PCM_RATE_32000 | | ||
| 764 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
| 765 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
| 766 | SNDRV_PCM_FMTBIT_S24_LE, | ||
| 767 | }, | ||
| 768 | .ops = &hdmi_audio_codec_ops, | ||
| 769 | }; | ||
| 770 | #endif | 699 | #endif |
| 771 | 700 | ||
| 772 | static int hdmi_get_clocks(struct platform_device *pdev) | 701 | static void __init hdmi_probe_pdata(struct platform_device *pdev) |
| 773 | { | 702 | { |
| 774 | struct clk *clk; | 703 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 704 | int r, i; | ||
| 775 | 705 | ||
| 776 | clk = clk_get(&pdev->dev, "sys_clk"); | 706 | for (i = 0; i < pdata->num_devices; ++i) { |
| 777 | if (IS_ERR(clk)) { | 707 | struct omap_dss_device *dssdev = pdata->devices[i]; |
| 778 | DSSERR("can't get sys_clk\n"); | ||
| 779 | return PTR_ERR(clk); | ||
| 780 | } | ||
| 781 | 708 | ||
| 782 | hdmi.sys_clk = clk; | 709 | if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) |
| 710 | continue; | ||
| 783 | 711 | ||
| 784 | return 0; | 712 | r = hdmi_init_display(dssdev); |
| 785 | } | 713 | if (r) { |
| 714 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
| 715 | continue; | ||
| 716 | } | ||
| 786 | 717 | ||
| 787 | static void hdmi_put_clocks(void) | 718 | r = omap_dss_register_device(dssdev, &pdev->dev, i); |
| 788 | { | 719 | if (r) |
| 789 | if (hdmi.sys_clk) | 720 | DSSERR("device %s register failed: %d\n", |
| 790 | clk_put(hdmi.sys_clk); | 721 | dssdev->name, r); |
| 722 | } | ||
| 791 | } | 723 | } |
| 792 | 724 | ||
| 793 | /* HDMI HW IP initialisation */ | 725 | /* HDMI HW IP initialisation */ |
| 794 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | 726 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) |
| 795 | { | 727 | { |
| 796 | struct resource *hdmi_mem; | 728 | struct resource *hdmi_mem; |
| 797 | int r; | 729 | int r; |
| 798 | 730 | ||
| 799 | hdmi.pdata = pdev->dev.platform_data; | ||
| 800 | hdmi.pdev = pdev; | 731 | hdmi.pdev = pdev; |
| 801 | 732 | ||
| 802 | mutex_init(&hdmi.lock); | 733 | mutex_init(&hdmi.lock); |
| @@ -830,28 +761,18 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 830 | 761 | ||
| 831 | hdmi_panel_init(); | 762 | hdmi_panel_init(); |
| 832 | 763 | ||
| 833 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 764 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
| 834 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 765 | |
| 766 | hdmi_probe_pdata(pdev); | ||
| 835 | 767 | ||
| 836 | /* Register ASoC codec DAI */ | ||
| 837 | r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, | ||
| 838 | &hdmi_codec_dai_drv, 1); | ||
| 839 | if (r) { | ||
| 840 | DSSERR("can't register ASoC HDMI audio codec\n"); | ||
| 841 | return r; | ||
| 842 | } | ||
| 843 | #endif | ||
| 844 | return 0; | 768 | return 0; |
| 845 | } | 769 | } |
| 846 | 770 | ||
| 847 | static int omapdss_hdmihw_remove(struct platform_device *pdev) | 771 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) |
| 848 | { | 772 | { |
| 849 | hdmi_panel_exit(); | 773 | omap_dss_unregister_child_devices(&pdev->dev); |
| 850 | 774 | ||
| 851 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 775 | hdmi_panel_exit(); |
| 852 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
| 853 | snd_soc_unregister_codec(&pdev->dev); | ||
| 854 | #endif | ||
| 855 | 776 | ||
| 856 | pm_runtime_disable(&pdev->dev); | 777 | pm_runtime_disable(&pdev->dev); |
| 857 | 778 | ||
| @@ -867,7 +788,6 @@ static int hdmi_runtime_suspend(struct device *dev) | |||
| 867 | clk_disable(hdmi.sys_clk); | 788 | clk_disable(hdmi.sys_clk); |
| 868 | 789 | ||
| 869 | dispc_runtime_put(); | 790 | dispc_runtime_put(); |
| 870 | dss_runtime_put(); | ||
| 871 | 791 | ||
| 872 | return 0; | 792 | return 0; |
| 873 | } | 793 | } |
| @@ -876,23 +796,13 @@ static int hdmi_runtime_resume(struct device *dev) | |||
| 876 | { | 796 | { |
| 877 | int r; | 797 | int r; |
| 878 | 798 | ||
| 879 | r = dss_runtime_get(); | ||
| 880 | if (r < 0) | ||
| 881 | goto err_get_dss; | ||
| 882 | |||
| 883 | r = dispc_runtime_get(); | 799 | r = dispc_runtime_get(); |
| 884 | if (r < 0) | 800 | if (r < 0) |
| 885 | goto err_get_dispc; | 801 | return r; |
| 886 | |||
| 887 | 802 | ||
| 888 | clk_enable(hdmi.sys_clk); | 803 | clk_enable(hdmi.sys_clk); |
| 889 | 804 | ||
| 890 | return 0; | 805 | return 0; |
| 891 | |||
| 892 | err_get_dispc: | ||
| 893 | dss_runtime_put(); | ||
| 894 | err_get_dss: | ||
| 895 | return r; | ||
| 896 | } | 806 | } |
| 897 | 807 | ||
| 898 | static const struct dev_pm_ops hdmi_pm_ops = { | 808 | static const struct dev_pm_ops hdmi_pm_ops = { |
| @@ -901,8 +811,7 @@ static const struct dev_pm_ops hdmi_pm_ops = { | |||
| 901 | }; | 811 | }; |
| 902 | 812 | ||
| 903 | static struct platform_driver omapdss_hdmihw_driver = { | 813 | static struct platform_driver omapdss_hdmihw_driver = { |
| 904 | .probe = omapdss_hdmihw_probe, | 814 | .remove = __exit_p(omapdss_hdmihw_remove), |
| 905 | .remove = omapdss_hdmihw_remove, | ||
| 906 | .driver = { | 815 | .driver = { |
| 907 | .name = "omapdss_hdmi", | 816 | .name = "omapdss_hdmi", |
| 908 | .owner = THIS_MODULE, | 817 | .owner = THIS_MODULE, |
| @@ -910,12 +819,12 @@ static struct platform_driver omapdss_hdmihw_driver = { | |||
| 910 | }, | 819 | }, |
| 911 | }; | 820 | }; |
| 912 | 821 | ||
| 913 | int hdmi_init_platform_driver(void) | 822 | int __init hdmi_init_platform_driver(void) |
| 914 | { | 823 | { |
| 915 | return platform_driver_register(&omapdss_hdmihw_driver); | 824 | return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe); |
| 916 | } | 825 | } |
| 917 | 826 | ||
| 918 | void hdmi_uninit_platform_driver(void) | 827 | void __exit hdmi_uninit_platform_driver(void) |
| 919 | { | 828 | { |
| 920 | return platform_driver_unregister(&omapdss_hdmihw_driver); | 829 | platform_driver_unregister(&omapdss_hdmihw_driver); |
| 921 | } | 830 | } |
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index 533d5dc634d2..1179e3c4b1c7 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c | |||
| @@ -30,7 +30,12 @@ | |||
| 30 | #include "dss.h" | 30 | #include "dss.h" |
| 31 | 31 | ||
| 32 | static struct { | 32 | static struct { |
| 33 | struct mutex hdmi_lock; | 33 | /* This protects the panel ops, mainly when accessing the HDMI IP. */ |
| 34 | struct mutex lock; | ||
| 35 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 36 | /* This protects the audio ops, specifically. */ | ||
| 37 | spinlock_t audio_lock; | ||
| 38 | #endif | ||
| 34 | } hdmi; | 39 | } hdmi; |
| 35 | 40 | ||
| 36 | 41 | ||
| @@ -54,12 +59,168 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev) | |||
| 54 | 59 | ||
| 55 | } | 60 | } |
| 56 | 61 | ||
| 62 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 63 | static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) | ||
| 64 | { | ||
| 65 | unsigned long flags; | ||
| 66 | int r; | ||
| 67 | |||
| 68 | mutex_lock(&hdmi.lock); | ||
| 69 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
| 70 | |||
| 71 | /* enable audio only if the display is active and supports audio */ | ||
| 72 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || | ||
| 73 | !hdmi_mode_has_audio()) { | ||
| 74 | DSSERR("audio not supported or display is off\n"); | ||
| 75 | r = -EPERM; | ||
| 76 | goto err; | ||
| 77 | } | ||
| 78 | |||
| 79 | r = hdmi_audio_enable(); | ||
| 80 | |||
| 81 | if (!r) | ||
| 82 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
| 83 | |||
| 84 | err: | ||
| 85 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
| 86 | mutex_unlock(&hdmi.lock); | ||
| 87 | return r; | ||
| 88 | } | ||
| 89 | |||
| 90 | static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) | ||
| 91 | { | ||
| 92 | unsigned long flags; | ||
| 93 | |||
| 94 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
| 95 | |||
| 96 | hdmi_audio_disable(); | ||
| 97 | |||
| 98 | dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED; | ||
| 99 | |||
| 100 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
| 101 | } | ||
| 102 | |||
| 103 | static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) | ||
| 104 | { | ||
| 105 | unsigned long flags; | ||
| 106 | int r; | ||
| 107 | |||
| 108 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
| 109 | /* | ||
| 110 | * No need to check the panel state. It was checked when trasitioning | ||
| 111 | * to AUDIO_ENABLED. | ||
| 112 | */ | ||
| 113 | if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) { | ||
| 114 | DSSERR("audio start from invalid state\n"); | ||
| 115 | r = -EPERM; | ||
| 116 | goto err; | ||
| 117 | } | ||
| 118 | |||
| 119 | r = hdmi_audio_start(); | ||
| 120 | |||
| 121 | if (!r) | ||
| 122 | dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING; | ||
| 123 | |||
| 124 | err: | ||
| 125 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
| 126 | return r; | ||
| 127 | } | ||
| 128 | |||
| 129 | static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) | ||
| 130 | { | ||
| 131 | unsigned long flags; | ||
| 132 | |||
| 133 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
| 134 | |||
| 135 | hdmi_audio_stop(); | ||
| 136 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
| 137 | |||
| 138 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
| 139 | } | ||
| 140 | |||
| 141 | static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) | ||
| 142 | { | ||
| 143 | bool r = false; | ||
| 144 | |||
| 145 | mutex_lock(&hdmi.lock); | ||
| 146 | |||
| 147 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
| 148 | goto err; | ||
| 149 | |||
| 150 | if (!hdmi_mode_has_audio()) | ||
| 151 | goto err; | ||
| 152 | |||
| 153 | r = true; | ||
| 154 | err: | ||
| 155 | mutex_unlock(&hdmi.lock); | ||
| 156 | return r; | ||
| 157 | } | ||
| 158 | |||
| 159 | static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, | ||
| 160 | struct omap_dss_audio *audio) | ||
| 161 | { | ||
| 162 | unsigned long flags; | ||
| 163 | int r; | ||
| 164 | |||
| 165 | mutex_lock(&hdmi.lock); | ||
| 166 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
| 167 | |||
| 168 | /* config audio only if the display is active and supports audio */ | ||
| 169 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || | ||
| 170 | !hdmi_mode_has_audio()) { | ||
| 171 | DSSERR("audio not supported or display is off\n"); | ||
| 172 | r = -EPERM; | ||
| 173 | goto err; | ||
| 174 | } | ||
| 175 | |||
| 176 | r = hdmi_audio_config(audio); | ||
| 177 | |||
| 178 | if (!r) | ||
| 179 | dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED; | ||
| 180 | |||
| 181 | err: | ||
| 182 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
| 183 | mutex_unlock(&hdmi.lock); | ||
| 184 | return r; | ||
| 185 | } | ||
| 186 | |||
| 187 | #else | ||
| 188 | static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) | ||
| 189 | { | ||
| 190 | return -EPERM; | ||
| 191 | } | ||
| 192 | |||
| 193 | static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) | ||
| 194 | { | ||
| 195 | } | ||
| 196 | |||
| 197 | static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) | ||
| 198 | { | ||
| 199 | return -EPERM; | ||
| 200 | } | ||
| 201 | |||
| 202 | static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) | ||
| 203 | { | ||
| 204 | } | ||
| 205 | |||
| 206 | static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) | ||
| 207 | { | ||
| 208 | return false; | ||
| 209 | } | ||
| 210 | |||
| 211 | static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, | ||
| 212 | struct omap_dss_audio *audio) | ||
| 213 | { | ||
| 214 | return -EPERM; | ||
| 215 | } | ||
| 216 | #endif | ||
| 217 | |||
| 57 | static int hdmi_panel_enable(struct omap_dss_device *dssdev) | 218 | static int hdmi_panel_enable(struct omap_dss_device *dssdev) |
| 58 | { | 219 | { |
| 59 | int r = 0; | 220 | int r = 0; |
| 60 | DSSDBG("ENTER hdmi_panel_enable\n"); | 221 | DSSDBG("ENTER hdmi_panel_enable\n"); |
| 61 | 222 | ||
| 62 | mutex_lock(&hdmi.hdmi_lock); | 223 | mutex_lock(&hdmi.lock); |
| 63 | 224 | ||
| 64 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | 225 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { |
| 65 | r = -EINVAL; | 226 | r = -EINVAL; |
| @@ -75,40 +236,52 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) | |||
| 75 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 236 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
| 76 | 237 | ||
| 77 | err: | 238 | err: |
| 78 | mutex_unlock(&hdmi.hdmi_lock); | 239 | mutex_unlock(&hdmi.lock); |
| 79 | 240 | ||
| 80 | return r; | 241 | return r; |
| 81 | } | 242 | } |
| 82 | 243 | ||
| 83 | static void hdmi_panel_disable(struct omap_dss_device *dssdev) | 244 | static void hdmi_panel_disable(struct omap_dss_device *dssdev) |
| 84 | { | 245 | { |
| 85 | mutex_lock(&hdmi.hdmi_lock); | 246 | mutex_lock(&hdmi.lock); |
| 86 | 247 | ||
| 87 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 248 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { |
| 249 | /* | ||
| 250 | * TODO: notify audio users that the display was disabled. For | ||
| 251 | * now, disable audio locally to not break our audio state | ||
| 252 | * machine. | ||
| 253 | */ | ||
| 254 | hdmi_panel_audio_disable(dssdev); | ||
| 88 | omapdss_hdmi_display_disable(dssdev); | 255 | omapdss_hdmi_display_disable(dssdev); |
| 256 | } | ||
| 89 | 257 | ||
| 90 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 258 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| 91 | 259 | ||
| 92 | mutex_unlock(&hdmi.hdmi_lock); | 260 | mutex_unlock(&hdmi.lock); |
| 93 | } | 261 | } |
| 94 | 262 | ||
| 95 | static int hdmi_panel_suspend(struct omap_dss_device *dssdev) | 263 | static int hdmi_panel_suspend(struct omap_dss_device *dssdev) |
| 96 | { | 264 | { |
| 97 | int r = 0; | 265 | int r = 0; |
| 98 | 266 | ||
| 99 | mutex_lock(&hdmi.hdmi_lock); | 267 | mutex_lock(&hdmi.lock); |
| 100 | 268 | ||
| 101 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 269 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
| 102 | r = -EINVAL; | 270 | r = -EINVAL; |
| 103 | goto err; | 271 | goto err; |
| 104 | } | 272 | } |
| 105 | 273 | ||
| 106 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | 274 | /* |
| 275 | * TODO: notify audio users that the display was suspended. For now, | ||
| 276 | * disable audio locally to not break our audio state machine. | ||
| 277 | */ | ||
| 278 | hdmi_panel_audio_disable(dssdev); | ||
| 107 | 279 | ||
| 280 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 108 | omapdss_hdmi_display_disable(dssdev); | 281 | omapdss_hdmi_display_disable(dssdev); |
| 109 | 282 | ||
| 110 | err: | 283 | err: |
| 111 | mutex_unlock(&hdmi.hdmi_lock); | 284 | mutex_unlock(&hdmi.lock); |
| 112 | 285 | ||
| 113 | return r; | 286 | return r; |
| 114 | } | 287 | } |
| @@ -117,7 +290,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev) | |||
| 117 | { | 290 | { |
| 118 | int r = 0; | 291 | int r = 0; |
| 119 | 292 | ||
| 120 | mutex_lock(&hdmi.hdmi_lock); | 293 | mutex_lock(&hdmi.lock); |
| 121 | 294 | ||
| 122 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { | 295 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { |
| 123 | r = -EINVAL; | 296 | r = -EINVAL; |
| @@ -129,11 +302,12 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev) | |||
| 129 | DSSERR("failed to power on\n"); | 302 | DSSERR("failed to power on\n"); |
| 130 | goto err; | 303 | goto err; |
| 131 | } | 304 | } |
| 305 | /* TODO: notify audio users that the panel resumed. */ | ||
| 132 | 306 | ||
| 133 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 307 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
| 134 | 308 | ||
| 135 | err: | 309 | err: |
| 136 | mutex_unlock(&hdmi.hdmi_lock); | 310 | mutex_unlock(&hdmi.lock); |
| 137 | 311 | ||
| 138 | return r; | 312 | return r; |
| 139 | } | 313 | } |
| @@ -141,11 +315,11 @@ err: | |||
| 141 | static void hdmi_get_timings(struct omap_dss_device *dssdev, | 315 | static void hdmi_get_timings(struct omap_dss_device *dssdev, |
| 142 | struct omap_video_timings *timings) | 316 | struct omap_video_timings *timings) |
| 143 | { | 317 | { |
| 144 | mutex_lock(&hdmi.hdmi_lock); | 318 | mutex_lock(&hdmi.lock); |
| 145 | 319 | ||
| 146 | *timings = dssdev->panel.timings; | 320 | *timings = dssdev->panel.timings; |
| 147 | 321 | ||
| 148 | mutex_unlock(&hdmi.hdmi_lock); | 322 | mutex_unlock(&hdmi.lock); |
| 149 | } | 323 | } |
| 150 | 324 | ||
| 151 | static void hdmi_set_timings(struct omap_dss_device *dssdev, | 325 | static void hdmi_set_timings(struct omap_dss_device *dssdev, |
| @@ -153,12 +327,18 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, | |||
| 153 | { | 327 | { |
| 154 | DSSDBG("hdmi_set_timings\n"); | 328 | DSSDBG("hdmi_set_timings\n"); |
| 155 | 329 | ||
| 156 | mutex_lock(&hdmi.hdmi_lock); | 330 | mutex_lock(&hdmi.lock); |
| 331 | |||
| 332 | /* | ||
| 333 | * TODO: notify audio users that there was a timings change. For | ||
| 334 | * now, disable audio locally to not break our audio state machine. | ||
| 335 | */ | ||
| 336 | hdmi_panel_audio_disable(dssdev); | ||
| 157 | 337 | ||
| 158 | dssdev->panel.timings = *timings; | 338 | dssdev->panel.timings = *timings; |
| 159 | omapdss_hdmi_display_set_timing(dssdev); | 339 | omapdss_hdmi_display_set_timing(dssdev); |
| 160 | 340 | ||
| 161 | mutex_unlock(&hdmi.hdmi_lock); | 341 | mutex_unlock(&hdmi.lock); |
| 162 | } | 342 | } |
| 163 | 343 | ||
| 164 | static int hdmi_check_timings(struct omap_dss_device *dssdev, | 344 | static int hdmi_check_timings(struct omap_dss_device *dssdev, |
| @@ -168,11 +348,11 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev, | |||
| 168 | 348 | ||
| 169 | DSSDBG("hdmi_check_timings\n"); | 349 | DSSDBG("hdmi_check_timings\n"); |
| 170 | 350 | ||
| 171 | mutex_lock(&hdmi.hdmi_lock); | 351 | mutex_lock(&hdmi.lock); |
| 172 | 352 | ||
| 173 | r = omapdss_hdmi_display_check_timing(dssdev, timings); | 353 | r = omapdss_hdmi_display_check_timing(dssdev, timings); |
| 174 | 354 | ||
| 175 | mutex_unlock(&hdmi.hdmi_lock); | 355 | mutex_unlock(&hdmi.lock); |
| 176 | return r; | 356 | return r; |
| 177 | } | 357 | } |
| 178 | 358 | ||
| @@ -180,7 +360,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) | |||
| 180 | { | 360 | { |
| 181 | int r; | 361 | int r; |
| 182 | 362 | ||
| 183 | mutex_lock(&hdmi.hdmi_lock); | 363 | mutex_lock(&hdmi.lock); |
| 184 | 364 | ||
| 185 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 365 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
| 186 | r = omapdss_hdmi_display_enable(dssdev); | 366 | r = omapdss_hdmi_display_enable(dssdev); |
| @@ -194,7 +374,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) | |||
| 194 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) | 374 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) |
| 195 | omapdss_hdmi_display_disable(dssdev); | 375 | omapdss_hdmi_display_disable(dssdev); |
| 196 | err: | 376 | err: |
| 197 | mutex_unlock(&hdmi.hdmi_lock); | 377 | mutex_unlock(&hdmi.lock); |
| 198 | 378 | ||
| 199 | return r; | 379 | return r; |
| 200 | } | 380 | } |
| @@ -203,7 +383,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev) | |||
| 203 | { | 383 | { |
| 204 | int r; | 384 | int r; |
| 205 | 385 | ||
| 206 | mutex_lock(&hdmi.hdmi_lock); | 386 | mutex_lock(&hdmi.lock); |
| 207 | 387 | ||
| 208 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 388 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
| 209 | r = omapdss_hdmi_display_enable(dssdev); | 389 | r = omapdss_hdmi_display_enable(dssdev); |
| @@ -217,7 +397,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev) | |||
| 217 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) | 397 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) |
| 218 | omapdss_hdmi_display_disable(dssdev); | 398 | omapdss_hdmi_display_disable(dssdev); |
| 219 | err: | 399 | err: |
| 220 | mutex_unlock(&hdmi.hdmi_lock); | 400 | mutex_unlock(&hdmi.lock); |
| 221 | 401 | ||
| 222 | return r; | 402 | return r; |
| 223 | } | 403 | } |
| @@ -234,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = { | |||
| 234 | .check_timings = hdmi_check_timings, | 414 | .check_timings = hdmi_check_timings, |
| 235 | .read_edid = hdmi_read_edid, | 415 | .read_edid = hdmi_read_edid, |
| 236 | .detect = hdmi_detect, | 416 | .detect = hdmi_detect, |
| 417 | .audio_enable = hdmi_panel_audio_enable, | ||
| 418 | .audio_disable = hdmi_panel_audio_disable, | ||
| 419 | .audio_start = hdmi_panel_audio_start, | ||
| 420 | .audio_stop = hdmi_panel_audio_stop, | ||
| 421 | .audio_supported = hdmi_panel_audio_supported, | ||
| 422 | .audio_config = hdmi_panel_audio_config, | ||
| 237 | .driver = { | 423 | .driver = { |
| 238 | .name = "hdmi_panel", | 424 | .name = "hdmi_panel", |
| 239 | .owner = THIS_MODULE, | 425 | .owner = THIS_MODULE, |
| @@ -242,7 +428,11 @@ static struct omap_dss_driver hdmi_driver = { | |||
| 242 | 428 | ||
| 243 | int hdmi_panel_init(void) | 429 | int hdmi_panel_init(void) |
| 244 | { | 430 | { |
| 245 | mutex_init(&hdmi.hdmi_lock); | 431 | mutex_init(&hdmi.lock); |
| 432 | |||
| 433 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 434 | spin_lock_init(&hdmi.audio_lock); | ||
| 435 | #endif | ||
| 246 | 436 | ||
| 247 | omap_dss_register_driver(&hdmi_driver); | 437 | omap_dss_register_driver(&hdmi_driver); |
| 248 | 438 | ||
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index e7364603f6a1..0cbcde4c688a 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
| @@ -654,9 +654,20 @@ static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, | |||
| 654 | return 0; | 654 | return 0; |
| 655 | } | 655 | } |
| 656 | 656 | ||
| 657 | int dss_mgr_check_timings(struct omap_overlay_manager *mgr, | ||
| 658 | const struct omap_video_timings *timings) | ||
| 659 | { | ||
| 660 | if (!dispc_mgr_timings_ok(mgr->id, timings)) { | ||
| 661 | DSSERR("check_manager: invalid timings\n"); | ||
| 662 | return -EINVAL; | ||
| 663 | } | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | |||
| 657 | int dss_mgr_check(struct omap_overlay_manager *mgr, | 668 | int dss_mgr_check(struct omap_overlay_manager *mgr, |
| 658 | struct omap_dss_device *dssdev, | ||
| 659 | struct omap_overlay_manager_info *info, | 669 | struct omap_overlay_manager_info *info, |
| 670 | const struct omap_video_timings *mgr_timings, | ||
| 660 | struct omap_overlay_info **overlay_infos) | 671 | struct omap_overlay_info **overlay_infos) |
| 661 | { | 672 | { |
| 662 | struct omap_overlay *ovl; | 673 | struct omap_overlay *ovl; |
| @@ -668,6 +679,10 @@ int dss_mgr_check(struct omap_overlay_manager *mgr, | |||
| 668 | return r; | 679 | return r; |
| 669 | } | 680 | } |
| 670 | 681 | ||
| 682 | r = dss_mgr_check_timings(mgr, mgr_timings); | ||
| 683 | if (r) | ||
| 684 | return r; | ||
| 685 | |||
| 671 | list_for_each_entry(ovl, &mgr->overlays, list) { | 686 | list_for_each_entry(ovl, &mgr->overlays, list) { |
| 672 | struct omap_overlay_info *oi; | 687 | struct omap_overlay_info *oi; |
| 673 | int r; | 688 | int r; |
| @@ -677,7 +692,7 @@ int dss_mgr_check(struct omap_overlay_manager *mgr, | |||
| 677 | if (oi == NULL) | 692 | if (oi == NULL) |
| 678 | continue; | 693 | continue; |
| 679 | 694 | ||
| 680 | r = dss_ovl_check(ovl, oi, dssdev); | 695 | r = dss_ovl_check(ovl, oi, mgr_timings); |
| 681 | if (r) | 696 | if (r) |
| 682 | return r; | 697 | return r; |
| 683 | } | 698 | } |
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 6e821810deec..b0ba60f88dd2 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
| @@ -628,19 +628,23 @@ int dss_ovl_simple_check(struct omap_overlay *ovl, | |||
| 628 | return -EINVAL; | 628 | return -EINVAL; |
| 629 | } | 629 | } |
| 630 | 630 | ||
| 631 | if (dss_feat_rotation_type_supported(info->rotation_type) == 0) { | ||
| 632 | DSSERR("check_overlay: rotation type %d not supported\n", | ||
| 633 | info->rotation_type); | ||
| 634 | return -EINVAL; | ||
| 635 | } | ||
| 636 | |||
| 631 | return 0; | 637 | return 0; |
| 632 | } | 638 | } |
| 633 | 639 | ||
| 634 | int dss_ovl_check(struct omap_overlay *ovl, | 640 | int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, |
| 635 | struct omap_overlay_info *info, struct omap_dss_device *dssdev) | 641 | const struct omap_video_timings *mgr_timings) |
| 636 | { | 642 | { |
| 637 | u16 outw, outh; | 643 | u16 outw, outh; |
| 638 | u16 dw, dh; | 644 | u16 dw, dh; |
| 639 | 645 | ||
| 640 | if (dssdev == NULL) | 646 | dw = mgr_timings->x_res; |
| 641 | return 0; | 647 | dh = mgr_timings->y_res; |
| 642 | |||
| 643 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
| 644 | 648 | ||
| 645 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | 649 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { |
| 646 | outw = info->width; | 650 | outw = info->width; |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 788a0ef6323a..3d8c206e90e5 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
| @@ -304,13 +304,23 @@ static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, | |||
| 304 | u16 height, void (*callback)(void *data), void *data) | 304 | u16 height, void (*callback)(void *data), void *data) |
| 305 | { | 305 | { |
| 306 | u32 l; | 306 | u32 l; |
| 307 | struct omap_video_timings timings = { | ||
| 308 | .hsw = 1, | ||
| 309 | .hfp = 1, | ||
| 310 | .hbp = 1, | ||
| 311 | .vsw = 1, | ||
| 312 | .vfp = 0, | ||
| 313 | .vbp = 0, | ||
| 314 | .x_res = width, | ||
| 315 | .y_res = height, | ||
| 316 | }; | ||
| 307 | 317 | ||
| 308 | /*BUG_ON(callback == 0);*/ | 318 | /*BUG_ON(callback == 0);*/ |
| 309 | BUG_ON(rfbi.framedone_callback != NULL); | 319 | BUG_ON(rfbi.framedone_callback != NULL); |
| 310 | 320 | ||
| 311 | DSSDBG("rfbi_transfer_area %dx%d\n", width, height); | 321 | DSSDBG("rfbi_transfer_area %dx%d\n", width, height); |
| 312 | 322 | ||
| 313 | dispc_mgr_set_lcd_size(dssdev->manager->id, width, height); | 323 | dss_mgr_set_timings(dssdev->manager, &timings); |
| 314 | 324 | ||
| 315 | dispc_mgr_enable(dssdev->manager->id, true); | 325 | dispc_mgr_enable(dssdev->manager->id, true); |
| 316 | 326 | ||
| @@ -766,6 +776,16 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | |||
| 766 | u16 *x, u16 *y, u16 *w, u16 *h) | 776 | u16 *x, u16 *y, u16 *w, u16 *h) |
| 767 | { | 777 | { |
| 768 | u16 dw, dh; | 778 | u16 dw, dh; |
| 779 | struct omap_video_timings timings = { | ||
| 780 | .hsw = 1, | ||
| 781 | .hfp = 1, | ||
| 782 | .hbp = 1, | ||
| 783 | .vsw = 1, | ||
| 784 | .vfp = 0, | ||
| 785 | .vbp = 0, | ||
| 786 | .x_res = *w, | ||
| 787 | .y_res = *h, | ||
| 788 | }; | ||
| 769 | 789 | ||
| 770 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | 790 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
| 771 | 791 | ||
| @@ -784,7 +804,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | |||
| 784 | if (*w == 0 || *h == 0) | 804 | if (*w == 0 || *h == 0) |
| 785 | return -EINVAL; | 805 | return -EINVAL; |
| 786 | 806 | ||
| 787 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); | 807 | dss_mgr_set_timings(dssdev->manager, &timings); |
| 788 | 808 | ||
| 789 | return 0; | 809 | return 0; |
| 790 | } | 810 | } |
| @@ -799,7 +819,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev, | |||
| 799 | } | 819 | } |
| 800 | EXPORT_SYMBOL(omap_rfbi_update); | 820 | EXPORT_SYMBOL(omap_rfbi_update); |
| 801 | 821 | ||
| 802 | void rfbi_dump_regs(struct seq_file *s) | 822 | static void rfbi_dump_regs(struct seq_file *s) |
| 803 | { | 823 | { |
| 804 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) | 824 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) |
| 805 | 825 | ||
| @@ -900,15 +920,39 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) | |||
| 900 | } | 920 | } |
| 901 | EXPORT_SYMBOL(omapdss_rfbi_display_disable); | 921 | EXPORT_SYMBOL(omapdss_rfbi_display_disable); |
| 902 | 922 | ||
| 903 | int rfbi_init_display(struct omap_dss_device *dssdev) | 923 | static int __init rfbi_init_display(struct omap_dss_device *dssdev) |
| 904 | { | 924 | { |
| 905 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; | 925 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; |
| 906 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | 926 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; |
| 907 | return 0; | 927 | return 0; |
| 908 | } | 928 | } |
| 909 | 929 | ||
| 930 | static void __init rfbi_probe_pdata(struct platform_device *pdev) | ||
| 931 | { | ||
| 932 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 933 | int i, r; | ||
| 934 | |||
| 935 | for (i = 0; i < pdata->num_devices; ++i) { | ||
| 936 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
| 937 | |||
| 938 | if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) | ||
| 939 | continue; | ||
| 940 | |||
| 941 | r = rfbi_init_display(dssdev); | ||
| 942 | if (r) { | ||
| 943 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
| 944 | continue; | ||
| 945 | } | ||
| 946 | |||
| 947 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | ||
| 948 | if (r) | ||
| 949 | DSSERR("device %s register failed: %d\n", | ||
| 950 | dssdev->name, r); | ||
| 951 | } | ||
| 952 | } | ||
| 953 | |||
| 910 | /* RFBI HW IP initialisation */ | 954 | /* RFBI HW IP initialisation */ |
| 911 | static int omap_rfbihw_probe(struct platform_device *pdev) | 955 | static int __init omap_rfbihw_probe(struct platform_device *pdev) |
| 912 | { | 956 | { |
| 913 | u32 rev; | 957 | u32 rev; |
| 914 | struct resource *rfbi_mem; | 958 | struct resource *rfbi_mem; |
| @@ -956,6 +1000,10 @@ static int omap_rfbihw_probe(struct platform_device *pdev) | |||
| 956 | 1000 | ||
| 957 | rfbi_runtime_put(); | 1001 | rfbi_runtime_put(); |
| 958 | 1002 | ||
| 1003 | dss_debugfs_create_file("rfbi", rfbi_dump_regs); | ||
| 1004 | |||
| 1005 | rfbi_probe_pdata(pdev); | ||
| 1006 | |||
| 959 | return 0; | 1007 | return 0; |
| 960 | 1008 | ||
| 961 | err_runtime_get: | 1009 | err_runtime_get: |
| @@ -963,8 +1011,9 @@ err_runtime_get: | |||
| 963 | return r; | 1011 | return r; |
| 964 | } | 1012 | } |
| 965 | 1013 | ||
| 966 | static int omap_rfbihw_remove(struct platform_device *pdev) | 1014 | static int __exit omap_rfbihw_remove(struct platform_device *pdev) |
| 967 | { | 1015 | { |
| 1016 | omap_dss_unregister_child_devices(&pdev->dev); | ||
| 968 | pm_runtime_disable(&pdev->dev); | 1017 | pm_runtime_disable(&pdev->dev); |
| 969 | return 0; | 1018 | return 0; |
| 970 | } | 1019 | } |
| @@ -972,7 +1021,6 @@ static int omap_rfbihw_remove(struct platform_device *pdev) | |||
| 972 | static int rfbi_runtime_suspend(struct device *dev) | 1021 | static int rfbi_runtime_suspend(struct device *dev) |
| 973 | { | 1022 | { |
| 974 | dispc_runtime_put(); | 1023 | dispc_runtime_put(); |
| 975 | dss_runtime_put(); | ||
| 976 | 1024 | ||
| 977 | return 0; | 1025 | return 0; |
| 978 | } | 1026 | } |
| @@ -981,20 +1029,11 @@ static int rfbi_runtime_resume(struct device *dev) | |||
| 981 | { | 1029 | { |
| 982 | int r; | 1030 | int r; |
| 983 | 1031 | ||
| 984 | r = dss_runtime_get(); | ||
| 985 | if (r < 0) | ||
| 986 | goto err_get_dss; | ||
| 987 | |||
| 988 | r = dispc_runtime_get(); | 1032 | r = dispc_runtime_get(); |
| 989 | if (r < 0) | 1033 | if (r < 0) |
| 990 | goto err_get_dispc; | 1034 | return r; |
| 991 | 1035 | ||
| 992 | return 0; | 1036 | return 0; |
| 993 | |||
| 994 | err_get_dispc: | ||
| 995 | dss_runtime_put(); | ||
| 996 | err_get_dss: | ||
| 997 | return r; | ||
| 998 | } | 1037 | } |
| 999 | 1038 | ||
| 1000 | static const struct dev_pm_ops rfbi_pm_ops = { | 1039 | static const struct dev_pm_ops rfbi_pm_ops = { |
| @@ -1003,8 +1042,7 @@ static const struct dev_pm_ops rfbi_pm_ops = { | |||
| 1003 | }; | 1042 | }; |
| 1004 | 1043 | ||
| 1005 | static struct platform_driver omap_rfbihw_driver = { | 1044 | static struct platform_driver omap_rfbihw_driver = { |
| 1006 | .probe = omap_rfbihw_probe, | 1045 | .remove = __exit_p(omap_rfbihw_remove), |
| 1007 | .remove = omap_rfbihw_remove, | ||
| 1008 | .driver = { | 1046 | .driver = { |
| 1009 | .name = "omapdss_rfbi", | 1047 | .name = "omapdss_rfbi", |
| 1010 | .owner = THIS_MODULE, | 1048 | .owner = THIS_MODULE, |
| @@ -1012,12 +1050,12 @@ static struct platform_driver omap_rfbihw_driver = { | |||
| 1012 | }, | 1050 | }, |
| 1013 | }; | 1051 | }; |
| 1014 | 1052 | ||
| 1015 | int rfbi_init_platform_driver(void) | 1053 | int __init rfbi_init_platform_driver(void) |
| 1016 | { | 1054 | { |
| 1017 | return platform_driver_register(&omap_rfbihw_driver); | 1055 | return platform_driver_probe(&omap_rfbihw_driver, omap_rfbihw_probe); |
| 1018 | } | 1056 | } |
| 1019 | 1057 | ||
| 1020 | void rfbi_uninit_platform_driver(void) | 1058 | void __exit rfbi_uninit_platform_driver(void) |
| 1021 | { | 1059 | { |
| 1022 | return platform_driver_unregister(&omap_rfbihw_driver); | 1060 | platform_driver_unregister(&omap_rfbihw_driver); |
| 1023 | } | 1061 | } |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 8266ca0d666b..3a43dc2a9b46 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
| 25 | #include <linux/regulator/consumer.h> | 25 | #include <linux/regulator/consumer.h> |
| 26 | #include <linux/export.h> | 26 | #include <linux/export.h> |
| 27 | #include <linux/platform_device.h> | ||
| 27 | 28 | ||
| 28 | #include <video/omapdss.h> | 29 | #include <video/omapdss.h> |
| 29 | #include "dss.h" | 30 | #include "dss.h" |
| @@ -71,10 +72,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
| 71 | if (r) | 72 | if (r) |
| 72 | goto err_reg_enable; | 73 | goto err_reg_enable; |
| 73 | 74 | ||
| 74 | r = dss_runtime_get(); | ||
| 75 | if (r) | ||
| 76 | goto err_get_dss; | ||
| 77 | |||
| 78 | r = dispc_runtime_get(); | 75 | r = dispc_runtime_get(); |
| 79 | if (r) | 76 | if (r) |
| 80 | goto err_get_dispc; | 77 | goto err_get_dispc; |
| @@ -107,7 +104,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
| 107 | } | 104 | } |
| 108 | 105 | ||
| 109 | 106 | ||
| 110 | dispc_mgr_set_lcd_timings(dssdev->manager->id, t); | 107 | dss_mgr_set_timings(dssdev->manager, t); |
| 111 | 108 | ||
| 112 | r = dss_set_clock_div(&dss_cinfo); | 109 | r = dss_set_clock_div(&dss_cinfo); |
| 113 | if (r) | 110 | if (r) |
| @@ -137,8 +134,6 @@ err_set_dss_clock_div: | |||
| 137 | err_calc_clock_div: | 134 | err_calc_clock_div: |
| 138 | dispc_runtime_put(); | 135 | dispc_runtime_put(); |
| 139 | err_get_dispc: | 136 | err_get_dispc: |
| 140 | dss_runtime_put(); | ||
| 141 | err_get_dss: | ||
| 142 | regulator_disable(sdi.vdds_sdi_reg); | 137 | regulator_disable(sdi.vdds_sdi_reg); |
| 143 | err_reg_enable: | 138 | err_reg_enable: |
| 144 | omap_dss_stop_device(dssdev); | 139 | omap_dss_stop_device(dssdev); |
| @@ -154,7 +149,6 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | |||
| 154 | dss_sdi_disable(); | 149 | dss_sdi_disable(); |
| 155 | 150 | ||
| 156 | dispc_runtime_put(); | 151 | dispc_runtime_put(); |
| 157 | dss_runtime_put(); | ||
| 158 | 152 | ||
| 159 | regulator_disable(sdi.vdds_sdi_reg); | 153 | regulator_disable(sdi.vdds_sdi_reg); |
| 160 | 154 | ||
| @@ -162,7 +156,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | |||
| 162 | } | 156 | } |
| 163 | EXPORT_SYMBOL(omapdss_sdi_display_disable); | 157 | EXPORT_SYMBOL(omapdss_sdi_display_disable); |
| 164 | 158 | ||
| 165 | int sdi_init_display(struct omap_dss_device *dssdev) | 159 | static int __init sdi_init_display(struct omap_dss_device *dssdev) |
| 166 | { | 160 | { |
| 167 | DSSDBG("SDI init\n"); | 161 | DSSDBG("SDI init\n"); |
| 168 | 162 | ||
| @@ -182,11 +176,58 @@ int sdi_init_display(struct omap_dss_device *dssdev) | |||
| 182 | return 0; | 176 | return 0; |
| 183 | } | 177 | } |
| 184 | 178 | ||
| 185 | int sdi_init(void) | 179 | static void __init sdi_probe_pdata(struct platform_device *pdev) |
| 180 | { | ||
| 181 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 182 | int i, r; | ||
| 183 | |||
| 184 | for (i = 0; i < pdata->num_devices; ++i) { | ||
| 185 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
| 186 | |||
| 187 | if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) | ||
| 188 | continue; | ||
| 189 | |||
| 190 | r = sdi_init_display(dssdev); | ||
| 191 | if (r) { | ||
| 192 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
| 193 | continue; | ||
| 194 | } | ||
| 195 | |||
| 196 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | ||
| 197 | if (r) | ||
| 198 | DSSERR("device %s register failed: %d\n", | ||
| 199 | dssdev->name, r); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | static int __init omap_sdi_probe(struct platform_device *pdev) | ||
| 186 | { | 204 | { |
| 205 | sdi_probe_pdata(pdev); | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static int __exit omap_sdi_remove(struct platform_device *pdev) | ||
| 211 | { | ||
| 212 | omap_dss_unregister_child_devices(&pdev->dev); | ||
| 213 | |||
| 187 | return 0; | 214 | return 0; |
| 188 | } | 215 | } |
| 189 | 216 | ||
| 190 | void sdi_exit(void) | 217 | static struct platform_driver omap_sdi_driver = { |
| 218 | .remove = __exit_p(omap_sdi_remove), | ||
| 219 | .driver = { | ||
| 220 | .name = "omapdss_sdi", | ||
| 221 | .owner = THIS_MODULE, | ||
| 222 | }, | ||
| 223 | }; | ||
| 224 | |||
| 225 | int __init sdi_init_platform_driver(void) | ||
| 226 | { | ||
| 227 | return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe); | ||
| 228 | } | ||
| 229 | |||
| 230 | void __exit sdi_uninit_platform_driver(void) | ||
| 191 | { | 231 | { |
| 232 | platform_driver_unregister(&omap_sdi_driver); | ||
| 192 | } | 233 | } |
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 1f58b84d6901..e734cb444bc7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
| @@ -96,7 +96,9 @@ struct ti_hdmi_ip_ops { | |||
| 96 | 96 | ||
| 97 | void (*pll_disable)(struct hdmi_ip_data *ip_data); | 97 | void (*pll_disable)(struct hdmi_ip_data *ip_data); |
| 98 | 98 | ||
| 99 | void (*video_enable)(struct hdmi_ip_data *ip_data, bool start); | 99 | int (*video_enable)(struct hdmi_ip_data *ip_data); |
| 100 | |||
| 101 | void (*video_disable)(struct hdmi_ip_data *ip_data); | ||
| 100 | 102 | ||
| 101 | void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); | 103 | void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); |
| 102 | 104 | ||
| @@ -106,9 +108,17 @@ struct ti_hdmi_ip_ops { | |||
| 106 | 108 | ||
| 107 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); | 109 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); |
| 108 | 110 | ||
| 109 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 111 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
| 110 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 112 | int (*audio_enable)(struct hdmi_ip_data *ip_data); |
| 111 | void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); | 113 | |
| 114 | void (*audio_disable)(struct hdmi_ip_data *ip_data); | ||
| 115 | |||
| 116 | int (*audio_start)(struct hdmi_ip_data *ip_data); | ||
| 117 | |||
| 118 | void (*audio_stop)(struct hdmi_ip_data *ip_data); | ||
| 119 | |||
| 120 | int (*audio_config)(struct hdmi_ip_data *ip_data, | ||
| 121 | struct omap_dss_audio *audio); | ||
| 112 | #endif | 122 | #endif |
| 113 | 123 | ||
| 114 | }; | 124 | }; |
| @@ -173,7 +183,8 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); | |||
| 173 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); | 183 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); |
| 174 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); | 184 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); |
| 175 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); | 185 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); |
| 176 | void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start); | 186 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); |
| 187 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); | ||
| 177 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); | 188 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); |
| 178 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); | 189 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); |
| 179 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); | 190 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); |
| @@ -181,8 +192,13 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | |||
| 181 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 192 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
| 182 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 193 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
| 183 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 194 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
| 184 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 195 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
| 185 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 196 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts); |
| 186 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); | 197 | int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data); |
| 198 | void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data); | ||
| 199 | int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data); | ||
| 200 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data); | ||
| 201 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, | ||
| 202 | struct omap_dss_audio *audio); | ||
| 187 | #endif | 203 | #endif |
| 188 | #endif | 204 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index bfe6fe65c8be..4dae1b291079 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
| @@ -29,9 +29,14 @@ | |||
| 29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
| 30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
| 31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
| 32 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 33 | #include <sound/asound.h> | ||
| 34 | #include <sound/asoundef.h> | ||
| 35 | #endif | ||
| 32 | 36 | ||
| 33 | #include "ti_hdmi_4xxx_ip.h" | 37 | #include "ti_hdmi_4xxx_ip.h" |
| 34 | #include "dss.h" | 38 | #include "dss.h" |
| 39 | #include "dss_features.h" | ||
| 35 | 40 | ||
| 36 | static inline void hdmi_write_reg(void __iomem *base_addr, | 41 | static inline void hdmi_write_reg(void __iomem *base_addr, |
| 37 | const u16 idx, u32 val) | 42 | const u16 idx, u32 val) |
| @@ -298,9 +303,9 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | |||
| 298 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | 303 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); |
| 299 | 304 | ||
| 300 | r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), | 305 | r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), |
| 301 | NULL, hpd_irq_handler, | 306 | NULL, hpd_irq_handler, |
| 302 | IRQF_DISABLED | IRQF_TRIGGER_RISING | | 307 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | |
| 303 | IRQF_TRIGGER_FALLING, "hpd", ip_data); | 308 | IRQF_ONESHOT, "hpd", ip_data); |
| 304 | if (r) { | 309 | if (r) { |
| 305 | DSSERR("HPD IRQ request failed\n"); | 310 | DSSERR("HPD IRQ request failed\n"); |
| 306 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | 311 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); |
| @@ -699,9 +704,15 @@ static void hdmi_wp_init(struct omap_video_timings *timings, | |||
| 699 | 704 | ||
| 700 | } | 705 | } |
| 701 | 706 | ||
| 702 | void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start) | 707 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data) |
| 708 | { | ||
| 709 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, true, 31, 31); | ||
| 710 | return 0; | ||
| 711 | } | ||
| 712 | |||
| 713 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data) | ||
| 703 | { | 714 | { |
| 704 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31); | 715 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, false, 31, 31); |
| 705 | } | 716 | } |
| 706 | 717 | ||
| 707 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, | 718 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, |
| @@ -886,10 +897,12 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | |||
| 886 | 897 | ||
| 887 | #define CORE_REG(i, name) name(i) | 898 | #define CORE_REG(i, name) name(i) |
| 888 | #define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\ | 899 | #define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\ |
| 889 | hdmi_read_reg(hdmi_pll_base(ip_data), r)) | 900 | hdmi_read_reg(hdmi_core_sys_base(ip_data), r)) |
| 890 | #define DUMPCOREAV(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ | 901 | #define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\ |
| 902 | hdmi_read_reg(hdmi_av_base(ip_data), r)) | ||
| 903 | #define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ | ||
| 891 | (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \ | 904 | (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \ |
| 892 | hdmi_read_reg(hdmi_pll_base(ip_data), CORE_REG(i, r))) | 905 | hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r))) |
| 893 | 906 | ||
| 894 | DUMPCORE(HDMI_CORE_SYS_VND_IDL); | 907 | DUMPCORE(HDMI_CORE_SYS_VND_IDL); |
| 895 | DUMPCORE(HDMI_CORE_SYS_DEV_IDL); | 908 | DUMPCORE(HDMI_CORE_SYS_DEV_IDL); |
| @@ -898,6 +911,13 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | |||
| 898 | DUMPCORE(HDMI_CORE_SYS_SRST); | 911 | DUMPCORE(HDMI_CORE_SYS_SRST); |
| 899 | DUMPCORE(HDMI_CORE_CTRL1); | 912 | DUMPCORE(HDMI_CORE_CTRL1); |
| 900 | DUMPCORE(HDMI_CORE_SYS_SYS_STAT); | 913 | DUMPCORE(HDMI_CORE_SYS_SYS_STAT); |
| 914 | DUMPCORE(HDMI_CORE_SYS_DE_DLY); | ||
| 915 | DUMPCORE(HDMI_CORE_SYS_DE_CTRL); | ||
| 916 | DUMPCORE(HDMI_CORE_SYS_DE_TOP); | ||
| 917 | DUMPCORE(HDMI_CORE_SYS_DE_CNTL); | ||
| 918 | DUMPCORE(HDMI_CORE_SYS_DE_CNTH); | ||
| 919 | DUMPCORE(HDMI_CORE_SYS_DE_LINL); | ||
| 920 | DUMPCORE(HDMI_CORE_SYS_DE_LINH_1); | ||
| 901 | DUMPCORE(HDMI_CORE_SYS_VID_ACEN); | 921 | DUMPCORE(HDMI_CORE_SYS_VID_ACEN); |
| 902 | DUMPCORE(HDMI_CORE_SYS_VID_MODE); | 922 | DUMPCORE(HDMI_CORE_SYS_VID_MODE); |
| 903 | DUMPCORE(HDMI_CORE_SYS_INTR_STATE); | 923 | DUMPCORE(HDMI_CORE_SYS_INTR_STATE); |
| @@ -907,102 +927,91 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | |||
| 907 | DUMPCORE(HDMI_CORE_SYS_INTR4); | 927 | DUMPCORE(HDMI_CORE_SYS_INTR4); |
| 908 | DUMPCORE(HDMI_CORE_SYS_UMASK1); | 928 | DUMPCORE(HDMI_CORE_SYS_UMASK1); |
| 909 | DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL); | 929 | DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL); |
| 910 | DUMPCORE(HDMI_CORE_SYS_DE_DLY); | ||
| 911 | DUMPCORE(HDMI_CORE_SYS_DE_CTRL); | ||
| 912 | DUMPCORE(HDMI_CORE_SYS_DE_TOP); | ||
| 913 | DUMPCORE(HDMI_CORE_SYS_DE_CNTL); | ||
| 914 | DUMPCORE(HDMI_CORE_SYS_DE_CNTH); | ||
| 915 | DUMPCORE(HDMI_CORE_SYS_DE_LINL); | ||
| 916 | DUMPCORE(HDMI_CORE_SYS_DE_LINH_1); | ||
| 917 | 930 | ||
| 918 | DUMPCORE(HDMI_CORE_DDC_CMD); | ||
| 919 | DUMPCORE(HDMI_CORE_DDC_STATUS); | ||
| 920 | DUMPCORE(HDMI_CORE_DDC_ADDR); | 931 | DUMPCORE(HDMI_CORE_DDC_ADDR); |
| 932 | DUMPCORE(HDMI_CORE_DDC_SEGM); | ||
| 921 | DUMPCORE(HDMI_CORE_DDC_OFFSET); | 933 | DUMPCORE(HDMI_CORE_DDC_OFFSET); |
| 922 | DUMPCORE(HDMI_CORE_DDC_COUNT1); | 934 | DUMPCORE(HDMI_CORE_DDC_COUNT1); |
| 923 | DUMPCORE(HDMI_CORE_DDC_COUNT2); | 935 | DUMPCORE(HDMI_CORE_DDC_COUNT2); |
| 936 | DUMPCORE(HDMI_CORE_DDC_STATUS); | ||
| 937 | DUMPCORE(HDMI_CORE_DDC_CMD); | ||
| 924 | DUMPCORE(HDMI_CORE_DDC_DATA); | 938 | DUMPCORE(HDMI_CORE_DDC_DATA); |
| 925 | DUMPCORE(HDMI_CORE_DDC_SEGM); | ||
| 926 | 939 | ||
| 927 | DUMPCORE(HDMI_CORE_AV_HDMI_CTRL); | 940 | DUMPCOREAV(HDMI_CORE_AV_ACR_CTRL); |
| 928 | DUMPCORE(HDMI_CORE_AV_DPD); | 941 | DUMPCOREAV(HDMI_CORE_AV_FREQ_SVAL); |
| 929 | DUMPCORE(HDMI_CORE_AV_PB_CTRL1); | 942 | DUMPCOREAV(HDMI_CORE_AV_N_SVAL1); |
| 930 | DUMPCORE(HDMI_CORE_AV_PB_CTRL2); | 943 | DUMPCOREAV(HDMI_CORE_AV_N_SVAL2); |
| 931 | DUMPCORE(HDMI_CORE_AV_AVI_TYPE); | 944 | DUMPCOREAV(HDMI_CORE_AV_N_SVAL3); |
| 932 | DUMPCORE(HDMI_CORE_AV_AVI_VERS); | 945 | DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL1); |
| 933 | DUMPCORE(HDMI_CORE_AV_AVI_LEN); | 946 | DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL2); |
| 934 | DUMPCORE(HDMI_CORE_AV_AVI_CHSUM); | 947 | DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL3); |
| 948 | DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL1); | ||
| 949 | DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL2); | ||
| 950 | DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL3); | ||
| 951 | DUMPCOREAV(HDMI_CORE_AV_AUD_MODE); | ||
| 952 | DUMPCOREAV(HDMI_CORE_AV_SPDIF_CTRL); | ||
| 953 | DUMPCOREAV(HDMI_CORE_AV_HW_SPDIF_FS); | ||
| 954 | DUMPCOREAV(HDMI_CORE_AV_SWAP_I2S); | ||
| 955 | DUMPCOREAV(HDMI_CORE_AV_SPDIF_ERTH); | ||
| 956 | DUMPCOREAV(HDMI_CORE_AV_I2S_IN_MAP); | ||
| 957 | DUMPCOREAV(HDMI_CORE_AV_I2S_IN_CTRL); | ||
| 958 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST0); | ||
| 959 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST1); | ||
| 960 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST2); | ||
| 961 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST4); | ||
| 962 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST5); | ||
| 963 | DUMPCOREAV(HDMI_CORE_AV_ASRC); | ||
| 964 | DUMPCOREAV(HDMI_CORE_AV_I2S_IN_LEN); | ||
| 965 | DUMPCOREAV(HDMI_CORE_AV_HDMI_CTRL); | ||
| 966 | DUMPCOREAV(HDMI_CORE_AV_AUDO_TXSTAT); | ||
| 967 | DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_1); | ||
| 968 | DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_2); | ||
| 969 | DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_3); | ||
| 970 | DUMPCOREAV(HDMI_CORE_AV_TEST_TXCTRL); | ||
| 971 | DUMPCOREAV(HDMI_CORE_AV_DPD); | ||
| 972 | DUMPCOREAV(HDMI_CORE_AV_PB_CTRL1); | ||
| 973 | DUMPCOREAV(HDMI_CORE_AV_PB_CTRL2); | ||
| 974 | DUMPCOREAV(HDMI_CORE_AV_AVI_TYPE); | ||
| 975 | DUMPCOREAV(HDMI_CORE_AV_AVI_VERS); | ||
| 976 | DUMPCOREAV(HDMI_CORE_AV_AVI_LEN); | ||
| 977 | DUMPCOREAV(HDMI_CORE_AV_AVI_CHSUM); | ||
| 935 | 978 | ||
| 936 | for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++) | 979 | for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++) |
| 937 | DUMPCOREAV(i, HDMI_CORE_AV_AVI_DBYTE); | 980 | DUMPCOREAV2(i, HDMI_CORE_AV_AVI_DBYTE); |
| 981 | |||
| 982 | DUMPCOREAV(HDMI_CORE_AV_SPD_TYPE); | ||
| 983 | DUMPCOREAV(HDMI_CORE_AV_SPD_VERS); | ||
| 984 | DUMPCOREAV(HDMI_CORE_AV_SPD_LEN); | ||
| 985 | DUMPCOREAV(HDMI_CORE_AV_SPD_CHSUM); | ||
| 938 | 986 | ||
| 939 | for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++) | 987 | for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++) |
| 940 | DUMPCOREAV(i, HDMI_CORE_AV_SPD_DBYTE); | 988 | DUMPCOREAV2(i, HDMI_CORE_AV_SPD_DBYTE); |
| 989 | |||
| 990 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_TYPE); | ||
| 991 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_VERS); | ||
| 992 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_LEN); | ||
| 993 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_CHSUM); | ||
| 941 | 994 | ||
| 942 | for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++) | 995 | for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++) |
| 943 | DUMPCOREAV(i, HDMI_CORE_AV_AUD_DBYTE); | 996 | DUMPCOREAV2(i, HDMI_CORE_AV_AUD_DBYTE); |
| 997 | |||
| 998 | DUMPCOREAV(HDMI_CORE_AV_MPEG_TYPE); | ||
| 999 | DUMPCOREAV(HDMI_CORE_AV_MPEG_VERS); | ||
| 1000 | DUMPCOREAV(HDMI_CORE_AV_MPEG_LEN); | ||
| 1001 | DUMPCOREAV(HDMI_CORE_AV_MPEG_CHSUM); | ||
| 944 | 1002 | ||
| 945 | for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++) | 1003 | for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++) |
| 946 | DUMPCOREAV(i, HDMI_CORE_AV_MPEG_DBYTE); | 1004 | DUMPCOREAV2(i, HDMI_CORE_AV_MPEG_DBYTE); |
| 947 | 1005 | ||
| 948 | for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++) | 1006 | for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++) |
| 949 | DUMPCOREAV(i, HDMI_CORE_AV_GEN_DBYTE); | 1007 | DUMPCOREAV2(i, HDMI_CORE_AV_GEN_DBYTE); |
| 1008 | |||
| 1009 | DUMPCOREAV(HDMI_CORE_AV_CP_BYTE1); | ||
| 950 | 1010 | ||
| 951 | for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++) | 1011 | for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++) |
| 952 | DUMPCOREAV(i, HDMI_CORE_AV_GEN2_DBYTE); | 1012 | DUMPCOREAV2(i, HDMI_CORE_AV_GEN2_DBYTE); |
| 953 | 1013 | ||
| 954 | DUMPCORE(HDMI_CORE_AV_ACR_CTRL); | 1014 | DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID); |
| 955 | DUMPCORE(HDMI_CORE_AV_FREQ_SVAL); | ||
| 956 | DUMPCORE(HDMI_CORE_AV_N_SVAL1); | ||
| 957 | DUMPCORE(HDMI_CORE_AV_N_SVAL2); | ||
| 958 | DUMPCORE(HDMI_CORE_AV_N_SVAL3); | ||
| 959 | DUMPCORE(HDMI_CORE_AV_CTS_SVAL1); | ||
| 960 | DUMPCORE(HDMI_CORE_AV_CTS_SVAL2); | ||
| 961 | DUMPCORE(HDMI_CORE_AV_CTS_SVAL3); | ||
| 962 | DUMPCORE(HDMI_CORE_AV_CTS_HVAL1); | ||
| 963 | DUMPCORE(HDMI_CORE_AV_CTS_HVAL2); | ||
| 964 | DUMPCORE(HDMI_CORE_AV_CTS_HVAL3); | ||
| 965 | DUMPCORE(HDMI_CORE_AV_AUD_MODE); | ||
| 966 | DUMPCORE(HDMI_CORE_AV_SPDIF_CTRL); | ||
| 967 | DUMPCORE(HDMI_CORE_AV_HW_SPDIF_FS); | ||
| 968 | DUMPCORE(HDMI_CORE_AV_SWAP_I2S); | ||
| 969 | DUMPCORE(HDMI_CORE_AV_SPDIF_ERTH); | ||
| 970 | DUMPCORE(HDMI_CORE_AV_I2S_IN_MAP); | ||
| 971 | DUMPCORE(HDMI_CORE_AV_I2S_IN_CTRL); | ||
| 972 | DUMPCORE(HDMI_CORE_AV_I2S_CHST0); | ||
| 973 | DUMPCORE(HDMI_CORE_AV_I2S_CHST1); | ||
| 974 | DUMPCORE(HDMI_CORE_AV_I2S_CHST2); | ||
| 975 | DUMPCORE(HDMI_CORE_AV_I2S_CHST4); | ||
| 976 | DUMPCORE(HDMI_CORE_AV_I2S_CHST5); | ||
| 977 | DUMPCORE(HDMI_CORE_AV_ASRC); | ||
| 978 | DUMPCORE(HDMI_CORE_AV_I2S_IN_LEN); | ||
| 979 | DUMPCORE(HDMI_CORE_AV_HDMI_CTRL); | ||
| 980 | DUMPCORE(HDMI_CORE_AV_AUDO_TXSTAT); | ||
| 981 | DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_1); | ||
| 982 | DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_2); | ||
| 983 | DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_3); | ||
| 984 | DUMPCORE(HDMI_CORE_AV_TEST_TXCTRL); | ||
| 985 | DUMPCORE(HDMI_CORE_AV_DPD); | ||
| 986 | DUMPCORE(HDMI_CORE_AV_PB_CTRL1); | ||
| 987 | DUMPCORE(HDMI_CORE_AV_PB_CTRL2); | ||
| 988 | DUMPCORE(HDMI_CORE_AV_AVI_TYPE); | ||
| 989 | DUMPCORE(HDMI_CORE_AV_AVI_VERS); | ||
| 990 | DUMPCORE(HDMI_CORE_AV_AVI_LEN); | ||
| 991 | DUMPCORE(HDMI_CORE_AV_AVI_CHSUM); | ||
| 992 | DUMPCORE(HDMI_CORE_AV_SPD_TYPE); | ||
| 993 | DUMPCORE(HDMI_CORE_AV_SPD_VERS); | ||
| 994 | DUMPCORE(HDMI_CORE_AV_SPD_LEN); | ||
| 995 | DUMPCORE(HDMI_CORE_AV_SPD_CHSUM); | ||
| 996 | DUMPCORE(HDMI_CORE_AV_AUDIO_TYPE); | ||
| 997 | DUMPCORE(HDMI_CORE_AV_AUDIO_VERS); | ||
| 998 | DUMPCORE(HDMI_CORE_AV_AUDIO_LEN); | ||
| 999 | DUMPCORE(HDMI_CORE_AV_AUDIO_CHSUM); | ||
| 1000 | DUMPCORE(HDMI_CORE_AV_MPEG_TYPE); | ||
| 1001 | DUMPCORE(HDMI_CORE_AV_MPEG_VERS); | ||
| 1002 | DUMPCORE(HDMI_CORE_AV_MPEG_LEN); | ||
| 1003 | DUMPCORE(HDMI_CORE_AV_MPEG_CHSUM); | ||
| 1004 | DUMPCORE(HDMI_CORE_AV_CP_BYTE1); | ||
| 1005 | DUMPCORE(HDMI_CORE_AV_CEC_ADDR_ID); | ||
| 1006 | } | 1015 | } |
| 1007 | 1016 | ||
| 1008 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | 1017 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) |
| @@ -1016,9 +1025,8 @@ void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | |||
| 1016 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); | 1025 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); |
| 1017 | } | 1026 | } |
| 1018 | 1027 | ||
| 1019 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 1028 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
| 1020 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 1029 | static void ti_hdmi_4xxx_wp_audio_config_format(struct hdmi_ip_data *ip_data, |
| 1021 | void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, | ||
| 1022 | struct hdmi_audio_format *aud_fmt) | 1030 | struct hdmi_audio_format *aud_fmt) |
| 1023 | { | 1031 | { |
| 1024 | u32 r; | 1032 | u32 r; |
| @@ -1037,7 +1045,7 @@ void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, | |||
| 1037 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); | 1045 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); |
| 1038 | } | 1046 | } |
| 1039 | 1047 | ||
| 1040 | void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | 1048 | static void ti_hdmi_4xxx_wp_audio_config_dma(struct hdmi_ip_data *ip_data, |
| 1041 | struct hdmi_audio_dma *aud_dma) | 1049 | struct hdmi_audio_dma *aud_dma) |
| 1042 | { | 1050 | { |
| 1043 | u32 r; | 1051 | u32 r; |
| @@ -1055,7 +1063,7 @@ void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | |||
| 1055 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); | 1063 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); |
| 1056 | } | 1064 | } |
| 1057 | 1065 | ||
| 1058 | void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | 1066 | static void ti_hdmi_4xxx_core_audio_config(struct hdmi_ip_data *ip_data, |
| 1059 | struct hdmi_core_audio_config *cfg) | 1067 | struct hdmi_core_audio_config *cfg) |
| 1060 | { | 1068 | { |
| 1061 | u32 r; | 1069 | u32 r; |
| @@ -1106,27 +1114,33 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
| 1106 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, | 1114 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, |
| 1107 | cfg->fs_override, 1, 1); | 1115 | cfg->fs_override, 1, 1); |
| 1108 | 1116 | ||
| 1109 | /* I2S parameters */ | 1117 | /* |
| 1110 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_CHST4, | 1118 | * Set IEC-60958-3 channel status word. It is passed to the IP |
| 1111 | cfg->freq_sample, 3, 0); | 1119 | * just as it is received. The user of the driver is responsible |
| 1112 | 1120 | * for its contents. | |
| 1121 | */ | ||
| 1122 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0, | ||
| 1123 | cfg->iec60958_cfg->status[0]); | ||
| 1124 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1, | ||
| 1125 | cfg->iec60958_cfg->status[1]); | ||
| 1126 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2, | ||
| 1127 | cfg->iec60958_cfg->status[2]); | ||
| 1128 | /* yes, this is correct: status[3] goes to CHST4 register */ | ||
| 1129 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4, | ||
| 1130 | cfg->iec60958_cfg->status[3]); | ||
| 1131 | /* yes, this is correct: status[4] goes to CHST5 register */ | ||
| 1132 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, | ||
| 1133 | cfg->iec60958_cfg->status[4]); | ||
| 1134 | |||
| 1135 | /* set I2S parameters */ | ||
| 1113 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL); | 1136 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL); |
| 1114 | r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7); | ||
| 1115 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); | 1137 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); |
| 1116 | r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); | ||
| 1117 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); | 1138 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); |
| 1118 | r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); | ||
| 1119 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); | 1139 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); |
| 1120 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); | 1140 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); |
| 1121 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); | 1141 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); |
| 1122 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r); | 1142 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r); |
| 1123 | 1143 | ||
| 1124 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_CHST5); | ||
| 1125 | r = FLD_MOD(r, cfg->freq_sample, 7, 4); | ||
| 1126 | r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); | ||
| 1127 | r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); | ||
| 1128 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, r); | ||
| 1129 | |||
| 1130 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN, | 1144 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN, |
| 1131 | cfg->i2s_cfg.in_length_bits, 3, 0); | 1145 | cfg->i2s_cfg.in_length_bits, 3, 0); |
| 1132 | 1146 | ||
| @@ -1138,12 +1152,19 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
| 1138 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); | 1152 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); |
| 1139 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); | 1153 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); |
| 1140 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); | 1154 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); |
| 1155 | |||
| 1156 | /* Audio channel mappings */ | ||
| 1157 | /* TODO: Make channel mapping dynamic. For now, map channels | ||
| 1158 | * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as | ||
| 1159 | * HDMI speaker order is different. See CEA-861 Section 6.6.2. | ||
| 1160 | */ | ||
| 1161 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78); | ||
| 1162 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5); | ||
| 1141 | } | 1163 | } |
| 1142 | 1164 | ||
| 1143 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | 1165 | static void ti_hdmi_4xxx_core_audio_infoframe_cfg(struct hdmi_ip_data *ip_data, |
| 1144 | struct hdmi_core_infoframe_audio *info_aud) | 1166 | struct snd_cea_861_aud_if *info_aud) |
| 1145 | { | 1167 | { |
| 1146 | u8 val; | ||
| 1147 | u8 sum = 0, checksum = 0; | 1168 | u8 sum = 0, checksum = 0; |
| 1148 | void __iomem *av_base = hdmi_av_base(ip_data); | 1169 | void __iomem *av_base = hdmi_av_base(ip_data); |
| 1149 | 1170 | ||
| @@ -1157,24 +1178,23 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | |||
| 1157 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a); | 1178 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a); |
| 1158 | sum += 0x84 + 0x001 + 0x00a; | 1179 | sum += 0x84 + 0x001 + 0x00a; |
| 1159 | 1180 | ||
| 1160 | val = (info_aud->db1_coding_type << 4) | 1181 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), |
| 1161 | | (info_aud->db1_channel_count - 1); | 1182 | info_aud->db1_ct_cc); |
| 1162 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), val); | 1183 | sum += info_aud->db1_ct_cc; |
| 1163 | sum += val; | ||
| 1164 | 1184 | ||
| 1165 | val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; | 1185 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), |
| 1166 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), val); | 1186 | info_aud->db2_sf_ss); |
| 1167 | sum += val; | 1187 | sum += info_aud->db2_sf_ss; |
| 1168 | 1188 | ||
| 1169 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), 0x00); | 1189 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3); |
| 1190 | sum += info_aud->db3; | ||
| 1170 | 1191 | ||
| 1171 | val = info_aud->db4_channel_alloc; | 1192 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca); |
| 1172 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), val); | 1193 | sum += info_aud->db4_ca; |
| 1173 | sum += val; | ||
| 1174 | 1194 | ||
| 1175 | val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); | 1195 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), |
| 1176 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), val); | 1196 | info_aud->db5_dminh_lsv); |
| 1177 | sum += val; | 1197 | sum += info_aud->db5_dminh_lsv; |
| 1178 | 1198 | ||
| 1179 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00); | 1199 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00); |
| 1180 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00); | 1200 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00); |
| @@ -1192,70 +1212,212 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | |||
| 1192 | */ | 1212 | */ |
| 1193 | } | 1213 | } |
| 1194 | 1214 | ||
| 1195 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | 1215 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, |
| 1196 | u32 sample_freq, u32 *n, u32 *cts) | 1216 | struct omap_dss_audio *audio) |
| 1197 | { | 1217 | { |
| 1198 | u32 r; | 1218 | struct hdmi_audio_format audio_format; |
| 1199 | u32 deep_color = 0; | 1219 | struct hdmi_audio_dma audio_dma; |
| 1200 | u32 pclk = ip_data->cfg.timings.pixel_clock; | 1220 | struct hdmi_core_audio_config core; |
| 1201 | 1221 | int err, n, cts, channel_count; | |
| 1202 | if (n == NULL || cts == NULL) | 1222 | unsigned int fs_nr; |
| 1223 | bool word_length_16b = false; | ||
| 1224 | |||
| 1225 | if (!audio || !audio->iec || !audio->cea || !ip_data) | ||
| 1203 | return -EINVAL; | 1226 | return -EINVAL; |
| 1227 | |||
| 1228 | core.iec60958_cfg = audio->iec; | ||
| 1204 | /* | 1229 | /* |
| 1205 | * Obtain current deep color configuration. This needed | 1230 | * In the IEC-60958 status word, check if the audio sample word length |
| 1206 | * to calculate the TMDS clock based on the pixel clock. | 1231 | * is 16-bit as several optimizations can be performed in such case. |
| 1207 | */ | 1232 | */ |
| 1208 | r = REG_GET(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, 1, 0); | 1233 | if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)) |
| 1209 | switch (r) { | 1234 | if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16) |
| 1210 | case 1: /* No deep color selected */ | 1235 | word_length_16b = true; |
| 1211 | deep_color = 100; | 1236 | |
| 1237 | /* I2S configuration. See Phillips' specification */ | ||
| 1238 | if (word_length_16b) | ||
| 1239 | core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
| 1240 | else | ||
| 1241 | core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
| 1242 | /* | ||
| 1243 | * The I2S input word length is twice the lenght given in the IEC-60958 | ||
| 1244 | * status word. If the word size is greater than | ||
| 1245 | * 20 bits, increment by one. | ||
| 1246 | */ | ||
| 1247 | core.i2s_cfg.in_length_bits = audio->iec->status[4] | ||
| 1248 | & IEC958_AES4_CON_WORDLEN; | ||
| 1249 | if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) | ||
| 1250 | core.i2s_cfg.in_length_bits++; | ||
| 1251 | core.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
| 1252 | core.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
| 1253 | core.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
| 1254 | core.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
| 1255 | |||
| 1256 | /* convert sample frequency to a number */ | ||
| 1257 | switch (audio->iec->status[3] & IEC958_AES3_CON_FS) { | ||
| 1258 | case IEC958_AES3_CON_FS_32000: | ||
| 1259 | fs_nr = 32000; | ||
| 1260 | break; | ||
| 1261 | case IEC958_AES3_CON_FS_44100: | ||
| 1262 | fs_nr = 44100; | ||
| 1263 | break; | ||
| 1264 | case IEC958_AES3_CON_FS_48000: | ||
| 1265 | fs_nr = 48000; | ||
| 1212 | break; | 1266 | break; |
| 1213 | case 2: /* 10-bit deep color selected */ | 1267 | case IEC958_AES3_CON_FS_88200: |
| 1214 | deep_color = 125; | 1268 | fs_nr = 88200; |
| 1215 | break; | 1269 | break; |
| 1216 | case 3: /* 12-bit deep color selected */ | 1270 | case IEC958_AES3_CON_FS_96000: |
| 1217 | deep_color = 150; | 1271 | fs_nr = 96000; |
| 1272 | break; | ||
| 1273 | case IEC958_AES3_CON_FS_176400: | ||
| 1274 | fs_nr = 176400; | ||
| 1275 | break; | ||
| 1276 | case IEC958_AES3_CON_FS_192000: | ||
| 1277 | fs_nr = 192000; | ||
| 1218 | break; | 1278 | break; |
| 1219 | default: | 1279 | default: |
| 1220 | return -EINVAL; | 1280 | return -EINVAL; |
| 1221 | } | 1281 | } |
| 1222 | 1282 | ||
| 1223 | switch (sample_freq) { | 1283 | err = hdmi_compute_acr(fs_nr, &n, &cts); |
| 1224 | case 32000: | 1284 | |
| 1225 | if ((deep_color == 125) && ((pclk == 54054) | 1285 | /* Audio clock regeneration settings */ |
| 1226 | || (pclk == 74250))) | 1286 | core.n = n; |
| 1227 | *n = 8192; | 1287 | core.cts = cts; |
| 1228 | else | 1288 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { |
| 1229 | *n = 4096; | 1289 | core.aud_par_busclk = 0; |
| 1290 | core.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
| 1291 | core.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); | ||
| 1292 | } else { | ||
| 1293 | core.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
| 1294 | core.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
| 1295 | core.use_mclk = true; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | if (core.use_mclk) | ||
| 1299 | core.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
| 1300 | |||
| 1301 | /* Audio channels settings */ | ||
| 1302 | channel_count = (audio->cea->db1_ct_cc & | ||
| 1303 | CEA861_AUDIO_INFOFRAME_DB1CC) + 1; | ||
| 1304 | |||
| 1305 | switch (channel_count) { | ||
| 1306 | case 2: | ||
| 1307 | audio_format.active_chnnls_msk = 0x03; | ||
| 1308 | break; | ||
| 1309 | case 3: | ||
| 1310 | audio_format.active_chnnls_msk = 0x07; | ||
| 1311 | break; | ||
| 1312 | case 4: | ||
| 1313 | audio_format.active_chnnls_msk = 0x0f; | ||
| 1314 | break; | ||
| 1315 | case 5: | ||
| 1316 | audio_format.active_chnnls_msk = 0x1f; | ||
| 1230 | break; | 1317 | break; |
| 1231 | case 44100: | 1318 | case 6: |
| 1232 | *n = 6272; | 1319 | audio_format.active_chnnls_msk = 0x3f; |
| 1233 | break; | 1320 | break; |
| 1234 | case 48000: | 1321 | case 7: |
| 1235 | if ((deep_color == 125) && ((pclk == 54054) | 1322 | audio_format.active_chnnls_msk = 0x7f; |
| 1236 | || (pclk == 74250))) | 1323 | break; |
| 1237 | *n = 8192; | 1324 | case 8: |
| 1238 | else | 1325 | audio_format.active_chnnls_msk = 0xff; |
| 1239 | *n = 6144; | ||
| 1240 | break; | 1326 | break; |
| 1241 | default: | 1327 | default: |
| 1242 | *n = 0; | ||
| 1243 | return -EINVAL; | 1328 | return -EINVAL; |
| 1244 | } | 1329 | } |
| 1245 | 1330 | ||
| 1246 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ | 1331 | /* |
| 1247 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); | 1332 | * the HDMI IP needs to enable four stereo channels when transmitting |
| 1333 | * more than 2 audio channels | ||
| 1334 | */ | ||
| 1335 | if (channel_count == 2) { | ||
| 1336 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | ||
| 1337 | core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
| 1338 | core.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
| 1339 | } else { | ||
| 1340 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS; | ||
| 1341 | core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN | | ||
| 1342 | HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | | ||
| 1343 | HDMI_AUDIO_I2S_SD3_EN; | ||
| 1344 | core.layout = HDMI_AUDIO_LAYOUT_8CH; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | core.en_spdif = false; | ||
| 1348 | /* use sample frequency from channel status word */ | ||
| 1349 | core.fs_override = true; | ||
| 1350 | /* enable ACR packets */ | ||
| 1351 | core.en_acr_pkt = true; | ||
| 1352 | /* disable direct streaming digital audio */ | ||
| 1353 | core.en_dsd_audio = false; | ||
| 1354 | /* use parallel audio interface */ | ||
| 1355 | core.en_parallel_aud_input = true; | ||
| 1356 | |||
| 1357 | /* DMA settings */ | ||
| 1358 | if (word_length_16b) | ||
| 1359 | audio_dma.transfer_size = 0x10; | ||
| 1360 | else | ||
| 1361 | audio_dma.transfer_size = 0x20; | ||
| 1362 | audio_dma.block_size = 0xC0; | ||
| 1363 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | ||
| 1364 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
| 1365 | |||
| 1366 | /* audio FIFO format settings */ | ||
| 1367 | if (word_length_16b) { | ||
| 1368 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
| 1369 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
| 1370 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
| 1371 | } else { | ||
| 1372 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
| 1373 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
| 1374 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
| 1375 | } | ||
| 1376 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
| 1377 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
| 1378 | /* disable start/stop signals of IEC 60958 blocks */ | ||
| 1379 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; | ||
| 1380 | |||
| 1381 | /* configure DMA and audio FIFO format*/ | ||
| 1382 | ti_hdmi_4xxx_wp_audio_config_dma(ip_data, &audio_dma); | ||
| 1383 | ti_hdmi_4xxx_wp_audio_config_format(ip_data, &audio_format); | ||
| 1384 | |||
| 1385 | /* configure the core*/ | ||
| 1386 | ti_hdmi_4xxx_core_audio_config(ip_data, &core); | ||
| 1387 | |||
| 1388 | /* configure CEA 861 audio infoframe*/ | ||
| 1389 | ti_hdmi_4xxx_core_audio_infoframe_cfg(ip_data, audio->cea); | ||
| 1248 | 1390 | ||
| 1249 | return 0; | 1391 | return 0; |
| 1250 | } | 1392 | } |
| 1251 | 1393 | ||
| 1252 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) | 1394 | int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data) |
| 1395 | { | ||
| 1396 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
| 1397 | HDMI_WP_AUDIO_CTRL, true, 31, 31); | ||
| 1398 | return 0; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data) | ||
| 1402 | { | ||
| 1403 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
| 1404 | HDMI_WP_AUDIO_CTRL, false, 31, 31); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data) | ||
| 1253 | { | 1408 | { |
| 1254 | REG_FLD_MOD(hdmi_av_base(ip_data), | 1409 | REG_FLD_MOD(hdmi_av_base(ip_data), |
| 1255 | HDMI_CORE_AV_AUD_MODE, enable, 0, 0); | 1410 | HDMI_CORE_AV_AUD_MODE, true, 0, 0); |
| 1256 | REG_FLD_MOD(hdmi_wp_base(ip_data), | 1411 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
| 1257 | HDMI_WP_AUDIO_CTRL, enable, 31, 31); | 1412 | HDMI_WP_AUDIO_CTRL, true, 30, 30); |
| 1413 | return 0; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data) | ||
| 1417 | { | ||
| 1418 | REG_FLD_MOD(hdmi_av_base(ip_data), | ||
| 1419 | HDMI_CORE_AV_AUD_MODE, false, 0, 0); | ||
| 1258 | REG_FLD_MOD(hdmi_wp_base(ip_data), | 1420 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
| 1259 | HDMI_WP_AUDIO_CTRL, enable, 30, 30); | 1421 | HDMI_WP_AUDIO_CTRL, false, 30, 30); |
| 1260 | } | 1422 | } |
| 1261 | #endif | 1423 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index a14d1a0e6e41..8366ae19e82e 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | |||
| @@ -24,11 +24,6 @@ | |||
| 24 | #include <linux/string.h> | 24 | #include <linux/string.h> |
| 25 | #include <video/omapdss.h> | 25 | #include <video/omapdss.h> |
| 26 | #include "ti_hdmi.h" | 26 | #include "ti_hdmi.h" |
| 27 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
| 28 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
| 29 | #include <sound/soc.h> | ||
| 30 | #include <sound/pcm_params.h> | ||
| 31 | #endif | ||
| 32 | 27 | ||
| 33 | /* HDMI Wrapper */ | 28 | /* HDMI Wrapper */ |
| 34 | 29 | ||
| @@ -57,6 +52,13 @@ | |||
| 57 | #define HDMI_CORE_SYS_SRST 0x14 | 52 | #define HDMI_CORE_SYS_SRST 0x14 |
| 58 | #define HDMI_CORE_CTRL1 0x20 | 53 | #define HDMI_CORE_CTRL1 0x20 |
| 59 | #define HDMI_CORE_SYS_SYS_STAT 0x24 | 54 | #define HDMI_CORE_SYS_SYS_STAT 0x24 |
| 55 | #define HDMI_CORE_SYS_DE_DLY 0xC8 | ||
| 56 | #define HDMI_CORE_SYS_DE_CTRL 0xCC | ||
| 57 | #define HDMI_CORE_SYS_DE_TOP 0xD0 | ||
| 58 | #define HDMI_CORE_SYS_DE_CNTL 0xD8 | ||
| 59 | #define HDMI_CORE_SYS_DE_CNTH 0xDC | ||
| 60 | #define HDMI_CORE_SYS_DE_LINL 0xE0 | ||
| 61 | #define HDMI_CORE_SYS_DE_LINH_1 0xE4 | ||
| 60 | #define HDMI_CORE_SYS_VID_ACEN 0x124 | 62 | #define HDMI_CORE_SYS_VID_ACEN 0x124 |
| 61 | #define HDMI_CORE_SYS_VID_MODE 0x128 | 63 | #define HDMI_CORE_SYS_VID_MODE 0x128 |
| 62 | #define HDMI_CORE_SYS_INTR_STATE 0x1C0 | 64 | #define HDMI_CORE_SYS_INTR_STATE 0x1C0 |
| @@ -66,50 +68,24 @@ | |||
| 66 | #define HDMI_CORE_SYS_INTR4 0x1D0 | 68 | #define HDMI_CORE_SYS_INTR4 0x1D0 |
| 67 | #define HDMI_CORE_SYS_UMASK1 0x1D4 | 69 | #define HDMI_CORE_SYS_UMASK1 0x1D4 |
| 68 | #define HDMI_CORE_SYS_TMDS_CTRL 0x208 | 70 | #define HDMI_CORE_SYS_TMDS_CTRL 0x208 |
| 69 | #define HDMI_CORE_SYS_DE_DLY 0xC8 | 71 | |
| 70 | #define HDMI_CORE_SYS_DE_CTRL 0xCC | ||
| 71 | #define HDMI_CORE_SYS_DE_TOP 0xD0 | ||
| 72 | #define HDMI_CORE_SYS_DE_CNTL 0xD8 | ||
| 73 | #define HDMI_CORE_SYS_DE_CNTH 0xDC | ||
| 74 | #define HDMI_CORE_SYS_DE_LINL 0xE0 | ||
| 75 | #define HDMI_CORE_SYS_DE_LINH_1 0xE4 | ||
| 76 | #define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC 0x1 | 72 | #define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC 0x1 |
| 77 | #define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC 0x1 | 73 | #define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC 0x1 |
| 78 | #define HDMI_CORE_CTRL1_BSEL_24BITBUS 0x1 | 74 | #define HDMI_CORE_CTRL1_BSEL_24BITBUS 0x1 |
| 79 | #define HDMI_CORE_CTRL1_EDGE_RISINGEDGE 0x1 | 75 | #define HDMI_CORE_CTRL1_EDGE_RISINGEDGE 0x1 |
| 80 | 76 | ||
| 81 | /* HDMI DDC E-DID */ | 77 | /* HDMI DDC E-DID */ |
| 82 | #define HDMI_CORE_DDC_CMD 0x3CC | ||
| 83 | #define HDMI_CORE_DDC_STATUS 0x3C8 | ||
| 84 | #define HDMI_CORE_DDC_ADDR 0x3B4 | 78 | #define HDMI_CORE_DDC_ADDR 0x3B4 |
| 79 | #define HDMI_CORE_DDC_SEGM 0x3B8 | ||
| 85 | #define HDMI_CORE_DDC_OFFSET 0x3BC | 80 | #define HDMI_CORE_DDC_OFFSET 0x3BC |
| 86 | #define HDMI_CORE_DDC_COUNT1 0x3C0 | 81 | #define HDMI_CORE_DDC_COUNT1 0x3C0 |
| 87 | #define HDMI_CORE_DDC_COUNT2 0x3C4 | 82 | #define HDMI_CORE_DDC_COUNT2 0x3C4 |
| 83 | #define HDMI_CORE_DDC_STATUS 0x3C8 | ||
| 84 | #define HDMI_CORE_DDC_CMD 0x3CC | ||
| 88 | #define HDMI_CORE_DDC_DATA 0x3D0 | 85 | #define HDMI_CORE_DDC_DATA 0x3D0 |
| 89 | #define HDMI_CORE_DDC_SEGM 0x3B8 | ||
| 90 | 86 | ||
| 91 | /* HDMI IP Core Audio Video */ | 87 | /* HDMI IP Core Audio Video */ |
| 92 | 88 | ||
| 93 | #define HDMI_CORE_AV_HDMI_CTRL 0xBC | ||
| 94 | #define HDMI_CORE_AV_DPD 0xF4 | ||
| 95 | #define HDMI_CORE_AV_PB_CTRL1 0xF8 | ||
| 96 | #define HDMI_CORE_AV_PB_CTRL2 0xFC | ||
| 97 | #define HDMI_CORE_AV_AVI_TYPE 0x100 | ||
| 98 | #define HDMI_CORE_AV_AVI_VERS 0x104 | ||
| 99 | #define HDMI_CORE_AV_AVI_LEN 0x108 | ||
| 100 | #define HDMI_CORE_AV_AVI_CHSUM 0x10C | ||
| 101 | #define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110) | ||
| 102 | #define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15 | ||
| 103 | #define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190) | ||
| 104 | #define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27 | ||
| 105 | #define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210) | ||
| 106 | #define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10 | ||
| 107 | #define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290) | ||
| 108 | #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27 | ||
| 109 | #define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300) | ||
| 110 | #define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31 | ||
| 111 | #define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380) | ||
| 112 | #define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31 | ||
| 113 | #define HDMI_CORE_AV_ACR_CTRL 0x4 | 89 | #define HDMI_CORE_AV_ACR_CTRL 0x4 |
| 114 | #define HDMI_CORE_AV_FREQ_SVAL 0x8 | 90 | #define HDMI_CORE_AV_FREQ_SVAL 0x8 |
| 115 | #define HDMI_CORE_AV_N_SVAL1 0xC | 91 | #define HDMI_CORE_AV_N_SVAL1 0xC |
| @@ -148,25 +124,39 @@ | |||
| 148 | #define HDMI_CORE_AV_AVI_VERS 0x104 | 124 | #define HDMI_CORE_AV_AVI_VERS 0x104 |
| 149 | #define HDMI_CORE_AV_AVI_LEN 0x108 | 125 | #define HDMI_CORE_AV_AVI_LEN 0x108 |
| 150 | #define HDMI_CORE_AV_AVI_CHSUM 0x10C | 126 | #define HDMI_CORE_AV_AVI_CHSUM 0x10C |
| 127 | #define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110) | ||
| 151 | #define HDMI_CORE_AV_SPD_TYPE 0x180 | 128 | #define HDMI_CORE_AV_SPD_TYPE 0x180 |
| 152 | #define HDMI_CORE_AV_SPD_VERS 0x184 | 129 | #define HDMI_CORE_AV_SPD_VERS 0x184 |
| 153 | #define HDMI_CORE_AV_SPD_LEN 0x188 | 130 | #define HDMI_CORE_AV_SPD_LEN 0x188 |
| 154 | #define HDMI_CORE_AV_SPD_CHSUM 0x18C | 131 | #define HDMI_CORE_AV_SPD_CHSUM 0x18C |
| 132 | #define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190) | ||
| 155 | #define HDMI_CORE_AV_AUDIO_TYPE 0x200 | 133 | #define HDMI_CORE_AV_AUDIO_TYPE 0x200 |
| 156 | #define HDMI_CORE_AV_AUDIO_VERS 0x204 | 134 | #define HDMI_CORE_AV_AUDIO_VERS 0x204 |
| 157 | #define HDMI_CORE_AV_AUDIO_LEN 0x208 | 135 | #define HDMI_CORE_AV_AUDIO_LEN 0x208 |
| 158 | #define HDMI_CORE_AV_AUDIO_CHSUM 0x20C | 136 | #define HDMI_CORE_AV_AUDIO_CHSUM 0x20C |
| 137 | #define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210) | ||
| 159 | #define HDMI_CORE_AV_MPEG_TYPE 0x280 | 138 | #define HDMI_CORE_AV_MPEG_TYPE 0x280 |
| 160 | #define HDMI_CORE_AV_MPEG_VERS 0x284 | 139 | #define HDMI_CORE_AV_MPEG_VERS 0x284 |
| 161 | #define HDMI_CORE_AV_MPEG_LEN 0x288 | 140 | #define HDMI_CORE_AV_MPEG_LEN 0x288 |
| 162 | #define HDMI_CORE_AV_MPEG_CHSUM 0x28C | 141 | #define HDMI_CORE_AV_MPEG_CHSUM 0x28C |
| 142 | #define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290) | ||
| 143 | #define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300) | ||
| 163 | #define HDMI_CORE_AV_CP_BYTE1 0x37C | 144 | #define HDMI_CORE_AV_CP_BYTE1 0x37C |
| 145 | #define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380) | ||
| 164 | #define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC | 146 | #define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC |
| 147 | |||
| 165 | #define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4 | 148 | #define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4 |
| 166 | #define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4 | 149 | #define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4 |
| 167 | #define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4 | 150 | #define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4 |
| 168 | #define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4 | 151 | #define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4 |
| 169 | 152 | ||
| 153 | #define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15 | ||
| 154 | #define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27 | ||
| 155 | #define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10 | ||
| 156 | #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27 | ||
| 157 | #define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31 | ||
| 158 | #define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31 | ||
| 159 | |||
| 170 | /* PLL */ | 160 | /* PLL */ |
| 171 | 161 | ||
| 172 | #define PLLCTRL_PLL_CONTROL 0x0 | 162 | #define PLLCTRL_PLL_CONTROL 0x0 |
| @@ -284,35 +274,6 @@ enum hdmi_core_infoframe { | |||
| 284 | HDMI_INFOFRAME_AVI_DB5PR_8 = 7, | 274 | HDMI_INFOFRAME_AVI_DB5PR_8 = 7, |
| 285 | HDMI_INFOFRAME_AVI_DB5PR_9 = 8, | 275 | HDMI_INFOFRAME_AVI_DB5PR_9 = 8, |
| 286 | HDMI_INFOFRAME_AVI_DB5PR_10 = 9, | 276 | HDMI_INFOFRAME_AVI_DB5PR_10 = 9, |
| 287 | HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0, | ||
| 288 | HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1, | ||
| 289 | HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2, | ||
| 290 | HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3, | ||
| 291 | HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4, | ||
| 292 | HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5, | ||
| 293 | HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6, | ||
| 294 | HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7, | ||
| 295 | HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8, | ||
| 296 | HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9, | ||
| 297 | HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10, | ||
| 298 | HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11, | ||
| 299 | HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12, | ||
| 300 | HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13, | ||
| 301 | HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14, | ||
| 302 | HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0, | ||
| 303 | HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1, | ||
| 304 | HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2, | ||
| 305 | HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3, | ||
| 306 | HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4, | ||
| 307 | HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5, | ||
| 308 | HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6, | ||
| 309 | HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7, | ||
| 310 | HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0, | ||
| 311 | HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1, | ||
| 312 | HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2, | ||
| 313 | HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3, | ||
| 314 | HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0, | ||
| 315 | HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1 | ||
| 316 | }; | 277 | }; |
| 317 | 278 | ||
| 318 | enum hdmi_packing_mode { | 279 | enum hdmi_packing_mode { |
| @@ -322,17 +283,6 @@ enum hdmi_packing_mode { | |||
| 322 | HDMI_PACK_ALREADYPACKED = 7 | 283 | HDMI_PACK_ALREADYPACKED = 7 |
| 323 | }; | 284 | }; |
| 324 | 285 | ||
| 325 | enum hdmi_core_audio_sample_freq { | ||
| 326 | HDMI_AUDIO_FS_32000 = 0x3, | ||
| 327 | HDMI_AUDIO_FS_44100 = 0x0, | ||
| 328 | HDMI_AUDIO_FS_48000 = 0x2, | ||
| 329 | HDMI_AUDIO_FS_88200 = 0x8, | ||
| 330 | HDMI_AUDIO_FS_96000 = 0xA, | ||
| 331 | HDMI_AUDIO_FS_176400 = 0xC, | ||
| 332 | HDMI_AUDIO_FS_192000 = 0xE, | ||
| 333 | HDMI_AUDIO_FS_NOT_INDICATED = 0x1 | ||
| 334 | }; | ||
| 335 | |||
| 336 | enum hdmi_core_audio_layout { | 286 | enum hdmi_core_audio_layout { |
| 337 | HDMI_AUDIO_LAYOUT_2CH = 0, | 287 | HDMI_AUDIO_LAYOUT_2CH = 0, |
| 338 | HDMI_AUDIO_LAYOUT_8CH = 1 | 288 | HDMI_AUDIO_LAYOUT_8CH = 1 |
| @@ -387,37 +337,12 @@ enum hdmi_audio_blk_strt_end_sig { | |||
| 387 | }; | 337 | }; |
| 388 | 338 | ||
| 389 | enum hdmi_audio_i2s_config { | 339 | enum hdmi_audio_i2s_config { |
| 390 | HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0, | ||
| 391 | HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1, | ||
| 392 | HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0, | 340 | HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0, |
| 393 | HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1, | 341 | HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1, |
| 394 | HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0, | ||
| 395 | HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1, | ||
| 396 | HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0, | ||
| 397 | HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1, | ||
| 398 | HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6, | ||
| 399 | HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2, | ||
| 400 | HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4, | ||
| 401 | HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5, | ||
| 402 | HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1, | ||
| 403 | HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6, | ||
| 404 | HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2, | ||
| 405 | HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4, | ||
| 406 | HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5, | ||
| 407 | HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0, | 342 | HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0, |
| 408 | HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1, | 343 | HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1, |
| 409 | HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0, | 344 | HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0, |
| 410 | HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1, | 345 | HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1, |
| 411 | HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0, | ||
| 412 | HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2, | ||
| 413 | HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12, | ||
| 414 | HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4, | ||
| 415 | HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8, | ||
| 416 | HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10, | ||
| 417 | HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13, | ||
| 418 | HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5, | ||
| 419 | HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9, | ||
| 420 | HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11, | ||
| 421 | HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0, | 346 | HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0, |
| 422 | HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1, | 347 | HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1, |
| 423 | HDMI_AUDIO_I2S_SD0_EN = 1, | 348 | HDMI_AUDIO_I2S_SD0_EN = 1, |
| @@ -446,20 +371,6 @@ struct hdmi_core_video_config { | |||
| 446 | enum hdmi_core_tclkselclkmult tclk_sel_clkmult; | 371 | enum hdmi_core_tclkselclkmult tclk_sel_clkmult; |
| 447 | }; | 372 | }; |
| 448 | 373 | ||
| 449 | /* | ||
| 450 | * Refer to section 8.2 in HDMI 1.3 specification for | ||
| 451 | * details about infoframe databytes | ||
| 452 | */ | ||
| 453 | struct hdmi_core_infoframe_audio { | ||
| 454 | u8 db1_coding_type; | ||
| 455 | u8 db1_channel_count; | ||
| 456 | u8 db2_sample_freq; | ||
| 457 | u8 db2_sample_size; | ||
| 458 | u8 db4_channel_alloc; | ||
| 459 | bool db5_downmix_inh; | ||
| 460 | u8 db5_lsv; /* Level shift values for downmix */ | ||
| 461 | }; | ||
| 462 | |||
| 463 | struct hdmi_core_packet_enable_repeat { | 374 | struct hdmi_core_packet_enable_repeat { |
| 464 | u32 audio_pkt; | 375 | u32 audio_pkt; |
| 465 | u32 audio_pkt_repeat; | 376 | u32 audio_pkt_repeat; |
| @@ -496,15 +407,10 @@ struct hdmi_audio_dma { | |||
| 496 | }; | 407 | }; |
| 497 | 408 | ||
| 498 | struct hdmi_core_audio_i2s_config { | 409 | struct hdmi_core_audio_i2s_config { |
| 499 | u8 word_max_length; | ||
| 500 | u8 word_length; | ||
| 501 | u8 in_length_bits; | 410 | u8 in_length_bits; |
| 502 | u8 justification; | 411 | u8 justification; |
| 503 | u8 en_high_bitrate_aud; | ||
| 504 | u8 sck_edge_mode; | 412 | u8 sck_edge_mode; |
| 505 | u8 cbit_order; | ||
| 506 | u8 vbit; | 413 | u8 vbit; |
| 507 | u8 ws_polarity; | ||
| 508 | u8 direction; | 414 | u8 direction; |
| 509 | u8 shift; | 415 | u8 shift; |
| 510 | u8 active_sds; | 416 | u8 active_sds; |
| @@ -512,7 +418,7 @@ struct hdmi_core_audio_i2s_config { | |||
| 512 | 418 | ||
| 513 | struct hdmi_core_audio_config { | 419 | struct hdmi_core_audio_config { |
| 514 | struct hdmi_core_audio_i2s_config i2s_cfg; | 420 | struct hdmi_core_audio_i2s_config i2s_cfg; |
| 515 | enum hdmi_core_audio_sample_freq freq_sample; | 421 | struct snd_aes_iec958 *iec60958_cfg; |
| 516 | bool fs_override; | 422 | bool fs_override; |
| 517 | u32 n; | 423 | u32 n; |
| 518 | u32 cts; | 424 | u32 cts; |
| @@ -527,17 +433,4 @@ struct hdmi_core_audio_config { | |||
| 527 | bool en_spdif; | 433 | bool en_spdif; |
| 528 | }; | 434 | }; |
| 529 | 435 | ||
| 530 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
| 531 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
| 532 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | ||
| 533 | u32 sample_freq, u32 *n, u32 *cts); | ||
| 534 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | ||
| 535 | struct hdmi_core_infoframe_audio *info_aud); | ||
| 536 | void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | ||
| 537 | struct hdmi_core_audio_config *cfg); | ||
| 538 | void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | ||
| 539 | struct hdmi_audio_dma *aud_dma); | ||
| 540 | void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, | ||
| 541 | struct hdmi_audio_format *aud_fmt); | ||
| 542 | #endif | ||
| 543 | #endif | 436 | #endif |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 9c3daf71750c..2b8973931ff4 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
| @@ -415,6 +415,7 @@ static const struct venc_config *venc_timings_to_config( | |||
| 415 | return &venc_config_ntsc_trm; | 415 | return &venc_config_ntsc_trm; |
| 416 | 416 | ||
| 417 | BUG(); | 417 | BUG(); |
| 418 | return NULL; | ||
| 418 | } | 419 | } |
| 419 | 420 | ||
| 420 | static int venc_power_on(struct omap_dss_device *dssdev) | 421 | static int venc_power_on(struct omap_dss_device *dssdev) |
| @@ -440,10 +441,11 @@ static int venc_power_on(struct omap_dss_device *dssdev) | |||
| 440 | 441 | ||
| 441 | venc_write_reg(VENC_OUTPUT_CONTROL, l); | 442 | venc_write_reg(VENC_OUTPUT_CONTROL, l); |
| 442 | 443 | ||
| 443 | dispc_set_digit_size(dssdev->panel.timings.x_res, | 444 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); |
| 444 | dssdev->panel.timings.y_res/2); | ||
| 445 | 445 | ||
| 446 | regulator_enable(venc.vdda_dac_reg); | 446 | r = regulator_enable(venc.vdda_dac_reg); |
| 447 | if (r) | ||
| 448 | goto err; | ||
| 447 | 449 | ||
| 448 | if (dssdev->platform_enable) | 450 | if (dssdev->platform_enable) |
| 449 | dssdev->platform_enable(dssdev); | 451 | dssdev->platform_enable(dssdev); |
| @@ -485,16 +487,68 @@ unsigned long venc_get_pixel_clock(void) | |||
| 485 | return 13500000; | 487 | return 13500000; |
| 486 | } | 488 | } |
| 487 | 489 | ||
| 490 | static ssize_t display_output_type_show(struct device *dev, | ||
| 491 | struct device_attribute *attr, char *buf) | ||
| 492 | { | ||
| 493 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 494 | const char *ret; | ||
| 495 | |||
| 496 | switch (dssdev->phy.venc.type) { | ||
| 497 | case OMAP_DSS_VENC_TYPE_COMPOSITE: | ||
| 498 | ret = "composite"; | ||
| 499 | break; | ||
| 500 | case OMAP_DSS_VENC_TYPE_SVIDEO: | ||
| 501 | ret = "svideo"; | ||
| 502 | break; | ||
| 503 | default: | ||
| 504 | return -EINVAL; | ||
| 505 | } | ||
| 506 | |||
| 507 | return snprintf(buf, PAGE_SIZE, "%s\n", ret); | ||
| 508 | } | ||
| 509 | |||
| 510 | static ssize_t display_output_type_store(struct device *dev, | ||
| 511 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 512 | { | ||
| 513 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 514 | enum omap_dss_venc_type new_type; | ||
| 515 | |||
| 516 | if (sysfs_streq("composite", buf)) | ||
| 517 | new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; | ||
| 518 | else if (sysfs_streq("svideo", buf)) | ||
| 519 | new_type = OMAP_DSS_VENC_TYPE_SVIDEO; | ||
| 520 | else | ||
| 521 | return -EINVAL; | ||
| 522 | |||
| 523 | mutex_lock(&venc.venc_lock); | ||
| 524 | |||
| 525 | if (dssdev->phy.venc.type != new_type) { | ||
| 526 | dssdev->phy.venc.type = new_type; | ||
| 527 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
| 528 | venc_power_off(dssdev); | ||
| 529 | venc_power_on(dssdev); | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | mutex_unlock(&venc.venc_lock); | ||
| 534 | |||
| 535 | return size; | ||
| 536 | } | ||
| 537 | |||
| 538 | static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, | ||
| 539 | display_output_type_show, display_output_type_store); | ||
| 540 | |||
| 488 | /* driver */ | 541 | /* driver */ |
| 489 | static int venc_panel_probe(struct omap_dss_device *dssdev) | 542 | static int venc_panel_probe(struct omap_dss_device *dssdev) |
| 490 | { | 543 | { |
| 491 | dssdev->panel.timings = omap_dss_pal_timings; | 544 | dssdev->panel.timings = omap_dss_pal_timings; |
| 492 | 545 | ||
| 493 | return 0; | 546 | return device_create_file(&dssdev->dev, &dev_attr_output_type); |
| 494 | } | 547 | } |
| 495 | 548 | ||
| 496 | static void venc_panel_remove(struct omap_dss_device *dssdev) | 549 | static void venc_panel_remove(struct omap_dss_device *dssdev) |
| 497 | { | 550 | { |
| 551 | device_remove_file(&dssdev->dev, &dev_attr_output_type); | ||
| 498 | } | 552 | } |
| 499 | 553 | ||
| 500 | static int venc_panel_enable(struct omap_dss_device *dssdev) | 554 | static int venc_panel_enable(struct omap_dss_device *dssdev) |
| @@ -577,12 +631,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev) | |||
| 577 | return venc_panel_enable(dssdev); | 631 | return venc_panel_enable(dssdev); |
| 578 | } | 632 | } |
| 579 | 633 | ||
| 580 | static void venc_get_timings(struct omap_dss_device *dssdev, | ||
| 581 | struct omap_video_timings *timings) | ||
| 582 | { | ||
| 583 | *timings = dssdev->panel.timings; | ||
| 584 | } | ||
| 585 | |||
| 586 | static void venc_set_timings(struct omap_dss_device *dssdev, | 634 | static void venc_set_timings(struct omap_dss_device *dssdev, |
| 587 | struct omap_video_timings *timings) | 635 | struct omap_video_timings *timings) |
| 588 | { | 636 | { |
| @@ -597,6 +645,8 @@ static void venc_set_timings(struct omap_dss_device *dssdev, | |||
| 597 | /* turn the venc off and on to get new timings to use */ | 645 | /* turn the venc off and on to get new timings to use */ |
| 598 | venc_panel_disable(dssdev); | 646 | venc_panel_disable(dssdev); |
| 599 | venc_panel_enable(dssdev); | 647 | venc_panel_enable(dssdev); |
| 648 | } else { | ||
| 649 | dss_mgr_set_timings(dssdev->manager, timings); | ||
| 600 | } | 650 | } |
| 601 | } | 651 | } |
| 602 | 652 | ||
| @@ -661,7 +711,6 @@ static struct omap_dss_driver venc_driver = { | |||
| 661 | .get_resolution = omapdss_default_get_resolution, | 711 | .get_resolution = omapdss_default_get_resolution, |
| 662 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | 712 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, |
| 663 | 713 | ||
| 664 | .get_timings = venc_get_timings, | ||
| 665 | .set_timings = venc_set_timings, | 714 | .set_timings = venc_set_timings, |
| 666 | .check_timings = venc_check_timings, | 715 | .check_timings = venc_check_timings, |
| 667 | 716 | ||
| @@ -675,7 +724,7 @@ static struct omap_dss_driver venc_driver = { | |||
| 675 | }; | 724 | }; |
| 676 | /* driver end */ | 725 | /* driver end */ |
| 677 | 726 | ||
| 678 | int venc_init_display(struct omap_dss_device *dssdev) | 727 | static int __init venc_init_display(struct omap_dss_device *dssdev) |
| 679 | { | 728 | { |
| 680 | DSSDBG("init_display\n"); | 729 | DSSDBG("init_display\n"); |
| 681 | 730 | ||
| @@ -695,7 +744,7 @@ int venc_init_display(struct omap_dss_device *dssdev) | |||
| 695 | return 0; | 744 | return 0; |
| 696 | } | 745 | } |
| 697 | 746 | ||
| 698 | void venc_dump_regs(struct seq_file *s) | 747 | static void venc_dump_regs(struct seq_file *s) |
| 699 | { | 748 | { |
| 700 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) | 749 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) |
| 701 | 750 | ||
| @@ -779,8 +828,32 @@ static void venc_put_clocks(void) | |||
| 779 | clk_put(venc.tv_dac_clk); | 828 | clk_put(venc.tv_dac_clk); |
| 780 | } | 829 | } |
| 781 | 830 | ||
| 831 | static void __init venc_probe_pdata(struct platform_device *pdev) | ||
| 832 | { | ||
| 833 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 834 | int r, i; | ||
| 835 | |||
| 836 | for (i = 0; i < pdata->num_devices; ++i) { | ||
| 837 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
| 838 | |||
| 839 | if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) | ||
| 840 | continue; | ||
| 841 | |||
| 842 | r = venc_init_display(dssdev); | ||
| 843 | if (r) { | ||
| 844 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
| 845 | continue; | ||
| 846 | } | ||
| 847 | |||
| 848 | r = omap_dss_register_device(dssdev, &pdev->dev, i); | ||
| 849 | if (r) | ||
| 850 | DSSERR("device %s register failed: %d\n", | ||
| 851 | dssdev->name, r); | ||
| 852 | } | ||
| 853 | } | ||
| 854 | |||
| 782 | /* VENC HW IP initialisation */ | 855 | /* VENC HW IP initialisation */ |
| 783 | static int omap_venchw_probe(struct platform_device *pdev) | 856 | static int __init omap_venchw_probe(struct platform_device *pdev) |
| 784 | { | 857 | { |
| 785 | u8 rev_id; | 858 | u8 rev_id; |
| 786 | struct resource *venc_mem; | 859 | struct resource *venc_mem; |
| @@ -824,6 +897,10 @@ static int omap_venchw_probe(struct platform_device *pdev) | |||
| 824 | if (r) | 897 | if (r) |
| 825 | goto err_reg_panel_driver; | 898 | goto err_reg_panel_driver; |
| 826 | 899 | ||
| 900 | dss_debugfs_create_file("venc", venc_dump_regs); | ||
| 901 | |||
| 902 | venc_probe_pdata(pdev); | ||
| 903 | |||
| 827 | return 0; | 904 | return 0; |
| 828 | 905 | ||
| 829 | err_reg_panel_driver: | 906 | err_reg_panel_driver: |
| @@ -833,12 +910,15 @@ err_runtime_get: | |||
| 833 | return r; | 910 | return r; |
| 834 | } | 911 | } |
| 835 | 912 | ||
| 836 | static int omap_venchw_remove(struct platform_device *pdev) | 913 | static int __exit omap_venchw_remove(struct platform_device *pdev) |
| 837 | { | 914 | { |
| 915 | omap_dss_unregister_child_devices(&pdev->dev); | ||
| 916 | |||
| 838 | if (venc.vdda_dac_reg != NULL) { | 917 | if (venc.vdda_dac_reg != NULL) { |
| 839 | regulator_put(venc.vdda_dac_reg); | 918 | regulator_put(venc.vdda_dac_reg); |
| 840 | venc.vdda_dac_reg = NULL; | 919 | venc.vdda_dac_reg = NULL; |
| 841 | } | 920 | } |
| 921 | |||
| 842 | omap_dss_unregister_driver(&venc_driver); | 922 | omap_dss_unregister_driver(&venc_driver); |
| 843 | 923 | ||
| 844 | pm_runtime_disable(&pdev->dev); | 924 | pm_runtime_disable(&pdev->dev); |
| @@ -853,7 +933,6 @@ static int venc_runtime_suspend(struct device *dev) | |||
| 853 | clk_disable(venc.tv_dac_clk); | 933 | clk_disable(venc.tv_dac_clk); |
| 854 | 934 | ||
| 855 | dispc_runtime_put(); | 935 | dispc_runtime_put(); |
| 856 | dss_runtime_put(); | ||
| 857 | 936 | ||
| 858 | return 0; | 937 | return 0; |
| 859 | } | 938 | } |
| @@ -862,23 +941,14 @@ static int venc_runtime_resume(struct device *dev) | |||
| 862 | { | 941 | { |
| 863 | int r; | 942 | int r; |
| 864 | 943 | ||
| 865 | r = dss_runtime_get(); | ||
| 866 | if (r < 0) | ||
| 867 | goto err_get_dss; | ||
| 868 | |||
| 869 | r = dispc_runtime_get(); | 944 | r = dispc_runtime_get(); |
| 870 | if (r < 0) | 945 | if (r < 0) |
| 871 | goto err_get_dispc; | 946 | return r; |
| 872 | 947 | ||
| 873 | if (venc.tv_dac_clk) | 948 | if (venc.tv_dac_clk) |
| 874 | clk_enable(venc.tv_dac_clk); | 949 | clk_enable(venc.tv_dac_clk); |
| 875 | 950 | ||
| 876 | return 0; | 951 | return 0; |
| 877 | |||
| 878 | err_get_dispc: | ||
| 879 | dss_runtime_put(); | ||
| 880 | err_get_dss: | ||
| 881 | return r; | ||
| 882 | } | 952 | } |
| 883 | 953 | ||
| 884 | static const struct dev_pm_ops venc_pm_ops = { | 954 | static const struct dev_pm_ops venc_pm_ops = { |
| @@ -887,8 +957,7 @@ static const struct dev_pm_ops venc_pm_ops = { | |||
| 887 | }; | 957 | }; |
| 888 | 958 | ||
| 889 | static struct platform_driver omap_venchw_driver = { | 959 | static struct platform_driver omap_venchw_driver = { |
| 890 | .probe = omap_venchw_probe, | 960 | .remove = __exit_p(omap_venchw_remove), |
| 891 | .remove = omap_venchw_remove, | ||
| 892 | .driver = { | 961 | .driver = { |
| 893 | .name = "omapdss_venc", | 962 | .name = "omapdss_venc", |
| 894 | .owner = THIS_MODULE, | 963 | .owner = THIS_MODULE, |
| @@ -896,18 +965,18 @@ static struct platform_driver omap_venchw_driver = { | |||
| 896 | }, | 965 | }, |
| 897 | }; | 966 | }; |
| 898 | 967 | ||
| 899 | int venc_init_platform_driver(void) | 968 | int __init venc_init_platform_driver(void) |
| 900 | { | 969 | { |
| 901 | if (cpu_is_omap44xx()) | 970 | if (cpu_is_omap44xx()) |
| 902 | return 0; | 971 | return 0; |
| 903 | 972 | ||
| 904 | return platform_driver_register(&omap_venchw_driver); | 973 | return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); |
| 905 | } | 974 | } |
| 906 | 975 | ||
| 907 | void venc_uninit_platform_driver(void) | 976 | void __exit venc_uninit_platform_driver(void) |
| 908 | { | 977 | { |
| 909 | if (cpu_is_omap44xx()) | 978 | if (cpu_is_omap44xx()) |
| 910 | return; | 979 | return; |
| 911 | 980 | ||
| 912 | return platform_driver_unregister(&omap_venchw_driver); | 981 | platform_driver_unregister(&omap_venchw_driver); |
| 913 | } | 982 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 6a09ef87e14f..c6cf372d22c5 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
| @@ -70,7 +70,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
| 70 | 70 | ||
| 71 | DBG("omapfb_setup_plane\n"); | 71 | DBG("omapfb_setup_plane\n"); |
| 72 | 72 | ||
| 73 | if (ofbi->num_overlays != 1) { | 73 | if (ofbi->num_overlays == 0) { |
| 74 | r = -EINVAL; | 74 | r = -EINVAL; |
| 75 | goto out; | 75 | goto out; |
| 76 | } | 76 | } |
| @@ -185,7 +185,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
| 185 | { | 185 | { |
| 186 | struct omapfb_info *ofbi = FB2OFB(fbi); | 186 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 187 | 187 | ||
| 188 | if (ofbi->num_overlays != 1) { | 188 | if (ofbi->num_overlays == 0) { |
| 189 | memset(pi, 0, sizeof(*pi)); | 189 | memset(pi, 0, sizeof(*pi)); |
| 190 | } else { | 190 | } else { |
| 191 | struct omap_overlay *ovl; | 191 | struct omap_overlay *ovl; |
| @@ -225,6 +225,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 225 | down_write_nested(&rg->lock, rg->id); | 225 | down_write_nested(&rg->lock, rg->id); |
| 226 | atomic_inc(&rg->lock_count); | 226 | atomic_inc(&rg->lock_count); |
| 227 | 227 | ||
| 228 | if (rg->size == size && rg->type == mi->type) | ||
| 229 | goto out; | ||
| 230 | |||
| 228 | if (atomic_read(&rg->map_count)) { | 231 | if (atomic_read(&rg->map_count)) { |
| 229 | r = -EBUSY; | 232 | r = -EBUSY; |
| 230 | goto out; | 233 | goto out; |
| @@ -247,12 +250,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 247 | } | 250 | } |
| 248 | } | 251 | } |
| 249 | 252 | ||
| 250 | if (rg->size != size || rg->type != mi->type) { | 253 | r = omapfb_realloc_fbmem(fbi, size, mi->type); |
| 251 | r = omapfb_realloc_fbmem(fbi, size, mi->type); | 254 | if (r) { |
| 252 | if (r) { | 255 | dev_err(fbdev->dev, "realloc fbmem failed\n"); |
| 253 | dev_err(fbdev->dev, "realloc fbmem failed\n"); | 256 | goto out; |
| 254 | goto out; | ||
| 255 | } | ||
| 256 | } | 257 | } |
| 257 | 258 | ||
| 258 | out: | 259 | out: |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index b00db4068d21..3450ea0966c9 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
| @@ -179,6 +179,7 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) | |||
| 179 | break; | 179 | break; |
| 180 | default: | 180 | default: |
| 181 | BUG(); | 181 | BUG(); |
| 182 | return 0; | ||
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | offset *= vrfb->bytespp; | 185 | offset *= vrfb->bytespp; |
| @@ -1502,7 +1503,7 @@ static int omapfb_parse_vram_param(const char *param, int max_entries, | |||
| 1502 | 1503 | ||
| 1503 | fbnum = simple_strtoul(p, &p, 10); | 1504 | fbnum = simple_strtoul(p, &p, 10); |
| 1504 | 1505 | ||
| 1505 | if (p == param) | 1506 | if (p == start) |
| 1506 | return -EINVAL; | 1507 | return -EINVAL; |
| 1507 | 1508 | ||
| 1508 | if (*p != ':') | 1509 | if (*p != ':') |
| @@ -2307,7 +2308,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
| 2307 | return 0; | 2308 | return 0; |
| 2308 | } | 2309 | } |
| 2309 | 2310 | ||
| 2310 | static int omapfb_probe(struct platform_device *pdev) | 2311 | static int __init omapfb_probe(struct platform_device *pdev) |
| 2311 | { | 2312 | { |
| 2312 | struct omapfb2_device *fbdev = NULL; | 2313 | struct omapfb2_device *fbdev = NULL; |
| 2313 | int r = 0; | 2314 | int r = 0; |
| @@ -2448,7 +2449,7 @@ err0: | |||
| 2448 | return r; | 2449 | return r; |
| 2449 | } | 2450 | } |
| 2450 | 2451 | ||
| 2451 | static int omapfb_remove(struct platform_device *pdev) | 2452 | static int __exit omapfb_remove(struct platform_device *pdev) |
| 2452 | { | 2453 | { |
| 2453 | struct omapfb2_device *fbdev = platform_get_drvdata(pdev); | 2454 | struct omapfb2_device *fbdev = platform_get_drvdata(pdev); |
| 2454 | 2455 | ||
| @@ -2462,8 +2463,7 @@ static int omapfb_remove(struct platform_device *pdev) | |||
| 2462 | } | 2463 | } |
| 2463 | 2464 | ||
| 2464 | static struct platform_driver omapfb_driver = { | 2465 | static struct platform_driver omapfb_driver = { |
| 2465 | .probe = omapfb_probe, | 2466 | .remove = __exit_p(omapfb_remove), |
| 2466 | .remove = omapfb_remove, | ||
| 2467 | .driver = { | 2467 | .driver = { |
| 2468 | .name = "omapfb", | 2468 | .name = "omapfb", |
| 2469 | .owner = THIS_MODULE, | 2469 | .owner = THIS_MODULE, |
| @@ -2474,7 +2474,7 @@ static int __init omapfb_init(void) | |||
| 2474 | { | 2474 | { |
| 2475 | DBG("omapfb_init\n"); | 2475 | DBG("omapfb_init\n"); |
| 2476 | 2476 | ||
| 2477 | if (platform_driver_register(&omapfb_driver)) { | 2477 | if (platform_driver_probe(&omapfb_driver, omapfb_probe)) { |
| 2478 | printk(KERN_ERR "failed to register omapfb driver\n"); | 2478 | printk(KERN_ERR "failed to register omapfb driver\n"); |
| 2479 | return -ENODEV; | 2479 | return -ENODEV; |
| 2480 | } | 2480 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index c0bdc9b54ecf..30361a09aecd 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h | |||
| @@ -166,6 +166,7 @@ static inline struct omapfb_display_data *get_display_data( | |||
| 166 | 166 | ||
| 167 | /* This should never happen */ | 167 | /* This should never happen */ |
| 168 | BUG(); | 168 | BUG(); |
| 169 | return NULL; | ||
| 169 | } | 170 | } |
| 170 | 171 | ||
| 171 | static inline void omapfb_lock(struct omapfb2_device *fbdev) | 172 | static inline void omapfb_lock(struct omapfb2_device *fbdev) |
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c index 4e5b960c32c8..7e990220ad2a 100644 --- a/drivers/video/omap2/vrfb.c +++ b/drivers/video/omap2/vrfb.c | |||
| @@ -179,8 +179,10 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr, | |||
| 179 | pixel_size_exp = 2; | 179 | pixel_size_exp = 2; |
| 180 | else if (bytespp == 2) | 180 | else if (bytespp == 2) |
| 181 | pixel_size_exp = 1; | 181 | pixel_size_exp = 1; |
| 182 | else | 182 | else { |
| 183 | BUG(); | 183 | BUG(); |
| 184 | return; | ||
| 185 | } | ||
| 184 | 186 | ||
| 185 | vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp; | 187 | vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp; |
| 186 | vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT); | 188 | vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT); |
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 1d71c08a818f..0b4ae0cebeda 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c | |||
| @@ -316,12 +316,9 @@ pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv) | |||
| 316 | ret = wait_event_interruptible_timeout(priv->wait_idle, | 316 | ret = wait_event_interruptible_timeout(priv->wait_idle, |
| 317 | !priv->shared->hw_running, HZ*4); | 317 | !priv->shared->hw_running, HZ*4); |
| 318 | 318 | ||
| 319 | if (ret < 0) | 319 | if (ret != 0) |
| 320 | break; | 320 | break; |
| 321 | 321 | ||
| 322 | if (ret > 0) | ||
| 323 | continue; | ||
| 324 | |||
| 325 | if (gc_readl(priv, REG_GCRBEXHR) == rbexhr && | 322 | if (gc_readl(priv, REG_GCRBEXHR) == rbexhr && |
| 326 | priv->shared->num_interrupts == num) { | 323 | priv->shared->num_interrupts == num) { |
| 327 | QERROR("TIMEOUT"); | 324 | QERROR("TIMEOUT"); |
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index f3105160bf98..5f9d8e69029e 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
| @@ -47,7 +47,7 @@ | |||
| 47 | #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE | 47 | #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE |
| 48 | #undef writel | 48 | #undef writel |
| 49 | #define writel(v, r) do { \ | 49 | #define writel(v, r) do { \ |
| 50 | printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ | 50 | pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \ |
| 51 | __raw_writel(v, r); \ | 51 | __raw_writel(v, r); \ |
| 52 | } while (0) | 52 | } while (0) |
| 53 | #endif /* FB_S3C_DEBUG_REGWRITE */ | 53 | #endif /* FB_S3C_DEBUG_REGWRITE */ |
| @@ -495,7 +495,6 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
| 495 | u32 alpha = 0; | 495 | u32 alpha = 0; |
| 496 | u32 data; | 496 | u32 data; |
| 497 | u32 pagewidth; | 497 | u32 pagewidth; |
| 498 | int clkdiv; | ||
| 499 | 498 | ||
| 500 | dev_dbg(sfb->dev, "setting framebuffer parameters\n"); | 499 | dev_dbg(sfb->dev, "setting framebuffer parameters\n"); |
| 501 | 500 | ||
| @@ -532,48 +531,9 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
| 532 | /* disable the window whilst we update it */ | 531 | /* disable the window whilst we update it */ |
| 533 | writel(0, regs + WINCON(win_no)); | 532 | writel(0, regs + WINCON(win_no)); |
| 534 | 533 | ||
| 535 | /* use platform specified window as the basis for the lcd timings */ | 534 | if (!sfb->output_on) |
| 536 | |||
| 537 | if (win_no == sfb->pdata->default_win) { | ||
| 538 | clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); | ||
| 539 | |||
| 540 | data = sfb->pdata->vidcon0; | ||
| 541 | data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); | ||
| 542 | |||
| 543 | if (clkdiv > 1) | ||
| 544 | data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; | ||
| 545 | else | ||
| 546 | data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ | ||
| 547 | |||
| 548 | /* write the timing data to the panel */ | ||
| 549 | |||
| 550 | if (sfb->variant.is_2443) | ||
| 551 | data |= (1 << 5); | ||
| 552 | |||
| 553 | writel(data, regs + VIDCON0); | ||
| 554 | |||
| 555 | s3c_fb_enable(sfb, 1); | 535 | s3c_fb_enable(sfb, 1); |
| 556 | 536 | ||
| 557 | data = VIDTCON0_VBPD(var->upper_margin - 1) | | ||
| 558 | VIDTCON0_VFPD(var->lower_margin - 1) | | ||
| 559 | VIDTCON0_VSPW(var->vsync_len - 1); | ||
| 560 | |||
| 561 | writel(data, regs + sfb->variant.vidtcon); | ||
| 562 | |||
| 563 | data = VIDTCON1_HBPD(var->left_margin - 1) | | ||
| 564 | VIDTCON1_HFPD(var->right_margin - 1) | | ||
| 565 | VIDTCON1_HSPW(var->hsync_len - 1); | ||
| 566 | |||
| 567 | /* VIDTCON1 */ | ||
| 568 | writel(data, regs + sfb->variant.vidtcon + 4); | ||
| 569 | |||
| 570 | data = VIDTCON2_LINEVAL(var->yres - 1) | | ||
| 571 | VIDTCON2_HOZVAL(var->xres - 1) | | ||
| 572 | VIDTCON2_LINEVAL_E(var->yres - 1) | | ||
| 573 | VIDTCON2_HOZVAL_E(var->xres - 1); | ||
| 574 | writel(data, regs + sfb->variant.vidtcon + 8); | ||
| 575 | } | ||
| 576 | |||
| 577 | /* write the buffer address */ | 537 | /* write the buffer address */ |
| 578 | 538 | ||
| 579 | /* start and end registers stride is 8 */ | 539 | /* start and end registers stride is 8 */ |
| @@ -839,6 +799,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
| 839 | struct s3c_fb *sfb = win->parent; | 799 | struct s3c_fb *sfb = win->parent; |
| 840 | unsigned int index = win->index; | 800 | unsigned int index = win->index; |
| 841 | u32 wincon; | 801 | u32 wincon; |
| 802 | u32 output_on = sfb->output_on; | ||
| 842 | 803 | ||
| 843 | dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); | 804 | dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); |
| 844 | 805 | ||
| @@ -877,34 +838,18 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
| 877 | 838 | ||
| 878 | shadow_protect_win(win, 1); | 839 | shadow_protect_win(win, 1); |
| 879 | writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); | 840 | writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); |
| 880 | shadow_protect_win(win, 0); | ||
| 881 | 841 | ||
| 882 | /* Check the enabled state to see if we need to be running the | 842 | /* Check the enabled state to see if we need to be running the |
| 883 | * main LCD interface, as if there are no active windows then | 843 | * main LCD interface, as if there are no active windows then |
| 884 | * it is highly likely that we also do not need to output | 844 | * it is highly likely that we also do not need to output |
| 885 | * anything. | 845 | * anything. |
| 886 | */ | 846 | */ |
| 887 | 847 | s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); | |
| 888 | /* We could do something like the following code, but the current | 848 | shadow_protect_win(win, 0); |
| 889 | * system of using framebuffer events means that we cannot make | ||
| 890 | * the distinction between just window 0 being inactive and all | ||
| 891 | * the windows being down. | ||
| 892 | * | ||
| 893 | * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0); | ||
| 894 | */ | ||
| 895 | |||
| 896 | /* we're stuck with this until we can do something about overriding | ||
| 897 | * the power control using the blanking event for a single fb. | ||
| 898 | */ | ||
| 899 | if (index == sfb->pdata->default_win) { | ||
| 900 | shadow_protect_win(win, 1); | ||
| 901 | s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); | ||
| 902 | shadow_protect_win(win, 0); | ||
| 903 | } | ||
| 904 | 849 | ||
| 905 | pm_runtime_put_sync(sfb->dev); | 850 | pm_runtime_put_sync(sfb->dev); |
| 906 | 851 | ||
| 907 | return 0; | 852 | return output_on == sfb->output_on; |
| 908 | } | 853 | } |
| 909 | 854 | ||
| 910 | /** | 855 | /** |
| @@ -1111,7 +1056,7 @@ static struct fb_ops s3c_fb_ops = { | |||
| 1111 | * | 1056 | * |
| 1112 | * Calculate the pixel clock when none has been given through platform data. | 1057 | * Calculate the pixel clock when none has been given through platform data. |
| 1113 | */ | 1058 | */ |
| 1114 | static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode) | 1059 | static void s3c_fb_missing_pixclock(struct fb_videomode *mode) |
| 1115 | { | 1060 | { |
| 1116 | u64 pixclk = 1000000000000ULL; | 1061 | u64 pixclk = 1000000000000ULL; |
| 1117 | u32 div; | 1062 | u32 div; |
| @@ -1144,11 +1089,11 @@ static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb, | |||
| 1144 | 1089 | ||
| 1145 | dev_dbg(sfb->dev, "allocating memory for display\n"); | 1090 | dev_dbg(sfb->dev, "allocating memory for display\n"); |
| 1146 | 1091 | ||
| 1147 | real_size = windata->win_mode.xres * windata->win_mode.yres; | 1092 | real_size = windata->xres * windata->yres; |
| 1148 | virt_size = windata->virtual_x * windata->virtual_y; | 1093 | virt_size = windata->virtual_x * windata->virtual_y; |
| 1149 | 1094 | ||
| 1150 | dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", | 1095 | dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n", |
| 1151 | real_size, windata->win_mode.xres, windata->win_mode.yres, | 1096 | real_size, windata->xres, windata->yres, |
| 1152 | virt_size, windata->virtual_x, windata->virtual_y); | 1097 | virt_size, windata->virtual_x, windata->virtual_y); |
| 1153 | 1098 | ||
| 1154 | size = (real_size > virt_size) ? real_size : virt_size; | 1099 | size = (real_size > virt_size) ? real_size : virt_size; |
| @@ -1230,7 +1175,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
| 1230 | struct s3c_fb_win **res) | 1175 | struct s3c_fb_win **res) |
| 1231 | { | 1176 | { |
| 1232 | struct fb_var_screeninfo *var; | 1177 | struct fb_var_screeninfo *var; |
| 1233 | struct fb_videomode *initmode; | 1178 | struct fb_videomode initmode; |
| 1234 | struct s3c_fb_pd_win *windata; | 1179 | struct s3c_fb_pd_win *windata; |
| 1235 | struct s3c_fb_win *win; | 1180 | struct s3c_fb_win *win; |
| 1236 | struct fb_info *fbinfo; | 1181 | struct fb_info *fbinfo; |
| @@ -1251,11 +1196,11 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
| 1251 | } | 1196 | } |
| 1252 | 1197 | ||
| 1253 | windata = sfb->pdata->win[win_no]; | 1198 | windata = sfb->pdata->win[win_no]; |
| 1254 | initmode = &windata->win_mode; | 1199 | initmode = *sfb->pdata->vtiming; |
| 1255 | 1200 | ||
| 1256 | WARN_ON(windata->max_bpp == 0); | 1201 | WARN_ON(windata->max_bpp == 0); |
| 1257 | WARN_ON(windata->win_mode.xres == 0); | 1202 | WARN_ON(windata->xres == 0); |
| 1258 | WARN_ON(windata->win_mode.yres == 0); | 1203 | WARN_ON(windata->yres == 0); |
| 1259 | 1204 | ||
| 1260 | win = fbinfo->par; | 1205 | win = fbinfo->par; |
| 1261 | *res = win; | 1206 | *res = win; |
| @@ -1294,7 +1239,9 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
| 1294 | } | 1239 | } |
| 1295 | 1240 | ||
| 1296 | /* setup the initial video mode from the window */ | 1241 | /* setup the initial video mode from the window */ |
| 1297 | fb_videomode_to_var(&fbinfo->var, initmode); | 1242 | initmode.xres = windata->xres; |
| 1243 | initmode.yres = windata->yres; | ||
| 1244 | fb_videomode_to_var(&fbinfo->var, &initmode); | ||
| 1298 | 1245 | ||
| 1299 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | 1246 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; |
| 1300 | fbinfo->fix.accel = FB_ACCEL_NONE; | 1247 | fbinfo->fix.accel = FB_ACCEL_NONE; |
| @@ -1339,6 +1286,53 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no, | |||
| 1339 | } | 1286 | } |
| 1340 | 1287 | ||
| 1341 | /** | 1288 | /** |
| 1289 | * s3c_fb_set_rgb_timing() - set video timing for rgb interface. | ||
| 1290 | * @sfb: The base resources for the hardware. | ||
| 1291 | * | ||
| 1292 | * Set horizontal and vertical lcd rgb interface timing. | ||
| 1293 | */ | ||
| 1294 | static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb) | ||
| 1295 | { | ||
| 1296 | struct fb_videomode *vmode = sfb->pdata->vtiming; | ||
| 1297 | void __iomem *regs = sfb->regs; | ||
| 1298 | int clkdiv; | ||
| 1299 | u32 data; | ||
| 1300 | |||
| 1301 | if (!vmode->pixclock) | ||
| 1302 | s3c_fb_missing_pixclock(vmode); | ||
| 1303 | |||
| 1304 | clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock); | ||
| 1305 | |||
| 1306 | data = sfb->pdata->vidcon0; | ||
| 1307 | data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); | ||
| 1308 | |||
| 1309 | if (clkdiv > 1) | ||
| 1310 | data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; | ||
| 1311 | else | ||
| 1312 | data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ | ||
| 1313 | |||
| 1314 | if (sfb->variant.is_2443) | ||
| 1315 | data |= (1 << 5); | ||
| 1316 | writel(data, regs + VIDCON0); | ||
| 1317 | |||
| 1318 | data = VIDTCON0_VBPD(vmode->upper_margin - 1) | | ||
| 1319 | VIDTCON0_VFPD(vmode->lower_margin - 1) | | ||
| 1320 | VIDTCON0_VSPW(vmode->vsync_len - 1); | ||
| 1321 | writel(data, regs + sfb->variant.vidtcon); | ||
| 1322 | |||
| 1323 | data = VIDTCON1_HBPD(vmode->left_margin - 1) | | ||
| 1324 | VIDTCON1_HFPD(vmode->right_margin - 1) | | ||
| 1325 | VIDTCON1_HSPW(vmode->hsync_len - 1); | ||
| 1326 | writel(data, regs + sfb->variant.vidtcon + 4); | ||
| 1327 | |||
| 1328 | data = VIDTCON2_LINEVAL(vmode->yres - 1) | | ||
| 1329 | VIDTCON2_HOZVAL(vmode->xres - 1) | | ||
| 1330 | VIDTCON2_LINEVAL_E(vmode->yres - 1) | | ||
| 1331 | VIDTCON2_HOZVAL_E(vmode->xres - 1); | ||
| 1332 | writel(data, regs + sfb->variant.vidtcon + 8); | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | /** | ||
| 1342 | * s3c_fb_clear_win() - clear hardware window registers. | 1336 | * s3c_fb_clear_win() - clear hardware window registers. |
| 1343 | * @sfb: The base resources for the hardware. | 1337 | * @sfb: The base resources for the hardware. |
| 1344 | * @win: The window to process. | 1338 | * @win: The window to process. |
| @@ -1481,15 +1475,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
| 1481 | writel(0xffffff, regs + WKEYCON1); | 1475 | writel(0xffffff, regs + WKEYCON1); |
| 1482 | } | 1476 | } |
| 1483 | 1477 | ||
| 1478 | s3c_fb_set_rgb_timing(sfb); | ||
| 1479 | |||
| 1484 | /* we have the register setup, start allocating framebuffers */ | 1480 | /* we have the register setup, start allocating framebuffers */ |
| 1485 | 1481 | ||
| 1486 | for (win = 0; win < fbdrv->variant.nr_windows; win++) { | 1482 | for (win = 0; win < fbdrv->variant.nr_windows; win++) { |
| 1487 | if (!pd->win[win]) | 1483 | if (!pd->win[win]) |
| 1488 | continue; | 1484 | continue; |
| 1489 | 1485 | ||
| 1490 | if (!pd->win[win]->win_mode.pixclock) | ||
| 1491 | s3c_fb_missing_pixclock(&pd->win[win]->win_mode); | ||
| 1492 | |||
| 1493 | ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], | 1486 | ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], |
| 1494 | &sfb->windows[win]); | 1487 | &sfb->windows[win]); |
| 1495 | if (ret < 0) { | 1488 | if (ret < 0) { |
| @@ -1564,6 +1557,8 @@ static int s3c_fb_suspend(struct device *dev) | |||
| 1564 | struct s3c_fb_win *win; | 1557 | struct s3c_fb_win *win; |
| 1565 | int win_no; | 1558 | int win_no; |
| 1566 | 1559 | ||
| 1560 | pm_runtime_get_sync(sfb->dev); | ||
| 1561 | |||
| 1567 | for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { | 1562 | for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { |
| 1568 | win = sfb->windows[win_no]; | 1563 | win = sfb->windows[win_no]; |
| 1569 | if (!win) | 1564 | if (!win) |
| @@ -1577,6 +1572,9 @@ static int s3c_fb_suspend(struct device *dev) | |||
| 1577 | clk_disable(sfb->lcd_clk); | 1572 | clk_disable(sfb->lcd_clk); |
| 1578 | 1573 | ||
| 1579 | clk_disable(sfb->bus_clk); | 1574 | clk_disable(sfb->bus_clk); |
| 1575 | |||
| 1576 | pm_runtime_put_sync(sfb->dev); | ||
| 1577 | |||
| 1580 | return 0; | 1578 | return 0; |
| 1581 | } | 1579 | } |
| 1582 | 1580 | ||
| @@ -1589,6 +1587,8 @@ static int s3c_fb_resume(struct device *dev) | |||
| 1589 | int win_no; | 1587 | int win_no; |
| 1590 | u32 reg; | 1588 | u32 reg; |
| 1591 | 1589 | ||
| 1590 | pm_runtime_get_sync(sfb->dev); | ||
| 1591 | |||
| 1592 | clk_enable(sfb->bus_clk); | 1592 | clk_enable(sfb->bus_clk); |
| 1593 | 1593 | ||
| 1594 | if (!sfb->variant.has_clksel) | 1594 | if (!sfb->variant.has_clksel) |
| @@ -1623,6 +1623,8 @@ static int s3c_fb_resume(struct device *dev) | |||
| 1623 | shadow_protect_win(win, 0); | 1623 | shadow_protect_win(win, 0); |
| 1624 | } | 1624 | } |
| 1625 | 1625 | ||
| 1626 | s3c_fb_set_rgb_timing(sfb); | ||
| 1627 | |||
| 1626 | /* restore framebuffers */ | 1628 | /* restore framebuffers */ |
| 1627 | for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { | 1629 | for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { |
| 1628 | win = sfb->windows[win_no]; | 1630 | win = sfb->windows[win_no]; |
| @@ -1633,6 +1635,8 @@ static int s3c_fb_resume(struct device *dev) | |||
| 1633 | s3c_fb_set_par(win->fbinfo); | 1635 | s3c_fb_set_par(win->fbinfo); |
| 1634 | } | 1636 | } |
| 1635 | 1637 | ||
| 1638 | pm_runtime_put_sync(sfb->dev); | ||
| 1639 | |||
| 1636 | return 0; | 1640 | return 0; |
| 1637 | } | 1641 | } |
| 1638 | #endif | 1642 | #endif |
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index eafb19da2c07..930e550e752a 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | #include "sh_mobile_lcdcfb.h" | 32 | #include "sh_mobile_lcdcfb.h" |
| 33 | 33 | ||
| 34 | /* HDMI Core Control Register (HTOP0) */ | ||
| 34 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ | 35 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ |
| 35 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, | 36 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, |
| 36 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ | 37 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ |
| @@ -201,6 +202,68 @@ | |||
| 201 | #define HDMI_REVISION_ID 0xF1 /* Revision ID */ | 202 | #define HDMI_REVISION_ID 0xF1 /* Revision ID */ |
| 202 | #define HDMI_TEST_MODE 0xFE /* Test mode */ | 203 | #define HDMI_TEST_MODE 0xFE /* Test mode */ |
| 203 | 204 | ||
| 205 | /* HDMI Control Register (HTOP1) */ | ||
| 206 | #define HDMI_HTOP1_TEST_MODE 0x0000 /* Test mode */ | ||
| 207 | #define HDMI_HTOP1_VIDEO_INPUT 0x0008 /* VideoInput */ | ||
| 208 | #define HDMI_HTOP1_CORE_RSTN 0x000C /* CoreResetn */ | ||
| 209 | #define HDMI_HTOP1_PLLBW 0x0018 /* PLLBW */ | ||
| 210 | #define HDMI_HTOP1_CLK_TO_PHY 0x001C /* Clk to Phy */ | ||
| 211 | #define HDMI_HTOP1_VIDEO_INPUT2 0x0020 /* VideoInput2 */ | ||
| 212 | #define HDMI_HTOP1_TISEMP0_1 0x0024 /* tisemp0-1 */ | ||
| 213 | #define HDMI_HTOP1_TISEMP2_C 0x0028 /* tisemp2-c */ | ||
| 214 | #define HDMI_HTOP1_TISIDRV 0x002C /* tisidrv */ | ||
| 215 | #define HDMI_HTOP1_TISEN 0x0034 /* tisen */ | ||
| 216 | #define HDMI_HTOP1_TISDREN 0x0038 /* tisdren */ | ||
| 217 | #define HDMI_HTOP1_CISRANGE 0x003C /* cisrange */ | ||
| 218 | #define HDMI_HTOP1_ENABLE_SELECTOR 0x0040 /* Enable Selector */ | ||
| 219 | #define HDMI_HTOP1_MACRO_RESET 0x0044 /* Macro reset */ | ||
| 220 | #define HDMI_HTOP1_PLL_CALIBRATION 0x0048 /* PLL calibration */ | ||
| 221 | #define HDMI_HTOP1_RE_CALIBRATION 0x004C /* Re-calibration */ | ||
| 222 | #define HDMI_HTOP1_CURRENT 0x0050 /* Current */ | ||
| 223 | #define HDMI_HTOP1_PLL_LOCK_DETECT 0x0054 /* PLL lock detect */ | ||
| 224 | #define HDMI_HTOP1_PHY_TEST_MODE 0x0058 /* PHY Test Mode */ | ||
| 225 | #define HDMI_HTOP1_CLK_SET 0x0080 /* Clock Set */ | ||
| 226 | #define HDMI_HTOP1_DDC_FAIL_SAFE 0x0084 /* DDC fail safe */ | ||
| 227 | #define HDMI_HTOP1_PRBS 0x0088 /* PRBS */ | ||
| 228 | #define HDMI_HTOP1_EDID_AINC_CONTROL 0x008C /* EDID ainc Control */ | ||
| 229 | #define HDMI_HTOP1_HTOP_DCL_MODE 0x00FC /* Deep Coloer Mode */ | ||
| 230 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF0 0x0100 /* Deep Color:FRC COEF0 */ | ||
| 231 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF1 0x0104 /* Deep Color:FRC COEF1 */ | ||
| 232 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF2 0x0108 /* Deep Color:FRC COEF2 */ | ||
| 233 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF3 0x010C /* Deep Color:FRC COEF3 */ | ||
| 234 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF0_C 0x0110 /* Deep Color:FRC COEF0C */ | ||
| 235 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF1_C 0x0114 /* Deep Color:FRC COEF1C */ | ||
| 236 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF2_C 0x0118 /* Deep Color:FRC COEF2C */ | ||
| 237 | #define HDMI_HTOP1_HTOP_DCL_FRC_COEF3_C 0x011C /* Deep Color:FRC COEF3C */ | ||
| 238 | #define HDMI_HTOP1_HTOP_DCL_FRC_MODE 0x0120 /* Deep Color:FRC Mode */ | ||
| 239 | #define HDMI_HTOP1_HTOP_DCL_RECT_START1 0x0124 /* Deep Color:Rect Start1 */ | ||
| 240 | #define HDMI_HTOP1_HTOP_DCL_RECT_SIZE1 0x0128 /* Deep Color:Rect Size1 */ | ||
| 241 | #define HDMI_HTOP1_HTOP_DCL_RECT_START2 0x012C /* Deep Color:Rect Start2 */ | ||
| 242 | #define HDMI_HTOP1_HTOP_DCL_RECT_SIZE2 0x0130 /* Deep Color:Rect Size2 */ | ||
| 243 | #define HDMI_HTOP1_HTOP_DCL_RECT_START3 0x0134 /* Deep Color:Rect Start3 */ | ||
| 244 | #define HDMI_HTOP1_HTOP_DCL_RECT_SIZE3 0x0138 /* Deep Color:Rect Size3 */ | ||
| 245 | #define HDMI_HTOP1_HTOP_DCL_RECT_START4 0x013C /* Deep Color:Rect Start4 */ | ||
| 246 | #define HDMI_HTOP1_HTOP_DCL_RECT_SIZE4 0x0140 /* Deep Color:Rect Size4 */ | ||
| 247 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1 0x0144 /* Deep Color:Fil Para Y1_1 */ | ||
| 248 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2 0x0148 /* Deep Color:Fil Para Y1_2 */ | ||
| 249 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1 0x014C /* Deep Color:Fil Para CB1_1 */ | ||
| 250 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2 0x0150 /* Deep Color:Fil Para CB1_2 */ | ||
| 251 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1 0x0154 /* Deep Color:Fil Para CR1_1 */ | ||
| 252 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2 0x0158 /* Deep Color:Fil Para CR1_2 */ | ||
| 253 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1 0x015C /* Deep Color:Fil Para Y2_1 */ | ||
| 254 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2 0x0160 /* Deep Color:Fil Para Y2_2 */ | ||
| 255 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1 0x0164 /* Deep Color:Fil Para CB2_1 */ | ||
| 256 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2 0x0168 /* Deep Color:Fil Para CB2_2 */ | ||
| 257 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1 0x016C /* Deep Color:Fil Para CR2_1 */ | ||
| 258 | #define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2 0x0170 /* Deep Color:Fil Para CR2_2 */ | ||
| 259 | #define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1 0x0174 /* Deep Color:Cor Para Y1 */ | ||
| 260 | #define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1 0x0178 /* Deep Color:Cor Para CB1 */ | ||
| 261 | #define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1 0x017C /* Deep Color:Cor Para CR1 */ | ||
| 262 | #define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2 0x0180 /* Deep Color:Cor Para Y2 */ | ||
| 263 | #define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2 0x0184 /* Deep Color:Cor Para CB2 */ | ||
| 264 | #define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2 0x0188 /* Deep Color:Cor Para CR2 */ | ||
| 265 | #define HDMI_HTOP1_EDID_DATA_READ 0x0200 /* EDID Data Read 128Byte:0x03FC */ | ||
| 266 | |||
| 204 | enum hotplug_state { | 267 | enum hotplug_state { |
| 205 | HDMI_HOTPLUG_DISCONNECTED, | 268 | HDMI_HOTPLUG_DISCONNECTED, |
| 206 | HDMI_HOTPLUG_CONNECTED, | 269 | HDMI_HOTPLUG_CONNECTED, |
| @@ -211,6 +274,7 @@ struct sh_hdmi { | |||
| 211 | struct sh_mobile_lcdc_entity entity; | 274 | struct sh_mobile_lcdc_entity entity; |
| 212 | 275 | ||
| 213 | void __iomem *base; | 276 | void __iomem *base; |
| 277 | void __iomem *htop1; | ||
| 214 | enum hotplug_state hp_state; /* hot-plug status */ | 278 | enum hotplug_state hp_state; /* hot-plug status */ |
| 215 | u8 preprogrammed_vic; /* use a pre-programmed VIC or | 279 | u8 preprogrammed_vic; /* use a pre-programmed VIC or |
| 216 | the external mode */ | 280 | the external mode */ |
| @@ -222,20 +286,66 @@ struct sh_hdmi { | |||
| 222 | struct delayed_work edid_work; | 286 | struct delayed_work edid_work; |
| 223 | struct fb_videomode mode; | 287 | struct fb_videomode mode; |
| 224 | struct fb_monspecs monspec; | 288 | struct fb_monspecs monspec; |
| 289 | |||
| 290 | /* register access functions */ | ||
| 291 | void (*write)(struct sh_hdmi *hdmi, u8 data, u8 reg); | ||
| 292 | u8 (*read)(struct sh_hdmi *hdmi, u8 reg); | ||
| 225 | }; | 293 | }; |
| 226 | 294 | ||
| 227 | #define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) | 295 | #define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) |
| 228 | 296 | ||
| 229 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | 297 | static void __hdmi_write8(struct sh_hdmi *hdmi, u8 data, u8 reg) |
| 230 | { | 298 | { |
| 231 | iowrite8(data, hdmi->base + reg); | 299 | iowrite8(data, hdmi->base + reg); |
| 232 | } | 300 | } |
| 233 | 301 | ||
| 234 | static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg) | 302 | static u8 __hdmi_read8(struct sh_hdmi *hdmi, u8 reg) |
| 235 | { | 303 | { |
| 236 | return ioread8(hdmi->base + reg); | 304 | return ioread8(hdmi->base + reg); |
| 237 | } | 305 | } |
| 238 | 306 | ||
| 307 | static void __hdmi_write32(struct sh_hdmi *hdmi, u8 data, u8 reg) | ||
| 308 | { | ||
| 309 | iowrite32((u32)data, hdmi->base + (reg * 4)); | ||
| 310 | udelay(100); | ||
| 311 | } | ||
| 312 | |||
| 313 | static u8 __hdmi_read32(struct sh_hdmi *hdmi, u8 reg) | ||
| 314 | { | ||
| 315 | return (u8)ioread32(hdmi->base + (reg * 4)); | ||
| 316 | } | ||
| 317 | |||
| 318 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | ||
| 319 | { | ||
| 320 | hdmi->write(hdmi, data, reg); | ||
| 321 | } | ||
| 322 | |||
| 323 | static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg) | ||
| 324 | { | ||
| 325 | return hdmi->read(hdmi, reg); | ||
| 326 | } | ||
| 327 | |||
| 328 | static void hdmi_bit_set(struct sh_hdmi *hdmi, u8 mask, u8 data, u8 reg) | ||
| 329 | { | ||
| 330 | u8 val = hdmi_read(hdmi, reg); | ||
| 331 | |||
| 332 | val &= ~mask; | ||
| 333 | val |= (data & mask); | ||
| 334 | |||
| 335 | hdmi_write(hdmi, val, reg); | ||
| 336 | } | ||
| 337 | |||
| 338 | static void hdmi_htop1_write(struct sh_hdmi *hdmi, u32 data, u32 reg) | ||
| 339 | { | ||
| 340 | iowrite32(data, hdmi->htop1 + reg); | ||
| 341 | udelay(100); | ||
| 342 | } | ||
| 343 | |||
| 344 | static u32 hdmi_htop1_read(struct sh_hdmi *hdmi, u32 reg) | ||
| 345 | { | ||
| 346 | return ioread32(hdmi->htop1 + reg); | ||
| 347 | } | ||
| 348 | |||
| 239 | /* | 349 | /* |
| 240 | * HDMI sound | 350 | * HDMI sound |
| 241 | */ | 351 | */ |
| @@ -693,11 +803,11 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) | |||
| 693 | msleep(10); | 803 | msleep(10); |
| 694 | 804 | ||
| 695 | /* PS mode b->d, reset PLLA and PLLB */ | 805 | /* PS mode b->d, reset PLLA and PLLB */ |
| 696 | hdmi_write(hdmi, 0x4C, HDMI_SYSTEM_CTRL); | 806 | hdmi_bit_set(hdmi, 0xFC, 0x4C, HDMI_SYSTEM_CTRL); |
| 697 | 807 | ||
| 698 | udelay(10); | 808 | udelay(10); |
| 699 | 809 | ||
| 700 | hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); | 810 | hdmi_bit_set(hdmi, 0xFC, 0x40, HDMI_SYSTEM_CTRL); |
| 701 | } | 811 | } |
| 702 | 812 | ||
| 703 | static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, | 813 | static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, |
| @@ -746,7 +856,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, | |||
| 746 | /* Read EDID */ | 856 | /* Read EDID */ |
| 747 | dev_dbg(hdmi->dev, "Read back EDID code:"); | 857 | dev_dbg(hdmi->dev, "Read back EDID code:"); |
| 748 | for (i = 0; i < 128; i++) { | 858 | for (i = 0; i < 128; i++) { |
| 749 | edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); | 859 | edid[i] = (hdmi->htop1) ? |
| 860 | (u8)hdmi_htop1_read(hdmi, HDMI_HTOP1_EDID_DATA_READ + (i * 4)) : | ||
| 861 | hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); | ||
| 750 | #ifdef DEBUG | 862 | #ifdef DEBUG |
| 751 | if ((i % 16) == 0) { | 863 | if ((i % 16) == 0) { |
| 752 | printk(KERN_CONT "\n"); | 864 | printk(KERN_CONT "\n"); |
| @@ -917,13 +1029,13 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
| 917 | u8 status1, status2, mask1, mask2; | 1029 | u8 status1, status2, mask1, mask2; |
| 918 | 1030 | ||
| 919 | /* mode_b and PLLA and PLLB reset */ | 1031 | /* mode_b and PLLA and PLLB reset */ |
| 920 | hdmi_write(hdmi, 0x2C, HDMI_SYSTEM_CTRL); | 1032 | hdmi_bit_set(hdmi, 0xFC, 0x2C, HDMI_SYSTEM_CTRL); |
| 921 | 1033 | ||
| 922 | /* How long shall reset be held? */ | 1034 | /* How long shall reset be held? */ |
| 923 | udelay(10); | 1035 | udelay(10); |
| 924 | 1036 | ||
| 925 | /* mode_b and PLLA and PLLB reset release */ | 1037 | /* mode_b and PLLA and PLLB reset release */ |
| 926 | hdmi_write(hdmi, 0x20, HDMI_SYSTEM_CTRL); | 1038 | hdmi_bit_set(hdmi, 0xFC, 0x20, HDMI_SYSTEM_CTRL); |
| 927 | 1039 | ||
| 928 | status1 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_1); | 1040 | status1 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_1); |
| 929 | status2 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_2); | 1041 | status2 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_2); |
| @@ -1001,7 +1113,7 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity) | |||
| 1001 | */ | 1113 | */ |
| 1002 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { | 1114 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { |
| 1003 | /* PS mode d->e. All functions are active */ | 1115 | /* PS mode d->e. All functions are active */ |
| 1004 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); | 1116 | hdmi_bit_set(hdmi, 0xFC, 0x80, HDMI_SYSTEM_CTRL); |
| 1005 | dev_dbg(hdmi->dev, "HDMI running\n"); | 1117 | dev_dbg(hdmi->dev, "HDMI running\n"); |
| 1006 | } | 1118 | } |
| 1007 | 1119 | ||
| @@ -1016,7 +1128,7 @@ static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) | |||
| 1016 | 1128 | ||
| 1017 | dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi); | 1129 | dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi); |
| 1018 | /* PS mode e->a */ | 1130 | /* PS mode e->a */ |
| 1019 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); | 1131 | hdmi_bit_set(hdmi, 0xFC, 0x10, HDMI_SYSTEM_CTRL); |
| 1020 | } | 1132 | } |
| 1021 | 1133 | ||
| 1022 | static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = { | 1134 | static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = { |
| @@ -1110,10 +1222,58 @@ out: | |||
| 1110 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); | 1222 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); |
| 1111 | } | 1223 | } |
| 1112 | 1224 | ||
| 1225 | static void sh_hdmi_htop1_init(struct sh_hdmi *hdmi) | ||
| 1226 | { | ||
| 1227 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_MODE); | ||
| 1228 | hdmi_htop1_write(hdmi, 0x0000000b, 0x0010); | ||
| 1229 | hdmi_htop1_write(hdmi, 0x00006710, HDMI_HTOP1_HTOP_DCL_FRC_MODE); | ||
| 1230 | hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1); | ||
| 1231 | hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2); | ||
| 1232 | hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1); | ||
| 1233 | hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2); | ||
| 1234 | hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1); | ||
| 1235 | hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2); | ||
| 1236 | hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1); | ||
| 1237 | hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2); | ||
| 1238 | hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1); | ||
| 1239 | hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2); | ||
| 1240 | hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1); | ||
| 1241 | hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2); | ||
| 1242 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1); | ||
| 1243 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1); | ||
| 1244 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1); | ||
| 1245 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2); | ||
| 1246 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2); | ||
| 1247 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2); | ||
| 1248 | hdmi_htop1_write(hdmi, 0x00000008, HDMI_HTOP1_CURRENT); | ||
| 1249 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP0_1); | ||
| 1250 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP2_C); | ||
| 1251 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PHY_TEST_MODE); | ||
| 1252 | hdmi_htop1_write(hdmi, 0x00000081, HDMI_HTOP1_TISIDRV); | ||
| 1253 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PLLBW); | ||
| 1254 | hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN); | ||
| 1255 | hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN); | ||
| 1256 | hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR); | ||
| 1257 | hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET); | ||
| 1258 | hdmi_htop1_write(hdmi, 0x00000016, HDMI_HTOP1_CISRANGE); | ||
| 1259 | msleep(100); | ||
| 1260 | hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_ENABLE_SELECTOR); | ||
| 1261 | msleep(100); | ||
| 1262 | hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR); | ||
| 1263 | hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET); | ||
| 1264 | hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN); | ||
| 1265 | hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN); | ||
| 1266 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT); | ||
| 1267 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_CLK_TO_PHY); | ||
| 1268 | hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT2); | ||
| 1269 | hdmi_htop1_write(hdmi, 0x0000000a, HDMI_HTOP1_CLK_SET); | ||
| 1270 | } | ||
| 1271 | |||
| 1113 | static int __init sh_hdmi_probe(struct platform_device *pdev) | 1272 | static int __init sh_hdmi_probe(struct platform_device *pdev) |
| 1114 | { | 1273 | { |
| 1115 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1274 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
| 1116 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1275 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1276 | struct resource *htop1_res; | ||
| 1117 | int irq = platform_get_irq(pdev, 0), ret; | 1277 | int irq = platform_get_irq(pdev, 0), ret; |
| 1118 | struct sh_hdmi *hdmi; | 1278 | struct sh_hdmi *hdmi; |
| 1119 | long rate; | 1279 | long rate; |
| @@ -1121,6 +1281,15 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 1121 | if (!res || !pdata || irq < 0) | 1281 | if (!res || !pdata || irq < 0) |
| 1122 | return -ENODEV; | 1282 | return -ENODEV; |
| 1123 | 1283 | ||
| 1284 | htop1_res = NULL; | ||
| 1285 | if (pdata->flags & HDMI_HAS_HTOP1) { | ||
| 1286 | htop1_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
| 1287 | if (!htop1_res) { | ||
| 1288 | dev_err(&pdev->dev, "htop1 needs register base\n"); | ||
| 1289 | return -EINVAL; | ||
| 1290 | } | ||
| 1291 | } | ||
| 1292 | |||
| 1124 | hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); | 1293 | hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); |
| 1125 | if (!hdmi) { | 1294 | if (!hdmi) { |
| 1126 | dev_err(&pdev->dev, "Cannot allocate device data\n"); | 1295 | dev_err(&pdev->dev, "Cannot allocate device data\n"); |
| @@ -1138,6 +1307,15 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 1138 | goto egetclk; | 1307 | goto egetclk; |
| 1139 | } | 1308 | } |
| 1140 | 1309 | ||
| 1310 | /* select register access functions */ | ||
| 1311 | if (pdata->flags & HDMI_32BIT_REG) { | ||
| 1312 | hdmi->write = __hdmi_write32; | ||
| 1313 | hdmi->read = __hdmi_read32; | ||
| 1314 | } else { | ||
| 1315 | hdmi->write = __hdmi_write8; | ||
| 1316 | hdmi->read = __hdmi_read8; | ||
| 1317 | } | ||
| 1318 | |||
| 1141 | /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ | 1319 | /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ |
| 1142 | rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); | 1320 | rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); |
| 1143 | if (rate > 0) | 1321 | if (rate > 0) |
| @@ -1176,6 +1354,24 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 1176 | pm_runtime_enable(&pdev->dev); | 1354 | pm_runtime_enable(&pdev->dev); |
| 1177 | pm_runtime_get_sync(&pdev->dev); | 1355 | pm_runtime_get_sync(&pdev->dev); |
| 1178 | 1356 | ||
| 1357 | /* init interrupt polarity */ | ||
| 1358 | if (pdata->flags & HDMI_OUTPUT_PUSH_PULL) | ||
| 1359 | hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL); | ||
| 1360 | |||
| 1361 | if (pdata->flags & HDMI_OUTPUT_POLARITY_HI) | ||
| 1362 | hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL); | ||
| 1363 | |||
| 1364 | /* enable htop1 register if needed */ | ||
| 1365 | if (htop1_res) { | ||
| 1366 | hdmi->htop1 = ioremap(htop1_res->start, resource_size(htop1_res)); | ||
| 1367 | if (!hdmi->htop1) { | ||
| 1368 | dev_err(&pdev->dev, "control register region already claimed\n"); | ||
| 1369 | ret = -ENOMEM; | ||
| 1370 | goto emap_htop1; | ||
| 1371 | } | ||
| 1372 | sh_hdmi_htop1_init(hdmi); | ||
| 1373 | } | ||
| 1374 | |||
| 1179 | /* Product and revision IDs are 0 in sh-mobile version */ | 1375 | /* Product and revision IDs are 0 in sh-mobile version */ |
| 1180 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", | 1376 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", |
| 1181 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); | 1377 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); |
| @@ -1199,6 +1395,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
| 1199 | ecodec: | 1395 | ecodec: |
| 1200 | free_irq(irq, hdmi); | 1396 | free_irq(irq, hdmi); |
| 1201 | ereqirq: | 1397 | ereqirq: |
| 1398 | if (hdmi->htop1) | ||
| 1399 | iounmap(hdmi->htop1); | ||
| 1400 | emap_htop1: | ||
| 1202 | pm_runtime_put(&pdev->dev); | 1401 | pm_runtime_put(&pdev->dev); |
| 1203 | pm_runtime_disable(&pdev->dev); | 1402 | pm_runtime_disable(&pdev->dev); |
| 1204 | iounmap(hdmi->base); | 1403 | iounmap(hdmi->base); |
| @@ -1230,6 +1429,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) | |||
| 1230 | pm_runtime_disable(&pdev->dev); | 1429 | pm_runtime_disable(&pdev->dev); |
| 1231 | clk_disable(hdmi->hdmi_clk); | 1430 | clk_disable(hdmi->hdmi_clk); |
| 1232 | clk_put(hdmi->hdmi_clk); | 1431 | clk_put(hdmi->hdmi_clk); |
| 1432 | if (hdmi->htop1) | ||
| 1433 | iounmap(hdmi->htop1); | ||
| 1233 | iounmap(hdmi->base); | 1434 | iounmap(hdmi->base); |
| 1234 | release_mem_region(res->start, resource_size(res)); | 1435 | release_mem_region(res->start, resource_size(res)); |
| 1235 | kfree(hdmi); | 1436 | kfree(hdmi); |
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h index aff73842d877..85d6738b6c64 100644 --- a/drivers/video/sis/init.h +++ b/drivers/video/sis/init.h | |||
| @@ -105,51 +105,6 @@ static const unsigned short ModeIndex_1920x1440[] = {0x68, 0x69, 0x00, 0x6b}; | |||
| 105 | static const unsigned short ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; | 105 | static const unsigned short ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; |
| 106 | static const unsigned short ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e}; | 106 | static const unsigned short ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e}; |
| 107 | 107 | ||
| 108 | static const unsigned short SiS_DRAMType[17][5]={ | ||
| 109 | {0x0C,0x0A,0x02,0x40,0x39}, | ||
| 110 | {0x0D,0x0A,0x01,0x40,0x48}, | ||
| 111 | {0x0C,0x09,0x02,0x20,0x35}, | ||
| 112 | {0x0D,0x09,0x01,0x20,0x44}, | ||
| 113 | {0x0C,0x08,0x02,0x10,0x31}, | ||
| 114 | {0x0D,0x08,0x01,0x10,0x40}, | ||
| 115 | {0x0C,0x0A,0x01,0x20,0x34}, | ||
| 116 | {0x0C,0x09,0x01,0x08,0x32}, | ||
| 117 | {0x0B,0x08,0x02,0x08,0x21}, | ||
| 118 | {0x0C,0x08,0x01,0x08,0x30}, | ||
| 119 | {0x0A,0x08,0x02,0x04,0x11}, | ||
| 120 | {0x0B,0x0A,0x01,0x10,0x28}, | ||
| 121 | {0x09,0x08,0x02,0x02,0x01}, | ||
| 122 | {0x0B,0x09,0x01,0x08,0x24}, | ||
| 123 | {0x0B,0x08,0x01,0x04,0x20}, | ||
| 124 | {0x0A,0x08,0x01,0x02,0x10}, | ||
| 125 | {0x09,0x08,0x01,0x01,0x00} | ||
| 126 | }; | ||
| 127 | |||
| 128 | static const unsigned short SiS_SDRDRAM_TYPE[13][5] = | ||
| 129 | { | ||
| 130 | { 2,12, 9,64,0x35}, | ||
| 131 | { 1,13, 9,64,0x44}, | ||
| 132 | { 2,12, 8,32,0x31}, | ||
| 133 | { 2,11, 9,32,0x25}, | ||
| 134 | { 1,12, 9,32,0x34}, | ||
| 135 | { 1,13, 8,32,0x40}, | ||
| 136 | { 2,11, 8,16,0x21}, | ||
| 137 | { 1,12, 8,16,0x30}, | ||
| 138 | { 1,11, 9,16,0x24}, | ||
| 139 | { 1,11, 8, 8,0x20}, | ||
| 140 | { 2, 9, 8, 4,0x01}, | ||
| 141 | { 1,10, 8, 4,0x10}, | ||
| 142 | { 1, 9, 8, 2,0x00} | ||
| 143 | }; | ||
| 144 | |||
| 145 | static const unsigned short SiS_DDRDRAM_TYPE[4][5] = | ||
| 146 | { | ||
| 147 | { 2,12, 9,64,0x35}, | ||
| 148 | { 2,12, 8,32,0x31}, | ||
| 149 | { 2,11, 8,16,0x21}, | ||
| 150 | { 2, 9, 8, 4,0x01} | ||
| 151 | }; | ||
| 152 | |||
| 153 | static const unsigned char SiS_MDA_DAC[] = | 108 | static const unsigned char SiS_MDA_DAC[] = |
| 154 | { | 109 | { |
| 155 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | 110 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 078ca2167d6f..a7a48db64ce2 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
| @@ -4222,6 +4222,26 @@ sisfb_post_300_buswidth(struct sis_video_info *ivideo) | |||
| 4222 | return 1; /* 32bit */ | 4222 | return 1; /* 32bit */ |
| 4223 | } | 4223 | } |
| 4224 | 4224 | ||
| 4225 | static const unsigned short __devinitconst SiS_DRAMType[17][5] = { | ||
| 4226 | {0x0C,0x0A,0x02,0x40,0x39}, | ||
| 4227 | {0x0D,0x0A,0x01,0x40,0x48}, | ||
| 4228 | {0x0C,0x09,0x02,0x20,0x35}, | ||
| 4229 | {0x0D,0x09,0x01,0x20,0x44}, | ||
| 4230 | {0x0C,0x08,0x02,0x10,0x31}, | ||
| 4231 | {0x0D,0x08,0x01,0x10,0x40}, | ||
| 4232 | {0x0C,0x0A,0x01,0x20,0x34}, | ||
| 4233 | {0x0C,0x09,0x01,0x08,0x32}, | ||
| 4234 | {0x0B,0x08,0x02,0x08,0x21}, | ||
| 4235 | {0x0C,0x08,0x01,0x08,0x30}, | ||
| 4236 | {0x0A,0x08,0x02,0x04,0x11}, | ||
| 4237 | {0x0B,0x0A,0x01,0x10,0x28}, | ||
| 4238 | {0x09,0x08,0x02,0x02,0x01}, | ||
| 4239 | {0x0B,0x09,0x01,0x08,0x24}, | ||
| 4240 | {0x0B,0x08,0x01,0x04,0x20}, | ||
| 4241 | {0x0A,0x08,0x01,0x02,0x10}, | ||
| 4242 | {0x09,0x08,0x01,0x01,0x00} | ||
| 4243 | }; | ||
| 4244 | |||
| 4225 | static int __devinit | 4245 | static int __devinit |
| 4226 | sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth, | 4246 | sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth, |
| 4227 | int PseudoRankCapacity, int PseudoAdrPinCount, | 4247 | int PseudoRankCapacity, int PseudoAdrPinCount, |
| @@ -4231,27 +4251,8 @@ sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth | |||
| 4231 | unsigned short sr14; | 4251 | unsigned short sr14; |
| 4232 | unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid; | 4252 | unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid; |
| 4233 | unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage; | 4253 | unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage; |
| 4234 | static const unsigned short SiS_DRAMType[17][5] = { | ||
| 4235 | {0x0C,0x0A,0x02,0x40,0x39}, | ||
| 4236 | {0x0D,0x0A,0x01,0x40,0x48}, | ||
| 4237 | {0x0C,0x09,0x02,0x20,0x35}, | ||
| 4238 | {0x0D,0x09,0x01,0x20,0x44}, | ||
| 4239 | {0x0C,0x08,0x02,0x10,0x31}, | ||
| 4240 | {0x0D,0x08,0x01,0x10,0x40}, | ||
| 4241 | {0x0C,0x0A,0x01,0x20,0x34}, | ||
| 4242 | {0x0C,0x09,0x01,0x08,0x32}, | ||
| 4243 | {0x0B,0x08,0x02,0x08,0x21}, | ||
| 4244 | {0x0C,0x08,0x01,0x08,0x30}, | ||
| 4245 | {0x0A,0x08,0x02,0x04,0x11}, | ||
| 4246 | {0x0B,0x0A,0x01,0x10,0x28}, | ||
| 4247 | {0x09,0x08,0x02,0x02,0x01}, | ||
| 4248 | {0x0B,0x09,0x01,0x08,0x24}, | ||
| 4249 | {0x0B,0x08,0x01,0x04,0x20}, | ||
| 4250 | {0x0A,0x08,0x01,0x02,0x10}, | ||
| 4251 | {0x09,0x08,0x01,0x01,0x00} | ||
| 4252 | }; | ||
| 4253 | 4254 | ||
| 4254 | for(k = 0; k <= 16; k++) { | 4255 | for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) { |
| 4255 | 4256 | ||
| 4256 | RankCapacity = buswidth * SiS_DRAMType[k][3]; | 4257 | RankCapacity = buswidth * SiS_DRAMType[k][3]; |
| 4257 | 4258 | ||
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 30f7a815a62b..5b6abc6de84b 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c | |||
| @@ -1036,6 +1036,6 @@ static void __exit xxxfb_exit(void) | |||
| 1036 | */ | 1036 | */ |
| 1037 | 1037 | ||
| 1038 | module_init(xxxfb_init); | 1038 | module_init(xxxfb_init); |
| 1039 | module_exit(xxxfb_remove); | 1039 | module_exit(xxxfb_exit); |
| 1040 | 1040 | ||
| 1041 | MODULE_LICENSE("GPL"); | 1041 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index ccbfef5e828f..af3ef27ad36c 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c | |||
| @@ -846,7 +846,7 @@ static void ufx_raw_rect(struct ufx_data *dev, u16 *cmd, int x, int y, | |||
| 846 | } | 846 | } |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | int ufx_handle_damage(struct ufx_data *dev, int x, int y, | 849 | static int ufx_handle_damage(struct ufx_data *dev, int x, int y, |
| 850 | int width, int height) | 850 | int width, int height) |
| 851 | { | 851 | { |
| 852 | size_t packed_line_len = ALIGN((width * 2), 4); | 852 | size_t packed_line_len = ALIGN((width * 2), 4); |
| @@ -1083,7 +1083,7 @@ static int ufx_ops_open(struct fb_info *info, int user) | |||
| 1083 | 1083 | ||
| 1084 | struct fb_deferred_io *fbdefio; | 1084 | struct fb_deferred_io *fbdefio; |
| 1085 | 1085 | ||
| 1086 | fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); | 1086 | fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); |
| 1087 | 1087 | ||
| 1088 | if (fbdefio) { | 1088 | if (fbdefio) { |
| 1089 | fbdefio->delay = UFX_DEFIO_WRITE_DELAY; | 1089 | fbdefio->delay = UFX_DEFIO_WRITE_DELAY; |
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 7af1e8166182..8af64148294b 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c | |||
| @@ -893,7 +893,7 @@ static int dlfb_ops_open(struct fb_info *info, int user) | |||
| 893 | 893 | ||
| 894 | struct fb_deferred_io *fbdefio; | 894 | struct fb_deferred_io *fbdefio; |
| 895 | 895 | ||
| 896 | fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); | 896 | fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); |
| 897 | 897 | ||
| 898 | if (fbdefio) { | 898 | if (fbdefio) { |
| 899 | fbdefio->delay = DL_DEFIO_WRITE_DELAY; | 899 | fbdefio->delay = DL_DEFIO_WRITE_DELAY; |
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 0c8837565bc7..c80e770e1800 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c | |||
| @@ -1276,17 +1276,12 @@ static int viafb_dfph_proc_open(struct inode *inode, struct file *file) | |||
| 1276 | static ssize_t viafb_dfph_proc_write(struct file *file, | 1276 | static ssize_t viafb_dfph_proc_write(struct file *file, |
| 1277 | const char __user *buffer, size_t count, loff_t *pos) | 1277 | const char __user *buffer, size_t count, loff_t *pos) |
| 1278 | { | 1278 | { |
| 1279 | char buf[20]; | 1279 | int err; |
| 1280 | u8 reg_val = 0; | 1280 | u8 reg_val; |
| 1281 | unsigned long length; | 1281 | err = kstrtou8_from_user(buffer, count, 0, ®_val); |
| 1282 | if (count < 1) | 1282 | if (err) |
| 1283 | return -EINVAL; | 1283 | return err; |
| 1284 | length = count > 20 ? 20 : count; | 1284 | |
| 1285 | if (copy_from_user(&buf[0], buffer, length)) | ||
| 1286 | return -EFAULT; | ||
| 1287 | buf[length - 1] = '\0'; /*Ensure end string */ | ||
| 1288 | if (kstrtou8(buf, 0, ®_val) < 0) | ||
| 1289 | return -EINVAL; | ||
| 1290 | viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f); | 1285 | viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f); |
| 1291 | return count; | 1286 | return count; |
| 1292 | } | 1287 | } |
| @@ -1316,17 +1311,12 @@ static int viafb_dfpl_proc_open(struct inode *inode, struct file *file) | |||
| 1316 | static ssize_t viafb_dfpl_proc_write(struct file *file, | 1311 | static ssize_t viafb_dfpl_proc_write(struct file *file, |
| 1317 | const char __user *buffer, size_t count, loff_t *pos) | 1312 | const char __user *buffer, size_t count, loff_t *pos) |
| 1318 | { | 1313 | { |
| 1319 | char buf[20]; | 1314 | int err; |
| 1320 | u8 reg_val = 0; | 1315 | u8 reg_val; |
| 1321 | unsigned long length; | 1316 | err = kstrtou8_from_user(buffer, count, 0, ®_val); |
| 1322 | if (count < 1) | 1317 | if (err) |
| 1323 | return -EINVAL; | 1318 | return err; |
| 1324 | length = count > 20 ? 20 : count; | 1319 | |
| 1325 | if (copy_from_user(&buf[0], buffer, length)) | ||
| 1326 | return -EFAULT; | ||
| 1327 | buf[length - 1] = '\0'; /*Ensure end string */ | ||
| 1328 | if (kstrtou8(buf, 0, ®_val) < 0) | ||
| 1329 | return -EINVAL; | ||
| 1330 | viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f); | 1320 | viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f); |
| 1331 | return count; | 1321 | return count; |
| 1332 | } | 1322 | } |
