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