linux/drivers/ata/pata_buddha.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Buddha, Catweasel and X-Surf PATA controller driver
   5 *
   6 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
   7 *              http://www.samsung.com
   8 *
   9 * Based on buddha.c:
  10 *
  11 *      Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
  12 */
  13
  14#include <linux/ata.h>
  15#include <linux/blkdev.h>
  16#include <linux/delay.h>
  17#include <linux/interrupt.h>
  18#include <linux/kernel.h>
  19#include <linux/libata.h>
  20#include <linux/mm.h>
  21#include <linux/module.h>
  22#include <linux/zorro.h>
  23#include <scsi/scsi_cmnd.h>
  24#include <scsi/scsi_host.h>
  25
  26#include <asm/amigahw.h>
  27#include <asm/amigaints.h>
  28#include <asm/ide.h>
  29#include <asm/setup.h>
  30
  31#define DRV_NAME "pata_buddha"
  32#define DRV_VERSION "0.1.0"
  33
  34#define BUDDHA_BASE1    0x800
  35#define BUDDHA_BASE2    0xa00
  36#define BUDDHA_BASE3    0xc00
  37#define XSURF_BASE1     0xb000 /* 2.5" interface */
  38#define XSURF_BASE2     0xd000 /* 3.5" interface */
  39#define BUDDHA_CONTROL  0x11a
  40#define BUDDHA_IRQ      0xf00
  41#define XSURF_IRQ       0x7e
  42#define BUDDHA_IRQ_MR   0xfc0   /* master interrupt enable */
  43
  44enum {
  45        BOARD_BUDDHA = 0,
  46        BOARD_CATWEASEL,
  47        BOARD_XSURF
  48};
  49
  50static unsigned int buddha_bases[3] __initdata = {
  51        BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
  52};
  53
  54static unsigned int xsurf_bases[2] __initdata = {
  55        XSURF_BASE1, XSURF_BASE2
  56};
  57
  58static struct scsi_host_template pata_buddha_sht = {
  59        ATA_PIO_SHT(DRV_NAME),
  60};
  61
  62/* FIXME: is this needed? */
  63static unsigned int pata_buddha_data_xfer(struct ata_queued_cmd *qc,
  64                                         unsigned char *buf,
  65                                         unsigned int buflen, int rw)
  66{
  67        struct ata_device *dev = qc->dev;
  68        struct ata_port *ap = dev->link->ap;
  69        void __iomem *data_addr = ap->ioaddr.data_addr;
  70        unsigned int words = buflen >> 1;
  71
  72        /* Transfer multiple of 2 bytes */
  73        if (rw == READ)
  74                raw_insw((u16 *)data_addr, (u16 *)buf, words);
  75        else
  76                raw_outsw((u16 *)data_addr, (u16 *)buf, words);
  77
  78        /* Transfer trailing byte, if any. */
  79        if (unlikely(buflen & 0x01)) {
  80                unsigned char pad[2] = { };
  81
  82                /* Point buf to the tail of buffer */
  83                buf += buflen - 1;
  84
  85                if (rw == READ) {
  86                        raw_insw((u16 *)data_addr, (u16 *)pad, 1);
  87                        *buf = pad[0];
  88                } else {
  89                        pad[0] = *buf;
  90                        raw_outsw((u16 *)data_addr, (u16 *)pad, 1);
  91                }
  92                words++;
  93        }
  94
  95        return words << 1;
  96}
  97
  98/*
  99 * Provide our own set_mode() as we don't want to change anything that has
 100 * already been configured..
 101 */
 102static int pata_buddha_set_mode(struct ata_link *link,
 103                                struct ata_device **unused)
 104{
 105        struct ata_device *dev;
 106
 107        ata_for_each_dev(dev, link, ENABLED) {
 108                /* We don't really care */
 109                dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
 110                dev->xfer_shift = ATA_SHIFT_PIO;
 111                dev->flags |= ATA_DFLAG_PIO;
 112                ata_dev_info(dev, "configured for PIO\n");
 113        }
 114        return 0;
 115}
 116
 117static bool pata_buddha_irq_check(struct ata_port *ap)
 118{
 119        u8 ch;
 120
 121        ch = z_readb((unsigned long)ap->private_data);
 122
 123        return !!(ch & 0x80);
 124}
 125
 126static void pata_xsurf_irq_clear(struct ata_port *ap)
 127{
 128        z_writeb(0, (unsigned long)ap->private_data);
 129}
 130
 131static struct ata_port_operations pata_buddha_ops = {
 132        .inherits       = &ata_sff_port_ops,
 133        .sff_data_xfer  = pata_buddha_data_xfer,
 134        .sff_irq_check  = pata_buddha_irq_check,
 135        .cable_detect   = ata_cable_unknown,
 136        .set_mode       = pata_buddha_set_mode,
 137};
 138
 139static struct ata_port_operations pata_xsurf_ops = {
 140        .inherits       = &ata_sff_port_ops,
 141        .sff_data_xfer  = pata_buddha_data_xfer,
 142        .sff_irq_check  = pata_buddha_irq_check,
 143        .sff_irq_clear  = pata_xsurf_irq_clear,
 144        .cable_detect   = ata_cable_unknown,
 145        .set_mode       = pata_buddha_set_mode,
 146};
 147
 148static int __init pata_buddha_init_one(void)
 149{
 150        struct zorro_dev *z = NULL;
 151
 152        while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
 153                static const char *board_name[]
 154                        = { "Buddha", "Catweasel", "X-Surf" };
 155                struct ata_host *host;
 156                void __iomem *buddha_board;
 157                unsigned long board;
 158                unsigned int type, nr_ports = 2;
 159                int i;
 160
 161                if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
 162                        type = BOARD_BUDDHA;
 163                } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
 164                        type = BOARD_CATWEASEL;
 165                        nr_ports++;
 166                } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
 167                        type = BOARD_XSURF;
 168                } else
 169                        continue;
 170
 171                dev_info(&z->dev, "%s IDE controller\n", board_name[type]);
 172
 173                board = z->resource.start;
 174
 175                if (type != BOARD_XSURF) {
 176                        if (!devm_request_mem_region(&z->dev,
 177                                                     board + BUDDHA_BASE1,
 178                                                     0x800, DRV_NAME))
 179                                continue;
 180                } else {
 181                        if (!devm_request_mem_region(&z->dev,
 182                                                     board + XSURF_BASE1,
 183                                                     0x1000, DRV_NAME))
 184                                continue;
 185                        if (!devm_request_mem_region(&z->dev,
 186                                                     board + XSURF_BASE2,
 187                                                     0x1000, DRV_NAME))
 188                                continue;
 189                }
 190
 191                /* allocate host */
 192                host = ata_host_alloc(&z->dev, nr_ports);
 193                if (!host)
 194                        continue;
 195
 196                buddha_board = ZTWO_VADDR(board);
 197
 198                /* enable the board IRQ on Buddha/Catweasel */
 199                if (type != BOARD_XSURF)
 200                        z_writeb(0, buddha_board + BUDDHA_IRQ_MR);
 201
 202                for (i = 0; i < nr_ports; i++) {
 203                        struct ata_port *ap = host->ports[i];
 204                        void __iomem *base, *irqport;
 205                        unsigned long ctl = 0;
 206
 207                        if (type != BOARD_XSURF) {
 208                                ap->ops = &pata_buddha_ops;
 209                                base = buddha_board + buddha_bases[i];
 210                                ctl = BUDDHA_CONTROL;
 211                                irqport = buddha_board + BUDDHA_IRQ + i * 0x40;
 212                        } else {
 213                                ap->ops = &pata_xsurf_ops;
 214                                base = buddha_board + xsurf_bases[i];
 215                                /* X-Surf has no CS1* (Control/AltStat) */
 216                                irqport = buddha_board + XSURF_IRQ;
 217                        }
 218
 219                        ap->pio_mask = ATA_PIO4;
 220                        ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
 221
 222                        ap->ioaddr.data_addr            = base;
 223                        ap->ioaddr.error_addr           = base + 2 + 1 * 4;
 224                        ap->ioaddr.feature_addr         = base + 2 + 1 * 4;
 225                        ap->ioaddr.nsect_addr           = base + 2 + 2 * 4;
 226                        ap->ioaddr.lbal_addr            = base + 2 + 3 * 4;
 227                        ap->ioaddr.lbam_addr            = base + 2 + 4 * 4;
 228                        ap->ioaddr.lbah_addr            = base + 2 + 5 * 4;
 229                        ap->ioaddr.device_addr          = base + 2 + 6 * 4;
 230                        ap->ioaddr.status_addr          = base + 2 + 7 * 4;
 231                        ap->ioaddr.command_addr         = base + 2 + 7 * 4;
 232
 233                        if (ctl) {
 234                                ap->ioaddr.altstatus_addr = base + ctl;
 235                                ap->ioaddr.ctl_addr       = base + ctl;
 236                        }
 237
 238                        ap->private_data = (void *)irqport;
 239
 240                        ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", board,
 241                                      ctl ? board + buddha_bases[i] + ctl : 0);
 242                }
 243
 244                ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt,
 245                                  IRQF_SHARED, &pata_buddha_sht);
 246
 247        }
 248
 249        return 0;
 250}
 251
 252module_init(pata_buddha_init_one);
 253
 254MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
 255MODULE_DESCRIPTION("low-level driver for Buddha/Catweasel/X-Surf PATA");
 256MODULE_LICENSE("GPL v2");
 257MODULE_VERSION(DRV_VERSION);
 258