210 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* jazz_esp.c: ESP front-end for MIPS JAZZ systems.3 *4 * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)5 */6 7#include <linux/kernel.h>8#include <linux/gfp.h>9#include <linux/types.h>10#include <linux/module.h>11#include <linux/init.h>12#include <linux/interrupt.h>13#include <linux/platform_device.h>14#include <linux/dma-mapping.h>15 16#include <asm/irq.h>17#include <asm/io.h>18#include <asm/dma.h>19 20#include <asm/jazz.h>21#include <asm/jazzdma.h>22 23#include <scsi/scsi_host.h>24 25#include "esp_scsi.h"26 27#define DRV_MODULE_NAME "jazz_esp"28#define PFX DRV_MODULE_NAME ": "29#define DRV_VERSION "1.000"30#define DRV_MODULE_RELDATE "May 19, 2007"31 32static void jazz_esp_write8(struct esp *esp, u8 val, unsigned long reg)33{34 *(volatile u8 *)(esp->regs + reg) = val;35}36 37static u8 jazz_esp_read8(struct esp *esp, unsigned long reg)38{39 return *(volatile u8 *)(esp->regs + reg);40}41 42static int jazz_esp_irq_pending(struct esp *esp)43{44 if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR)45 return 1;46 return 0;47}48 49static void jazz_esp_reset_dma(struct esp *esp)50{51 vdma_disable ((int)esp->dma_regs);52}53 54static void jazz_esp_dma_drain(struct esp *esp)55{56 /* nothing to do */57}58 59static void jazz_esp_dma_invalidate(struct esp *esp)60{61 vdma_disable ((int)esp->dma_regs);62}63 64static void jazz_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,65 u32 dma_count, int write, u8 cmd)66{67 BUG_ON(!(cmd & ESP_CMD_DMA));68 69 jazz_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);70 jazz_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);71 vdma_disable ((int)esp->dma_regs);72 if (write)73 vdma_set_mode ((int)esp->dma_regs, DMA_MODE_READ);74 else75 vdma_set_mode ((int)esp->dma_regs, DMA_MODE_WRITE);76 77 vdma_set_addr ((int)esp->dma_regs, addr);78 vdma_set_count ((int)esp->dma_regs, dma_count);79 vdma_enable ((int)esp->dma_regs);80 81 scsi_esp_cmd(esp, cmd);82}83 84static int jazz_esp_dma_error(struct esp *esp)85{86 u32 enable = vdma_get_enable((int)esp->dma_regs);87 88 if (enable & (R4030_MEM_INTR|R4030_ADDR_INTR))89 return 1;90 91 return 0;92}93 94static const struct esp_driver_ops jazz_esp_ops = {95 .esp_write8 = jazz_esp_write8,96 .esp_read8 = jazz_esp_read8,97 .irq_pending = jazz_esp_irq_pending,98 .reset_dma = jazz_esp_reset_dma,99 .dma_drain = jazz_esp_dma_drain,100 .dma_invalidate = jazz_esp_dma_invalidate,101 .send_dma_cmd = jazz_esp_send_dma_cmd,102 .dma_error = jazz_esp_dma_error,103};104 105static int esp_jazz_probe(struct platform_device *dev)106{107 const struct scsi_host_template *tpnt = &scsi_esp_template;108 struct Scsi_Host *host;109 struct esp *esp;110 struct resource *res;111 int err;112 113 host = scsi_host_alloc(tpnt, sizeof(struct esp));114 115 err = -ENOMEM;116 if (!host)117 goto fail;118 119 host->max_id = 8;120 esp = shost_priv(host);121 122 esp->host = host;123 esp->dev = &dev->dev;124 esp->ops = &jazz_esp_ops;125 126 res = platform_get_resource(dev, IORESOURCE_MEM, 0);127 if (!res)128 goto fail_unlink;129 130 esp->regs = (void __iomem *)res->start;131 if (!esp->regs)132 goto fail_unlink;133 134 res = platform_get_resource(dev, IORESOURCE_MEM, 1);135 if (!res)136 goto fail_unlink;137 138 esp->dma_regs = (void __iomem *)res->start;139 140 esp->command_block = dma_alloc_coherent(esp->dev, 16,141 &esp->command_block_dma,142 GFP_KERNEL);143 if (!esp->command_block)144 goto fail_unmap_regs;145 146 host->irq = err = platform_get_irq(dev, 0);147 if (err < 0)148 goto fail_unmap_command_block;149 err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);150 if (err < 0)151 goto fail_unmap_command_block;152 153 esp->scsi_id = 7;154 esp->host->this_id = esp->scsi_id;155 esp->scsi_id_mask = (1 << esp->scsi_id);156 esp->cfreq = 40000000;157 158 dev_set_drvdata(&dev->dev, esp);159 160 err = scsi_esp_register(esp);161 if (err)162 goto fail_free_irq;163 164 return 0;165 166fail_free_irq:167 free_irq(host->irq, esp);168fail_unmap_command_block:169 dma_free_coherent(esp->dev, 16,170 esp->command_block,171 esp->command_block_dma);172fail_unmap_regs:173fail_unlink:174 scsi_host_put(host);175fail:176 return err;177}178 179static void esp_jazz_remove(struct platform_device *dev)180{181 struct esp *esp = dev_get_drvdata(&dev->dev);182 unsigned int irq = esp->host->irq;183 184 scsi_esp_unregister(esp);185 186 free_irq(irq, esp);187 dma_free_coherent(esp->dev, 16,188 esp->command_block,189 esp->command_block_dma);190 191 scsi_host_put(esp->host);192}193 194/* work with hotplug and coldplug */195MODULE_ALIAS("platform:jazz_esp");196 197static struct platform_driver esp_jazz_driver = {198 .probe = esp_jazz_probe,199 .remove_new = esp_jazz_remove,200 .driver = {201 .name = "jazz_esp",202 },203};204module_platform_driver(esp_jazz_driver);205 206MODULE_DESCRIPTION("JAZZ ESP SCSI driver");207MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");208MODULE_LICENSE("GPL");209MODULE_VERSION(DRV_VERSION);210