diff options
Diffstat (limited to 'hw/ssi/aspeed_smc.c')
-rw-r--r-- | hw/ssi/aspeed_smc.c | 861 |
1 files changed, 478 insertions, 383 deletions
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 612040493c..5466be6317 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -169,11 +169,6 @@ #define ASPEED_SMC_R_SPI_MAX (0x20 / 4) #define ASPEED_SMC_R_SMC_MAX (0x20 / 4) -#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000 -#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 -#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 -#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000 - /* * DMA DRAM addresses should be 4 bytes aligned and the valid address * range is 0x40000000 - 0x5FFFFFFF (AST2400) @@ -186,8 +181,8 @@ * 0: 4 bytes * 0x7FFFFF: 32M bytes */ -#define DMA_DRAM_ADDR(s, val) ((val) & (s)->ctrl->dma_dram_mask) -#define DMA_FLASH_ADDR(s, val) ((val) & (s)->ctrl->dma_flash_mask) +#define DMA_DRAM_ADDR(asc, val) ((val) & (asc)->dma_dram_mask) +#define DMA_FLASH_ADDR(asc, val) ((val) & (asc)->dma_flash_mask) #define DMA_LENGTH(val) ((val) & 0x01FFFFFC) /* Flash opcodes. */ @@ -201,316 +196,25 @@ * controller. These can be changed when board is initialized with the * Segment Address Registers. */ -static const AspeedSegments aspeed_segments_legacy[] = { - { 0x10000000, 32 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_fmc[] = { - { 0x20000000, 64 * 1024 * 1024 }, /* start address is readonly */ - { 0x24000000, 32 * 1024 * 1024 }, - { 0x26000000, 32 * 1024 * 1024 }, - { 0x28000000, 32 * 1024 * 1024 }, - { 0x2A000000, 32 * 1024 * 1024 } -}; - -static const AspeedSegments aspeed_segments_spi[] = { - { 0x30000000, 64 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_ast2500_fmc[] = { - { 0x20000000, 128 * 1024 * 1024 }, /* start address is readonly */ - { 0x28000000, 32 * 1024 * 1024 }, - { 0x2A000000, 32 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_ast2500_spi1[] = { - { 0x30000000, 32 * 1024 * 1024 }, /* start address is readonly */ - { 0x32000000, 96 * 1024 * 1024 }, /* end address is readonly */ -}; - -static const AspeedSegments aspeed_segments_ast2500_spi2[] = { - { 0x38000000, 32 * 1024 * 1024 }, /* start address is readonly */ - { 0x3A000000, 96 * 1024 * 1024 }, /* end address is readonly */ -}; -static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg); -static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg, - AspeedSegments *seg); -static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t value); - -/* - * AST2600 definitions - */ -#define ASPEED26_SOC_FMC_FLASH_BASE 0x20000000 -#define ASPEED26_SOC_SPI_FLASH_BASE 0x30000000 -#define ASPEED26_SOC_SPI2_FLASH_BASE 0x50000000 - -static const AspeedSegments aspeed_segments_ast2600_fmc[] = { - { 0x0, 128 * MiB }, /* start address is readonly */ - { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */ - { 0x0, 0 }, /* disabled */ -}; - -static const AspeedSegments aspeed_segments_ast2600_spi1[] = { - { 0x0, 128 * MiB }, /* start address is readonly */ - { 0x0, 0 }, /* disabled */ -}; - -static const AspeedSegments aspeed_segments_ast2600_spi2[] = { - { 0x0, 128 * MiB }, /* start address is readonly */ - { 0x0, 0 }, /* disabled */ - { 0x0, 0 }, /* disabled */ -}; - -static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg); -static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, - uint32_t reg, AspeedSegments *seg); -static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t value); +static const AspeedSegments aspeed_2400_fmc_segments[]; +static const AspeedSegments aspeed_2400_spi1_segments[]; +static const AspeedSegments aspeed_2500_fmc_segments[]; +static const AspeedSegments aspeed_2500_spi1_segments[]; +static const AspeedSegments aspeed_2500_spi2_segments[]; +static const AspeedSegments aspeed_2600_fmc_segments[]; #define ASPEED_SMC_FEATURE_DMA 0x1 #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2 #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4 -static inline bool aspeed_smc_has_dma(const AspeedSMCState *s) -{ - return !!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA); -} - -static inline bool aspeed_smc_has_wdt_control(const AspeedSMCState *s) -{ - return !!(s->ctrl->features & ASPEED_SMC_FEATURE_WDT_CONTROL); -} - -static const AspeedSMCController controllers[] = { - { - .name = "aspeed.smc-ast2400", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 1, - .segments = aspeed_segments_legacy, - .flash_window_base = ASPEED_SOC_SMC_FLASH_BASE, - .flash_window_size = 0x6000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_SMC_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.fmc-ast2400", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 5, - .segments = aspeed_segments_fmc, - .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x1FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.spi1-ast2400", - .r_conf = R_SPI_CONF, - .r_ce_ctrl = 0xff, - .r_ctrl0 = R_SPI_CTRL0, - .r_timings = R_SPI_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = SPI_CONF_ENABLE_W0, - .max_peripherals = 1, - .segments = aspeed_segments_spi, - .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_SPI_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.fmc-ast2500", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 3, - .segments = aspeed_segments_ast2500_fmc, - .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.spi1-ast2500", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 2, - .segments = aspeed_segments_ast2500_spi1, - .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, - .flash_window_size = 0x8000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.spi2-ast2500", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 2, - .segments = aspeed_segments_ast2500_spi2, - .flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE, - .flash_window_size = 0x8000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.fmc-ast2600", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 3, - .segments = aspeed_segments_ast2600_fmc, - .flash_window_base = ASPEED26_SOC_FMC_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_WDT_CONTROL, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_2600_smc_segment_to_reg, - .reg_to_segment = aspeed_2600_smc_reg_to_segment, - .dma_ctrl = aspeed_2600_smc_dma_ctrl, - }, { - .name = "aspeed.spi1-ast2600", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 2, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 2, - .segments = aspeed_segments_ast2600_spi1, - .flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_GRANT, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_2600_smc_segment_to_reg, - .reg_to_segment = aspeed_2600_smc_reg_to_segment, - .dma_ctrl = aspeed_2600_smc_dma_ctrl, - }, { - .name = "aspeed.spi2-ast2600", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 3, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 3, - .segments = aspeed_segments_ast2600_spi2, - .flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_GRANT, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_2600_smc_segment_to_reg, - .reg_to_segment = aspeed_2600_smc_reg_to_segment, - .dma_ctrl = aspeed_2600_smc_dma_ctrl, - }, -}; - -/* - * The Segment Registers of the AST2400 and AST2500 have a 8MB - * unit. The address range of a flash SPI peripheral is encoded with - * absolute addresses which should be part of the overall controller - * window. - */ -static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg) -{ - uint32_t reg = 0; - reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; - reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; - return reg; -} - -static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, - uint32_t reg, AspeedSegments *seg) -{ - seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; - seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; -} - -/* - * The Segment Registers of the AST2600 have a 1MB unit. The address - * range of a flash SPI peripheral is encoded with offsets in the overall - * controller window. The previous SoC AST2400 and AST2500 used - * absolute addresses. Only bits [27:20] are relevant and the end - * address is an upper bound limit. - */ -#define AST2600_SEG_ADDR_MASK 0x0ff00000 - -static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg) +static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc) { - uint32_t reg = 0; - - /* Disabled segments have a nil register */ - if (!seg->size) { - return 0; - } - - reg |= (seg->addr & AST2600_SEG_ADDR_MASK) >> 16; /* start offset */ - reg |= (seg->addr + seg->size - 1) & AST2600_SEG_ADDR_MASK; /* end offset */ - return reg; + return !!(asc->features & ASPEED_SMC_FEATURE_DMA); } -static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, - uint32_t reg, AspeedSegments *seg) +static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc) { - uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK; - uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK; - - if (reg) { - seg->addr = s->ctrl->flash_window_base + start_offset; - seg->size = end_offset + MiB - start_offset; - } else { - seg->addr = s->ctrl->flash_window_base; - seg->size = 0; - } + return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL); } #define aspeed_smc_error(fmt, ...) \ @@ -520,15 +224,16 @@ static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, const AspeedSegments *new, int cs) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSegments seg; int i; - for (i = 0; i < s->ctrl->max_peripherals; i++) { + for (i = 0; i < asc->max_peripherals; i++) { if (i == cs) { continue; } - s->ctrl->reg_to_segment(s, s->regs[R_SEG_ADDR0 + i], &seg); + asc->reg_to_segment(s, s->regs[R_SEG_ADDR0 + i], &seg); if (new->addr + new->size > seg.addr && new->addr < seg.addr + seg.size) { @@ -546,14 +251,15 @@ static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, static void aspeed_smc_flash_set_segment_region(AspeedSMCState *s, int cs, uint64_t regval) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSMCFlash *fl = &s->flashes[cs]; AspeedSegments seg; - s->ctrl->reg_to_segment(s, regval, &seg); + asc->reg_to_segment(s, regval, &seg); memory_region_transaction_begin(); memory_region_set_size(&fl->mmio, seg.size); - memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base); + memory_region_set_address(&fl->mmio, seg.addr - asc->flash_window_base); memory_region_set_enabled(&fl->mmio, !!seg.size); memory_region_transaction_commit(); @@ -563,40 +269,41 @@ static void aspeed_smc_flash_set_segment_region(AspeedSMCState *s, int cs, static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, uint64_t new) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSegments seg; - s->ctrl->reg_to_segment(s, new, &seg); + asc->reg_to_segment(s, new, &seg); trace_aspeed_smc_flash_set_segment(cs, new, seg.addr, seg.addr + seg.size); /* The start address of CS0 is read-only */ - if (cs == 0 && seg.addr != s->ctrl->flash_window_base) { + if (cs == 0 && seg.addr != asc->flash_window_base) { aspeed_smc_error("Tried to change CS0 start address to 0x%" HWADDR_PRIx, seg.addr); - seg.addr = s->ctrl->flash_window_base; - new = s->ctrl->segment_to_reg(s, &seg); + seg.addr = asc->flash_window_base; + new = asc->segment_to_reg(s, &seg); } /* * The end address of the AST2500 spi controllers is also * read-only. */ - if ((s->ctrl->segments == aspeed_segments_ast2500_spi1 || - s->ctrl->segments == aspeed_segments_ast2500_spi2) && - cs == s->ctrl->max_peripherals && - seg.addr + seg.size != s->ctrl->segments[cs].addr + - s->ctrl->segments[cs].size) { + if ((asc->segments == aspeed_2500_spi1_segments || + asc->segments == aspeed_2500_spi2_segments) && + cs == asc->max_peripherals && + seg.addr + seg.size != asc->segments[cs].addr + + asc->segments[cs].size) { aspeed_smc_error("Tried to change CS%d end address to 0x%" HWADDR_PRIx, cs, seg.addr + seg.size); - seg.size = s->ctrl->segments[cs].addr + s->ctrl->segments[cs].size - + seg.size = asc->segments[cs].addr + asc->segments[cs].size - seg.addr; - new = s->ctrl->segment_to_reg(s, &seg); + new = asc->segment_to_reg(s, &seg); } /* Keep the segment in the overall flash window */ if (seg.size && - (seg.addr + seg.size <= s->ctrl->flash_window_base || - seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size)) { + (seg.addr + seg.size <= asc->flash_window_base || + seg.addr > asc->flash_window_base + asc->flash_window_size)) { aspeed_smc_error("new segment for CS%d is invalid : " "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]", cs, seg.addr, seg.addr + seg.size); @@ -681,8 +388,9 @@ static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl) static inline int aspeed_smc_flash_is_4byte(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); - if (s->ctrl->segments == aspeed_segments_spi) { + if (asc->segments == aspeed_2400_spi1_segments) { return s->regs[s->r_ctrl0] & CTRL_AST2400_SPI_4BYTE; } else { return s->regs[s->r_ce_ctrl] & (1 << (CTRL_EXTENDED0 + fl->id)); @@ -712,9 +420,10 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl, uint32_t addr) { const AspeedSMCState *s = fl->controller; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSegments seg; - s->ctrl->reg_to_segment(s, s->regs[R_SEG_ADDR0 + fl->id], &seg); + asc->reg_to_segment(s, s->regs[R_SEG_ADDR0 + fl->id], &seg); if ((addr % seg.size) != addr) { aspeed_smc_error("invalid address 0x%08x for CS%d segment : " "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]", @@ -974,6 +683,7 @@ static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value) static void aspeed_smc_reset(DeviceState *d) { AspeedSMCState *s = ASPEED_SMC(d); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); int i; memset(s->regs, 0, sizeof s->regs); @@ -985,13 +695,13 @@ static void aspeed_smc_reset(DeviceState *d) } /* setup the default segment register values and regions for all */ - for (i = 0; i < s->ctrl->max_peripherals; ++i) { + for (i = 0; i < asc->max_peripherals; ++i) { aspeed_smc_flash_set_segment_region(s, i, - s->ctrl->segment_to_reg(s, &s->ctrl->segments[i])); + asc->segment_to_reg(s, &asc->segments[i])); } /* HW strapping flash type for the AST2600 controllers */ - if (s->ctrl->segments == aspeed_segments_ast2600_fmc) { + if (asc->segments == aspeed_2600_fmc_segments) { /* flash type is fixed to SPI for all */ s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1); @@ -999,7 +709,7 @@ static void aspeed_smc_reset(DeviceState *d) } /* HW strapping flash type for FMC controllers */ - if (s->ctrl->segments == aspeed_segments_ast2500_fmc) { + if (asc->segments == aspeed_2500_fmc_segments) { /* flash type is fixed to SPI for CE0 and CE1 */ s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1); @@ -1007,7 +717,7 @@ static void aspeed_smc_reset(DeviceState *d) /* HW strapping for AST2400 FMC controllers (SCU70). Let's use the * configuration of the palmetto-bmc machine */ - if (s->ctrl->segments == aspeed_segments_fmc) { + if (asc->segments == aspeed_2400_fmc_segments) { s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); } @@ -1018,25 +728,26 @@ static void aspeed_smc_reset(DeviceState *d) static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) { AspeedSMCState *s = ASPEED_SMC(opaque); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(opaque); addr >>= 2; if (addr == s->r_conf || (addr >= s->r_timings && - addr < s->r_timings + s->ctrl->nregs_timings) || + addr < s->r_timings + asc->nregs_timings) || addr == s->r_ce_ctrl || addr == R_CE_CMD_CTRL || addr == R_INTR_CTRL || addr == R_DUMMY_DATA || - (aspeed_smc_has_wdt_control(s) && addr == R_FMC_WDT2_CTRL) || - (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) || - (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) || - (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) || - (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) || - (aspeed_smc_has_dma(s) && addr == R_DMA_CHECKSUM) || + (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) || + (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) || + (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) || + (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) || + (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) || + (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) || (addr >= R_SEG_ADDR0 && - addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) || - (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_peripherals)) { + addr < R_SEG_ADDR0 + asc->max_peripherals) || + (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + asc->max_peripherals)) { trace_aspeed_smc_read(addr, size, s->regs[addr]); @@ -1292,7 +1003,9 @@ static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl) static inline bool aspeed_smc_dma_granted(AspeedSMCState *s) { - if (!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA_GRANT)) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + + if (!(asc->features & ASPEED_SMC_FEATURE_DMA_GRANT)) { return true; } @@ -1334,6 +1047,7 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { AspeedSMCState *s = ASPEED_SMC(opaque); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); uint32_t value = data; addr >>= 2; @@ -1342,14 +1056,14 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, if (addr == s->r_conf || (addr >= s->r_timings && - addr < s->r_timings + s->ctrl->nregs_timings) || + addr < s->r_timings + asc->nregs_timings) || addr == s->r_ce_ctrl) { s->regs[addr] = value; } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) { int cs = addr - s->r_ctrl0; aspeed_smc_flash_update_ctrl(&s->flashes[cs], value); } else if (addr >= R_SEG_ADDR0 && - addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) { + addr < R_SEG_ADDR0 + asc->max_peripherals) { int cs = addr - R_SEG_ADDR0; if (value != s->regs[R_SEG_ADDR0 + cs]) { @@ -1359,19 +1073,19 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, s->regs[addr] = value & 0xff; } else if (addr == R_DUMMY_DATA) { s->regs[addr] = value & 0xff; - } else if (aspeed_smc_has_wdt_control(s) && addr == R_FMC_WDT2_CTRL) { + } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) { s->regs[addr] = value & FMC_WDT2_CTRL_EN; } else if (addr == R_INTR_CTRL) { s->regs[addr] = value; - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) { - s->ctrl->dma_ctrl(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR && + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) { + asc->dma_ctrl(s, value); + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR && aspeed_smc_dma_granted(s)) { - s->regs[addr] = DMA_DRAM_ADDR(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR && + s->regs[addr] = DMA_DRAM_ADDR(asc, value); + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR && aspeed_smc_dma_granted(s)) { - s->regs[addr] = DMA_FLASH_ADDR(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN && + s->regs[addr] = DMA_FLASH_ADDR(asc, value); + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN && aspeed_smc_dma_granted(s)) { s->regs[addr] = DMA_LENGTH(value); } else { @@ -1407,24 +1121,22 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedSMCState *s = ASPEED_SMC(dev); - AspeedSMCClass *mc = ASPEED_SMC_GET_CLASS(s); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); int i; char name[32]; hwaddr offset = 0; - s->ctrl = mc->ctrl; - /* keep a copy under AspeedSMCState to speed up accesses */ - s->r_conf = s->ctrl->r_conf; - s->r_ce_ctrl = s->ctrl->r_ce_ctrl; - s->r_ctrl0 = s->ctrl->r_ctrl0; - s->r_timings = s->ctrl->r_timings; - s->conf_enable_w0 = s->ctrl->conf_enable_w0; + s->r_conf = asc->r_conf; + s->r_ce_ctrl = asc->r_ce_ctrl; + s->r_ctrl0 = asc->r_ctrl0; + s->r_timings = asc->r_timings; + s->conf_enable_w0 = asc->conf_enable_w0; /* Enforce some real HW limits */ - if (s->num_cs > s->ctrl->max_peripherals) { - aspeed_smc_error("num_cs cannot exceed: %d", s->ctrl->max_peripherals); - s->num_cs = s->ctrl->max_peripherals; + if (s->num_cs > asc->max_peripherals) { + aspeed_smc_error("num_cs cannot exceed: %d", asc->max_peripherals); + s->num_cs = asc->max_peripherals; } /* DMA irq. Keep it first for the initialization in the SoC */ @@ -1441,7 +1153,7 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) /* The memory region for the controller registers */ memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s, - TYPE_ASPEED_SMC, s->ctrl->nregs * 4); + TYPE_ASPEED_SMC, asc->nregs * 4); sysbus_init_mmio(sbd, &s->mmio); /* @@ -1452,13 +1164,13 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->mmio_flash, OBJECT(s), &aspeed_smc_flash_default_ops, s, TYPE_ASPEED_SMC ".flash", - s->ctrl->flash_window_size); + asc->flash_window_size); memory_region_init_alias(&s->mmio_flash_alias, OBJECT(s), TYPE_ASPEED_SMC ".flash", - &s->mmio_flash, 0, s->ctrl->flash_window_size); + &s->mmio_flash, 0, asc->flash_window_size); sysbus_init_mmio(sbd, &s->mmio_flash_alias); - s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_peripherals); + s->flashes = g_new0(AspeedSMCFlash, asc->max_peripherals); /* * Let's create a sub memory region for each possible peripheral. All @@ -1467,14 +1179,14 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) * module behind to handle the memory accesses. This depends on * the board configuration. */ - for (i = 0; i < s->ctrl->max_peripherals; ++i) { + for (i = 0; i < asc->max_peripherals; ++i) { AspeedSMCFlash *fl = &s->flashes[i]; snprintf(name, sizeof(name), TYPE_ASPEED_SMC ".flash.%d", i); fl->id = i; fl->controller = s; - fl->size = s->ctrl->segments[i].size; + fl->size = asc->segments[i].size; memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops, fl, name, fl->size); memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio); @@ -1482,7 +1194,7 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) } /* DMA support */ - if (aspeed_smc_has_dma(s)) { + if (aspeed_smc_has_dma(asc)) { aspeed_smc_dma_setup(s, errp); } } @@ -1510,13 +1222,11 @@ static Property aspeed_smc_properties[] = { static void aspeed_smc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - AspeedSMCClass *mc = ASPEED_SMC_CLASS(klass); dc->realize = aspeed_smc_realize; dc->reset = aspeed_smc_reset; device_class_set_props(dc, aspeed_smc_properties); dc->vmsd = &vmstate_aspeed_smc; - mc->ctrl = data; } static const TypeInfo aspeed_smc_info = { @@ -1524,23 +1234,408 @@ static const TypeInfo aspeed_smc_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AspeedSMCState), .class_size = sizeof(AspeedSMCClass), + .class_init = aspeed_smc_class_init, .abstract = true, }; -static void aspeed_smc_register_types(void) + +/* + * The Segment Registers of the AST2400 and AST2500 have a 8MB + * unit. The address range of a flash SPI peripheral is encoded with + * absolute addresses which should be part of the overall controller + * window. + */ +static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, + const AspeedSegments *seg) { - int i; + uint32_t reg = 0; + reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; + reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; + return reg; +} - type_register_static(&aspeed_smc_info); - for (i = 0; i < ARRAY_SIZE(controllers); ++i) { - TypeInfo ti = { - .name = controllers[i].name, - .parent = TYPE_ASPEED_SMC, - .class_init = aspeed_smc_class_init, - .class_data = (void *)&controllers[i], - }; - type_register(&ti); +static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, + uint32_t reg, AspeedSegments *seg) +{ + seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; + seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; +} + +static const AspeedSegments aspeed_2400_smc_segments[] = { + { 0x10000000, 32 * MiB }, +}; + +static void aspeed_2400_smc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2400 SMC Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 1; + asc->segments = aspeed_2400_smc_segments; + asc->flash_window_base = 0x10000000; + asc->flash_window_size = 0x6000000; + asc->features = 0x0; + asc->nregs = ASPEED_SMC_R_SMC_MAX; + asc->segment_to_reg = aspeed_smc_segment_to_reg; + asc->reg_to_segment = aspeed_smc_reg_to_segment; + asc->dma_ctrl = aspeed_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2400_smc_info = { + .name = "aspeed.smc-ast2400", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2400_smc_class_init, +}; + +static const AspeedSegments aspeed_2400_fmc_segments[] = { + { 0x20000000, 64 * MiB }, /* start address is readonly */ + { 0x24000000, 32 * MiB }, + { 0x26000000, 32 * MiB }, + { 0x28000000, 32 * MiB }, + { 0x2A000000, 32 * MiB } +}; + +static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2400 FMC Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 5; + asc->segments = aspeed_2400_fmc_segments; + asc->flash_window_base = 0x20000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x1FFFFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_smc_segment_to_reg; + asc->reg_to_segment = aspeed_smc_reg_to_segment; + asc->dma_ctrl = aspeed_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2400_fmc_info = { + .name = "aspeed.fmc-ast2400", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2400_fmc_class_init, +}; + +static const AspeedSegments aspeed_2400_spi1_segments[] = { + { 0x30000000, 64 * MiB }, +}; + +static void aspeed_2400_spi1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2400 SPI1 Controller"; + asc->r_conf = R_SPI_CONF; + asc->r_ce_ctrl = 0xff; + asc->r_ctrl0 = R_SPI_CTRL0; + asc->r_timings = R_SPI_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = SPI_CONF_ENABLE_W0; + asc->max_peripherals = 1; + asc->segments = aspeed_2400_spi1_segments; + asc->flash_window_base = 0x30000000; + asc->flash_window_size = 0x10000000; + asc->features = 0x0; + asc->nregs = ASPEED_SMC_R_SPI_MAX; + asc->segment_to_reg = aspeed_smc_segment_to_reg; + asc->reg_to_segment = aspeed_smc_reg_to_segment; + asc->dma_ctrl = aspeed_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2400_spi1_info = { + .name = "aspeed.spi1-ast2400", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2400_spi1_class_init, +}; + +static const AspeedSegments aspeed_2500_fmc_segments[] = { + { 0x20000000, 128 * MiB }, /* start address is readonly */ + { 0x28000000, 32 * MiB }, + { 0x2A000000, 32 * MiB }, +}; + +static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 FMC Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 3; + asc->segments = aspeed_2500_fmc_segments; + asc->flash_window_base = 0x20000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_smc_segment_to_reg; + asc->reg_to_segment = aspeed_smc_reg_to_segment; + asc->dma_ctrl = aspeed_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2500_fmc_info = { + .name = "aspeed.fmc-ast2500", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2500_fmc_class_init, +}; + +static const AspeedSegments aspeed_2500_spi1_segments[] = { + { 0x30000000, 32 * MiB }, /* start address is readonly */ + { 0x32000000, 96 * MiB }, /* end address is readonly */ +}; + +static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 SPI1 Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 2; + asc->segments = aspeed_2500_spi1_segments; + asc->flash_window_base = 0x30000000; + asc->flash_window_size = 0x8000000; + asc->features = 0x0; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_smc_segment_to_reg; + asc->reg_to_segment = aspeed_smc_reg_to_segment; + asc->dma_ctrl = aspeed_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2500_spi1_info = { + .name = "aspeed.spi1-ast2500", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2500_spi1_class_init, +}; + +static const AspeedSegments aspeed_2500_spi2_segments[] = { + { 0x38000000, 32 * MiB }, /* start address is readonly */ + { 0x3A000000, 96 * MiB }, /* end address is readonly */ +}; + +static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 SPI2 Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 2; + asc->segments = aspeed_2500_spi2_segments; + asc->flash_window_base = 0x38000000; + asc->flash_window_size = 0x8000000; + asc->features = 0x0; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_smc_segment_to_reg; + asc->reg_to_segment = aspeed_smc_reg_to_segment; + asc->dma_ctrl = aspeed_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2500_spi2_info = { + .name = "aspeed.spi2-ast2500", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2500_spi2_class_init, +}; + +/* + * The Segment Registers of the AST2600 have a 1MB unit. The address + * range of a flash SPI peripheral is encoded with offsets in the overall + * controller window. The previous SoC AST2400 and AST2500 used + * absolute addresses. Only bits [27:20] are relevant and the end + * address is an upper bound limit. + */ +#define AST2600_SEG_ADDR_MASK 0x0ff00000 + +static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s, + const AspeedSegments *seg) +{ + uint32_t reg = 0; + + /* Disabled segments have a nil register */ + if (!seg->size) { + return 0; + } + + reg |= (seg->addr & AST2600_SEG_ADDR_MASK) >> 16; /* start offset */ + reg |= (seg->addr + seg->size - 1) & AST2600_SEG_ADDR_MASK; /* end offset */ + return reg; +} + +static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, + uint32_t reg, AspeedSegments *seg) +{ + uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK; + uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + + if (reg) { + seg->addr = asc->flash_window_base + start_offset; + seg->size = end_offset + MiB - start_offset; + } else { + seg->addr = asc->flash_window_base; + seg->size = 0; } } +static const AspeedSegments aspeed_2600_fmc_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 FMC Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 3; + asc->segments = aspeed_2600_fmc_segments; + asc->flash_window_base = 0x20000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_WDT_CONTROL; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; + asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; + asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2600_fmc_info = { + .name = "aspeed.fmc-ast2600", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2600_fmc_class_init, +}; + +static const AspeedSegments aspeed_2600_spi1_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 SPI1 Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 2; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 2; + asc->segments = aspeed_2600_spi1_segments; + asc->flash_window_base = 0x30000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_DMA_GRANT; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; + asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; + asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2600_spi1_info = { + .name = "aspeed.spi1-ast2600", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2600_spi1_class_init, +}; + +static const AspeedSegments aspeed_2600_spi2_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 0x0, 0 }, /* disabled */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 SPI2 Controller"; + asc->r_conf = R_CONF; + asc->r_ce_ctrl = R_CE_CTRL; + asc->r_ctrl0 = R_CTRL0; + asc->r_timings = R_TIMINGS; + asc->nregs_timings = 3; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 3; + asc->segments = aspeed_2600_spi2_segments; + asc->flash_window_base = 0x50000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_DMA_GRANT; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + asc->nregs = ASPEED_SMC_R_MAX; + asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; + asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; + asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; +} + +static const TypeInfo aspeed_2600_spi2_info = { + .name = "aspeed.spi2-ast2600", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2600_spi2_class_init, +}; + +static void aspeed_smc_register_types(void) +{ + type_register_static(&aspeed_smc_info); + type_register_static(&aspeed_2400_smc_info); + type_register_static(&aspeed_2400_fmc_info); + type_register_static(&aspeed_2400_spi1_info); + type_register_static(&aspeed_2500_fmc_info); + type_register_static(&aspeed_2500_spi1_info); + type_register_static(&aspeed_2500_spi2_info); + type_register_static(&aspeed_2600_fmc_info); + type_register_static(&aspeed_2600_spi1_info); + type_register_static(&aspeed_2600_spi2_info); +} + type_init(aspeed_smc_register_types) |