Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* sun3x_esp.c: ESP front-end for Sun3x systems.
0003  *
0004  * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/gfp.h>
0009 #include <linux/types.h>
0010 #include <linux/delay.h>
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/dma-mapping.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/io.h>
0017 
0018 #include <asm/sun3x.h>
0019 #include <asm/dma.h>
0020 #include <asm/dvma.h>
0021 
0022 /* DMA controller reg offsets */
0023 #define DMA_CSR     0x00UL  /* rw  DMA control/status register    0x00   */
0024 #define DMA_ADDR        0x04UL  /* rw  DMA transfer address register  0x04   */
0025 #define DMA_COUNT       0x08UL  /* rw  DMA transfer count register    0x08   */
0026 #define DMA_TEST        0x0cUL  /* rw  DMA test/debug register        0x0c   */
0027 
0028 #include <scsi/scsi_host.h>
0029 
0030 #include "esp_scsi.h"
0031 
0032 #define DRV_MODULE_NAME     "sun3x_esp"
0033 #define PFX DRV_MODULE_NAME ": "
0034 #define DRV_VERSION     "1.000"
0035 #define DRV_MODULE_RELDATE  "Nov 1, 2007"
0036 
0037 /*
0038  * m68k always assumes readl/writel operate on little endian
0039  * mmio space; this is wrong at least for Sun3x, so we
0040  * need to workaround this until a proper way is found
0041  */
0042 #if 0
0043 #define dma_read32(REG) \
0044     readl(esp->dma_regs + (REG))
0045 #define dma_write32(VAL, REG) \
0046     writel((VAL), esp->dma_regs + (REG))
0047 #else
0048 #define dma_read32(REG) \
0049     *(volatile u32 *)(esp->dma_regs + (REG))
0050 #define dma_write32(VAL, REG) \
0051     do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0)
0052 #endif
0053 
0054 static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg)
0055 {
0056     writeb(val, esp->regs + (reg * 4UL));
0057 }
0058 
0059 static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg)
0060 {
0061     return readb(esp->regs + (reg * 4UL));
0062 }
0063 
0064 static int sun3x_esp_irq_pending(struct esp *esp)
0065 {
0066     if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
0067         return 1;
0068     return 0;
0069 }
0070 
0071 static void sun3x_esp_reset_dma(struct esp *esp)
0072 {
0073     u32 val;
0074 
0075     val = dma_read32(DMA_CSR);
0076     dma_write32(val | DMA_RST_SCSI, DMA_CSR);
0077     dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
0078 
0079     /* Enable interrupts.  */
0080     val = dma_read32(DMA_CSR);
0081     dma_write32(val | DMA_INT_ENAB, DMA_CSR);
0082 }
0083 
0084 static void sun3x_esp_dma_drain(struct esp *esp)
0085 {
0086     u32 csr;
0087     int lim;
0088 
0089     csr = dma_read32(DMA_CSR);
0090     if (!(csr & DMA_FIFO_ISDRAIN))
0091         return;
0092 
0093     dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
0094 
0095     lim = 1000;
0096     while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
0097         if (--lim == 0) {
0098             printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
0099                    esp->host->unique_id);
0100             break;
0101         }
0102         udelay(1);
0103     }
0104 }
0105 
0106 static void sun3x_esp_dma_invalidate(struct esp *esp)
0107 {
0108     u32 val;
0109     int lim;
0110 
0111     lim = 1000;
0112     while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
0113         if (--lim == 0) {
0114             printk(KERN_ALERT PFX "esp%d: DMA will not "
0115                    "invalidate!\n", esp->host->unique_id);
0116             break;
0117         }
0118         udelay(1);
0119     }
0120 
0121     val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
0122     val |= DMA_FIFO_INV;
0123     dma_write32(val, DMA_CSR);
0124     val &= ~DMA_FIFO_INV;
0125     dma_write32(val, DMA_CSR);
0126 }
0127 
0128 static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
0129                   u32 dma_count, int write, u8 cmd)
0130 {
0131     u32 csr;
0132 
0133     BUG_ON(!(cmd & ESP_CMD_DMA));
0134 
0135     sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
0136     sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
0137     csr = dma_read32(DMA_CSR);
0138     csr |= DMA_ENABLE;
0139     if (write)
0140         csr |= DMA_ST_WRITE;
0141     else
0142         csr &= ~DMA_ST_WRITE;
0143     dma_write32(csr, DMA_CSR);
0144     dma_write32(addr, DMA_ADDR);
0145 
0146     scsi_esp_cmd(esp, cmd);
0147 }
0148 
0149 static int sun3x_esp_dma_error(struct esp *esp)
0150 {
0151     u32 csr = dma_read32(DMA_CSR);
0152 
0153     if (csr & DMA_HNDL_ERROR)
0154         return 1;
0155 
0156     return 0;
0157 }
0158 
0159 static const struct esp_driver_ops sun3x_esp_ops = {
0160     .esp_write8 =   sun3x_esp_write8,
0161     .esp_read8  =   sun3x_esp_read8,
0162     .irq_pending    =   sun3x_esp_irq_pending,
0163     .reset_dma  =   sun3x_esp_reset_dma,
0164     .dma_drain  =   sun3x_esp_dma_drain,
0165     .dma_invalidate =   sun3x_esp_dma_invalidate,
0166     .send_dma_cmd   =   sun3x_esp_send_dma_cmd,
0167     .dma_error  =   sun3x_esp_dma_error,
0168 };
0169 
0170 static int esp_sun3x_probe(struct platform_device *dev)
0171 {
0172     struct scsi_host_template *tpnt = &scsi_esp_template;
0173     struct Scsi_Host *host;
0174     struct esp *esp;
0175     struct resource *res;
0176     int err = -ENOMEM;
0177 
0178     host = scsi_host_alloc(tpnt, sizeof(struct esp));
0179     if (!host)
0180         goto fail;
0181 
0182     host->max_id = 8;
0183     esp = shost_priv(host);
0184 
0185     esp->host = host;
0186     esp->dev = &dev->dev;
0187     esp->ops = &sun3x_esp_ops;
0188 
0189     res = platform_get_resource(dev, IORESOURCE_MEM, 0);
0190     if (!res || !res->start)
0191         goto fail_unlink;
0192 
0193     esp->regs = ioremap(res->start, 0x20);
0194     if (!esp->regs)
0195         goto fail_unmap_regs;
0196 
0197     res = platform_get_resource(dev, IORESOURCE_MEM, 1);
0198     if (!res || !res->start)
0199         goto fail_unmap_regs;
0200 
0201     esp->dma_regs = ioremap(res->start, 0x10);
0202 
0203     esp->command_block = dma_alloc_coherent(esp->dev, 16,
0204                         &esp->command_block_dma,
0205                         GFP_KERNEL);
0206     if (!esp->command_block)
0207         goto fail_unmap_regs_dma;
0208 
0209     host->irq = err = platform_get_irq(dev, 0);
0210     if (err < 0)
0211         goto fail_unmap_command_block;
0212     err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
0213               "SUN3X ESP", esp);
0214     if (err < 0)
0215         goto fail_unmap_command_block;
0216 
0217     esp->scsi_id = 7;
0218     esp->host->this_id = esp->scsi_id;
0219     esp->scsi_id_mask = (1 << esp->scsi_id);
0220     esp->cfreq = 20000000;
0221 
0222     dev_set_drvdata(&dev->dev, esp);
0223 
0224     err = scsi_esp_register(esp);
0225     if (err)
0226         goto fail_free_irq;
0227 
0228     return 0;
0229 
0230 fail_free_irq:
0231     free_irq(host->irq, esp);
0232 fail_unmap_command_block:
0233     dma_free_coherent(esp->dev, 16,
0234               esp->command_block,
0235               esp->command_block_dma);
0236 fail_unmap_regs_dma:
0237     iounmap(esp->dma_regs);
0238 fail_unmap_regs:
0239     iounmap(esp->regs);
0240 fail_unlink:
0241     scsi_host_put(host);
0242 fail:
0243     return err;
0244 }
0245 
0246 static int esp_sun3x_remove(struct platform_device *dev)
0247 {
0248     struct esp *esp = dev_get_drvdata(&dev->dev);
0249     unsigned int irq = esp->host->irq;
0250     u32 val;
0251 
0252     scsi_esp_unregister(esp);
0253 
0254     /* Disable interrupts.  */
0255     val = dma_read32(DMA_CSR);
0256     dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
0257 
0258     free_irq(irq, esp);
0259     dma_free_coherent(esp->dev, 16,
0260               esp->command_block,
0261               esp->command_block_dma);
0262 
0263     scsi_host_put(esp->host);
0264 
0265     return 0;
0266 }
0267 
0268 static struct platform_driver esp_sun3x_driver = {
0269     .probe          = esp_sun3x_probe,
0270     .remove         = esp_sun3x_remove,
0271     .driver = {
0272         .name   = "sun3x_esp",
0273     },
0274 };
0275 module_platform_driver(esp_sun3x_driver);
0276 
0277 MODULE_DESCRIPTION("Sun3x ESP SCSI driver");
0278 MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)");
0279 MODULE_LICENSE("GPL");
0280 MODULE_VERSION(DRV_VERSION);
0281 MODULE_ALIAS("platform:sun3x_esp");