mirror of
https://gitlab.com/qemu-project/openbios.git
synced 2024-02-13 08:34:06 +08:00
more of the sparc32 port by Blue Swirl <blueswir1@hotmail.com>
git-svn-id: svn://coreboot.org/openbios/openbios-devel@4 f158a5a8-5612-0410-a976-696ce0be7e32
This commit is contained in:
377
drivers/esp.c
Normal file
377
drivers/esp.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* OpenBIOS ESP driver
|
||||
*
|
||||
* Copyright (C) 2004 Jens Axboe <axboe@suse.de>
|
||||
* Copyright (C) 2005 Stefan Reinauer <stepan@openbios.org>
|
||||
*
|
||||
* Credit goes to Hale Landis for his excellent ata demo software
|
||||
* OF node handling and some fixes by Stefan Reinauer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "openbios/config.h"
|
||||
#include "openbios/bindings.h"
|
||||
#include "openbios/kernel.h"
|
||||
#include "libc/byteorder.h"
|
||||
#include "libc/vsprintf.h"
|
||||
|
||||
#include "openbios/drivers.h"
|
||||
#include "asm/dma.h"
|
||||
|
||||
#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */
|
||||
#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
|
||||
|
||||
#define REGISTER_NAMED_NODE( name, path ) do { \
|
||||
bind_new_node( name##_flags_, name##_size_, \
|
||||
path, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
||||
} while(0)
|
||||
|
||||
#define REGISTER_NODE_METHODS( name, path ) do { \
|
||||
char *paths[1]; \
|
||||
\
|
||||
paths[0] = path; \
|
||||
bind_node( name##_flags_, name##_size_, \
|
||||
paths, 1, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
||||
} while(0)
|
||||
|
||||
struct esp_dma {
|
||||
struct sparc_dma_registers *regs;
|
||||
enum dvma_rev revision;
|
||||
};
|
||||
|
||||
typedef struct sd_private {
|
||||
unsigned int id;
|
||||
unsigned int hw_sector;
|
||||
} sd_private_t;
|
||||
|
||||
struct esp_regs {
|
||||
unsigned int regs[16];
|
||||
};
|
||||
|
||||
typedef struct esp_private {
|
||||
volatile struct esp_regs *ll;
|
||||
__u32 buffer_dvma;
|
||||
unsigned int irq; /* device IRQ number */
|
||||
|
||||
struct esp_dma *espdma; /* If set this points to espdma */
|
||||
|
||||
unsigned char *buffer;
|
||||
} esp_private_t;
|
||||
|
||||
/* DECLARE data structures for the nodes. */
|
||||
DECLARE_UNNAMED_NODE(ob_sd, INSTALL_OPEN, sizeof(sd_private_t));
|
||||
DECLARE_UNNAMED_NODE(ob_esp, INSTALL_OPEN, sizeof(esp_private_t));
|
||||
|
||||
// offset is multiple of 512, len in bytes
|
||||
static int
|
||||
ob_sd_read_sectors(sd_private_t *sd, int offset, void *dest, short len)
|
||||
{
|
||||
#if 0
|
||||
unsigned char *buffer = malloc(2048); // XXX setup dvma
|
||||
|
||||
// Set SCSI target
|
||||
outb(PHYS_JJ_ESP + 4*4, sd->id & 7);
|
||||
// Set DMA address
|
||||
outl(PHYS_JJ_ESPDMA + 4, buffer);
|
||||
// Set DMA length
|
||||
outb(PHYS_JJ_ESP + 0*4, 10);
|
||||
outb(PHYS_JJ_ESP + 1*4, 0);
|
||||
// Set DMA direction
|
||||
outl(PHYS_JJ_ESPDMA + 0, 0x000);
|
||||
// Setup command = Read(10)
|
||||
buffer[0] = 0x80;
|
||||
buffer[1] = 0x28;
|
||||
buffer[2] = 0x00;
|
||||
buffer[3] = (offset >> 24) & 0xff;
|
||||
buffer[4] = (offset >> 16) & 0xff;
|
||||
buffer[5] = (offset >> 8) & 0xff;
|
||||
buffer[6] = offset & 0xff;
|
||||
buffer[7] = 0x00;
|
||||
buffer[8] = ((len / 512) >> 8) & 0xff;
|
||||
buffer[9] = (len / 512) & 0xff;
|
||||
// Set ATN, issue command
|
||||
outb(PHYS_JJ_ESP + 3*4, 0xc2);
|
||||
|
||||
// Set DMA length
|
||||
outb(PHYS_JJ_ESP + 0*4, len & 0xff);
|
||||
outb(PHYS_JJ_ESP + 1*4, (len >> 8) & 0xff);
|
||||
// Set DMA direction
|
||||
outl(PHYS_JJ_ESPDMA + 0, 0x100);
|
||||
// Transfer
|
||||
outb(PHYS_JJ_ESP + 3*4, 0x90);
|
||||
memcpy(buffer, dest, len);
|
||||
free(buffer);
|
||||
#endif
|
||||
return 0 * sd->id * offset * len * (int)dest;
|
||||
}
|
||||
|
||||
static void
|
||||
ob_sd_read_blocks(sd_private_t *sd)
|
||||
{
|
||||
cell n = POP(), cnt=n;
|
||||
ucell blk = POP();
|
||||
char *dest = (char*)POP();
|
||||
|
||||
#ifdef CONFIG_DEBUG_ESP
|
||||
printk("ob_sd_read_blocks %lx block=%d n=%d\n", (unsigned long)dest, blk, n );
|
||||
#endif
|
||||
while (n) {
|
||||
int len = n;
|
||||
|
||||
if (ob_sd_read_sectors(sd, blk, dest, len)) {
|
||||
printk("ob_ide_read_blocks: error\n");
|
||||
RET(0);
|
||||
}
|
||||
dest += len * sd->hw_sector;
|
||||
n -= len;
|
||||
blk += len;
|
||||
}
|
||||
PUSH(cnt);
|
||||
}
|
||||
|
||||
static void
|
||||
ob_sd_block_size(sd_private_t *sd)
|
||||
{
|
||||
PUSH(sd->hw_sector);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_block_size(sd_private_t *sd)
|
||||
{
|
||||
#if 1
|
||||
return 512 + sd->id * 0; // XXX
|
||||
#else
|
||||
unsigned char *buffer = malloc(64); // XXX setup dvma
|
||||
unsigned int ret;
|
||||
|
||||
// Set SCSI target
|
||||
outb(PHYS_JJ_ESP + 4*4, sd->id & 7);
|
||||
// Set DMA address
|
||||
outl(PHYS_JJ_ESPDMA + 4, buffer);
|
||||
// Set DMA length
|
||||
outb(PHYS_JJ_ESP + 0*4, 10);
|
||||
outb(PHYS_JJ_ESP + 1*4, 0);
|
||||
// Set DMA direction
|
||||
outl(PHYS_JJ_ESPDMA + 0, 0x000);
|
||||
// Setup command = Read Capacity
|
||||
buffer[0] = 0x80;
|
||||
buffer[1] = 0x25;
|
||||
buffer[2] = 0x00;
|
||||
buffer[3] = 0x00;
|
||||
buffer[4] = 0x00;
|
||||
buffer[5] = 0x00;
|
||||
buffer[6] = 0x00;
|
||||
buffer[7] = 0x00;
|
||||
buffer[8] = 0x00;
|
||||
buffer[9] = 0x00;
|
||||
buffer[10] = 0x00;
|
||||
// Set ATN, issue command
|
||||
outb(PHYS_JJ_ESP + 3*4, 0xc2);
|
||||
|
||||
// Set DMA length
|
||||
outb(PHYS_JJ_ESP + 0*4, 0);
|
||||
outb(PHYS_JJ_ESP + 1*4, 8 & 0xff);
|
||||
// Set DMA direction
|
||||
outl(PHYS_JJ_ESPDMA + 0, 0x100);
|
||||
// Transfer
|
||||
outb(PHYS_JJ_ESP + 3*4, 0x90);
|
||||
ret = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
|
||||
free(buffer);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ob_sd_open(sd_private_t *sd)
|
||||
{
|
||||
int ret=1;
|
||||
phandle_t ph;
|
||||
|
||||
fword("my-unit");
|
||||
sd->id = POP();
|
||||
sd->hw_sector = get_block_size(sd);
|
||||
|
||||
#ifdef CONFIG_DEBUG_ESP
|
||||
printk("opening drive %d\n", sd->id);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
dump_drive(drive);
|
||||
|
||||
if (drive->type != esp_type_ata)
|
||||
ret= !ob_esp_atapi_drive_ready(drive);
|
||||
#endif
|
||||
|
||||
selfword("open-deblocker");
|
||||
|
||||
/* interpose disk-label */
|
||||
ph = find_dev("/packages/disk-label");
|
||||
fword("my-args");
|
||||
PUSH_ph( ph );
|
||||
fword("interpose");
|
||||
|
||||
RET ( -ret );
|
||||
}
|
||||
|
||||
static void
|
||||
ob_sd_close(__attribute__((unused)) sd_private_t *sd)
|
||||
{
|
||||
selfword("close-deblocker");
|
||||
}
|
||||
|
||||
NODE_METHODS(ob_sd) = {
|
||||
{ "open", ob_sd_open },
|
||||
{ "close", ob_sd_close },
|
||||
{ "read-blocks", ob_sd_read_blocks },
|
||||
{ "block-size", ob_sd_block_size },
|
||||
};
|
||||
|
||||
static void
|
||||
ob_esp_initialize(esp_private_t *esp)
|
||||
{
|
||||
phandle_t ph=get_cur_dev();
|
||||
|
||||
set_int_property(ph, "#address-cells", 2);
|
||||
set_int_property(ph, "#size-cells", 0);
|
||||
|
||||
/* set device type */
|
||||
push_str("scsi");
|
||||
fword("device-type");
|
||||
|
||||
/* set reg */
|
||||
PUSH(4);
|
||||
fword("encode-int");
|
||||
PUSH(0x08800000);
|
||||
fword("encode-int");
|
||||
fword("encode+");
|
||||
PUSH(0x00000010);
|
||||
fword("encode-int");
|
||||
fword("encode+");
|
||||
push_str("reg");
|
||||
fword("property");
|
||||
#if 1
|
||||
esp->ll = (void *)PHYS_JJ_ESP;
|
||||
esp->buffer = (void *)0x100000; // XXX
|
||||
#else
|
||||
/* Get the IO region */
|
||||
esp->ll = map_io(PHYS_JJ_ESP, sizeof (struct esp_regs));
|
||||
if (esp->ll == 0)
|
||||
return -1;
|
||||
|
||||
esp->buffer = dvma_alloc(BUFSIZE, &esp->buffer_dvma);
|
||||
esp->espdma = espdma;
|
||||
#endif
|
||||
// Chip reset
|
||||
outb((int)esp->ll + 3*2, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
ob_esp_decodeunit(__attribute__((unused)) esp_private_t * esp)
|
||||
{
|
||||
fword("decode-unit-scsi");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ob_esp_encodeunit(__attribute__((unused)) esp_private_t * esp)
|
||||
{
|
||||
fword("encode-unit-scsi");
|
||||
}
|
||||
|
||||
NODE_METHODS(ob_esp) = {
|
||||
{ NULL, ob_esp_initialize },
|
||||
{ "decode-unit", ob_esp_decodeunit },
|
||||
{ "encode-unit", ob_esp_encodeunit },
|
||||
};
|
||||
|
||||
static int
|
||||
drive_present(int drive)
|
||||
{
|
||||
// XXX
|
||||
if (drive == 0 || drive == 2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
drive_cdrom(int drive)
|
||||
{
|
||||
// XXX
|
||||
if (drive == 2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_alias(const unsigned char *device, const unsigned char *alias)
|
||||
{
|
||||
push_str("/aliases");
|
||||
fword("find-device");
|
||||
push_str(device);
|
||||
fword("encode-string");
|
||||
push_str(alias);
|
||||
fword("encode-string");
|
||||
fword("property");
|
||||
}
|
||||
|
||||
int ob_esp_init(void)
|
||||
{
|
||||
int id, diskcount = 0, cdcount = 0, *counter_ptr;
|
||||
char nodebuff[256], aliasbuff[256];
|
||||
const char *type;
|
||||
|
||||
#ifdef CONFIG_DEBUG_ESP
|
||||
printk("Initializing SCSI...");
|
||||
#endif
|
||||
sprintf(nodebuff, "/iommu/sbus/espdma/esp");
|
||||
REGISTER_NAMED_NODE(ob_esp, nodebuff);
|
||||
device_end();
|
||||
#ifdef CONFIG_DEBUG_ESP
|
||||
printk("done\n");
|
||||
printk("Initializing SCSI devices...");
|
||||
#endif
|
||||
for (id = 0; id < 8; id++) {
|
||||
if (!drive_present(id))
|
||||
continue;
|
||||
push_str("/iommu/sbus/espdma/esp");
|
||||
fword("find-device");
|
||||
fword("new-device");
|
||||
push_str("sd");
|
||||
fword("device-name");
|
||||
push_str("block");
|
||||
fword("device-type");
|
||||
fword("is-deblocker");
|
||||
PUSH(id);
|
||||
fword("encode-int");
|
||||
PUSH(0);
|
||||
fword("encode-int");
|
||||
fword("encode+");
|
||||
push_str("reg");
|
||||
fword("property");
|
||||
fword("finish-device");
|
||||
sprintf(nodebuff, "/iommu/sbus/espdma/esp/sd@%d,0", id);
|
||||
REGISTER_NODE_METHODS(ob_sd, nodebuff);
|
||||
if (drive_cdrom(id)) {
|
||||
type = "cdrom";
|
||||
counter_ptr = &cdcount;
|
||||
} else {
|
||||
type = "disk";
|
||||
counter_ptr = &diskcount;
|
||||
}
|
||||
if (*counter_ptr == 0) {
|
||||
add_alias(nodebuff, type);
|
||||
}
|
||||
sprintf(aliasbuff, "%s%d", type, *counter_ptr);
|
||||
(*counter_ptr)++;
|
||||
add_alias(nodebuff, aliasbuff);
|
||||
}
|
||||
#ifdef CONFIG_DEBUG_ESP
|
||||
printk("done\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user