1203130Simp/***********************license start*************** 2203130Simp * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights 3203130Simp * reserved. 4203130Simp * 5203130Simp * 6203130Simp * Redistribution and use in source and binary forms, with or without 7203130Simp * modification, are permitted provided that the following conditions are 8203130Simp * met: 9203130Simp * 10203130Simp * * Redistributions of source code must retain the above copyright 11203130Simp * notice, this list of conditions and the following disclaimer. 12203130Simp * 13203130Simp * * Redistributions in binary form must reproduce the above 14203130Simp * copyright notice, this list of conditions and the following 15203130Simp * disclaimer in the documentation and/or other materials provided 16203130Simp * with the distribution. 17203130Simp * 18203130Simp * * Neither the name of Cavium Networks nor the names of 19203130Simp * its contributors may be used to endorse or promote products 20203130Simp * derived from this software without specific prior written 21203130Simp * permission. 22203130Simp * 23203130Simp * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24203130Simp * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25203130Simp * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26203130Simp * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27203130Simp * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28203130Simp * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29203130Simp * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30203130Simp * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31203130Simp * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32203130Simp * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33203130Simp * 34203130Simp * 35203130Simp * For any questions regarding licensing please contact marketing@caviumnetworks.com 36203130Simp * 37203130Simp ***********************license end**************************************/ 38203130Simp 39194149Simp/* 40194149Simp * octeon_ebt3000_cf.c 41194149Simp * 42194149Simp */ 43194149Simp 44194149Simp#include <sys/cdefs.h> 45194149Simp__FBSDID("$FreeBSD: releng/10.3/sys/mips/cavium/octeon_ebt3000_cf.c 265999 2014-05-14 01:35:43Z ian $"); 46194149Simp 47194149Simp#include <sys/param.h> 48194149Simp#include <sys/bio.h> 49194149Simp#include <sys/systm.h> 50194149Simp#include <sys/sysctl.h> 51210311Sjmallett#include <sys/ata.h> 52194149Simp#include <sys/bus.h> 53194149Simp#include <sys/kernel.h> 54194149Simp#include <sys/module.h> 55194149Simp#include <sys/rman.h> 56194149Simp#include <sys/power.h> 57194149Simp#include <sys/smp.h> 58194149Simp#include <sys/time.h> 59194149Simp#include <sys/timetc.h> 60194149Simp#include <sys/malloc.h> 61194149Simp 62194149Simp#include <geom/geom.h> 63194149Simp 64194149Simp#include <machine/clock.h> 65194149Simp#include <machine/locore.h> 66194149Simp#include <machine/md_var.h> 67194149Simp#include <machine/cpuregs.h> 68194149Simp 69202063Simp#include <mips/cavium/octeon_pcmap_regs.h> 70194149Simp 71210311Sjmallett#include <contrib/octeon-sdk/cvmx.h> 72210311Sjmallett 73194149Simp/* ATA Commands */ 74194149Simp#define CMD_READ_SECTOR 0x20 75194149Simp#define CMD_WRITE_SECTOR 0x30 76194149Simp#define CMD_IDENTIFY 0xEC 77194149Simp 78194149Simp/* The ATA Task File */ 79194149Simp#define TF_DATA 0x00 80194149Simp#define TF_ERROR 0x01 81194149Simp#define TF_PRECOMP 0x01 82194149Simp#define TF_SECTOR_COUNT 0x02 83194149Simp#define TF_SECTOR_NUMBER 0x03 84194149Simp#define TF_CYL_LSB 0x04 85194149Simp#define TF_CYL_MSB 0x05 86194149Simp#define TF_DRV_HEAD 0x06 87194149Simp#define TF_STATUS 0x07 88194149Simp#define TF_COMMAND 0x07 89194149Simp 90194149Simp/* Status Register */ 91194149Simp#define STATUS_BSY 0x80 /* Drive is busy */ 92194149Simp#define STATUS_RDY 0x40 /* Drive is ready */ 93204789Sjmallett#define STATUS_DF 0x20 /* Device fault */ 94194149Simp#define STATUS_DRQ 0x08 /* Data can be transferred */ 95194149Simp 96194149Simp/* Miscelaneous */ 97194149Simp#define SECTOR_SIZE 512 98194149Simp#define WAIT_DELAY 1000 99194149Simp#define NR_TRIES 1000 100194149Simp#define SWAP_SHORT(x) ((x << 8) | (x >> 8)) 101194149Simp#define MODEL_STR_SIZE 40 102194149Simp 103194149Simp/* Globals */ 104222671Simp/* 105222671Simp * There's three bus types supported by this driver. 106222671Simp * 107222671Simp * CF_8 -- Traditional PC Card IDE interface on an 8-bit wide bus. We assume 108222671Simp * the bool loader has configure attribute memory properly. We then access 109222671Simp * the device like old-school 8-bit IDE card (which is all a traditional PC Card 110222671Simp * interface really is). 111222671Simp * CF_16 -- Traditional PC Card IDE interface on a 16-bit wide bus. Registers on 112222671Simp * this bus are 16-bits wide too. When accessing registers in the task file, you 113222671Simp * have to do it in 16-bit chunks, and worry about masking out what you don't want 114222671Simp * or ORing together the traditional 8-bit values. We assume the bootloader does 115222671Simp * the right attribute memory initialization dance. 116222671Simp * CF_TRUE_IDE_8 - CF Card wired to True IDE mode. There's no Attribute memory 117222671Simp * space at all. Instead all the traditional 8-bit registers are there, but 118222671Simp * on a 16-bit bus where addr0 isn't wired. This means we need to read/write them 119222671Simp * 16-bit chunks, but only the lower 8 bits are valid. We do not (and can not) 120222671Simp * access this like CF_16 with the comingled registers. Yet we can't access 121222671Simp * this like CF_8 because of the register offset. Except the TF_DATA register 122222671Simp * appears to be full width? 123222671Simp */ 124194149Simpvoid *base_addr; 125222671Simpint bus_type; 126222671Simp#define CF_8 1 /* 8-bit bus, no offsets - PC Card */ 127222671Simp#define CF_16 2 /* 16-bit bus, registers shared - PC Card */ 128222671Simp#define CF_TRUE_IDE_8 3 /* 16-bit bus, only lower 8-bits, TrueIDE */ 129222671Simpconst char *const cf_type[] = { 130222671Simp "impossible type", 131222671Simp "CF 8-bit", 132222671Simp "CF 16-bit", 133222671Simp "True IDE" 134222671Simp}; 135194149Simp 136194149Simp/* Device parameters */ 137194149Simpstruct drive_param{ 138194149Simp union { 139194149Simp char buf[SECTOR_SIZE]; 140210311Sjmallett struct ata_params driveid; 141194149Simp } u; 142194149Simp 143194149Simp char model[MODEL_STR_SIZE]; 144194149Simp uint32_t nr_sectors; 145194149Simp uint16_t sector_size; 146194149Simp uint16_t heads; 147194149Simp uint16_t tracks; 148194149Simp uint16_t sec_track; 149233278Sjmallett}; 150194149Simp 151233278Sjmallett/* Device softc */ 152233278Sjmallettstruct cf_priv { 153233278Sjmallett device_t dev; 154233278Sjmallett struct drive_param drive_param; 155194149Simp 156233278Sjmallett struct bio_queue_head cf_bq; 157233278Sjmallett struct g_geom *cf_geom; 158233278Sjmallett struct g_provider *cf_provider; 159233278Sjmallett 160233278Sjmallett}; 161233278Sjmallett 162194149Simp/* GEOM class implementation */ 163194149Simpstatic g_access_t cf_access; 164194149Simpstatic g_start_t cf_start; 165194149Simpstatic g_ioctl_t cf_ioctl; 166194149Simp 167194149Simpstruct g_class g_cf_class = { 168194149Simp .name = "CF", 169194149Simp .version = G_VERSION, 170194149Simp .start = cf_start, 171194149Simp .access = cf_access, 172194149Simp .ioctl = cf_ioctl, 173194149Simp}; 174194149Simp 175214708SjmallettDECLARE_GEOM_CLASS(g_cf_class, g_cf); 176214708Sjmallett 177194149Simp/* Device methods */ 178194149Simpstatic int cf_probe(device_t); 179194149Simpstatic void cf_identify(driver_t *, device_t); 180194149Simpstatic int cf_attach(device_t); 181233278Sjmallettstatic void cf_attach_geom(void *, int); 182194149Simp 183194149Simp/* ATA methods */ 184233278Sjmallettstatic int cf_cmd_identify(struct cf_priv *); 185204789Sjmallettstatic int cf_cmd_write(uint32_t, uint32_t, void *); 186204789Sjmallettstatic int cf_cmd_read(uint32_t, uint32_t, void *); 187204789Sjmallettstatic int cf_wait_busy(void); 188204789Sjmallettstatic int cf_send_cmd(uint32_t, uint8_t); 189194149Simp 190194149Simp/* Miscelenous */ 191194149Simpstatic void cf_swap_ascii(unsigned char[], char[]); 192194149Simp 193194149Simp 194194149Simp/* ------------------------------------------------------------------- * 195194149Simp * cf_access() * 196194149Simp * ------------------------------------------------------------------- */ 197194149Simpstatic int cf_access (struct g_provider *pp, int r, int w, int e) 198194149Simp{ 199194149Simp return (0); 200194149Simp} 201194149Simp 202194149Simp 203194149Simp/* ------------------------------------------------------------------- * 204194149Simp * cf_start() * 205194149Simp * ------------------------------------------------------------------- */ 206194149Simpstatic void cf_start (struct bio *bp) 207194149Simp{ 208233278Sjmallett struct cf_priv *cf_priv; 209204789Sjmallett int error; 210204789Sjmallett 211233278Sjmallett cf_priv = bp->bio_to->geom->softc; 212233278Sjmallett 213194149Simp /* 214194149Simp * Handle actual I/O requests. The request is passed down through 215194149Simp * the bio struct. 216194149Simp */ 217194149Simp 218194149Simp if(bp->bio_cmd & BIO_GETATTR) { 219233278Sjmallett if (g_handleattr_int(bp, "GEOM::fwsectors", cf_priv->drive_param.sec_track)) 220194149Simp return; 221233278Sjmallett if (g_handleattr_int(bp, "GEOM::fwheads", cf_priv->drive_param.heads)) 222194149Simp return; 223194149Simp g_io_deliver(bp, ENOIOCTL); 224194149Simp return; 225194149Simp } 226194149Simp 227194149Simp if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { 228194149Simp 229194149Simp if (bp->bio_cmd & BIO_READ) { 230233278Sjmallett error = cf_cmd_read(bp->bio_length / cf_priv->drive_param.sector_size, 231233278Sjmallett bp->bio_offset / cf_priv->drive_param.sector_size, bp->bio_data); 232194149Simp } else if (bp->bio_cmd & BIO_WRITE) { 233233278Sjmallett error = cf_cmd_write(bp->bio_length / cf_priv->drive_param.sector_size, 234233278Sjmallett bp->bio_offset/cf_priv->drive_param.sector_size, bp->bio_data); 235204789Sjmallett } else { 236204789Sjmallett printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd); 237204789Sjmallett error = ENOTSUP; 238194149Simp } 239194149Simp 240204789Sjmallett if (error != 0) { 241204789Sjmallett g_io_deliver(bp, error); 242204789Sjmallett return; 243204789Sjmallett } 244204789Sjmallett 245194149Simp bp->bio_resid = 0; 246194149Simp bp->bio_completed = bp->bio_length; 247194149Simp g_io_deliver(bp, 0); 248194149Simp } 249194149Simp} 250194149Simp 251194149Simp 252194149Simpstatic int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 253194149Simp{ 254222671Simp return (0); 255194149Simp} 256194149Simp 257194149Simp 258222671Simpstatic uint8_t cf_inb_8(int port) 259222671Simp{ 260222671Simp /* 261222671Simp * Traditional 8-bit PC Card/CF bus access. 262222671Simp */ 263222671Simp if (bus_type == CF_8) { 264222671Simp volatile uint8_t *task_file = (volatile uint8_t *)base_addr; 265222671Simp return task_file[port]; 266222671Simp } 267222671Simp 268222671Simp /* 269222671Simp * True IDE access. lower 8 bits on a 16-bit bus (see above). 270222671Simp */ 271222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 272222671Simp return task_file[port] & 0xff; 273222671Simp} 274222671Simp 275222671Simpstatic void cf_outb_8(int port, uint8_t val) 276222671Simp{ 277222671Simp /* 278222671Simp * Traditional 8-bit PC Card/CF bus access. 279222671Simp */ 280222671Simp if (bus_type == CF_8) { 281222671Simp volatile uint8_t *task_file = (volatile uint8_t *)base_addr; 282222671Simp task_file[port] = val; 283242201Sjmallett return; 284222671Simp } 285222671Simp 286222671Simp /* 287222671Simp * True IDE access. lower 8 bits on a 16-bit bus (see above). 288222671Simp */ 289222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 290222671Simp task_file[port] = val & 0xff; 291222671Simp} 292222671Simp 293222671Simpstatic uint8_t cf_inb_16(int port) 294222671Simp{ 295222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 296222671Simp uint16_t val = task_file[port / 2]; 297222671Simp if (port & 1) 298222671Simp return (val >> 8) & 0xff; 299222671Simp return val & 0xff; 300222671Simp} 301222671Simp 302222671Simpstatic uint16_t cf_inw_16(int port) 303222671Simp{ 304222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 305222671Simp uint16_t val = task_file[port / 2]; 306222671Simp return val; 307222671Simp} 308222671Simp 309222671Simpstatic void cf_outw_16(int port, uint16_t val) 310222671Simp{ 311222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 312222671Simp task_file[port / 2] = val; 313222671Simp} 314222671Simp 315194149Simp/* ------------------------------------------------------------------- * 316194149Simp * cf_cmd_read() * 317194149Simp * ------------------------------------------------------------------- * 318194149Simp * 319194149Simp * Read nr_sectors from the device starting from start_sector. 320194149Simp */ 321204789Sjmallettstatic int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) 322194149Simp{ 323194149Simp unsigned long lba; 324194149Simp uint32_t count; 325194149Simp uint16_t *ptr_16; 326194149Simp uint8_t *ptr_8; 327204789Sjmallett int error; 328194149Simp 329194149Simp ptr_8 = (uint8_t*)buf; 330194149Simp ptr_16 = (uint16_t*)buf; 331194149Simp lba = start_sector; 332194149Simp 333194149Simp while (nr_sectors--) { 334204789Sjmallett error = cf_send_cmd(lba, CMD_READ_SECTOR); 335204789Sjmallett if (error != 0) { 336204789Sjmallett printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error); 337204789Sjmallett return (error); 338204789Sjmallett } 339194149Simp 340222671Simp switch (bus_type) 341222671Simp { 342222671Simp case CF_8: 343194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 344222671Simp *ptr_8++ = cf_inb_8(TF_DATA); 345222671Simp if ((count & 0xf) == 0) 346222671Simp (void)cf_inb_8(TF_STATUS); 347194149Simp } 348222671Simp break; 349222671Simp case CF_TRUE_IDE_8: 350222671Simp case CF_16: 351222671Simp default: 352194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 353194149Simp uint16_t temp; 354222671Simp temp = cf_inw_16(TF_DATA); 355194149Simp *ptr_16++ = SWAP_SHORT(temp); 356222671Simp if ((count & 0xf) == 0) 357222671Simp (void)cf_inb_16(TF_STATUS); 358194149Simp } 359222671Simp break; 360194149Simp } 361194149Simp 362222671Simp lba++; 363194149Simp } 364204789Sjmallett return (0); 365194149Simp} 366194149Simp 367194149Simp 368194149Simp/* ------------------------------------------------------------------- * 369194149Simp * cf_cmd_write() * 370194149Simp * ------------------------------------------------------------------- * 371194149Simp * 372194149Simp * Write nr_sectors to the device starting from start_sector. 373194149Simp */ 374204789Sjmallettstatic int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) 375194149Simp{ 376194149Simp uint32_t lba; 377194149Simp uint32_t count; 378194149Simp uint16_t *ptr_16; 379194149Simp uint8_t *ptr_8; 380204789Sjmallett int error; 381194149Simp 382194149Simp lba = start_sector; 383194149Simp ptr_8 = (uint8_t*)buf; 384194149Simp ptr_16 = (uint16_t*)buf; 385194149Simp 386194149Simp while (nr_sectors--) { 387204789Sjmallett error = cf_send_cmd(lba, CMD_WRITE_SECTOR); 388204789Sjmallett if (error != 0) { 389204789Sjmallett printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error); 390204789Sjmallett return (error); 391204789Sjmallett } 392194149Simp 393222671Simp switch (bus_type) 394222671Simp { 395222671Simp case CF_8: 396194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 397222671Simp cf_outb_8(TF_DATA, *ptr_8++); 398222671Simp if ((count & 0xf) == 0) 399222671Simp (void)cf_inb_8(TF_STATUS); 400194149Simp } 401222671Simp break; 402222671Simp case CF_TRUE_IDE_8: 403222671Simp case CF_16: 404222671Simp default: 405194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 406194149Simp uint16_t temp = *ptr_16++; 407222671Simp cf_outw_16(TF_DATA, SWAP_SHORT(temp)); 408222671Simp if ((count & 0xf) == 0) 409222671Simp (void)cf_inb_16(TF_STATUS); 410194149Simp } 411222671Simp break; 412194149Simp } 413194149Simp 414222671Simp lba++; 415194149Simp } 416204789Sjmallett return (0); 417194149Simp} 418194149Simp 419194149Simp 420194149Simp/* ------------------------------------------------------------------- * 421194149Simp * cf_cmd_identify() * 422194149Simp * ------------------------------------------------------------------- * 423194149Simp * 424194149Simp * Read parameters and other information from the drive and store 425194149Simp * it in the drive_param structure 426194149Simp * 427194149Simp */ 428233278Sjmallettstatic int cf_cmd_identify(struct cf_priv *cf_priv) 429194149Simp{ 430194149Simp int count; 431204789Sjmallett int error; 432194149Simp 433222671Simp error = cf_send_cmd(0, CMD_IDENTIFY); 434204789Sjmallett if (error != 0) { 435204789Sjmallett printf("%s: identify failed: %d\n", __func__, error); 436204789Sjmallett return (error); 437204789Sjmallett } 438222671Simp switch (bus_type) 439222671Simp { 440222671Simp case CF_8: 441222671Simp for (count = 0; count < SECTOR_SIZE; count++) 442233278Sjmallett cf_priv->drive_param.u.buf[count] = cf_inb_8(TF_DATA); 443222671Simp break; 444222671Simp case CF_TRUE_IDE_8: 445222671Simp case CF_16: 446222671Simp default: 447222671Simp for (count = 0; count < SECTOR_SIZE; count += 2) { 448222671Simp uint16_t temp; 449222671Simp temp = cf_inw_16(TF_DATA); 450222671Simp 451222671Simp /* endianess will be swapped below */ 452233278Sjmallett cf_priv->drive_param.u.buf[count] = (temp & 0xff); 453233278Sjmallett cf_priv->drive_param.u.buf[count + 1] = (temp & 0xff00) >> 8; 454222671Simp } 455222671Simp break; 456222671Simp } 457194149Simp 458233278Sjmallett cf_swap_ascii(cf_priv->drive_param.u.driveid.model, cf_priv->drive_param.model); 459194149Simp 460233278Sjmallett cf_priv->drive_param.sector_size = 512; //= SWAP_SHORT (cf_priv->drive_param.u.driveid.sector_bytes); 461233278Sjmallett cf_priv->drive_param.heads = SWAP_SHORT (cf_priv->drive_param.u.driveid.current_heads); 462233278Sjmallett cf_priv->drive_param.tracks = SWAP_SHORT (cf_priv->drive_param.u.driveid.current_cylinders); 463233278Sjmallett cf_priv->drive_param.sec_track = SWAP_SHORT (cf_priv->drive_param.u.driveid.current_sectors); 464233278Sjmallett cf_priv->drive_param.nr_sectors = (uint32_t)SWAP_SHORT (cf_priv->drive_param.u.driveid.lba_size_1) | 465233278Sjmallett ((uint32_t)SWAP_SHORT (cf_priv->drive_param.u.driveid.lba_size_2)); 466226020Smarcel if (bootverbose) { 467233278Sjmallett printf(" model %s\n", cf_priv->drive_param.model); 468226020Smarcel printf(" heads %d tracks %d sec_tracks %d sectors %d\n", 469233278Sjmallett cf_priv->drive_param.heads, cf_priv->drive_param.tracks, 470233278Sjmallett cf_priv->drive_param.sec_track, cf_priv->drive_param.nr_sectors); 471226020Smarcel } 472194149Simp 473204789Sjmallett return (0); 474194149Simp} 475194149Simp 476194149Simp 477194149Simp/* ------------------------------------------------------------------- * 478194149Simp * cf_send_cmd() * 479194149Simp * ------------------------------------------------------------------- * 480194149Simp * 481194149Simp * Send command to read/write one sector specified by lba. 482194149Simp * 483194149Simp */ 484204789Sjmallettstatic int cf_send_cmd (uint32_t lba, uint8_t cmd) 485194149Simp{ 486222671Simp switch (bus_type) 487222671Simp { 488222671Simp case CF_8: 489222671Simp case CF_TRUE_IDE_8: 490222671Simp while (cf_inb_8(TF_STATUS) & STATUS_BSY) 491194149Simp DELAY(WAIT_DELAY); 492222671Simp cf_outb_8(TF_SECTOR_COUNT, 1); 493222671Simp cf_outb_8(TF_SECTOR_NUMBER, lba & 0xff); 494222671Simp cf_outb_8(TF_CYL_LSB, (lba >> 8) & 0xff); 495222671Simp cf_outb_8(TF_CYL_MSB, (lba >> 16) & 0xff); 496222671Simp cf_outb_8(TF_DRV_HEAD, ((lba >> 24) & 0xff) | 0xe0); 497222671Simp cf_outb_8(TF_COMMAND, cmd); 498222671Simp break; 499222671Simp case CF_16: 500222671Simp default: 501222671Simp while (cf_inb_16(TF_STATUS) & STATUS_BSY) 502194149Simp DELAY(WAIT_DELAY); 503222671Simp cf_outw_16(TF_SECTOR_COUNT, 1 | ((lba & 0xff) << 8)); 504222671Simp cf_outw_16(TF_CYL_LSB, ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8)); 505222671Simp cf_outw_16(TF_DRV_HEAD, (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8)); 506222671Simp break; 507194149Simp } 508194149Simp 509204789Sjmallett return (cf_wait_busy()); 510194149Simp} 511194149Simp 512194149Simp/* ------------------------------------------------------------------- * 513194149Simp * cf_wait_busy() * 514194149Simp * ------------------------------------------------------------------- * 515194149Simp * 516194149Simp * Wait until the drive finishes a given command and data is 517194149Simp * ready to be transferred. This is done by repeatedly checking 518204789Sjmallett * the BSY bit of the status register. When the controller is ready for 519204789Sjmallett * data transfer, it clears the BSY bit and sets the DRQ bit. 520194149Simp * 521204789Sjmallett * If the DF bit is ever set, we return error. 522204789Sjmallett * 523204789Sjmallett * This code originally spun on DRQ. If that behavior turns out to be 524204789Sjmallett * necessary, a flag can be added or this function can be called 525204789Sjmallett * repeatedly as long as it is returning ENXIO. 526194149Simp */ 527204789Sjmallettstatic int cf_wait_busy (void) 528194149Simp{ 529194149Simp uint8_t status; 530194149Simp 531222671Simp switch (bus_type) 532222671Simp { 533222671Simp case CF_8: 534222671Simp case CF_TRUE_IDE_8: 535222671Simp status = cf_inb_8(TF_STATUS); 536204789Sjmallett while ((status & STATUS_BSY) == STATUS_BSY) { 537204789Sjmallett if ((status & STATUS_DF) != 0) { 538204789Sjmallett printf("%s: device fault (status=%x)\n", __func__, status); 539204789Sjmallett return (EIO); 540204789Sjmallett } 541194149Simp DELAY(WAIT_DELAY); 542222671Simp status = cf_inb_8(TF_STATUS); 543194149Simp } 544222671Simp break; 545222671Simp case CF_16: 546222671Simp default: 547222671Simp status = cf_inb_16(TF_STATUS); 548204789Sjmallett while ((status & STATUS_BSY) == STATUS_BSY) { 549204789Sjmallett if ((status & STATUS_DF) != 0) { 550204789Sjmallett printf("%s: device fault (status=%x)\n", __func__, status); 551204789Sjmallett return (EIO); 552204789Sjmallett } 553194149Simp DELAY(WAIT_DELAY); 554222671Simp status = cf_inb_16(TF_STATUS); 555194149Simp } 556222671Simp break; 557194149Simp } 558226020Smarcel 559226020Smarcel /* DRQ is only for when read data is actually available; check BSY */ 560226020Smarcel /* Some vendors do assert DRQ, but not all. Check BSY instead. */ 561226020Smarcel if (status & STATUS_BSY) { 562204789Sjmallett printf("%s: device not ready (status=%x)\n", __func__, status); 563204789Sjmallett return (ENXIO); 564204789Sjmallett } 565194149Simp 566204789Sjmallett return (0); 567194149Simp} 568194149Simp 569194149Simp/* ------------------------------------------------------------------- * 570194149Simp * cf_swap_ascii() * 571194149Simp * ------------------------------------------------------------------- * 572194149Simp * 573194149Simp * The ascii string returned by the controller specifying 574194149Simp * the model of the drive is byte-swaped. This routine 575194149Simp * corrects the byte ordering. 576194149Simp * 577194149Simp */ 578194149Simpstatic void cf_swap_ascii (unsigned char str1[], char str2[]) 579194149Simp{ 580194149Simp int i; 581194149Simp 582222671Simp for(i = 0; i < MODEL_STR_SIZE; i++) 583222671Simp str2[i] = str1[i ^ 1]; 584194149Simp} 585194149Simp 586194149Simp 587194149Simp/* ------------------------------------------------------------------- * 588194149Simp * cf_probe() * 589194149Simp * ------------------------------------------------------------------- */ 590194149Simp 591194149Simpstatic int cf_probe (device_t dev) 592194149Simp{ 593242346Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 594222671Simp return (ENXIO); 595194149Simp 596194149Simp if (device_get_unit(dev) != 0) { 597194149Simp panic("can't attach more devices\n"); 598194149Simp } 599194149Simp 600194149Simp device_set_desc(dev, "Octeon Compact Flash Driver"); 601194149Simp 602265999Sian return (BUS_PROBE_NOWILDCARD); 603194149Simp} 604194149Simp 605194149Simp/* ------------------------------------------------------------------- * 606194149Simp * cf_identify() * 607194149Simp * ------------------------------------------------------------------- * 608194149Simp * 609194149Simp * Find the bootbus region for the CF to determine 610194149Simp * 16 or 8 bit and check to see if device is 611194149Simp * inserted. 612194149Simp * 613194149Simp */ 614194149Simpstatic void cf_identify (driver_t *drv, device_t parent) 615194149Simp{ 616226020Smarcel int bus_region; 617194149Simp int count = 0; 618226020Smarcel cvmx_mio_boot_reg_cfgx_t cfg; 619233278Sjmallett uint64_t phys_base; 620233278Sjmallett 621242346Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 622194173Simp return; 623194149Simp 624233278Sjmallett phys_base = cvmx_sysinfo_get()->compact_flash_common_base_addr; 625242389Sjmallett if (phys_base == 0) 626242389Sjmallett return; 627226020Smarcel base_addr = cvmx_phys_to_ptr(phys_base); 628194149Simp 629194149Simp for (bus_region = 0; bus_region < 8; bus_region++) 630194149Simp { 631210311Sjmallett cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(bus_region)); 632226020Smarcel if (cfg.s.base == phys_base >> 16) 633194149Simp { 634226020Smarcel if (cvmx_sysinfo_get()->compact_flash_attribute_base_addr == 0) 635222671Simp bus_type = CF_TRUE_IDE_8; 636222671Simp else 637222671Simp bus_type = (cfg.s.width) ? CF_16 : CF_8; 638222671Simp printf("Compact flash found in bootbus region %d (%s).\n", bus_region, cf_type[bus_type]); 639194149Simp break; 640194149Simp } 641194149Simp } 642194149Simp 643222671Simp switch (bus_type) 644222671Simp { 645222671Simp case CF_8: 646222671Simp case CF_TRUE_IDE_8: 647194149Simp /* Check if CF is inserted */ 648222671Simp while (cf_inb_8(TF_STATUS) & STATUS_BSY) { 649222671Simp if ((count++) == NR_TRIES ) { 650194149Simp printf("Compact Flash not present\n"); 651194149Simp return; 652194149Simp } 653194149Simp DELAY(WAIT_DELAY); 654194149Simp } 655222671Simp break; 656222671Simp case CF_16: 657222671Simp default: 658194149Simp /* Check if CF is inserted */ 659222671Simp while (cf_inb_16(TF_STATUS) & STATUS_BSY) { 660222671Simp if ((count++) == NR_TRIES ) { 661194149Simp printf("Compact Flash not present\n"); 662194149Simp return; 663194149Simp } 664194149Simp DELAY(WAIT_DELAY); 665194149Simp } 666222671Simp break; 667194149Simp } 668194149Simp 669194149Simp BUS_ADD_CHILD(parent, 0, "cf", 0); 670194149Simp} 671194149Simp 672194149Simp 673194149Simp/* ------------------------------------------------------------------- * 674194149Simp * cf_attach_geom() * 675194149Simp * ------------------------------------------------------------------- */ 676194149Simp 677233278Sjmallettstatic void cf_attach_geom (void *arg, int flag) 678194149Simp{ 679194149Simp struct cf_priv *cf_priv; 680194149Simp 681194149Simp cf_priv = (struct cf_priv *) arg; 682194149Simp cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev)); 683233278Sjmallett cf_priv->cf_geom->softc = cf_priv; 684194149Simp cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name); 685233278Sjmallett cf_priv->cf_provider->sectorsize = cf_priv->drive_param.sector_size; 686233278Sjmallett cf_priv->cf_provider->mediasize = cf_priv->drive_param.nr_sectors * cf_priv->cf_provider->sectorsize; 687194149Simp g_error_provider(cf_priv->cf_provider, 0); 688194149Simp} 689194149Simp 690194149Simp/* ------------------------------------------------------------------- * 691194149Simp * cf_attach() * 692194149Simp * ------------------------------------------------------------------- */ 693194149Simp 694194149Simpstatic int cf_attach (device_t dev) 695194149Simp{ 696194149Simp struct cf_priv *cf_priv; 697233278Sjmallett int error; 698194149Simp 699242346Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 700222671Simp return (ENXIO); 701194149Simp 702194149Simp cf_priv = device_get_softc(dev); 703194149Simp cf_priv->dev = dev; 704194149Simp 705233278Sjmallett error = cf_cmd_identify(cf_priv); 706233278Sjmallett if (error != 0) { 707233278Sjmallett device_printf(dev, "cf_cmd_identify failed: %d\n", error); 708233278Sjmallett return (error); 709233278Sjmallett } 710233278Sjmallett 711233278Sjmallett g_post_event(cf_attach_geom, cf_priv, M_WAITOK, NULL); 712194149Simp bioq_init(&cf_priv->cf_bq); 713194149Simp 714194149Simp return 0; 715194149Simp} 716194149Simp 717194149Simp 718194149Simpstatic device_method_t cf_methods[] = { 719194149Simp /* Device interface */ 720194149Simp DEVMETHOD(device_probe, cf_probe), 721194149Simp DEVMETHOD(device_identify, cf_identify), 722194149Simp DEVMETHOD(device_attach, cf_attach), 723194149Simp DEVMETHOD(device_detach, bus_generic_detach), 724194149Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 725194149Simp 726194149Simp { 0, 0 } 727194149Simp}; 728194149Simp 729194149Simpstatic driver_t cf_driver = { 730194149Simp "cf", 731194149Simp cf_methods, 732194149Simp sizeof(struct cf_priv) 733194149Simp}; 734194149Simp 735194149Simpstatic devclass_t cf_devclass; 736194149Simp 737194149SimpDRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0); 738