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$"); 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/* XXX */ 104210311Sjmallettextern cvmx_bootinfo_t *octeon_bootinfo; 105194149Simp 106194149Simp/* Globals */ 107222671Simp/* 108222671Simp * There's three bus types supported by this driver. 109222671Simp * 110222671Simp * CF_8 -- Traditional PC Card IDE interface on an 8-bit wide bus. We assume 111222671Simp * the bool loader has configure attribute memory properly. We then access 112222671Simp * the device like old-school 8-bit IDE card (which is all a traditional PC Card 113222671Simp * interface really is). 114222671Simp * CF_16 -- Traditional PC Card IDE interface on a 16-bit wide bus. Registers on 115222671Simp * this bus are 16-bits wide too. When accessing registers in the task file, you 116222671Simp * have to do it in 16-bit chunks, and worry about masking out what you don't want 117222671Simp * or ORing together the traditional 8-bit values. We assume the bootloader does 118222671Simp * the right attribute memory initialization dance. 119222671Simp * CF_TRUE_IDE_8 - CF Card wired to True IDE mode. There's no Attribute memory 120222671Simp * space at all. Instead all the traditional 8-bit registers are there, but 121222671Simp * on a 16-bit bus where addr0 isn't wired. This means we need to read/write them 122222671Simp * 16-bit chunks, but only the lower 8 bits are valid. We do not (and can not) 123222671Simp * access this like CF_16 with the comingled registers. Yet we can't access 124222671Simp * this like CF_8 because of the register offset. Except the TF_DATA register 125222671Simp * appears to be full width? 126222671Simp */ 127194149Simpvoid *base_addr; 128222671Simpint bus_type; 129222671Simp#define CF_8 1 /* 8-bit bus, no offsets - PC Card */ 130222671Simp#define CF_16 2 /* 16-bit bus, registers shared - PC Card */ 131222671Simp#define CF_TRUE_IDE_8 3 /* 16-bit bus, only lower 8-bits, TrueIDE */ 132222671Simpconst char *const cf_type[] = { 133222671Simp "impossible type", 134222671Simp "CF 8-bit", 135222671Simp "CF 16-bit", 136222671Simp "True IDE" 137222671Simp}; 138194149Simp 139194149Simp/* Device softc */ 140194149Simpstruct cf_priv { 141194149Simp device_t dev; 142194149Simp struct drive_param *drive_param; 143194149Simp 144194149Simp struct bio_queue_head cf_bq; 145194149Simp struct g_geom *cf_geom; 146194149Simp struct g_provider *cf_provider; 147194149Simp 148194149Simp}; 149194149Simp 150194149Simp/* Device parameters */ 151194149Simpstruct drive_param{ 152194149Simp union { 153194149Simp char buf[SECTOR_SIZE]; 154210311Sjmallett struct ata_params driveid; 155194149Simp } u; 156194149Simp 157194149Simp char model[MODEL_STR_SIZE]; 158194149Simp uint32_t nr_sectors; 159194149Simp uint16_t sector_size; 160194149Simp uint16_t heads; 161194149Simp uint16_t tracks; 162194149Simp uint16_t sec_track; 163194149Simp 164194149Simp} drive_param; 165194149Simp 166194149Simp/* GEOM class implementation */ 167194149Simpstatic g_access_t cf_access; 168194149Simpstatic g_start_t cf_start; 169194149Simpstatic g_ioctl_t cf_ioctl; 170194149Simp 171194149Simpstruct g_class g_cf_class = { 172194149Simp .name = "CF", 173194149Simp .version = G_VERSION, 174194149Simp .start = cf_start, 175194149Simp .access = cf_access, 176194149Simp .ioctl = cf_ioctl, 177194149Simp}; 178194149Simp 179214708SjmallettDECLARE_GEOM_CLASS(g_cf_class, g_cf); 180214708Sjmallett 181194149Simp/* Device methods */ 182194149Simpstatic int cf_probe(device_t); 183194149Simpstatic void cf_identify(driver_t *, device_t); 184194149Simpstatic int cf_attach(device_t); 185194149Simpstatic int cf_attach_geom(void *, int); 186194149Simp 187194149Simp/* ATA methods */ 188204789Sjmallettstatic int cf_cmd_identify(void); 189204789Sjmallettstatic int cf_cmd_write(uint32_t, uint32_t, void *); 190204789Sjmallettstatic int cf_cmd_read(uint32_t, uint32_t, void *); 191204789Sjmallettstatic int cf_wait_busy(void); 192204789Sjmallettstatic int cf_send_cmd(uint32_t, uint8_t); 193194149Simpstatic void cf_attach_geom_proxy(void *arg, int flag); 194194149Simp 195194149Simp/* Miscelenous */ 196194149Simpstatic void cf_swap_ascii(unsigned char[], char[]); 197194149Simp 198194149Simp 199194149Simp/* ------------------------------------------------------------------- * 200194149Simp * cf_access() * 201194149Simp * ------------------------------------------------------------------- */ 202194149Simpstatic int cf_access (struct g_provider *pp, int r, int w, int e) 203194149Simp{ 204194149Simp 205194149Simp pp->sectorsize = drive_param.sector_size; 206194149Simp pp->stripesize = drive_param.heads * drive_param.sec_track * drive_param.sector_size; 207194149Simp pp->mediasize = pp->stripesize * drive_param.tracks; 208194149Simp 209194149Simp return (0); 210194149Simp} 211194149Simp 212194149Simp 213194149Simp/* ------------------------------------------------------------------- * 214194149Simp * cf_start() * 215194149Simp * ------------------------------------------------------------------- */ 216194149Simpstatic void cf_start (struct bio *bp) 217194149Simp{ 218204789Sjmallett int error; 219204789Sjmallett 220194149Simp /* 221194149Simp * Handle actual I/O requests. The request is passed down through 222194149Simp * the bio struct. 223194149Simp */ 224194149Simp 225194149Simp if(bp->bio_cmd & BIO_GETATTR) { 226194149Simp if (g_handleattr_int(bp, "GEOM::fwsectors", drive_param.sec_track)) 227194149Simp return; 228194149Simp if (g_handleattr_int(bp, "GEOM::fwheads", drive_param.heads)) 229194149Simp return; 230194149Simp g_io_deliver(bp, ENOIOCTL); 231194149Simp return; 232194149Simp } 233194149Simp 234194149Simp if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { 235194149Simp 236194149Simp if (bp->bio_cmd & BIO_READ) { 237204789Sjmallett error = cf_cmd_read(bp->bio_length / drive_param.sector_size, 238204789Sjmallett bp->bio_offset / drive_param.sector_size, bp->bio_data); 239194149Simp } else if (bp->bio_cmd & BIO_WRITE) { 240204789Sjmallett error = cf_cmd_write(bp->bio_length / drive_param.sector_size, 241204789Sjmallett bp->bio_offset/drive_param.sector_size, bp->bio_data); 242204789Sjmallett } else { 243204789Sjmallett printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd); 244204789Sjmallett error = ENOTSUP; 245194149Simp } 246194149Simp 247204789Sjmallett if (error != 0) { 248204789Sjmallett g_io_deliver(bp, error); 249204789Sjmallett return; 250204789Sjmallett } 251204789Sjmallett 252194149Simp bp->bio_resid = 0; 253194149Simp bp->bio_completed = bp->bio_length; 254194149Simp g_io_deliver(bp, 0); 255194149Simp } 256194149Simp} 257194149Simp 258194149Simp 259194149Simpstatic int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 260194149Simp{ 261222671Simp return (0); 262194149Simp} 263194149Simp 264194149Simp 265222671Simpstatic uint8_t cf_inb_8(int port) 266222671Simp{ 267222671Simp /* 268222671Simp * Traditional 8-bit PC Card/CF bus access. 269222671Simp */ 270222671Simp if (bus_type == CF_8) { 271222671Simp volatile uint8_t *task_file = (volatile uint8_t *)base_addr; 272222671Simp return task_file[port]; 273222671Simp } 274222671Simp 275222671Simp /* 276222671Simp * True IDE access. lower 8 bits on a 16-bit bus (see above). 277222671Simp */ 278222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 279222671Simp return task_file[port] & 0xff; 280222671Simp} 281222671Simp 282222671Simpstatic void cf_outb_8(int port, uint8_t val) 283222671Simp{ 284222671Simp /* 285222671Simp * Traditional 8-bit PC Card/CF bus access. 286222671Simp */ 287222671Simp if (bus_type == CF_8) { 288222671Simp volatile uint8_t *task_file = (volatile uint8_t *)base_addr; 289222671Simp task_file[port] = val; 290222671Simp } 291222671Simp 292222671Simp /* 293222671Simp * True IDE access. lower 8 bits on a 16-bit bus (see above). 294222671Simp */ 295222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 296222671Simp task_file[port] = val & 0xff; 297222671Simp} 298222671Simp 299222671Simpstatic uint8_t cf_inb_16(int port) 300222671Simp{ 301222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 302222671Simp uint16_t val = task_file[port / 2]; 303222671Simp if (port & 1) 304222671Simp return (val >> 8) & 0xff; 305222671Simp return val & 0xff; 306222671Simp} 307222671Simp 308222671Simpstatic uint16_t cf_inw_16(int port) 309222671Simp{ 310222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 311222671Simp uint16_t val = task_file[port / 2]; 312222671Simp return val; 313222671Simp} 314222671Simp 315222671Simpstatic void cf_outw_16(int port, uint16_t val) 316222671Simp{ 317222671Simp volatile uint16_t *task_file = (volatile uint16_t *)base_addr; 318222671Simp task_file[port / 2] = val; 319222671Simp} 320222671Simp 321194149Simp/* ------------------------------------------------------------------- * 322194149Simp * cf_cmd_read() * 323194149Simp * ------------------------------------------------------------------- * 324194149Simp * 325194149Simp * Read nr_sectors from the device starting from start_sector. 326194149Simp */ 327204789Sjmallettstatic int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) 328194149Simp{ 329194149Simp unsigned long lba; 330194149Simp uint32_t count; 331194149Simp uint16_t *ptr_16; 332194149Simp uint8_t *ptr_8; 333204789Sjmallett int error; 334194149Simp 335194149Simp//#define OCTEON_VISUAL_CF_0 1 336194149Simp#ifdef OCTEON_VISUAL_CF_0 337194149Simp octeon_led_write_char(0, 'R'); 338194149Simp#endif 339194149Simp ptr_8 = (uint8_t*)buf; 340194149Simp ptr_16 = (uint16_t*)buf; 341194149Simp lba = start_sector; 342194149Simp 343194149Simp 344194149Simp while (nr_sectors--) { 345204789Sjmallett error = cf_send_cmd(lba, CMD_READ_SECTOR); 346204789Sjmallett if (error != 0) { 347204789Sjmallett printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error); 348204789Sjmallett return (error); 349204789Sjmallett } 350194149Simp 351222671Simp switch (bus_type) 352222671Simp { 353222671Simp case CF_8: 354194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 355222671Simp *ptr_8++ = cf_inb_8(TF_DATA); 356222671Simp if ((count & 0xf) == 0) 357222671Simp (void)cf_inb_8(TF_STATUS); 358194149Simp } 359222671Simp break; 360222671Simp case CF_TRUE_IDE_8: 361222671Simp case CF_16: 362222671Simp default: 363194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 364194149Simp uint16_t temp; 365222671Simp temp = cf_inw_16(TF_DATA); 366194149Simp *ptr_16++ = SWAP_SHORT(temp); 367222671Simp if ((count & 0xf) == 0) 368222671Simp (void)cf_inb_16(TF_STATUS); 369194149Simp } 370222671Simp break; 371194149Simp } 372194149Simp 373222671Simp lba++; 374194149Simp } 375194149Simp#ifdef OCTEON_VISUAL_CF_0 376194149Simp octeon_led_write_char(0, ' '); 377194149Simp#endif 378204789Sjmallett return (0); 379194149Simp} 380194149Simp 381194149Simp 382194149Simp/* ------------------------------------------------------------------- * 383194149Simp * cf_cmd_write() * 384194149Simp * ------------------------------------------------------------------- * 385194149Simp * 386194149Simp * Write nr_sectors to the device starting from start_sector. 387194149Simp */ 388204789Sjmallettstatic int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) 389194149Simp{ 390194149Simp uint32_t lba; 391194149Simp uint32_t count; 392194149Simp uint16_t *ptr_16; 393194149Simp uint8_t *ptr_8; 394204789Sjmallett int error; 395194149Simp 396194149Simp//#define OCTEON_VISUAL_CF_1 1 397194149Simp#ifdef OCTEON_VISUAL_CF_1 398194149Simp octeon_led_write_char(1, 'W'); 399194149Simp#endif 400194149Simp lba = start_sector; 401194149Simp ptr_8 = (uint8_t*)buf; 402194149Simp ptr_16 = (uint16_t*)buf; 403194149Simp 404194149Simp while (nr_sectors--) { 405204789Sjmallett error = cf_send_cmd(lba, CMD_WRITE_SECTOR); 406204789Sjmallett if (error != 0) { 407204789Sjmallett printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error); 408204789Sjmallett return (error); 409204789Sjmallett } 410194149Simp 411222671Simp switch (bus_type) 412222671Simp { 413222671Simp case CF_8: 414194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 415222671Simp cf_outb_8(TF_DATA, *ptr_8++); 416222671Simp if ((count & 0xf) == 0) 417222671Simp (void)cf_inb_8(TF_STATUS); 418194149Simp } 419222671Simp break; 420222671Simp case CF_TRUE_IDE_8: 421222671Simp case CF_16: 422222671Simp default: 423194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 424194149Simp uint16_t temp = *ptr_16++; 425222671Simp cf_outw_16(TF_DATA, SWAP_SHORT(temp)); 426222671Simp if ((count & 0xf) == 0) 427222671Simp (void)cf_inb_16(TF_STATUS); 428194149Simp } 429222671Simp break; 430194149Simp } 431194149Simp 432222671Simp lba++; 433194149Simp } 434194149Simp#ifdef OCTEON_VISUAL_CF_1 435194149Simp octeon_led_write_char(1, ' '); 436194149Simp#endif 437204789Sjmallett return (0); 438194149Simp} 439194149Simp 440194149Simp 441194149Simp/* ------------------------------------------------------------------- * 442194149Simp * cf_cmd_identify() * 443194149Simp * ------------------------------------------------------------------- * 444194149Simp * 445194149Simp * Read parameters and other information from the drive and store 446194149Simp * it in the drive_param structure 447194149Simp * 448194149Simp */ 449204789Sjmallettstatic int cf_cmd_identify (void) 450194149Simp{ 451194149Simp int count; 452204789Sjmallett int error; 453194149Simp 454222671Simp error = cf_send_cmd(0, CMD_IDENTIFY); 455204789Sjmallett if (error != 0) { 456204789Sjmallett printf("%s: identify failed: %d\n", __func__, error); 457204789Sjmallett return (error); 458204789Sjmallett } 459222671Simp switch (bus_type) 460222671Simp { 461222671Simp case CF_8: 462222671Simp for (count = 0; count < SECTOR_SIZE; count++) 463222671Simp drive_param.u.buf[count] = cf_inb_8(TF_DATA); 464222671Simp break; 465222671Simp case CF_TRUE_IDE_8: 466222671Simp case CF_16: 467222671Simp default: 468222671Simp for (count = 0; count < SECTOR_SIZE; count += 2) { 469222671Simp uint16_t temp; 470222671Simp temp = cf_inw_16(TF_DATA); 471222671Simp 472222671Simp /* endianess will be swapped below */ 473222671Simp drive_param.u.buf[count] = (temp & 0xff); 474222671Simp drive_param.u.buf[count + 1] = (temp & 0xff00) >> 8; 475222671Simp } 476222671Simp break; 477222671Simp } 478194149Simp 479194149Simp cf_swap_ascii(drive_param.u.driveid.model, drive_param.model); 480194149Simp 481194149Simp drive_param.sector_size = 512; //= SWAP_SHORT (drive_param.u.driveid.sector_bytes); 482210311Sjmallett drive_param.heads = SWAP_SHORT (drive_param.u.driveid.current_heads); 483210311Sjmallett drive_param.tracks = SWAP_SHORT (drive_param.u.driveid.current_cylinders); 484210311Sjmallett drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.current_sectors); 485210311Sjmallett drive_param.nr_sectors = (uint32_t)SWAP_SHORT (drive_param.u.driveid.lba_size_1) | 486210311Sjmallett ((uint32_t)SWAP_SHORT (drive_param.u.driveid.lba_size_2)); 487222671Simp printf("cf0: <%s> %lld sectors\n", drive_param.model, (long long)drive_param.nr_sectors); 488194149Simp 489204789Sjmallett return (0); 490194149Simp} 491194149Simp 492194149Simp 493194149Simp/* ------------------------------------------------------------------- * 494194149Simp * cf_send_cmd() * 495194149Simp * ------------------------------------------------------------------- * 496194149Simp * 497194149Simp * Send command to read/write one sector specified by lba. 498194149Simp * 499194149Simp */ 500204789Sjmallettstatic int cf_send_cmd (uint32_t lba, uint8_t cmd) 501194149Simp{ 502222671Simp switch (bus_type) 503222671Simp { 504222671Simp case CF_8: 505222671Simp case CF_TRUE_IDE_8: 506222671Simp while (cf_inb_8(TF_STATUS) & STATUS_BSY) 507194149Simp DELAY(WAIT_DELAY); 508222671Simp cf_outb_8(TF_SECTOR_COUNT, 1); 509222671Simp cf_outb_8(TF_SECTOR_NUMBER, lba & 0xff); 510222671Simp cf_outb_8(TF_CYL_LSB, (lba >> 8) & 0xff); 511222671Simp cf_outb_8(TF_CYL_MSB, (lba >> 16) & 0xff); 512222671Simp cf_outb_8(TF_DRV_HEAD, ((lba >> 24) & 0xff) | 0xe0); 513222671Simp cf_outb_8(TF_COMMAND, cmd); 514222671Simp break; 515222671Simp case CF_16: 516222671Simp default: 517222671Simp while (cf_inb_16(TF_STATUS) & STATUS_BSY) 518194149Simp DELAY(WAIT_DELAY); 519222671Simp cf_outw_16(TF_SECTOR_COUNT, 1 | ((lba & 0xff) << 8)); 520222671Simp cf_outw_16(TF_CYL_LSB, ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8)); 521222671Simp cf_outw_16(TF_DRV_HEAD, (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8)); 522222671Simp break; 523194149Simp } 524194149Simp 525204789Sjmallett return (cf_wait_busy()); 526194149Simp} 527194149Simp 528194149Simp/* ------------------------------------------------------------------- * 529194149Simp * cf_wait_busy() * 530194149Simp * ------------------------------------------------------------------- * 531194149Simp * 532194149Simp * Wait until the drive finishes a given command and data is 533194149Simp * ready to be transferred. This is done by repeatedly checking 534204789Sjmallett * the BSY bit of the status register. When the controller is ready for 535204789Sjmallett * data transfer, it clears the BSY bit and sets the DRQ bit. 536194149Simp * 537204789Sjmallett * If the DF bit is ever set, we return error. 538204789Sjmallett * 539204789Sjmallett * This code originally spun on DRQ. If that behavior turns out to be 540204789Sjmallett * necessary, a flag can be added or this function can be called 541204789Sjmallett * repeatedly as long as it is returning ENXIO. 542194149Simp */ 543204789Sjmallettstatic int cf_wait_busy (void) 544194149Simp{ 545194149Simp uint8_t status; 546194149Simp 547194149Simp//#define OCTEON_VISUAL_CF_2 1 548194149Simp#ifdef OCTEON_VISUAL_CF_2 549194149Simp static int where0 = 0; 550194149Simp 551194149Simp octeon_led_run_wheel(&where0, 2); 552194149Simp#endif 553194149Simp 554222671Simp switch (bus_type) 555222671Simp { 556222671Simp case CF_8: 557222671Simp case CF_TRUE_IDE_8: 558222671Simp status = cf_inb_8(TF_STATUS); 559204789Sjmallett while ((status & STATUS_BSY) == STATUS_BSY) { 560204789Sjmallett if ((status & STATUS_DF) != 0) { 561204789Sjmallett printf("%s: device fault (status=%x)\n", __func__, status); 562204789Sjmallett return (EIO); 563204789Sjmallett } 564194149Simp DELAY(WAIT_DELAY); 565222671Simp status = cf_inb_8(TF_STATUS); 566194149Simp } 567222671Simp break; 568222671Simp case CF_16: 569222671Simp default: 570222671Simp status = cf_inb_16(TF_STATUS); 571204789Sjmallett while ((status & STATUS_BSY) == STATUS_BSY) { 572204789Sjmallett if ((status & STATUS_DF) != 0) { 573204789Sjmallett printf("%s: device fault (status=%x)\n", __func__, status); 574204789Sjmallett return (EIO); 575204789Sjmallett } 576194149Simp DELAY(WAIT_DELAY); 577222671Simp status = cf_inb_16(TF_STATUS); 578194149Simp } 579222671Simp break; 580194149Simp } 581204789Sjmallett if ((status & STATUS_DRQ) == 0) { 582204789Sjmallett printf("%s: device not ready (status=%x)\n", __func__, status); 583204789Sjmallett return (ENXIO); 584204789Sjmallett } 585194149Simp 586194149Simp#ifdef OCTEON_VISUAL_CF_2 587194149Simp octeon_led_write_char(2, ' '); 588194149Simp#endif 589204789Sjmallett return (0); 590194149Simp} 591194149Simp 592194149Simp/* ------------------------------------------------------------------- * 593194149Simp * cf_swap_ascii() * 594194149Simp * ------------------------------------------------------------------- * 595194149Simp * 596194149Simp * The ascii string returned by the controller specifying 597194149Simp * the model of the drive is byte-swaped. This routine 598194149Simp * corrects the byte ordering. 599194149Simp * 600194149Simp */ 601194149Simpstatic void cf_swap_ascii (unsigned char str1[], char str2[]) 602194149Simp{ 603194149Simp int i; 604194149Simp 605222671Simp for(i = 0; i < MODEL_STR_SIZE; i++) 606222671Simp str2[i] = str1[i ^ 1]; 607194149Simp} 608194149Simp 609194149Simp 610194149Simp/* ------------------------------------------------------------------- * 611194149Simp * cf_probe() * 612194149Simp * ------------------------------------------------------------------- */ 613194149Simp 614194149Simpstatic int cf_probe (device_t dev) 615194149Simp{ 616222671Simp if (octeon_is_simulation()) 617222671Simp return (ENXIO); 618194149Simp 619194149Simp if (device_get_unit(dev) != 0) { 620194149Simp panic("can't attach more devices\n"); 621194149Simp } 622194149Simp 623194149Simp device_set_desc(dev, "Octeon Compact Flash Driver"); 624194149Simp 625204789Sjmallett return (cf_cmd_identify()); 626194149Simp} 627194149Simp 628194149Simp/* ------------------------------------------------------------------- * 629194149Simp * cf_identify() * 630194149Simp * ------------------------------------------------------------------- * 631194149Simp * 632194149Simp * Find the bootbus region for the CF to determine 633194149Simp * 16 or 8 bit and check to see if device is 634194149Simp * inserted. 635194149Simp * 636194149Simp */ 637222671Simptypedef unsigned long long llu; 638194149Simpstatic void cf_identify (driver_t *drv, device_t parent) 639194149Simp{ 640194149Simp int bus_region; 641194149Simp int count = 0; 642210311Sjmallett cvmx_mio_boot_reg_cfgx_t cfg; 643194149Simp 644210311Sjmallett if (octeon_is_simulation()) 645194173Simp return; 646194149Simp 647210311Sjmallett base_addr = cvmx_phys_to_ptr(octeon_bootinfo->compact_flash_common_base_addr); 648194149Simp 649194149Simp for (bus_region = 0; bus_region < 8; bus_region++) 650194149Simp { 651210311Sjmallett cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(bus_region)); 652210311Sjmallett if (cfg.s.base == octeon_bootinfo->compact_flash_common_base_addr >> 16) 653194149Simp { 654222671Simp if (octeon_bootinfo->compact_flash_attribute_base_addr == 0) 655222671Simp bus_type = CF_TRUE_IDE_8; 656222671Simp else 657222671Simp bus_type = (cfg.s.width) ? CF_16 : CF_8; 658222671Simp printf("Compact flash found in bootbus region %d (%s).\n", bus_region, cf_type[bus_type]); 659194149Simp break; 660194149Simp } 661194149Simp } 662194149Simp 663222671Simp switch (bus_type) 664222671Simp { 665222671Simp case CF_8: 666222671Simp case CF_TRUE_IDE_8: 667194149Simp /* Check if CF is inserted */ 668222671Simp while (cf_inb_8(TF_STATUS) & STATUS_BSY) { 669222671Simp if ((count++) == NR_TRIES ) { 670194149Simp printf("Compact Flash not present\n"); 671194149Simp return; 672194149Simp } 673194149Simp DELAY(WAIT_DELAY); 674194149Simp } 675222671Simp break; 676222671Simp case CF_16: 677222671Simp default: 678194149Simp /* Check if CF is inserted */ 679222671Simp while (cf_inb_16(TF_STATUS) & STATUS_BSY) { 680222671Simp if ((count++) == NR_TRIES ) { 681194149Simp printf("Compact Flash not present\n"); 682194149Simp return; 683194149Simp } 684194149Simp DELAY(WAIT_DELAY); 685194149Simp } 686222671Simp break; 687194149Simp } 688194149Simp 689194149Simp BUS_ADD_CHILD(parent, 0, "cf", 0); 690194149Simp} 691194149Simp 692194149Simp 693194149Simp/* ------------------------------------------------------------------- * 694194149Simp * cf_attach_geom() * 695194149Simp * ------------------------------------------------------------------- */ 696194149Simp 697194149Simpstatic int cf_attach_geom (void *arg, int flag) 698194149Simp{ 699194149Simp struct cf_priv *cf_priv; 700194149Simp 701194149Simp cf_priv = (struct cf_priv *) arg; 702194149Simp cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev)); 703194149Simp cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name); 704194149Simp cf_priv->cf_geom->softc = cf_priv; 705194149Simp g_error_provider(cf_priv->cf_provider, 0); 706194149Simp 707194149Simp return (0); 708194149Simp} 709194149Simp 710194149Simp/* ------------------------------------------------------------------- * 711194149Simp * cf_attach_geom() * 712194149Simp * ------------------------------------------------------------------- */ 713194149Simpstatic void cf_attach_geom_proxy (void *arg, int flag) 714194149Simp{ 715222671Simp cf_attach_geom(arg, flag); 716194149Simp} 717194149Simp 718194149Simp 719194149Simp 720194149Simp/* ------------------------------------------------------------------- * 721194149Simp * cf_attach() * 722194149Simp * ------------------------------------------------------------------- */ 723194149Simp 724194149Simpstatic int cf_attach (device_t dev) 725194149Simp{ 726194149Simp struct cf_priv *cf_priv; 727194149Simp 728222671Simp if (octeon_is_simulation()) 729222671Simp return (ENXIO); 730194149Simp 731194149Simp cf_priv = device_get_softc(dev); 732194149Simp cf_priv->dev = dev; 733194149Simp cf_priv->drive_param = &drive_param; 734194149Simp 735194149Simp g_post_event(cf_attach_geom_proxy, cf_priv, M_WAITOK, NULL); 736194149Simp bioq_init(&cf_priv->cf_bq); 737194149Simp 738194149Simp return 0; 739194149Simp} 740194149Simp 741194149Simp 742194149Simpstatic device_method_t cf_methods[] = { 743194149Simp /* Device interface */ 744194149Simp DEVMETHOD(device_probe, cf_probe), 745194149Simp DEVMETHOD(device_identify, cf_identify), 746194149Simp DEVMETHOD(device_attach, cf_attach), 747194149Simp DEVMETHOD(device_detach, bus_generic_detach), 748194149Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 749194149Simp 750194149Simp { 0, 0 } 751194149Simp}; 752194149Simp 753194149Simpstatic driver_t cf_driver = { 754194149Simp "cf", 755194149Simp cf_methods, 756194149Simp sizeof(struct cf_priv) 757194149Simp}; 758194149Simp 759194149Simpstatic devclass_t cf_devclass; 760194149Simp 761194149SimpDRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0); 762