18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* sun_esp.c: ESP front-end for Sparc SBUS systems. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/mm.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/gfp.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/irq.h> 198c2ecf20Sopenharmony_ci#include <asm/io.h> 208c2ecf20Sopenharmony_ci#include <asm/dma.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "esp_scsi.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "sun_esp" 278c2ecf20Sopenharmony_ci#define PFX DRV_MODULE_NAME ": " 288c2ecf20Sopenharmony_ci#define DRV_VERSION "1.100" 298c2ecf20Sopenharmony_ci#define DRV_MODULE_RELDATE "August 27, 2008" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define dma_read32(REG) \ 328c2ecf20Sopenharmony_ci sbus_readl(esp->dma_regs + (REG)) 338c2ecf20Sopenharmony_ci#define dma_write32(VAL, REG) \ 348c2ecf20Sopenharmony_ci sbus_writel((VAL), esp->dma_regs + (REG)) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* DVMA chip revisions */ 378c2ecf20Sopenharmony_cienum dvma_rev { 388c2ecf20Sopenharmony_ci dvmarev0, 398c2ecf20Sopenharmony_ci dvmaesc1, 408c2ecf20Sopenharmony_ci dvmarev1, 418c2ecf20Sopenharmony_ci dvmarev2, 428c2ecf20Sopenharmony_ci dvmarev3, 438c2ecf20Sopenharmony_ci dvmarevplus, 448c2ecf20Sopenharmony_ci dvmahme 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic int esp_sbus_setup_dma(struct esp *esp, struct platform_device *dma_of) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci esp->dma = dma_of; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci esp->dma_regs = of_ioremap(&dma_of->resource[0], 0, 528c2ecf20Sopenharmony_ci resource_size(&dma_of->resource[0]), 538c2ecf20Sopenharmony_ci "espdma"); 548c2ecf20Sopenharmony_ci if (!esp->dma_regs) 558c2ecf20Sopenharmony_ci return -ENOMEM; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) { 588c2ecf20Sopenharmony_ci case DMA_VERS0: 598c2ecf20Sopenharmony_ci esp->dmarev = dvmarev0; 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci case DMA_ESCV1: 628c2ecf20Sopenharmony_ci esp->dmarev = dvmaesc1; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case DMA_VERS1: 658c2ecf20Sopenharmony_ci esp->dmarev = dvmarev1; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci case DMA_VERS2: 688c2ecf20Sopenharmony_ci esp->dmarev = dvmarev2; 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case DMA_VERHME: 718c2ecf20Sopenharmony_ci esp->dmarev = dvmahme; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case DMA_VERSPLUS: 748c2ecf20Sopenharmony_ci esp->dmarev = dvmarevplus; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int esp_sbus_map_regs(struct esp *esp, int hme) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 858c2ecf20Sopenharmony_ci struct resource *res; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* On HME, two reg sets exist, first is DVMA, 888c2ecf20Sopenharmony_ci * second is ESP registers. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci if (hme) 918c2ecf20Sopenharmony_ci res = &op->resource[1]; 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci res = &op->resource[0]; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); 968c2ecf20Sopenharmony_ci if (!esp->regs) 978c2ecf20Sopenharmony_ci return -ENOMEM; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int esp_sbus_map_command_block(struct esp *esp) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci esp->command_block = dma_alloc_coherent(esp->dev, 16, 1058c2ecf20Sopenharmony_ci &esp->command_block_dma, 1068c2ecf20Sopenharmony_ci GFP_KERNEL); 1078c2ecf20Sopenharmony_ci if (!esp->command_block) 1088c2ecf20Sopenharmony_ci return -ENOMEM; 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int esp_sbus_register_irq(struct esp *esp) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct Scsi_Host *host = esp->host; 1158c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci host->irq = op->archdata.irqs[0]; 1188c2ecf20Sopenharmony_ci return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void esp_get_scsi_id(struct esp *esp, struct platform_device *espdma) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 1248c2ecf20Sopenharmony_ci struct device_node *dp; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci dp = op->dev.of_node; 1278c2ecf20Sopenharmony_ci esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); 1288c2ecf20Sopenharmony_ci if (esp->scsi_id != 0xff) 1298c2ecf20Sopenharmony_ci goto done; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff); 1328c2ecf20Sopenharmony_ci if (esp->scsi_id != 0xff) 1338c2ecf20Sopenharmony_ci goto done; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci esp->scsi_id = of_getintprop_default(espdma->dev.of_node, 1368c2ecf20Sopenharmony_ci "scsi-initiator-id", 7); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cidone: 1398c2ecf20Sopenharmony_ci esp->host->this_id = esp->scsi_id; 1408c2ecf20Sopenharmony_ci esp->scsi_id_mask = (1 << esp->scsi_id); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void esp_get_differential(struct esp *esp) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 1468c2ecf20Sopenharmony_ci struct device_node *dp; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci dp = op->dev.of_node; 1498c2ecf20Sopenharmony_ci if (of_find_property(dp, "differential", NULL)) 1508c2ecf20Sopenharmony_ci esp->flags |= ESP_FLAG_DIFFERENTIAL; 1518c2ecf20Sopenharmony_ci else 1528c2ecf20Sopenharmony_ci esp->flags &= ~ESP_FLAG_DIFFERENTIAL; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void esp_get_clock_params(struct esp *esp) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 1588c2ecf20Sopenharmony_ci struct device_node *bus_dp, *dp; 1598c2ecf20Sopenharmony_ci int fmhz; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dp = op->dev.of_node; 1628c2ecf20Sopenharmony_ci bus_dp = dp->parent; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci fmhz = of_getintprop_default(dp, "clock-frequency", 0); 1658c2ecf20Sopenharmony_ci if (fmhz == 0) 1668c2ecf20Sopenharmony_ci fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci esp->cfreq = fmhz; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void esp_get_bursts(struct esp *esp, struct platform_device *dma_of) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct device_node *dma_dp = dma_of->dev.of_node; 1748c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 1758c2ecf20Sopenharmony_ci struct device_node *dp; 1768c2ecf20Sopenharmony_ci u8 bursts, val; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci dp = op->dev.of_node; 1798c2ecf20Sopenharmony_ci bursts = of_getintprop_default(dp, "burst-sizes", 0xff); 1808c2ecf20Sopenharmony_ci val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); 1818c2ecf20Sopenharmony_ci if (val != 0xff) 1828c2ecf20Sopenharmony_ci bursts &= val; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff); 1858c2ecf20Sopenharmony_ci if (val != 0xff) 1868c2ecf20Sopenharmony_ci bursts &= val; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (bursts == 0xff || 1898c2ecf20Sopenharmony_ci (bursts & DMA_BURST16) == 0 || 1908c2ecf20Sopenharmony_ci (bursts & DMA_BURST32) == 0) 1918c2ecf20Sopenharmony_ci bursts = (DMA_BURST32 - 1); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci esp->bursts = bursts; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void esp_sbus_get_props(struct esp *esp, struct platform_device *espdma) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci esp_get_scsi_id(esp, espdma); 1998c2ecf20Sopenharmony_ci esp_get_differential(esp); 2008c2ecf20Sopenharmony_ci esp_get_clock_params(esp); 2018c2ecf20Sopenharmony_ci esp_get_bursts(esp, espdma); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci sbus_writeb(val, esp->regs + (reg * 4UL)); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic u8 sbus_esp_read8(struct esp *esp, unsigned long reg) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci return sbus_readb(esp->regs + (reg * 4UL)); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int sbus_esp_irq_pending(struct esp *esp) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) 2178c2ecf20Sopenharmony_ci return 1; 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void sbus_esp_reset_dma(struct esp *esp) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int can_do_burst16, can_do_burst32, can_do_burst64; 2248c2ecf20Sopenharmony_ci int can_do_sbus64, lim; 2258c2ecf20Sopenharmony_ci struct platform_device *op = to_platform_device(esp->dev); 2268c2ecf20Sopenharmony_ci u32 val; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; 2298c2ecf20Sopenharmony_ci can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; 2308c2ecf20Sopenharmony_ci can_do_burst64 = 0; 2318c2ecf20Sopenharmony_ci can_do_sbus64 = 0; 2328c2ecf20Sopenharmony_ci if (sbus_can_dma_64bit()) 2338c2ecf20Sopenharmony_ci can_do_sbus64 = 1; 2348c2ecf20Sopenharmony_ci if (sbus_can_burst64()) 2358c2ecf20Sopenharmony_ci can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* Put the DVMA into a known state. */ 2388c2ecf20Sopenharmony_ci if (esp->dmarev != dvmahme) { 2398c2ecf20Sopenharmony_ci val = dma_read32(DMA_CSR); 2408c2ecf20Sopenharmony_ci dma_write32(val | DMA_RST_SCSI, DMA_CSR); 2418c2ecf20Sopenharmony_ci dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci switch (esp->dmarev) { 2448c2ecf20Sopenharmony_ci case dvmahme: 2458c2ecf20Sopenharmony_ci dma_write32(DMA_RESET_FAS366, DMA_CSR); 2468c2ecf20Sopenharmony_ci dma_write32(DMA_RST_SCSI, DMA_CSR); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS | 2498c2ecf20Sopenharmony_ci DMA_SCSI_DISAB | DMA_INT_ENAB); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE | 2528c2ecf20Sopenharmony_ci DMA_BRST_SZ); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (can_do_burst64) 2558c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr |= DMA_BRST64; 2568c2ecf20Sopenharmony_ci else if (can_do_burst32) 2578c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr |= DMA_BRST32; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (can_do_sbus64) { 2608c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; 2618c2ecf20Sopenharmony_ci sbus_set_sbus64(&op->dev, esp->bursts); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci lim = 1000; 2658c2ecf20Sopenharmony_ci while (dma_read32(DMA_CSR) & DMA_PEND_READ) { 2668c2ecf20Sopenharmony_ci if (--lim == 0) { 2678c2ecf20Sopenharmony_ci printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ " 2688c2ecf20Sopenharmony_ci "will not clear!\n", 2698c2ecf20Sopenharmony_ci esp->host->unique_id); 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci udelay(1); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dma_write32(0, DMA_CSR); 2768c2ecf20Sopenharmony_ci dma_write32(esp->prev_hme_dmacsr, DMA_CSR); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dma_write32(0, DMA_ADDR); 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci case dvmarev2: 2828c2ecf20Sopenharmony_ci if (esp->rev != ESP100) { 2838c2ecf20Sopenharmony_ci val = dma_read32(DMA_CSR); 2848c2ecf20Sopenharmony_ci dma_write32(val | DMA_3CLKS, DMA_CSR); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci case dvmarev3: 2898c2ecf20Sopenharmony_ci val = dma_read32(DMA_CSR); 2908c2ecf20Sopenharmony_ci val &= ~DMA_3CLKS; 2918c2ecf20Sopenharmony_ci val |= DMA_2CLKS; 2928c2ecf20Sopenharmony_ci if (can_do_burst32) { 2938c2ecf20Sopenharmony_ci val &= ~DMA_BRST_SZ; 2948c2ecf20Sopenharmony_ci val |= DMA_BRST32; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci dma_write32(val, DMA_CSR); 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci case dvmaesc1: 3008c2ecf20Sopenharmony_ci val = dma_read32(DMA_CSR); 3018c2ecf20Sopenharmony_ci val |= DMA_ADD_ENABLE; 3028c2ecf20Sopenharmony_ci val &= ~DMA_BCNT_ENAB; 3038c2ecf20Sopenharmony_ci if (!can_do_burst32 && can_do_burst16) { 3048c2ecf20Sopenharmony_ci val |= DMA_ESC_BURST; 3058c2ecf20Sopenharmony_ci } else { 3068c2ecf20Sopenharmony_ci val &= ~(DMA_ESC_BURST); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci dma_write32(val, DMA_CSR); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci default: 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Enable interrupts. */ 3168c2ecf20Sopenharmony_ci val = dma_read32(DMA_CSR); 3178c2ecf20Sopenharmony_ci dma_write32(val | DMA_INT_ENAB, DMA_CSR); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void sbus_esp_dma_drain(struct esp *esp) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u32 csr; 3238c2ecf20Sopenharmony_ci int lim; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (esp->dmarev == dvmahme) 3268c2ecf20Sopenharmony_ci return; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci csr = dma_read32(DMA_CSR); 3298c2ecf20Sopenharmony_ci if (!(csr & DMA_FIFO_ISDRAIN)) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1) 3338c2ecf20Sopenharmony_ci dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci lim = 1000; 3368c2ecf20Sopenharmony_ci while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { 3378c2ecf20Sopenharmony_ci if (--lim == 0) { 3388c2ecf20Sopenharmony_ci printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", 3398c2ecf20Sopenharmony_ci esp->host->unique_id); 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci udelay(1); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic void sbus_esp_dma_invalidate(struct esp *esp) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci if (esp->dmarev == dvmahme) { 3498c2ecf20Sopenharmony_ci dma_write32(DMA_RST_SCSI, DMA_CSR); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | 3528c2ecf20Sopenharmony_ci (DMA_PARITY_OFF | DMA_2CLKS | 3538c2ecf20Sopenharmony_ci DMA_SCSI_DISAB | DMA_INT_ENAB)) & 3548c2ecf20Sopenharmony_ci ~(DMA_ST_WRITE | DMA_ENABLE)); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci dma_write32(0, DMA_CSR); 3578c2ecf20Sopenharmony_ci dma_write32(esp->prev_hme_dmacsr, DMA_CSR); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* This is necessary to avoid having the SCSI channel 3608c2ecf20Sopenharmony_ci * engine lock up on us. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci dma_write32(0, DMA_ADDR); 3638c2ecf20Sopenharmony_ci } else { 3648c2ecf20Sopenharmony_ci u32 val; 3658c2ecf20Sopenharmony_ci int lim; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci lim = 1000; 3688c2ecf20Sopenharmony_ci while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { 3698c2ecf20Sopenharmony_ci if (--lim == 0) { 3708c2ecf20Sopenharmony_ci printk(KERN_ALERT PFX "esp%d: DMA will not " 3718c2ecf20Sopenharmony_ci "invalidate!\n", esp->host->unique_id); 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci udelay(1); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); 3788c2ecf20Sopenharmony_ci val |= DMA_FIFO_INV; 3798c2ecf20Sopenharmony_ci dma_write32(val, DMA_CSR); 3808c2ecf20Sopenharmony_ci val &= ~DMA_FIFO_INV; 3818c2ecf20Sopenharmony_ci dma_write32(val, DMA_CSR); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, 3868c2ecf20Sopenharmony_ci u32 dma_count, int write, u8 cmd) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci u32 csr; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci BUG_ON(!(cmd & ESP_CMD_DMA)); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); 3938c2ecf20Sopenharmony_ci sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); 3948c2ecf20Sopenharmony_ci if (esp->rev == FASHME) { 3958c2ecf20Sopenharmony_ci sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO); 3968c2ecf20Sopenharmony_ci sbus_esp_write8(esp, 0, FAS_RHI); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci scsi_esp_cmd(esp, cmd); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci csr = esp->prev_hme_dmacsr; 4018c2ecf20Sopenharmony_ci csr |= DMA_SCSI_DISAB | DMA_ENABLE; 4028c2ecf20Sopenharmony_ci if (write) 4038c2ecf20Sopenharmony_ci csr |= DMA_ST_WRITE; 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci csr &= ~DMA_ST_WRITE; 4068c2ecf20Sopenharmony_ci esp->prev_hme_dmacsr = csr; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci dma_write32(dma_count, DMA_COUNT); 4098c2ecf20Sopenharmony_ci dma_write32(addr, DMA_ADDR); 4108c2ecf20Sopenharmony_ci dma_write32(csr, DMA_CSR); 4118c2ecf20Sopenharmony_ci } else { 4128c2ecf20Sopenharmony_ci csr = dma_read32(DMA_CSR); 4138c2ecf20Sopenharmony_ci csr |= DMA_ENABLE; 4148c2ecf20Sopenharmony_ci if (write) 4158c2ecf20Sopenharmony_ci csr |= DMA_ST_WRITE; 4168c2ecf20Sopenharmony_ci else 4178c2ecf20Sopenharmony_ci csr &= ~DMA_ST_WRITE; 4188c2ecf20Sopenharmony_ci dma_write32(csr, DMA_CSR); 4198c2ecf20Sopenharmony_ci if (esp->dmarev == dvmaesc1) { 4208c2ecf20Sopenharmony_ci u32 end = PAGE_ALIGN(addr + dma_count + 16U); 4218c2ecf20Sopenharmony_ci dma_write32(end - addr, DMA_COUNT); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci dma_write32(addr, DMA_ADDR); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci scsi_esp_cmd(esp, cmd); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int sbus_esp_dma_error(struct esp *esp) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci u32 csr = dma_read32(DMA_CSR); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (csr & DMA_HNDL_ERROR) 4358c2ecf20Sopenharmony_ci return 1; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic const struct esp_driver_ops sbus_esp_ops = { 4418c2ecf20Sopenharmony_ci .esp_write8 = sbus_esp_write8, 4428c2ecf20Sopenharmony_ci .esp_read8 = sbus_esp_read8, 4438c2ecf20Sopenharmony_ci .irq_pending = sbus_esp_irq_pending, 4448c2ecf20Sopenharmony_ci .reset_dma = sbus_esp_reset_dma, 4458c2ecf20Sopenharmony_ci .dma_drain = sbus_esp_dma_drain, 4468c2ecf20Sopenharmony_ci .dma_invalidate = sbus_esp_dma_invalidate, 4478c2ecf20Sopenharmony_ci .send_dma_cmd = sbus_esp_send_dma_cmd, 4488c2ecf20Sopenharmony_ci .dma_error = sbus_esp_dma_error, 4498c2ecf20Sopenharmony_ci}; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int esp_sbus_probe_one(struct platform_device *op, 4528c2ecf20Sopenharmony_ci struct platform_device *espdma, int hme) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct scsi_host_template *tpnt = &scsi_esp_template; 4558c2ecf20Sopenharmony_ci struct Scsi_Host *host; 4568c2ecf20Sopenharmony_ci struct esp *esp; 4578c2ecf20Sopenharmony_ci int err; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci host = scsi_host_alloc(tpnt, sizeof(struct esp)); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci err = -ENOMEM; 4628c2ecf20Sopenharmony_ci if (!host) 4638c2ecf20Sopenharmony_ci goto fail; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci host->max_id = (hme ? 16 : 8); 4668c2ecf20Sopenharmony_ci esp = shost_priv(host); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci esp->host = host; 4698c2ecf20Sopenharmony_ci esp->dev = &op->dev; 4708c2ecf20Sopenharmony_ci esp->ops = &sbus_esp_ops; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (hme) 4738c2ecf20Sopenharmony_ci esp->flags |= ESP_FLAG_WIDE_CAPABLE; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci err = esp_sbus_setup_dma(esp, espdma); 4768c2ecf20Sopenharmony_ci if (err < 0) 4778c2ecf20Sopenharmony_ci goto fail_unlink; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci err = esp_sbus_map_regs(esp, hme); 4808c2ecf20Sopenharmony_ci if (err < 0) 4818c2ecf20Sopenharmony_ci goto fail_unlink; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci err = esp_sbus_map_command_block(esp); 4848c2ecf20Sopenharmony_ci if (err < 0) 4858c2ecf20Sopenharmony_ci goto fail_unmap_regs; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci err = esp_sbus_register_irq(esp); 4888c2ecf20Sopenharmony_ci if (err < 0) 4898c2ecf20Sopenharmony_ci goto fail_unmap_command_block; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci esp_sbus_get_props(esp, espdma); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Before we try to touch the ESP chip, ESC1 dma can 4948c2ecf20Sopenharmony_ci * come up with the reset bit set, so make sure that 4958c2ecf20Sopenharmony_ci * is clear first. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci if (esp->dmarev == dvmaesc1) { 4988c2ecf20Sopenharmony_ci u32 val = dma_read32(DMA_CSR); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci dev_set_drvdata(&op->dev, esp); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci err = scsi_esp_register(esp); 5068c2ecf20Sopenharmony_ci if (err) 5078c2ecf20Sopenharmony_ci goto fail_free_irq; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cifail_free_irq: 5128c2ecf20Sopenharmony_ci free_irq(host->irq, esp); 5138c2ecf20Sopenharmony_cifail_unmap_command_block: 5148c2ecf20Sopenharmony_ci dma_free_coherent(&op->dev, 16, 5158c2ecf20Sopenharmony_ci esp->command_block, 5168c2ecf20Sopenharmony_ci esp->command_block_dma); 5178c2ecf20Sopenharmony_cifail_unmap_regs: 5188c2ecf20Sopenharmony_ci of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE); 5198c2ecf20Sopenharmony_cifail_unlink: 5208c2ecf20Sopenharmony_ci scsi_host_put(host); 5218c2ecf20Sopenharmony_cifail: 5228c2ecf20Sopenharmony_ci return err; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int esp_sbus_probe(struct platform_device *op) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct device_node *dma_node = NULL; 5288c2ecf20Sopenharmony_ci struct device_node *dp = op->dev.of_node; 5298c2ecf20Sopenharmony_ci struct platform_device *dma_of = NULL; 5308c2ecf20Sopenharmony_ci int hme = 0; 5318c2ecf20Sopenharmony_ci int ret; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (of_node_name_eq(dp->parent, "espdma") || 5348c2ecf20Sopenharmony_ci of_node_name_eq(dp->parent, "dma")) 5358c2ecf20Sopenharmony_ci dma_node = dp->parent; 5368c2ecf20Sopenharmony_ci else if (of_node_name_eq(dp, "SUNW,fas")) { 5378c2ecf20Sopenharmony_ci dma_node = op->dev.of_node; 5388c2ecf20Sopenharmony_ci hme = 1; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci if (dma_node) 5418c2ecf20Sopenharmony_ci dma_of = of_find_device_by_node(dma_node); 5428c2ecf20Sopenharmony_ci if (!dma_of) 5438c2ecf20Sopenharmony_ci return -ENODEV; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci ret = esp_sbus_probe_one(op, dma_of, hme); 5468c2ecf20Sopenharmony_ci if (ret) 5478c2ecf20Sopenharmony_ci put_device(&dma_of->dev); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return ret; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int esp_sbus_remove(struct platform_device *op) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct esp *esp = dev_get_drvdata(&op->dev); 5558c2ecf20Sopenharmony_ci struct platform_device *dma_of = esp->dma; 5568c2ecf20Sopenharmony_ci unsigned int irq = esp->host->irq; 5578c2ecf20Sopenharmony_ci bool is_hme; 5588c2ecf20Sopenharmony_ci u32 val; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci scsi_esp_unregister(esp); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Disable interrupts. */ 5638c2ecf20Sopenharmony_ci val = dma_read32(DMA_CSR); 5648c2ecf20Sopenharmony_ci dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci free_irq(irq, esp); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci is_hme = (esp->dmarev == dvmahme); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci dma_free_coherent(&op->dev, 16, 5718c2ecf20Sopenharmony_ci esp->command_block, 5728c2ecf20Sopenharmony_ci esp->command_block_dma); 5738c2ecf20Sopenharmony_ci of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs, 5748c2ecf20Sopenharmony_ci SBUS_ESP_REG_SIZE); 5758c2ecf20Sopenharmony_ci of_iounmap(&dma_of->resource[0], esp->dma_regs, 5768c2ecf20Sopenharmony_ci resource_size(&dma_of->resource[0])); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci scsi_host_put(esp->host); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci dev_set_drvdata(&op->dev, NULL); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci put_device(&dma_of->dev); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic const struct of_device_id esp_match[] = { 5888c2ecf20Sopenharmony_ci { 5898c2ecf20Sopenharmony_ci .name = "SUNW,esp", 5908c2ecf20Sopenharmony_ci }, 5918c2ecf20Sopenharmony_ci { 5928c2ecf20Sopenharmony_ci .name = "SUNW,fas", 5938c2ecf20Sopenharmony_ci }, 5948c2ecf20Sopenharmony_ci { 5958c2ecf20Sopenharmony_ci .name = "esp", 5968c2ecf20Sopenharmony_ci }, 5978c2ecf20Sopenharmony_ci {}, 5988c2ecf20Sopenharmony_ci}; 5998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, esp_match); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic struct platform_driver esp_sbus_driver = { 6028c2ecf20Sopenharmony_ci .driver = { 6038c2ecf20Sopenharmony_ci .name = "esp", 6048c2ecf20Sopenharmony_ci .of_match_table = esp_match, 6058c2ecf20Sopenharmony_ci }, 6068c2ecf20Sopenharmony_ci .probe = esp_sbus_probe, 6078c2ecf20Sopenharmony_ci .remove = esp_sbus_remove, 6088c2ecf20Sopenharmony_ci}; 6098c2ecf20Sopenharmony_cimodule_platform_driver(esp_sbus_driver); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sun ESP SCSI driver"); 6128c2ecf20Sopenharmony_ciMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 6138c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6148c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 615