447 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* mac_esp.c: ESP front-end for Macintosh Quadra systems.3 *4 * Adapted from jazz_esp.c and the old mac_esp.c.5 *6 * The pseudo DMA algorithm is based on the one used in NetBSD.7 * See sys/arch/mac68k/obio/esp.c for some background information.8 *9 * Copyright (C) 2007-2008 Finn Thain10 */11 12#include <linux/kernel.h>13#include <linux/types.h>14#include <linux/module.h>15#include <linux/init.h>16#include <linux/interrupt.h>17#include <linux/platform_device.h>18#include <linux/dma-mapping.h>19#include <linux/scatterlist.h>20#include <linux/delay.h>21#include <linux/io.h>22#include <linux/nubus.h>23#include <linux/slab.h>24 25#include <asm/irq.h>26#include <asm/dma.h>27#include <asm/macints.h>28#include <asm/macintosh.h>29#include <asm/mac_via.h>30 31#include <scsi/scsi_host.h>32 33#include "esp_scsi.h"34 35#define DRV_MODULE_NAME "mac_esp"36#define PFX DRV_MODULE_NAME ": "37#define DRV_VERSION "1.000"38#define DRV_MODULE_RELDATE "Sept 15, 2007"39 40#define MAC_ESP_IO_BASE 0x50F0000041#define MAC_ESP_REGS_QUADRA (MAC_ESP_IO_BASE + 0x10000)42#define MAC_ESP_REGS_QUADRA2 (MAC_ESP_IO_BASE + 0xF000)43#define MAC_ESP_REGS_QUADRA3 (MAC_ESP_IO_BASE + 0x18000)44#define MAC_ESP_REGS_SPACING 0x40245#define MAC_ESP_PDMA_REG 0xF980002446#define MAC_ESP_PDMA_REG_SPACING 0x447#define MAC_ESP_PDMA_IO_OFFSET 0x10048 49#define esp_read8(REG) mac_esp_read8(esp, REG)50#define esp_write8(VAL, REG) mac_esp_write8(esp, VAL, REG)51 52struct mac_esp_priv {53 struct esp *esp;54 void __iomem *pdma_regs;55 void __iomem *pdma_io;56};57static struct esp *esp_chips[2];58static DEFINE_SPINLOCK(esp_chips_lock);59 60#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \61 dev_get_drvdata((esp)->dev))62 63static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg)64{65 nubus_writeb(val, esp->regs + reg * 16);66}67 68static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg)69{70 return nubus_readb(esp->regs + reg * 16);71}72 73static void mac_esp_reset_dma(struct esp *esp)74{75 /* Nothing to do. */76}77 78static void mac_esp_dma_drain(struct esp *esp)79{80 /* Nothing to do. */81}82 83static void mac_esp_dma_invalidate(struct esp *esp)84{85 /* Nothing to do. */86}87 88static int mac_esp_dma_error(struct esp *esp)89{90 return esp->send_cmd_error;91}92 93static inline int mac_esp_wait_for_empty_fifo(struct esp *esp)94{95 int i = 500000;96 97 do {98 if (!(esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES))99 return 0;100 101 if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)102 return 1;103 104 udelay(2);105 } while (--i);106 107 printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n",108 esp_read8(ESP_STATUS));109 esp->send_cmd_error = 1;110 return 1;111}112 113static inline int mac_esp_wait_for_dreq(struct esp *esp)114{115 struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);116 int i = 500000;117 118 do {119 if (mep->pdma_regs == NULL) {120 if (via2_scsi_drq_pending())121 return 0;122 } else {123 if (nubus_readl(mep->pdma_regs) & 0x200)124 return 0;125 }126 127 if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)128 return 1;129 130 udelay(2);131 } while (--i);132 133 printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n",134 esp_read8(ESP_STATUS));135 esp->send_cmd_error = 1;136 return 1;137}138 139#define MAC_ESP_PDMA_LOOP(operands) \140 asm volatile ( \141 " tstw %1 \n" \142 " jbeq 20f \n" \143 "1: movew " operands " \n" \144 "2: movew " operands " \n" \145 "3: movew " operands " \n" \146 "4: movew " operands " \n" \147 "5: movew " operands " \n" \148 "6: movew " operands " \n" \149 "7: movew " operands " \n" \150 "8: movew " operands " \n" \151 "9: movew " operands " \n" \152 "10: movew " operands " \n" \153 "11: movew " operands " \n" \154 "12: movew " operands " \n" \155 "13: movew " operands " \n" \156 "14: movew " operands " \n" \157 "15: movew " operands " \n" \158 "16: movew " operands " \n" \159 " subqw #1,%1 \n" \160 " jbne 1b \n" \161 "20: tstw %2 \n" \162 " jbeq 30f \n" \163 "21: movew " operands " \n" \164 " subqw #1,%2 \n" \165 " jbne 21b \n" \166 "30: tstw %3 \n" \167 " jbeq 40f \n" \168 "31: moveb " operands " \n" \169 "32: nop \n" \170 "40: \n" \171 " \n" \172 " .section __ex_table,\"a\" \n" \173 " .align 4 \n" \174 " .long 1b,40b \n" \175 " .long 2b,40b \n" \176 " .long 3b,40b \n" \177 " .long 4b,40b \n" \178 " .long 5b,40b \n" \179 " .long 6b,40b \n" \180 " .long 7b,40b \n" \181 " .long 8b,40b \n" \182 " .long 9b,40b \n" \183 " .long 10b,40b \n" \184 " .long 11b,40b \n" \185 " .long 12b,40b \n" \186 " .long 13b,40b \n" \187 " .long 14b,40b \n" \188 " .long 15b,40b \n" \189 " .long 16b,40b \n" \190 " .long 21b,40b \n" \191 " .long 31b,40b \n" \192 " .long 32b,40b \n" \193 " .previous \n" \194 : "+a" (addr), "+r" (count32), "+r" (count2) \195 : "g" (count1), "a" (mep->pdma_io))196 197static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,198 u32 dma_count, int write, u8 cmd)199{200 struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);201 202 esp->send_cmd_error = 0;203 204 if (!write)205 scsi_esp_cmd(esp, ESP_CMD_FLUSH);206 207 esp_write8((esp_count >> 0) & 0xFF, ESP_TCLOW);208 esp_write8((esp_count >> 8) & 0xFF, ESP_TCMED);209 210 scsi_esp_cmd(esp, cmd);211 212 do {213 unsigned int count32 = esp_count >> 5;214 unsigned int count2 = (esp_count & 0x1F) >> 1;215 unsigned int count1 = esp_count & 1;216 unsigned int start_addr = addr;217 218 if (mac_esp_wait_for_dreq(esp))219 break;220 221 if (write) {222 MAC_ESP_PDMA_LOOP("%4@,%0@+");223 224 esp_count -= addr - start_addr;225 } else {226 unsigned int n;227 228 MAC_ESP_PDMA_LOOP("%0@+,%4@");229 230 if (mac_esp_wait_for_empty_fifo(esp))231 break;232 233 n = (esp_read8(ESP_TCMED) << 8) + esp_read8(ESP_TCLOW);234 addr = start_addr + esp_count - n;235 esp_count = n;236 }237 } while (esp_count);238}239 240static int mac_esp_irq_pending(struct esp *esp)241{242 if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)243 return 1;244 return 0;245}246 247static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)248{249 return dma_len > 0xFFFF ? 0xFFFF : dma_len;250}251 252static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id)253{254 int got_intr;255 256 /*257 * This is an edge triggered IRQ, so we have to be careful to258 * avoid missing a transition when it is shared by two ESP devices.259 */260 261 do {262 got_intr = 0;263 if (esp_chips[0] &&264 (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) {265 (void)scsi_esp_intr(irq, esp_chips[0]);266 got_intr = 1;267 }268 if (esp_chips[1] &&269 (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) {270 (void)scsi_esp_intr(irq, esp_chips[1]);271 got_intr = 1;272 }273 } while (got_intr);274 275 return IRQ_HANDLED;276}277 278static struct esp_driver_ops mac_esp_ops = {279 .esp_write8 = mac_esp_write8,280 .esp_read8 = mac_esp_read8,281 .irq_pending = mac_esp_irq_pending,282 .dma_length_limit = mac_esp_dma_length_limit,283 .reset_dma = mac_esp_reset_dma,284 .dma_drain = mac_esp_dma_drain,285 .dma_invalidate = mac_esp_dma_invalidate,286 .send_dma_cmd = mac_esp_send_pdma_cmd,287 .dma_error = mac_esp_dma_error,288};289 290static int esp_mac_probe(struct platform_device *dev)291{292 const struct scsi_host_template *tpnt = &scsi_esp_template;293 struct Scsi_Host *host;294 struct esp *esp;295 int err;296 struct mac_esp_priv *mep;297 298 if (!MACH_IS_MAC)299 return -ENODEV;300 301 if (dev->id > 1)302 return -ENODEV;303 304 host = scsi_host_alloc(tpnt, sizeof(struct esp));305 306 err = -ENOMEM;307 if (!host)308 goto fail;309 310 host->max_id = 8;311 host->dma_boundary = PAGE_SIZE - 1;312 esp = shost_priv(host);313 314 esp->host = host;315 esp->dev = &dev->dev;316 317 esp->command_block = kzalloc(16, GFP_KERNEL);318 if (!esp->command_block)319 goto fail_unlink;320 esp->command_block_dma = (dma_addr_t)esp->command_block;321 322 esp->scsi_id = 7;323 host->this_id = esp->scsi_id;324 esp->scsi_id_mask = 1 << esp->scsi_id;325 326 mep = kzalloc(sizeof(struct mac_esp_priv), GFP_KERNEL);327 if (!mep)328 goto fail_free_command_block;329 mep->esp = esp;330 platform_set_drvdata(dev, mep);331 332 switch (macintosh_config->scsi_type) {333 case MAC_SCSI_QUADRA:334 esp->cfreq = 16500000;335 esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA;336 mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET;337 mep->pdma_regs = NULL;338 break;339 case MAC_SCSI_QUADRA2:340 esp->cfreq = 25000000;341 esp->regs = (void __iomem *)(MAC_ESP_REGS_QUADRA2 +342 dev->id * MAC_ESP_REGS_SPACING);343 mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET;344 mep->pdma_regs = (void __iomem *)(MAC_ESP_PDMA_REG +345 dev->id * MAC_ESP_PDMA_REG_SPACING);346 nubus_writel(0x1d1, mep->pdma_regs);347 break;348 case MAC_SCSI_QUADRA3:349 /* These quadras have a real DMA controller (the PSC) but we350 * don't know how to drive it so we must use PIO instead.351 */352 esp->cfreq = 25000000;353 esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA3;354 mep->pdma_io = NULL;355 mep->pdma_regs = NULL;356 break;357 }358 esp->fifo_reg = esp->regs + ESP_FDATA * 16;359 360 esp->ops = &mac_esp_ops;361 esp->flags = ESP_FLAG_NO_DMA_MAP;362 if (mep->pdma_io == NULL) {363 printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id);364 esp_write8(0, ESP_TCLOW);365 esp_write8(0, ESP_TCMED);366 esp->flags |= ESP_FLAG_DISABLE_SYNC;367 mac_esp_ops.send_dma_cmd = esp_send_pio_cmd;368 } else {369 printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id);370 }371 372 host->irq = IRQ_MAC_SCSI;373 374 /* The request_irq() call is intended to succeed for the first device375 * and fail for the second device.376 */377 err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL);378 spin_lock(&esp_chips_lock);379 if (err < 0 && esp_chips[!dev->id] == NULL) {380 spin_unlock(&esp_chips_lock);381 goto fail_free_priv;382 }383 esp_chips[dev->id] = esp;384 spin_unlock(&esp_chips_lock);385 386 err = scsi_esp_register(esp);387 if (err)388 goto fail_free_irq;389 390 return 0;391 392fail_free_irq:393 spin_lock(&esp_chips_lock);394 esp_chips[dev->id] = NULL;395 if (esp_chips[!dev->id] == NULL) {396 spin_unlock(&esp_chips_lock);397 free_irq(host->irq, NULL);398 } else399 spin_unlock(&esp_chips_lock);400fail_free_priv:401 kfree(mep);402fail_free_command_block:403 kfree(esp->command_block);404fail_unlink:405 scsi_host_put(host);406fail:407 return err;408}409 410static void esp_mac_remove(struct platform_device *dev)411{412 struct mac_esp_priv *mep = platform_get_drvdata(dev);413 struct esp *esp = mep->esp;414 unsigned int irq = esp->host->irq;415 416 scsi_esp_unregister(esp);417 418 spin_lock(&esp_chips_lock);419 esp_chips[dev->id] = NULL;420 if (esp_chips[!dev->id] == NULL) {421 spin_unlock(&esp_chips_lock);422 free_irq(irq, NULL);423 } else424 spin_unlock(&esp_chips_lock);425 426 kfree(mep);427 428 kfree(esp->command_block);429 430 scsi_host_put(esp->host);431}432 433static struct platform_driver esp_mac_driver = {434 .probe = esp_mac_probe,435 .remove_new = esp_mac_remove,436 .driver = {437 .name = DRV_MODULE_NAME,438 },439};440module_platform_driver(esp_mac_driver);441 442MODULE_DESCRIPTION("Mac ESP SCSI driver");443MODULE_AUTHOR("Finn Thain");444MODULE_LICENSE("GPL v2");445MODULE_VERSION(DRV_VERSION);446MODULE_ALIAS("platform:" DRV_MODULE_NAME);447