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 31 static void jazz_esp_write8(struct esp *esp, u8 val, unsigned long reg) 32 { 33 *(volatile u8 *)(esp->regs + reg) = val; 34 } 35 36 static u8 jazz_esp_read8(struct esp *esp, unsigned long reg) 37 { 38 return *(volatile u8 *)(esp->regs + reg); 39 } 40 41 static 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 47 static 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 53 static 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 59 static 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 65 static 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 72 static void jazz_esp_reset_dma(struct esp *esp) 73 { 74 vdma_disable ((int)esp->dma_regs); 75 } 76 77 static void jazz_esp_dma_drain(struct esp *esp) 78 { 79 /* nothing to do */ 80 } 81 82 static void jazz_esp_dma_invalidate(struct esp *esp) 83 { 84 vdma_disable ((int)esp->dma_regs); 85 } 86 87 static 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 107 static 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 117 static 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 132 static 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 191 fail_free_irq: 192 free_irq(host->irq, esp); 193 fail_unmap_command_block: 194 dma_free_coherent(esp->dev, 16, 195 esp->command_block, 196 esp->command_block_dma); 197 fail_unmap_regs: 198 fail_unlink: 199 scsi_host_put(host); 200 fail: 201 return err; 202 } 203 204 static 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 */ 222 MODULE_ALIAS("platform:jazz_esp"); 223 224 static struct platform_driver esp_jazz_driver = { 225 .probe = esp_jazz_probe, 226 .remove = esp_jazz_remove, 227 .driver = { 228 .name = "jazz_esp", 229 .owner = THIS_MODULE, 230 }, 231 }; 232 233 static int __init jazz_esp_init(void) 234 { 235 return platform_driver_register(&esp_jazz_driver); 236 } 237 238 static void __exit jazz_esp_exit(void) 239 { 240 platform_driver_unregister(&esp_jazz_driver); 241 } 242 243 MODULE_DESCRIPTION("JAZZ ESP SCSI driver"); 244 MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); 245 MODULE_LICENSE("GPL"); 246 MODULE_VERSION(DRV_VERSION); 247 248 module_init(jazz_esp_init); 249 module_exit(jazz_esp_exit); 250