1/* jazz_esp.c: ESP front-end for MIPS JAZZ systems. 2 * 3 * Copyright (C) 2007 Thomas Bogend��rfer (tsbogend@alpha.frankende) 4 */ 5 6#include <linux/kernel.h> 7#include <linux/gfp.h> 8#include <linux/types.h> 9#include <linux/module.h> 10#include <linux/init.h> 11#include <linux/interrupt.h> 12#include <linux/platform_device.h> 13#include <linux/dma-mapping.h> 14 15#include <asm/irq.h> 16#include <asm/io.h> 17#include <asm/dma.h> 18 19#include <asm/jazz.h> 20#include <asm/jazzdma.h> 21 22#include <scsi/scsi_host.h> 23 24#include "esp_scsi.h" 25 26#define DRV_MODULE_NAME "jazz_esp" 27#define PFX DRV_MODULE_NAME ": " 28#define DRV_VERSION "1.000" 29#define DRV_MODULE_RELDATE "May 19, 2007" 30 31static void jazz_esp_write8(struct esp *esp, u8 val, unsigned long reg) 32{ 33 *(volatile u8 *)(esp->regs + reg) = val; 34} 35 36static u8 jazz_esp_read8(struct esp *esp, unsigned long reg) 37{ 38 return *(volatile u8 *)(esp->regs + reg); 39} 40 41static dma_addr_t jazz_esp_map_single(struct esp *esp, void *buf, 42 size_t sz, int dir) 43{ 44 return dma_map_single(esp->dev, buf, sz, dir); 45} 46 47static int jazz_esp_map_sg(struct esp *esp, struct scatterlist *sg, 48 int num_sg, int dir) 49{ 50 return dma_map_sg(esp->dev, sg, num_sg, dir); 51} 52 53static void jazz_esp_unmap_single(struct esp *esp, dma_addr_t addr, 54 size_t sz, int dir) 55{ 56 dma_unmap_single(esp->dev, addr, sz, dir); 57} 58 59static void jazz_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, 60 int num_sg, int dir) 61{ 62 dma_unmap_sg(esp->dev, sg, num_sg, dir); 63} 64 65static int jazz_esp_irq_pending(struct esp *esp) 66{ 67 if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) 68 return 1; 69 return 0; 70} 71 72static void jazz_esp_reset_dma(struct esp *esp) 73{ 74 vdma_disable ((int)esp->dma_regs); 75} 76 77static void jazz_esp_dma_drain(struct esp *esp) 78{ 79 /* nothing to do */ 80} 81 82static void jazz_esp_dma_invalidate(struct esp *esp) 83{ 84 vdma_disable ((int)esp->dma_regs); 85} 86 87static void jazz_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, 88 u32 dma_count, int write, u8 cmd) 89{ 90 BUG_ON(!(cmd & ESP_CMD_DMA)); 91 92 jazz_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); 93 jazz_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); 94 vdma_disable ((int)esp->dma_regs); 95 if (write) 96 vdma_set_mode ((int)esp->dma_regs, DMA_MODE_READ); 97 else 98 vdma_set_mode ((int)esp->dma_regs, DMA_MODE_WRITE); 99 100 vdma_set_addr ((int)esp->dma_regs, addr); 101 vdma_set_count ((int)esp->dma_regs, dma_count); 102 vdma_enable ((int)esp->dma_regs); 103 104 scsi_esp_cmd(esp, cmd); 105} 106 107static int jazz_esp_dma_error(struct esp *esp) 108{ 109 u32 enable = vdma_get_enable((int)esp->dma_regs); 110 111 if (enable & (R4030_MEM_INTR|R4030_ADDR_INTR)) 112 return 1; 113 114 return 0; 115} 116 117static const struct esp_driver_ops jazz_esp_ops = { 118 .esp_write8 = jazz_esp_write8, 119 .esp_read8 = jazz_esp_read8, 120 .map_single = jazz_esp_map_single, 121 .map_sg = jazz_esp_map_sg, 122 .unmap_single = jazz_esp_unmap_single, 123 .unmap_sg = jazz_esp_unmap_sg, 124 .irq_pending = jazz_esp_irq_pending, 125 .reset_dma = jazz_esp_reset_dma, 126 .dma_drain = jazz_esp_dma_drain, 127 .dma_invalidate = jazz_esp_dma_invalidate, 128 .send_dma_cmd = jazz_esp_send_dma_cmd, 129 .dma_error = jazz_esp_dma_error, 130}; 131 132static int esp_jazz_probe(struct platform_device *dev) 133{ 134 struct scsi_host_template *tpnt = &scsi_esp_template; 135 struct Scsi_Host *host; 136 struct esp *esp; 137 struct resource *res; 138 int err; 139 140 host = scsi_host_alloc(tpnt, sizeof(struct esp)); 141 142 err = -ENOMEM; 143 if (!host) 144 goto fail; 145 146 host->max_id = 8; 147 esp = shost_priv(host); 148 149 esp->host = host; 150 esp->dev = dev; 151 esp->ops = &jazz_esp_ops; 152 153 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 154 if (!res) 155 goto fail_unlink; 156 157 esp->regs = (void __iomem *)res->start; 158 if (!esp->regs) 159 goto fail_unlink; 160 161 res = platform_get_resource(dev, IORESOURCE_MEM, 1); 162 if (!res) 163 goto fail_unlink; 164 165 esp->dma_regs = (void __iomem *)res->start; 166 167 esp->command_block = dma_alloc_coherent(esp->dev, 16, 168 &esp->command_block_dma, 169 GFP_KERNEL); 170 if (!esp->command_block) 171 goto fail_unmap_regs; 172 173 host->irq = platform_get_irq(dev, 0); 174 err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); 175 if (err < 0) 176 goto fail_unmap_command_block; 177 178 esp->scsi_id = 7; 179 esp->host->this_id = esp->scsi_id; 180 esp->scsi_id_mask = (1 << esp->scsi_id); 181 esp->cfreq = 40000000; 182 183 dev_set_drvdata(&dev->dev, esp); 184 185 err = scsi_esp_register(esp, &dev->dev); 186 if (err) 187 goto fail_free_irq; 188 189 return 0; 190 191fail_free_irq: 192 free_irq(host->irq, esp); 193fail_unmap_command_block: 194 dma_free_coherent(esp->dev, 16, 195 esp->command_block, 196 esp->command_block_dma); 197fail_unmap_regs: 198fail_unlink: 199 scsi_host_put(host); 200fail: 201 return err; 202} 203 204static int esp_jazz_remove(struct platform_device *dev) 205{ 206 struct esp *esp = dev_get_drvdata(&dev->dev); 207 unsigned int irq = esp->host->irq; 208 209 scsi_esp_unregister(esp); 210 211 free_irq(irq, esp); 212 dma_free_coherent(esp->dev, 16, 213 esp->command_block, 214 esp->command_block_dma); 215 216 scsi_host_put(esp->host); 217 218 return 0; 219} 220 221/* work with hotplug and coldplug */ 222MODULE_ALIAS("platform:jazz_esp"); 223 224static struct platform_driver esp_jazz_driver = { 225 .probe = esp_jazz_probe, 226 .remove = esp_jazz_remove, 227 .driver = { 228 .name = "jazz_esp", 229 }, 230}; 231 232static int __init jazz_esp_init(void) 233{ 234 return platform_driver_register(&esp_jazz_driver); 235} 236 237static void __exit jazz_esp_exit(void) 238{ 239 platform_driver_unregister(&esp_jazz_driver); 240} 241 242MODULE_DESCRIPTION("JAZZ ESP SCSI driver"); 243MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); 244MODULE_LICENSE("GPL"); 245MODULE_VERSION(DRV_VERSION); 246 247module_init(jazz_esp_init); 248module_exit(jazz_esp_exit); 249