commit
605e15db2b
@ -1,46 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <pci.h> |
||||
#include <asm/pci.h> |
||||
#include <asm/fsp/fsp_support.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
void board_pci_setup_hose(struct pci_controller *hose) |
||||
{ |
||||
hose->first_busno = 0; |
||||
hose->last_busno = 0; |
||||
|
||||
/* PCI memory space */ |
||||
pci_set_region(hose->regions + 0, |
||||
CONFIG_PCI_MEM_BUS, |
||||
CONFIG_PCI_MEM_PHYS, |
||||
CONFIG_PCI_MEM_SIZE, |
||||
PCI_REGION_MEM); |
||||
|
||||
/* PCI IO space */ |
||||
pci_set_region(hose->regions + 1, |
||||
CONFIG_PCI_IO_BUS, |
||||
CONFIG_PCI_IO_PHYS, |
||||
CONFIG_PCI_IO_SIZE, |
||||
PCI_REGION_IO); |
||||
|
||||
pci_set_region(hose->regions + 2, |
||||
CONFIG_PCI_PREF_BUS, |
||||
CONFIG_PCI_PREF_PHYS, |
||||
CONFIG_PCI_PREF_SIZE, |
||||
PCI_REGION_PREFETCH); |
||||
|
||||
pci_set_region(hose->regions + 3, |
||||
0, |
||||
0, |
||||
gd->ram_size < 0x80000000 ? gd->ram_size : 0x80000000, |
||||
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); |
||||
|
||||
hose->region_count = 4; |
||||
} |
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <cpu.h> |
||||
#include <dm.h> |
||||
#include <errno.h> |
||||
#include <asm/cpu.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
int cpu_x86_bind(struct udevice *dev) |
||||
{ |
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev); |
||||
|
||||
plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, |
||||
"intel,apic-id", -1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cpu_x86_get_desc(struct udevice *dev, char *buf, int size) |
||||
{ |
||||
if (size < CPU_MAX_NAME_LEN) |
||||
return -ENOSPC; |
||||
|
||||
cpu_get_name(buf); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int cpu_x86_get_count(struct udevice *dev) |
||||
{ |
||||
int node, cpu; |
||||
int num = 0; |
||||
|
||||
node = fdt_path_offset(gd->fdt_blob, "/cpus"); |
||||
if (node < 0) |
||||
return -ENOENT; |
||||
|
||||
for (cpu = fdt_first_subnode(gd->fdt_blob, node); |
||||
cpu >= 0; |
||||
cpu = fdt_next_subnode(gd->fdt_blob, cpu)) { |
||||
const char *device_type; |
||||
|
||||
device_type = fdt_getprop(gd->fdt_blob, cpu, |
||||
"device_type", NULL); |
||||
if (!device_type) |
||||
continue; |
||||
if (strcmp(device_type, "cpu") == 0) |
||||
num++; |
||||
} |
||||
|
||||
return num; |
||||
} |
||||
|
||||
static const struct cpu_ops cpu_x86_ops = { |
||||
.get_desc = cpu_x86_get_desc, |
||||
.get_count = cpu_x86_get_count, |
||||
}; |
||||
|
||||
static const struct udevice_id cpu_x86_ids[] = { |
||||
{ .compatible = "cpu-x86" }, |
||||
{ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(cpu_x86_drv) = { |
||||
.name = "cpu_x86", |
||||
.id = UCLASS_CPU, |
||||
.of_match = cpu_x86_ids, |
||||
.bind = cpu_x86_bind, |
||||
.ops = &cpu_x86_ops, |
||||
}; |
@ -0,0 +1,21 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/ioapic.h> |
||||
|
||||
u32 io_apic_read(u32 reg) |
||||
{ |
||||
writel(reg, IO_APIC_INDEX); |
||||
return readl(IO_APIC_DATA); |
||||
} |
||||
|
||||
void io_apic_write(u32 reg, u32 val) |
||||
{ |
||||
writel(reg, IO_APIC_INDEX); |
||||
writel(val, IO_APIC_DATA); |
||||
} |
@ -0,0 +1,6 @@ |
||||
/ { |
||||
rtc { |
||||
compatible = "motorola,mc146818"; |
||||
reg = <0x70 2>; |
||||
}; |
||||
}; |
@ -0,0 +1,34 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _ASM_CPU_X86_H |
||||
#define _ASM_CPU_X86_H |
||||
|
||||
/**
|
||||
* cpu_x86_bind() - Bind an x86 CPU with the driver |
||||
* |
||||
* This updates cpu device's platform data with information from device tree, |
||||
* like the processor local apic id. |
||||
* |
||||
* @dev: Device to check (UCLASS_CPU) |
||||
* @return 0 always |
||||
*/ |
||||
int cpu_x86_bind(struct udevice *dev); |
||||
|
||||
/**
|
||||
* cpu_x86_get_desc() - Get a description string for an x86 CPU |
||||
* |
||||
* This uses cpu_get_name() and is suitable to use as the get_desc() method for |
||||
* the CPU uclass. |
||||
* |
||||
* @dev: Device to check (UCLASS_CPU) |
||||
* @buf: Buffer to place string |
||||
* @size: Size of string space |
||||
* @return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error |
||||
*/ |
||||
int cpu_x86_get_desc(struct udevice *dev, char *buf, int size); |
||||
|
||||
#endif /* _ASM_CPU_X86_H */ |
@ -1,101 +0,0 @@ |
||||
/*
|
||||
* Taken from the Coreboot file of the same name |
||||
* |
||||
* (C) Copyright 2014 Google, Inc |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0 |
||||
*/ |
||||
|
||||
#ifndef _ASM_LAPIC_DEF_H |
||||
#define _ASM_LAPIC_DEF_H |
||||
|
||||
#define LAPIC_BASE_MSR 0x1B |
||||
#define LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8) |
||||
#define LAPIC_BASE_MSR_ENABLE (1 << 11) |
||||
#define LAPIC_BASE_MSR_ADDR_MASK 0xFFFFF000 |
||||
|
||||
#define LOCAL_APIC_ADDR 0xfee00000 |
||||
#define LAPIC_DEFAULT_BASE LOCAL_APIC_ADDR |
||||
|
||||
#define LAPIC_ID 0x020 |
||||
#define LAPIC_LVR 0x030 |
||||
#define LAPIC_TASKPRI 0x80 |
||||
#define LAPIC_TPRI_MASK 0xFF |
||||
#define LAPIC_ARBID 0x090 |
||||
#define LAPIC_RRR 0x0C0 |
||||
#define LAPIC_SVR 0x0f0 |
||||
#define LAPIC_SPIV 0x0f0 |
||||
#define LAPIC_SPIV_ENABLE 0x100 |
||||
#define LAPIC_ESR 0x280 |
||||
#define LAPIC_ESR_SEND_CS 0x00001 |
||||
#define LAPIC_ESR_RECV_CS 0x00002 |
||||
#define LAPIC_ESR_SEND_ACC 0x00004 |
||||
#define LAPIC_ESR_RECV_ACC 0x00008 |
||||
#define LAPIC_ESR_SENDILL 0x00020 |
||||
#define LAPIC_ESR_RECVILL 0x00040 |
||||
#define LAPIC_ESR_ILLREGA 0x00080 |
||||
#define LAPIC_ICR 0x300 |
||||
#define LAPIC_DEST_SELF 0x40000 |
||||
#define LAPIC_DEST_ALLINC 0x80000 |
||||
#define LAPIC_DEST_ALLBUT 0xC0000 |
||||
#define LAPIC_ICR_RR_MASK 0x30000 |
||||
#define LAPIC_ICR_RR_INVALID 0x00000 |
||||
#define LAPIC_ICR_RR_INPROG 0x10000 |
||||
#define LAPIC_ICR_RR_VALID 0x20000 |
||||
#define LAPIC_INT_LEVELTRIG 0x08000 |
||||
#define LAPIC_INT_ASSERT 0x04000 |
||||
#define LAPIC_ICR_BUSY 0x01000 |
||||
#define LAPIC_DEST_LOGICAL 0x00800 |
||||
#define LAPIC_DM_FIXED 0x00000 |
||||
#define LAPIC_DM_LOWEST 0x00100 |
||||
#define LAPIC_DM_SMI 0x00200 |
||||
#define LAPIC_DM_REMRD 0x00300 |
||||
#define LAPIC_DM_NMI 0x00400 |
||||
#define LAPIC_DM_INIT 0x00500 |
||||
#define LAPIC_DM_STARTUP 0x00600 |
||||
#define LAPIC_DM_EXTINT 0x00700 |
||||
#define LAPIC_VECTOR_MASK 0x000FF |
||||
#define LAPIC_ICR2 0x310 |
||||
#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) |
||||
#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) |
||||
#define LAPIC_LVTT 0x320 |
||||
#define LAPIC_LVTPC 0x340 |
||||
#define LAPIC_LVT0 0x350 |
||||
#define LAPIC_LVT_TIMER_BASE_MASK (0x3 << 18) |
||||
#define GET_LAPIC_TIMER_BASE(x) (((x) >> 18) & 0x3) |
||||
#define SET_LAPIC_TIMER_BASE(x) (((x) << 18)) |
||||
#define LAPIC_TIMER_BASE_CLKIN 0x0 |
||||
#define LAPIC_TIMER_BASE_TMBASE 0x1 |
||||
#define LAPIC_TIMER_BASE_DIV 0x2 |
||||
#define LAPIC_LVT_TIMER_PERIODIC (1 << 17) |
||||
#define LAPIC_LVT_MASKED (1 << 16) |
||||
#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) |
||||
#define LAPIC_LVT_REMOTE_IRR (1 << 14) |
||||
#define LAPIC_INPUT_POLARITY (1 << 13) |
||||
#define LAPIC_SEND_PENDING (1 << 12) |
||||
#define LAPIC_LVT_RESERVED_1 (1 << 11) |
||||
#define LAPIC_DELIVERY_MODE_MASK (7 << 8) |
||||
#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) |
||||
#define LAPIC_DELIVERY_MODE_NMI (4 << 8) |
||||
#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) |
||||
#define GET_LAPIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) |
||||
#define SET_LAPIC_DELIVERY_MODE(x, y) (((x) & ~0x700)|((y) << 8)) |
||||
#define LAPIC_MODE_FIXED 0x0 |
||||
#define LAPIC_MODE_NMI 0x4 |
||||
#define LAPIC_MODE_EXINT 0x7 |
||||
#define LAPIC_LVT1 0x360 |
||||
#define LAPIC_LVTERR 0x370 |
||||
#define LAPIC_TMICT 0x380 |
||||
#define LAPIC_TMCCT 0x390 |
||||
#define LAPIC_TDCR 0x3E0 |
||||
#define LAPIC_TDR_DIV_TMBASE (1 << 2) |
||||
#define LAPIC_TDR_DIV_1 0xB |
||||
#define LAPIC_TDR_DIV_2 0x0 |
||||
#define LAPIC_TDR_DIV_4 0x1 |
||||
#define LAPIC_TDR_DIV_8 0x2 |
||||
#define LAPIC_TDR_DIV_16 0x3 |
||||
#define LAPIC_TDR_DIV_32 0x8 |
||||
#define LAPIC_TDR_DIV_64 0x9 |
||||
#define LAPIC_TDR_DIV_128 0xA |
||||
|
||||
#endif |
@ -0,0 +1,444 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* Adapted from coreboot src/arch/x86/include/arch/smp/mpspec.h |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef __ASM_MPSPEC_H |
||||
#define __ASM_MPSPEC_H |
||||
|
||||
/*
|
||||
* Structure definitions for SMP machines following the |
||||
* Intel MultiProcessor Specification 1.4 |
||||
*/ |
||||
|
||||
#define MPSPEC_V14 4 |
||||
|
||||
#define MPF_SIGNATURE "_MP_" |
||||
|
||||
struct mp_floating_table { |
||||
char mpf_signature[4]; /* "_MP_" */ |
||||
u32 mpf_physptr; /* Configuration table address */ |
||||
u8 mpf_length; /* Our length (paragraphs) */ |
||||
u8 mpf_spec; /* Specification version */ |
||||
u8 mpf_checksum; /* Checksum (makes sum 0) */ |
||||
u8 mpf_feature1; /* Predefined or Unique configuration? */ |
||||
u8 mpf_feature2; /* Bit7 set for IMCR/PIC */ |
||||
u8 mpf_feature3; /* Unused (0) */ |
||||
u8 mpf_feature4; /* Unused (0) */ |
||||
u8 mpf_feature5; /* Unused (0) */ |
||||
}; |
||||
|
||||
#define MPC_SIGNATURE "PCMP" |
||||
|
||||
struct mp_config_table { |
||||
char mpc_signature[4]; /* "PCMP" */ |
||||
u16 mpc_length; /* Size of table */ |
||||
u8 mpc_spec; /* Specification version */ |
||||
u8 mpc_checksum; /* Checksum (makes sum 0) */ |
||||
char mpc_oem[8]; /* OEM ID */ |
||||
char mpc_product[12]; /* Product ID */ |
||||
u32 mpc_oemptr; /* OEM table address */ |
||||
u16 mpc_oemsize; /* OEM table size */ |
||||
u16 mpc_entry_count; /* Number of entries in the table */ |
||||
u32 mpc_lapic; /* Local APIC address */ |
||||
u16 mpe_length; /* Extended table size */ |
||||
u8 mpe_checksum; /* Extended table checksum */ |
||||
u8 reserved; |
||||
}; |
||||
|
||||
/* Base MP configuration table entry types */ |
||||
|
||||
enum mp_base_config_entry_type { |
||||
MP_PROCESSOR, |
||||
MP_BUS, |
||||
MP_IOAPIC, |
||||
MP_INTSRC, |
||||
MP_LINTSRC |
||||
}; |
||||
|
||||
#define MPC_CPU_EN (1 << 0) |
||||
#define MPC_CPU_BP (1 << 1) |
||||
|
||||
struct mpc_config_processor { |
||||
u8 mpc_type; |
||||
u8 mpc_apicid; |
||||
u8 mpc_apicver; |
||||
u8 mpc_cpuflag; |
||||
u32 mpc_cpusignature; |
||||
u32 mpc_cpufeature; |
||||
u32 mpc_reserved[2]; |
||||
}; |
||||
|
||||
#define BUSTYPE_CBUS "CBUS " |
||||
#define BUSTYPE_CBUSII "CBUSII" |
||||
#define BUSTYPE_EISA "EISA " |
||||
#define BUSTYPE_FUTURE "FUTURE" |
||||
#define BUSTYPE_INTERN "INTERN" |
||||
#define BUSTYPE_ISA "ISA " |
||||
#define BUSTYPE_MBI "MBI " |
||||
#define BUSTYPE_MBII "MBII " |
||||
#define BUSTYPE_MCA "MCA " |
||||
#define BUSTYPE_MPI "MPI " |
||||
#define BUSTYPE_MPSA "MPSA " |
||||
#define BUSTYPE_NUBUS "NUBUS " |
||||
#define BUSTYPE_PCI "PCI " |
||||
#define BUSTYPE_PCMCIA "PCMCIA" |
||||
#define BUSTYPE_TC "TC " |
||||
#define BUSTYPE_VL "VL " |
||||
#define BUSTYPE_VME "VME " |
||||
#define BUSTYPE_XPRESS "XPRESS" |
||||
|
||||
struct mpc_config_bus { |
||||
u8 mpc_type; |
||||
u8 mpc_busid; |
||||
u8 mpc_bustype[6]; |
||||
}; |
||||
|
||||
#define MPC_APIC_USABLE (1 << 0) |
||||
|
||||
struct mpc_config_ioapic { |
||||
u8 mpc_type; |
||||
u8 mpc_apicid; |
||||
u8 mpc_apicver; |
||||
u8 mpc_flags; |
||||
u32 mpc_apicaddr; |
||||
}; |
||||
|
||||
enum mp_irq_source_types { |
||||
MP_INT, |
||||
MP_NMI, |
||||
MP_SMI, |
||||
MP_EXTINT |
||||
}; |
||||
|
||||
#define MP_IRQ_POLARITY_DEFAULT 0x0 |
||||
#define MP_IRQ_POLARITY_HIGH 0x1 |
||||
#define MP_IRQ_POLARITY_LOW 0x3 |
||||
#define MP_IRQ_POLARITY_MASK 0x3 |
||||
#define MP_IRQ_TRIGGER_DEFAULT 0x0 |
||||
#define MP_IRQ_TRIGGER_EDGE 0x4 |
||||
#define MP_IRQ_TRIGGER_LEVEL 0xc |
||||
#define MP_IRQ_TRIGGER_MASK 0xc |
||||
|
||||
#define MP_APIC_ALL 0xff |
||||
|
||||
struct mpc_config_intsrc { |
||||
u8 mpc_type; |
||||
u8 mpc_irqtype; |
||||
u16 mpc_irqflag; |
||||
u8 mpc_srcbus; |
||||
u8 mpc_srcbusirq; |
||||
u8 mpc_dstapic; |
||||
u8 mpc_dstirq; |
||||
}; |
||||
|
||||
struct mpc_config_lintsrc { |
||||
u8 mpc_type; |
||||
u8 mpc_irqtype; |
||||
u16 mpc_irqflag; |
||||
u8 mpc_srcbusid; |
||||
u8 mpc_srcbusirq; |
||||
u8 mpc_destapic; |
||||
u8 mpc_destlint; |
||||
}; |
||||
|
||||
/* Extended MP configuration table entry types */ |
||||
|
||||
enum mp_ext_config_entry_type { |
||||
MPE_SYSTEM_ADDRESS_SPACE = 128, |
||||
MPE_BUS_HIERARCHY, |
||||
MPE_COMPAT_ADDRESS_SPACE |
||||
}; |
||||
|
||||
struct mp_ext_config { |
||||
u8 mpe_type; |
||||
u8 mpe_length; |
||||
}; |
||||
|
||||
#define ADDRESS_TYPE_IO 0 |
||||
#define ADDRESS_TYPE_MEM 1 |
||||
#define ADDRESS_TYPE_PREFETCH 2 |
||||
|
||||
struct mp_ext_system_address_space { |
||||
u8 mpe_type; |
||||
u8 mpe_length; |
||||
u8 mpe_busid; |
||||
u8 mpe_addr_type; |
||||
u32 mpe_addr_base_low; |
||||
u32 mpe_addr_base_high; |
||||
u32 mpe_addr_length_low; |
||||
u32 mpe_addr_length_high; |
||||
}; |
||||
|
||||
#define BUS_SUBTRACTIVE_DECODE (1 << 0) |
||||
|
||||
struct mp_ext_bus_hierarchy { |
||||
u8 mpe_type; |
||||
u8 mpe_length; |
||||
u8 mpe_busid; |
||||
u8 mpe_bus_info; |
||||
u8 mpe_parent_busid; |
||||
u8 reserved[3]; |
||||
}; |
||||
|
||||
#define ADDRESS_RANGE_ADD 0 |
||||
#define ADDRESS_RANGE_SUBTRACT 1 |
||||
|
||||
/*
|
||||
* X100 - X3FF |
||||
* X500 - X7FF |
||||
* X900 - XBFF |
||||
* XD00 - XFFF |
||||
*/ |
||||
#define RANGE_LIST_IO_ISA 0 |
||||
/*
|
||||
* X3B0 - X3BB |
||||
* X3C0 - X3DF |
||||
* X7B0 - X7BB |
||||
* X7C0 - X7DF |
||||
* XBB0 - XBBB |
||||
* XBC0 - XBDF |
||||
* XFB0 - XFBB |
||||
* XFC0 - XCDF |
||||
*/ |
||||
#define RANGE_LIST_IO_VGA 1 |
||||
|
||||
struct mp_ext_compat_address_space { |
||||
u8 mpe_type; |
||||
u8 mpe_length; |
||||
u8 mpe_busid; |
||||
u8 mpe_addr_modifier; |
||||
u32 mpe_range_list; |
||||
}; |
||||
|
||||
/**
|
||||
* mp_next_mpc_entry() - Compute MP configuration table end to be used as |
||||
* next base table entry start address |
||||
* |
||||
* This computes the end address of current MP configuration table, without |
||||
* counting any extended configuration table entry. |
||||
* |
||||
* @mc: configuration table header address |
||||
* @return: configuration table end address |
||||
*/ |
||||
static inline u32 mp_next_mpc_entry(struct mp_config_table *mc) |
||||
{ |
||||
return (u32)mc + mc->mpc_length; |
||||
} |
||||
|
||||
/**
|
||||
* mp_add_mpc_entry() - Add a base MP configuration table entry |
||||
* |
||||
* This adds the base MP configuration table entry size with |
||||
* added base table entry length and increases entry count by 1. |
||||
* |
||||
* @mc: configuration table header address |
||||
* @length: length of the added table entry |
||||
*/ |
||||
static inline void mp_add_mpc_entry(struct mp_config_table *mc, uint length) |
||||
{ |
||||
mc->mpc_length += length; |
||||
mc->mpc_entry_count++; |
||||
} |
||||
|
||||
/**
|
||||
* mp_next_mpe_entry() - Compute MP configuration table end to be used as |
||||
* next extended table entry start address |
||||
* |
||||
* This computes the end address of current MP configuration table, |
||||
* including any extended configuration table entry. |
||||
* |
||||
* @mc: configuration table header address |
||||
* @return: configuration table end address |
||||
*/ |
||||
static inline u32 mp_next_mpe_entry(struct mp_config_table *mc) |
||||
{ |
||||
return (u32)mc + mc->mpc_length + mc->mpe_length; |
||||
} |
||||
|
||||
/**
|
||||
* mp_add_mpe_entry() - Add an extended MP configuration table entry |
||||
* |
||||
* This adds the extended MP configuration table entry size with |
||||
* added extended table entry length. |
||||
* |
||||
* @mc: configuration table header address |
||||
* @mpe: extended table entry base address |
||||
*/ |
||||
static inline void mp_add_mpe_entry(struct mp_config_table *mc, |
||||
struct mp_ext_config *mpe) |
||||
{ |
||||
mc->mpe_length += mpe->mpe_length; |
||||
} |
||||
|
||||
/**
|
||||
* mp_write_floating_table() - Write the MP floating table |
||||
* |
||||
* This writes the MP floating table, and points MP configuration table |
||||
* to its end address so that MP configuration table follows immediately |
||||
* after the floating table. |
||||
* |
||||
* @mf: MP floating table base address |
||||
* @return: MP configuration table header address |
||||
*/ |
||||
struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf); |
||||
|
||||
/**
|
||||
* mp_config_table_init() - Initialize the MP configuration table header |
||||
* |
||||
* This populates the MP configuration table header with valid bits. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
*/ |
||||
void mp_config_table_init(struct mp_config_table *mc); |
||||
|
||||
/**
|
||||
* mp_write_processor() - Write a processor entry |
||||
* |
||||
* This writes a processor entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
*/ |
||||
void mp_write_processor(struct mp_config_table *mc); |
||||
|
||||
/**
|
||||
* mp_write_bus() - Write a bus entry |
||||
* |
||||
* This writes a bus entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @id: bus id |
||||
* @bustype: bus type name |
||||
*/ |
||||
void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype); |
||||
|
||||
/**
|
||||
* mp_write_ioapic() - Write an I/O APIC entry |
||||
* |
||||
* This writes an I/O APIC entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @id: I/O APIC id |
||||
* @ver: I/O APIC version |
||||
* @apicaddr: I/O APIC address |
||||
*/ |
||||
void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr); |
||||
|
||||
/**
|
||||
* mp_write_intsrc() - Write an I/O interrupt assignment entry |
||||
* |
||||
* This writes an I/O interrupt assignment entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @irqtype: IRQ type (INT/NMI/SMI/ExtINT) |
||||
* @irqflag: IRQ flag (level/trigger) |
||||
* @srcbus: source bus id where the interrupt comes from |
||||
* @srcbusirq: IRQ number mapped on the source bus |
||||
* @dstapic: destination I/O APIC id where the interrupt goes to |
||||
* @dstirq: destination I/O APIC pin where the interrupt goes to |
||||
*/ |
||||
void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, |
||||
int srcbus, int srcbusirq, int dstapic, int dstirq); |
||||
|
||||
/**
|
||||
* mp_write_pci_intsrc() - Write a PCI interrupt assignment entry |
||||
* |
||||
* This writes a PCI interrupt assignment entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @irqtype: IRQ type (INT/NMI/SMI/ExtINT) |
||||
* @srcbus: PCI bus number where the interrupt comes from |
||||
* @dev: device number on the PCI bus |
||||
* @pin: PCI interrupt pin (INT A/B/C/D) |
||||
* @dstapic: destination I/O APIC id where the interrupt goes to |
||||
* @dstirq: destination I/O APIC pin where the interrupt goes to |
||||
*/ |
||||
void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, |
||||
int srcbus, int dev, int pin, int dstapic, int dstirq); |
||||
|
||||
/**
|
||||
* mp_write_lintsrc() - Write a local interrupt assignment entry |
||||
* |
||||
* This writes a local interrupt assignment entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @irqtype: IRQ type (INT/NMI/SMI/ExtINT) |
||||
* @irqflag: IRQ flag (level/trigger) |
||||
* @srcbus: PCI bus number where the interrupt comes from |
||||
* @srcbusirq: IRQ number mapped on the source bus |
||||
* @dstapic: destination local APIC id where the interrupt goes to |
||||
* @destlint: destination local APIC pin where the interrupt goes to |
||||
*/ |
||||
void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, |
||||
int srcbus, int srcbusirq, int destapic, int destlint); |
||||
|
||||
|
||||
/**
|
||||
* mp_write_address_space() - Write a system address space entry |
||||
* |
||||
* This writes a system address space entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @busid: bus id for the bus where system address space is mapped |
||||
* @addr_type: system address type |
||||
* @addr_base_low: starting address low |
||||
* @addr_base_high: starting address high |
||||
* @addr_length_low: address length low |
||||
* @addr_length_high: address length high |
||||
*/ |
||||
void mp_write_address_space(struct mp_config_table *mc, |
||||
int busid, int addr_type, |
||||
u32 addr_base_low, u32 addr_base_high, |
||||
u32 addr_length_low, u32 addr_length_high); |
||||
|
||||
/**
|
||||
* mp_write_bus_hierarchy() - Write a bus hierarchy descriptor entry |
||||
* |
||||
* This writes a bus hierarchy descriptor entry to the configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @busid: bus id |
||||
* @bus_info: bit0 indicates if the bus is a subtractive decode bus |
||||
* @parent_busid: parent bus id |
||||
*/ |
||||
void mp_write_bus_hierarchy(struct mp_config_table *mc, |
||||
int busid, int bus_info, int parent_busid); |
||||
|
||||
/**
|
||||
* mp_write_compat_address_space() - Write a compat bus address space entry |
||||
* |
||||
* This writes a compatibility bus address space modifier entry to the |
||||
* configuration table. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @busid: bus id |
||||
* @addr_modifier: add or subtract to predefined address range list |
||||
* @range_list: list of predefined address space ranges |
||||
*/ |
||||
void mp_write_compat_address_space(struct mp_config_table *mc, int busid, |
||||
int addr_modifier, u32 range_list); |
||||
|
||||
/**
|
||||
* mptable_finalize() - Finalize the MP table |
||||
* |
||||
* This finalizes the MP table by calculating required checksums. |
||||
* |
||||
* @mc: MP configuration table header address |
||||
* @return: MP table end address |
||||
*/ |
||||
u32 mptable_finalize(struct mp_config_table *mc); |
||||
|
||||
/**
|
||||
* write_mp_table() - Write MP table |
||||
* |
||||
* This writes MP table at a given address. |
||||
* |
||||
* @addr: start address to write MP table |
||||
* @return: end address of MP table |
||||
*/ |
||||
u32 write_mp_table(u32 addr); |
||||
|
||||
#endif /* __ASM_MPSPEC_H */ |
@ -0,0 +1,382 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* Adapted from coreboot src/arch/x86/boot/mpspec.c |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <cpu.h> |
||||
#include <dm.h> |
||||
#include <errno.h> |
||||
#include <fdtdec.h> |
||||
#include <asm/cpu.h> |
||||
#include <asm/irq.h> |
||||
#include <asm/ioapic.h> |
||||
#include <asm/lapic.h> |
||||
#include <asm/mpspec.h> |
||||
#include <asm/tables.h> |
||||
#include <dm/uclass-internal.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) |
||||
{ |
||||
u32 mc; |
||||
|
||||
memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); |
||||
mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); |
||||
mf->mpf_length = 1; |
||||
mf->mpf_spec = MPSPEC_V14; |
||||
mf->mpf_checksum = 0; |
||||
/* We don't use the default configuration table */ |
||||
mf->mpf_feature1 = 0; |
||||
/* Indicate that virtual wire mode is always implemented */ |
||||
mf->mpf_feature2 = 0; |
||||
mf->mpf_feature3 = 0; |
||||
mf->mpf_feature4 = 0; |
||||
mf->mpf_feature5 = 0; |
||||
mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); |
||||
|
||||
mc = (u32)mf + sizeof(struct mp_floating_table); |
||||
return (struct mp_config_table *)mc; |
||||
} |
||||
|
||||
void mp_config_table_init(struct mp_config_table *mc) |
||||
{ |
||||
memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); |
||||
mc->mpc_length = sizeof(struct mp_config_table); |
||||
mc->mpc_spec = MPSPEC_V14; |
||||
mc->mpc_checksum = 0; |
||||
mc->mpc_oemptr = 0; |
||||
mc->mpc_oemsize = 0; |
||||
mc->mpc_entry_count = 0; |
||||
mc->mpc_lapic = LAPIC_DEFAULT_BASE; |
||||
mc->mpe_length = 0; |
||||
mc->mpe_checksum = 0; |
||||
mc->reserved = 0; |
||||
|
||||
/* The oem/product id fields are exactly 8/12 bytes long */ |
||||
table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); |
||||
table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); |
||||
} |
||||
|
||||
void mp_write_processor(struct mp_config_table *mc) |
||||
{ |
||||
struct mpc_config_processor *mpc; |
||||
struct udevice *dev; |
||||
u8 boot_apicid, apicver; |
||||
u32 cpusignature, cpufeature; |
||||
struct cpuid_result result; |
||||
|
||||
boot_apicid = lapicid(); |
||||
apicver = lapic_read(LAPIC_LVR) & 0xff; |
||||
result = cpuid(1); |
||||
cpusignature = result.eax; |
||||
cpufeature = result.edx; |
||||
|
||||
for (uclass_find_first_device(UCLASS_CPU, &dev); |
||||
dev; |
||||
uclass_find_next_device(&dev)) { |
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev); |
||||
u8 cpuflag = MPC_CPU_EN; |
||||
|
||||
if (!device_active(dev)) |
||||
continue; |
||||
|
||||
mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); |
||||
mpc->mpc_type = MP_PROCESSOR; |
||||
mpc->mpc_apicid = plat->cpu_id; |
||||
mpc->mpc_apicver = apicver; |
||||
if (boot_apicid == plat->cpu_id) |
||||
cpuflag |= MPC_CPU_BP; |
||||
mpc->mpc_cpuflag = cpuflag; |
||||
mpc->mpc_cpusignature = cpusignature; |
||||
mpc->mpc_cpufeature = cpufeature; |
||||
mpc->mpc_reserved[0] = 0; |
||||
mpc->mpc_reserved[1] = 0; |
||||
mp_add_mpc_entry(mc, sizeof(*mpc)); |
||||
} |
||||
} |
||||
|
||||
void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) |
||||
{ |
||||
struct mpc_config_bus *mpc; |
||||
|
||||
mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); |
||||
mpc->mpc_type = MP_BUS; |
||||
mpc->mpc_busid = id; |
||||
memcpy(mpc->mpc_bustype, bustype, 6); |
||||
mp_add_mpc_entry(mc, sizeof(*mpc)); |
||||
} |
||||
|
||||
void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) |
||||
{ |
||||
struct mpc_config_ioapic *mpc; |
||||
|
||||
mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); |
||||
mpc->mpc_type = MP_IOAPIC; |
||||
mpc->mpc_apicid = id; |
||||
mpc->mpc_apicver = ver; |
||||
mpc->mpc_flags = MPC_APIC_USABLE; |
||||
mpc->mpc_apicaddr = apicaddr; |
||||
mp_add_mpc_entry(mc, sizeof(*mpc)); |
||||
} |
||||
|
||||
void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, |
||||
int srcbus, int srcbusirq, int dstapic, int dstirq) |
||||
{ |
||||
struct mpc_config_intsrc *mpc; |
||||
|
||||
mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); |
||||
mpc->mpc_type = MP_INTSRC; |
||||
mpc->mpc_irqtype = irqtype; |
||||
mpc->mpc_irqflag = irqflag; |
||||
mpc->mpc_srcbus = srcbus; |
||||
mpc->mpc_srcbusirq = srcbusirq; |
||||
mpc->mpc_dstapic = dstapic; |
||||
mpc->mpc_dstirq = dstirq; |
||||
mp_add_mpc_entry(mc, sizeof(*mpc)); |
||||
} |
||||
|
||||
void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, |
||||
int srcbus, int dev, int pin, int dstapic, int dstirq) |
||||
{ |
||||
u8 srcbusirq = (dev << 2) | (pin - 1); |
||||
|
||||
mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, |
||||
srcbus, srcbusirq, dstapic, dstirq); |
||||
} |
||||
|
||||
void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, |
||||
int srcbus, int srcbusirq, int destapic, int destlint) |
||||
{ |
||||
struct mpc_config_lintsrc *mpc; |
||||
|
||||
mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); |
||||
mpc->mpc_type = MP_LINTSRC; |
||||
mpc->mpc_irqtype = irqtype; |
||||
mpc->mpc_irqflag = irqflag; |
||||
mpc->mpc_srcbusid = srcbus; |
||||
mpc->mpc_srcbusirq = srcbusirq; |
||||
mpc->mpc_destapic = destapic; |
||||
mpc->mpc_destlint = destlint; |
||||
mp_add_mpc_entry(mc, sizeof(*mpc)); |
||||
} |
||||
|
||||
void mp_write_address_space(struct mp_config_table *mc, |
||||
int busid, int addr_type, |
||||
u32 addr_base_low, u32 addr_base_high, |
||||
u32 addr_length_low, u32 addr_length_high) |
||||
{ |
||||
struct mp_ext_system_address_space *mpe; |
||||
|
||||
mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); |
||||
mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; |
||||
mpe->mpe_length = sizeof(*mpe); |
||||
mpe->mpe_busid = busid; |
||||
mpe->mpe_addr_type = addr_type; |
||||
mpe->mpe_addr_base_low = addr_base_low; |
||||
mpe->mpe_addr_base_high = addr_base_high; |
||||
mpe->mpe_addr_length_low = addr_length_low; |
||||
mpe->mpe_addr_length_high = addr_length_high; |
||||
mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); |
||||
} |
||||
|
||||
void mp_write_bus_hierarchy(struct mp_config_table *mc, |
||||
int busid, int bus_info, int parent_busid) |
||||
{ |
||||
struct mp_ext_bus_hierarchy *mpe; |
||||
|
||||
mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); |
||||
mpe->mpe_type = MPE_BUS_HIERARCHY; |
||||
mpe->mpe_length = sizeof(*mpe); |
||||
mpe->mpe_busid = busid; |
||||
mpe->mpe_bus_info = bus_info; |
||||
mpe->mpe_parent_busid = parent_busid; |
||||
mpe->reserved[0] = 0; |
||||
mpe->reserved[1] = 0; |
||||
mpe->reserved[2] = 0; |
||||
mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); |
||||
} |
||||
|
||||
void mp_write_compat_address_space(struct mp_config_table *mc, int busid, |
||||
int addr_modifier, u32 range_list) |
||||
{ |
||||
struct mp_ext_compat_address_space *mpe; |
||||
|
||||
mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); |
||||
mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; |
||||
mpe->mpe_length = sizeof(*mpe); |
||||
mpe->mpe_busid = busid; |
||||
mpe->mpe_addr_modifier = addr_modifier; |
||||
mpe->mpe_range_list = range_list; |
||||
mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); |
||||
} |
||||
|
||||
u32 mptable_finalize(struct mp_config_table *mc) |
||||
{ |
||||
u32 end; |
||||
|
||||
mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), |
||||
mc->mpe_length); |
||||
mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); |
||||
end = mp_next_mpe_entry(mc); |
||||
|
||||
debug("Write the MP table at: %x - %x\n", (u32)mc, end); |
||||
|
||||
return end; |
||||
} |
||||
|
||||
static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa, |
||||
int apicid, int external_int2) |
||||
{ |
||||
int i; |
||||
|
||||
mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT, |
||||
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, |
||||
bus_isa, 0, apicid, 0); |
||||
mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, |
||||
bus_isa, 1, apicid, 1); |
||||
mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT, |
||||
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, |
||||
bus_isa, 0, apicid, 2); |
||||
|
||||
for (i = 3; i < 16; i++) |
||||
mp_write_intsrc(mc, MP_INT, |
||||
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, |
||||
bus_isa, i, apicid, i); |
||||
} |
||||
|
||||
/*
|
||||
* Check duplicated I/O interrupt assignment table entry, to make sure |
||||
* there is only one entry with the given bus, device and interrupt pin. |
||||
*/ |
||||
static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base, |
||||
int entry_num, int bus, int device, int pin) |
||||
{ |
||||
struct mpc_config_intsrc *intsrc = intsrc_base; |
||||
int i; |
||||
|
||||
for (i = 0; i < entry_num; i++) { |
||||
if (intsrc->mpc_srcbus == bus && |
||||
intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1))) |
||||
break; |
||||
intsrc++; |
||||
} |
||||
|
||||
return (i == entry_num) ? false : true; |
||||
} |
||||
|
||||
static int mptable_add_intsrc(struct mp_config_table *mc, |
||||
int bus_isa, int apicid) |
||||
{ |
||||
struct mpc_config_intsrc *intsrc_base; |
||||
int intsrc_entries = 0; |
||||
const void *blob = gd->fdt_blob; |
||||
int node; |
||||
int len, count; |
||||
const u32 *cell; |
||||
int i; |
||||
|
||||
/* Legacy Interrupts */ |
||||
debug("Writing ISA IRQs\n"); |
||||
mptable_add_isa_interrupts(mc, bus_isa, apicid, 0); |
||||
|
||||
/* Get I/O interrupt information from device tree */ |
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); |
||||
if (node < 0) { |
||||
debug("%s: Cannot find irq router node\n", __func__); |
||||
return -ENOENT; |
||||
} |
||||
|
||||
cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); |
||||
if (!cell) |
||||
return -ENOENT; |
||||
|
||||
if ((len % sizeof(struct pirq_routing)) == 0) |
||||
count = len / sizeof(struct pirq_routing); |
||||
else |
||||
return -EINVAL; |
||||
|
||||
intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); |
||||
|
||||
for (i = 0; i < count; i++) { |
||||
struct pirq_routing pr; |
||||
|
||||
pr.bdf = fdt_addr_to_cpu(cell[0]); |
||||
pr.pin = fdt_addr_to_cpu(cell[1]); |
||||
pr.pirq = fdt_addr_to_cpu(cell[2]); |
||||
|
||||
if (check_dup_entry(intsrc_base, intsrc_entries, |
||||
PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) { |
||||
debug("found entry for bus %d device %d INT%c, skipping\n", |
||||
PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), |
||||
'A' + pr.pin - 1); |
||||
cell += sizeof(struct pirq_routing) / sizeof(u32); |
||||
continue; |
||||
} |
||||
|
||||
/* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */ |
||||
mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf), |
||||
PCI_DEV(pr.bdf), pr.pin, apicid, |
||||
pr.pirq + 16); |
||||
intsrc_entries++; |
||||
cell += sizeof(struct pirq_routing) / sizeof(u32); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa) |
||||
{ |
||||
mp_write_lintsrc(mc, MP_EXTINT, |
||||
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, |
||||
bus_isa, 0, MP_APIC_ALL, 0); |
||||
mp_write_lintsrc(mc, MP_NMI, |
||||
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, |
||||
bus_isa, 0, MP_APIC_ALL, 1); |
||||
} |
||||
|
||||
u32 write_mp_table(u32 addr) |
||||
{ |
||||
struct mp_config_table *mc; |
||||
int ioapic_id, ioapic_ver; |
||||
int bus_isa = 0xff; |
||||
int ret; |
||||
u32 end; |
||||
|
||||
/* 16 byte align the table address */ |
||||
addr = ALIGN(addr, 16); |
||||
|
||||
/* Write floating table */ |
||||
mc = mp_write_floating_table((struct mp_floating_table *)addr); |
||||
|
||||
/* Write configuration table header */ |
||||
mp_config_table_init(mc); |
||||
|
||||
/* Write processor entry */ |
||||
mp_write_processor(mc); |
||||
|
||||
/* Write bus entry */ |
||||
mp_write_bus(mc, bus_isa, BUSTYPE_ISA); |
||||
|
||||
/* Write I/O APIC entry */ |
||||
ioapic_id = io_apic_read(IO_APIC_ID) >> 24; |
||||
ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff; |
||||
mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR); |
||||
|
||||
/* Write I/O interrupt assignment entry */ |
||||
ret = mptable_add_intsrc(mc, bus_isa, ioapic_id); |
||||
if (ret) |
||||
debug("Failed to write I/O interrupt assignment table\n"); |
||||
|
||||
/* Write local interrupt assignment entry */ |
||||
mptable_add_lintsrc(mc, bus_isa); |
||||
|
||||
/* Finalize the MP table */ |
||||
end = mptable_finalize(mc); |
||||
|
||||
return end; |
||||
} |
@ -1,717 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) Procsys. All rights reserved. |
||||
* Author: Mushtaq Khan <mushtaq_k@procsys.com> |
||||
* <mushtaqk_921@yahoo.co.in> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
* |
||||
* with the reference to ata_piix driver in kernel 2.4.32 |
||||
*/ |
||||
|
||||
/*
|
||||
* This file contains SATA controller and SATA drive initialization functions |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <pci.h> |
||||
#include <command.h> |
||||
#include <config.h> |
||||
#include <asm/byteorder.h> |
||||
#include <part.h> |
||||
#include <ide.h> |
||||
#include <ata.h> |
||||
#include <sata.h> |
||||
|
||||
#define DEBUG_SATA 0 /* For debug prints set DEBUG_SATA to 1 */ |
||||
|
||||
#define SATA_DECL |
||||
#define DRV_DECL /* For file specific declarations */ |
||||
#include "ata_piix.h" |
||||
|
||||
/* Macros realted to PCI */ |
||||
#define PCI_SATA_BUS 0x00 |
||||
#define PCI_SATA_DEV 0x1f |
||||
#define PCI_SATA_FUNC 0x02 |
||||
|
||||
#define PCI_SATA_BASE1 0x10 |
||||
#define PCI_SATA_BASE2 0x14 |
||||
#define PCI_SATA_BASE3 0x18 |
||||
#define PCI_SATA_BASE4 0x1c |
||||
#define PCI_SATA_BASE5 0x20 |
||||
#define PCI_PMR 0x90 |
||||
#define PCI_PI 0x09 |
||||
#define PCI_PCS 0x92 |
||||
#define PCI_DMA_CTL 0x48 |
||||
|
||||
#define PORT_PRESENT (1<<0) |
||||
#define PORT_ENABLED (1<<4) |
||||
|
||||
u32 bdf; |
||||
u32 iobase1; /* Primary cmd block */ |
||||
u32 iobase2; /* Primary ctl block */ |
||||
u32 iobase3; /* Sec cmd block */ |
||||
u32 iobase4; /* sec ctl block */ |
||||
u32 iobase5; /* BMDMA*/ |
||||
|
||||
int pci_sata_init(void) |
||||
{ |
||||
u32 bus = PCI_SATA_BUS; |
||||
u32 dev = PCI_SATA_DEV; |
||||
u32 fun = PCI_SATA_FUNC; |
||||
u16 cmd = 0; |
||||
u8 lat = 0, pcibios_max_latency = 0xff; |
||||
u8 pmr; /* Port mapping reg */ |
||||
u8 pi; /* Prgming Interface reg */ |
||||
|
||||
bdf = PCI_BDF(bus, dev, fun); |
||||
pci_read_config_dword(bdf, PCI_SATA_BASE1, &iobase1); |
||||
pci_read_config_dword(bdf, PCI_SATA_BASE2, &iobase2); |
||||
pci_read_config_dword(bdf, PCI_SATA_BASE3, &iobase3); |
||||
pci_read_config_dword(bdf, PCI_SATA_BASE4, &iobase4); |
||||
pci_read_config_dword(bdf, PCI_SATA_BASE5, &iobase5); |
||||
|
||||
if ((iobase1 == 0xFFFFFFFF) || (iobase2 == 0xFFFFFFFF) || |
||||
(iobase3 == 0xFFFFFFFF) || (iobase4 == 0xFFFFFFFF) || |
||||
(iobase5 == 0xFFFFFFFF)) { |
||||
/* ERROR */ |
||||
printf("error no base addr for SATA controller\n"); |
||||
return 1; |
||||
} |
||||
|
||||
iobase1 &= 0xFFFFFFFE; |
||||
iobase2 &= 0xFFFFFFFE; |
||||
iobase3 &= 0xFFFFFFFE; |
||||
iobase4 &= 0xFFFFFFFE; |
||||
iobase5 &= 0xFFFFFFFE; |
||||
|
||||
/* check for mode */ |
||||
pci_read_config_byte(bdf, PCI_PMR, &pmr); |
||||
if (pmr > 1) { |
||||
puts("combined mode not supported\n"); |
||||
return 1; |
||||
} |
||||
|
||||
pci_read_config_byte(bdf, PCI_PI, &pi); |
||||
if ((pi & 0x05) != 0x05) { |
||||
puts("Sata is in Legacy mode\n"); |
||||
return 1; |
||||
} else |
||||
puts("sata is in Native mode\n"); |
||||
|
||||
/* MASTER CFG AND IO CFG */ |
||||
pci_read_config_word(bdf, PCI_COMMAND, &cmd); |
||||
cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO; |
||||
pci_write_config_word(bdf, PCI_COMMAND, cmd); |
||||
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); |
||||
|
||||
if (lat < 16) |
||||
lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; |
||||
else if (lat > pcibios_max_latency) |
||||
lat = pcibios_max_latency; |
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int sata_bus_probe(int port_no) |
||||
{ |
||||
int orig_mask, mask; |
||||
u16 pcs; |
||||
|
||||
mask = (PORT_PRESENT << port_no); |
||||
pci_read_config_word(bdf, PCI_PCS, &pcs); |
||||
orig_mask = (int) pcs & 0xff; |
||||
if ((orig_mask & mask) != mask) |
||||
return 0; |
||||
else |
||||
return 1; |
||||
} |
||||
|
||||
int init_sata(int dev) |
||||
{ |
||||
static int done; |
||||
u8 i, rv = 0; |
||||
|
||||
if (!done) |
||||
done = 1; |
||||
else |
||||
return 0; |
||||
|
||||
rv = pci_sata_init(); |
||||
if (rv == 1) { |
||||
puts("pci initialization failed\n"); |
||||
return 1; |
||||
} |
||||
|
||||
port[0].port_no = 0; |
||||
port[0].ioaddr.cmd_addr = iobase1; |
||||
port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = |
||||
iobase2 | ATA_PCI_CTL_OFS; |
||||
port[0].ioaddr.bmdma_addr = iobase5; |
||||
|
||||
port[1].port_no = 1; |
||||
port[1].ioaddr.cmd_addr = iobase3; |
||||
port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = |
||||
iobase4 | ATA_PCI_CTL_OFS; |
||||
port[1].ioaddr.bmdma_addr = iobase5 + 0x8; |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) |
||||
sata_port(&port[i].ioaddr); |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) { |
||||
if (!(sata_bus_probe(i))) { |
||||
port[i].port_state = 0; |
||||
printf("SATA#%d port is not present\n", i); |
||||
} else { |
||||
printf("SATA#%d port is present\n", i); |
||||
if (sata_bus_softreset(i)) |
||||
port[i].port_state = 0; |
||||
else |
||||
port[i].port_state = 1; |
||||
} |
||||
} |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) { |
||||
u8 j, devno; |
||||
|
||||
if (port[i].port_state == 0) |
||||
continue; |
||||
for (j = 0; j < CONFIG_SYS_SATA_DEVS_PER_BUS; j++) { |
||||
sata_identify(i, j); |
||||
set_Feature_cmd(i, j); |
||||
devno = i * CONFIG_SYS_SATA_DEVS_PER_BUS + j; |
||||
if ((sata_dev_desc[devno].lba > 0) && |
||||
(sata_dev_desc[devno].blksz > 0)) { |
||||
dev_print(&sata_dev_desc[devno]); |
||||
/* initialize partition type */ |
||||
init_part(&sata_dev_desc[devno]); |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int reset_sata(int dev) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
static inline u8 sata_inb(unsigned long ioaddr) |
||||
{ |
||||
return inb(ioaddr); |
||||
} |
||||
|
||||
static inline void sata_outb(unsigned char val, unsigned long ioaddr) |
||||
{ |
||||
outb(val, ioaddr); |
||||
} |
||||
|
||||
static void output_data(struct sata_ioports *ioaddr, ulong * sect_buf, |
||||
int words) |
||||
{ |
||||
outsw(ioaddr->data_addr, sect_buf, words << 1); |
||||
} |
||||
|
||||
static int input_data(struct sata_ioports *ioaddr, ulong * sect_buf, int words) |
||||
{ |
||||
insw(ioaddr->data_addr, sect_buf, words << 1); |
||||
return 0; |
||||
} |
||||
|
||||
static void sata_cpy(unsigned char *dst, unsigned char *src, unsigned int len) |
||||
{ |
||||
unsigned char *end, *last; |
||||
|
||||
last = dst; |
||||
end = src + len - 1; |
||||
|
||||
/* reserve space for '\0' */ |
||||
if (len < 2) |
||||
goto OUT; |
||||
|
||||
/* skip leading white space */ |
||||
while ((*src) && (src < end) && (*src == ' ')) |
||||
++src; |
||||
|
||||
/* copy string, omitting trailing white space */ |
||||
while ((*src) && (src < end)) { |
||||
*dst++ = *src; |
||||
if (*src++ != ' ') |
||||
last = dst; |
||||
} |
||||
OUT: |
||||
*last = '\0'; |
||||
} |
||||
|
||||
int sata_bus_softreset(int num) |
||||
{ |
||||
u8 dev = 0, status = 0, i; |
||||
|
||||
port[num].dev_mask = 0; |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_DEVS_PER_BUS; i++) { |
||||
if (!(sata_devchk(&port[num].ioaddr, i))) { |
||||
debug("dev_chk failed for dev#%d\n", i); |
||||
} else { |
||||
port[num].dev_mask |= (1 << i); |
||||
debug("dev_chk passed for dev#%d\n", i); |
||||
} |
||||
} |
||||
|
||||
if (!(port[num].dev_mask)) { |
||||
printf("no devices on port%d\n", num); |
||||
return 1; |
||||
} |
||||
|
||||
dev_select(&port[num].ioaddr, dev); |
||||
|
||||
port[num].ctl_reg = 0x08; /* Default value of control reg */ |
||||
sata_outb(port[num].ctl_reg, port[num].ioaddr.ctl_addr); |
||||
udelay(10); |
||||
sata_outb(port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); |
||||
udelay(10); |
||||
sata_outb(port[num].ctl_reg, port[num].ioaddr.ctl_addr); |
||||
|
||||
/*
|
||||
* spec mandates ">= 2ms" before checking status. |
||||
* We wait 150ms, because that was the magic delay used for |
||||
* ATAPI devices in Hale Landis's ATADRVR, for the period of time |
||||
* between when the ATA command register is written, and then |
||||
* status is checked. Because waiting for "a while" before |
||||
* checking status is fine, post SRST, we perform this magic |
||||
* delay here as well. |
||||
*/ |
||||
mdelay(150); |
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 300); |
||||
while ((status & ATA_BUSY)) { |
||||
mdelay(100); |
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 3); |
||||
} |
||||
|
||||
if (status & ATA_BUSY) |
||||
printf("ata%u is slow to respond,plz be patient\n", num); |
||||
|
||||
while ((status & ATA_BUSY)) { |
||||
mdelay(100); |
||||
status = sata_chk_status(&port[num].ioaddr); |
||||
} |
||||
|
||||
if (status & ATA_BUSY) { |
||||
printf("ata%u failed to respond : bus reset failed\n", num); |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void sata_identify(int num, int dev) |
||||
{ |
||||
u8 cmd = 0, status = 0; |
||||
u8 devno = num * CONFIG_SYS_SATA_DEVS_PER_BUS + dev; |
||||
u16 iobuf[ATA_SECT_SIZE]; |
||||
u64 n_sectors = 0; |
||||
u8 mask = 0; |
||||
|
||||
memset(iobuf, 0, sizeof(iobuf)); |
||||
hd_driveid_t *iop = (hd_driveid_t *) iobuf; |
||||
|
||||
if (dev == 0) |
||||
mask = 0x01; |
||||
else |
||||
mask = 0x02; |
||||
|
||||
if (!(port[num].dev_mask & mask)) { |
||||
printf("dev%d is not present on port#%d\n", dev, num); |
||||
return; |
||||
} |
||||
|
||||
printf("port=%d dev=%d\n", num, dev); |
||||
|
||||
dev_select(&port[num].ioaddr, dev); |
||||
|
||||
status = 0; |
||||
cmd = ATA_CMD_IDENT; /* Device Identify Command */ |
||||
sata_outb(cmd, port[num].ioaddr.command_addr); |
||||
sata_inb(port[num].ioaddr.altstatus_addr); |
||||
udelay(10); |
||||
|
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 1000); |
||||
if (status & ATA_ERR) { |
||||
puts("\ndevice not responding\n"); |
||||
port[num].dev_mask &= ~mask; |
||||
return; |
||||
} |
||||
|
||||
input_data(&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS); |
||||
|
||||
debug("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x" |
||||
"86:%04x" "87:%04x 88:%04x\n", num, dev, iobuf[49], |
||||
iobuf[82], iobuf[83], iobuf[84], iobuf[85], iobuf[86], |
||||
iobuf[87], iobuf[88]); |
||||
|
||||
/* we require LBA and DMA support (bits 8 & 9 of word 49) */ |
||||
if (!ata_id_has_dma(iobuf) || !ata_id_has_lba(iobuf)) |
||||
debug("ata%u: no dma/lba\n", num); |
||||
ata_dump_id(iobuf); |
||||
|
||||
if (ata_id_has_lba48(iobuf)) |
||||
n_sectors = ata_id_u64(iobuf, 100); |
||||
else |
||||
n_sectors = ata_id_u32(iobuf, 60); |
||||
debug("no. of sectors %u\n", ata_id_u64(iobuf, 100)); |
||||
debug("no. of sectors %u\n", ata_id_u32(iobuf, 60)); |
||||
|
||||
if (n_sectors == 0) { |
||||
port[num].dev_mask &= ~mask; |
||||
return; |
||||
} |
||||
|
||||
sata_cpy((unsigned char *)sata_dev_desc[devno].revision, iop->fw_rev, |
||||
sizeof(sata_dev_desc[devno].revision)); |
||||
sata_cpy((unsigned char *)sata_dev_desc[devno].vendor, iop->model, |
||||
sizeof(sata_dev_desc[devno].vendor)); |
||||
sata_cpy((unsigned char *)sata_dev_desc[devno].product, iop->serial_no, |
||||
sizeof(sata_dev_desc[devno].product)); |
||||
strswab(sata_dev_desc[devno].revision); |
||||
strswab(sata_dev_desc[devno].vendor); |
||||
|
||||
if ((iop->config & 0x0080) == 0x0080) |
||||
sata_dev_desc[devno].removable = 1; |
||||
else |
||||
sata_dev_desc[devno].removable = 0; |
||||
|
||||
sata_dev_desc[devno].lba = iop->lba_capacity; |
||||
debug("lba=0x%x", sata_dev_desc[devno].lba); |
||||
|
||||
#ifdef CONFIG_LBA48 |
||||
if (iop->command_set_2 & 0x0400) { |
||||
sata_dev_desc[devno].lba48 = 1; |
||||
lba = (unsigned long long) iop->lba48_capacity[0] | |
||||
((unsigned long long) iop->lba48_capacity[1] << 16) | |
||||
((unsigned long long) iop->lba48_capacity[2] << 32) | |
||||
((unsigned long long) iop->lba48_capacity[3] << 48); |
||||
} else { |
||||
sata_dev_desc[devno].lba48 = 0; |
||||
} |
||||
#endif |
||||
|
||||
/* assuming HD */ |
||||
sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; |
||||
sata_dev_desc[devno].blksz = ATA_BLOCKSIZE; |
||||
sata_dev_desc[devno].log2blksz = LOG2(sata_dev_desc[devno].blksz); |
||||
sata_dev_desc[devno].lun = 0; /* just to fill something in... */ |
||||
} |
||||
|
||||
void set_Feature_cmd(int num, int dev) |
||||
{ |
||||
u8 mask = 0x00, status = 0; |
||||
|
||||
if (dev == 0) |
||||
mask = 0x01; |
||||
else |
||||
mask = 0x02; |
||||
|
||||
if (!(port[num].dev_mask & mask)) { |
||||
debug("dev%d is not present on port#%d\n", dev, num); |
||||
return; |
||||
} |
||||
|
||||
dev_select(&port[num].ioaddr, dev); |
||||
|
||||
sata_outb(SETFEATURES_XFER, port[num].ioaddr.feature_addr); |
||||
sata_outb(XFER_PIO_4, port[num].ioaddr.nsect_addr); |
||||
sata_outb(0, port[num].ioaddr.lbal_addr); |
||||
sata_outb(0, port[num].ioaddr.lbam_addr); |
||||
sata_outb(0, port[num].ioaddr.lbah_addr); |
||||
|
||||
sata_outb(ATA_DEVICE_OBS, port[num].ioaddr.device_addr); |
||||
sata_outb(ATA_CMD_SETF, port[num].ioaddr.command_addr); |
||||
|
||||
udelay(50); |
||||
mdelay(150); |
||||
|
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 5000); |
||||
if ((status & (ATA_STAT_BUSY | ATA_STAT_ERR))) { |
||||
printf("Error : status 0x%02x\n", status); |
||||
port[num].dev_mask &= ~mask; |
||||
} |
||||
} |
||||
|
||||
void sata_port(struct sata_ioports *ioport) |
||||
{ |
||||
ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; |
||||
ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; |
||||
ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; |
||||
ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; |
||||
ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; |
||||
ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; |
||||
ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; |
||||
ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; |
||||
ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; |
||||
ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; |
||||
} |
||||
|
||||
int sata_devchk(struct sata_ioports *ioaddr, int dev) |
||||
{ |
||||
u8 nsect, lbal; |
||||
|
||||
dev_select(ioaddr, dev); |
||||
|
||||
sata_outb(0x55, ioaddr->nsect_addr); |
||||
sata_outb(0xaa, ioaddr->lbal_addr); |
||||
|
||||
sata_outb(0xaa, ioaddr->nsect_addr); |
||||
sata_outb(0x55, ioaddr->lbal_addr); |
||||
|
||||
sata_outb(0x55, ioaddr->nsect_addr); |
||||
sata_outb(0xaa, ioaddr->lbal_addr); |
||||
|
||||
nsect = sata_inb(ioaddr->nsect_addr); |
||||
lbal = sata_inb(ioaddr->lbal_addr); |
||||
|
||||
if ((nsect == 0x55) && (lbal == 0xaa)) |
||||
return 1; /* we found a device */ |
||||
else |
||||
return 0; /* nothing found */ |
||||
} |
||||
|
||||
void dev_select(struct sata_ioports *ioaddr, int dev) |
||||
{ |
||||
u8 tmp = 0; |
||||
|
||||
if (dev == 0) |
||||
tmp = ATA_DEVICE_OBS; |
||||
else |
||||
tmp = ATA_DEVICE_OBS | ATA_DEV1; |
||||
|
||||
sata_outb(tmp, ioaddr->device_addr); |
||||
sata_inb(ioaddr->altstatus_addr); |
||||
udelay(5); |
||||
} |
||||
|
||||
u8 sata_busy_wait(struct sata_ioports *ioaddr, int bits, unsigned int max) |
||||
{ |
||||
u8 status; |
||||
|
||||
do { |
||||
udelay(1000); |
||||
status = sata_chk_status(ioaddr); |
||||
max--; |
||||
} while ((status & bits) && (max > 0)); |
||||
|
||||
return status; |
||||
} |
||||
|
||||
u8 sata_chk_status(struct sata_ioports *ioaddr) |
||||
{ |
||||
return sata_inb(ioaddr->status_addr); |
||||
} |
||||
|
||||
|
||||
ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buff) |
||||
{ |
||||
ulong n = 0, *buffer = (ulong *)buff; |
||||
u8 dev = 0, num = 0, mask = 0, status = 0; |
||||
|
||||
#ifdef CONFIG_LBA48 |
||||
unsigned char lba48 = 0; |
||||
|
||||
if (blknr & 0x0000fffff0000000) { |
||||
if (!sata_dev_desc[devno].lba48) { |
||||
printf("Drive doesn't support 48-bit addressing\n"); |
||||
return 0; |
||||
} |
||||
/* more than 28 bits used, use 48bit mode */ |
||||
lba48 = 1; |
||||
} |
||||
#endif |
||||
/* Port Number */ |
||||
num = device / CONFIG_SYS_SATA_DEVS_PER_BUS; |
||||
/* dev on the port */ |
||||
if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS) |
||||
dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS; |
||||
else |
||||
dev = device; |
||||
|
||||
if (dev == 0) |
||||
mask = 0x01; |
||||
else |
||||
mask = 0x02; |
||||
|
||||
if (!(port[num].dev_mask & mask)) { |
||||
printf("dev%d is not present on port#%d\n", dev, num); |
||||
return 0; |
||||
} |
||||
|
||||
/* Select device */ |
||||
dev_select(&port[num].ioaddr, dev); |
||||
|
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); |
||||
if (status & ATA_BUSY) { |
||||
printf("ata%u failed to respond\n", port[num].port_no); |
||||
return n; |
||||
} |
||||
while (blkcnt-- > 0) { |
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); |
||||
if (status & ATA_BUSY) { |
||||
printf("ata%u failed to respond\n", 0); |
||||
return n; |
||||
} |
||||
#ifdef CONFIG_LBA48 |
||||
if (lba48) { |
||||
/* write high bits */ |
||||
sata_outb(0, port[num].ioaddr.nsect_addr); |
||||
sata_outb((blknr >> 24) & 0xFF, |
||||
port[num].ioaddr.lbal_addr); |
||||
sata_outb((blknr >> 32) & 0xFF, |
||||
port[num].ioaddr.lbam_addr); |
||||
sata_outb((blknr >> 40) & 0xFF, |
||||
port[num].ioaddr.lbah_addr); |
||||
} |
||||
#endif |
||||
sata_outb(1, port[num].ioaddr.nsect_addr); |
||||
sata_outb(((blknr) >> 0) & 0xFF, |
||||
port[num].ioaddr.lbal_addr); |
||||
sata_outb((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); |
||||
sata_outb((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); |
||||
|
||||
#ifdef CONFIG_LBA48 |
||||
if (lba48) { |
||||
sata_outb(ATA_LBA, port[num].ioaddr.device_addr); |
||||
sata_outb(ATA_CMD_READ_EXT, |
||||
port[num].ioaddr.command_addr); |
||||
} else |
||||
#endif |
||||
{ |
||||
sata_outb(ATA_LBA | ((blknr >> 24) & 0xF), |
||||
port[num].ioaddr.device_addr); |
||||
sata_outb(ATA_CMD_READ, |
||||
port[num].ioaddr.command_addr); |
||||
} |
||||
|
||||
mdelay(50); |
||||
/* may take up to 4 sec */ |
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 4000); |
||||
|
||||
if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) |
||||
!= ATA_STAT_DRQ) { |
||||
u8 err = 0; |
||||
|
||||
printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", |
||||
device, (ulong) blknr, status); |
||||
err = sata_inb(port[num].ioaddr.error_addr); |
||||
printf("Error reg = 0x%x\n", err); |
||||
return n; |
||||
} |
||||
input_data(&port[num].ioaddr, buffer, ATA_SECTORWORDS); |
||||
sata_inb(port[num].ioaddr.altstatus_addr); |
||||
udelay(50); |
||||
|
||||
++n; |
||||
++blknr; |
||||
buffer += ATA_SECTORWORDS; |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buff) |
||||
{ |
||||
ulong n = 0, *buffer = (ulong *)buff; |
||||
unsigned char status = 0, num = 0, dev = 0, mask = 0; |
||||
|
||||
#ifdef CONFIG_LBA48 |
||||
unsigned char lba48 = 0; |
||||
|
||||
if (blknr & 0x0000fffff0000000) { |
||||
if (!sata_dev_desc[devno].lba48) { |
||||
printf("Drive doesn't support 48-bit addressing\n"); |
||||
return 0; |
||||
} |
||||
/* more than 28 bits used, use 48bit mode */ |
||||
lba48 = 1; |
||||
} |
||||
#endif |
||||
/* Port Number */ |
||||
num = device / CONFIG_SYS_SATA_DEVS_PER_BUS; |
||||
/* dev on the Port */ |
||||
if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS) |
||||
dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS; |
||||
else |
||||
dev = device; |
||||
|
||||
if (dev == 0) |
||||
mask = 0x01; |
||||
else |
||||
mask = 0x02; |
||||
|
||||
/* Select device */ |
||||
dev_select(&port[num].ioaddr, dev); |
||||
|
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); |
||||
if (status & ATA_BUSY) { |
||||
printf("ata%u failed to respond\n", port[num].port_no); |
||||
return n; |
||||
} |
||||
|
||||
while (blkcnt-- > 0) { |
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); |
||||
if (status & ATA_BUSY) { |
||||
printf("ata%u failed to respond\n", |
||||
port[num].port_no); |
||||
return n; |
||||
} |
||||
#ifdef CONFIG_LBA48 |
||||
if (lba48) { |
||||
/* write high bits */ |
||||
sata_outb(0, port[num].ioaddr.nsect_addr); |
||||
sata_outb((blknr >> 24) & 0xFF, |
||||
port[num].ioaddr.lbal_addr); |
||||
sata_outb((blknr >> 32) & 0xFF, |
||||
port[num].ioaddr.lbam_addr); |
||||
sata_outb((blknr >> 40) & 0xFF, |
||||
port[num].ioaddr.lbah_addr); |
||||
} |
||||
#endif |
||||
sata_outb(1, port[num].ioaddr.nsect_addr); |
||||
sata_outb((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); |
||||
sata_outb((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); |
||||
sata_outb((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); |
||||
#ifdef CONFIG_LBA48 |
||||
if (lba48) { |
||||
sata_outb(ATA_LBA, port[num].ioaddr.device_addr); |
||||
sata_outb(ATA_CMD_WRITE_EXT, |
||||
port[num].ioaddr.command_addr); |
||||
} else |
||||
#endif |
||||
{ |
||||
sata_outb(ATA_LBA | ((blknr >> 24) & 0xF), |
||||
port[num].ioaddr.device_addr); |
||||
sata_outb(ATA_CMD_WRITE, |
||||
port[num].ioaddr.command_addr); |
||||
} |
||||
|
||||
mdelay(50); |
||||
/* may take up to 4 sec */ |
||||
status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 4000); |
||||
if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) |
||||
!= ATA_STAT_DRQ) { |
||||
printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", |
||||
device, (ulong) blknr, status); |
||||
return n; |
||||
} |
||||
|
||||
output_data(&port[num].ioaddr, buffer, ATA_SECTORWORDS); |
||||
sata_inb(port[num].ioaddr.altstatus_addr); |
||||
udelay(50); |
||||
|
||||
++n; |
||||
++blknr; |
||||
buffer += ATA_SECTORWORDS; |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
int scan_sata(int dev) |
||||
{ |
||||
return 0; |
||||
} |
@ -1,71 +0,0 @@ |
||||
#ifndef __ATA_PIIX_H__ |
||||
#define __ATA_PIIX_H__ |
||||
|
||||
struct sata_ioports { |
||||
unsigned long cmd_addr; |
||||
unsigned long data_addr; |
||||
unsigned long error_addr; |
||||
unsigned long feature_addr; |
||||
unsigned long nsect_addr; |
||||
unsigned long lbal_addr; |
||||
unsigned long lbam_addr; |
||||
unsigned long lbah_addr; |
||||
unsigned long device_addr; |
||||
unsigned long status_addr; |
||||
unsigned long command_addr; |
||||
unsigned long altstatus_addr; |
||||
unsigned long ctl_addr; |
||||
unsigned long bmdma_addr; |
||||
unsigned long scr_addr; |
||||
}; |
||||
|
||||
struct sata_port { |
||||
unsigned char port_no; /* primary=0, secondary=1 */ |
||||
struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ |
||||
unsigned char ctl_reg; |
||||
unsigned char last_ctl; |
||||
unsigned char port_state; /* 1-port is available and */ |
||||
/* 0-port is not available */ |
||||
unsigned char dev_mask; |
||||
}; |
||||
|
||||
/***********SATA LIBRARY SPECIFIC DEFINITIONS AND DECLARATIONS**************/ |
||||
#ifdef SATA_DECL /* SATA library specific declarations */ |
||||
inline void ata_dump_id(u16 *id) |
||||
{ |
||||
debug("49 = 0x%04x " |
||||
"53 = 0x%04x " |
||||
"63 = 0x%04x " |
||||
"64 = 0x%04x " |
||||
"75 = 0x%04x\n", id[49], id[53], id[63], id[64], id[75]); |
||||
debug("80 = 0x%04x " |
||||
"81 = 0x%04x " |
||||
"82 = 0x%04x " |
||||
"83 = 0x%04x " |
||||
"84 = 0x%04x\n", id[80], id[81], id[82], id[83], id[84]); |
||||
debug("88 = 0x%04x " "93 = 0x%04x\n", id[88], id[93]); |
||||
} |
||||
#endif |
||||
|
||||
#ifdef SATA_DECL /*SATA library specific declarations */ |
||||
int sata_bus_softreset(int num); |
||||
void sata_identify(int num, int dev); |
||||
void sata_port(struct sata_ioports *ioport); |
||||
void set_Feature_cmd(int num, int dev); |
||||
int sata_devchk(struct sata_ioports *ioaddr, int dev); |
||||
void dev_select(struct sata_ioports *ioaddr, int dev); |
||||
u8 sata_busy_wait(struct sata_ioports *ioaddr, int bits, unsigned int max); |
||||
u8 sata_chk_status(struct sata_ioports *ioaddr); |
||||
#endif |
||||
|
||||
/************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/ |
||||
|
||||
#ifdef DRV_DECL /* Driver specific declaration */ |
||||
int init_sata(int dev); |
||||
#endif |
||||
|
||||
#ifdef DRV_DECL /* Defines Driver Specific variables */ |
||||
struct sata_port port[CONFIG_SYS_SATA_MAXBUS]; |
||||
#endif |
||||
|
||||
#endif /* __ATA_PIIX_H__ */ |
Loading…
Reference in new issue