614 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* sun_esp.c: ESP front-end for Sparc SBUS systems.3 *4 * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)5 */6 7#include <linux/kernel.h>8#include <linux/types.h>9#include <linux/delay.h>10#include <linux/module.h>11#include <linux/mm.h>12#include <linux/init.h>13#include <linux/dma-mapping.h>14#include <linux/of.h>15#include <linux/of_platform.h>16#include <linux/platform_device.h>17#include <linux/gfp.h>18 19#include <asm/irq.h>20#include <asm/io.h>21#include <asm/dma.h>22 23#include <scsi/scsi_host.h>24 25#include "esp_scsi.h"26 27#define DRV_MODULE_NAME "sun_esp"28#define PFX DRV_MODULE_NAME ": "29#define DRV_VERSION "1.100"30#define DRV_MODULE_RELDATE "August 27, 2008"31 32#define dma_read32(REG) \33 sbus_readl(esp->dma_regs + (REG))34#define dma_write32(VAL, REG) \35 sbus_writel((VAL), esp->dma_regs + (REG))36 37/* DVMA chip revisions */38enum dvma_rev {39 dvmarev0,40 dvmaesc1,41 dvmarev1,42 dvmarev2,43 dvmarev3,44 dvmarevplus,45 dvmahme46};47 48static int esp_sbus_setup_dma(struct esp *esp, struct platform_device *dma_of)49{50 esp->dma = dma_of;51 52 esp->dma_regs = of_ioremap(&dma_of->resource[0], 0,53 resource_size(&dma_of->resource[0]),54 "espdma");55 if (!esp->dma_regs)56 return -ENOMEM;57 58 switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) {59 case DMA_VERS0:60 esp->dmarev = dvmarev0;61 break;62 case DMA_ESCV1:63 esp->dmarev = dvmaesc1;64 break;65 case DMA_VERS1:66 esp->dmarev = dvmarev1;67 break;68 case DMA_VERS2:69 esp->dmarev = dvmarev2;70 break;71 case DMA_VERHME:72 esp->dmarev = dvmahme;73 break;74 case DMA_VERSPLUS:75 esp->dmarev = dvmarevplus;76 break;77 }78 79 return 0;80 81}82 83static int esp_sbus_map_regs(struct esp *esp, int hme)84{85 struct platform_device *op = to_platform_device(esp->dev);86 struct resource *res;87 88 /* On HME, two reg sets exist, first is DVMA,89 * second is ESP registers.90 */91 if (hme)92 res = &op->resource[1];93 else94 res = &op->resource[0];95 96 esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");97 if (!esp->regs)98 return -ENOMEM;99 100 return 0;101}102 103static int esp_sbus_map_command_block(struct esp *esp)104{105 esp->command_block = dma_alloc_coherent(esp->dev, 16,106 &esp->command_block_dma,107 GFP_KERNEL);108 if (!esp->command_block)109 return -ENOMEM;110 return 0;111}112 113static int esp_sbus_register_irq(struct esp *esp)114{115 struct Scsi_Host *host = esp->host;116 struct platform_device *op = to_platform_device(esp->dev);117 118 host->irq = op->archdata.irqs[0];119 return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);120}121 122static void esp_get_scsi_id(struct esp *esp, struct platform_device *espdma)123{124 struct platform_device *op = to_platform_device(esp->dev);125 struct device_node *dp;126 127 dp = op->dev.of_node;128 esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);129 if (esp->scsi_id != 0xff)130 goto done;131 132 esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff);133 if (esp->scsi_id != 0xff)134 goto done;135 136 esp->scsi_id = of_getintprop_default(espdma->dev.of_node,137 "scsi-initiator-id", 7);138 139done:140 esp->host->this_id = esp->scsi_id;141 esp->scsi_id_mask = (1 << esp->scsi_id);142}143 144static void esp_get_differential(struct esp *esp)145{146 struct platform_device *op = to_platform_device(esp->dev);147 struct device_node *dp;148 149 dp = op->dev.of_node;150 if (of_property_read_bool(dp, "differential"))151 esp->flags |= ESP_FLAG_DIFFERENTIAL;152 else153 esp->flags &= ~ESP_FLAG_DIFFERENTIAL;154}155 156static void esp_get_clock_params(struct esp *esp)157{158 struct platform_device *op = to_platform_device(esp->dev);159 struct device_node *bus_dp, *dp;160 int fmhz;161 162 dp = op->dev.of_node;163 bus_dp = dp->parent;164 165 fmhz = of_getintprop_default(dp, "clock-frequency", 0);166 if (fmhz == 0)167 fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0);168 169 esp->cfreq = fmhz;170}171 172static void esp_get_bursts(struct esp *esp, struct platform_device *dma_of)173{174 struct device_node *dma_dp = dma_of->dev.of_node;175 struct platform_device *op = to_platform_device(esp->dev);176 struct device_node *dp;177 u8 bursts, val;178 179 dp = op->dev.of_node;180 bursts = of_getintprop_default(dp, "burst-sizes", 0xff);181 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);182 if (val != 0xff)183 bursts &= val;184 185 val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff);186 if (val != 0xff)187 bursts &= val;188 189 if (bursts == 0xff ||190 (bursts & DMA_BURST16) == 0 ||191 (bursts & DMA_BURST32) == 0)192 bursts = (DMA_BURST32 - 1);193 194 esp->bursts = bursts;195}196 197static void esp_sbus_get_props(struct esp *esp, struct platform_device *espdma)198{199 esp_get_scsi_id(esp, espdma);200 esp_get_differential(esp);201 esp_get_clock_params(esp);202 esp_get_bursts(esp, espdma);203}204 205static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg)206{207 sbus_writeb(val, esp->regs + (reg * 4UL));208}209 210static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)211{212 return sbus_readb(esp->regs + (reg * 4UL));213}214 215static int sbus_esp_irq_pending(struct esp *esp)216{217 if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))218 return 1;219 return 0;220}221 222static void sbus_esp_reset_dma(struct esp *esp)223{224 int can_do_burst16, can_do_burst32, can_do_burst64;225 int can_do_sbus64, lim;226 struct platform_device *op = to_platform_device(esp->dev);227 u32 val;228 229 can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;230 can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;231 can_do_burst64 = 0;232 can_do_sbus64 = 0;233 if (sbus_can_dma_64bit())234 can_do_sbus64 = 1;235 if (sbus_can_burst64())236 can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;237 238 /* Put the DVMA into a known state. */239 if (esp->dmarev != dvmahme) {240 val = dma_read32(DMA_CSR);241 dma_write32(val | DMA_RST_SCSI, DMA_CSR);242 dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);243 }244 switch (esp->dmarev) {245 case dvmahme:246 dma_write32(DMA_RESET_FAS366, DMA_CSR);247 dma_write32(DMA_RST_SCSI, DMA_CSR);248 249 esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS |250 DMA_SCSI_DISAB | DMA_INT_ENAB);251 252 esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE |253 DMA_BRST_SZ);254 255 if (can_do_burst64)256 esp->prev_hme_dmacsr |= DMA_BRST64;257 else if (can_do_burst32)258 esp->prev_hme_dmacsr |= DMA_BRST32;259 260 if (can_do_sbus64) {261 esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;262 sbus_set_sbus64(&op->dev, esp->bursts);263 }264 265 lim = 1000;266 while (dma_read32(DMA_CSR) & DMA_PEND_READ) {267 if (--lim == 0) {268 printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ "269 "will not clear!\n",270 esp->host->unique_id);271 break;272 }273 udelay(1);274 }275 276 dma_write32(0, DMA_CSR);277 dma_write32(esp->prev_hme_dmacsr, DMA_CSR);278 279 dma_write32(0, DMA_ADDR);280 break;281 282 case dvmarev2:283 if (esp->rev != ESP100) {284 val = dma_read32(DMA_CSR);285 dma_write32(val | DMA_3CLKS, DMA_CSR);286 }287 break;288 289 case dvmarev3:290 val = dma_read32(DMA_CSR);291 val &= ~DMA_3CLKS;292 val |= DMA_2CLKS;293 if (can_do_burst32) {294 val &= ~DMA_BRST_SZ;295 val |= DMA_BRST32;296 }297 dma_write32(val, DMA_CSR);298 break;299 300 case dvmaesc1:301 val = dma_read32(DMA_CSR);302 val |= DMA_ADD_ENABLE;303 val &= ~DMA_BCNT_ENAB;304 if (!can_do_burst32 && can_do_burst16) {305 val |= DMA_ESC_BURST;306 } else {307 val &= ~(DMA_ESC_BURST);308 }309 dma_write32(val, DMA_CSR);310 break;311 312 default:313 break;314 }315 316 /* Enable interrupts. */317 val = dma_read32(DMA_CSR);318 dma_write32(val | DMA_INT_ENAB, DMA_CSR);319}320 321static void sbus_esp_dma_drain(struct esp *esp)322{323 u32 csr;324 int lim;325 326 if (esp->dmarev == dvmahme)327 return;328 329 csr = dma_read32(DMA_CSR);330 if (!(csr & DMA_FIFO_ISDRAIN))331 return;332 333 if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1)334 dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);335 336 lim = 1000;337 while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {338 if (--lim == 0) {339 printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",340 esp->host->unique_id);341 break;342 }343 udelay(1);344 }345}346 347static void sbus_esp_dma_invalidate(struct esp *esp)348{349 if (esp->dmarev == dvmahme) {350 dma_write32(DMA_RST_SCSI, DMA_CSR);351 352 esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |353 (DMA_PARITY_OFF | DMA_2CLKS |354 DMA_SCSI_DISAB | DMA_INT_ENAB)) &355 ~(DMA_ST_WRITE | DMA_ENABLE));356 357 dma_write32(0, DMA_CSR);358 dma_write32(esp->prev_hme_dmacsr, DMA_CSR);359 360 /* This is necessary to avoid having the SCSI channel361 * engine lock up on us.362 */363 dma_write32(0, DMA_ADDR);364 } else {365 u32 val;366 int lim;367 368 lim = 1000;369 while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {370 if (--lim == 0) {371 printk(KERN_ALERT PFX "esp%d: DMA will not "372 "invalidate!\n", esp->host->unique_id);373 break;374 }375 udelay(1);376 }377 378 val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);379 val |= DMA_FIFO_INV;380 dma_write32(val, DMA_CSR);381 val &= ~DMA_FIFO_INV;382 dma_write32(val, DMA_CSR);383 }384}385 386static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,387 u32 dma_count, int write, u8 cmd)388{389 u32 csr;390 391 BUG_ON(!(cmd & ESP_CMD_DMA));392 393 sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);394 sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);395 if (esp->rev == FASHME) {396 sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO);397 sbus_esp_write8(esp, 0, FAS_RHI);398 399 scsi_esp_cmd(esp, cmd);400 401 csr = esp->prev_hme_dmacsr;402 csr |= DMA_SCSI_DISAB | DMA_ENABLE;403 if (write)404 csr |= DMA_ST_WRITE;405 else406 csr &= ~DMA_ST_WRITE;407 esp->prev_hme_dmacsr = csr;408 409 dma_write32(dma_count, DMA_COUNT);410 dma_write32(addr, DMA_ADDR);411 dma_write32(csr, DMA_CSR);412 } else {413 csr = dma_read32(DMA_CSR);414 csr |= DMA_ENABLE;415 if (write)416 csr |= DMA_ST_WRITE;417 else418 csr &= ~DMA_ST_WRITE;419 dma_write32(csr, DMA_CSR);420 if (esp->dmarev == dvmaesc1) {421 u32 end = PAGE_ALIGN(addr + dma_count + 16U);422 dma_write32(end - addr, DMA_COUNT);423 }424 dma_write32(addr, DMA_ADDR);425 426 scsi_esp_cmd(esp, cmd);427 }428 429}430 431static int sbus_esp_dma_error(struct esp *esp)432{433 u32 csr = dma_read32(DMA_CSR);434 435 if (csr & DMA_HNDL_ERROR)436 return 1;437 438 return 0;439}440 441static const struct esp_driver_ops sbus_esp_ops = {442 .esp_write8 = sbus_esp_write8,443 .esp_read8 = sbus_esp_read8,444 .irq_pending = sbus_esp_irq_pending,445 .reset_dma = sbus_esp_reset_dma,446 .dma_drain = sbus_esp_dma_drain,447 .dma_invalidate = sbus_esp_dma_invalidate,448 .send_dma_cmd = sbus_esp_send_dma_cmd,449 .dma_error = sbus_esp_dma_error,450};451 452static int esp_sbus_probe_one(struct platform_device *op,453 struct platform_device *espdma, int hme)454{455 const struct scsi_host_template *tpnt = &scsi_esp_template;456 struct Scsi_Host *host;457 struct esp *esp;458 int err;459 460 host = scsi_host_alloc(tpnt, sizeof(struct esp));461 462 err = -ENOMEM;463 if (!host)464 goto fail;465 466 host->max_id = (hme ? 16 : 8);467 esp = shost_priv(host);468 469 esp->host = host;470 esp->dev = &op->dev;471 esp->ops = &sbus_esp_ops;472 473 if (hme)474 esp->flags |= ESP_FLAG_WIDE_CAPABLE;475 476 err = esp_sbus_setup_dma(esp, espdma);477 if (err < 0)478 goto fail_unlink;479 480 err = esp_sbus_map_regs(esp, hme);481 if (err < 0)482 goto fail_unlink;483 484 err = esp_sbus_map_command_block(esp);485 if (err < 0)486 goto fail_unmap_regs;487 488 err = esp_sbus_register_irq(esp);489 if (err < 0)490 goto fail_unmap_command_block;491 492 esp_sbus_get_props(esp, espdma);493 494 /* Before we try to touch the ESP chip, ESC1 dma can495 * come up with the reset bit set, so make sure that496 * is clear first.497 */498 if (esp->dmarev == dvmaesc1) {499 u32 val = dma_read32(DMA_CSR);500 501 dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);502 }503 504 dev_set_drvdata(&op->dev, esp);505 506 err = scsi_esp_register(esp);507 if (err)508 goto fail_free_irq;509 510 return 0;511 512fail_free_irq:513 free_irq(host->irq, esp);514fail_unmap_command_block:515 dma_free_coherent(&op->dev, 16,516 esp->command_block,517 esp->command_block_dma);518fail_unmap_regs:519 of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE);520fail_unlink:521 scsi_host_put(host);522fail:523 return err;524}525 526static int esp_sbus_probe(struct platform_device *op)527{528 struct device_node *dma_node = NULL;529 struct device_node *dp = op->dev.of_node;530 struct platform_device *dma_of = NULL;531 int hme = 0;532 int ret;533 534 if (of_node_name_eq(dp->parent, "espdma") ||535 of_node_name_eq(dp->parent, "dma"))536 dma_node = dp->parent;537 else if (of_node_name_eq(dp, "SUNW,fas")) {538 dma_node = op->dev.of_node;539 hme = 1;540 }541 if (dma_node)542 dma_of = of_find_device_by_node(dma_node);543 if (!dma_of)544 return -ENODEV;545 546 ret = esp_sbus_probe_one(op, dma_of, hme);547 if (ret)548 put_device(&dma_of->dev);549 550 return ret;551}552 553static void esp_sbus_remove(struct platform_device *op)554{555 struct esp *esp = dev_get_drvdata(&op->dev);556 struct platform_device *dma_of = esp->dma;557 unsigned int irq = esp->host->irq;558 bool is_hme;559 u32 val;560 561 scsi_esp_unregister(esp);562 563 /* Disable interrupts. */564 val = dma_read32(DMA_CSR);565 dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);566 567 free_irq(irq, esp);568 569 is_hme = (esp->dmarev == dvmahme);570 571 dma_free_coherent(&op->dev, 16,572 esp->command_block,573 esp->command_block_dma);574 of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs,575 SBUS_ESP_REG_SIZE);576 of_iounmap(&dma_of->resource[0], esp->dma_regs,577 resource_size(&dma_of->resource[0]));578 579 scsi_host_put(esp->host);580 581 dev_set_drvdata(&op->dev, NULL);582 583 put_device(&dma_of->dev);584}585 586static const struct of_device_id esp_match[] = {587 {588 .name = "SUNW,esp",589 },590 {591 .name = "SUNW,fas",592 },593 {594 .name = "esp",595 },596 {},597};598MODULE_DEVICE_TABLE(of, esp_match);599 600static struct platform_driver esp_sbus_driver = {601 .driver = {602 .name = "esp",603 .of_match_table = esp_match,604 },605 .probe = esp_sbus_probe,606 .remove_new = esp_sbus_remove,607};608module_platform_driver(esp_sbus_driver);609 610MODULE_DESCRIPTION("Sun ESP SCSI driver");611MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");612MODULE_LICENSE("GPL");613MODULE_VERSION(DRV_VERSION);614