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 int jazz_esp_irq_pending(struct esp *esp) 42 { 43 if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) 44 return 1; 45 return 0; 46 } 47 48 static void jazz_esp_reset_dma(struct esp *esp) 49 { 50 vdma_disable ((int)esp->dma_regs); 51 } 52 53 static void jazz_esp_dma_drain(struct esp *esp) 54 { 55 /* nothing to do */ 56 } 57 58 static void jazz_esp_dma_invalidate(struct esp *esp) 59 { 60 vdma_disable ((int)esp->dma_regs); 61 } 62 63 static void jazz_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, 64 u32 dma_count, int write, u8 cmd) 65 { 66 BUG_ON(!(cmd & ESP_CMD_DMA)); 67 68 jazz_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); 69 jazz_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); 70 vdma_disable ((int)esp->dma_regs); 71 if (write) 72 vdma_set_mode ((int)esp->dma_regs, DMA_MODE_READ); 73 else 74 vdma_set_mode ((int)esp->dma_regs, DMA_MODE_WRITE); 75 76 vdma_set_addr ((int)esp->dma_regs, addr); 77 vdma_set_count ((int)esp->dma_regs, dma_count); 78 vdma_enable ((int)esp->dma_regs); 79 80 scsi_esp_cmd(esp, cmd); 81 } 82 83 static int jazz_esp_dma_error(struct esp *esp) 84 { 85 u32 enable = vdma_get_enable((int)esp->dma_regs); 86 87 if (enable & (R4030_MEM_INTR|R4030_ADDR_INTR)) 88 return 1; 89 90 return 0; 91 } 92 93 static const struct esp_driver_ops jazz_esp_ops = { 94 .esp_write8 = jazz_esp_write8, 95 .esp_read8 = jazz_esp_read8, 96 .irq_pending = jazz_esp_irq_pending, 97 .reset_dma = jazz_esp_reset_dma, 98 .dma_drain = jazz_esp_dma_drain, 99 .dma_invalidate = jazz_esp_dma_invalidate, 100 .send_dma_cmd = jazz_esp_send_dma_cmd, 101 .dma_error = jazz_esp_dma_error, 102 }; 103 104 static int esp_jazz_probe(struct platform_device *dev) 105 { 106 struct scsi_host_template *tpnt = &scsi_esp_template; 107 struct Scsi_Host *host; 108 struct esp *esp; 109 struct resource *res; 110 int err; 111 112 host = scsi_host_alloc(tpnt, sizeof(struct esp)); 113 114 err = -ENOMEM; 115 if (!host) 116 goto fail; 117 118 host->max_id = 8; 119 esp = shost_priv(host); 120 121 esp->host = host; 122 esp->dev = &dev->dev; 123 esp->ops = &jazz_esp_ops; 124 125 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 126 if (!res) 127 goto fail_unlink; 128 129 esp->regs = (void __iomem *)res->start; 130 if (!esp->regs) 131 goto fail_unlink; 132 133 res = platform_get_resource(dev, IORESOURCE_MEM, 1); 134 if (!res) 135 goto fail_unlink; 136 137 esp->dma_regs = (void __iomem *)res->start; 138 139 esp->command_block = dma_alloc_coherent(esp->dev, 16, 140 &esp->command_block_dma, 141 GFP_KERNEL); 142 if (!esp->command_block) 143 goto fail_unmap_regs; 144 145 host->irq = platform_get_irq(dev, 0); 146 err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); 147 if (err < 0) 148 goto fail_unmap_command_block; 149 150 esp->scsi_id = 7; 151 esp->host->this_id = esp->scsi_id; 152 esp->scsi_id_mask = (1 << esp->scsi_id); 153 esp->cfreq = 40000000; 154 155 dev_set_drvdata(&dev->dev, esp); 156 157 err = scsi_esp_register(esp); 158 if (err) 159 goto fail_free_irq; 160 161 return 0; 162 163 fail_free_irq: 164 free_irq(host->irq, esp); 165 fail_unmap_command_block: 166 dma_free_coherent(esp->dev, 16, 167 esp->command_block, 168 esp->command_block_dma); 169 fail_unmap_regs: 170 fail_unlink: 171 scsi_host_put(host); 172 fail: 173 return err; 174 } 175 176 static int esp_jazz_remove(struct platform_device *dev) 177 { 178 struct esp *esp = dev_get_drvdata(&dev->dev); 179 unsigned int irq = esp->host->irq; 180 181 scsi_esp_unregister(esp); 182 183 free_irq(irq, esp); 184 dma_free_coherent(esp->dev, 16, 185 esp->command_block, 186 esp->command_block_dma); 187 188 scsi_host_put(esp->host); 189 190 return 0; 191 } 192 193 /* work with hotplug and coldplug */ 194 MODULE_ALIAS("platform:jazz_esp"); 195 196 static struct platform_driver esp_jazz_driver = { 197 .probe = esp_jazz_probe, 198 .remove = esp_jazz_remove, 199 .driver = { 200 .name = "jazz_esp", 201 }, 202 }; 203 204 static int __init jazz_esp_init(void) 205 { 206 return platform_driver_register(&esp_jazz_driver); 207 } 208 209 static void __exit jazz_esp_exit(void) 210 { 211 platform_driver_unregister(&esp_jazz_driver); 212 } 213 214 MODULE_DESCRIPTION("JAZZ ESP SCSI driver"); 215 MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); 216 MODULE_LICENSE("GPL"); 217 MODULE_VERSION(DRV_VERSION); 218 219 module_init(jazz_esp_init); 220 module_exit(jazz_esp_exit); 221