octeon_ebt3000_cf.c revision 233278
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: head/sys/mips/cavium/octeon_ebt3000_cf.c 233278 2012-03-21 10:27:12Z jmallett $"); 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 103210311Sjmallett/* Globals */ 104210311Sjmallett/* 105194149Simp * There's three bus types supported by this driver. 106194149Simp * 107194149Simp * CF_8 -- Traditional PC Card IDE interface on an 8-bit wide bus. We assume 108194149Simp * the bool loader has configure attribute memory properly. We then access 109194149Simp * the device like old-school 8-bit IDE card (which is all a traditional PC Card 110194149Simp * interface really is). 111194149Simp * CF_16 -- Traditional PC Card IDE interface on a 16-bit wide bus. Registers on 112194149Simp * this bus are 16-bits wide too. When accessing registers in the task file, you 113194149Simp * have to do it in 16-bit chunks, and worry about masking out what you don't want 114194149Simp * or ORing together the traditional 8-bit values. We assume the bootloader does 115194149Simp * the right attribute memory initialization dance. 116194149Simp * CF_TRUE_IDE_8 - CF Card wired to True IDE mode. There's no Attribute memory 117194149Simp * space at all. Instead all the traditional 8-bit registers are there, but 118194149Simp * on a 16-bit bus where addr0 isn't wired. This means we need to read/write them 119194149Simp * 16-bit chunks, but only the lower 8 bits are valid. We do not (and can not) 120194149Simp * access this like CF_16 with the comingled registers. Yet we can't access 121194149Simp * this like CF_8 because of the register offset. Except the TF_DATA register 122194149Simp * appears to be full width? 123194149Simp */ 124194149Simpvoid *base_addr; 125194149Simpint bus_type; 126210311Sjmallett#define CF_8 1 /* 8-bit bus, no offsets - PC Card */ 127194149Simp#define CF_16 2 /* 16-bit bus, registers shared - PC Card */ 128194149Simp#define CF_TRUE_IDE_8 3 /* 16-bit bus, only lower 8-bits, TrueIDE */ 129194149Simpconst char *const cf_type[] = { 130194149Simp "impossible type", 131194149Simp "CF 8-bit", 132194149Simp "CF 16-bit", 133194149Simp "True IDE" 134194149Simp}; 135194149Simp 136194149Simp/* Device parameters */ 137194149Simpstruct drive_param{ 138194149Simp union { 139194149Simp char buf[SECTOR_SIZE]; 140194149Simp 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; 149194149Simp}; 150194149Simp 151214708Sjmallett/* Device softc */ 152214708Sjmallettstruct cf_priv { 153194149Simp device_t dev; 154194149Simp struct drive_param drive_param; 155194149Simp 156194149Simp struct bio_queue_head cf_bq; 157194149Simp struct g_geom *cf_geom; 158194149Simp struct g_provider *cf_provider; 159194149Simp 160204789Sjmallett}; 161204789Sjmallett 162204789Sjmallett/* GEOM class implementation */ 163204789Sjmallettstatic g_access_t cf_access; 164204789Sjmallettstatic 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 175194149SimpDECLARE_GEOM_CLASS(g_cf_class, g_cf); 176194149Simp 177194149Simp/* Device methods */ 178194149Simpstatic int cf_probe(device_t); 179194149Simpstatic void cf_identify(driver_t *, device_t); 180194149Simpstatic int cf_attach(device_t); 181194149Simpstatic void cf_attach_geom(void *, int); 182194149Simp 183194149Simp/* ATA methods */ 184194149Simpstatic int cf_cmd_identify(struct cf_priv *); 185194149Simpstatic int cf_cmd_write(uint32_t, uint32_t, void *); 186194149Simpstatic int cf_cmd_read(uint32_t, uint32_t, void *); 187194149Simpstatic int cf_wait_busy(void); 188194149Simpstatic int cf_send_cmd(uint32_t, uint8_t); 189194149Simp 190204789Sjmallett/* Miscelenous */ 191204789Sjmallettstatic 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{ 208194149Simp struct cf_priv *cf_priv; 209204789Sjmallett int error; 210204789Sjmallett 211194149Simp cf_priv = bp->bio_to->geom->softc; 212204789Sjmallett 213204789Sjmallett /* 214204789Sjmallett * Handle actual I/O requests. The request is passed down through 215204789Sjmallett * the bio struct. 216204789Sjmallett */ 217194149Simp 218194149Simp if(bp->bio_cmd & BIO_GETATTR) { 219204789Sjmallett if (g_handleattr_int(bp, "GEOM::fwsectors", cf_priv->drive_param.sec_track)) 220204789Sjmallett return; 221204789Sjmallett if (g_handleattr_int(bp, "GEOM::fwheads", cf_priv->drive_param.heads)) 222204789Sjmallett return; 223204789Sjmallett 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) { 230194149Simp error = cf_cmd_read(bp->bio_length / cf_priv->drive_param.sector_size, 231194149Simp bp->bio_offset / cf_priv->drive_param.sector_size, bp->bio_data); 232194149Simp } else if (bp->bio_cmd & BIO_WRITE) { 233194149Simp error = cf_cmd_write(bp->bio_length / cf_priv->drive_param.sector_size, 234194149Simp bp->bio_offset/cf_priv->drive_param.sector_size, bp->bio_data); 235194149Simp } else { 236194149Simp printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd); 237194149Simp error = ENOTSUP; 238194149Simp } 239194149Simp 240194149Simp if (error != 0) { 241194149Simp g_io_deliver(bp, error); 242194149Simp return; 243204789Sjmallett } 244194149Simp 245194149Simp bp->bio_resid = 0; 246194149Simp bp->bio_completed = bp->bio_length; 247194149Simp g_io_deliver(bp, 0); 248194149Simp } 249204789Sjmallett} 250194149Simp 251194149Simp 252194149Simpstatic int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 253194149Simp{ 254194149Simp return (0); 255194149Simp} 256194149Simp 257194149Simp 258194149Simpstatic uint8_t cf_inb_8(int port) 259194149Simp{ 260194149Simp /* 261204789Sjmallett * Traditional 8-bit PC Card/CF bus access. 262204789Sjmallett */ 263204789Sjmallett if (bus_type == CF_8) { 264204789Sjmallett volatile uint8_t *task_file = (volatile uint8_t *)base_addr; 265204789Sjmallett return task_file[port]; 266194149Simp } 267194149Simp 268194149Simp /* 269194149Simp * True IDE access. lower 8 bits on a 16-bit bus (see above). 270194149Simp */ 271194149Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 272194149Simp return task_file[port] & 0xff; 273194149Simp} 274194149Simp 275194149Simpstatic void cf_outb_8(int port, uint8_t val) 276194149Simp{ 277194149Simp /* 278194149Simp * Traditional 8-bit PC Card/CF bus access. 279194149Simp */ 280194149Simp if (bus_type == CF_8) { 281194149Simp volatile uint8_t *task_file = (volatile uint8_t *)base_addr; 282194149Simp task_file[port] = val; 283194149Simp } 284194149Simp 285194149Simp /* 286194149Simp * True IDE access. lower 8 bits on a 16-bit bus (see above). 287194149Simp */ 288194149Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 289194149Simp task_file[port] = val & 0xff; 290204789Sjmallett} 291194149Simp 292194149Simpstatic uint8_t cf_inb_16(int port) 293194149Simp{ 294194149Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 295194149Simp uint16_t val = task_file[port / 2]; 296194149Simp if (port & 1) 297194149Simp return (val >> 8) & 0xff; 298194149Simp return val & 0xff; 299194149Simp} 300204789Sjmallett 301194149Simpstatic uint16_t cf_inw_16(int port) 302194149Simp{ 303194149Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 304194149Simp uint16_t val = task_file[port / 2]; 305194149Simp return val; 306204789Sjmallett} 307194149Simp 308194149Simpstatic void cf_outw_16(int port, uint16_t val) 309194149Simp{ 310194149Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 311194149Simp task_file[port / 2] = val; 312194149Simp} 313194149Simp 314194149Simp/* ------------------------------------------------------------------- * 315194149Simp * cf_cmd_read() * 316194149Simp * ------------------------------------------------------------------- * 317204789Sjmallett * 318204789Sjmallett * Read nr_sectors from the device starting from start_sector. 319204789Sjmallett */ 320204789Sjmallettstatic int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) 321204789Sjmallett{ 322194149Simp unsigned long lba; 323194149Simp uint32_t count; 324194149Simp uint16_t *ptr_16; 325194149Simp uint8_t *ptr_8; 326194149Simp int error; 327194149Simp 328194149Simp//#define OCTEON_VISUAL_CF_0 1 329194149Simp#ifdef OCTEON_VISUAL_CF_0 330194149Simp octeon_led_write_char(0, 'R'); 331194149Simp#endif 332194149Simp ptr_8 = (uint8_t*)buf; 333194149Simp ptr_16 = (uint16_t*)buf; 334194149Simp lba = start_sector; 335194149Simp 336194149Simp 337194149Simp while (nr_sectors--) { 338194149Simp error = cf_send_cmd(lba, CMD_READ_SECTOR); 339194149Simp if (error != 0) { 340194149Simp printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error); 341194149Simp return (error); 342194149Simp } 343194149Simp 344194149Simp switch (bus_type) 345194149Simp { 346194149Simp case CF_8: 347194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 348194149Simp *ptr_8++ = cf_inb_8(TF_DATA); 349204789Sjmallett if ((count & 0xf) == 0) 350194149Simp (void)cf_inb_8(TF_STATUS); 351194149Simp } 352194149Simp break; 353194149Simp case CF_TRUE_IDE_8: 354194149Simp case CF_16: 355194149Simp default: 356194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 357194149Simp uint16_t temp; 358194149Simp temp = cf_inw_16(TF_DATA); 359194149Simp *ptr_16++ = SWAP_SHORT(temp); 360194149Simp if ((count & 0xf) == 0) 361204789Sjmallett (void)cf_inb_16(TF_STATUS); 362194149Simp } 363194149Simp break; 364194149Simp } 365204789Sjmallett 366194149Simp lba++; 367194149Simp } 368194149Simp#ifdef OCTEON_VISUAL_CF_0 369194149Simp octeon_led_write_char(0, ' '); 370194149Simp#endif 371194149Simp return (0); 372194149Simp} 373194149Simp 374194149Simp 375194149Simp/* ------------------------------------------------------------------- * 376194149Simp * cf_cmd_write() * 377194149Simp * ------------------------------------------------------------------- * 378194149Simp * 379194149Simp * Write nr_sectors to the device starting from start_sector. 380194149Simp */ 381194149Simpstatic int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) 382194149Simp{ 383204789Sjmallett uint32_t lba; 384204789Sjmallett uint32_t count; 385204789Sjmallett uint16_t *ptr_16; 386204789Sjmallett uint8_t *ptr_8; 387204789Sjmallett int error; 388194149Simp 389194149Simp//#define OCTEON_VISUAL_CF_1 1 390194149Simp#ifdef OCTEON_VISUAL_CF_1 391194149Simp octeon_led_write_char(1, 'W'); 392194149Simp#endif 393194149Simp lba = start_sector; 394194149Simp ptr_8 = (uint8_t*)buf; 395194149Simp ptr_16 = (uint16_t*)buf; 396194149Simp 397194149Simp while (nr_sectors--) { 398194149Simp error = cf_send_cmd(lba, CMD_WRITE_SECTOR); 399194149Simp if (error != 0) { 400194149Simp printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error); 401204789Sjmallett return (error); 402204789Sjmallett } 403204789Sjmallett 404204789Sjmallett switch (bus_type) 405204789Sjmallett { 406204789Sjmallett case CF_8: 407204789Sjmallett for (count = 0; count < SECTOR_SIZE; count++) { 408204789Sjmallett cf_outb_8(TF_DATA, *ptr_8++); 409204789Sjmallett if ((count & 0xf) == 0) 410204789Sjmallett (void)cf_inb_8(TF_STATUS); 411194149Simp } 412194149Simp break; 413204789Sjmallett case CF_TRUE_IDE_8: 414204789Sjmallett case CF_16: 415204789Sjmallett default: 416204789Sjmallett for (count = 0; count < SECTOR_SIZE; count+=2) { 417194149Simp uint16_t temp = *ptr_16++; 418194149Simp cf_outw_16(TF_DATA, SWAP_SHORT(temp)); 419194149Simp if ((count & 0xf) == 0) 420194149Simp (void)cf_inb_16(TF_STATUS); 421210311Sjmallett } 422210311Sjmallett break; 423210311Sjmallett } 424210311Sjmallett 425210311Sjmallett lba++; 426194149Simp } 427204789Sjmallett#ifdef OCTEON_VISUAL_CF_1 428194149Simp octeon_led_write_char(1, ' '); 429194149Simp#endif 430194149Simp return (0); 431194149Simp} 432194149Simp 433194149Simp 434194149Simp/* ------------------------------------------------------------------- * 435194149Simp * cf_cmd_identify() * 436194149Simp * ------------------------------------------------------------------- * 437194149Simp * 438204789Sjmallett * Read parameters and other information from the drive and store 439194149Simp * it in the drive_param structure 440194149Simp * 441194149Simp */ 442194149Simpstatic int cf_cmd_identify(struct cf_priv *cf_priv) 443194149Simp{ 444194149Simp int count; 445194149Simp int error; 446194149Simp 447194149Simp error = cf_send_cmd(0, CMD_IDENTIFY); 448194149Simp if (error != 0) { 449194149Simp printf("%s: identify failed: %d\n", __func__, error); 450194149Simp return (error); 451194149Simp } 452194149Simp switch (bus_type) 453194149Simp { 454194149Simp case CF_8: 455194149Simp for (count = 0; count < SECTOR_SIZE; count++) 456194149Simp cf_priv->drive_param.u.buf[count] = cf_inb_8(TF_DATA); 457194149Simp break; 458194149Simp case CF_TRUE_IDE_8: 459194149Simp case CF_16: 460194149Simp default: 461194149Simp for (count = 0; count < SECTOR_SIZE; count += 2) { 462194149Simp uint16_t temp; 463194149Simp temp = cf_inw_16(TF_DATA); 464194149Simp 465194149Simp /* endianess will be swapped below */ 466194149Simp cf_priv->drive_param.u.buf[count] = (temp & 0xff); 467194149Simp cf_priv->drive_param.u.buf[count + 1] = (temp & 0xff00) >> 8; 468194149Simp } 469194149Simp break; 470194149Simp } 471194149Simp 472194149Simp cf_swap_ascii(cf_priv->drive_param.u.driveid.model, cf_priv->drive_param.model); 473204789Sjmallett 474194149Simp cf_priv->drive_param.sector_size = 512; //= SWAP_SHORT (cf_priv->drive_param.u.driveid.sector_bytes); 475194149Simp cf_priv->drive_param.heads = SWAP_SHORT (cf_priv->drive_param.u.driveid.current_heads); 476194149Simp cf_priv->drive_param.tracks = SWAP_SHORT (cf_priv->drive_param.u.driveid.current_cylinders); 477194149Simp cf_priv->drive_param.sec_track = SWAP_SHORT (cf_priv->drive_param.u.driveid.current_sectors); 478194149Simp cf_priv->drive_param.nr_sectors = (uint32_t)SWAP_SHORT (cf_priv->drive_param.u.driveid.lba_size_1) | 479194149Simp ((uint32_t)SWAP_SHORT (cf_priv->drive_param.u.driveid.lba_size_2)); 480194149Simp if (bootverbose) { 481194149Simp printf(" model %s\n", cf_priv->drive_param.model); 482204789Sjmallett printf(" heads %d tracks %d sec_tracks %d sectors %d\n", 483204789Sjmallett cf_priv->drive_param.heads, cf_priv->drive_param.tracks, 484194149Simp cf_priv->drive_param.sec_track, cf_priv->drive_param.nr_sectors); 485204789Sjmallett } 486204789Sjmallett 487204789Sjmallett return (0); 488204789Sjmallett} 489204789Sjmallett 490194149Simp 491204789Sjmallett/* ------------------------------------------------------------------- * 492194149Simp * cf_send_cmd() * 493194149Simp * ------------------------------------------------------------------- * 494194149Simp * 495194149Simp * Send command to read/write one sector specified by lba. 496194149Simp * 497194149Simp */ 498194149Simpstatic int cf_send_cmd (uint32_t lba, uint8_t cmd) 499194149Simp{ 500194149Simp switch (bus_type) 501194149Simp { 502194149Simp case CF_8: 503194149Simp case CF_TRUE_IDE_8: 504194149Simp while (cf_inb_8(TF_STATUS) & STATUS_BSY) 505194149Simp DELAY(WAIT_DELAY); 506194149Simp cf_outb_8(TF_SECTOR_COUNT, 1); 507204789Sjmallett cf_outb_8(TF_SECTOR_NUMBER, lba & 0xff); 508204789Sjmallett cf_outb_8(TF_CYL_LSB, (lba >> 8) & 0xff); 509204789Sjmallett cf_outb_8(TF_CYL_MSB, (lba >> 16) & 0xff); 510204789Sjmallett cf_outb_8(TF_DRV_HEAD, ((lba >> 24) & 0xff) | 0xe0); 511204789Sjmallett cf_outb_8(TF_COMMAND, cmd); 512194149Simp break; 513194149Simp case CF_16: 514194149Simp default: 515194149Simp while (cf_inb_16(TF_STATUS) & STATUS_BSY) 516194149Simp DELAY(WAIT_DELAY); 517194149Simp cf_outw_16(TF_SECTOR_COUNT, 1 | ((lba & 0xff) << 8)); 518194149Simp cf_outw_16(TF_CYL_LSB, ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8)); 519194149Simp cf_outw_16(TF_DRV_HEAD, (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8)); 520204789Sjmallett break; 521204789Sjmallett } 522204789Sjmallett 523204789Sjmallett return (cf_wait_busy()); 524204789Sjmallett} 525194149Simp 526194149Simp/* ------------------------------------------------------------------- * 527194149Simp * cf_wait_busy() * 528194149Simp * ------------------------------------------------------------------- * 529204789Sjmallett * 530204789Sjmallett * Wait until the drive finishes a given command and data is 531204789Sjmallett * ready to be transferred. This is done by repeatedly checking 532204789Sjmallett * the BSY bit of the status register. When the controller is ready for 533194149Simp * data transfer, it clears the BSY bit and sets the DRQ bit. 534194149Simp * 535194149Simp * If the DF bit is ever set, we return error. 536194149Simp * 537204789Sjmallett * This code originally spun on DRQ. If that behavior turns out to be 538194149Simp * necessary, a flag can be added or this function can be called 539194149Simp * repeatedly as long as it is returning ENXIO. 540194149Simp */ 541194149Simpstatic int cf_wait_busy (void) 542194149Simp{ 543194149Simp uint8_t status; 544194149Simp 545194149Simp//#define OCTEON_VISUAL_CF_2 1 546194149Simp#ifdef OCTEON_VISUAL_CF_2 547194149Simp static int where0 = 0; 548194149Simp 549194149Simp octeon_led_run_wheel(&where0, 2); 550194149Simp#endif 551194149Simp 552194149Simp switch (bus_type) 553194149Simp { 554194149Simp case CF_8: 555194149Simp case CF_TRUE_IDE_8: 556194149Simp status = cf_inb_8(TF_STATUS); 557194149Simp while ((status & STATUS_BSY) == STATUS_BSY) { 558194149Simp if ((status & STATUS_DF) != 0) { 559194149Simp printf("%s: device fault (status=%x)\n", __func__, status); 560194149Simp return (EIO); 561194149Simp } 562194149Simp DELAY(WAIT_DELAY); 563194149Simp status = cf_inb_8(TF_STATUS); 564194149Simp } 565210311Sjmallett break; 566194149Simp case CF_16: 567194149Simp default: 568194149Simp status = cf_inb_16(TF_STATUS); 569194149Simp while ((status & STATUS_BSY) == STATUS_BSY) { 570194149Simp if ((status & STATUS_DF) != 0) { 571194149Simp printf("%s: device fault (status=%x)\n", __func__, status); 572194149Simp return (EIO); 573204789Sjmallett } 574194149Simp DELAY(WAIT_DELAY); 575194149Simp status = cf_inb_16(TF_STATUS); 576194149Simp } 577194149Simp break; 578194149Simp } 579194149Simp 580194149Simp /* DRQ is only for when read data is actually available; check BSY */ 581194149Simp /* Some vendors do assert DRQ, but not all. Check BSY instead. */ 582194149Simp if (status & STATUS_BSY) { 583194149Simp printf("%s: device not ready (status=%x)\n", __func__, status); 584194149Simp return (ENXIO); 585194149Simp } 586194149Simp 587194149Simp#ifdef OCTEON_VISUAL_CF_2 588194149Simp octeon_led_write_char(2, ' '); 589194149Simp#endif 590210311Sjmallett return (0); 591194149Simp} 592210311Sjmallett 593194173Simp/* ------------------------------------------------------------------- * 594194149Simp * cf_swap_ascii() * 595210311Sjmallett * ------------------------------------------------------------------- * 596194149Simp * 597194149Simp * The ascii string returned by the controller specifying 598194149Simp * the model of the drive is byte-swaped. This routine 599210311Sjmallett * corrects the byte ordering. 600210311Sjmallett * 601194149Simp */ 602210311Sjmallettstatic void cf_swap_ascii (unsigned char str1[], char str2[]) 603194149Simp{ 604194149Simp int i; 605194149Simp 606194149Simp for(i = 0; i < MODEL_STR_SIZE; i++) 607194149Simp str2[i] = str1[i ^ 1]; 608194149Simp} 609194149Simp 610194149Simp 611194149Simp/* ------------------------------------------------------------------- * 612194149Simp * cf_probe() * 613194149Simp * ------------------------------------------------------------------- */ 614194149Simp 615194149Simpstatic int cf_probe (device_t dev) 616194149Simp{ 617194149Simp if (octeon_is_simulation()) 618194149Simp return (ENXIO); 619194149Simp 620194149Simp if (device_get_unit(dev) != 0) { 621194149Simp panic("can't attach more devices\n"); 622194149Simp } 623194149Simp 624194149Simp device_set_desc(dev, "Octeon Compact Flash Driver"); 625194149Simp 626194149Simp return (0); 627194149Simp} 628194149Simp 629194149Simp/* ------------------------------------------------------------------- * 630194149Simp * cf_identify() * 631194149Simp * ------------------------------------------------------------------- * 632194149Simp * 633194149Simp * Find the bootbus region for the CF to determine 634194149Simp * 16 or 8 bit and check to see if device is 635194149Simp * inserted. 636194149Simp * 637194149Simp */ 638194149Simpstatic void cf_identify (driver_t *drv, device_t parent) 639194149Simp{ 640194149Simp int bus_region; 641194149Simp int count = 0; 642194149Simp cvmx_mio_boot_reg_cfgx_t cfg; 643194149Simp uint64_t phys_base; 644194149Simp 645194149Simp if (octeon_is_simulation()) 646194149Simp return; 647194149Simp 648194149Simp phys_base = cvmx_sysinfo_get()->compact_flash_common_base_addr; 649194149Simp base_addr = cvmx_phys_to_ptr(phys_base); 650194149Simp 651194149Simp for (bus_region = 0; bus_region < 8; bus_region++) 652194149Simp { 653194149Simp cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(bus_region)); 654194149Simp if (cfg.s.base == phys_base >> 16) 655194149Simp { 656194149Simp if (cvmx_sysinfo_get()->compact_flash_attribute_base_addr == 0) 657194149Simp bus_type = CF_TRUE_IDE_8; 658194149Simp else 659194149Simp bus_type = (cfg.s.width) ? CF_16 : CF_8; 660194149Simp printf("Compact flash found in bootbus region %d (%s).\n", bus_region, cf_type[bus_type]); 661194149Simp break; 662194149Simp } 663194149Simp } 664194149Simp 665194149Simp switch (bus_type) 666194149Simp { 667194149Simp case CF_8: 668194149Simp case CF_TRUE_IDE_8: 669194149Simp /* Check if CF is inserted */ 670194149Simp while (cf_inb_8(TF_STATUS) & STATUS_BSY) { 671210311Sjmallett if ((count++) == NR_TRIES ) { 672194149Simp printf("Compact Flash not present\n"); 673194149Simp return; 674194149Simp } 675194149Simp DELAY(WAIT_DELAY); 676194149Simp } 677194149Simp break; 678194149Simp case CF_16: 679194149Simp default: 680194149Simp /* Check if CF is inserted */ 681194149Simp while (cf_inb_16(TF_STATUS) & STATUS_BSY) { 682194149Simp if ((count++) == NR_TRIES ) { 683194149Simp printf("Compact Flash not present\n"); 684194149Simp return; 685194149Simp } 686194149Simp DELAY(WAIT_DELAY); 687194149Simp } 688194149Simp break; 689194149Simp } 690194149Simp 691194149Simp BUS_ADD_CHILD(parent, 0, "cf", 0); 692194149Simp} 693194149Simp 694194149Simp 695194149Simp/* ------------------------------------------------------------------- * 696194149Simp * cf_attach_geom() * 697194149Simp * ------------------------------------------------------------------- */ 698194149Simp 699194149Simpstatic void cf_attach_geom (void *arg, int flag) 700194149Simp{ 701194149Simp struct cf_priv *cf_priv; 702194149Simp 703194149Simp cf_priv = (struct cf_priv *) arg; 704194149Simp cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev)); 705 cf_priv->cf_geom->softc = cf_priv; 706 cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name); 707 cf_priv->cf_provider->sectorsize = cf_priv->drive_param.sector_size; 708 cf_priv->cf_provider->mediasize = cf_priv->drive_param.nr_sectors * cf_priv->cf_provider->sectorsize; 709 g_error_provider(cf_priv->cf_provider, 0); 710} 711 712/* ------------------------------------------------------------------- * 713 * cf_attach() * 714 * ------------------------------------------------------------------- */ 715 716static int cf_attach (device_t dev) 717{ 718 struct cf_priv *cf_priv; 719 int error; 720 721 if (octeon_is_simulation()) 722 return (ENXIO); 723 724 cf_priv = device_get_softc(dev); 725 cf_priv->dev = dev; 726 727 error = cf_cmd_identify(cf_priv); 728 if (error != 0) { 729 device_printf(dev, "cf_cmd_identify failed: %d\n", error); 730 return (error); 731 } 732 733 g_post_event(cf_attach_geom, cf_priv, M_WAITOK, NULL); 734 bioq_init(&cf_priv->cf_bq); 735 736 return 0; 737} 738 739 740static device_method_t cf_methods[] = { 741 /* Device interface */ 742 DEVMETHOD(device_probe, cf_probe), 743 DEVMETHOD(device_identify, cf_identify), 744 DEVMETHOD(device_attach, cf_attach), 745 DEVMETHOD(device_detach, bus_generic_detach), 746 DEVMETHOD(device_shutdown, bus_generic_shutdown), 747 748 { 0, 0 } 749}; 750 751static driver_t cf_driver = { 752 "cf", 753 cf_methods, 754 sizeof(struct cf_priv) 755}; 756 757static devclass_t cf_devclass; 758 759DRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0); 760