octeon_ebt3000_cf.c revision 203130
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 203130 2010-01-28 20:46:40Z imp $"); 46194149Simp 47194149Simp#include <sys/param.h> 48194149Simp#include <sys/bio.h> 49194149Simp#include <sys/systm.h> 50194149Simp#include <sys/sysctl.h> 51194149Simp#include <sys/bus.h> 52194149Simp#include <sys/kernel.h> 53194149Simp#include <sys/module.h> 54194149Simp#include <sys/rman.h> 55194149Simp#include <sys/power.h> 56194149Simp#include <sys/smp.h> 57194149Simp#include <sys/time.h> 58194149Simp#include <sys/timetc.h> 59194149Simp#include <sys/malloc.h> 60194149Simp 61194149Simp#include <geom/geom.h> 62194149Simp 63194149Simp#include <machine/clock.h> 64194149Simp#include <machine/locore.h> 65194149Simp#include <machine/md_var.h> 66194149Simp#include <machine/cpuregs.h> 67194149Simp 68194149Simp#include "octeon_ebt3000_cf.h" 69194149Simp#include "driveid.h" 70202063Simp#include <mips/cavium/octeon_pcmap_regs.h> 71194149Simp 72194149Simp/* ATA Commands */ 73194149Simp#define CMD_READ_SECTOR 0x20 74194149Simp#define CMD_WRITE_SECTOR 0x30 75194149Simp#define CMD_IDENTIFY 0xEC 76194149Simp 77194149Simp/* The ATA Task File */ 78194149Simp#define TF_DATA 0x00 79194149Simp#define TF_ERROR 0x01 80194149Simp#define TF_PRECOMP 0x01 81194149Simp#define TF_SECTOR_COUNT 0x02 82194149Simp#define TF_SECTOR_NUMBER 0x03 83194149Simp#define TF_CYL_LSB 0x04 84194149Simp#define TF_CYL_MSB 0x05 85194149Simp#define TF_DRV_HEAD 0x06 86194149Simp#define TF_STATUS 0x07 87194149Simp#define TF_COMMAND 0x07 88194149Simp 89194149Simp/* Status Register */ 90194149Simp#define STATUS_BSY 0x80 /* Drive is busy */ 91194149Simp#define STATUS_RDY 0x40 /* Drive is ready */ 92194149Simp#define STATUS_DRQ 0x08 /* Data can be transferred */ 93194149Simp 94194149Simp/* Miscelaneous */ 95194149Simp#define SECTOR_SIZE 512 96194149Simp#define WAIT_DELAY 1000 97194149Simp#define NR_TRIES 1000 98194149Simp#define SWAP_SHORT(x) ((x << 8) | (x >> 8)) 99194149Simp#define SWAP_LONG(x) (((x << 24) & 0xFF000000) | ((x << 8) & 0x00FF0000) | \ 100194149Simp ((x >> 8) & 0x0000FF00) | ((x << 24) & 0x000000FF) ) 101194149Simp#define MODEL_STR_SIZE 40 102194149Simp 103194149Simp 104194149Simp/* Globals */ 105194149Simpint bus_width; 106194149Simpvoid *base_addr; 107194149Simp 108194149Simp/* Device softc */ 109194149Simpstruct cf_priv { 110194149Simp 111194149Simp device_t dev; 112194149Simp struct drive_param *drive_param; 113194149Simp 114194149Simp struct bio_queue_head cf_bq; 115194149Simp struct g_geom *cf_geom; 116194149Simp struct g_provider *cf_provider; 117194149Simp 118194149Simp}; 119194149Simp 120194149Simp/* Device parameters */ 121194149Simpstruct drive_param{ 122194149Simp union { 123194149Simp char buf[SECTOR_SIZE]; 124194149Simp struct hd_driveid driveid; 125194149Simp } u; 126194149Simp 127194149Simp char model[MODEL_STR_SIZE]; 128194149Simp uint32_t nr_sectors; 129194149Simp uint16_t sector_size; 130194149Simp uint16_t heads; 131194149Simp uint16_t tracks; 132194149Simp uint16_t sec_track; 133194149Simp 134194149Simp} drive_param; 135194149Simp 136194149Simp/* GEOM class implementation */ 137194149Simpstatic g_access_t cf_access; 138194149Simpstatic g_start_t cf_start; 139194149Simpstatic g_ioctl_t cf_ioctl; 140194149Simp 141194149Simpstruct g_class g_cf_class = { 142194149Simp .name = "CF", 143194149Simp .version = G_VERSION, 144194149Simp .start = cf_start, 145194149Simp .access = cf_access, 146194149Simp .ioctl = cf_ioctl, 147194149Simp}; 148194149Simp 149194149Simp/* Device methods */ 150194149Simpstatic int cf_probe(device_t); 151194149Simpstatic void cf_identify(driver_t *, device_t); 152194149Simpstatic int cf_attach(device_t); 153194149Simpstatic int cf_attach_geom(void *, int); 154194149Simp 155194149Simp/* ATA methods */ 156194149Simpstatic void cf_cmd_identify(void); 157194149Simpstatic void cf_cmd_write(uint32_t, uint32_t, void *); 158194149Simpstatic void cf_cmd_read(uint32_t, uint32_t, void *); 159194149Simpstatic void cf_wait_busy(void); 160194149Simpstatic void cf_send_cmd(uint32_t, uint8_t); 161194149Simpstatic void cf_attach_geom_proxy(void *arg, int flag); 162194149Simp 163194149Simp/* Miscelenous */ 164194149Simpstatic void cf_swap_ascii(unsigned char[], char[]); 165194149Simp 166194149Simp 167194149Simp/* ------------------------------------------------------------------- * 168194149Simp * cf_access() * 169194149Simp * ------------------------------------------------------------------- */ 170194149Simpstatic int cf_access (struct g_provider *pp, int r, int w, int e) 171194149Simp{ 172194149Simp 173194149Simp pp->sectorsize = drive_param.sector_size; 174194149Simp pp->stripesize = drive_param.heads * drive_param.sec_track * drive_param.sector_size; 175194149Simp pp->mediasize = pp->stripesize * drive_param.tracks; 176194149Simp 177194149Simp return (0); 178194149Simp} 179194149Simp 180194149Simp 181194149Simp/* ------------------------------------------------------------------- * 182194149Simp * cf_start() * 183194149Simp * ------------------------------------------------------------------- */ 184194149Simpstatic void cf_start (struct bio *bp) 185194149Simp{ 186194149Simp /* 187194149Simp * Handle actual I/O requests. The request is passed down through 188194149Simp * the bio struct. 189194149Simp */ 190194149Simp 191194149Simp if(bp->bio_cmd & BIO_GETATTR) { 192194149Simp if (g_handleattr_int(bp, "GEOM::fwsectors", drive_param.sec_track)) 193194149Simp return; 194194149Simp if (g_handleattr_int(bp, "GEOM::fwheads", drive_param.heads)) 195194149Simp return; 196194149Simp g_io_deliver(bp, ENOIOCTL); 197194149Simp return; 198194149Simp } 199194149Simp 200194149Simp if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { 201194149Simp 202194149Simp if (bp->bio_cmd & BIO_READ) { 203194149Simp cf_cmd_read(bp->bio_length / drive_param.sector_size, 204194149Simp bp->bio_offset / drive_param.sector_size, bp->bio_data); 205194149Simp 206194149Simp } else if (bp->bio_cmd & BIO_WRITE) { 207194149Simp cf_cmd_write(bp->bio_length / drive_param.sector_size, 208194149Simp bp->bio_offset/drive_param.sector_size, bp->bio_data); 209194149Simp } 210194149Simp 211194149Simp bp->bio_resid = 0; 212194149Simp bp->bio_completed = bp->bio_length; 213194149Simp g_io_deliver(bp, 0); 214194149Simp } 215194149Simp} 216194149Simp 217194149Simp 218194149Simpstatic int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 219194149Simp{ 220194149Simp return (0); 221194149Simp} 222194149Simp 223194149Simp 224194149Simp/* ------------------------------------------------------------------- * 225194149Simp * cf_cmd_read() * 226194149Simp * ------------------------------------------------------------------- * 227194149Simp * 228194149Simp * Read nr_sectors from the device starting from start_sector. 229194149Simp */ 230194149Simpstatic void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) 231194149Simp{ 232194149Simp unsigned long lba; 233194149Simp uint32_t count; 234194149Simp uint16_t *ptr_16; 235194149Simp uint8_t *ptr_8; 236194149Simp 237194149Simp//#define OCTEON_VISUAL_CF_0 1 238194149Simp#ifdef OCTEON_VISUAL_CF_0 239194149Simp octeon_led_write_char(0, 'R'); 240194149Simp#endif 241194149Simp ptr_8 = (uint8_t*)buf; 242194149Simp ptr_16 = (uint16_t*)buf; 243194149Simp lba = start_sector; 244194149Simp 245194149Simp 246194149Simp while (nr_sectors--) { 247194149Simp 248194149Simp cf_send_cmd(lba, CMD_READ_SECTOR); 249194149Simp 250194149Simp if (bus_width == 8) { 251194149Simp volatile uint8_t *task_file = (volatile uint8_t*)base_addr; 252194149Simp volatile uint8_t dummy; 253194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 254194149Simp *ptr_8++ = task_file[TF_DATA]; 255194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS]; 256194149Simp } 257194149Simp } else { 258194149Simp volatile uint16_t *task_file = (volatile uint16_t*)base_addr; 259194149Simp volatile uint16_t dummy; 260194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 261194149Simp uint16_t temp; 262194149Simp temp = task_file[TF_DATA]; 263194149Simp *ptr_16++ = SWAP_SHORT(temp); 264194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2]; 265194149Simp } 266194149Simp } 267194149Simp 268194149Simp lba ++; 269194149Simp } 270194149Simp#ifdef OCTEON_VISUAL_CF_0 271194149Simp octeon_led_write_char(0, ' '); 272194149Simp#endif 273194149Simp} 274194149Simp 275194149Simp 276194149Simp/* ------------------------------------------------------------------- * 277194149Simp * cf_cmd_write() * 278194149Simp * ------------------------------------------------------------------- * 279194149Simp * 280194149Simp * Write nr_sectors to the device starting from start_sector. 281194149Simp */ 282194149Simpstatic void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) 283194149Simp{ 284194149Simp uint32_t lba; 285194149Simp uint32_t count; 286194149Simp uint16_t *ptr_16; 287194149Simp uint8_t *ptr_8; 288194149Simp 289194149Simp//#define OCTEON_VISUAL_CF_1 1 290194149Simp#ifdef OCTEON_VISUAL_CF_1 291194149Simp octeon_led_write_char(1, 'W'); 292194149Simp#endif 293194149Simp lba = start_sector; 294194149Simp ptr_8 = (uint8_t*)buf; 295194149Simp ptr_16 = (uint16_t*)buf; 296194149Simp 297194149Simp while (nr_sectors--) { 298194149Simp 299194149Simp cf_send_cmd(lba, CMD_WRITE_SECTOR); 300194149Simp 301194149Simp if (bus_width == 8) { 302194149Simp volatile uint8_t *task_file; 303194149Simp volatile uint8_t dummy; 304194149Simp 305194149Simp task_file = (volatile uint8_t *) base_addr; 306194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 307194149Simp task_file[TF_DATA] = *ptr_8++; 308194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS]; 309194149Simp } 310194149Simp } else { 311194149Simp volatile uint16_t *task_file; 312194149Simp volatile uint16_t dummy; 313194149Simp 314194149Simp task_file = (volatile uint16_t *) base_addr; 315194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 316194149Simp uint16_t temp = *ptr_16++; 317194149Simp task_file[TF_DATA] = SWAP_SHORT(temp); 318194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2]; 319194149Simp } 320194149Simp } 321194149Simp 322194149Simp lba ++; 323194149Simp } 324194149Simp#ifdef OCTEON_VISUAL_CF_1 325194149Simp octeon_led_write_char(1, ' '); 326194149Simp#endif 327194149Simp} 328194149Simp 329194149Simp 330194149Simp/* ------------------------------------------------------------------- * 331194149Simp * cf_cmd_identify() * 332194149Simp * ------------------------------------------------------------------- * 333194149Simp * 334194149Simp * Read parameters and other information from the drive and store 335194149Simp * it in the drive_param structure 336194149Simp * 337194149Simp */ 338194149Simpstatic void cf_cmd_identify (void) 339194149Simp{ 340194149Simp int count; 341194149Simp uint8_t status; 342194149Simp 343194149Simp if (bus_width == 8) { 344194149Simp volatile uint8_t *task_file; 345194149Simp 346194149Simp task_file = (volatile uint8_t *) base_addr; 347194149Simp 348194149Simp while ((status = task_file[TF_STATUS]) & STATUS_BSY) { 349194149Simp DELAY(WAIT_DELAY); 350194149Simp } 351194149Simp 352194149Simp task_file[TF_SECTOR_COUNT] = 0; 353194149Simp task_file[TF_SECTOR_NUMBER] = 0; 354194149Simp task_file[TF_CYL_LSB] = 0; 355194149Simp task_file[TF_CYL_MSB] = 0; 356194149Simp task_file[TF_DRV_HEAD] = 0; 357194149Simp task_file[TF_COMMAND] = CMD_IDENTIFY; 358194149Simp 359194149Simp cf_wait_busy(); 360194149Simp 361194149Simp for (count = 0; count < SECTOR_SIZE; count++) 362194149Simp drive_param.u.buf[count] = task_file[TF_DATA]; 363194149Simp 364194149Simp } else { 365194149Simp volatile uint16_t *task_file; 366194149Simp 367194149Simp task_file = (volatile uint16_t *) base_addr; 368194149Simp 369194149Simp while ((status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) { 370194149Simp DELAY(WAIT_DELAY); 371194149Simp } 372194149Simp 373194149Simp task_file[TF_SECTOR_COUNT/2] = 0; /* this includes TF_SECTOR_NUMBER */ 374194149Simp task_file[TF_CYL_LSB/2] = 0; /* this includes TF_CYL_MSB */ 375194149Simp task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */ 376194149Simp 377194149Simp cf_wait_busy(); 378194149Simp 379194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 380194149Simp uint16_t temp; 381194149Simp temp = task_file[TF_DATA]; 382194149Simp 383194149Simp /* endianess will be swapped below */ 384194149Simp drive_param.u.buf[count] = (temp & 0xff); 385194149Simp drive_param.u.buf[count+1] = (temp & 0xff00)>>8; 386194149Simp } 387194149Simp } 388194149Simp 389194149Simp cf_swap_ascii(drive_param.u.driveid.model, drive_param.model); 390194149Simp 391194149Simp drive_param.sector_size = 512; //= SWAP_SHORT (drive_param.u.driveid.sector_bytes); 392194149Simp drive_param.heads = SWAP_SHORT (drive_param.u.driveid.cur_heads); 393194149Simp drive_param.tracks = SWAP_SHORT (drive_param.u.driveid.cur_cyls); 394194149Simp drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.cur_sectors); 395194149Simp drive_param.nr_sectors = SWAP_LONG (drive_param.u.driveid.lba_capacity); 396194149Simp 397194149Simp} 398194149Simp 399194149Simp 400194149Simp/* ------------------------------------------------------------------- * 401194149Simp * cf_send_cmd() * 402194149Simp * ------------------------------------------------------------------- * 403194149Simp * 404194149Simp * Send command to read/write one sector specified by lba. 405194149Simp * 406194149Simp */ 407194149Simpstatic void cf_send_cmd (uint32_t lba, uint8_t cmd) 408194149Simp{ 409194149Simp uint8_t status; 410194149Simp 411194149Simp if (bus_width == 8) { 412194149Simp volatile uint8_t *task_file; 413194149Simp 414194149Simp task_file = (volatile uint8_t *) base_addr; 415194149Simp 416194149Simp while ( (status = task_file[TF_STATUS]) & STATUS_BSY) { 417194149Simp DELAY(WAIT_DELAY); 418194149Simp } 419194149Simp 420194149Simp task_file[TF_SECTOR_COUNT] = 1; 421194149Simp task_file[TF_SECTOR_NUMBER] = (lba & 0xff); 422194149Simp task_file[TF_CYL_LSB] = ((lba >> 8) & 0xff); 423194149Simp task_file[TF_CYL_MSB] = ((lba >> 16) & 0xff); 424194149Simp task_file[TF_DRV_HEAD] = ((lba >> 24) & 0xff) | 0xe0; 425194149Simp task_file[TF_COMMAND] = cmd; 426194149Simp 427194149Simp } else { 428194149Simp volatile uint16_t *task_file; 429194149Simp 430194149Simp task_file = (volatile uint16_t *) base_addr; 431194149Simp 432194149Simp while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) { 433194149Simp DELAY(WAIT_DELAY); 434194149Simp } 435194149Simp 436194149Simp task_file[TF_SECTOR_COUNT/2] = 1 | ((lba & 0xff) << 8); 437194149Simp task_file[TF_CYL_LSB/2] = ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8); 438194149Simp task_file[TF_DRV_HEAD/2] = (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8); 439194149Simp 440194149Simp } 441194149Simp 442194149Simp cf_wait_busy(); 443194149Simp} 444194149Simp 445194149Simp/* ------------------------------------------------------------------- * 446194149Simp * cf_wait_busy() * 447194149Simp * ------------------------------------------------------------------- * 448194149Simp * 449194149Simp * Wait until the drive finishes a given command and data is 450194149Simp * ready to be transferred. This is done by repeatedly checking 451194149Simp * the BSY and DRQ bits of the status register. When the controller 452194149Simp * is ready for data transfer, it clears the BSY bit and sets the 453194149Simp * DRQ bit. 454194149Simp * 455194149Simp */ 456194149Simpstatic void cf_wait_busy (void) 457194149Simp{ 458194149Simp uint8_t status; 459194149Simp 460194149Simp//#define OCTEON_VISUAL_CF_2 1 461194149Simp#ifdef OCTEON_VISUAL_CF_2 462194149Simp static int where0 = 0; 463194149Simp 464194149Simp octeon_led_run_wheel(&where0, 2); 465194149Simp#endif 466194149Simp 467194149Simp if (bus_width == 8) { 468194149Simp volatile uint8_t *task_file; 469194149Simp task_file = (volatile uint8_t *)base_addr; 470194149Simp 471194149Simp status = task_file[TF_STATUS]; 472194149Simp while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { 473194149Simp DELAY(WAIT_DELAY); 474194149Simp status = task_file[TF_STATUS]; 475194149Simp } 476194149Simp } else { 477194149Simp volatile uint16_t *task_file; 478194149Simp task_file = (volatile uint16_t *)base_addr; 479194149Simp 480194149Simp status = task_file[TF_STATUS/2]>>8; 481194149Simp while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { 482194149Simp DELAY(WAIT_DELAY); 483194149Simp status = (uint8_t)(task_file[TF_STATUS/2]>>8); 484194149Simp } 485194149Simp } 486194149Simp 487194149Simp#ifdef OCTEON_VISUAL_CF_2 488194149Simp octeon_led_write_char(2, ' '); 489194149Simp#endif 490194149Simp} 491194149Simp 492194149Simp/* ------------------------------------------------------------------- * 493194149Simp * cf_swap_ascii() * 494194149Simp * ------------------------------------------------------------------- * 495194149Simp * 496194149Simp * The ascii string returned by the controller specifying 497194149Simp * the model of the drive is byte-swaped. This routine 498194149Simp * corrects the byte ordering. 499194149Simp * 500194149Simp */ 501194149Simpstatic void cf_swap_ascii (unsigned char str1[], char str2[]) 502194149Simp{ 503194149Simp int i; 504194149Simp 505194149Simp for(i = 0; i < MODEL_STR_SIZE; i++) { 506194149Simp str2[i] = str1[i^1]; 507194149Simp } 508194149Simp} 509194149Simp 510194149Simp 511194149Simp/* ------------------------------------------------------------------- * 512194149Simp * cf_probe() * 513194149Simp * ------------------------------------------------------------------- */ 514194149Simp 515194149Simpstatic int cf_probe (device_t dev) 516194149Simp{ 517194149Simp if (!octeon_board_real()) return 1; 518194149Simp 519194149Simp if (device_get_unit(dev) != 0) { 520194149Simp panic("can't attach more devices\n"); 521194149Simp } 522194149Simp 523194149Simp device_set_desc(dev, "Octeon Compact Flash Driver"); 524194149Simp 525194149Simp cf_cmd_identify(); 526194149Simp 527194149Simp return (0); 528194149Simp} 529194149Simp 530194149Simp/* ------------------------------------------------------------------- * 531194149Simp * cf_identify() * 532194149Simp * ------------------------------------------------------------------- * 533194149Simp * 534194149Simp * Find the bootbus region for the CF to determine 535194149Simp * 16 or 8 bit and check to see if device is 536194149Simp * inserted. 537194149Simp * 538194149Simp */ 539194149Simpstatic void cf_identify (driver_t *drv, device_t parent) 540194149Simp{ 541194149Simp uint8_t status; 542194149Simp int bus_region; 543194149Simp int count = 0; 544194149Simp octeon_mio_boot_reg_cfgx_t cfg; 545194149Simp 546194149Simp 547194173Simp if (!octeon_board_real()) 548194173Simp return; 549194149Simp 550195414Simp base_addr = (void *) MIPS_PHYS_TO_KSEG0(OCTEON_CF_COMMON_BASE_ADDR); 551194149Simp 552194149Simp for (bus_region = 0; bus_region < 8; bus_region++) 553194149Simp { 554194149Simp cfg.word64 = oct_read64(OCTEON_MIO_BOOT_REG_CFGX(bus_region)); 555194149Simp if (cfg.bits.base == OCTEON_CF_COMMON_BASE_ADDR >> 16) 556194149Simp { 557194149Simp bus_width = (cfg.bits.width) ? 16: 8; 558194149Simp printf("Compact flash found in bootbus region %d (%d bit).\n", bus_region, bus_width); 559194149Simp break; 560194149Simp } 561194149Simp } 562194149Simp 563194149Simp if (bus_width == 8) { 564194149Simp volatile uint8_t *task_file; 565194149Simp task_file = (volatile uint8_t *) base_addr; 566194149Simp /* Check if CF is inserted */ 567194149Simp while ( (status = task_file[TF_STATUS]) & STATUS_BSY){ 568194149Simp if ((count++) == NR_TRIES ) { 569194149Simp printf("Compact Flash not present\n"); 570194149Simp return; 571194149Simp } 572194149Simp DELAY(WAIT_DELAY); 573194149Simp } 574194149Simp } else { 575194149Simp volatile uint16_t *task_file; 576194149Simp task_file = (volatile uint16_t *) base_addr; 577194149Simp /* Check if CF is inserted */ 578194149Simp while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY){ 579194149Simp if ((count++) == NR_TRIES ) { 580194149Simp printf("Compact Flash not present\n"); 581194149Simp return; 582194149Simp } 583194149Simp DELAY(WAIT_DELAY); 584194149Simp } 585194149Simp } 586194149Simp 587194149Simp BUS_ADD_CHILD(parent, 0, "cf", 0); 588194149Simp} 589194149Simp 590194149Simp 591194149Simp/* ------------------------------------------------------------------- * 592194149Simp * cf_attach_geom() * 593194149Simp * ------------------------------------------------------------------- */ 594194149Simp 595194149Simpstatic int cf_attach_geom (void *arg, int flag) 596194149Simp{ 597194149Simp struct cf_priv *cf_priv; 598194149Simp 599194149Simp cf_priv = (struct cf_priv *) arg; 600194149Simp cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev)); 601194149Simp cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name); 602194149Simp cf_priv->cf_geom->softc = cf_priv; 603194149Simp g_error_provider(cf_priv->cf_provider, 0); 604194149Simp 605194149Simp return (0); 606194149Simp} 607194149Simp 608194149Simp/* ------------------------------------------------------------------- * 609194149Simp * cf_attach_geom() * 610194149Simp * ------------------------------------------------------------------- */ 611194149Simpstatic void cf_attach_geom_proxy (void *arg, int flag) 612194149Simp{ 613194149Simp cf_attach_geom(arg, flag); 614194149Simp} 615194149Simp 616194149Simp 617194149Simp 618194149Simp/* ------------------------------------------------------------------- * 619194149Simp * cf_attach() * 620194149Simp * ------------------------------------------------------------------- */ 621194149Simp 622194149Simpstatic int cf_attach (device_t dev) 623194149Simp{ 624194149Simp struct cf_priv *cf_priv; 625194149Simp 626194149Simp if (!octeon_board_real()) return 1; 627194149Simp 628194149Simp cf_priv = device_get_softc(dev); 629194149Simp cf_priv->dev = dev; 630194149Simp cf_priv->drive_param = &drive_param; 631194149Simp 632194149Simp g_post_event(cf_attach_geom_proxy, cf_priv, M_WAITOK, NULL); 633194149Simp bioq_init(&cf_priv->cf_bq); 634194149Simp 635194149Simp return 0; 636194149Simp} 637194149Simp 638194149Simp 639194149Simpstatic device_method_t cf_methods[] = { 640194149Simp /* Device interface */ 641194149Simp DEVMETHOD(device_probe, cf_probe), 642194149Simp DEVMETHOD(device_identify, cf_identify), 643194149Simp DEVMETHOD(device_attach, cf_attach), 644194149Simp DEVMETHOD(device_detach, bus_generic_detach), 645194149Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 646194149Simp 647194149Simp { 0, 0 } 648194149Simp}; 649194149Simp 650194149Simpstatic driver_t cf_driver = { 651194149Simp "cf", 652194149Simp cf_methods, 653194149Simp sizeof(struct cf_priv) 654194149Simp}; 655194149Simp 656194149Simpstatic devclass_t cf_devclass; 657194149Simp 658194149SimpDRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0); 659194149Simp 660