162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* sun_esp.c: ESP front-end for Sparc SBUS systems. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/mm.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_platform.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/gfp.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/irq.h> 2062306a36Sopenharmony_ci#include <asm/io.h> 2162306a36Sopenharmony_ci#include <asm/dma.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "esp_scsi.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DRV_MODULE_NAME "sun_esp" 2862306a36Sopenharmony_ci#define PFX DRV_MODULE_NAME ": " 2962306a36Sopenharmony_ci#define DRV_VERSION "1.100" 3062306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "August 27, 2008" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define dma_read32(REG) \ 3362306a36Sopenharmony_ci sbus_readl(esp->dma_regs + (REG)) 3462306a36Sopenharmony_ci#define dma_write32(VAL, REG) \ 3562306a36Sopenharmony_ci sbus_writel((VAL), esp->dma_regs + (REG)) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* DVMA chip revisions */ 3862306a36Sopenharmony_cienum dvma_rev { 3962306a36Sopenharmony_ci dvmarev0, 4062306a36Sopenharmony_ci dvmaesc1, 4162306a36Sopenharmony_ci dvmarev1, 4262306a36Sopenharmony_ci dvmarev2, 4362306a36Sopenharmony_ci dvmarev3, 4462306a36Sopenharmony_ci dvmarevplus, 4562306a36Sopenharmony_ci dvmahme 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int esp_sbus_setup_dma(struct esp *esp, struct platform_device *dma_of) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci esp->dma = dma_of; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci esp->dma_regs = of_ioremap(&dma_of->resource[0], 0, 5362306a36Sopenharmony_ci resource_size(&dma_of->resource[0]), 5462306a36Sopenharmony_ci "espdma"); 5562306a36Sopenharmony_ci if (!esp->dma_regs) 5662306a36Sopenharmony_ci return -ENOMEM; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) { 5962306a36Sopenharmony_ci case DMA_VERS0: 6062306a36Sopenharmony_ci esp->dmarev = dvmarev0; 6162306a36Sopenharmony_ci break; 6262306a36Sopenharmony_ci case DMA_ESCV1: 6362306a36Sopenharmony_ci esp->dmarev = dvmaesc1; 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci case DMA_VERS1: 6662306a36Sopenharmony_ci esp->dmarev = dvmarev1; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci case DMA_VERS2: 6962306a36Sopenharmony_ci esp->dmarev = dvmarev2; 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci case DMA_VERHME: 7262306a36Sopenharmony_ci esp->dmarev = dvmahme; 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci case DMA_VERSPLUS: 7562306a36Sopenharmony_ci esp->dmarev = dvmarevplus; 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int esp_sbus_map_regs(struct esp *esp, int hme) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 8662306a36Sopenharmony_ci struct resource *res; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* On HME, two reg sets exist, first is DVMA, 8962306a36Sopenharmony_ci * second is ESP registers. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci if (hme) 9262306a36Sopenharmony_ci res = &op->resource[1]; 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci res = &op->resource[0]; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); 9762306a36Sopenharmony_ci if (!esp->regs) 9862306a36Sopenharmony_ci return -ENOMEM; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int esp_sbus_map_command_block(struct esp *esp) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci esp->command_block = dma_alloc_coherent(esp->dev, 16, 10662306a36Sopenharmony_ci &esp->command_block_dma, 10762306a36Sopenharmony_ci GFP_KERNEL); 10862306a36Sopenharmony_ci if (!esp->command_block) 10962306a36Sopenharmony_ci return -ENOMEM; 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int esp_sbus_register_irq(struct esp *esp) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct Scsi_Host *host = esp->host; 11662306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci host->irq = op->archdata.irqs[0]; 11962306a36Sopenharmony_ci return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void esp_get_scsi_id(struct esp *esp, struct platform_device *espdma) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 12562306a36Sopenharmony_ci struct device_node *dp; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci dp = op->dev.of_node; 12862306a36Sopenharmony_ci esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); 12962306a36Sopenharmony_ci if (esp->scsi_id != 0xff) 13062306a36Sopenharmony_ci goto done; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff); 13362306a36Sopenharmony_ci if (esp->scsi_id != 0xff) 13462306a36Sopenharmony_ci goto done; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci esp->scsi_id = of_getintprop_default(espdma->dev.of_node, 13762306a36Sopenharmony_ci "scsi-initiator-id", 7); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cidone: 14062306a36Sopenharmony_ci esp->host->this_id = esp->scsi_id; 14162306a36Sopenharmony_ci esp->scsi_id_mask = (1 << esp->scsi_id); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void esp_get_differential(struct esp *esp) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 14762306a36Sopenharmony_ci struct device_node *dp; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci dp = op->dev.of_node; 15062306a36Sopenharmony_ci if (of_property_read_bool(dp, "differential")) 15162306a36Sopenharmony_ci esp->flags |= ESP_FLAG_DIFFERENTIAL; 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci esp->flags &= ~ESP_FLAG_DIFFERENTIAL; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void esp_get_clock_params(struct esp *esp) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 15962306a36Sopenharmony_ci struct device_node *bus_dp, *dp; 16062306a36Sopenharmony_ci int fmhz; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci dp = op->dev.of_node; 16362306a36Sopenharmony_ci bus_dp = dp->parent; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci fmhz = of_getintprop_default(dp, "clock-frequency", 0); 16662306a36Sopenharmony_ci if (fmhz == 0) 16762306a36Sopenharmony_ci fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci esp->cfreq = fmhz; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void esp_get_bursts(struct esp *esp, struct platform_device *dma_of) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct device_node *dma_dp = dma_of->dev.of_node; 17562306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 17662306a36Sopenharmony_ci struct device_node *dp; 17762306a36Sopenharmony_ci u8 bursts, val; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci dp = op->dev.of_node; 18062306a36Sopenharmony_ci bursts = of_getintprop_default(dp, "burst-sizes", 0xff); 18162306a36Sopenharmony_ci val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); 18262306a36Sopenharmony_ci if (val != 0xff) 18362306a36Sopenharmony_ci bursts &= val; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff); 18662306a36Sopenharmony_ci if (val != 0xff) 18762306a36Sopenharmony_ci bursts &= val; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (bursts == 0xff || 19062306a36Sopenharmony_ci (bursts & DMA_BURST16) == 0 || 19162306a36Sopenharmony_ci (bursts & DMA_BURST32) == 0) 19262306a36Sopenharmony_ci bursts = (DMA_BURST32 - 1); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci esp->bursts = bursts; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void esp_sbus_get_props(struct esp *esp, struct platform_device *espdma) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci esp_get_scsi_id(esp, espdma); 20062306a36Sopenharmony_ci esp_get_differential(esp); 20162306a36Sopenharmony_ci esp_get_clock_params(esp); 20262306a36Sopenharmony_ci esp_get_bursts(esp, espdma); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci sbus_writeb(val, esp->regs + (reg * 4UL)); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic u8 sbus_esp_read8(struct esp *esp, unsigned long reg) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return sbus_readb(esp->regs + (reg * 4UL)); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int sbus_esp_irq_pending(struct esp *esp) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) 21862306a36Sopenharmony_ci return 1; 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic void sbus_esp_reset_dma(struct esp *esp) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int can_do_burst16, can_do_burst32, can_do_burst64; 22562306a36Sopenharmony_ci int can_do_sbus64, lim; 22662306a36Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 22762306a36Sopenharmony_ci u32 val; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; 23062306a36Sopenharmony_ci can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; 23162306a36Sopenharmony_ci can_do_burst64 = 0; 23262306a36Sopenharmony_ci can_do_sbus64 = 0; 23362306a36Sopenharmony_ci if (sbus_can_dma_64bit()) 23462306a36Sopenharmony_ci can_do_sbus64 = 1; 23562306a36Sopenharmony_ci if (sbus_can_burst64()) 23662306a36Sopenharmony_ci can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Put the DVMA into a known state. */ 23962306a36Sopenharmony_ci if (esp->dmarev != dvmahme) { 24062306a36Sopenharmony_ci val = dma_read32(DMA_CSR); 24162306a36Sopenharmony_ci dma_write32(val | DMA_RST_SCSI, DMA_CSR); 24262306a36Sopenharmony_ci dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci switch (esp->dmarev) { 24562306a36Sopenharmony_ci case dvmahme: 24662306a36Sopenharmony_ci dma_write32(DMA_RESET_FAS366, DMA_CSR); 24762306a36Sopenharmony_ci dma_write32(DMA_RST_SCSI, DMA_CSR); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS | 25062306a36Sopenharmony_ci DMA_SCSI_DISAB | DMA_INT_ENAB); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE | 25362306a36Sopenharmony_ci DMA_BRST_SZ); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (can_do_burst64) 25662306a36Sopenharmony_ci esp->prev_hme_dmacsr |= DMA_BRST64; 25762306a36Sopenharmony_ci else if (can_do_burst32) 25862306a36Sopenharmony_ci esp->prev_hme_dmacsr |= DMA_BRST32; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (can_do_sbus64) { 26162306a36Sopenharmony_ci esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; 26262306a36Sopenharmony_ci sbus_set_sbus64(&op->dev, esp->bursts); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci lim = 1000; 26662306a36Sopenharmony_ci while (dma_read32(DMA_CSR) & DMA_PEND_READ) { 26762306a36Sopenharmony_ci if (--lim == 0) { 26862306a36Sopenharmony_ci printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ " 26962306a36Sopenharmony_ci "will not clear!\n", 27062306a36Sopenharmony_ci esp->host->unique_id); 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci udelay(1); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci dma_write32(0, DMA_CSR); 27762306a36Sopenharmony_ci dma_write32(esp->prev_hme_dmacsr, DMA_CSR); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci dma_write32(0, DMA_ADDR); 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci case dvmarev2: 28362306a36Sopenharmony_ci if (esp->rev != ESP100) { 28462306a36Sopenharmony_ci val = dma_read32(DMA_CSR); 28562306a36Sopenharmony_ci dma_write32(val | DMA_3CLKS, DMA_CSR); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci case dvmarev3: 29062306a36Sopenharmony_ci val = dma_read32(DMA_CSR); 29162306a36Sopenharmony_ci val &= ~DMA_3CLKS; 29262306a36Sopenharmony_ci val |= DMA_2CLKS; 29362306a36Sopenharmony_ci if (can_do_burst32) { 29462306a36Sopenharmony_ci val &= ~DMA_BRST_SZ; 29562306a36Sopenharmony_ci val |= DMA_BRST32; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci dma_write32(val, DMA_CSR); 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci case dvmaesc1: 30162306a36Sopenharmony_ci val = dma_read32(DMA_CSR); 30262306a36Sopenharmony_ci val |= DMA_ADD_ENABLE; 30362306a36Sopenharmony_ci val &= ~DMA_BCNT_ENAB; 30462306a36Sopenharmony_ci if (!can_do_burst32 && can_do_burst16) { 30562306a36Sopenharmony_ci val |= DMA_ESC_BURST; 30662306a36Sopenharmony_ci } else { 30762306a36Sopenharmony_ci val &= ~(DMA_ESC_BURST); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci dma_write32(val, DMA_CSR); 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci default: 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Enable interrupts. */ 31762306a36Sopenharmony_ci val = dma_read32(DMA_CSR); 31862306a36Sopenharmony_ci dma_write32(val | DMA_INT_ENAB, DMA_CSR); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void sbus_esp_dma_drain(struct esp *esp) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci u32 csr; 32462306a36Sopenharmony_ci int lim; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (esp->dmarev == dvmahme) 32762306a36Sopenharmony_ci return; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci csr = dma_read32(DMA_CSR); 33062306a36Sopenharmony_ci if (!(csr & DMA_FIFO_ISDRAIN)) 33162306a36Sopenharmony_ci return; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1) 33462306a36Sopenharmony_ci dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci lim = 1000; 33762306a36Sopenharmony_ci while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { 33862306a36Sopenharmony_ci if (--lim == 0) { 33962306a36Sopenharmony_ci printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", 34062306a36Sopenharmony_ci esp->host->unique_id); 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci udelay(1); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void sbus_esp_dma_invalidate(struct esp *esp) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci if (esp->dmarev == dvmahme) { 35062306a36Sopenharmony_ci dma_write32(DMA_RST_SCSI, DMA_CSR); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | 35362306a36Sopenharmony_ci (DMA_PARITY_OFF | DMA_2CLKS | 35462306a36Sopenharmony_ci DMA_SCSI_DISAB | DMA_INT_ENAB)) & 35562306a36Sopenharmony_ci ~(DMA_ST_WRITE | DMA_ENABLE)); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci dma_write32(0, DMA_CSR); 35862306a36Sopenharmony_ci dma_write32(esp->prev_hme_dmacsr, DMA_CSR); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* This is necessary to avoid having the SCSI channel 36162306a36Sopenharmony_ci * engine lock up on us. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci dma_write32(0, DMA_ADDR); 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci u32 val; 36662306a36Sopenharmony_ci int lim; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci lim = 1000; 36962306a36Sopenharmony_ci while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { 37062306a36Sopenharmony_ci if (--lim == 0) { 37162306a36Sopenharmony_ci printk(KERN_ALERT PFX "esp%d: DMA will not " 37262306a36Sopenharmony_ci "invalidate!\n", esp->host->unique_id); 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci udelay(1); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); 37962306a36Sopenharmony_ci val |= DMA_FIFO_INV; 38062306a36Sopenharmony_ci dma_write32(val, DMA_CSR); 38162306a36Sopenharmony_ci val &= ~DMA_FIFO_INV; 38262306a36Sopenharmony_ci dma_write32(val, DMA_CSR); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, 38762306a36Sopenharmony_ci u32 dma_count, int write, u8 cmd) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci u32 csr; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci BUG_ON(!(cmd & ESP_CMD_DMA)); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); 39462306a36Sopenharmony_ci sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); 39562306a36Sopenharmony_ci if (esp->rev == FASHME) { 39662306a36Sopenharmony_ci sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO); 39762306a36Sopenharmony_ci sbus_esp_write8(esp, 0, FAS_RHI); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci scsi_esp_cmd(esp, cmd); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci csr = esp->prev_hme_dmacsr; 40262306a36Sopenharmony_ci csr |= DMA_SCSI_DISAB | DMA_ENABLE; 40362306a36Sopenharmony_ci if (write) 40462306a36Sopenharmony_ci csr |= DMA_ST_WRITE; 40562306a36Sopenharmony_ci else 40662306a36Sopenharmony_ci csr &= ~DMA_ST_WRITE; 40762306a36Sopenharmony_ci esp->prev_hme_dmacsr = csr; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci dma_write32(dma_count, DMA_COUNT); 41062306a36Sopenharmony_ci dma_write32(addr, DMA_ADDR); 41162306a36Sopenharmony_ci dma_write32(csr, DMA_CSR); 41262306a36Sopenharmony_ci } else { 41362306a36Sopenharmony_ci csr = dma_read32(DMA_CSR); 41462306a36Sopenharmony_ci csr |= DMA_ENABLE; 41562306a36Sopenharmony_ci if (write) 41662306a36Sopenharmony_ci csr |= DMA_ST_WRITE; 41762306a36Sopenharmony_ci else 41862306a36Sopenharmony_ci csr &= ~DMA_ST_WRITE; 41962306a36Sopenharmony_ci dma_write32(csr, DMA_CSR); 42062306a36Sopenharmony_ci if (esp->dmarev == dvmaesc1) { 42162306a36Sopenharmony_ci u32 end = PAGE_ALIGN(addr + dma_count + 16U); 42262306a36Sopenharmony_ci dma_write32(end - addr, DMA_COUNT); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci dma_write32(addr, DMA_ADDR); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci scsi_esp_cmd(esp, cmd); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int sbus_esp_dma_error(struct esp *esp) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci u32 csr = dma_read32(DMA_CSR); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (csr & DMA_HNDL_ERROR) 43662306a36Sopenharmony_ci return 1; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic const struct esp_driver_ops sbus_esp_ops = { 44262306a36Sopenharmony_ci .esp_write8 = sbus_esp_write8, 44362306a36Sopenharmony_ci .esp_read8 = sbus_esp_read8, 44462306a36Sopenharmony_ci .irq_pending = sbus_esp_irq_pending, 44562306a36Sopenharmony_ci .reset_dma = sbus_esp_reset_dma, 44662306a36Sopenharmony_ci .dma_drain = sbus_esp_dma_drain, 44762306a36Sopenharmony_ci .dma_invalidate = sbus_esp_dma_invalidate, 44862306a36Sopenharmony_ci .send_dma_cmd = sbus_esp_send_dma_cmd, 44962306a36Sopenharmony_ci .dma_error = sbus_esp_dma_error, 45062306a36Sopenharmony_ci}; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int esp_sbus_probe_one(struct platform_device *op, 45362306a36Sopenharmony_ci struct platform_device *espdma, int hme) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci const struct scsi_host_template *tpnt = &scsi_esp_template; 45662306a36Sopenharmony_ci struct Scsi_Host *host; 45762306a36Sopenharmony_ci struct esp *esp; 45862306a36Sopenharmony_ci int err; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci host = scsi_host_alloc(tpnt, sizeof(struct esp)); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci err = -ENOMEM; 46362306a36Sopenharmony_ci if (!host) 46462306a36Sopenharmony_ci goto fail; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci host->max_id = (hme ? 16 : 8); 46762306a36Sopenharmony_ci esp = shost_priv(host); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci esp->host = host; 47062306a36Sopenharmony_ci esp->dev = &op->dev; 47162306a36Sopenharmony_ci esp->ops = &sbus_esp_ops; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (hme) 47462306a36Sopenharmony_ci esp->flags |= ESP_FLAG_WIDE_CAPABLE; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci err = esp_sbus_setup_dma(esp, espdma); 47762306a36Sopenharmony_ci if (err < 0) 47862306a36Sopenharmony_ci goto fail_unlink; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci err = esp_sbus_map_regs(esp, hme); 48162306a36Sopenharmony_ci if (err < 0) 48262306a36Sopenharmony_ci goto fail_unlink; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci err = esp_sbus_map_command_block(esp); 48562306a36Sopenharmony_ci if (err < 0) 48662306a36Sopenharmony_ci goto fail_unmap_regs; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci err = esp_sbus_register_irq(esp); 48962306a36Sopenharmony_ci if (err < 0) 49062306a36Sopenharmony_ci goto fail_unmap_command_block; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci esp_sbus_get_props(esp, espdma); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Before we try to touch the ESP chip, ESC1 dma can 49562306a36Sopenharmony_ci * come up with the reset bit set, so make sure that 49662306a36Sopenharmony_ci * is clear first. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci if (esp->dmarev == dvmaesc1) { 49962306a36Sopenharmony_ci u32 val = dma_read32(DMA_CSR); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci dev_set_drvdata(&op->dev, esp); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci err = scsi_esp_register(esp); 50762306a36Sopenharmony_ci if (err) 50862306a36Sopenharmony_ci goto fail_free_irq; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cifail_free_irq: 51362306a36Sopenharmony_ci free_irq(host->irq, esp); 51462306a36Sopenharmony_cifail_unmap_command_block: 51562306a36Sopenharmony_ci dma_free_coherent(&op->dev, 16, 51662306a36Sopenharmony_ci esp->command_block, 51762306a36Sopenharmony_ci esp->command_block_dma); 51862306a36Sopenharmony_cifail_unmap_regs: 51962306a36Sopenharmony_ci of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE); 52062306a36Sopenharmony_cifail_unlink: 52162306a36Sopenharmony_ci scsi_host_put(host); 52262306a36Sopenharmony_cifail: 52362306a36Sopenharmony_ci return err; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int esp_sbus_probe(struct platform_device *op) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct device_node *dma_node = NULL; 52962306a36Sopenharmony_ci struct device_node *dp = op->dev.of_node; 53062306a36Sopenharmony_ci struct platform_device *dma_of = NULL; 53162306a36Sopenharmony_ci int hme = 0; 53262306a36Sopenharmony_ci int ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (of_node_name_eq(dp->parent, "espdma") || 53562306a36Sopenharmony_ci of_node_name_eq(dp->parent, "dma")) 53662306a36Sopenharmony_ci dma_node = dp->parent; 53762306a36Sopenharmony_ci else if (of_node_name_eq(dp, "SUNW,fas")) { 53862306a36Sopenharmony_ci dma_node = op->dev.of_node; 53962306a36Sopenharmony_ci hme = 1; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci if (dma_node) 54262306a36Sopenharmony_ci dma_of = of_find_device_by_node(dma_node); 54362306a36Sopenharmony_ci if (!dma_of) 54462306a36Sopenharmony_ci return -ENODEV; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = esp_sbus_probe_one(op, dma_of, hme); 54762306a36Sopenharmony_ci if (ret) 54862306a36Sopenharmony_ci put_device(&dma_of->dev); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return ret; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int esp_sbus_remove(struct platform_device *op) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct esp *esp = dev_get_drvdata(&op->dev); 55662306a36Sopenharmony_ci struct platform_device *dma_of = esp->dma; 55762306a36Sopenharmony_ci unsigned int irq = esp->host->irq; 55862306a36Sopenharmony_ci bool is_hme; 55962306a36Sopenharmony_ci u32 val; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci scsi_esp_unregister(esp); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Disable interrupts. */ 56462306a36Sopenharmony_ci val = dma_read32(DMA_CSR); 56562306a36Sopenharmony_ci dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci free_irq(irq, esp); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci is_hme = (esp->dmarev == dvmahme); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci dma_free_coherent(&op->dev, 16, 57262306a36Sopenharmony_ci esp->command_block, 57362306a36Sopenharmony_ci esp->command_block_dma); 57462306a36Sopenharmony_ci of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs, 57562306a36Sopenharmony_ci SBUS_ESP_REG_SIZE); 57662306a36Sopenharmony_ci of_iounmap(&dma_of->resource[0], esp->dma_regs, 57762306a36Sopenharmony_ci resource_size(&dma_of->resource[0])); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci scsi_host_put(esp->host); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci dev_set_drvdata(&op->dev, NULL); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci put_device(&dma_of->dev); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic const struct of_device_id esp_match[] = { 58962306a36Sopenharmony_ci { 59062306a36Sopenharmony_ci .name = "SUNW,esp", 59162306a36Sopenharmony_ci }, 59262306a36Sopenharmony_ci { 59362306a36Sopenharmony_ci .name = "SUNW,fas", 59462306a36Sopenharmony_ci }, 59562306a36Sopenharmony_ci { 59662306a36Sopenharmony_ci .name = "esp", 59762306a36Sopenharmony_ci }, 59862306a36Sopenharmony_ci {}, 59962306a36Sopenharmony_ci}; 60062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, esp_match); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic struct platform_driver esp_sbus_driver = { 60362306a36Sopenharmony_ci .driver = { 60462306a36Sopenharmony_ci .name = "esp", 60562306a36Sopenharmony_ci .of_match_table = esp_match, 60662306a36Sopenharmony_ci }, 60762306a36Sopenharmony_ci .probe = esp_sbus_probe, 60862306a36Sopenharmony_ci .remove = esp_sbus_remove, 60962306a36Sopenharmony_ci}; 61062306a36Sopenharmony_cimodule_platform_driver(esp_sbus_driver); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ciMODULE_DESCRIPTION("Sun ESP SCSI driver"); 61362306a36Sopenharmony_ciMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 61462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 61562306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 616