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