* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "cpu.h"
#include "hw/hw.h"
#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc4xx.h"
+#include "hw/boards.h"
#include "qemu/log.h"
#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
-#define DEBUG_UIC
-
+/*#define DEBUG_UIC*/
#ifdef DEBUG_UIC
# define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
/*****************************************************************************/
/* Generic PowerPC 4xx processor instantiation */
-PowerPCCPU *ppc4xx_init(const char *cpu_model,
+PowerPCCPU *ppc4xx_init(const char *cpu_type,
clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
uint32_t sysclk)
{
CPUPPCState *env;
/* init CPUs */
- cpu = cpu_ppc_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
- cpu_model);
- exit(1);
- }
+ cpu = POWERPC_CPU(cpu_create(cpu_type));
env = &cpu->env;
cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
uint32_t mask, sr;
uic = opaque;
- mask = 1 << (31-irq_num);
+ mask = 1U << (31-irq_num);
LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
" mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
__func__, irq_num, level,
uint32_t bcr;
switch (ram_size) {
- case (4 * 1024 * 1024):
+ case 4 * MiB:
bcr = 0x00000000;
break;
- case (8 * 1024 * 1024):
+ case 8 * MiB:
bcr = 0x00020000;
break;
- case (16 * 1024 * 1024):
+ case 16 * MiB:
bcr = 0x00040000;
break;
- case (32 * 1024 * 1024):
+ case 32 * MiB:
bcr = 0x00060000;
break;
- case (64 * 1024 * 1024):
+ case 64 * MiB:
bcr = 0x00080000;
break;
- case (128 * 1024 * 1024):
+ case 128 * MiB:
bcr = 0x000A0000;
break;
- case (256 * 1024 * 1024):
+ case 256 * MiB:
bcr = 0x000C0000;
break;
default:
if (sh == 7)
size = -1;
else
- size = (4 * 1024 * 1024) << sh;
+ size = (4 * MiB) << sh;
return size;
}
-static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
- uint32_t *bcrp, uint32_t bcr, int enabled)
+static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
+ uint32_t bcr, int enabled)
{
- unsigned n = bcrp - sdram->bcr;
-
- if (*bcrp & 0x00000001) {
+ if (sdram->bcr[i] & 0x00000001) {
/* Unmap RAM */
#ifdef DEBUG_SDRAM
printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
- __func__, sdram_base(*bcrp), sdram_size(*bcrp));
+ __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
#endif
memory_region_del_subregion(get_system_memory(),
- &sdram->containers[n]);
- memory_region_del_subregion(&sdram->containers[n],
- &sdram->ram_memories[n]);
- memory_region_destroy(&sdram->containers[n]);
+ &sdram->containers[i]);
+ memory_region_del_subregion(&sdram->containers[i],
+ &sdram->ram_memories[i]);
+ object_unparent(OBJECT(&sdram->containers[i]));
}
- *bcrp = bcr & 0xFFDEE001;
+ sdram->bcr[i] = bcr & 0xFFDEE001;
if (enabled && (bcr & 0x00000001)) {
#ifdef DEBUG_SDRAM
printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
__func__, sdram_base(bcr), sdram_size(bcr));
#endif
- memory_region_init(&sdram->containers[n], NULL, "sdram-containers",
+ memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
sdram_size(bcr));
- memory_region_add_subregion(&sdram->containers[n], 0,
- &sdram->ram_memories[n]);
+ memory_region_add_subregion(&sdram->containers[i], 0,
+ &sdram->ram_memories[i]);
memory_region_add_subregion(get_system_memory(),
sdram_base(bcr),
- &sdram->containers[n]);
+ &sdram->containers[i]);
}
}
for (i = 0; i < sdram->nbanks; i++) {
if (sdram->ram_sizes[i] != 0) {
- sdram_set_bcr(sdram,
- &sdram->bcr[i],
- sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
- 1);
+ sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i],
+ sdram->ram_sizes[i]), 1);
} else {
- sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0);
+ sdram_set_bcr(sdram, i, 0x00000000, 0);
}
}
}
sdram->pmit = (val & 0xF8000000) | 0x07C00000;
break;
case 0x40: /* SDRAM_B0CR */
- sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000);
+ sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
break;
case 0x44: /* SDRAM_B1CR */
- sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000);
+ sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
break;
case 0x48: /* SDRAM_B2CR */
- sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000);
+ sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
break;
case 0x4C: /* SDRAM_B3CR */
- sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000);
+ sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
break;
case 0x80: /* SDRAM_TR */
sdram->tr = val & 0x018FC01F;
MemoryRegion ram_memories[],
hwaddr ram_bases[],
hwaddr ram_sizes[],
- const unsigned int sdram_bank_sizes[])
+ const ram_addr_t sdram_bank_sizes[])
{
+ MemoryRegion *ram = g_malloc0(sizeof(*ram));
ram_addr_t size_left = ram_size;
ram_addr_t base = 0;
+ ram_addr_t bank_size;
int i;
int j;
for (i = 0; i < nr_banks; i++) {
for (j = 0; sdram_bank_sizes[j] != 0; j++) {
- unsigned int bank_size = sdram_bank_sizes[j];
+ bank_size = sdram_bank_sizes[j];
+ if (bank_size <= size_left) {
+ size_left -= bank_size;
+ }
+ }
+ if (!size_left) {
+ /* No need to use the remaining banks. */
+ break;
+ }
+ }
+
+ ram_size -= size_left;
+ if (size_left) {
+ error_report("Truncating memory to %" PRId64 " MiB to fit SDRAM"
+ " controller limits", ram_size / MiB);
+ }
+
+ memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram", ram_size);
+
+ size_left = ram_size;
+ for (i = 0; i < nr_banks && size_left; i++) {
+ for (j = 0; sdram_bank_sizes[j] != 0; j++) {
+ bank_size = sdram_bank_sizes[j];
if (bank_size <= size_left) {
char name[32];
snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
- memory_region_init_ram(&ram_memories[i], NULL, name, bank_size);
- vmstate_register_ram_global(&ram_memories[i]);
+ memory_region_init_alias(&ram_memories[i], NULL, name, ram,
+ base, bank_size);
ram_bases[i] = base;
ram_sizes[i] = bank_size;
base += bank_size;
break;
}
}
+ }
- if (!size_left) {
- /* No need to use the remaining banks. */
- break;
+ return ram_size;
+}
+
+/*****************************************************************************/
+/* MAL */
+
+enum {
+ MAL0_CFG = 0x180,
+ MAL0_ESR = 0x181,
+ MAL0_IER = 0x182,
+ MAL0_TXCASR = 0x184,
+ MAL0_TXCARR = 0x185,
+ MAL0_TXEOBISR = 0x186,
+ MAL0_TXDEIR = 0x187,
+ MAL0_RXCASR = 0x190,
+ MAL0_RXCARR = 0x191,
+ MAL0_RXEOBISR = 0x192,
+ MAL0_RXDEIR = 0x193,
+ MAL0_TXCTP0R = 0x1A0,
+ MAL0_RXCTP0R = 0x1C0,
+ MAL0_RCBS0 = 0x1E0,
+ MAL0_RCBS1 = 0x1E1,
+};
+
+typedef struct ppc4xx_mal_t ppc4xx_mal_t;
+struct ppc4xx_mal_t {
+ qemu_irq irqs[4];
+ uint32_t cfg;
+ uint32_t esr;
+ uint32_t ier;
+ uint32_t txcasr;
+ uint32_t txcarr;
+ uint32_t txeobisr;
+ uint32_t txdeir;
+ uint32_t rxcasr;
+ uint32_t rxcarr;
+ uint32_t rxeobisr;
+ uint32_t rxdeir;
+ uint32_t *txctpr;
+ uint32_t *rxctpr;
+ uint32_t *rcbs;
+ uint8_t txcnum;
+ uint8_t rxcnum;
+};
+
+static void ppc4xx_mal_reset(void *opaque)
+{
+ ppc4xx_mal_t *mal;
+
+ mal = opaque;
+ mal->cfg = 0x0007C000;
+ mal->esr = 0x00000000;
+ mal->ier = 0x00000000;
+ mal->rxcasr = 0x00000000;
+ mal->rxdeir = 0x00000000;
+ mal->rxeobisr = 0x00000000;
+ mal->txcasr = 0x00000000;
+ mal->txdeir = 0x00000000;
+ mal->txeobisr = 0x00000000;
+}
+
+static uint32_t dcr_read_mal(void *opaque, int dcrn)
+{
+ ppc4xx_mal_t *mal;
+ uint32_t ret;
+
+ mal = opaque;
+ switch (dcrn) {
+ case MAL0_CFG:
+ ret = mal->cfg;
+ break;
+ case MAL0_ESR:
+ ret = mal->esr;
+ break;
+ case MAL0_IER:
+ ret = mal->ier;
+ break;
+ case MAL0_TXCASR:
+ ret = mal->txcasr;
+ break;
+ case MAL0_TXCARR:
+ ret = mal->txcarr;
+ break;
+ case MAL0_TXEOBISR:
+ ret = mal->txeobisr;
+ break;
+ case MAL0_TXDEIR:
+ ret = mal->txdeir;
+ break;
+ case MAL0_RXCASR:
+ ret = mal->rxcasr;
+ break;
+ case MAL0_RXCARR:
+ ret = mal->rxcarr;
+ break;
+ case MAL0_RXEOBISR:
+ ret = mal->rxeobisr;
+ break;
+ case MAL0_RXDEIR:
+ ret = mal->rxdeir;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
+ ret = mal->txctpr[dcrn - MAL0_TXCTP0R];
+ }
+ if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
+ ret = mal->rxctpr[dcrn - MAL0_RXCTP0R];
+ }
+ if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
+ ret = mal->rcbs[dcrn - MAL0_RCBS0];
+ }
+
+ return ret;
+}
+
+static void dcr_write_mal(void *opaque, int dcrn, uint32_t val)
+{
+ ppc4xx_mal_t *mal;
+
+ mal = opaque;
+ switch (dcrn) {
+ case MAL0_CFG:
+ if (val & 0x80000000) {
+ ppc4xx_mal_reset(mal);
}
+ mal->cfg = val & 0x00FFC087;
+ break;
+ case MAL0_ESR:
+ /* Read/clear */
+ mal->esr &= ~val;
+ break;
+ case MAL0_IER:
+ mal->ier = val & 0x0000001F;
+ break;
+ case MAL0_TXCASR:
+ mal->txcasr = val & 0xF0000000;
+ break;
+ case MAL0_TXCARR:
+ mal->txcarr = val & 0xF0000000;
+ break;
+ case MAL0_TXEOBISR:
+ /* Read/clear */
+ mal->txeobisr &= ~val;
+ break;
+ case MAL0_TXDEIR:
+ /* Read/clear */
+ mal->txdeir &= ~val;
+ break;
+ case MAL0_RXCASR:
+ mal->rxcasr = val & 0xC0000000;
+ break;
+ case MAL0_RXCARR:
+ mal->rxcarr = val & 0xC0000000;
+ break;
+ case MAL0_RXEOBISR:
+ /* Read/clear */
+ mal->rxeobisr &= ~val;
+ break;
+ case MAL0_RXDEIR:
+ /* Read/clear */
+ mal->rxdeir &= ~val;
+ break;
+ }
+ if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
+ mal->txctpr[dcrn - MAL0_TXCTP0R] = val;
}
+ if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
+ mal->rxctpr[dcrn - MAL0_RXCTP0R] = val;
+ }
+ if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
+ mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF;
+ }
+}
- ram_size -= size_left;
- if (size_left)
- printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
- (int)(ram_size >> 20));
+void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
+ qemu_irq irqs[4])
+{
+ ppc4xx_mal_t *mal;
+ int i;
- return ram_size;
+ assert(txcnum <= 32 && rxcnum <= 32);
+ mal = g_malloc0(sizeof(*mal));
+ mal->txcnum = txcnum;
+ mal->rxcnum = rxcnum;
+ mal->txctpr = g_new0(uint32_t, txcnum);
+ mal->rxctpr = g_new0(uint32_t, rxcnum);
+ mal->rcbs = g_new0(uint32_t, rxcnum);
+ for (i = 0; i < 4; i++) {
+ mal->irqs[i] = irqs[i];
+ }
+ qemu_register_reset(&ppc4xx_mal_reset, mal);
+ ppc_dcr_register(env, MAL0_CFG,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_ESR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_IER,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCASR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCARR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXEOBISR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXDEIR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXCASR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXCARR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXEOBISR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXDEIR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ for (i = 0; i < txcnum; i++) {
+ ppc_dcr_register(env, MAL0_TXCTP0R + i,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ }
+ for (i = 0; i < rxcnum; i++) {
+ ppc_dcr_register(env, MAL0_RXCTP0R + i,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ }
+ for (i = 0; i < rxcnum; i++) {
+ ppc_dcr_register(env, MAL0_RCBS0 + i,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ }
}