Add MVME3100 PPC SBC v2
cover Add MVME3100 PPC SBC v2
Changes since previous iteration.
openpic: debug w/ info_report()
New
i2c: start trace-events
i2c: add mpc8540 i2c controller
Debugging cleanup and fix a spurious warning triggered by Linux guests.
qtest: add e500_i2c_create()
Unchanged
timer: generalize Dallas/Maxim RTC i2c devices
tests: rewrite testing for DS RTC devices
Combined models of ds1338 and ds1375 RTCs, along with untested support for some similar chips.
Test case for setting time to exercise offset calculation.
e500: fix pci host bridge class/type
After further investigation, revert the change which caused the host bridge to be identified as a pci-pci bridge.
e500: additional CCSR registers
Also update CPUPPCState::mpic_iack when changing CCSRBAR.
e500: additional CCSR registers
e500: move mpic under CCSR
e500: move uarts CCSR
e500: derive baud from CCB clock
e500: add i2c controller to CCSR
e500: move PCI host bridge into CCSR
Moved MPIC, UARTS, and PCI host bridge under CCSR device. Many of the PPCE500Params members become properties of the CCSR device.
e500: split mpc8544ds specific initialization
Split ppce500_init() to create mpc85xx_init().
mpc85xx_init() has all the bits used by the exist mpc8544ds and ppce500 machines, but not by the new mvme3100 machine (which doesn't use PPCE500Params).
ppc: add mvme3100 machine
Minor changes related to ppce500_init() changes
tests: run ds-rtc-i2c-test w/ ppc/mvme3100
New
tests: add mvme3100-test
Unchanged
Michael Davidsaver (17):
openpic: debug w/ info_report()
i2c: start trace-events
i2c: add mpc8540 i2c controller
qtest: add e500_i2c_create()
timer: generalize Dallas/Maxim RTC i2c devices
tests: rewrite testing for DS RTC devices
e500: fix pci host bridge class/type
e500: additional CCSR registers
e500: move mpic under CCSR
e500: move uarts CCSR
e500: derive baud from CCB clock
e500: add i2c controller to CCSR
e500: move PCI host bridge into CCSR
e500: split mpc8544ds specific initialization
ppc: add mvme3100 machine
tests: run ds-rtc-i2c-test w/ ppc/mvme3100
tests: add mvme3100-test
Makefile.objs | 1 + default-configs/arm-softmmu.mak | 2 +- default-configs/ppc-softmmu.mak | 1 + hw/i2c/Makefile.objs | 1 + hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++ hw/i2c/trace-events | 7 + hw/intc/openpic.c | 102 +++--- hw/pci-host/ppce500.c | 5 - hw/ppc/Makefile.objs | 1 + hw/ppc/e500.c | 175 +++------- hw/ppc/e500.h | 3 +- hw/ppc/e500_ccsr.c | 246 ++++++++++++- hw/ppc/e500plat.c | 2 +- hw/ppc/mpc8544ds.c | 2 +- hw/ppc/mvme3100.c | 740 ++++++++++++++++++++++++++++++++++++++++ hw/ppc/mvme3100_cpld.c | 192 +++++++++++ hw/timer/Makefile.objs | 2 +- hw/timer/ds-rtc-i2c.c | 461 +++++++++++++++++++++++++ hw/timer/ds1338.c | 239 ------------- tests/Makefile.include | 9 +- tests/ds-rtc-i2c-test.c | 170 +++++++++ tests/ds1338-test.c | 77 ----- tests/libqos/i2c-e500.c | 66 ++++ tests/libqos/i2c.h | 3 + tests/mvme3100-test.c | 79 +++++ 25 files changed, 2376 insertions(+), 517 deletions(-) create mode 100644 hw/i2c/mpc8540_i2c.c create mode 100644 hw/i2c/trace-events create mode 100644 hw/ppc/mvme3100.c create mode 100644 hw/ppc/mvme3100_cpld.c create mode 100644 hw/timer/ds-rtc-i2c.c delete mode 100644 hw/timer/ds1338.c create mode 100644 tests/ds-rtc-i2c-test.c delete mode 100644 tests/ds1338-test.c create mode 100644 tests/libqos/i2c-e500.c create mode 100644 tests/mvme3100-test.c
Signature · 1 line
2.11.0
PATCH 1/17 openpic: debug w/ info_report()
Replace *printf() with *_report().
Remove trailing new lines.
--- hw/intc/openpic.c | 102 +++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 51 deletions(-)
hw/intc/openpic.c +51 -51
@@ -46,6 +46,7 @@#include "qapi/qmp/qerror.h" #include "qemu/log.h" #include "qemu/timer.h" +#include "qemu/error-report.h" //#define DEBUG_OPENPIC
@@ -58,8 +59,7 @@ static const int debug_openpic = 0;static int get_current_cpu (void );#define DPRINTF (fmt, ...) do { \ if (debug_openpic) { \ - printf("Core%d: ", get_current_cpu()); \ - printf(fmt , ## __VA_ARGS__); \ + info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \ } \ } while (0)
@@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt) } } -fprintf (stderr,"%s: unsupported inttgt %d\n" , __func__, inttgt); +error_report ("%s: unsupported inttgt %d" , __func__, inttgt);return OPENPIC_OUTPUT_INT ; }
@@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q)break ; } -DPRINTF ("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n" , +DPRINTF ("IRQ_check: irq %d set ivpr_pr=%d pr=%d" , irq,IVPR_PRIORITY (opp->src[irq].ivpr), priority);if (IVPR_PRIORITY (opp->src[irq].ivpr) > priority) {
@@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; -DPRINTF ("%s: IRQ %d active %d was %d\n" , +DPRINTF ("%s: IRQ %d active %d was %d" , __func__, n_IRQ, active, was_active);if (src->output !=OPENPIC_OUTPUT_INT ) { -DPRINTF ("%s: output %d irq %d active %d was %d count %d\n" , +DPRINTF ("%s: output %d irq %d active %d was %d count %d" , __func__, src->output, n_IRQ, active, was_active, dst->outputs_active[src->output]);
@@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,*/ if (active) {if (!was_active && dst->outputs_active[src->output]++ ==0 ) { -DPRINTF ("%s: Raise OpenPIC output %d cpu %d irq %d\n" , +DPRINTF ("%s: Raise OpenPIC output %d cpu %d irq %d" , __func__, src->output, n_CPU, n_IRQ);qemu_irq_raise (dst->irqs[src->output]); } }else {if (was_active && --dst->outputs_active[src->output] ==0 ) { -DPRINTF ("%s: Lower OpenPIC output %d cpu %d irq %d\n" , +DPRINTF ("%s: Lower OpenPIC output %d cpu %d irq %d" , __func__, src->output, n_CPU, n_IRQ);qemu_irq_lower (dst->irqs[src->output]); }
@@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,IRQ_check (opp, &dst->raised);if (active && priority <= dst->ctpr) { -DPRINTF ("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n" , +DPRINTF ("%s: IRQ %d priority %d too low for ctpr %d on CPU %d" , __func__, n_IRQ, priority, dst->ctpr, n_CPU); active =0 ; }
@@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,if (active) {if (IRQ_get_next (opp, &dst->servicing) >=0 && priority <= dst->servicing.priority) { -DPRINTF ("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n" , +DPRINTF ("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d" , __func__, n_IRQ, dst->servicing.next, n_CPU); }else { -DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n" , +DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d/%d" , __func__, n_CPU, n_IRQ, dst->raised.next);qemu_irq_raise (opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT ]); }
@@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,IRQ_get_next (opp, &dst->servicing);if (dst->raised.priority > dst->ctpr && dst->raised.priority > dst->servicing.priority) { -DPRINTF ("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n" , +DPRINTF ("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d" , __func__, n_IRQ, dst->raised.next, dst->raised.priority, dst->ctpr, dst->servicing.priority, n_CPU);/* IRQ line stays asserted */ }else { -DPRINTF ("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n" , +DPRINTF ("%s: IRQ %d inactive, current prio %d/%d, CPU %d" , __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);qemu_irq_lower (opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT ]); }
@@ -489,7 +489,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)if ((src->ivpr &IVPR_MASK_MASK ) && !src->nomask) {/* Interrupt source is disabled */ -DPRINTF ("%s: IRQ %d is disabled\n" , __func__, n_IRQ); +DPRINTF ("%s: IRQ %d is disabled" , __func__, n_IRQ); active = false; }
@@ -500,7 +500,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)* ctpr may have changed and we need to withdraw the interrupt. */ if (!active && !was_active) { -DPRINTF ("%s: IRQ %d is already inactive\n" , __func__, n_IRQ); +DPRINTF ("%s: IRQ %d is already inactive" , __func__, n_IRQ);return ; }
@@ -512,7 +512,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)if (src->destmask ==0 ) {/* No target */ -DPRINTF ("%s: IRQ %d has no target\n" , __func__, n_IRQ); +DPRINTF ("%s: IRQ %d has no target" , __func__, n_IRQ);return ; }
@@ -547,12 +547,12 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)IRQSource *src;if (n_IRQ >=OPENPIC_MAX_IRQ ) { -fprintf (stderr,"%s: IRQ %d out of range\n" , __func__, n_IRQ); +error_report ("%s: IRQ %d out of range" , __func__, n_IRQ);abort (); } src = &opp->src[n_IRQ]; -DPRINTF ("openpic: set irq %d = %d ivpr=0x%08x\n" , +DPRINTF ("openpic: set irq %d = %d ivpr=0x%08x" , n_IRQ, level, src->ivpr);if (src->level) {/* level-sensitive irq */
@@ -612,13 +612,13 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } src->idr = val & mask; -DPRINTF ("Set IDR %d to 0x%08x\n" , n_IRQ, src->idr); +DPRINTF ("Set IDR %d to 0x%08x" , n_IRQ, src->idr);if (opp->flags &OPENPIC_FLAG_IDR_CRIT ) {if (src->idr & crit_mask) {if (src->idr & normal_mask) {DPRINTF ("%s: IRQ configured for multiple output types, using " -"critical\n" , __func__); +"critical" , __func__); } src->output =OPENPIC_OUTPUT_CINT ;
@@ -648,7 +648,7 @@ static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)IRQSource *src = &opp->src[n_IRQ]; src->output =inttgt_to_output (val &ILR_INTTGT_MASK ); -DPRINTF ("Set ILR %d to 0x%08x, output %d\n" , n_IRQ, src->idr, +DPRINTF ("Set ILR %d to 0x%08x, output %d" , n_IRQ, src->idr, src->output);/* TODO: on MPIC v4.0 only, set nomask for non-INT */
@@ -688,7 +688,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) }openpic_update_irq (opp, n_IRQ); -DPRINTF ("Set IVPR %d to 0x%08x -> 0x%08x\n" , n_IRQ, val, +DPRINTF ("Set IVPR %d to 0x%08x -> 0x%08x" , n_IRQ, val, opp->src[n_IRQ].ivpr); }
@@ -719,7 +719,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,IRQDest *dst;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64, __func__, addr, val);if (addr &0xF ) {return ;
@@ -747,11 +747,11 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,case 0x1090 :/* PIR */ for (idx =0 ; idx < opp->nb_cpus; idx++) {if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { -DPRINTF ("Raise OpenPIC RESET output for CPU %d\n" , idx); +DPRINTF ("Raise OpenPIC RESET output for CPU %d" , idx); dst = &opp->dst[idx];qemu_irq_raise (dst->irqs[OPENPIC_OUTPUT_RESET ]); }else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { -DPRINTF ("Lower OpenPIC RESET output for CPU %d\n" , idx); +DPRINTF ("Lower OpenPIC RESET output for CPU %d" , idx); dst = &opp->dst[idx];qemu_irq_lower (dst->irqs[OPENPIC_OUTPUT_RESET ]); }
@@ -781,7 +781,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)OpenPICState *opp = opaque;uint32_t retval; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr); retval =0xFFFFFFFF ;if (addr &0xF ) {return retval;
@@ -828,7 +828,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)default :break ; } -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }
@@ -843,7 +843,7 @@ static void qemu_timer_cb(void *opaque)uint32_t val = tmr->tbcr & ~TBCR_CI ;uint32_t tog = ((tmr->tccr &TCCR_TOG ) ^TCCR_TOG );/* invert toggle. */ -DPRINTF ("%s n_IRQ=%d\n" , __func__, n_IRQ); +DPRINTF ("%s n_IRQ=%d" , __func__, n_IRQ);/* Reload current count from base count and setup timer. */ tmr->tccr = val | tog;openpic_tmr_set_tmr (tmr, val,/*enabled=*/ true);
@@ -898,7 +898,7 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,OpenPICState *opp = opaque;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64, __func__, (addr +0x10f0 ), val);if (addr &0xF ) {return ;
@@ -943,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)uint32_t retval =-1 ;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr +0x10f0 ); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr +0x10f0 );if (addr &0xF ) { goto out; }
@@ -970,7 +970,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } out: -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }
@@ -981,7 +981,7 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,OpenPICState *opp = opaque;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64, __func__, addr, val); addr = addr &0xffff ;
@@ -1006,7 +1006,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)uint32_t retval;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr); retval =0xFFFFFFFF ; addr = addr &0xffff ;
@@ -1024,7 +1024,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)break ; } -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }
@@ -1035,7 +1035,7 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,int idx = opp->irq_msi;int srs, ibs; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64, __func__, addr, val);if (addr &0xF ) {return ;
@@ -1061,7 +1061,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)uint64_t r =0 ;int i, srs; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr);if (addr &0xF ) {return -1 ; }
@@ -1096,7 +1096,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) {uint64_t r =0 ; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr);/* TODO: EISR/EIMR */
@@ -1106,7 +1106,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)static void openpic_summary_write (void *opaque,hwaddr addr,uint64_t val,unsigned size) { -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64, __func__, addr, val);/* TODO: EISR/EIMR */
@@ -1120,7 +1120,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,IRQDest *dst;int s_IRQ, n_IRQ; -DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx" <= 0x%08x\n" , __func__, idx, +DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx" <= 0x%08x" , __func__, idx, addr, val);if (idx <0 || idx >= opp->nb_cpus) {
@@ -1146,16 +1146,16 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,case 0x80 :/* CTPR */ dst->ctpr = val &0x0000000F ; -DPRINTF ("%s: set CPU %d ctpr to %d, raised %d servicing %d\n" , +DPRINTF ("%s: set CPU %d ctpr to %d, raised %d servicing %d" , __func__, idx, dst->ctpr, dst->raised.priority, dst->servicing.priority);if (dst->raised.priority <= dst->ctpr) { -DPRINTF ("%s: Lower OpenPIC INT output cpu %d due to ctpr\n" , +DPRINTF ("%s: Lower OpenPIC INT output cpu %d due to ctpr" , __func__, idx);qemu_irq_lower (dst->irqs[OPENPIC_OUTPUT_INT ]); }else if (dst->raised.priority > dst->servicing.priority) { -DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d\n" , +DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d" , __func__, idx, dst->raised.next);qemu_irq_raise (dst->irqs[OPENPIC_OUTPUT_INT ]); }
@@ -1168,11 +1168,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,/* Read-only register */ break ;case 0xB0 :/* EOI */ -DPRINTF ("EOI\n" ); +DPRINTF ("EOI" ); s_IRQ =IRQ_get_next (opp, &dst->servicing);if (s_IRQ <0 ) { -DPRINTF ("%s: EOI with no interrupt in service\n" , __func__); +DPRINTF ("%s: EOI with no interrupt in service" , __func__);break ; }
@@ -1185,7 +1185,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,if (n_IRQ !=-1 && (s_IRQ ==-1 ||IVPR_PRIORITY (src->ivpr) > dst->servicing.priority)) { -DPRINTF ("Raise OpenPIC INT output cpu %d irq %d\n" , +DPRINTF ("Raise OpenPIC INT output cpu %d irq %d" , idx, n_IRQ);qemu_irq_raise (opp->dst[idx].irqs[OPENPIC_OUTPUT_INT ]); }
@@ -1207,11 +1207,11 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)IRQSource *src;int retval, irq; -DPRINTF ("Lower OpenPIC INT output\n" ); +DPRINTF ("Lower OpenPIC INT output" );qemu_irq_lower (dst->irqs[OPENPIC_OUTPUT_INT ]); irq =IRQ_get_next (opp, &dst->raised); -DPRINTF ("IACK: irq=%d\n" , irq); +DPRINTF ("IACK: irq=%d" , irq);if (irq ==-1 ) {/* No more interrupt pending */
@@ -1221,7 +1221,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) src = &opp->src[irq];if (!(src->ivpr &IVPR_ACTIVITY_MASK ) || !(IVPR_PRIORITY (src->ivpr) > dst->ctpr)) { -fprintf (stderr,"%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n" , +error_report ("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x" , __func__, irq, dst->ctpr, src->ivpr);openpic_update_irq (opp, irq); retval = opp->spve;
@@ -1241,7 +1241,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)/* Timers and IPIs support multicast. */ if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 +OPENPIC_MAX_IPI ))) || ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 +OPENPIC_MAX_TMR )))) { -DPRINTF ("irq is IPI or TMR\n" ); +DPRINTF ("irq is IPI or TMR" ); src->destmask &= ~(1 << cpu);if (src->destmask && !src->level) {/* trigger on CPUs that didn't know about it yet */
@@ -1262,7 +1262,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,IRQDest *dst;uint32_t retval; -DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx"\n" , __func__, idx, addr); +DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr); retval =0xFFFFFFFF ;if (idx <0 || idx >= opp->nb_cpus) {
@@ -1290,7 +1290,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,default :break ; } -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }
Signature · 1 line
2.11.0
David Gibson
AppliedRe: [Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report()
Quoted 4 lines · Michael Davidsaver
Replace
*printf()with*_report().
Remove trailing new lines.Signed-off-by Michael Davidsaver <[email protected]>
Applied to ppc-for-2.12.
Quoted 429 lines
--- hw/intc/openpic.c | 102 +++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 51 deletions(-)hw/intc/openpic.c +51
-51@@ -46,6 +46,7 @@#include "qapi/qmp/qerror.h" #include "qemu/log.h" #include "qemu/timer.h" +#include "qemu/error-report.h" //#define DEBUG_OPENPIC @@ -58,8 +59,7 @@ static const int debug_openpic = 0;static int get_current_cpu (void );#define DPRINTF (fmt, ...) do { \ if (debug_openpic) { \ - printf("Core%d: ", get_current_cpu()); \ - printf(fmt , ## __VA_ARGS__); \ + info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \ } \ } while (0)@@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt) } } -fprintf (stderr,"%s: unsupported inttgt %d\n" , __func__, inttgt); +error_report ("%s: unsupported inttgt %d" , __func__, inttgt);return OPENPIC_OUTPUT_INT ; }@@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q)break ; } -DPRINTF ("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n" , +DPRINTF ("IRQ_check: irq %d set ivpr_pr=%d pr=%d" , irq,IVPR_PRIORITY (opp->src[irq].ivpr), priority);if (IVPR_PRIORITY (opp->src[irq].ivpr) > priority) {@@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; -DPRINTF ("%s: IRQ %d active %d was %d\n" , +DPRINTF ("%s: IRQ %d active %d was %d" , __func__, n_IRQ, active, was_active);if (src->output !=OPENPIC_OUTPUT_INT ) { -DPRINTF ("%s: output %d irq %d active %d was %d count %d\n" , +DPRINTF ("%s: output %d irq %d active %d was %d count %d" , __func__, src->output, n_IRQ, active, was_active, dst->outputs_active[src->output]);@@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,*/ if (active) {if (!was_active && dst->outputs_active[src->output]++ ==0 ) { -DPRINTF ("%s: Raise OpenPIC output %d cpu %d irq %d\n" , +DPRINTF ("%s: Raise OpenPIC output %d cpu %d irq %d" , __func__, src->output, n_CPU, n_IRQ);qemu_irq_raise (dst->irqs[src->output]); } }else {if (was_active && --dst->outputs_active[src->output] ==0 ) { -DPRINTF ("%s: Lower OpenPIC output %d cpu %d irq %d\n" , +DPRINTF ("%s: Lower OpenPIC output %d cpu %d irq %d" , __func__, src->output, n_CPU, n_IRQ);qemu_irq_lower (dst->irqs[src->output]); }@@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,IRQ_check (opp, &dst->raised);if (active && priority <= dst->ctpr) { -DPRINTF ("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n" , +DPRINTF ("%s: IRQ %d priority %d too low for ctpr %d on CPU %d" , __func__, n_IRQ, priority, dst->ctpr, n_CPU); active =0 ; }@@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,if (active) {if (IRQ_get_next (opp, &dst->servicing) >=0 && priority <= dst->servicing.priority) { -DPRINTF ("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n" , +DPRINTF ("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d" , __func__, n_IRQ, dst->servicing.next, n_CPU); }else { -DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n" , +DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d/%d" , __func__, n_CPU, n_IRQ, dst->raised.next);qemu_irq_raise (opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT ]); }@@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,IRQ_get_next (opp, &dst->servicing);if (dst->raised.priority > dst->ctpr && dst->raised.priority > dst->servicing.priority) { -DPRINTF ("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n" , +DPRINTF ("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d" , __func__, n_IRQ, dst->raised.next, dst->raised.priority, dst->ctpr, dst->servicing.priority, n_CPU);/* IRQ line stays asserted */ }else { -DPRINTF ("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n" , +DPRINTF ("%s: IRQ %d inactive, current prio %d/%d, CPU %d" , __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);qemu_irq_lower (opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT ]); }@@ -489,7 +489,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)if ((src->ivpr &IVPR_MASK_MASK ) && !src->nomask) {/* Interrupt source is disabled */ -DPRINTF ("%s: IRQ %d is disabled\n" , __func__, n_IRQ); +DPRINTF ("%s: IRQ %d is disabled" , __func__, n_IRQ); active = false; }@@ -500,7 +500,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)* ctpr may have changed and we need to withdraw the interrupt. */ if (!active && !was_active) { -DPRINTF ("%s: IRQ %d is already inactive\n" , __func__, n_IRQ); +DPRINTF ("%s: IRQ %d is already inactive" , __func__, n_IRQ);return ; }@@ -512,7 +512,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)if (src->destmask ==0 ) {/* No target */ -DPRINTF ("%s: IRQ %d has no target\n" , __func__, n_IRQ); +DPRINTF ("%s: IRQ %d has no target" , __func__, n_IRQ);return ; }@@ -547,12 +547,12 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)IRQSource *src;if (n_IRQ >=OPENPIC_MAX_IRQ ) { -fprintf (stderr,"%s: IRQ %d out of range\n" , __func__, n_IRQ); +error_report ("%s: IRQ %d out of range" , __func__, n_IRQ);abort (); } src = &opp->src[n_IRQ]; -DPRINTF ("openpic: set irq %d = %d ivpr=0x%08x\n" , +DPRINTF ("openpic: set irq %d = %d ivpr=0x%08x" , n_IRQ, level, src->ivpr);if (src->level) {/* level-sensitive irq */ @@ -612,13 +612,13 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } src->idr = val & mask; -DPRINTF ("Set IDR %d to 0x%08x\n" , n_IRQ, src->idr); +DPRINTF ("Set IDR %d to 0x%08x" , n_IRQ, src->idr);if (opp->flags &OPENPIC_FLAG_IDR_CRIT ) {if (src->idr & crit_mask) {if (src->idr & normal_mask) {DPRINTF ("%s: IRQ configured for multiple output types, using " -"critical\n" , __func__); +"critical" , __func__); } src->output =OPENPIC_OUTPUT_CINT ;@@ -648,7 +648,7 @@ static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)IRQSource *src = &opp->src[n_IRQ]; src->output =inttgt_to_output (val &ILR_INTTGT_MASK ); -DPRINTF ("Set ILR %d to 0x%08x, output %d\n" , n_IRQ, src->idr, +DPRINTF ("Set ILR %d to 0x%08x, output %d" , n_IRQ, src->idr, src->output);/* TODO: on MPIC v4.0 only, set nomask for non-INT */ @@ -688,7 +688,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) }openpic_update_irq (opp, n_IRQ); -DPRINTF ("Set IVPR %d to 0x%08x -> 0x%08x\n" , n_IRQ, val, +DPRINTF ("Set IVPR %d to 0x%08x -> 0x%08x" , n_IRQ, val, opp->src[n_IRQ].ivpr); }@@ -719,7 +719,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,IRQDest *dst;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64, __func__, addr, val);if (addr &0xF ) {return ;@@ -747,11 +747,11 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,case 0x1090 :/* PIR */ for (idx =0 ; idx < opp->nb_cpus; idx++) {if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { -DPRINTF ("Raise OpenPIC RESET output for CPU %d\n" , idx); +DPRINTF ("Raise OpenPIC RESET output for CPU %d" , idx); dst = &opp->dst[idx];qemu_irq_raise (dst->irqs[OPENPIC_OUTPUT_RESET ]); }else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { -DPRINTF ("Lower OpenPIC RESET output for CPU %d\n" , idx); +DPRINTF ("Lower OpenPIC RESET output for CPU %d" , idx); dst = &opp->dst[idx];qemu_irq_lower (dst->irqs[OPENPIC_OUTPUT_RESET ]); }@@ -781,7 +781,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)OpenPICState *opp = opaque;uint32_t retval; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr); retval =0xFFFFFFFF ;if (addr &0xF ) {return retval;@@ -828,7 +828,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)default :break ; } -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }@@ -843,7 +843,7 @@ static void qemu_timer_cb(void *opaque)uint32_t val = tmr->tbcr & ~TBCR_CI ;uint32_t tog = ((tmr->tccr &TCCR_TOG ) ^TCCR_TOG );/* invert toggle. */ -DPRINTF ("%s n_IRQ=%d\n" , __func__, n_IRQ); +DPRINTF ("%s n_IRQ=%d" , __func__, n_IRQ);/* Reload current count from base count and setup timer. */ tmr->tccr = val | tog;openpic_tmr_set_tmr (tmr, val,/*enabled=*/ true);@@ -898,7 +898,7 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,OpenPICState *opp = opaque;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64, __func__, (addr +0x10f0 ), val);if (addr &0xF ) {return ;@@ -943,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)uint32_t retval =-1 ;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr +0x10f0 ); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr +0x10f0 );if (addr &0xF ) { goto out; }@@ -970,7 +970,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } out: -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }@@ -981,7 +981,7 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,OpenPICState *opp = opaque;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= %08" PRIx64, __func__, addr, val); addr = addr &0xffff ;@@ -1006,7 +1006,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)uint32_t retval;int idx; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr); retval =0xFFFFFFFF ; addr = addr &0xffff ;@@ -1024,7 +1024,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)break ; } -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }@@ -1035,7 +1035,7 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,int idx = opp->irq_msi;int srs, ibs; -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64, __func__, addr, val);if (addr &0xF ) {return ;@@ -1061,7 +1061,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)uint64_t r =0 ;int i, srs; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr);if (addr &0xF ) {return -1 ; }@@ -1096,7 +1096,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) {uint64_t r =0 ; -DPRINTF ("%s: addr %#" HWADDR_PRIx"\n" , __func__, addr); +DPRINTF ("%s: addr %#" HWADDR_PRIx, __func__, addr);/* TODO: EISR/EIMR */ @@ -1106,7 +1106,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)static void openpic_summary_write (void *opaque,hwaddr addr,uint64_t val,unsigned size) { -DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64"\n" , +DPRINTF ("%s: addr %#" HWADDR_PRIx" <= 0x%08" PRIx64, __func__, addr, val);/* TODO: EISR/EIMR */ @@ -1120,7 +1120,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,IRQDest *dst;int s_IRQ, n_IRQ; -DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx" <= 0x%08x\n" , __func__, idx, +DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx" <= 0x%08x" , __func__, idx, addr, val);if (idx <0 || idx >= opp->nb_cpus) {@@ -1146,16 +1146,16 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,case 0x80 :/* CTPR */ dst->ctpr = val &0x0000000F ; -DPRINTF ("%s: set CPU %d ctpr to %d, raised %d servicing %d\n" , +DPRINTF ("%s: set CPU %d ctpr to %d, raised %d servicing %d" , __func__, idx, dst->ctpr, dst->raised.priority, dst->servicing.priority);if (dst->raised.priority <= dst->ctpr) { -DPRINTF ("%s: Lower OpenPIC INT output cpu %d due to ctpr\n" , +DPRINTF ("%s: Lower OpenPIC INT output cpu %d due to ctpr" , __func__, idx);qemu_irq_lower (dst->irqs[OPENPIC_OUTPUT_INT ]); }else if (dst->raised.priority > dst->servicing.priority) { -DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d\n" , +DPRINTF ("%s: Raise OpenPIC INT output cpu %d irq %d" , __func__, idx, dst->raised.next);qemu_irq_raise (dst->irqs[OPENPIC_OUTPUT_INT ]); }@@ -1168,11 +1168,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,/* Read-only register */ break ;case 0xB0 :/* EOI */ -DPRINTF ("EOI\n" ); +DPRINTF ("EOI" ); s_IRQ =IRQ_get_next (opp, &dst->servicing);if (s_IRQ <0 ) { -DPRINTF ("%s: EOI with no interrupt in service\n" , __func__); +DPRINTF ("%s: EOI with no interrupt in service" , __func__);break ; }@@ -1185,7 +1185,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,if (n_IRQ !=-1 && (s_IRQ ==-1 ||IVPR_PRIORITY (src->ivpr) > dst->servicing.priority)) { -DPRINTF ("Raise OpenPIC INT output cpu %d irq %d\n" , +DPRINTF ("Raise OpenPIC INT output cpu %d irq %d" , idx, n_IRQ);qemu_irq_raise (opp->dst[idx].irqs[OPENPIC_OUTPUT_INT ]); }@@ -1207,11 +1207,11 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)IRQSource *src;int retval, irq; -DPRINTF ("Lower OpenPIC INT output\n" ); +DPRINTF ("Lower OpenPIC INT output" );qemu_irq_lower (dst->irqs[OPENPIC_OUTPUT_INT ]); irq =IRQ_get_next (opp, &dst->raised); -DPRINTF ("IACK: irq=%d\n" , irq); +DPRINTF ("IACK: irq=%d" , irq);if (irq ==-1 ) {/* No more interrupt pending */ @@ -1221,7 +1221,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) src = &opp->src[irq];if (!(src->ivpr &IVPR_ACTIVITY_MASK ) || !(IVPR_PRIORITY (src->ivpr) > dst->ctpr)) { -fprintf (stderr,"%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n" , +error_report ("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x" , __func__, irq, dst->ctpr, src->ivpr);openpic_update_irq (opp, irq); retval = opp->spve;@@ -1241,7 +1241,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)/* Timers and IPIs support multicast. */ if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 +OPENPIC_MAX_IPI ))) || ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 +OPENPIC_MAX_TMR )))) { -DPRINTF ("irq is IPI or TMR\n" ); +DPRINTF ("irq is IPI or TMR" ); src->destmask &= ~(1 << cpu);if (src->destmask && !src->level) {/* trigger on CPUs that didn't know about it yet */ @@ -1262,7 +1262,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,IRQDest *dst;uint32_t retval; -DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx"\n" , __func__, idx, addr); +DPRINTF ("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr); retval =0xFFFFFFFF ;if (idx <0 || idx >= opp->nb_cpus) {@@ -1290,7 +1290,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,default :break ; } -DPRINTF ("%s: => 0x%08x\n" , __func__, retval); +DPRINTF ("%s: => 0x%08x" , __func__, retval);return retval; }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 2/17 i2c: start trace-events
In reply to Michael Davidsaver--- Makefile.objs | 1 + hw/i2c/trace-events | 1 + 2 files changed, 2 insertions(+) create mode 100644 hw/i2c/trace-events
Makefile.objs +1 -0
@@ -155,6 +155,7 @@ trace-events-subdirs += hw/arm trace-events-subdirs += hw/alpha trace-events-subdirs += hw/xen trace-events-subdirs += hw/ide +trace-events-subdirs += hw/i2c trace-events-subdirs += ui trace-events-subdirs += audio trace-events-subdirs += net
hw/i2c/trace-events new file +1 -0
@@ -0,0 +1 @@ +# See docs/devel/tracing.txt for syntax documentation.
Signature · 1 line
2.11.0
PATCH 3/17 i2c: add mpc8540 i2c controller
In reply to Michael Davidsaver--- hw/i2c/Makefile.objs | 1 + hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/i2c/trace-events | 6 + 3 files changed, 314 insertions(+) create mode 100644 hw/i2c/mpc8540_i2c.c
hw/i2c/Makefile.objs +1 -0
@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o +obj-$(CONFIG_E500) += mpc8540_i2c.o
hw/i2c/mpc8540_i2c.c new file +307 -0
307 lines not on this page · raw message
hw/i2c/trace-events +6 -0
@@ -1 +1,7 @@ # See docs/devel/tracing.txt for syntax documentation. + +# hw/i2c/mpc8540_i2c.c +mpc8540_i2c_event(const char *evt) "Bus Event %s" +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX" +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x" +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
Quoted 47 lines · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>--- hw/i2c/Makefile.objs | 1 + hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/i2c/trace-events | 6 + 3 files changed, 314 insertions(+) create mode 100644 hw/i2c/mpc8540_i2c.chw/i2c/Makefile.objs +1
-0@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o +obj-$(CONFIG_E500) += mpc8540_i2c.ohw/i2c/mpc8540_i2c.c new file +24
-0@@ -0,0 +1,307 @@ +/* +* MPC8540 I2C bus interface +* As described in +* MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1 +* Part 2 chapter 11 +* +* Compatible I2C controllers are found on other Freescale chips +* including mpc8544 and P2010. +* +* Copyright (c) 2015 Michael Davidsaver +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/i2c/i2c.h" +#include "hw/sysbus.h" +#include "qemu/error-report.h" + +#include "trace.h" +
hw/i2c/mpc8540_i2c.c line 34
Quoted 10 lines
hw/i2c/mpc8540_i2c.c new file +10
-0+/* #define DEBUG_LVL 0 */ + +#ifdef DEBUG_LVL +#define DPRINTK (LVL ,FMT , ...) do { \ + if ((LVL) <= DEBUG_LVL) {\ + info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \ + } } while (0) +#else +#define DPRINTK (LVL ,FMT , ...) do {} while (0) +#endif
So, you have both this DPRINTK stuff, and some trace events, which seems a bit odd? Why not just one or the other.
Quoted 240 lines
hw/i2c/mpc8540_i2c.c new file +240
-0+ +#define LOG (MSK ,FMT , ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \ + " : " FMT "\n", ## __VA_ARGS__) + +#define TYPE_MPC8540_I2C "mpc8540-i2c" +#define MPC8540_I2C (obj) OBJECT_CHECK(MPC8540I2CState, (obj), TYPE_MPC8540_I2C) + +/* offsets relative to CCSR offset 0x3000 */ +#define R_I2CADR (0) +#define R_I2CFDR (4) +#define R_I2CCR (8) +#define R_I2CSR (0xc) +#define R_I2CDR (0x10) +#define R_I2CDFSRR (0x14) + +FIELD(I2CCR, MEN, 7, 1) +FIELD(I2CCR, MIEN, 6, 1) +FIELD(I2CCR, MSTA, 5, 1) +FIELD(I2CCR, MTX, 4, 1) +FIELD(I2CCR, TXAK, 3, 1) +FIELD(I2CCR, RSTA, 2, 1) +FIELD(I2CCR, BCST, 0, 1) + +FIELD(I2CSR, MCF, 7, 1) +FIELD(I2CSR, MAAS, 6, 1) +FIELD(I2CSR, MBB, 5, 1) +FIELD(I2CSR, MAL, 4, 1) +FIELD(I2CSR, BCSTM, 3, 1) +FIELD(I2CSR, SRW, 2, 1) +FIELD(I2CSR, MIF, 1, 1) +FIELD(I2CSR, RXAK, 0, 1) + +typedef struct MPC8540I2CState { +SysBusDevice parent_obj; + +I2CBus *bus; + +uint8_t ctrl, sts; +uint8_t freq, filt; +/* Reads are pipelined, this is the next data value */ +uint8_t dbuf, dbuf_valid; + +qemu_irq irq; + +MemoryRegion mmio; +}MPC8540I2CState ; + +#define I2CCR (BIT ) FIELD_EX32(i2c->ctrl, I2CCR, BIT) +#define I2CSR (BIT ) FIELD_EX32(i2c->sts, I2CSR, BIT) + +#define I2CSR_SET (BIT ,VAL ) do {\ + i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\ + } while (0) + +static +void mpc8540_update_irq (MPC8540I2CState *i2c) +{ +int ena = i2c->ctrl &0x40 , + sts = i2c->sts &0x02 , + act = !!(ena && sts); + +DPRINTK (1 ,"IRQ %c ena %c sts %c" , + act ?'X' :'_' , + ena ?'X' :'_' , + sts ?'X' :'_' ); + +qemu_set_irq (i2c->irq, act); +} + +static +uint64_t mpc8540_i2c_read (void *opaque,hwaddr addr,unsigned size) +{ +MPC8540I2CState *i2c = opaque; +uint32_t val; + +switch (addr) { +case R_I2CADR :/* ADDR */ + val =0 ; +break ; +case R_I2CFDR :/* Freq Div. */ + val = i2c->freq; +break ; +case R_I2CCR :/* CONTROL */ + val = i2c->ctrl & ~0x06 ; +break ; +case R_I2CSR :/* STATUS */ + val = i2c->sts; +break ; +case R_I2CDR :/* DATA */ +/* Reads are "pipelined" and so return the previous value of the +* register +*/ + val = i2c->dbuf; +if (I2CCR (MEN ) &&I2CSR (MBB )) {/* enabled and busy */ +if (!i2c_bus_busy (i2c->bus) ||I2CCR (MTX )) { +if (!i2c->dbuf_valid) { +LOG (LOG_GUEST_ERROR ,"Read during addr or tx" ); + } + i2c->dbuf =0xff ; + i2c->dbuf_valid = false; + }else { +int ret =i2c_recv (i2c->bus); + i2c->dbuf = (uint8_t )ret; + i2c->dbuf_valid = true; +trace_mpc8540_i2c_read (i2c->dbuf); +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); +mpc8540_update_irq (i2c); + } + }else { + i2c->dbuf =0xff ; + i2c->dbuf_valid = false; +LOG (LOG_GUEST_ERROR ,"Read when not enabled or busy" ); + } +break ; +case R_I2CDFSRR :/* FILTER */ + val = i2c->filt; +break ; +default : + val =0xff ; + } + +DPRINTK (addr ==0xc ?2 :1 ," read %08x -> %08x" , + (unsigned )addr, (unsigned )val); +return val; +} + +static +void mpc8540_i2c_write (void *opaque,hwaddr addr,uint64_t val,unsigned size) +{ +MPC8540I2CState *i2c = opaque; + +DPRINTK (1 ," write %08x <- %08x" , (unsigned )addr, (unsigned )val); + +switch (addr) { +case R_I2CADR :/* ADDR */ +break ; +case R_I2CFDR :/* Freq Div. */ + i2c->freq = val &0x3f ; +break ; +case R_I2CCR :/* CONTROL CCR */ +if (!FIELD_EX32 (val,I2CCR ,MEN )) { +DPRINTK (0 ,"Not Enabled" ); + + }else if (!I2CCR (MSTA ) &&FIELD_EX32 (val,I2CCR ,MSTA )) { +/* MSTA 0 -> 1 is START */ + +I2CSR_SET (MBB ,1 ); +if (I2CCR (MTX )) { +trace_mpc8540_i2c_event ("START Tx" ); + }else { +trace_mpc8540_i2c_event ("START Rx" ); + } +i2c_end_transfer (i2c->bus);/* paranoia */ + + }else if (I2CCR (MSTA ) && !FIELD_EX32 (val,I2CCR ,MSTA )) { +/* MSTA 1 -> 0 is STOP */ + +I2CSR_SET (MBB ,0 ); +trace_mpc8540_i2c_event ("STOP" ); +i2c_end_transfer (i2c->bus); + + }else if (I2CCR (MSTA ) &&FIELD_EX32 (val,I2CCR ,RSTA )) { +i2c_end_transfer (i2c->bus); +I2CSR_SET (MBB ,1 ); +if (I2CCR (MTX )) { +trace_mpc8540_i2c_event ("REPEAT START Tx" ); + }else { +trace_mpc8540_i2c_event ("REPEAT START Rx" ); + } + + } +/* RSTA always reads zero, bit 1 unusd */ + val &=0xf9 ; + i2c->ctrl = val; +mpc8540_update_irq (i2c); +break ; +case R_I2CSR :/* STATUS CSR */ +/* only MAL and MIF are writable */ + val &=0x12 ; + i2c->sts &= ~0x12 ; + i2c->sts |= val; +mpc8540_update_irq (i2c); +break ; +case R_I2CDR :/* DATA CDR */ +if (I2CCR (MEN ) &&I2CSR (MBB )) {/* enabled and busy */ +if (!i2c_bus_busy (i2c->bus)) { +if (i2c_start_transfer (i2c->bus, val >>1 , val &1 )) { +LOG (LOG_GUEST_ERROR ,"I2C no device %02x" , + (unsigned )(val &0xfe )); + }else { +trace_mpc8540_i2c_address ((unsigned )(val &0xfe ), + (val &0x1 ) ?'R' :'T' ); + } +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); + + }else if (I2CCR (MTX )) { +trace_mpc8540_i2c_write ((unsigned )val); +i2c_send (i2c->bus, val); +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); + }else { +LOG (LOG_GUEST_ERROR ,"I2CDR Write during read" ); + } +mpc8540_update_irq (i2c); + }else { +LOG (LOG_GUEST_ERROR ,"I2CDR Write when not enabled or busy" ); + } +break ; +case R_I2CDFSRR :/* FILTER */ + val &=0x3f ; + i2c->filt = val; +break ; + } + +DPRINTK (1 ,"I2CCR = %02x I2SCR = %02x" , i2c->ctrl, i2c->sts); +} + +static const MemoryRegionOps i2c_ops = { + .read = mpc8540_i2c_read, + .write = mpc8540_i2c_write, + .endianness =DEVICE_NATIVE_ENDIAN , + .impl = { + .min_access_size =1 , + .max_access_size =1 , + }, +}; + +static +void mpc8540_i2c_reset (DeviceState *dev) +{ +MPC8540I2CState *i2c =MPC8540_I2C (dev); + + i2c->sts =0x81 ;/* transfer complete and ack received */ + i2c->dbuf_valid = false; +} + +static void mpc8540_i2c_inst_init (DeviceState *dev,Error **errp) +{
hw/i2c/mpc8540_i2c.c line 284
Quoted 10 lines
hw/i2c/mpc8540_i2c.c new file +10
-0+MPC8540I2CState *i2c =MPC8540_I2C (dev); + + i2c->bus =i2c_init_bus (dev,"bus" ); + +memory_region_init_io (&i2c->mmio,OBJECT (dev), + &i2c_ops, i2c,TYPE_MPC8540_I2C ,0x18 ); + +sysbus_init_mmio (SYS_BUS_DEVICE (dev), &i2c->mmio); +sysbus_init_irq (SYS_BUS_DEVICE (dev), &i2c->irq); +}
As someone pointed out on the earlier version, this stuff needs to go into a realize() function rather than instance_init - instance_init is called too early to go safely constructing and installing memory regions.
Quoted 35 lines
hw/i2c/mpc8540_i2c.c new file +23
-0+ +static void mpc8540_i2c_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = &mpc8540_i2c_inst_init; + dc->reset = &mpc8540_i2c_reset; +} + +static const TypeInfo mpc8540_i2c_type = { + .name =TYPE_MPC8540_I2C , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (MPC8540I2CState), + .class_size =sizeof (SysBusDeviceClass), + .class_init = mpc8540_i2c_class_init, +}; + +static void mpc8540_i2c_register (void ) +{ +type_register_static (&mpc8540_i2c_type); +} + +type_init (mpc8540_i2c_register)hw/i2c/trace-events +6
-0@@ -1 +1,7 @@ # See docs/devel/tracing.txt for syntax documentation. + +# hw/i2c/mpc8540_i2c.c +mpc8540_i2c_event(const char *evt) "Bus Event %s" +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX" +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x" +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
Quoted 53 lines · David Gibson
Quoted 52 lines · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>--- hw/i2c/Makefile.objs | 1 + hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/i2c/trace-events | 6 + 3 files changed, 314 insertions(+) create mode 100644 hw/i2c/mpc8540_i2c.chw/i2c/Makefile.objs +1
-0@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o +obj-$(CONFIG_E500) += mpc8540_i2c.ohw/i2c/mpc8540_i2c.c new file +29
-0@@ -0,0 +1,307 @@ +/* +* MPC8540 I2C bus interface +* As described in +* MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1 +* Part 2 chapter 11 +* +* Compatible I2C controllers are found on other Freescale chips +* including mpc8544 and P2010. +* +* Copyright (c) 2015 Michael Davidsaver +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/i2c/i2c.h" +#include "hw/sysbus.h" +#include "qemu/error-report.h" + +#include "trace.h" + +/* #define DEBUG_LVL 0 */ + +#ifdef DEBUG_LVL +#define DPRINTK (LVL ,FMT , ...) do { \ + if ((LVL) <= DEBUG_LVL) {\
Quoted 8 lines
hw/i2c/mpc8540_i2c.c line 34
Quoted 5 lines
hw/i2c/mpc8540_i2c.c new file +5
-0+ info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \ + } } while (0) +#else +#define DPRINTK (LVL ,FMT , ...) do {} while (0) +#endif So, you have both this DPRINTK stuff, and some trace events, which seems a bit odd? Why not just one or the other.
My thinking is to have trace events for the commonly used points (by me at least) for troubleshooting devices on the i2c bus, but leave the others for troubleshooting the i2c controller itself as DPRINTK.
So this is mainly my laziness in not seeing sufficient benefit to defining events for the remaining 5 DPRINTK s.
Quoted 247 lines
Quoted 247 lines
hw/i2c/mpc8540_i2c.c new file +247
-0+ +#define LOG (MSK ,FMT , ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \ + " : " FMT "\n", ## __VA_ARGS__) + +#define TYPE_MPC8540_I2C "mpc8540-i2c" +#define MPC8540_I2C (obj) OBJECT_CHECK(MPC8540I2CState, (obj), TYPE_MPC8540_I2C) + +/* offsets relative to CCSR offset 0x3000 */ +#define R_I2CADR (0) +#define R_I2CFDR (4) +#define R_I2CCR (8) +#define R_I2CSR (0xc) +#define R_I2CDR (0x10) +#define R_I2CDFSRR (0x14) + +FIELD(I2CCR, MEN, 7, 1) +FIELD(I2CCR, MIEN, 6, 1) +FIELD(I2CCR, MSTA, 5, 1) +FIELD(I2CCR, MTX, 4, 1) +FIELD(I2CCR, TXAK, 3, 1) +FIELD(I2CCR, RSTA, 2, 1) +FIELD(I2CCR, BCST, 0, 1) + +FIELD(I2CSR, MCF, 7, 1) +FIELD(I2CSR, MAAS, 6, 1) +FIELD(I2CSR, MBB, 5, 1) +FIELD(I2CSR, MAL, 4, 1) +FIELD(I2CSR, BCSTM, 3, 1) +FIELD(I2CSR, SRW, 2, 1) +FIELD(I2CSR, MIF, 1, 1) +FIELD(I2CSR, RXAK, 0, 1) + +typedef struct MPC8540I2CState { +SysBusDevice parent_obj; + +I2CBus *bus; + +uint8_t ctrl, sts; +uint8_t freq, filt; +/* Reads are pipelined, this is the next data value */ +uint8_t dbuf, dbuf_valid; + +qemu_irq irq; + +MemoryRegion mmio; +}MPC8540I2CState ; + +#define I2CCR (BIT ) FIELD_EX32(i2c->ctrl, I2CCR, BIT) +#define I2CSR (BIT ) FIELD_EX32(i2c->sts, I2CSR, BIT) + +#define I2CSR_SET (BIT ,VAL ) do {\ + i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\ + } while (0) + +static +void mpc8540_update_irq (MPC8540I2CState *i2c) +{ +int ena = i2c->ctrl &0x40 , + sts = i2c->sts &0x02 , + act = !!(ena && sts); + +DPRINTK (1 ,"IRQ %c ena %c sts %c" , + act ?'X' :'_' , + ena ?'X' :'_' , + sts ?'X' :'_' ); + +qemu_set_irq (i2c->irq, act); +} + +static +uint64_t mpc8540_i2c_read (void *opaque,hwaddr addr,unsigned size) +{ +MPC8540I2CState *i2c = opaque; +uint32_t val; + +switch (addr) { +case R_I2CADR :/* ADDR */ + val =0 ; +break ; +case R_I2CFDR :/* Freq Div. */ + val = i2c->freq; +break ; +case R_I2CCR :/* CONTROL */ + val = i2c->ctrl & ~0x06 ; +break ; +case R_I2CSR :/* STATUS */ + val = i2c->sts; +break ; +case R_I2CDR :/* DATA */ +/* Reads are "pipelined" and so return the previous value of the +* register +*/ + val = i2c->dbuf; +if (I2CCR (MEN ) &&I2CSR (MBB )) {/* enabled and busy */ +if (!i2c_bus_busy (i2c->bus) ||I2CCR (MTX )) { +if (!i2c->dbuf_valid) { +LOG (LOG_GUEST_ERROR ,"Read during addr or tx" ); + } + i2c->dbuf =0xff ; + i2c->dbuf_valid = false; + }else { +int ret =i2c_recv (i2c->bus); + i2c->dbuf = (uint8_t )ret; + i2c->dbuf_valid = true; +trace_mpc8540_i2c_read (i2c->dbuf); +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); +mpc8540_update_irq (i2c); + } + }else { + i2c->dbuf =0xff ; + i2c->dbuf_valid = false; +LOG (LOG_GUEST_ERROR ,"Read when not enabled or busy" ); + } +break ; +case R_I2CDFSRR :/* FILTER */ + val = i2c->filt; +break ; +default : + val =0xff ; + } + +DPRINTK (addr ==0xc ?2 :1 ," read %08x -> %08x" , + (unsigned )addr, (unsigned )val); +return val; +} + +static +void mpc8540_i2c_write (void *opaque,hwaddr addr,uint64_t val,unsigned size) +{ +MPC8540I2CState *i2c = opaque; + +DPRINTK (1 ," write %08x <- %08x" , (unsigned )addr, (unsigned )val); + +switch (addr) { +case R_I2CADR :/* ADDR */ +break ; +case R_I2CFDR :/* Freq Div. */ + i2c->freq = val &0x3f ; +break ; +case R_I2CCR :/* CONTROL CCR */ +if (!FIELD_EX32 (val,I2CCR ,MEN )) { +DPRINTK (0 ,"Not Enabled" ); + + }else if (!I2CCR (MSTA ) &&FIELD_EX32 (val,I2CCR ,MSTA )) { +/* MSTA 0 -> 1 is START */ + +I2CSR_SET (MBB ,1 ); +if (I2CCR (MTX )) { +trace_mpc8540_i2c_event ("START Tx" ); + }else { +trace_mpc8540_i2c_event ("START Rx" ); + } +i2c_end_transfer (i2c->bus);/* paranoia */ + + }else if (I2CCR (MSTA ) && !FIELD_EX32 (val,I2CCR ,MSTA )) { +/* MSTA 1 -> 0 is STOP */ + +I2CSR_SET (MBB ,0 ); +trace_mpc8540_i2c_event ("STOP" ); +i2c_end_transfer (i2c->bus); + + }else if (I2CCR (MSTA ) &&FIELD_EX32 (val,I2CCR ,RSTA )) { +i2c_end_transfer (i2c->bus); +I2CSR_SET (MBB ,1 ); +if (I2CCR (MTX )) { +trace_mpc8540_i2c_event ("REPEAT START Tx" ); + }else { +trace_mpc8540_i2c_event ("REPEAT START Rx" ); + } + + } +/* RSTA always reads zero, bit 1 unusd */ + val &=0xf9 ; + i2c->ctrl = val; +mpc8540_update_irq (i2c); +break ; +case R_I2CSR :/* STATUS CSR */ +/* only MAL and MIF are writable */ + val &=0x12 ; + i2c->sts &= ~0x12 ; + i2c->sts |= val; +mpc8540_update_irq (i2c); +break ; +case R_I2CDR :/* DATA CDR */ +if (I2CCR (MEN ) &&I2CSR (MBB )) {/* enabled and busy */ +if (!i2c_bus_busy (i2c->bus)) { +if (i2c_start_transfer (i2c->bus, val >>1 , val &1 )) { +LOG (LOG_GUEST_ERROR ,"I2C no device %02x" , + (unsigned )(val &0xfe )); + }else { +trace_mpc8540_i2c_address ((unsigned )(val &0xfe ), + (val &0x1 ) ?'R' :'T' ); + } +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); + + }else if (I2CCR (MTX )) { +trace_mpc8540_i2c_write ((unsigned )val); +i2c_send (i2c->bus, val); +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); + }else { +LOG (LOG_GUEST_ERROR ,"I2CDR Write during read" ); + } +mpc8540_update_irq (i2c); + }else { +LOG (LOG_GUEST_ERROR ,"I2CDR Write when not enabled or busy" ); + } +break ; +case R_I2CDFSRR :/* FILTER */ + val &=0x3f ; + i2c->filt = val; +break ; + } + +DPRINTK (1 ,"I2CCR = %02x I2SCR = %02x" , i2c->ctrl, i2c->sts); +} + +static const MemoryRegionOps i2c_ops = { + .read = mpc8540_i2c_read, + .write = mpc8540_i2c_write, + .endianness =DEVICE_NATIVE_ENDIAN , + .impl = { + .min_access_size =1 , + .max_access_size =1 , + }, +}; + +static +void mpc8540_i2c_reset (DeviceState *dev) +{ +MPC8540I2CState *i2c =MPC8540_I2C (dev); + + i2c->sts =0x81 ;/* transfer complete and ack received */ + i2c->dbuf_valid = false; +} + +static void mpc8540_i2c_inst_init (DeviceState *dev,Error **errp) +{ +MPC8540I2CState *i2c =MPC8540_I2C (dev); + + i2c->bus =i2c_init_bus (dev,"bus" ); + +memory_region_init_io (&i2c->mmio,OBJECT (dev), + &i2c_ops, i2c,TYPE_MPC8540_I2C ,0x18 ); +
Quoted 8 lines
hw/i2c/mpc8540_i2c.c line 284
Quoted 3 lines
hw/i2c/mpc8540_i2c.c new file +3
-0+sysbus_init_mmio (SYS_BUS_DEVICE (dev), &i2c->mmio); +sysbus_init_irq (SYS_BUS_DEVICE (dev), &i2c->irq); +}As someone pointed out on the earlier version, this stuff needs to go into a
realize()function rather thaninstance_init-instance_initis called too early to go safely constructing and installing memory regions.
In fact I did (see "dc->realize" below), but apparently managed to change the argument list without thinking to re-name the function. I will do so now...
Quoted 36 lines
Quoted 35 lines
hw/i2c/mpc8540_i2c.c new file +23
-0+ +static void mpc8540_i2c_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = &mpc8540_i2c_inst_init; + dc->reset = &mpc8540_i2c_reset; +} + +static const TypeInfo mpc8540_i2c_type = { + .name =TYPE_MPC8540_I2C , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (MPC8540I2CState), + .class_size =sizeof (SysBusDeviceClass), + .class_init = mpc8540_i2c_class_init, +}; + +static void mpc8540_i2c_register (void ) +{ +type_register_static (&mpc8540_i2c_type); +} + +type_init (mpc8540_i2c_register)hw/i2c/trace-events +6
-0@@ -1 +1,7 @@ # See docs/devel/tracing.txt for syntax documentation. + +# hw/i2c/mpc8540_i2c.c +mpc8540_i2c_event(const char *evt) "Bus Event %s" +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX" +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x" +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller
Quoted 63 lines · Michael Davidsaver
Quoted 53 lines · David Gibson
Quoted 52 lines · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>--- hw/i2c/Makefile.objs | 1 + hw/i2c/mpc8540_i2c.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/i2c/trace-events | 6 + 3 files changed, 314 insertions(+) create mode 100644 hw/i2c/mpc8540_i2c.chw/i2c/Makefile.objs +1
-0@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o +obj-$(CONFIG_E500) += mpc8540_i2c.ohw/i2c/mpc8540_i2c.c new file +29
-0@@ -0,0 +1,307 @@ +/* +* MPC8540 I2C bus interface +* As described in +* MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1 +* Part 2 chapter 11 +* +* Compatible I2C controllers are found on other Freescale chips +* including mpc8544 and P2010. +* +* Copyright (c) 2015 Michael Davidsaver +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/i2c/i2c.h" +#include "hw/sysbus.h" +#include "qemu/error-report.h" + +#include "trace.h" + +/* #define DEBUG_LVL 0 */ + +#ifdef DEBUG_LVL +#define DPRINTK (LVL ,FMT , ...) do { \ + if ((LVL) <= DEBUG_LVL) {\Quoted 8 lines
hw/i2c/mpc8540_i2c.c line 34
Quoted 5 lines
hw/i2c/mpc8540_i2c.c new file +5
-0+ info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \ + } } while (0) +#else +#define DPRINTK (LVL ,FMT , ...) do {} while (0) +#endif So, you have both this DPRINTK stuff, and some trace events, which seems a bit odd? Why not just one or the other.
Quoted 6 lines
My thinking is to have trace events for the commonly used points (by me at least) for troubleshooting devices on the i2c bus, but leave the others for troubleshooting the i2c controller itself as DPRINTK.
So this is mainly my laziness in not seeing sufficient benefit to defining events for the remaining 5 DPRINTK s.
I sympathize - I have mixed feelings about tracepoints myself. But they remain the preferred debugging approach in qemu.
To address they issue above, I suggest you use a consistent naming scheme for the "common" vs. "rare" tracepoints, that way the whole of one set or the other can be enabled/disabled with a single wildcard.
Quoted 298 lines
Quoted 248 lines
Quoted 248 lines
hw/i2c/mpc8540_i2c.c new file +247
-0+ +#define LOG (MSK ,FMT , ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \ + " : " FMT "\n", ## __VA_ARGS__) + +#define TYPE_MPC8540_I2C "mpc8540-i2c" +#define MPC8540_I2C (obj) OBJECT_CHECK(MPC8540I2CState, (obj), TYPE_MPC8540_I2C) + +/* offsets relative to CCSR offset 0x3000 */ +#define R_I2CADR (0) +#define R_I2CFDR (4) +#define R_I2CCR (8) +#define R_I2CSR (0xc) +#define R_I2CDR (0x10) +#define R_I2CDFSRR (0x14) + +FIELD(I2CCR, MEN, 7, 1) +FIELD(I2CCR, MIEN, 6, 1) +FIELD(I2CCR, MSTA, 5, 1) +FIELD(I2CCR, MTX, 4, 1) +FIELD(I2CCR, TXAK, 3, 1) +FIELD(I2CCR, RSTA, 2, 1) +FIELD(I2CCR, BCST, 0, 1) + +FIELD(I2CSR, MCF, 7, 1) +FIELD(I2CSR, MAAS, 6, 1) +FIELD(I2CSR, MBB, 5, 1) +FIELD(I2CSR, MAL, 4, 1) +FIELD(I2CSR, BCSTM, 3, 1) +FIELD(I2CSR, SRW, 2, 1) +FIELD(I2CSR, MIF, 1, 1) +FIELD(I2CSR, RXAK, 0, 1) + +typedef struct MPC8540I2CState { +SysBusDevice parent_obj; + +I2CBus *bus; + +uint8_t ctrl, sts; +uint8_t freq, filt; +/* Reads are pipelined, this is the next data value */ +uint8_t dbuf, dbuf_valid; + +qemu_irq irq; + +MemoryRegion mmio; +}MPC8540I2CState ; + +#define I2CCR (BIT ) FIELD_EX32(i2c->ctrl, I2CCR, BIT) +#define I2CSR (BIT ) FIELD_EX32(i2c->sts, I2CSR, BIT) + +#define I2CSR_SET (BIT ,VAL ) do {\ + i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\ + } while (0) + +static +void mpc8540_update_irq (MPC8540I2CState *i2c) +{ +int ena = i2c->ctrl &0x40 , + sts = i2c->sts &0x02 , + act = !!(ena && sts); + +DPRINTK (1 ,"IRQ %c ena %c sts %c" , + act ?'X' :'_' , + ena ?'X' :'_' , + sts ?'X' :'_' ); + +qemu_set_irq (i2c->irq, act); +} + +static +uint64_t mpc8540_i2c_read (void *opaque,hwaddr addr,unsigned size) +{ +MPC8540I2CState *i2c = opaque; +uint32_t val; + +switch (addr) { +case R_I2CADR :/* ADDR */ + val =0 ; +break ; +case R_I2CFDR :/* Freq Div. */ + val = i2c->freq; +break ; +case R_I2CCR :/* CONTROL */ + val = i2c->ctrl & ~0x06 ; +break ; +case R_I2CSR :/* STATUS */ + val = i2c->sts; +break ; +case R_I2CDR :/* DATA */ +/* Reads are "pipelined" and so return the previous value of the +* register +*/ + val = i2c->dbuf; +if (I2CCR (MEN ) &&I2CSR (MBB )) {/* enabled and busy */ +if (!i2c_bus_busy (i2c->bus) ||I2CCR (MTX )) { +if (!i2c->dbuf_valid) { +LOG (LOG_GUEST_ERROR ,"Read during addr or tx" ); + } + i2c->dbuf =0xff ; + i2c->dbuf_valid = false; + }else { +int ret =i2c_recv (i2c->bus); + i2c->dbuf = (uint8_t )ret; + i2c->dbuf_valid = true; +trace_mpc8540_i2c_read (i2c->dbuf); +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); +mpc8540_update_irq (i2c); + } + }else { + i2c->dbuf =0xff ; + i2c->dbuf_valid = false; +LOG (LOG_GUEST_ERROR ,"Read when not enabled or busy" ); + } +break ; +case R_I2CDFSRR :/* FILTER */ + val = i2c->filt; +break ; +default : + val =0xff ; + } + +DPRINTK (addr ==0xc ?2 :1 ," read %08x -> %08x" , + (unsigned )addr, (unsigned )val); +return val; +} + +static +void mpc8540_i2c_write (void *opaque,hwaddr addr,uint64_t val,unsigned size) +{ +MPC8540I2CState *i2c = opaque; + +DPRINTK (1 ," write %08x <- %08x" , (unsigned )addr, (unsigned )val); + +switch (addr) { +case R_I2CADR :/* ADDR */ +break ; +case R_I2CFDR :/* Freq Div. */ + i2c->freq = val &0x3f ; +break ; +case R_I2CCR :/* CONTROL CCR */ +if (!FIELD_EX32 (val,I2CCR ,MEN )) { +DPRINTK (0 ,"Not Enabled" ); + + }else if (!I2CCR (MSTA ) &&FIELD_EX32 (val,I2CCR ,MSTA )) { +/* MSTA 0 -> 1 is START */ + +I2CSR_SET (MBB ,1 ); +if (I2CCR (MTX )) { +trace_mpc8540_i2c_event ("START Tx" ); + }else { +trace_mpc8540_i2c_event ("START Rx" ); + } +i2c_end_transfer (i2c->bus);/* paranoia */ + + }else if (I2CCR (MSTA ) && !FIELD_EX32 (val,I2CCR ,MSTA )) { +/* MSTA 1 -> 0 is STOP */ + +I2CSR_SET (MBB ,0 ); +trace_mpc8540_i2c_event ("STOP" ); +i2c_end_transfer (i2c->bus); + + }else if (I2CCR (MSTA ) &&FIELD_EX32 (val,I2CCR ,RSTA )) { +i2c_end_transfer (i2c->bus); +I2CSR_SET (MBB ,1 ); +if (I2CCR (MTX )) { +trace_mpc8540_i2c_event ("REPEAT START Tx" ); + }else { +trace_mpc8540_i2c_event ("REPEAT START Rx" ); + } + + } +/* RSTA always reads zero, bit 1 unusd */ + val &=0xf9 ; + i2c->ctrl = val; +mpc8540_update_irq (i2c); +break ; +case R_I2CSR :/* STATUS CSR */ +/* only MAL and MIF are writable */ + val &=0x12 ; + i2c->sts &= ~0x12 ; + i2c->sts |= val; +mpc8540_update_irq (i2c); +break ; +case R_I2CDR :/* DATA CDR */ +if (I2CCR (MEN ) &&I2CSR (MBB )) {/* enabled and busy */ +if (!i2c_bus_busy (i2c->bus)) { +if (i2c_start_transfer (i2c->bus, val >>1 , val &1 )) { +LOG (LOG_GUEST_ERROR ,"I2C no device %02x" , + (unsigned )(val &0xfe )); + }else { +trace_mpc8540_i2c_address ((unsigned )(val &0xfe ), + (val &0x1 ) ?'R' :'T' ); + } +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); + + }else if (I2CCR (MTX )) { +trace_mpc8540_i2c_write ((unsigned )val); +i2c_send (i2c->bus, val); +I2CSR_SET (MIF ,1 ); +I2CSR_SET (RXAK ,0 ); + }else { +LOG (LOG_GUEST_ERROR ,"I2CDR Write during read" ); + } +mpc8540_update_irq (i2c); + }else { +LOG (LOG_GUEST_ERROR ,"I2CDR Write when not enabled or busy" ); + } +break ; +case R_I2CDFSRR :/* FILTER */ + val &=0x3f ; + i2c->filt = val; +break ; + } + +DPRINTK (1 ,"I2CCR = %02x I2SCR = %02x" , i2c->ctrl, i2c->sts); +} + +static const MemoryRegionOps i2c_ops = { + .read = mpc8540_i2c_read, + .write = mpc8540_i2c_write, + .endianness =DEVICE_NATIVE_ENDIAN , + .impl = { + .min_access_size =1 , + .max_access_size =1 , + }, +}; + +static +void mpc8540_i2c_reset (DeviceState *dev) +{ +MPC8540I2CState *i2c =MPC8540_I2C (dev); + + i2c->sts =0x81 ;/* transfer complete and ack received */ + i2c->dbuf_valid = false; +} + +static void mpc8540_i2c_inst_init (DeviceState *dev,Error **errp) +{ +MPC8540I2CState *i2c =MPC8540_I2C (dev); + + i2c->bus =i2c_init_bus (dev,"bus" ); + +memory_region_init_io (&i2c->mmio,OBJECT (dev), + &i2c_ops, i2c,TYPE_MPC8540_I2C ,0x18 ); +Quoted 8 lines
hw/i2c/mpc8540_i2c.c line 284
Quoted 3 lines
hw/i2c/mpc8540_i2c.c new file +3
-0+sysbus_init_mmio (SYS_BUS_DEVICE (dev), &i2c->mmio); +sysbus_init_irq (SYS_BUS_DEVICE (dev), &i2c->irq); +}As someone pointed out on the earlier version, this stuff needs to go into a
realize()function rather thaninstance_init-instance_initis called too early to go safely constructing and installing memory regions.In fact I did (see "
dc->realize" below), but apparently managed to change the argument list without thinking to re-name the function. I will do so now...Quoted 36 lines
Quoted 35 lines
hw/i2c/mpc8540_i2c.c new file +23
-0+ +static void mpc8540_i2c_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = &mpc8540_i2c_inst_init; + dc->reset = &mpc8540_i2c_reset; +} + +static const TypeInfo mpc8540_i2c_type = { + .name =TYPE_MPC8540_I2C , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (MPC8540I2CState), + .class_size =sizeof (SysBusDeviceClass), + .class_init = mpc8540_i2c_class_init, +}; + +static void mpc8540_i2c_register (void ) +{ +type_register_static (&mpc8540_i2c_type); +} + +type_init (mpc8540_i2c_register)hw/i2c/trace-events +6
-0@@ -1 +1,7 @@ # See docs/devel/tracing.txt for syntax documentation. + +# hw/i2c/mpc8540_i2c.c +mpc8540_i2c_event(const char *evt) "Bus Event %s" +mpc8540_i2c_address(uint8_t addr, const char direction) "Address device 0x%02x for %cX" +mpc8540_i2c_write(uint8_t byte) "Write 0x%02x" +mpc8540_i2c_read(uint8_t byte) "Read 0x%02x"
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 4/17 qtest: add e500_i2c_create()
In reply to Michael DavidsaverAdd interface for testing i2c devices
with PPC e500.
--- tests/Makefile.include | 1 + tests/libqos/i2c-e500.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/i2c.h | 3 +++ 3 files changed, 70 insertions(+) create mode 100644 tests/libqos/i2c-e500.c
tests/Makefile.include +1 -0
@@ -721,6 +721,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o +libqos-e500-obj-y = $(libqos-obj-y) tests/libqos/i2c-e500.o libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
tests/libqos/i2c-e500.c new file +66 -0
66 lines not on this page · raw message
tests/libqos/i2c.h +3 -0
@@ -29,4 +29,7 @@ I2CAdapter *omap_i2c_create(uint64_t addr);/* libi2c-imx.c */ I2CAdapter *imx_i2c_create (uint64_t addr); +/* i2c-e500.c */ +I2CAdapter *e500_i2c_create (uint64_t ccsr_base); +#endif
Signature · 1 line
2.11.0
PATCH 5/17 timer: generalize Dallas/Maxim RTC i2c devices
In reply to Michael DavidsaverSupport for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.
Tested with ds1338 and ds1375.
--- default-configs/arm-softmmu.mak | 2 +- hw/timer/Makefile.objs | 2 +- hw/timer/ds-rtc-i2c.c | 461 ++++++++++++++++++++++++++++++++++++++++ hw/timer/ds1338.c | 239 --------------------- 4 files changed, 463 insertions(+), 241 deletions(-) create mode 100644 hw/timer/ds-rtc-i2c.c delete mode 100644 hw/timer/ds1338.c
default-configs/arm-softmmu.mak +1 -1
@@ -31,7 +31,7 @@ CONFIG_SMC91C111=y CONFIG_ALLWINNER_EMAC=y CONFIG_IMX_FEC=y CONFIG_FTGMAC100=y -CONFIG_DS1338=y +CONFIG_DSRTCI2C=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_MICRODRIVE=y
hw/timer/Makefile.objs +1 -1
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o common-obj-$(CONFIG_CADENCE) += cadence_ttc.o -common-obj-$(CONFIG_DS1338) += ds1338.o +common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o common-obj-$(CONFIG_M48T59) += m48t59.o
hw/timer/ds-rtc-i2c.c new file +461 -0
461 lines not on this page · raw message
hw/timer/ds1338.c deleted +0 -239
239 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
Quoted 6 lines · Michael Davidsaver
Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.Tested with ds1338 and ds1375.
Signed-off-by Michael Davidsaver <[email protected]>
I certainly like the idea of consolidating this code, but reviewing to see that the new code really is a generalization of the old is something I won't have time for for a while.
Also, hw/timer is not within my purview so it'll probably need to go another path to merge.
Quoted 747 lines
--- default-configs/arm-softmmu.mak | 2 +- hw/timer/Makefile.objs | 2 +- hw/timer/ds-rtc-i2c.c | 461 ++++++++++++++++++++++++++++++++++++++++ hw/timer/ds1338.c | 239 --------------------- 4 files changed, 463 insertions(+), 241 deletions(-) create mode 100644 hw/timer/ds-rtc-i2c.c delete mode 100644 hw/timer/ds1338.cdefault-configs/arm-softmmu.mak +1
-1@@ -31,7 +31,7 @@ CONFIG_SMC91C111=y CONFIG_ALLWINNER_EMAC=y CONFIG_IMX_FEC=y CONFIG_FTGMAC100=y -CONFIG_DS1338=y +CONFIG_DSRTCI2C=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_MICRODRIVE=yhw/timer/Makefile.objs +1
-1@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o common-obj-$(CONFIG_CADENCE) += cadence_ttc.o -common-obj-$(CONFIG_DS1338) += ds1338.o +common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o common-obj-$(CONFIG_M48T59) += m48t59.ohw/timer/ds-rtc-i2c.c new file +461
-0@@ -0,0 +1,461 @@ +/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus +* +* Copyright (c) 2017 Michael Davidsaver +* Copyright (c) 2009 CodeSourcery +* +* Authors: Michael Davidsaver +* Paul Brook +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +* +* Models real time read/set and NVRAM. +* Does not model alarms, or control/status registers. +* +* Generalized register map is: +* [Current time] +* [Alarm settings] (optional) +* [Control/Status] (optional) +* [Non-volatile memory] (optional) +* +* The current time registers are almost always the same, +* with the exception being that some have a CENTURY bit +* in the month register. +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "qemu/bcd.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/i2c/i2c.h" +#include "sysemu/qtest.h" +#include "qemu/error-report.h" + +/* #define DEBUG_DSRTC */ + +#ifdef DEBUG_DSRTC +#define DPRINTK (FMT , ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__) +#else +#define DPRINTK (FMT , ...) do {} while (0) +#endif + +#define LOG (MSK ,FMT , ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \ + ## __VA_ARGS__) + +#define DSRTC_REGSIZE (0x40) + +/* values stored in BCD */ +/* 00-59 */ +#define R_SEC (0x0) +/* 00-59 */ +#define R_MIN (0x1) +#define R_HOUR (0x2) +/* 1-7 */ +#define R_WDAY (0x3) +/* 0-31 */ +#define R_DATE (0x4) +#define R_MONTH (0x5) +/* 0-99 */ +#define R_YEAR (0x6) + +/* use 12 hour mode when set */ +FIELD (HOUR ,SET12 ,6 ,1 ) +/* 00-23 */ +FIELD(HOUR, HOUR24, 0, 6) +FIELD (HOUR ,AMPM ,5 ,1 ) +/* 1-12 (not 0-11!) */ +FIELD (HOUR ,HOUR12 ,0 ,5 ) + +/* 1-12 */ +FIELD(MONTH, MONTH, 0, 5) +FIELD(MONTH, CENTURY, 7, 1) + +typedef struct DSRTCInfo { +/* if bit 7 of the Month register is set after Y2K */ +bool has_century; +/* address of first non-volatile memory cell. +* nv_start >= reg_end means no NV memory. +*/ +uint8_t nv_start; +/* total size of register range. When address counter rolls over. */ +uint8_t reg_size; +}DSRTCInfo ; + +typedef struct DSRTCState { +I2CSlave parent_obj; + +const DSRTCInfo *info; + +qemu_irq alarm_irq; + +/* register address counter */ +uint8_t addr; +/* when writing, whether the address has been sent */ +bool addrd; + +int64_t time_offset; +int8_t wday_offset; + +uint8_t regs[DSRTC_REGSIZE ]; +}DSRTCState ; + +typedef struct DSRTCClass { +I2CSlaveClass parent_class; + +const DSRTCInfo *info; +}DSRTCClass ; + +#define TYPE_DSRTC "ds-rtc-i2c" +#define DSRTC (obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC) +#define DSRTC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC) +#define DSRTC_CLASS (klass) \ + OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC) + +static const VMStateDescription vmstate_dsrtc = { + .name =TYPE_DSRTC , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_I2C_SLAVE (parent_obj, DSRTCState), +VMSTATE_INT64 (time_offset, DSRTCState), +VMSTATE_INT8_V (wday_offset, DSRTCState,2 ), +VMSTATE_UINT8_ARRAY (regs, DSRTCState,DSRTC_REGSIZE ), +VMSTATE_UINT8 (addr, DSRTCState), +VMSTATE_BOOL (addrd, DSRTCState), +VMSTATE_END_OF_LIST () + } +}; + +static void dsrtc_reset (DeviceState *device); + +/* update current time registers */ +static +void dsrtc_latch (DSRTCState *ds) +{ +struct tm now; +bool use12; + +qemu_get_timedate (&now, ds->time_offset); + +DPRINTK ("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)" , + now.tm_year, now.tm_mon, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + now.tm_wday); + + use12 =ARRAY_FIELD_EX32 (ds->regs,HOUR ,SET12 ); + +/* ensure unused bits are zero */ +memset (ds->regs,0 ,R_YEAR +1 ); + + ds->regs[R_SEC ] =to_bcd (now.tm_sec); + ds->regs[R_MIN ] =to_bcd (now.tm_min); + +if (!use12) { +/* 24 hour (0-23) */ +ARRAY_FIELD_DP32 (ds->regs,HOUR ,HOUR24 ,to_bcd (now.tm_hour)); + }else { +/* 12 hour am/pm (1-12) */ +ARRAY_FIELD_DP32 (ds->regs,HOUR ,SET12 ,1 ); +ARRAY_FIELD_DP32 (ds->regs,HOUR ,AMPM , now.tm_hour >=12u ); +ARRAY_FIELD_DP32 (ds->regs,HOUR ,HOUR12 , +to_bcd (1u + (now.tm_hour %12u ))); + } + + ds->regs[R_WDAY ] = (now.tm_wday + ds->wday_offset) %7u +1u ; + ds->regs[R_DATE ] =to_bcd (now.tm_mday); + +ARRAY_FIELD_DP32 (ds->regs,MONTH ,MONTH ,to_bcd (now.tm_mon +1 )); +if (ds->info->has_century) { +ARRAY_FIELD_DP32 (ds->regs,MONTH ,CENTURY , now.tm_year >=100u ); + } + + ds->regs[R_YEAR ] =to_bcd (now.tm_year %100u ); + +DPRINTK ("Latched time" ); +} + +/* call after guest writes to current time registers +* to re-compute our offset from host time. +*/ +static +void dsrtc_update (DSRTCState *ds) +{ +int user_wday; +struct tm now; + + now.tm_sec =from_bcd (ds->regs[R_SEC ]); + now.tm_min =from_bcd (ds->regs[R_MIN ]); + +if (ARRAY_FIELD_EX32 (ds->regs,HOUR ,SET12 )) { +/* 12 hour (1-12) */ + now.tm_hour =from_bcd (ARRAY_FIELD_EX32 (ds->regs,HOUR ,HOUR12 )) -1u ; +if (ARRAY_FIELD_EX32 (ds->regs,HOUR ,AMPM )) { + now.tm_hour +=12 ; + } + + }else { +/* 23 hour (0-23) */ + now.tm_hour =from_bcd (ARRAY_FIELD_EX32 (ds->regs,HOUR ,HOUR24 )); + } + + now.tm_wday =from_bcd (ds->regs[R_WDAY ]) -1u ; + now.tm_mday =from_bcd (ds->regs[R_DATE ]); + now.tm_mon =from_bcd (ARRAY_FIELD_EX32 (ds->regs,MONTH ,MONTH )) -1 ; + + now.tm_year =from_bcd (ds->regs[R_YEAR ]); +if (ARRAY_FIELD_EX32 (ds->regs,MONTH ,CENTURY ) || !ds->info->has_century) { + now.tm_year +=100 ; + } + +DPRINTK ("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)" , + now.tm_year, now.tm_mon, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + now.tm_wday); + +/* round trip to get real wday_offset based on time delta */ + user_wday = now.tm_wday; + ds->time_offset =qemu_timedate_diff (&now); +/* race possible if we run at midnight +* TODO: make qemu_timedate_diff() calculate wday offset as well? +*/ +qemu_get_timedate (&now, ds->time_offset); +/* calculate wday_offset to achieve guest requested wday */ + ds->wday_offset = user_wday - now.tm_wday; + +DPRINTK ("Update offset = %" PRId64", wday_offset = %d" , + ds->time_offset, ds->wday_offset); +} + +static +void dsrtc_advance (DSRTCState *ds) +{ + ds->addr = (ds->addr +1 ) % ds->info->reg_size; +if (ds->addr ==0 ) { +/* latch time on roll over */ +dsrtc_latch (ds); + } +} + +static +int dsrtc_event (I2CSlave *s,enum i2c_event event) +{ +DSRTCState *ds =DSRTC (s); + +switch (event) { +case I2C_START_SEND : + ds->addrd = false; +/* fall through */ +case I2C_START_RECV : +dsrtc_latch (ds); +/* fall through */ +case I2C_FINISH : +DPRINTK ("Event %d" , (int )event); +/* fall through */ +case I2C_NACK : +break ; + } +return 0 ; +} + +static +int dsrtc_recv (I2CSlave *s) +{ +DSRTCState *ds =DSRTC (s); +int ret =0 ; + + ret = ds->regs[ds->addr]; + +if (ds->addr >R_YEAR && ds->addr < ds->info->nv_start) { +LOG (LOG_UNIMP ,"Read from unimplemented (%02x) %02x" , ds->addr, ret); + } + +DPRINTK ("Recv (%02x) %02x" , ds->addr, ret); + +dsrtc_advance (ds); + +return ret; +} + +static +int dsrtc_send (I2CSlave *s,uint8_t data) +{ +DSRTCState *ds =DSRTC (s); + +if (!ds->addrd) { +if (data ==0xff &&qtest_enabled ()) { +/* allow test runner to zero offsets */ +DPRINTK ("Testing reset" ); +dsrtc_reset (DEVICE (s)); +return 0 ; + } + ds->addr = data %DSRTC_REGSIZE ; + ds->addrd = true; +DPRINTK ("Set address pointer %02x" , data); +return 0 ; + } + +DPRINTK ("Send (%02x) %02x" , ds->addr, data); + +if (ds->addr <=R_YEAR ) { + ds->regs[ds->addr] = data; +dsrtc_update (ds); + + }else if (ds->addr >= ds->info->nv_start) { + ds->regs[ds->addr] = data; + + }else { +LOG (LOG_UNIMP ,"Register not modeled" ); + } + +dsrtc_advance (ds); + +return 0 ; +} + +static +void dsrtc_reset (DeviceState *device) +{ +DSRTCState *ds =DSRTC (device); + +memset (ds->regs,0 ,sizeof (ds->regs)); + + ds->addr =0 ; + ds->addrd = false; + ds->time_offset =0 ; + ds->wday_offset =0 ; + +DPRINTK ("Reset" ); +} + +static +void dsrtc_realize (DeviceState *device,Error **errp) +{ +DSRTCState *ds =DSRTC (device); +DSRTCClass *r =DSRTC_GET_CLASS (device); + + ds->info = r->info; + +/* Alarms not yet implemented, but allow +* board code to wire up the alarm interrupt +* output anyway. +*/ +qdev_init_gpio_out (device, &ds->alarm_irq,1 ); +} + +static +void dsrtc_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); +I2CSlaveClass *k =I2C_SLAVE_CLASS (klass); +DSRTCClass *r =DSRTC_CLASS (klass); + + r->info = data; + + k->event = &dsrtc_event; + k->recv = &dsrtc_recv; + k->send = &dsrtc_send; + + dc->vmsd = &vmstate_dsrtc; + dc->realize = dsrtc_realize; + dc->reset = dsrtc_reset; + dc->user_creatable = true; +} + +static +const TypeInfo ds_rtc_base_type = { + .abstract = true, + .name =TYPE_DSRTC , + .parent =TYPE_I2C_SLAVE , + .instance_size =sizeof (DSRTCState), +}; + +#define DSRTC_CONFIG (NAME ) \ +static const TypeInfo NAME##_type = { \ + .name = #NAME, \ + .parent = TYPE_DSRTC, \ + .class_size = sizeof(I2CSlaveClass), \ + .class_init = dsrtc_class_init, \ + .class_data = (void *)&NAME##_info, \ +}; + +/* ds3231 - alarms, no eeprom */ +static const DSRTCInfo ds3231_info = { + .has_century = true, + .nv_start =0x13 ,/* no nv memory */ + .reg_size =0x13 , +}; +DSRTC_CONFIG (ds3231) + +/* only model block 0 (RTC), blocks 1,2 (eeprom) not modeled. +* blocks have different i2c addresses +*/ +static const DSRTCInfo ds1388_info = { + .has_century = false, + .nv_start =0x0d , + .reg_size =0x0d , +}; +DSRTC_CONFIG (ds1388) + +/* alarms, eeprom */ +static const DSRTCInfo ds1375_info = { + .has_century = true, + .nv_start =0x10 , + .reg_size =0x20 , +}; +DSRTC_CONFIG (ds1375) + +/* no alarms, no eeprom */ +static const DSRTCInfo ds1340_info = { + .has_century = false, + .nv_start =0x10 , + .reg_size =0x10 , +}; +DSRTC_CONFIG (ds1340) + +/* alarms, no eeprom */ +static const DSRTCInfo ds1339_info = { + .has_century = false, + .nv_start =0x11 , + .reg_size =0x11 , +}; +DSRTC_CONFIG (ds1339) + +/* no alarms, eeprom */ +static const DSRTCInfo ds1338_info = { + .has_century = false, + .nv_start =0x08 , + .reg_size =0x40 , +}; +DSRTC_CONFIG (ds1338) + +/* alarms, no eeprom */ +static const DSRTCInfo ds1337_info = { + .has_century = true, + .nv_start =0x10 , + .reg_size =0x10 , +}; +DSRTC_CONFIG (ds1337) + +/* ds1307 registers are identical to ds1338 */ +static +const TypeInfo ds1307_type = { + .name ="ds1307" , + .parent ="ds1338" , +}; + +static void ds_rtc_i2c_register (void ) +{ +type_register_static (&ds_rtc_base_type); +type_register_static (&ds3231_type); +type_register_static (&ds1388_type); +type_register_static (&ds1375_type); +type_register_static (&ds1340_type); +type_register_static (&ds1339_type); +type_register_static (&ds1338_type); +type_register_static (&ds1337_type); +type_register_static (&ds1307_type); +} + +type_init (ds_rtc_i2c_register)hw/timer/ds1338.c deleted +0
-239@@ -1,239 +0,0 @@ -/* -* MAXIM DS1338 I2C RTC+NVRAM -* -* Copyright (c) 2009 CodeSourcery. -* Written by Paul Brook -* -* This code is licensed under the GNU GPL v2. -* -* Contributions after 2012-01-13 are licensed under the terms of the -* GNU GPL, version 2 or (at your option) any later version. -*/ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "hw/i2c/i2c.h" -#include "qemu/bcd.h" - -/* Size of NVRAM including both the user-accessible area and the -* secondary register area. -*/ -#define NVRAM_SIZE 64 - -/* Flags definitions */ -#define SECONDS_CH 0x80 -#define HOURS_12 0x40 -#define HOURS_PM 0x20 -#define CTRL_OSF 0x20 - -#define TYPE_DS1338 "ds1338" -#define DS1338 (obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338) - -typedef struct DS1338State { -I2CSlave parent_obj; - -int64_t offset; -uint8_t wday_offset; -uint8_t nvram[NVRAM_SIZE ]; -int32_t ptr; -bool addr_byte; -}DS1338State ; - -static const VMStateDescription vmstate_ds1338 = { - .name ="ds1338" , - .version_id =2 , - .minimum_version_id =1 , - .fields = (VMStateField []) { -VMSTATE_I2C_SLAVE (parent_obj, DS1338State), -VMSTATE_INT64 (offset, DS1338State), -VMSTATE_UINT8_V (wday_offset, DS1338State,2 ), -VMSTATE_UINT8_ARRAY (nvram, DS1338State,NVRAM_SIZE ), -VMSTATE_INT32 (ptr, DS1338State), -VMSTATE_BOOL (addr_byte, DS1338State), -VMSTATE_END_OF_LIST () - } -}; - -static void capture_current_time (DS1338State *s) -{ -/* Capture the current time into the secondary registers -* which will be actually read by the data transfer operation. -*/ -struct tm now; -qemu_get_timedate (&now, s->offset); - s->nvram[0 ] =to_bcd (now.tm_sec); - s->nvram[1 ] =to_bcd (now.tm_min); -if (s->nvram[2 ] &HOURS_12 ) { -int tmp = now.tm_hour; -if (tmp %12 ==0 ) { - tmp +=12 ; - } -if (tmp <=12 ) { - s->nvram[2 ] =HOURS_12 |to_bcd (tmp); - }else { - s->nvram[2 ] =HOURS_12 |HOURS_PM |to_bcd (tmp -12 ); - } - }else { - s->nvram[2 ] =to_bcd (now.tm_hour); - } - s->nvram[3 ] = (now.tm_wday + s->wday_offset) %7 +1 ; - s->nvram[4 ] =to_bcd (now.tm_mday); - s->nvram[5 ] =to_bcd (now.tm_mon +1 ); - s->nvram[6 ] =to_bcd (now.tm_year -100 ); -} - -static void inc_regptr (DS1338State *s) -{ -/* The register pointer wraps around after 0x3F; wraparound -* causes the current time/date to be retransferred into -* the secondary registers. -*/ - s->ptr = (s->ptr +1 ) & (NVRAM_SIZE -1 ); -if (!s->ptr) { -capture_current_time (s); - } -} - -static int ds1338_event (I2CSlave *i2c,enum i2c_event event) -{ -DS1338State *s =DS1338 (i2c); - -switch (event) { -case I2C_START_RECV : -/* In h/w, capture happens on any START condition, not just a -* START_RECV, but there is no need to actually capture on -* START_SEND, because the guest can't get at that data -* without going through a START_RECV which would overwrite it. -*/ -capture_current_time (s); -break ; -case I2C_START_SEND : - s->addr_byte = true; -break ; -default : -break ; - } - -return 0 ; -} - -static int ds1338_recv (I2CSlave *i2c) -{ -DS1338State *s =DS1338 (i2c); -uint8_t res; - - res = s->nvram[s->ptr]; -inc_regptr (s); -return res; -} - -static int ds1338_send (I2CSlave *i2c,uint8_t data) -{ -DS1338State *s =DS1338 (i2c); - -if (s->addr_byte) { - s->ptr = data & (NVRAM_SIZE -1 ); - s->addr_byte = false; -return 0 ; - } -if (s->ptr <7 ) { -/* Time register. */ -struct tm now; -qemu_get_timedate (&now, s->offset); -switch (s->ptr) { -case 0 : -/* TODO: Implement CH (stop) bit. */ - now.tm_sec =from_bcd (data &0x7f ); -break ; -case 1 : - now.tm_min =from_bcd (data &0x7f ); -break ; -case 2 : -if (data &HOURS_12 ) { -int tmp =from_bcd (data & (HOURS_PM -1 )); -if (data &HOURS_PM ) { - tmp +=12 ; - } -if (tmp %12 ==0 ) { - tmp -=12 ; - } - now.tm_hour = tmp; - }else { - now.tm_hour =from_bcd (data & (HOURS_12 -1 )); - } -break ; -case 3 : - { -/* The day field is supposed to contain a value in -the range 1-7. Otherwise behavior is undefined. -*/ -int user_wday = (data &7 ) -1 ; - s->wday_offset = (user_wday - now.tm_wday +7 ) %7 ; - } -break ; -case 4 : - now.tm_mday =from_bcd (data &0x3f ); -break ; -case 5 : - now.tm_mon =from_bcd (data &0x1f ) -1 ; -break ; -case 6 : - now.tm_year =from_bcd (data) +100 ; -break ; - } - s->offset =qemu_timedate_diff (&now); - }else if (s->ptr ==7 ) { -/* Control register. */ - -/* Ensure bits 2, 3 and 6 will read back as zero. */ - data &=0xB3 ; - -/* Attempting to write the OSF flag to logic 1 leaves the -value unchanged. */ - data = (data & ~CTRL_OSF ) | (data & s->nvram[s->ptr] &CTRL_OSF ); - - s->nvram[s->ptr] = data; - }else { - s->nvram[s->ptr] = data; - } -inc_regptr (s); -return 0 ; -} - -static void ds1338_reset (DeviceState *dev) -{ -DS1338State *s =DS1338 (dev); - -/* The clock is running and synchronized with the host */ - s->offset =0 ; - s->wday_offset =0 ; -memset (s->nvram,0 ,NVRAM_SIZE ); - s->ptr =0 ; - s->addr_byte = false; -} - -static void ds1338_class_init (ObjectClass *klass,void *data) -{ -DeviceClass *dc =DEVICE_CLASS (klass); -I2CSlaveClass *k =I2C_SLAVE_CLASS (klass); - - k->event = ds1338_event; - k->recv = ds1338_recv; - k->send = ds1338_send; - dc->reset = ds1338_reset; - dc->vmsd = &vmstate_ds1338; -} - -static const TypeInfo ds1338_info = { - .name =TYPE_DS1338 , - .parent =TYPE_I2C_SLAVE , - .instance_size =sizeof (DS1338State), - .class_init = ds1338_class_init, -}; - -static void ds1338_register_types (void ) -{ -type_register_static (&ds1338_info); -} - -type_init (ds1338_register_types)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
Quoted 6 lines · David Gibson
Quoted 5 lines · Michael Davidsaver
Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.Tested with ds1338 and ds1375.
Quoted 8 lines
Quoted 1 line
Signed-off-by Michael Davidsaver <[email protected]>I certainly like the idea of consolidating this code, but reviewing to see that the new code really is a generalization of the old is something I won't have time for for a while.
Also, hw/timer is not within my purview so it'll probably need to go another path to merge.
Could you be a bit more explicit about what, if anything, I need to do to move this forward?
Quoted 748 lines
Quoted 747 lines
--- default-configs/arm-softmmu.mak | 2 +- hw/timer/Makefile.objs | 2 +- hw/timer/ds-rtc-i2c.c | 461 ++++++++++++++++++++++++++++++++++++++++ hw/timer/ds1338.c | 239 --------------------- 4 files changed, 463 insertions(+), 241 deletions(-) create mode 100644 hw/timer/ds-rtc-i2c.c delete mode 100644 hw/timer/ds1338.cdefault-configs/arm-softmmu.mak +1
-1@@ -31,7 +31,7 @@ CONFIG_SMC91C111=y CONFIG_ALLWINNER_EMAC=y CONFIG_IMX_FEC=y CONFIG_FTGMAC100=y -CONFIG_DS1338=y +CONFIG_DSRTCI2C=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_MICRODRIVE=yhw/timer/Makefile.objs +1
-1@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o common-obj-$(CONFIG_CADENCE) += cadence_ttc.o -common-obj-$(CONFIG_DS1338) += ds1338.o +common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o common-obj-$(CONFIG_M48T59) += m48t59.ohw/timer/ds-rtc-i2c.c new file +461
-0@@ -0,0 +1,461 @@ +/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus +* +* Copyright (c) 2017 Michael Davidsaver +* Copyright (c) 2009 CodeSourcery +* +* Authors: Michael Davidsaver +* Paul Brook +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +* +* Models real time read/set and NVRAM. +* Does not model alarms, or control/status registers. +* +* Generalized register map is: +* [Current time] +* [Alarm settings] (optional) +* [Control/Status] (optional) +* [Non-volatile memory] (optional) +* +* The current time registers are almost always the same, +* with the exception being that some have a CENTURY bit +* in the month register. +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "qemu/bcd.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/i2c/i2c.h" +#include "sysemu/qtest.h" +#include "qemu/error-report.h" + +/* #define DEBUG_DSRTC */ + +#ifdef DEBUG_DSRTC +#define DPRINTK (FMT , ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__) +#else +#define DPRINTK (FMT , ...) do {} while (0) +#endif + +#define LOG (MSK ,FMT , ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \ + ## __VA_ARGS__) + +#define DSRTC_REGSIZE (0x40) + +/* values stored in BCD */ +/* 00-59 */ +#define R_SEC (0x0) +/* 00-59 */ +#define R_MIN (0x1) +#define R_HOUR (0x2) +/* 1-7 */ +#define R_WDAY (0x3) +/* 0-31 */ +#define R_DATE (0x4) +#define R_MONTH (0x5) +/* 0-99 */ +#define R_YEAR (0x6) + +/* use 12 hour mode when set */ +FIELD (HOUR ,SET12 ,6 ,1 ) +/* 00-23 */ +FIELD(HOUR, HOUR24, 0, 6) +FIELD (HOUR ,AMPM ,5 ,1 ) +/* 1-12 (not 0-11!) */ +FIELD (HOUR ,HOUR12 ,0 ,5 ) + +/* 1-12 */ +FIELD(MONTH, MONTH, 0, 5) +FIELD(MONTH, CENTURY, 7, 1) + +typedef struct DSRTCInfo { +/* if bit 7 of the Month register is set after Y2K */ +bool has_century; +/* address of first non-volatile memory cell. +* nv_start >= reg_end means no NV memory. +*/ +uint8_t nv_start; +/* total size of register range. When address counter rolls over. */ +uint8_t reg_size; +}DSRTCInfo ; + +typedef struct DSRTCState { +I2CSlave parent_obj; + +const DSRTCInfo *info; + +qemu_irq alarm_irq; + +/* register address counter */ +uint8_t addr; +/* when writing, whether the address has been sent */ +bool addrd; + +int64_t time_offset; +int8_t wday_offset; + +uint8_t regs[DSRTC_REGSIZE ]; +}DSRTCState ; + +typedef struct DSRTCClass { +I2CSlaveClass parent_class; + +const DSRTCInfo *info; +}DSRTCClass ; + +#define TYPE_DSRTC "ds-rtc-i2c" +#define DSRTC (obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC) +#define DSRTC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC) +#define DSRTC_CLASS (klass) \ + OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC) + +static const VMStateDescription vmstate_dsrtc = { + .name =TYPE_DSRTC , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_I2C_SLAVE (parent_obj, DSRTCState), +VMSTATE_INT64 (time_offset, DSRTCState), +VMSTATE_INT8_V (wday_offset, DSRTCState,2 ), +VMSTATE_UINT8_ARRAY (regs, DSRTCState,DSRTC_REGSIZE ), +VMSTATE_UINT8 (addr, DSRTCState), +VMSTATE_BOOL (addrd, DSRTCState), +VMSTATE_END_OF_LIST () + } +}; + +static void dsrtc_reset (DeviceState *device); + +/* update current time registers */ +static +void dsrtc_latch (DSRTCState *ds) +{ +struct tm now; +bool use12; + +qemu_get_timedate (&now, ds->time_offset); + +DPRINTK ("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)" , + now.tm_year, now.tm_mon, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + now.tm_wday); + + use12 =ARRAY_FIELD_EX32 (ds->regs,HOUR ,SET12 ); + +/* ensure unused bits are zero */ +memset (ds->regs,0 ,R_YEAR +1 ); + + ds->regs[R_SEC ] =to_bcd (now.tm_sec); + ds->regs[R_MIN ] =to_bcd (now.tm_min); + +if (!use12) { +/* 24 hour (0-23) */ +ARRAY_FIELD_DP32 (ds->regs,HOUR ,HOUR24 ,to_bcd (now.tm_hour)); + }else { +/* 12 hour am/pm (1-12) */ +ARRAY_FIELD_DP32 (ds->regs,HOUR ,SET12 ,1 ); +ARRAY_FIELD_DP32 (ds->regs,HOUR ,AMPM , now.tm_hour >=12u ); +ARRAY_FIELD_DP32 (ds->regs,HOUR ,HOUR12 , +to_bcd (1u + (now.tm_hour %12u ))); + } + + ds->regs[R_WDAY ] = (now.tm_wday + ds->wday_offset) %7u +1u ; + ds->regs[R_DATE ] =to_bcd (now.tm_mday); + +ARRAY_FIELD_DP32 (ds->regs,MONTH ,MONTH ,to_bcd (now.tm_mon +1 )); +if (ds->info->has_century) { +ARRAY_FIELD_DP32 (ds->regs,MONTH ,CENTURY , now.tm_year >=100u ); + } + + ds->regs[R_YEAR ] =to_bcd (now.tm_year %100u ); + +DPRINTK ("Latched time" ); +} + +/* call after guest writes to current time registers +* to re-compute our offset from host time. +*/ +static +void dsrtc_update (DSRTCState *ds) +{ +int user_wday; +struct tm now; + + now.tm_sec =from_bcd (ds->regs[R_SEC ]); + now.tm_min =from_bcd (ds->regs[R_MIN ]); + +if (ARRAY_FIELD_EX32 (ds->regs,HOUR ,SET12 )) { +/* 12 hour (1-12) */ + now.tm_hour =from_bcd (ARRAY_FIELD_EX32 (ds->regs,HOUR ,HOUR12 )) -1u ; +if (ARRAY_FIELD_EX32 (ds->regs,HOUR ,AMPM )) { + now.tm_hour +=12 ; + } + + }else { +/* 23 hour (0-23) */ + now.tm_hour =from_bcd (ARRAY_FIELD_EX32 (ds->regs,HOUR ,HOUR24 )); + } + + now.tm_wday =from_bcd (ds->regs[R_WDAY ]) -1u ; + now.tm_mday =from_bcd (ds->regs[R_DATE ]); + now.tm_mon =from_bcd (ARRAY_FIELD_EX32 (ds->regs,MONTH ,MONTH )) -1 ; + + now.tm_year =from_bcd (ds->regs[R_YEAR ]); +if (ARRAY_FIELD_EX32 (ds->regs,MONTH ,CENTURY ) || !ds->info->has_century) { + now.tm_year +=100 ; + } + +DPRINTK ("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)" , + now.tm_year, now.tm_mon, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + now.tm_wday); + +/* round trip to get real wday_offset based on time delta */ + user_wday = now.tm_wday; + ds->time_offset =qemu_timedate_diff (&now); +/* race possible if we run at midnight +* TODO: make qemu_timedate_diff() calculate wday offset as well? +*/ +qemu_get_timedate (&now, ds->time_offset); +/* calculate wday_offset to achieve guest requested wday */ + ds->wday_offset = user_wday - now.tm_wday; + +DPRINTK ("Update offset = %" PRId64", wday_offset = %d" , + ds->time_offset, ds->wday_offset); +} + +static +void dsrtc_advance (DSRTCState *ds) +{ + ds->addr = (ds->addr +1 ) % ds->info->reg_size; +if (ds->addr ==0 ) { +/* latch time on roll over */ +dsrtc_latch (ds); + } +} + +static +int dsrtc_event (I2CSlave *s,enum i2c_event event) +{ +DSRTCState *ds =DSRTC (s); + +switch (event) { +case I2C_START_SEND : + ds->addrd = false; +/* fall through */ +case I2C_START_RECV : +dsrtc_latch (ds); +/* fall through */ +case I2C_FINISH : +DPRINTK ("Event %d" , (int )event); +/* fall through */ +case I2C_NACK : +break ; + } +return 0 ; +} + +static +int dsrtc_recv (I2CSlave *s) +{ +DSRTCState *ds =DSRTC (s); +int ret =0 ; + + ret = ds->regs[ds->addr]; + +if (ds->addr >R_YEAR && ds->addr < ds->info->nv_start) { +LOG (LOG_UNIMP ,"Read from unimplemented (%02x) %02x" , ds->addr, ret); + } + +DPRINTK ("Recv (%02x) %02x" , ds->addr, ret); + +dsrtc_advance (ds); + +return ret; +} + +static +int dsrtc_send (I2CSlave *s,uint8_t data) +{ +DSRTCState *ds =DSRTC (s); + +if (!ds->addrd) { +if (data ==0xff &&qtest_enabled ()) { +/* allow test runner to zero offsets */ +DPRINTK ("Testing reset" ); +dsrtc_reset (DEVICE (s)); +return 0 ; + } + ds->addr = data %DSRTC_REGSIZE ; + ds->addrd = true; +DPRINTK ("Set address pointer %02x" , data); +return 0 ; + } + +DPRINTK ("Send (%02x) %02x" , ds->addr, data); + +if (ds->addr <=R_YEAR ) { + ds->regs[ds->addr] = data; +dsrtc_update (ds); + + }else if (ds->addr >= ds->info->nv_start) { + ds->regs[ds->addr] = data; + + }else { +LOG (LOG_UNIMP ,"Register not modeled" ); + } + +dsrtc_advance (ds); + +return 0 ; +} + +static +void dsrtc_reset (DeviceState *device) +{ +DSRTCState *ds =DSRTC (device); + +memset (ds->regs,0 ,sizeof (ds->regs)); + + ds->addr =0 ; + ds->addrd = false; + ds->time_offset =0 ; + ds->wday_offset =0 ; + +DPRINTK ("Reset" ); +} + +static +void dsrtc_realize (DeviceState *device,Error **errp) +{ +DSRTCState *ds =DSRTC (device); +DSRTCClass *r =DSRTC_GET_CLASS (device); + + ds->info = r->info; + +/* Alarms not yet implemented, but allow +* board code to wire up the alarm interrupt +* output anyway. +*/ +qdev_init_gpio_out (device, &ds->alarm_irq,1 ); +} + +static +void dsrtc_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); +I2CSlaveClass *k =I2C_SLAVE_CLASS (klass); +DSRTCClass *r =DSRTC_CLASS (klass); + + r->info = data; + + k->event = &dsrtc_event; + k->recv = &dsrtc_recv; + k->send = &dsrtc_send; + + dc->vmsd = &vmstate_dsrtc; + dc->realize = dsrtc_realize; + dc->reset = dsrtc_reset; + dc->user_creatable = true; +} + +static +const TypeInfo ds_rtc_base_type = { + .abstract = true, + .name =TYPE_DSRTC , + .parent =TYPE_I2C_SLAVE , + .instance_size =sizeof (DSRTCState), +}; + +#define DSRTC_CONFIG (NAME ) \ +static const TypeInfo NAME##_type = { \ + .name = #NAME, \ + .parent = TYPE_DSRTC, \ + .class_size = sizeof(I2CSlaveClass), \ + .class_init = dsrtc_class_init, \ + .class_data = (void *)&NAME##_info, \ +}; + +/* ds3231 - alarms, no eeprom */ +static const DSRTCInfo ds3231_info = { + .has_century = true, + .nv_start =0x13 ,/* no nv memory */ + .reg_size =0x13 , +}; +DSRTC_CONFIG (ds3231) + +/* only model block 0 (RTC), blocks 1,2 (eeprom) not modeled. +* blocks have different i2c addresses +*/ +static const DSRTCInfo ds1388_info = { + .has_century = false, + .nv_start =0x0d , + .reg_size =0x0d , +}; +DSRTC_CONFIG (ds1388) + +/* alarms, eeprom */ +static const DSRTCInfo ds1375_info = { + .has_century = true, + .nv_start =0x10 , + .reg_size =0x20 , +}; +DSRTC_CONFIG (ds1375) + +/* no alarms, no eeprom */ +static const DSRTCInfo ds1340_info = { + .has_century = false, + .nv_start =0x10 , + .reg_size =0x10 , +}; +DSRTC_CONFIG (ds1340) + +/* alarms, no eeprom */ +static const DSRTCInfo ds1339_info = { + .has_century = false, + .nv_start =0x11 , + .reg_size =0x11 , +}; +DSRTC_CONFIG (ds1339) + +/* no alarms, eeprom */ +static const DSRTCInfo ds1338_info = { + .has_century = false, + .nv_start =0x08 , + .reg_size =0x40 , +}; +DSRTC_CONFIG (ds1338) + +/* alarms, no eeprom */ +static const DSRTCInfo ds1337_info = { + .has_century = true, + .nv_start =0x10 , + .reg_size =0x10 , +}; +DSRTC_CONFIG (ds1337) + +/* ds1307 registers are identical to ds1338 */ +static +const TypeInfo ds1307_type = { + .name ="ds1307" , + .parent ="ds1338" , +}; + +static void ds_rtc_i2c_register (void ) +{ +type_register_static (&ds_rtc_base_type); +type_register_static (&ds3231_type); +type_register_static (&ds1388_type); +type_register_static (&ds1375_type); +type_register_static (&ds1340_type); +type_register_static (&ds1339_type); +type_register_static (&ds1338_type); +type_register_static (&ds1337_type); +type_register_static (&ds1307_type); +} + +type_init (ds_rtc_i2c_register)hw/timer/ds1338.c deleted +0
-239@@ -1,239 +0,0 @@ -/* -* MAXIM DS1338 I2C RTC+NVRAM -* -* Copyright (c) 2009 CodeSourcery. -* Written by Paul Brook -* -* This code is licensed under the GNU GPL v2. -* -* Contributions after 2012-01-13 are licensed under the terms of the -* GNU GPL, version 2 or (at your option) any later version. -*/ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "hw/i2c/i2c.h" -#include "qemu/bcd.h" - -/* Size of NVRAM including both the user-accessible area and the -* secondary register area. -*/ -#define NVRAM_SIZE 64 - -/* Flags definitions */ -#define SECONDS_CH 0x80 -#define HOURS_12 0x40 -#define HOURS_PM 0x20 -#define CTRL_OSF 0x20 - -#define TYPE_DS1338 "ds1338" -#define DS1338 (obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338) - -typedef struct DS1338State { -I2CSlave parent_obj; - -int64_t offset; -uint8_t wday_offset; -uint8_t nvram[NVRAM_SIZE ]; -int32_t ptr; -bool addr_byte; -}DS1338State ; - -static const VMStateDescription vmstate_ds1338 = { - .name ="ds1338" , - .version_id =2 , - .minimum_version_id =1 , - .fields = (VMStateField []) { -VMSTATE_I2C_SLAVE (parent_obj, DS1338State), -VMSTATE_INT64 (offset, DS1338State), -VMSTATE_UINT8_V (wday_offset, DS1338State,2 ), -VMSTATE_UINT8_ARRAY (nvram, DS1338State,NVRAM_SIZE ), -VMSTATE_INT32 (ptr, DS1338State), -VMSTATE_BOOL (addr_byte, DS1338State), -VMSTATE_END_OF_LIST () - } -}; - -static void capture_current_time (DS1338State *s) -{ -/* Capture the current time into the secondary registers -* which will be actually read by the data transfer operation. -*/ -struct tm now; -qemu_get_timedate (&now, s->offset); - s->nvram[0 ] =to_bcd (now.tm_sec); - s->nvram[1 ] =to_bcd (now.tm_min); -if (s->nvram[2 ] &HOURS_12 ) { -int tmp = now.tm_hour; -if (tmp %12 ==0 ) { - tmp +=12 ; - } -if (tmp <=12 ) { - s->nvram[2 ] =HOURS_12 |to_bcd (tmp); - }else { - s->nvram[2 ] =HOURS_12 |HOURS_PM |to_bcd (tmp -12 ); - } - }else { - s->nvram[2 ] =to_bcd (now.tm_hour); - } - s->nvram[3 ] = (now.tm_wday + s->wday_offset) %7 +1 ; - s->nvram[4 ] =to_bcd (now.tm_mday); - s->nvram[5 ] =to_bcd (now.tm_mon +1 ); - s->nvram[6 ] =to_bcd (now.tm_year -100 ); -} - -static void inc_regptr (DS1338State *s) -{ -/* The register pointer wraps around after 0x3F; wraparound -* causes the current time/date to be retransferred into -* the secondary registers. -*/ - s->ptr = (s->ptr +1 ) & (NVRAM_SIZE -1 ); -if (!s->ptr) { -capture_current_time (s); - } -} - -static int ds1338_event (I2CSlave *i2c,enum i2c_event event) -{ -DS1338State *s =DS1338 (i2c); - -switch (event) { -case I2C_START_RECV : -/* In h/w, capture happens on any START condition, not just a -* START_RECV, but there is no need to actually capture on -* START_SEND, because the guest can't get at that data -* without going through a START_RECV which would overwrite it. -*/ -capture_current_time (s); -break ; -case I2C_START_SEND : - s->addr_byte = true; -break ; -default : -break ; - } - -return 0 ; -} - -static int ds1338_recv (I2CSlave *i2c) -{ -DS1338State *s =DS1338 (i2c); -uint8_t res; - - res = s->nvram[s->ptr]; -inc_regptr (s); -return res; -} - -static int ds1338_send (I2CSlave *i2c,uint8_t data) -{ -DS1338State *s =DS1338 (i2c); - -if (s->addr_byte) { - s->ptr = data & (NVRAM_SIZE -1 ); - s->addr_byte = false; -return 0 ; - } -if (s->ptr <7 ) { -/* Time register. */ -struct tm now; -qemu_get_timedate (&now, s->offset); -switch (s->ptr) { -case 0 : -/* TODO: Implement CH (stop) bit. */ - now.tm_sec =from_bcd (data &0x7f ); -break ; -case 1 : - now.tm_min =from_bcd (data &0x7f ); -break ; -case 2 : -if (data &HOURS_12 ) { -int tmp =from_bcd (data & (HOURS_PM -1 )); -if (data &HOURS_PM ) { - tmp +=12 ; - } -if (tmp %12 ==0 ) { - tmp -=12 ; - } - now.tm_hour = tmp; - }else { - now.tm_hour =from_bcd (data & (HOURS_12 -1 )); - } -break ; -case 3 : - { -/* The day field is supposed to contain a value in -the range 1-7. Otherwise behavior is undefined. -*/ -int user_wday = (data &7 ) -1 ; - s->wday_offset = (user_wday - now.tm_wday +7 ) %7 ; - } -break ; -case 4 : - now.tm_mday =from_bcd (data &0x3f ); -break ; -case 5 : - now.tm_mon =from_bcd (data &0x1f ) -1 ; -break ; -case 6 : - now.tm_year =from_bcd (data) +100 ; -break ; - } - s->offset =qemu_timedate_diff (&now); - }else if (s->ptr ==7 ) { -/* Control register. */ - -/* Ensure bits 2, 3 and 6 will read back as zero. */ - data &=0xB3 ; - -/* Attempting to write the OSF flag to logic 1 leaves the -value unchanged. */ - data = (data & ~CTRL_OSF ) | (data & s->nvram[s->ptr] &CTRL_OSF ); - - s->nvram[s->ptr] = data; - }else { - s->nvram[s->ptr] = data; - } -inc_regptr (s); -return 0 ; -} - -static void ds1338_reset (DeviceState *dev) -{ -DS1338State *s =DS1338 (dev); - -/* The clock is running and synchronized with the host */ - s->offset =0 ; - s->wday_offset =0 ; -memset (s->nvram,0 ,NVRAM_SIZE ); - s->ptr =0 ; - s->addr_byte = false; -} - -static void ds1338_class_init (ObjectClass *klass,void *data) -{ -DeviceClass *dc =DEVICE_CLASS (klass); -I2CSlaveClass *k =I2C_SLAVE_CLASS (klass); - - k->event = ds1338_event; - k->recv = ds1338_recv; - k->send = ds1338_send; - dc->reset = ds1338_reset; - dc->vmsd = &vmstate_ds1338; -} - -static const TypeInfo ds1338_info = { - .name =TYPE_DS1338 , - .parent =TYPE_I2C_SLAVE , - .instance_size =sizeof (DS1338State), - .class_init = ds1338_class_init, -}; - -static void ds1338_register_types (void ) -{ -type_register_static (&ds1338_info); -} - -type_init (ds1338_register_types)
Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
Quoted 13 lines · Michael Davidsaver
Quoted 12 lines · David Gibson
Quoted 6 lines · Michael Davidsaver
Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.Tested with ds1338 and ds1375.
Signed-off-by Michael Davidsaver <[email protected]>I certainly like the idea of consolidating this code, but reviewing to see that the new code really is a generalization of the old is something I won't have time for for a while.
Quoted 5 lines
Quoted 2 lines
Also, hw/timer is not within my purview so it'll probably need to go another path to merge.
Could you be a bit more explicit about what, if anything, I need to do to move this forward?
Ugh.. that's pretty tough, since ds1338 doesn't have an activate maintainer. You can look at the git history for some possible candidates of people to ask about it, but it hasn't been touched much in quite a while.
One approach that could help is to re-order so that your testing rework goes before the change to ds1338. If your new generalization can pass the same set of tests as the original ds1338 code, that's at least a good start on being convincing that it's a true superset of the previous functionality.
The other approach is to do the rework in a rather longer series of patches. Start by simply moving ds1338.c, then do a mechanical replacement of the names within it, then start generalizing and altering. That's a lot of work for you, but it makes it much easier to review each step
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices
Quoted 25 lines · David Gibson
Quoted 13 lines · Michael Davidsaver
Quoted 12 lines · David Gibson
Quoted 6 lines · Michael Davidsaver
Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.Tested with ds1338 and ds1375.
Signed-off-by Michael Davidsaver <[email protected]>I certainly like the idea of consolidating this code, but reviewing to see that the new code really is a generalization of the old is something I won't have time for for a while.
Quoted 5 lines
Quoted 2 lines
Also, hw/timer is not within my purview so it'll probably need to go another path to merge.
Could you be a bit more explicit about what, if anything, I need to do to move this forward?
Ugh.. that's pretty tough, since ds1338 doesn't have an activate maintainer. You can look at the git history for some possible candidates of people to ask about it, but it hasn't been touched much in quite a while.
Quoted 5 lines
One approach that could help is to re-order so that your testing rework goes before the change to ds1338. If your new generalization can pass the same set of tests as the original ds1338 code, that's at least a good start on being convincing that it's a true superset of the previous functionality.
A slight wrinkle is that my testing found two bugs with the original ds1338 model (also one in my new code). The two don't seem significant practically. It actually isn't possible to switch to 12-hour mode. And there is an obscure off by one situation possible with wday_offset and timezones. Of course most guests use 24-hour mode and ignore the RTC day-of-week.
The upshot of this is that several test cases now fail when run against ds1338.c.
My recommendation would be to start by looking at the test code. This could be compared against guest code. When I send the next iteration I'll include some links.
Quoted 5 lines
The other approach is to do the rework in a rather longer series of patches. Start by simply moving
ds1338.c, then do a mechanical replacement of the names within it, then start generalizing and altering. That's a lot of work for you, but it makes it much easier to review each step
I know from my first foray into QEMU land that this is preferable for review. Unfortunately, I expanded from my previous ds1375 model instead of the ds1338.
PATCH 6/17 tests: rewrite testing for DS RTC devices
In reply to Michael DavidsaverReplace existing ds1338-test with more thorough
test of time read and set.
--- tests/Makefile.include | 4 +- tests/ds-rtc-i2c-test.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/ds1338-test.c | 77 ----------------------- 3 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 tests/ds-rtc-i2c-test.c delete mode 100644 tests/ds1338-test.c
tests/Makefile.include +2 -2
@@ -348,7 +348,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF) check-qtest-sparc64-y += tests/prom-env-test$(EXESUF) check-qtest-arm-y = tests/tmp105-test$(EXESUF) -check-qtest-arm-y += tests/ds1338-test$(EXESUF) +check-qtest-arm-y += tests/ds-rtc-i2c-test$(EXESUF) check-qtest-arm-y += tests/m25p80-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -745,7 +745,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) -tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y) +tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) tests/m25p80-test$(EXESUF): tests/m25p80-test.o tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
tests/ds-rtc-i2c-test.c new file +162 -0
162 lines not on this page · raw message
tests/ds1338-test.c deleted +0 -77
77 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH 7/17 e500: fix pci host bridge class/type
In reply to Michael DavidsaverCorrect some confusion wrt. the PCI facing side of the PCI host bridge (not PCIe root complex). The ref. manual for the mpc8533 (as well as mpc8540 and mpc8540) give the class code as PCI_CLASS_PROCESSOR_POWERPC.
While the PCI_HEADER_TYPE field is oddly omitted, the tables in the "PCI Configuration Header" section shows a type 0 layout using all 6 BAR registers (as 2x 32, and 2x 64 bit regions)
So 997505065dc92e533debf5cb23012ba4e673d387 seems to be in error. Although there was perhaps some confusion as the mpc8533
has a separate PCIe root complex.
With PCIe, a root complex has PCI_HEADER_TYPE=1.
Neither the PCI host bridge, nor the PCIe root complex advertise class PCI_CLASS_BRIDGE_PCI.
This was confusing Linux guests, which try to interpret the host bridge as a pci-pci bridge, but get confused and re-enumerate the bus when the primary/secondary/subordinate bus registers don't have valid values.
--- hw/pci-host/ppce500.c | 5 ----- 1 file changed, 5 deletions(-)
hw/pci-host/ppce500.c +0 -5
@@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp) "/e500-ccsr"));MemoryRegion *ccsr_mr =sysbus_mmio_get_region (ccsr,0 ); -pci_config_set_class (d->config,PCI_CLASS_BRIDGE_PCI ); - d->config[PCI_HEADER_TYPE ] = - (d->config[PCI_HEADER_TYPE ] &PCI_HEADER_TYPE_MULTI_FUNCTION ) | -PCI_HEADER_TYPE_BRIDGE ; -memory_region_init_alias (&b->bar0,OBJECT (ccsr),"e500-pci-bar0" , ccsr_mr,0 ,memory_region_size (ccsr_mr));pci_register_bar (d,0 ,PCI_BASE_ADDRESS_SPACE_MEMORY , &b->bar0);
Signature · 1 line
2.11.0
David Gibson
AppliedRe: [Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type
Quoted 19 lines · Michael Davidsaver
Correct some confusion wrt. the PCI facing side of the PCI host bridge (not PCIe root complex). The ref. manual for the mpc8533 (as well as mpc8540 and mpc8540) give the class code as
PCI_CLASS_PROCESSOR_POWERPC.
While thePCI_HEADER_TYPEfield is oddly omitted, the tables in the "PCI Configuration Header" section shows a type 0 layout using all 6 BAR registers (as 2x 32, and 2x 64 bit regions)So
997505065dc92e533debf5cb23012ba4e673d387seems to be in error. Although there was perhaps some confusion as the mpc8533
has a separate PCIe root complex.
With PCIe, a root complex has PCI_HEADER_TYPE=1.Neither the PCI host bridge, nor the PCIe root complex advertise class
PCI_CLASS_BRIDGE_PCI.
Quoted 7 lines
This was confusing Linux guests, which try to interpret the host bridge as a pci-pci bridge, but get confused and re-enumerate the bus when the primary/secondary/subordinate bus registers don't have valid values.
Signed-off-by Michael Davidsaver <[email protected]>
Applied to ppc-for-2.12.
Quoted 20 lines
--- hw/pci-host/ppce500.c | 5 ----- 1 file changed, 5 deletions(-)hw/pci-host/ppce500.c +0
-5@@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp) "/e500-ccsr"));MemoryRegion *ccsr_mr =sysbus_mmio_get_region (ccsr,0 ); -pci_config_set_class (d->config,PCI_CLASS_BRIDGE_PCI ); - d->config[PCI_HEADER_TYPE ] = - (d->config[PCI_HEADER_TYPE ] &PCI_HEADER_TYPE_MULTI_FUNCTION ) | -PCI_HEADER_TYPE_BRIDGE ; -memory_region_init_alias (&b->bar0,OBJECT (ccsr),"e500-pci-bar0" , ccsr_mr,0 ,memory_region_size (ccsr_mr));pci_register_bar (d,0 ,PCI_BASE_ADDRESS_SPACE_MEMORY , &b->bar0);
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 8/17 e500: additional CCSR registers
In reply to Michael DavidsaverAdd CCSRBAR to allow CCSR region to be relocated.
Guest memory size introspection via RAM config
registers.
Dummy RAM error controls.
Clock introspection via Power on Reset PLL
Status Register.
ccsrbase also update iack
--- hw/ppc/e500.c | 5 ++- hw/ppc/e500_ccsr.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 3 deletions(-)
hw/ppc/e500.c +4 -1
@@ -51,7 +51,9 @@#define RAM_SIZES_ALIGN (64UL << 20) -/* TODO: parameterize */ +/* TODO: parameterize +* Some CCSR offsets duplicated in e500_ccsr.c +*/ #define MPC8544_CCSRBAR_SIZE 0x00100000ULL#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL#define MPC8544_MSI_REGS_OFFSET 0x41600ULL
@@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL );qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base); +qdev_prop_set_uint32 (dev,"ram-size" , ram_size);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 );
hw/ppc/e500_ccsr.c +91 -2
159 lines not on this page · raw message
Signature · 1 line
2.11.0
David Gibson
AppliedRe: [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers
Quoted 11 lines · Michael Davidsaver
Add CCSRBAR to allow CCSR region to be relocated.
Guest memory size introspection via RAM config
registers.Dummy RAM error controls.
Clock introspection via Power on Reset PLL
Status Register.Signed-off-by Michael Davidsaver <[email protected]>
Applied to ppc-for-2.12.
Quoted 198 lines
ccsrbase also update iack
--- hw/ppc/e500.c | 5 ++- hw/ppc/e500_ccsr.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 3 deletions(-)hw/ppc/e500.c +4
-1@@ -51,7 +51,9 @@#define RAM_SIZES_ALIGN (64UL << 20) -/* TODO: parameterize */ +/* TODO: parameterize +* Some CCSR offsets duplicated in e500_ccsr.c +*/ #define MPC8544_CCSRBAR_SIZE 0x00100000ULL#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL#define MPC8544_MSI_REGS_OFFSET 0x41600ULL@@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL );qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base); +qdev_prop_set_uint32 (dev,"ram-size" , ram_size);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 );hw/ppc/e500_ccsr.c +91
-2@@ -30,13 +30,26 @@#include "hw/sysbus.h" /* E500_ denotes registers common to all */ +/* Some CCSR offsets duplicated in e500.c */ +#define E500_CCSRBAR (0) + +#define E500_CS0_BNDS (0x2000) + +#define E500_CS0_CONFIG (0x2080) + +#define E500_ERR_DETECT (0x2e40) +#define E500_ERR_DISABLE (0x2e44) + +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)#define MPC8544_RSTCR (0xE00B0)#define MPC8544_RSTCR_RESET (0x02) +#define E500_MPIC_OFFSET (0x40000ULL) + typedef struct { /*< private >*/ SysBusDevice parent_obj;@@ -44,19 +57,59 @@ typedef struct {MemoryRegion iomem; -uint32_t defbase; +uint32_t defbase, base; +uint32_t ram_size; +uint32_t merrd; + +uint32_t porpllsr; + +DeviceState *pic; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"#define E500_CCSR (obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR) +/* call after changing CCSRState::base */ +static void e500_ccsr_post_move (CCSRState *ccsr) +{ +CPUState *cs; + +CPU_FOREACH (cs) { +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; + + env->mpic_iack = ccsr->base + +E500_MPIC_OFFSET +0xa0 ; + } + +sysbus_mmio_map (SYS_BUS_DEVICE (ccsr),0 , ccsr->base); +} +static uint64_t e500_ccsr_read (void *opaque,hwaddr addr,unsigned size) { +CCSRState *ccsr = opaque;PowerPCCPU *cpu =POWERPC_CPU (current_cpu);CPUPPCState *env = &cpu->env;switch (addr) { +case E500_CCSRBAR : +return ccsr->base >>12 ; +case E500_CS0_BNDS : +/* we model all RAM in a single chip with addresses [0, ram_size) */ +return (ccsr->ram_size -1 ) >>24 ; +case E500_CS0_CONFIG : +return 1 <<31 ; +case E500_ERR_DETECT : +return 0 ;/* (errors not modeled) */ +case E500_ERR_DISABLE : +return ccsr->merrd; +case E500_PORPLLSR : +if (!ccsr->porpllsr) { +qemu_log_mask (LOG_UNIMP , +"Machine does not provide valid PORPLLSR\n" ); + } +return ccsr->porpllsr;case E500_PVR :return env->spr[SPR_PVR ];case E500_SVR :@@ -72,10 +125,22 @@ static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,static void e500_ccsr_write (void *opaque,hwaddr addr,uint64_t value,unsigned size) { +CCSRState *ccsr = opaque;PowerPCCPU *cpu =POWERPC_CPU (current_cpu);CPUPPCState *env = &cpu->env;uint32_t svr = env->spr[SPR_E500_SVR ] >>16 ; +switch (addr) { +case E500_CCSRBAR : + value &=0x000fff00 ; + ccsr->base = value <<12 ; +e500_ccsr_post_move (ccsr); +return ; +case E500_ERR_DISABLE : + ccsr->merrd = value &0xd ; +return ; + } +switch (svr) {case 0 :/* generic. assumed to be mpc8544ds or e500plat board */ case 0x8034 :/* mpc8544 */ @@ -104,11 +169,20 @@ static const MemoryRegionOps e500_ccsr_ops = { } }; +static int e500_ccsr_post_load (void *opaque,int version_id) +{ +CCSRState *ccsr = opaque; + +e500_ccsr_post_move (ccsr); +return 0 ; +} +static void e500_ccsr_reset (DeviceState *dev) {CCSRState *ccsr =E500_CCSR (dev); -sysbus_mmio_map (SYS_BUS_DEVICE (dev),0 , ccsr->defbase); + ccsr->base = ccsr->defbase; +e500_ccsr_post_move (ccsr); }static void e500_ccsr_initfn (Object *obj)@@ -123,15 +197,30 @@ static void e500_ccsr_initfn(Object *obj)static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("base" , CCSRState, defbase,0xff700000 ), +DEFINE_PROP_UINT32 ("ram-size" , CCSRState, ram_size,0 ), +DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ),DEFINE_PROP_END_OF_LIST () }; +static const VMStateDescription vmstate_e500_ccsr = { + .name =TYPE_E500_CCSR , + .version_id =1 , + .minimum_version_id =1 , + .post_load = e500_ccsr_post_load, + .fields = (VMStateField []) { +VMSTATE_UINT32 (base, CCSRState), +VMSTATE_UINT32 (merrd, CCSRState), +VMSTATE_END_OF_LIST () + } +}; +static void e500_ccsr_class_initfn (ObjectClass *klass,void *data) {DeviceClass *dc =DEVICE_CLASS (klass); dc->props = e500_ccsr_props; + dc->vmsd = &vmstate_e500_ccsr; dc->reset = e500_ccsr_reset; }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 08/17] e500: additional CCSR registers
Quoted 6 lines · David Gibson
Quoted 5 lines · Michael Davidsaver
Add CCSRBAR to allow CCSR region to be relocated.
Guest memory size introspection via RAM config
registers.
Quoted 8 lines
Quoted 6 lines
Dummy RAM error controls.
Clock introspection via Power on Reset PLL
Status Register.Signed-off-by Michael Davidsaver <[email protected]>Applied to ppc-for-2.12.
Sorry, I've pulled this from ppc-for-2.12 because it depended on the guts patch which brokem make check.
Quoted 200 lines
Quoted 199 lines
ccsrbase also update iack
--- hw/ppc/e500.c | 5 ++- hw/ppc/e500_ccsr.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 3 deletions(-)hw/ppc/e500.c +4
-1@@ -51,7 +51,9 @@#define RAM_SIZES_ALIGN (64UL << 20) -/* TODO: parameterize */ +/* TODO: parameterize +* Some CCSR offsets duplicated in e500_ccsr.c +*/ #define MPC8544_CCSRBAR_SIZE 0x00100000ULL#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL#define MPC8544_MSI_REGS_OFFSET 0x41600ULL@@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL );qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base); +qdev_prop_set_uint32 (dev,"ram-size" , ram_size);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 );hw/ppc/e500_ccsr.c +91
-2@@ -30,13 +30,26 @@#include "hw/sysbus.h" /* E500_ denotes registers common to all */ +/* Some CCSR offsets duplicated in e500.c */ +#define E500_CCSRBAR (0) + +#define E500_CS0_BNDS (0x2000) + +#define E500_CS0_CONFIG (0x2080) + +#define E500_ERR_DETECT (0x2e40) +#define E500_ERR_DISABLE (0x2e44) + +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)#define MPC8544_RSTCR (0xE00B0)#define MPC8544_RSTCR_RESET (0x02) +#define E500_MPIC_OFFSET (0x40000ULL) + typedef struct { /*< private >*/ SysBusDevice parent_obj;@@ -44,19 +57,59 @@ typedef struct {MemoryRegion iomem; -uint32_t defbase; +uint32_t defbase, base; +uint32_t ram_size; +uint32_t merrd; + +uint32_t porpllsr; + +DeviceState *pic; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"#define E500_CCSR (obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR) +/* call after changing CCSRState::base */ +static void e500_ccsr_post_move (CCSRState *ccsr) +{ +CPUState *cs; + +CPU_FOREACH (cs) { +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; + + env->mpic_iack = ccsr->base + +E500_MPIC_OFFSET +0xa0 ; + } + +sysbus_mmio_map (SYS_BUS_DEVICE (ccsr),0 , ccsr->base); +} +static uint64_t e500_ccsr_read (void *opaque,hwaddr addr,unsigned size) { +CCSRState *ccsr = opaque;PowerPCCPU *cpu =POWERPC_CPU (current_cpu);CPUPPCState *env = &cpu->env;switch (addr) { +case E500_CCSRBAR : +return ccsr->base >>12 ; +case E500_CS0_BNDS : +/* we model all RAM in a single chip with addresses [0, ram_size) */ +return (ccsr->ram_size -1 ) >>24 ; +case E500_CS0_CONFIG : +return 1 <<31 ; +case E500_ERR_DETECT : +return 0 ;/* (errors not modeled) */ +case E500_ERR_DISABLE : +return ccsr->merrd; +case E500_PORPLLSR : +if (!ccsr->porpllsr) { +qemu_log_mask (LOG_UNIMP , +"Machine does not provide valid PORPLLSR\n" ); + } +return ccsr->porpllsr;case E500_PVR :return env->spr[SPR_PVR ];case E500_SVR :@@ -72,10 +125,22 @@ static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,static void e500_ccsr_write (void *opaque,hwaddr addr,uint64_t value,unsigned size) { +CCSRState *ccsr = opaque;PowerPCCPU *cpu =POWERPC_CPU (current_cpu);CPUPPCState *env = &cpu->env;uint32_t svr = env->spr[SPR_E500_SVR ] >>16 ; +switch (addr) { +case E500_CCSRBAR : + value &=0x000fff00 ; + ccsr->base = value <<12 ; +e500_ccsr_post_move (ccsr); +return ; +case E500_ERR_DISABLE : + ccsr->merrd = value &0xd ; +return ; + } +switch (svr) {case 0 :/* generic. assumed to be mpc8544ds or e500plat board */ case 0x8034 :/* mpc8544 */ @@ -104,11 +169,20 @@ static const MemoryRegionOps e500_ccsr_ops = { } }; +static int e500_ccsr_post_load (void *opaque,int version_id) +{ +CCSRState *ccsr = opaque; + +e500_ccsr_post_move (ccsr); +return 0 ; +} +static void e500_ccsr_reset (DeviceState *dev) {CCSRState *ccsr =E500_CCSR (dev); -sysbus_mmio_map (SYS_BUS_DEVICE (dev),0 , ccsr->defbase); + ccsr->base = ccsr->defbase; +e500_ccsr_post_move (ccsr); }static void e500_ccsr_initfn (Object *obj)@@ -123,15 +197,30 @@ static void e500_ccsr_initfn(Object *obj)static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("base" , CCSRState, defbase,0xff700000 ), +DEFINE_PROP_UINT32 ("ram-size" , CCSRState, ram_size,0 ), +DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ),DEFINE_PROP_END_OF_LIST () }; +static const VMStateDescription vmstate_e500_ccsr = { + .name =TYPE_E500_CCSR , + .version_id =1 , + .minimum_version_id =1 , + .post_load = e500_ccsr_post_load, + .fields = (VMStateField []) { +VMSTATE_UINT32 (base, CCSRState), +VMSTATE_UINT32 (merrd, CCSRState), +VMSTATE_END_OF_LIST () + } +}; +static void e500_ccsr_class_initfn (ObjectClass *klass,void *data) {DeviceClass *dc =DEVICE_CLASS (klass); dc->props = e500_ccsr_props; + dc->vmsd = &vmstate_e500_ccsr; dc->reset = e500_ccsr_reset; }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 9/17 e500: move mpic under CCSR
In reply to Michael DavidsaverStart moving code out of ppce500_init()
Existing ppce500_init_mpic() suggests that MPIC may not be created w/ KVM. However, ppce500_init() used mpicdev unconditionally, and would fail if the MPIC isn't created. So require creation.
Not tested with KVM for lack of hardware.
--- hw/ppc/e500.c | 102 +++-------------------------------------------------- hw/ppc/e500_ccsr.c | 85 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 103 deletions(-)
hw/ppc/e500.c +4 -98
@@ -29,7 +29,6 @@#include "sysemu/kvm.h" #include "kvm_ppc.h" #include "sysemu/device_tree.h" -#include "hw/ppc/openpic.h" #include "hw/ppc/ppc.h" #include "hw/loader.h" #include "elf.h"
@@ -679,92 +678,6 @@ static void ppce500_cpu_reset(void *opaque)mmubooke_create_initial_mapping (env); } -static DeviceState *ppce500_init_mpic_qemu (PPCE500Params *params, -qemu_irq **irqs) -{ -DeviceState *dev; -SysBusDevice *s; -int i, j, k; - - dev =qdev_create (NULL ,TYPE_OPENPIC ); -object_property_add_child (qdev_get_machine (),"pic" ,OBJECT (dev), - &error_fatal); -qdev_prop_set_uint32 (dev,"model" , params->mpic_version); -qdev_prop_set_uint32 (dev,"nb_cpus" , smp_cpus); - -qdev_init_nofail (dev); - s =SYS_BUS_DEVICE (dev); - - k =0 ; -for (i =0 ; i < smp_cpus; i++) { -for (j =0 ; j <OPENPIC_OUTPUT_NB ; j++) { -sysbus_connect_irq (s, k++, irqs[i][j]); - } - } - -return dev; -} - -static DeviceState *ppce500_init_mpic_kvm (PPCE500Params *params, -qemu_irq **irqs,Error **errp) -{ -Error *err =NULL ; -DeviceState *dev; -CPUState *cs; - - dev =qdev_create (NULL ,TYPE_KVM_OPENPIC ); -qdev_prop_set_uint32 (dev,"model" , params->mpic_version); - -object_property_set_bool (OBJECT (dev), true,"realized" , &err); -if (err) { -error_propagate (errp, err); -object_unparent (OBJECT (dev)); -return NULL ; - } - -CPU_FOREACH (cs) { -if (kvm_openpic_connect_vcpu (dev, cs)) { -fprintf (stderr,"%s: failed to connect vcpu to irqchip\n" , - __func__); -abort (); - } - } - -return dev; -} - -static DeviceState *ppce500_init_mpic (MachineState *machine, -PPCE500Params *params, -MemoryRegion *ccsr, -qemu_irq **irqs) -{ -DeviceState *dev =NULL ; -SysBusDevice *s; - -if (kvm_enabled ()) { -Error *err =NULL ; - -if (machine_kernel_irqchip_allowed (machine)) { - dev =ppce500_init_mpic_kvm (params, irqs, &err); - } -if (machine_kernel_irqchip_required (machine) && !dev) { -error_reportf_err (err, -"kernel_irqchip requested but unavailable: " ); -exit (1 ); - } - } - -if (!dev) { - dev =ppce500_init_mpic_qemu (params, irqs); - } - - s =SYS_BUS_DEVICE (dev); -memory_region_add_subregion (ccsr,MPC8544_MPIC_REGS_OFFSET , - s->mmio[0 ].memory); - -return dev; -} -static void ppce500_power_off (void *opaque,int line,int on) {if (on) {
@@ -794,18 +707,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)/* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and * 4 respectively */ unsigned int pci_irq_nrs[PCI_NUM_PINS ] = {1 ,2 ,3 ,4 }; -qemu_irq **irqs;DeviceState *dev, *mpicdev;CPUPPCState *firstenv =NULL ;MemoryRegion *ccsr_addr_space;SysBusDevice *s; - irqs =g_malloc0 (smp_cpus *sizeof (qemu_irq *)); - irqs[0 ] =g_malloc0 (smp_cpus *sizeof (qemu_irq) *OPENPIC_OUTPUT_NB );for (i =0 ; i < smp_cpus; i++) {PowerPCCPU *cpu;CPUState *cs; -qemu_irq *input; cpu =POWERPC_CPU (cpu_create (machine->cpu_type)); env = &cpu->env;
@@ -821,13 +730,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) firstenv = env; } - irqs[i] = irqs[0 ] + (i *OPENPIC_OUTPUT_NB ); - input = (qemu_irq *)env->irq_inputs; - irqs[i][OPENPIC_OUTPUT_INT ] = input[PPCE500_INPUT_INT ]; - irqs[i][OPENPIC_OUTPUT_CINT ] = input[PPCE500_INPUT_CINT ]; env->spr_cb[SPR_BOOKE_PIR ].default_value = cs->cpu_index = i; - env->mpic_iack = params->ccsrbar_base + -MPC8544_MPIC_REGS_OFFSET +0xa0 ;ppc_booke_timers_init (cpu,400000000 ,PPC_TIMER_E500 );
@@ -857,12 +760,15 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) dev =qdev_create (NULL ,"e500-ccsr" );object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL ); +qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 ); - mpicdev =ppce500_init_mpic (machine, params, ccsr_addr_space, irqs); +/* created under "e500-ccsr" */ + mpicdev =DEVICE (object_resolve_path ("/machine/pic" ,0 )); +assert (mpicdev);/* Serial */ if (serial_hds[0 ]) {
hw/ppc/e500_ccsr.c +80 -5
123 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR
Quoted 196 lines · Michael Davidsaver
Start moving code out of
ppce500_init()Existing
ppce500_init_mpic()suggests that MPIC may not be created w/ KVM. However,ppce500_init()used mpicdev unconditionally, and would fail if the MPIC isn't created. So require creation.Not tested with KVM for lack of hardware.
Signed-off-by Michael Davidsaver <[email protected]>--- hw/ppc/e500.c | 102 +++-------------------------------------------------- hw/ppc/e500_ccsr.c | 85 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 103 deletions(-)hw/ppc/e500.c +4
-98@@ -29,7 +29,6 @@#include "sysemu/kvm.h" #include "kvm_ppc.h" #include "sysemu/device_tree.h" -#include "hw/ppc/openpic.h" #include "hw/ppc/ppc.h" #include "hw/loader.h" #include "elf.h" @@ -679,92 +678,6 @@ static void ppce500_cpu_reset(void *opaque)mmubooke_create_initial_mapping (env); } -static DeviceState *ppce500_init_mpic_qemu (PPCE500Params *params, -qemu_irq **irqs) -{ -DeviceState *dev; -SysBusDevice *s; -int i, j, k; - - dev =qdev_create (NULL ,TYPE_OPENPIC ); -object_property_add_child (qdev_get_machine (),"pic" ,OBJECT (dev), - &error_fatal); -qdev_prop_set_uint32 (dev,"model" , params->mpic_version); -qdev_prop_set_uint32 (dev,"nb_cpus" , smp_cpus); - -qdev_init_nofail (dev); - s =SYS_BUS_DEVICE (dev); - - k =0 ; -for (i =0 ; i < smp_cpus; i++) { -for (j =0 ; j <OPENPIC_OUTPUT_NB ; j++) { -sysbus_connect_irq (s, k++, irqs[i][j]); - } - } - -return dev; -} - -static DeviceState *ppce500_init_mpic_kvm (PPCE500Params *params, -qemu_irq **irqs,Error **errp) -{ -Error *err =NULL ; -DeviceState *dev; -CPUState *cs; - - dev =qdev_create (NULL ,TYPE_KVM_OPENPIC ); -qdev_prop_set_uint32 (dev,"model" , params->mpic_version); - -object_property_set_bool (OBJECT (dev), true,"realized" , &err); -if (err) { -error_propagate (errp, err); -object_unparent (OBJECT (dev)); -return NULL ; - } - -CPU_FOREACH (cs) { -if (kvm_openpic_connect_vcpu (dev, cs)) { -fprintf (stderr,"%s: failed to connect vcpu to irqchip\n" , - __func__); -abort (); - } - } - -return dev; -} - -static DeviceState *ppce500_init_mpic (MachineState *machine, -PPCE500Params *params, -MemoryRegion *ccsr, -qemu_irq **irqs) -{ -DeviceState *dev =NULL ; -SysBusDevice *s; - -if (kvm_enabled ()) { -Error *err =NULL ; - -if (machine_kernel_irqchip_allowed (machine)) { - dev =ppce500_init_mpic_kvm (params, irqs, &err); - } -if (machine_kernel_irqchip_required (machine) && !dev) { -error_reportf_err (err, -"kernel_irqchip requested but unavailable: " ); -exit (1 ); - } - } - -if (!dev) { - dev =ppce500_init_mpic_qemu (params, irqs); - } - - s =SYS_BUS_DEVICE (dev); -memory_region_add_subregion (ccsr,MPC8544_MPIC_REGS_OFFSET , - s->mmio[0 ].memory); - -return dev; -} -static void ppce500_power_off (void *opaque,int line,int on) {if (on) {@@ -794,18 +707,14 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)/* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and * 4 respectively */ unsigned int pci_irq_nrs[PCI_NUM_PINS ] = {1 ,2 ,3 ,4 }; -qemu_irq **irqs;DeviceState *dev, *mpicdev;CPUPPCState *firstenv =NULL ;MemoryRegion *ccsr_addr_space;SysBusDevice *s; - irqs =g_malloc0 (smp_cpus *sizeof (qemu_irq *)); - irqs[0 ] =g_malloc0 (smp_cpus *sizeof (qemu_irq) *OPENPIC_OUTPUT_NB );for (i =0 ; i < smp_cpus; i++) {PowerPCCPU *cpu;CPUState *cs; -qemu_irq *input; cpu =POWERPC_CPU (cpu_create (machine->cpu_type)); env = &cpu->env;@@ -821,13 +730,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) firstenv = env; } - irqs[i] = irqs[0 ] + (i *OPENPIC_OUTPUT_NB ); - input = (qemu_irq *)env->irq_inputs; - irqs[i][OPENPIC_OUTPUT_INT ] = input[PPCE500_INPUT_INT ]; - irqs[i][OPENPIC_OUTPUT_CINT ] = input[PPCE500_INPUT_CINT ]; env->spr_cb[SPR_BOOKE_PIR ].default_value = cs->cpu_index = i; - env->mpic_iack = params->ccsrbar_base + -MPC8544_MPIC_REGS_OFFSET +0xa0 ;ppc_booke_timers_init (cpu,400000000 ,PPC_TIMER_E500 );@@ -857,12 +760,15 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) dev =qdev_create (NULL ,"e500-ccsr" );object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL ); +qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 ); - mpicdev =ppce500_init_mpic (machine, params, ccsr_addr_space, irqs); +/* created under "e500-ccsr" */ + mpicdev =DEVICE (object_resolve_path ("/machine/pic" ,0 )); +assert (mpicdev);/* Serial */ if (serial_hds[0 ]) {hw/ppc/e500_ccsr.c +5
-2@@ -24,10 +24,14 @@#include "qemu-common.h" #include "qemu/log.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "cpu.h" #include "hw/hw.h" +#include "hw/boards.h" #include "sysemu/sysemu.h" +#include "sysemu/kvm.h" #include "hw/sysbus.h" +#include "hw/ppc/openpic.h" /* E500_ denotes registers common to all */ /* Some CCSR offsets duplicated in e500.c */ @@ -185,20 +189,90 @@ static void e500_ccsr_reset(DeviceState *dev)e500_ccsr_post_move (ccsr); } -static void e500_ccsr_initfn (Object *obj) +static void e500_ccsr_init (Object *obj) { -CCSRState *ccsr =E500_CCSR (obj);
hw/ppc/e500_ccsr.c static void e500_ccsr_reset(DeviceState *dev) · line 203
Quoted 10 lines
hw/ppc/e500_ccsr.c +10
-0+DeviceState *dev =DEVICE (obj); +CCSRState *ccsr =E500_CCSR (dev); + +assert (current_machine); +if (kvm_enabled ()) { + +if (!machine_kernel_irqchip_allowed (current_machine)) { +error_report ("Machine does not allow PIC," +" but this is not supported" ); +exit (1 );
You've changed the logic here from the original; this now always requires a kernel irqchip with kvm, whereas previously it would allow fallback to the non kernel irqchip unless machine_kernel_irqchip_required().
Quoted 94 lines
hw/ppc/e500_ccsr.c +65
-3+ } -memory_region_init_io (&ccsr->iomem, obj, &e500_ccsr_ops, + ccsr->pic =qdev_create (NULL ,TYPE_KVM_OPENPIC ); + }else { + ccsr->pic =qdev_create (NULL ,TYPE_OPENPIC ); + } + +if (!ccsr->pic) { +error_report ("Failed to create PIC" ); +exit (1 ); + } + +object_property_add_child (qdev_get_machine (),"pic" ,OBJECT (ccsr->pic), + &error_fatal); + +qdev_prop_set_uint32 (ccsr->pic,"nb_cpus" , smp_cpus); + +object_property_add_alias (obj,"mpic-model" , +OBJECT (ccsr->pic),"model" , + &error_fatal); +} + +static void e500_ccsr_realize (DeviceState *dev,Error **errp) +{ +CCSRState *ccsr =E500_CCSR (dev); +SysBusDevice *pic; + +/* Base 1MB CCSR Region */ +memory_region_init_io (&ccsr->iomem,OBJECT (dev), &e500_ccsr_ops, ccsr,"e500-ccsr" ,1024 *1024 ); -sysbus_init_mmio (SYS_BUS_DEVICE (obj), &ccsr->iomem); +sysbus_init_mmio (SYS_BUS_DEVICE (dev), &ccsr->iomem); + +qdev_init_nofail (ccsr->pic); + pic =SYS_BUS_DEVICE (ccsr->pic); + +/* connect MPIC to CPU(s) */ +if (kvm_enabled ()) { +CPUState *cs; + +CPU_FOREACH (cs) { +if (kvm_openpic_connect_vcpu (ccsr->pic, cs)) { +error_setg (errp,"%s: failed to connect vcpu to irqchip" , + __func__); +return ; + } + } + + }else { +CPUState *cs; + +CPU_FOREACH (cs) { +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; +qemu_irq *inputs = (qemu_irq *)env->irq_inputs; +int base = cs->cpu_index *PPCE500_INPUT_NB ; + +sysbus_connect_irq (pic, base +OPENPIC_OUTPUT_INT , + inputs[PPCE500_INPUT_INT ]); +sysbus_connect_irq (pic, base +OPENPIC_OUTPUT_CINT , + inputs[PPCE500_INPUT_CINT ]); + } + } +memory_region_add_subregion (&ccsr->iomem,E500_MPIC_OFFSET , +sysbus_mmio_get_region (pic,0 )); }static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("base" , CCSRState, defbase,0xff700000 ),DEFINE_PROP_UINT32 ("ram-size" , CCSRState, ram_size,0 ),DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ), +/* "mpic-model" aliased from MPIC */ DEFINE_PROP_END_OF_LIST () };@@ -221,6 +295,7 @@ void e500_ccsr_class_initfn(ObjectClass *klass, void *data) dc->props = e500_ccsr_props; dc->vmsd = &vmstate_e500_ccsr; + dc->realize = e500_ccsr_realize; dc->reset = e500_ccsr_reset; }@@ -228,7 +303,7 @@ static const TypeInfo e500_ccsr_info = { .name = TYPE_E500_CCSR, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CCSRState), - .instance_init = e500_ccsr_initfn, + .instance_init = e500_ccsr_init, .class_size = sizeof(SysBusDeviceClass), .class_init = e500_ccsr_class_initfn };
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 10/17 e500: move uarts CCSR
In reply to Michael Davidsaver--- hw/ppc/e500.c | 13 ------------- hw/ppc/e500_ccsr.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 13 deletions(-)
hw/ppc/e500.c +0 -13
@@ -22,7 +22,6 @@#include "net/net.h" #include "qemu/config-file.h" #include "hw/hw.h" -#include "hw/char/serial.h" #include "hw/pci/pci.h" #include "hw/boards.h" #include "sysemu/sysemu.h"
@@ -770,18 +769,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) mpicdev =DEVICE (object_resolve_path ("/machine/pic" ,0 ));assert (mpicdev); -/* Serial */ -if (serial_hds[0 ]) { -serial_mm_init (ccsr_addr_space,MPC8544_SERIAL0_REGS_OFFSET , -0 ,qdev_get_gpio_in (mpicdev,42 ),399193 , - serial_hds[0 ],DEVICE_BIG_ENDIAN ); - } - -if (serial_hds[1 ]) { -serial_mm_init (ccsr_addr_space,MPC8544_SERIAL1_REGS_OFFSET , -0 ,qdev_get_gpio_in (mpicdev,42 ),399193 , - serial_hds[1 ],DEVICE_BIG_ENDIAN ); - }/* PCI */ dev =qdev_create (NULL ,"e500-pcihost" );
hw/ppc/e500_ccsr.c +18 -0
@@ -31,6 +31,7 @@#include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "hw/sysbus.h" +#include "hw/char/serial.h" #include "hw/ppc/openpic.h" /* E500_ denotes registers common to all */
@@ -45,6 +46,8 @@#define E500_ERR_DETECT (0x2e40)#define E500_ERR_DISABLE (0x2e44) +#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100) +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)
@@ -266,6 +269,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)memory_region_add_subregion (&ccsr->iomem,E500_MPIC_OFFSET ,sysbus_mmio_get_region (pic,0 )); +/* Note: MPIC internal interrupts are offset by 16 */ + +/* DUARTS */ +if (serial_hds[0 ]) { +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (0 ), +0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , + serial_hds[0 ],DEVICE_BIG_ENDIAN ); + } + +if (serial_hds[1 ]) { +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (1 ), +0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , + serial_hds[1 ],DEVICE_BIG_ENDIAN ); + } + }static Property e500_ccsr_props[] = {
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 10/17] e500: move uarts CCSR
Quoted 59 lines · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>--- hw/ppc/e500.c | 13 ------------- hw/ppc/e500_ccsr.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 13 deletions(-)hw/ppc/e500.c +0
-13@@ -22,7 +22,6 @@#include "net/net.h" #include "qemu/config-file.h" #include "hw/hw.h" -#include "hw/char/serial.h" #include "hw/pci/pci.h" #include "hw/boards.h" #include "sysemu/sysemu.h" @@ -770,18 +769,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) mpicdev =DEVICE (object_resolve_path ("/machine/pic" ,0 ));assert (mpicdev); -/* Serial */ -if (serial_hds[0 ]) { -serial_mm_init (ccsr_addr_space,MPC8544_SERIAL0_REGS_OFFSET , -0 ,qdev_get_gpio_in (mpicdev,42 ),399193 , - serial_hds[0 ],DEVICE_BIG_ENDIAN ); - } - -if (serial_hds[1 ]) { -serial_mm_init (ccsr_addr_space,MPC8544_SERIAL1_REGS_OFFSET , -0 ,qdev_get_gpio_in (mpicdev,42 ),399193 , - serial_hds[1 ],DEVICE_BIG_ENDIAN ); - }/* PCI */ dev =qdev_create (NULL ,"e500-pcihost" );hw/ppc/e500_ccsr.c +3
-0@@ -31,6 +31,7 @@#include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "hw/sysbus.h" +#include "hw/char/serial.h" #include "hw/ppc/openpic.h" /* E500_ denotes registers common to all */ @@ -45,6 +46,8 @@#define E500_ERR_DETECT (0x2e40)#define E500_ERR_DISABLE (0x2e44) +#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100) +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)
hw/ppc/e500_ccsr.c static void e500_ccsr_realize(DeviceState *dev, Error **errp) · line 276
Quoted 8 lines
hw/ppc/e500_ccsr.c +5
-0@@ -266,6 +269,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)memory_region_add_subregion (&ccsr->iomem,E500_MPIC_OFFSET ,sysbus_mmio_get_region (pic,0 )); +/* Note: MPIC internal interrupts are offset by 16 */ + +/* DUARTS */ +if (serial_hds[0 ]) { + serial_mm_init(&ccsr->iomem, E500_DUART_OFFSET(0),
By changing the constants in use here for the base address you're now creating the actual device and creating the device tree entry from different (but same valued) constants. That seems risky.
Quoted 13 lines
hw/ppc/e500_ccsr.c +10
-0+0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , + serial_hds[0], DEVICE_BIG_ENDIAN); + } + +if (serial_hds[1 ]) { +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (1 ), +0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , + serial_hds[1 ],DEVICE_BIG_ENDIAN ); + } + }static Property e500_ccsr_props[] = {
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 11/17 e500: derive baud from CCB clock
In reply to Michael DavidsaverThe CCB (Complex Core Bus) clock is the reference for the DUARTs with an extra divide by 16.
Quoted 1 line
From the mpc8540, mpc8544, and P2010 ref manuals.
CCB=333MHz, with divider=0x87a gives ~9600 baud.
333e6 Hz/(16*0x87a) = 9591 Hz.
This is verified with a real mpc8540.
The existing value for the mpc8544ds boards is replaced. Previously the uart "clock-frequency" device tree node was left as zero, and at some point either u-boot or Linux picks a value inconsistent with the frequency given to serial_mm_init().
The FIFO timeout calculated from this was incorrect.
Now use an arbitrary (valid) CCB frequency of 333MHz in the device tree and for the UART.
--- hw/ppc/e500.c | 9 ++++++++- hw/ppc/e500_ccsr.c | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-)
hw/ppc/e500.c +8 -1
@@ -49,6 +49,12 @@#define RAM_SIZES_ALIGN (64UL << 20) +/* Somewhat arbitrarily choosen Complex Core Bus frequency +* for our simulation (real freq of mpc8544ds board unknown) +* Used in baud rate calculations. +*/ +#define CCB_FREQ (333333333) +/* TODO: parameterize * Some CCSR offsets duplicated in e500_ccsr.c */
@@ -113,7 +119,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,qemu_fdt_setprop_string (fdt, ser,"compatible" ,"ns16550" );qemu_fdt_setprop_cells (fdt, ser,"reg" , offset,0x100 );qemu_fdt_setprop_cell (fdt, ser,"cell-index" , idx); -qemu_fdt_setprop_cell (fdt, ser,"clock-frequency" ,0 ); +qemu_fdt_setprop_cell (fdt, ser,"clock-frequency" ,CCB_FREQ );qemu_fdt_setprop_cells (fdt, ser,"interrupts" ,42 ,2 );qemu_fdt_setprop_phandle (fdt, ser,"interrupt-parent" , mpic);qemu_fdt_setprop_string (fdt,"/aliases" , alias, ser);
@@ -759,6 +765,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) dev =qdev_create (NULL ,"e500-ccsr" );object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL ); +qdev_prop_set_uint32 (dev,"ccb-freq" ,CCB_FREQ );qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size);
hw/ppc/e500_ccsr.c +12 -4
@@ -69,6 +69,7 @@ typedef struct {uint32_t merrd;uint32_t porpllsr; +uint32_t ccb_freq;DeviceState *pic; } CCSRState;
@@ -272,15 +273,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)/* Note: MPIC internal interrupts are offset by 16 */ /* DUARTS */ +/* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock +* is the CCB clock divided by 16. +* So baud rate is CCB/(16*divider) +*/ if (serial_hds[0 ]) { -serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (0 ), -0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (0 ),0 , +qdev_get_gpio_in (ccsr->pic,16 +26 ), + ccsr->ccb_freq /16u , serial_hds[0 ],DEVICE_BIG_ENDIAN ); }if (serial_hds[1 ]) { -serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (1 ), -0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (1 ),0 , +qdev_get_gpio_in (ccsr->pic,16 +26 ), + ccsr->ccb_freq /16u , serial_hds[1 ],DEVICE_BIG_ENDIAN ); }
@@ -290,6 +297,7 @@ static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("base" , CCSRState, defbase,0xff700000 ),DEFINE_PROP_UINT32 ("ram-size" , CCSRState, ram_size,0 ),DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ), +DEFINE_PROP_UINT32 ("ccb-freq" , CCSRState, ccb_freq,333333333u ),/* "mpic-model" aliased from MPIC */ DEFINE_PROP_END_OF_LIST() };
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock
Quoted 42 lines · Michael Davidsaver
The CCB (Complex Core Bus) clock is the reference for the DUARTs with an extra divide by 16.
Quoted 1 line
From the mpc8540, mpc8544, and P2010 ref manuals.
CCB=333MHz, with divider=0x87a gives ~9600 baud.
333e6 Hz/(16*0x87a) = 9591 Hz.
This is verified with a real mpc8540.The existing value for the mpc8544ds boards is replaced. Previously the uart "clock-frequency" device tree node was left as zero, and at some point either u-boot or Linux picks a value inconsistent with the frequency given to
serial_mm_init().
The FIFO timeout calculated from this was incorrect.Now use an arbitrary (valid) CCB frequency of 333MHz in the device tree and for the UART.
Signed-off-by Michael Davidsaver <[email protected]>--- hw/ppc/e500.c | 9 ++++++++- hw/ppc/e500_ccsr.c | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-)hw/ppc/e500.c +6
-0@@ -49,6 +49,12 @@#define RAM_SIZES_ALIGN (64UL << 20) +/* Somewhat arbitrarily choosen Complex Core Bus frequency +* for our simulation (real freq of mpc8544ds board unknown) +* Used in baud rate calculations. +*/ +#define CCB_FREQ (333333333) +/* TODO: parameterize * Some CCSR offsets duplicated in e500_ccsr.c */
hw/ppc/e500.c static void dt_serial_create(void *fdt, unsigned long long offset, · line 122
Quoted 5 lines
hw/ppc/e500.c +1
-1@@ -113,7 +119,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,qemu_fdt_setprop_string (fdt, ser,"compatible" ,"ns16550" );qemu_fdt_setprop_cells (fdt, ser,"reg" , offset,0x100 );qemu_fdt_setprop_cell (fdt, ser,"cell-index" , idx); -qemu_fdt_setprop_cell (fdt, ser,"clock-frequency" ,0 ); +qemu_fdt_setprop_cell (fdt, ser,"clock-frequency" ,CCB_FREQ );
Shouldn't this come off the property value, not the constant?
Quoted 50 lines
hw/ppc/e500.c +1
-0qemu_fdt_setprop_cells (fdt, ser,"interrupts" ,42 ,2 );qemu_fdt_setprop_phandle (fdt, ser,"interrupt-parent" , mpic);qemu_fdt_setprop_string (fdt,"/aliases" , alias, ser);@@ -759,6 +765,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) dev =qdev_create (NULL ,"e500-ccsr" );object_property_add_child (qdev_get_machine (),"e500-ccsr" ,OBJECT (dev),NULL ); +qdev_prop_set_uint32 (dev,"ccb-freq" ,CCB_FREQ );qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size);hw/ppc/e500_ccsr.c +11
-4@@ -69,6 +69,7 @@ typedef struct {uint32_t merrd;uint32_t porpllsr; +uint32_t ccb_freq;DeviceState *pic; } CCSRState;@@ -272,15 +273,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp)/* Note: MPIC internal interrupts are offset by 16 */ /* DUARTS */ +/* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock +* is the CCB clock divided by 16. +* So baud rate is CCB/(16*divider) +*/ if (serial_hds[0 ]) { -serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (0 ), -0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (0 ),0 , +qdev_get_gpio_in (ccsr->pic,16 +26 ), + ccsr->ccb_freq /16u , serial_hds[0 ],DEVICE_BIG_ENDIAN ); }if (serial_hds[1 ]) { -serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (1 ), -0 ,qdev_get_gpio_in (ccsr->pic,16 +26 ),399193 , +serial_mm_init (&ccsr->iomem,E500_DUART_OFFSET (1 ),0 , +qdev_get_gpio_in (ccsr->pic,16 +26 ), + ccsr->ccb_freq /16u , serial_hds[1 ],DEVICE_BIG_ENDIAN ); }
hw/ppc/e500_ccsr.c static Property e500_ccsr_props[] = { · line 301
Quoted 5 lines
hw/ppc/e500_ccsr.c +1
-0@@ -290,6 +297,7 @@ static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("base" , CCSRState, defbase,0xff700000 ),DEFINE_PROP_UINT32 ("ram-size" , CCSRState, ram_size,0 ),DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ), +DEFINE_PROP_UINT32 ("ccb-freq" , CCSRState, ccb_freq, 333333333u),
And shouldn't this use the #define as the default value?
Quoted 3 lines
hw/ppc/e500_ccsr.c +0
-0/* "mpic-model" aliased from MPIC */ DEFINE_PROP_END_OF_LIST ()};
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 12/17 e500: add i2c controller to CCSR
In reply to Michael DavidsaverAdd i2c controller found on mpc8540,
mpc8544, and P2010 (newer ppc, unmodeled).
--- hw/ppc/e500_ccsr.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
hw/ppc/e500_ccsr.c +15 -0
@@ -46,6 +46,8 @@#define E500_ERR_DETECT (0x2e40)#define E500_ERR_DISABLE (0x2e44) +#define E500_I2C_OFFSET (0x3000) +#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100)#define E500_PORPLLSR (0xE0000)
@@ -72,6 +74,7 @@ typedef struct {uint32_t ccb_freq;DeviceState *pic; +DeviceState *i2c; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"
@@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(pic, 0));/* Note: MPIC internal interrupts are offset by 16 */ +/* attach I2C controller */ + ccsr->i2c =qdev_create (NULL ,"mpc8540-i2c" ); +object_property_add_child (qdev_get_machine (),"i2c[*]" , +OBJECT (ccsr->i2c),NULL ); +qdev_init_nofail (ccsr->i2c); +memory_region_add_subregion (&ccsr->iomem,E500_I2C_OFFSET , +sysbus_mmio_get_region ( +SYS_BUS_DEVICE (ccsr->i2c),0 )); +sysbus_connect_irq (SYS_BUS_DEVICE (ccsr->i2c),0 , +qdev_get_gpio_in (ccsr->pic,16 +27 )); + +/* DUARTS */ /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock * is the CCB clock divided by 16.
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR
Quoted 2 lines · Michael Davidsaver
Add i2c controller found on mpc8540,
mpc8544, and P2010 (newer ppc, unmodeled).
This adds it unconditionally. Are there any E500 models where it doesn't exist?
Quoted 28 lines
Signed-off-by Michael Davidsaver <[email protected]>--- hw/ppc/e500_ccsr.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)hw/ppc/e500_ccsr.c +3
-0@@ -46,6 +46,8 @@#define E500_ERR_DETECT (0x2e40)#define E500_ERR_DISABLE (0x2e44) +#define E500_I2C_OFFSET (0x3000) +#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100)#define E500_PORPLLSR (0xE0000)@@ -72,6 +74,7 @@ typedef struct {uint32_t ccb_freq;DeviceState *pic; +DeviceState *i2c; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"
hw/ppc/e500_ccsr.c static void e500_ccsr_realize(DeviceState *dev, Error **errp) · line 279
Quoted 5 lines
hw/ppc/e500_ccsr.c +2
-0@@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(pic, 0));/* Note: MPIC internal interrupts are offset by 16 */ +/* attach I2C controller */ + ccsr->i2c =qdev_create (NULL ,"mpc8540-i2c" );
Ah.. so I think I missed this on many earlier patches. I believe you're not generally supposed to create new subdevices at realize() time. Instead the device should be created at CCSR instance_init() time (but the sub device's "realized" property will need to be set to 1 from CCSR realize()).
Quoted 13 lines
hw/ppc/e500_ccsr.c +10
-0+object_property_add_child (qdev_get_machine (),"i2c[*]" , +OBJECT (ccsr->i2c),NULL ); +qdev_init_nofail (ccsr->i2c); +memory_region_add_subregion (&ccsr->iomem,E500_I2C_OFFSET , +sysbus_mmio_get_region ( +SYS_BUS_DEVICE (ccsr->i2c),0 )); +sysbus_connect_irq (SYS_BUS_DEVICE (ccsr->i2c),0 , +qdev_get_gpio_in (ccsr->pic,16 +27 )); + +/* DUARTS */ /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock * is the CCB clock divided by 16.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR
Quoted 6 lines · David Gibson
Quoted 2 lines · Michael Davidsaver
Add i2c controller found on mpc8540,
mpc8544, and P2010 (newer ppc, unmodeled).This adds it unconditionally. Are there any E500 models where it doesn't exist?
Not in the devices I've looked at, though I certainly haven't looked at them all. In fact the mpc8544 has two i2c controllers.
I keep mentioning the P2010 as it is about a decade
newer than the mpc85xx chips. My _assumption_ is that the commonalities between these are a reasonable least common denominator.
Quoted 54 lines
Quoted 28 lines
Signed-off-by Michael Davidsaver <[email protected]>--- hw/ppc/e500_ccsr.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)hw/ppc/e500_ccsr.c +3
-0@@ -46,6 +46,8 @@#define E500_ERR_DETECT (0x2e40)#define E500_ERR_DISABLE (0x2e44) +#define E500_I2C_OFFSET (0x3000) +#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100)#define E500_PORPLLSR (0xE0000)@@ -72,6 +74,7 @@ typedef struct {uint32_t ccb_freq;DeviceState *pic; +DeviceState *i2c; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"hw/ppc/e500_ccsr.c static void e500_ccsr_realize(DeviceState *dev, Error **errp) · line 279
Quoted 5 lines
hw/ppc/e500_ccsr.c +2
-0@@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(pic, 0));/* Note: MPIC internal interrupts are offset by 16 */ +/* attach I2C controller */ + ccsr->i2c =qdev_create (NULL ,"mpc8540-i2c" );Ah.. so I think I missed this on many earlier patches. I believe you're not generally supposed to create new subdevices at
realize()time. Instead the device should be created at CCSRinstance_init()time (but the sub device's "realized" property will need to be set to 1 from CCSRrealize()).Quoted 13 lines
hw/ppc/e500_ccsr.c +10
-0+object_property_add_child (qdev_get_machine (),"i2c[*]" , +OBJECT (ccsr->i2c),NULL ); +qdev_init_nofail (ccsr->i2c); +memory_region_add_subregion (&ccsr->iomem,E500_I2C_OFFSET , +sysbus_mmio_get_region ( +SYS_BUS_DEVICE (ccsr->i2c),0 )); +sysbus_connect_irq (SYS_BUS_DEVICE (ccsr->i2c),0 , +qdev_get_gpio_in (ccsr->pic,16 +27 )); + +/* DUARTS */ /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock * is the CCB clock divided by 16.
PATCH 13/17 e500: move PCI host bridge into CCSR
In reply to Michael Davidsaver--- hw/ppc/e500.c | 13 ++++--------- hw/ppc/e500_ccsr.c | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-)
hw/ppc/e500.c +4 -9
@@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size); +qdev_prop_set_uint32 (dev,"pci_first_slot" , params->pci_first_slot); +qdev_prop_set_uint32 (dev,"pci_first_pin_irq" , pci_irq_nrs[0 ]);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 );
@@ -778,20 +780,13 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)/* PCI */ - dev =qdev_create (NULL ,"e500-pcihost" ); -object_property_add_child (qdev_get_machine (),"pci-host" ,OBJECT (dev), - &error_abort); -qdev_prop_set_uint32 (dev,"first_slot" , params->pci_first_slot); -qdev_prop_set_uint32 (dev,"first_pin_irq" , pci_irq_nrs[0 ]); -qdev_init_nofail (dev); + dev =DEVICE (object_resolve_path ("/machine/pci-host" ,0 )); +assert (dev); s =SYS_BUS_DEVICE (dev);for (i =0 ; i <PCI_NUM_PINS ; i++) {sysbus_connect_irq (s, i,qdev_get_gpio_in (mpicdev, pci_irq_nrs[i])); } -memory_region_add_subregion (ccsr_addr_space,MPC8544_PCI_REGS_OFFSET , -sysbus_mmio_get_region (s,0 )); - pci_bus = (PCIBus *)qdev_get_child_bus (dev,"pci.0" );if (!pci_bus)printf ("couldn't create PCI controller!\n" );
hw/ppc/e500_ccsr.c +27 -0
@@ -50,6 +50,8 @@#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100) +#define E500_PCI_OFFSET (0x8000ULL) +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)
@@ -75,6 +77,7 @@ typedef struct {DeviceState *pic;DeviceState *i2c; +DeviceState *pcihost; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"
@@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)DeviceState *dev =DEVICE (obj);CCSRState *ccsr =E500_CCSR (dev); +/* prepare MPIC */ assert (current_machine);if (kvm_enabled ()) {
@@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)object_property_add_alias (obj,"mpic-model" ,OBJECT (ccsr->pic),"model" , &error_fatal); + +/* prepare PCI host bridge */ + ccsr->pcihost =qdev_create (NULL ,"e500-pcihost" ); +object_property_add_child (qdev_get_machine (),"pci-host" ,OBJECT (ccsr->pcihost), + &error_abort); + +object_property_add_alias (obj,"pci_first_slot" , +OBJECT (ccsr->pcihost),"first_slot" , + &error_fatal); +object_property_add_alias (obj,"pci_first_pin_irq" , +OBJECT (ccsr->pcihost),"first_pin_irq" , + &error_fatal); }static void e500_ccsr_realize (DeviceState *dev,Error **errp)
@@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) ccsr, "e500-ccsr", 1024 * 1024);sysbus_init_mmio (SYS_BUS_DEVICE (dev), &ccsr->iomem); +/* realize MPIC */ qdev_init_nofail (ccsr->pic); pic =SYS_BUS_DEVICE (ccsr->pic);
@@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(pic, 0));/* Note: MPIC internal interrupts are offset by 16 */ +/* realize PCI host bridge*/ +qdev_init_nofail (ccsr->pcihost); + +memory_region_add_subregion (&ccsr->iomem,E500_PCI_OFFSET , +sysbus_mmio_get_region ( +SYS_BUS_DEVICE (ccsr->pcihost),0 )); +/* attach I2C controller */ ccsr->i2c =qdev_create (NULL ,"mpc8540-i2c" ); object_property_add_child(qdev_get_machine(), "i2c[*]",
@@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ),DEFINE_PROP_UINT32 ("ccb-freq" , CCSRState, ccb_freq,333333333u ),/* "mpic-model" aliased from MPIC */ +/* "pci_first_slot" +* "pci_first_pin_irq" aliased from PCI host bridge +*/ DEFINE_PROP_END_OF_LIST() };
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
Quoted 1 line · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>
Hmm. Is there anything you're *not* planning to move under the CCSR. If not, I'm really wondering if the CCSR ought to be a device in its own right, rather than just a container memory region used within the machine.
Quoted 121 lines
--- hw/ppc/e500.c | 13 ++++--------- hw/ppc/e500_ccsr.c | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-)hw/ppc/e500.c +4
-9@@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size); +qdev_prop_set_uint32 (dev,"pci_first_slot" , params->pci_first_slot); +qdev_prop_set_uint32 (dev,"pci_first_pin_irq" , pci_irq_nrs[0 ]);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 );@@ -778,20 +780,13 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)/* PCI */ - dev =qdev_create (NULL ,"e500-pcihost" ); -object_property_add_child (qdev_get_machine (),"pci-host" ,OBJECT (dev), - &error_abort); -qdev_prop_set_uint32 (dev,"first_slot" , params->pci_first_slot); -qdev_prop_set_uint32 (dev,"first_pin_irq" , pci_irq_nrs[0 ]); -qdev_init_nofail (dev); + dev =DEVICE (object_resolve_path ("/machine/pci-host" ,0 )); +assert (dev); s =SYS_BUS_DEVICE (dev);for (i =0 ; i <PCI_NUM_PINS ; i++) {sysbus_connect_irq (s, i,qdev_get_gpio_in (mpicdev, pci_irq_nrs[i])); } -memory_region_add_subregion (ccsr_addr_space,MPC8544_PCI_REGS_OFFSET , -sysbus_mmio_get_region (s,0 )); - pci_bus = (PCIBus *)qdev_get_child_bus (dev,"pci.0" );if (!pci_bus)printf ("couldn't create PCI controller!\n" );hw/ppc/e500_ccsr.c +27
-0@@ -50,6 +50,8 @@#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100) +#define E500_PCI_OFFSET (0x8000ULL) +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)@@ -75,6 +77,7 @@ typedef struct {DeviceState *pic;DeviceState *i2c; +DeviceState *pcihost; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"@@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)DeviceState *dev =DEVICE (obj);CCSRState *ccsr =E500_CCSR (dev); +/* prepare MPIC */ assert (current_machine);if (kvm_enabled ()) {@@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)object_property_add_alias (obj,"mpic-model" ,OBJECT (ccsr->pic),"model" , &error_fatal); + +/* prepare PCI host bridge */ + ccsr->pcihost =qdev_create (NULL ,"e500-pcihost" ); +object_property_add_child (qdev_get_machine (),"pci-host" ,OBJECT (ccsr->pcihost), + &error_abort); + +object_property_add_alias (obj,"pci_first_slot" , +OBJECT (ccsr->pcihost),"first_slot" , + &error_fatal); +object_property_add_alias (obj,"pci_first_pin_irq" , +OBJECT (ccsr->pcihost),"first_pin_irq" , + &error_fatal); }static void e500_ccsr_realize (DeviceState *dev,Error **errp)@@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) ccsr, "e500-ccsr", 1024 * 1024);sysbus_init_mmio (SYS_BUS_DEVICE (dev), &ccsr->iomem); +/* realize MPIC */ qdev_init_nofail (ccsr->pic); pic =SYS_BUS_DEVICE (ccsr->pic);@@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(pic, 0));/* Note: MPIC internal interrupts are offset by 16 */ +/* realize PCI host bridge*/ +qdev_init_nofail (ccsr->pcihost); + +memory_region_add_subregion (&ccsr->iomem,E500_PCI_OFFSET , +sysbus_mmio_get_region ( +SYS_BUS_DEVICE (ccsr->pcihost),0 )); +/* attach I2C controller */ ccsr->i2c =qdev_create (NULL ,"mpc8540-i2c" ); object_property_add_child(qdev_get_machine(), "i2c[*]",@@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ),DEFINE_PROP_UINT32 ("ccb-freq" , CCSRState, ccb_freq,333333333u ),/* "mpic-model" aliased from MPIC */ +/* "pci_first_slot" +* "pci_first_pin_irq" aliased from PCI host bridge +*/ DEFINE_PROP_END_OF_LIST() };
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
Quoted 4 lines · David Gibson
Quoted 1 line · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>Hmm. Is there anything you're *not* planning to move under the CCSR.
Well, the decrementer/timebase initialization for one as this has nothing to do with the CCSR registers.
I haven't added the TSEC/eTSEC instances either.
Partly this is because the existing boards, for reasons I don't understand, use virtio NICs.
Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544 has instances 1 and 3. So I decided to leave NIC setup to the Machine rather then add the extra code to parameterize this under the CCSR device.
Quoted 3 lines
If not, I'm really wondering if the CCSR ought to be a device in its own right, rather than just a container memory region used within the machine.
I don't think I follow what you mean by "device" in this context? The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr"). What device-like characteristics could it have?
Quoted 122 lines
Quoted 121 lines
--- hw/ppc/e500.c | 13 ++++--------- hw/ppc/e500_ccsr.c | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-)hw/ppc/e500.c +4
-9@@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)qdev_prop_set_uint32 (dev,"mpic-model" , params->mpic_version);qdev_prop_set_uint32 (dev,"base" , params->ccsrbar_base);qdev_prop_set_uint32 (dev,"ram-size" , ram_size); +qdev_prop_set_uint32 (dev,"pci_first_slot" , params->pci_first_slot); +qdev_prop_set_uint32 (dev,"pci_first_pin_irq" , pci_irq_nrs[0 ]);qdev_init_nofail (dev); ccsr_addr_space =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 );@@ -778,20 +780,13 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)/* PCI */ - dev =qdev_create (NULL ,"e500-pcihost" ); -object_property_add_child (qdev_get_machine (),"pci-host" ,OBJECT (dev), - &error_abort); -qdev_prop_set_uint32 (dev,"first_slot" , params->pci_first_slot); -qdev_prop_set_uint32 (dev,"first_pin_irq" , pci_irq_nrs[0 ]); -qdev_init_nofail (dev); + dev =DEVICE (object_resolve_path ("/machine/pci-host" ,0 )); +assert (dev); s =SYS_BUS_DEVICE (dev);for (i =0 ; i <PCI_NUM_PINS ; i++) {sysbus_connect_irq (s, i,qdev_get_gpio_in (mpicdev, pci_irq_nrs[i])); } -memory_region_add_subregion (ccsr_addr_space,MPC8544_PCI_REGS_OFFSET , -sysbus_mmio_get_region (s,0 )); - pci_bus = (PCIBus *)qdev_get_child_bus (dev,"pci.0" );if (!pci_bus)printf ("couldn't create PCI controller!\n" );hw/ppc/e500_ccsr.c +27
-0@@ -50,6 +50,8 @@#define E500_DUART_OFFSET (N ) (0x4500 + (N) * 0x100) +#define E500_PCI_OFFSET (0x8000ULL) +#define E500_PORPLLSR (0xE0000)#define E500_PVR (0xE00A0)#define E500_SVR (0xE00A4)@@ -75,6 +77,7 @@ typedef struct {DeviceState *pic;DeviceState *i2c; +DeviceState *pcihost; } CCSRState;#define TYPE_E500_CCSR "e500-ccsr"@@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)DeviceState *dev =DEVICE (obj);CCSRState *ccsr =E500_CCSR (dev); +/* prepare MPIC */ assert (current_machine);if (kvm_enabled ()) {@@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)object_property_add_alias (obj,"mpic-model" ,OBJECT (ccsr->pic),"model" , &error_fatal); + +/* prepare PCI host bridge */ + ccsr->pcihost =qdev_create (NULL ,"e500-pcihost" ); +object_property_add_child (qdev_get_machine (),"pci-host" ,OBJECT (ccsr->pcihost), + &error_abort); + +object_property_add_alias (obj,"pci_first_slot" , +OBJECT (ccsr->pcihost),"first_slot" , + &error_fatal); +object_property_add_alias (obj,"pci_first_pin_irq" , +OBJECT (ccsr->pcihost),"first_pin_irq" , + &error_fatal); }static void e500_ccsr_realize (DeviceState *dev,Error **errp)@@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) ccsr, "e500-ccsr", 1024 * 1024);sysbus_init_mmio (SYS_BUS_DEVICE (dev), &ccsr->iomem); +/* realize MPIC */ qdev_init_nofail (ccsr->pic); pic =SYS_BUS_DEVICE (ccsr->pic);@@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(pic, 0));/* Note: MPIC internal interrupts are offset by 16 */ +/* realize PCI host bridge*/ +qdev_init_nofail (ccsr->pcihost); + +memory_region_add_subregion (&ccsr->iomem,E500_PCI_OFFSET , +sysbus_mmio_get_region ( +SYS_BUS_DEVICE (ccsr->pcihost),0 )); +/* attach I2C controller */ ccsr->i2c =qdev_create (NULL ,"mpc8540-i2c" ); object_property_add_child(qdev_get_machine(), "i2c[*]",@@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {DEFINE_PROP_UINT32 ("porpllsr" , CCSRState, porpllsr,0 ),DEFINE_PROP_UINT32 ("ccb-freq" , CCSRState, ccb_freq,333333333u ),/* "mpic-model" aliased from MPIC */ +/* "pci_first_slot" +* "pci_first_pin_irq" aliased from PCI host bridge +*/ DEFINE_PROP_END_OF_LIST() };
Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
Quoted 8 lines · Michael Davidsaver
Quoted 4 lines · David Gibson
Quoted 1 line · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>Hmm. Is there anything you're *not* planning to move under the CCSR.
Well, the decrementer/timebase initialization for one as this has nothing to do with the CCSR registers.
Right, but no actual devices, even small ones?
Quoted 8 lines
I haven't added the TSEC/eTSEC instances either.
Partly this is because the existing boards, for reasons I don't understand, use virtio NICs.Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544 has instances 1 and 3. So I decided to leave NIC setup to the Machine rather then add the extra code to parameterize this under the CCSR device.
Quoted 7 lines
Quoted 3 lines
If not, I'm really wondering if the CCSR ought to be a device in its own right, rather than just a container memory region used within the machine.
I don't think I follow what you mean by "device" in this context? The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr"). What device-like characteristics could it have?
Sorry, I wasn't clear. the CCSR definitely *is* a device in the current scheme, but I'm wondering if that was a good idea.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR
Quoted 11 lines · David Gibson
Quoted 8 lines · Michael Davidsaver
Quoted 4 lines · David Gibson
Quoted 1 line · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>Hmm. Is there anything you're *not* planning to move under the CCSR.
Well, the decrementer/timebase initialization for one as this has nothing to do with the CCSR registers.
Right, but no actual devices, even small ones?
Well, there is the GPIO controller ("mpc8xxx_gpio") as I have frankly have no idea where it comes from. Neither MPC8540 nor 8544 define anything at CCSR offset 0xFF000. The registers modeled differ from the GPIO controller which is defined at 0xE0030.
So I'm considering this to be specific to the existing boards.
Quoted 12 lines
Quoted 12 lines
I haven't added the TSEC/eTSEC instances either.
Partly this is because the existing boards, for reasons I don't understand, use virtio NICs.Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544 has instances 1 and 3. So I decided to leave NIC setup to the Machine rather then add the extra code to parameterize this under the CCSR device.
Quoted 3 lines
If not, I'm really wondering if the CCSR ought to be a device in its own right, rather than just a container memory region used within the machine.
Quoted 6 lines
Quoted 3 lines
I don't think I follow what you mean by "device" in this context? The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr"). What device-like characteristics could it have?
Sorry, I wasn't clear. the CCSR definitely *is* a device in the current scheme, but I'm wondering if that was a good idea.
I think I see what you're getting at. You're right that CCSR isn't a "device" in the same sense as eg. a UART. In my mind it's more like a PCI host bridge, having a few registers itself, though serving mainly to route to the devices behind it.
I see the CCSR "device" as the bridge onto the system bus. In some ways it might be considered to be the only device on the system bus apart from the CPU(s). This "device" handles first level routing of physical addresses to RAM, PCI, or local bus via the LAWBAR* registers (unmodeled). Or to the I/O devices in the CCSR range via CCSRBAR.
I don't have plans to model that LAWBAR* registers, as it hasn't proved necessary for RTEMS or Linux guests. I have considered how this could be done as Linux does touch these registers, but doesn't readback/check the values it has written. I think having a CCSR "device" would make it simpler to model the local windows should this become desirable. eg. if Linux starts validating LAWBAR* or to run unmodified u-boot.
PATCH 14/17 e500: split mpc8544ds specific initialization
In reply to Michael Davidsaversplit off the remaining board specific parts of e500_init() as mpc85xx_init() which will be used by the existing mpc8544ds and generic e500 boards.
--- hw/ppc/e500.c | 49 ++++++++++++++++++++++++++++++++----------------- hw/ppc/e500.h | 3 ++- hw/ppc/e500plat.c | 2 +- hw/ppc/mpc8544ds.c | 2 +- 4 files changed, 36 insertions(+), 20 deletions(-)
hw/ppc/e500.c +32 -17
@@ -690,7 +690,32 @@ static void ppce500_power_off(void *opaque, int line, int on) } } -void ppce500_init (MachineState *machine,PPCE500Params *params) + +void ppce500_init (MachineState *machine,uint32_t decrementer_freq) +{ +int i; +for (i =0 ; i < smp_cpus; i++) { +PowerPCCPU *cpu; +CPUState *cs; +CPUPPCState *env; + + cpu =POWERPC_CPU (cpu_create (machine->cpu_type)); + env = &cpu->env; + cs =CPU (cpu); + +if (env->mmu_model !=POWERPC_MMU_BOOKE206 ) { +error_report ("MMU model %i not supported by this machine." , + env->mmu_model); +exit (1 ); + } + + env->spr_cb[SPR_BOOKE_PIR ].default_value = cs->cpu_index = i; + +ppc_booke_timers_init (cpu, decrementer_freq,PPC_TIMER_E500 ); + } +} + +void mpc85xx_init (MachineState *machine,PPCE500Params *params) {MemoryRegion *address_space_mem =get_system_memory ();MemoryRegion *ram =g_new (MemoryRegion,1 );
@@ -716,31 +741,21 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)CPUPPCState *firstenv =NULL ;MemoryRegion *ccsr_addr_space;SysBusDevice *s; +CPUState *cs; -for (i =0 ; i < smp_cpus; i++) { +ppce500_init (machine,400000000 ); + +CPU_FOREACH (cs) {PowerPCCPU *cpu; -CPUState *cs; - cpu =POWERPC_CPU (cpu_create (machine->cpu_type)); + cpu =POWERPC_CPU (cs); env = &cpu->env; - cs =CPU (cpu); -if (env->mmu_model !=POWERPC_MMU_BOOKE206 ) { -fprintf (stderr,"MMU model %i not supported by this machine.\n" , - env->mmu_model); -exit (1 ); - } +/* Register reset handler */ if (!firstenv) { firstenv = env; - } - env->spr_cb[SPR_BOOKE_PIR ].default_value = cs->cpu_index = i; - -ppc_booke_timers_init (cpu,400000000 ,PPC_TIMER_E500 ); - -/* Register reset handler */ -if (!i) {/* Primary CPU */ struct boot_info *boot_info; boot_info =g_malloc0 (sizeof (struct boot_info ));
hw/ppc/e500.h +2 -1
@@ -24,7 +24,8 @@ typedef struct PPCE500Params {hwaddr spin_base; } PPCE500Params; -void ppce500_init (MachineState *machine,PPCE500Params *params); +void ppce500_init (MachineState *machine,uint32_t decrementer_freq); +void mpc85xx_init (MachineState *machine,PPCE500Params *params);hwaddr booke206_page_size_to_tlb (uint64_t size);
hw/ppc/e500plat.c +1 -1
@@ -55,7 +55,7 @@ static void e500plat_init(MachineState *machine) params.mpic_version =OPENPIC_MODEL_FSL_MPIC_20 ; } -ppce500_init (machine, ¶ms); +mpc85xx_init (machine, ¶ms); }static void e500plat_machine_init (MachineClass *mc)
hw/ppc/mpc8544ds.c +1 -1
@@ -47,7 +47,7 @@ static void mpc8544ds_init(MachineState *machine)exit (1 ); } -ppce500_init (machine, ¶ms); +mpc85xx_init (machine, ¶ms); }
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization
Quoted 6 lines · Michael Davidsaver
split off the remaining board specific parts of
e500_init()asmpc85xx_init()which will be used by the existing mpc8544ds and generic e500 boards.Signed-off-by Michael Davidsaver <[email protected]>
Looks good, but will need a rebase.
Quoted 123 lines
--- hw/ppc/e500.c | 49 ++++++++++++++++++++++++++++++++----------------- hw/ppc/e500.h | 3 ++- hw/ppc/e500plat.c | 2 +- hw/ppc/mpc8544ds.c | 2 +- 4 files changed, 36 insertions(+), 20 deletions(-)hw/ppc/e500.c +32
-17@@ -690,7 +690,32 @@ static void ppce500_power_off(void *opaque, int line, int on) } } -void ppce500_init (MachineState *machine,PPCE500Params *params) + +void ppce500_init (MachineState *machine,uint32_t decrementer_freq) +{ +int i; +for (i =0 ; i < smp_cpus; i++) { +PowerPCCPU *cpu; +CPUState *cs; +CPUPPCState *env; + + cpu =POWERPC_CPU (cpu_create (machine->cpu_type)); + env = &cpu->env; + cs =CPU (cpu); + +if (env->mmu_model !=POWERPC_MMU_BOOKE206 ) { +error_report ("MMU model %i not supported by this machine." , + env->mmu_model); +exit (1 ); + } + + env->spr_cb[SPR_BOOKE_PIR ].default_value = cs->cpu_index = i; + +ppc_booke_timers_init (cpu, decrementer_freq,PPC_TIMER_E500 ); + } +} + +void mpc85xx_init (MachineState *machine,PPCE500Params *params) {MemoryRegion *address_space_mem =get_system_memory ();MemoryRegion *ram =g_new (MemoryRegion,1 );@@ -716,31 +741,21 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)CPUPPCState *firstenv =NULL ;MemoryRegion *ccsr_addr_space;SysBusDevice *s; +CPUState *cs; -for (i =0 ; i < smp_cpus; i++) { +ppce500_init (machine,400000000 ); + +CPU_FOREACH (cs) {PowerPCCPU *cpu; -CPUState *cs; - cpu =POWERPC_CPU (cpu_create (machine->cpu_type)); + cpu =POWERPC_CPU (cs); env = &cpu->env; - cs =CPU (cpu); -if (env->mmu_model !=POWERPC_MMU_BOOKE206 ) { -fprintf (stderr,"MMU model %i not supported by this machine.\n" , - env->mmu_model); -exit (1 ); - } +/* Register reset handler */ if (!firstenv) { firstenv = env; - } - env->spr_cb[SPR_BOOKE_PIR ].default_value = cs->cpu_index = i; - -ppc_booke_timers_init (cpu,400000000 ,PPC_TIMER_E500 ); - -/* Register reset handler */ -if (!i) {/* Primary CPU */ struct boot_info *boot_info; boot_info =g_malloc0 (sizeof (struct boot_info ));hw/ppc/e500.h +2
-1@@ -24,7 +24,8 @@ typedef struct PPCE500Params {hwaddr spin_base; } PPCE500Params; -void ppce500_init (MachineState *machine,PPCE500Params *params); +void ppce500_init (MachineState *machine,uint32_t decrementer_freq); +void mpc85xx_init (MachineState *machine,PPCE500Params *params);hwaddr booke206_page_size_to_tlb (uint64_t size);hw/ppc/e500plat.c +1
-1@@ -55,7 +55,7 @@ static void e500plat_init(MachineState *machine) params.mpic_version =OPENPIC_MODEL_FSL_MPIC_20 ; } -ppce500_init (machine, ¶ms); +mpc85xx_init (machine, ¶ms); }static void e500plat_machine_init (MachineClass *mc)hw/ppc/mpc8544ds.c +1
-1@@ -47,7 +47,7 @@ static void mpc8544ds_init(MachineState *machine)exit (1 ); } -ppce500_init (machine, ¶ms); +mpc85xx_init (machine, ¶ms); }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 15/17 ppc: add mvme3100 machine
In reply to Michael Davidsaver--- default-configs/ppc-softmmu.mak | 1 + hw/ppc/Makefile.objs | 1 + hw/ppc/mvme3100.c | 740 ++++++++++++++++++++++++++++++++++++++++ hw/ppc/mvme3100_cpld.c | 192 +++++++++++ 4 files changed, 934 insertions(+) create mode 100644 hw/ppc/mvme3100.c create mode 100644 hw/ppc/mvme3100_cpld.c
default-configs/ppc-softmmu.mak +1 -0
@@ -52,3 +52,4 @@ CONFIG_SERIAL_ISA=y CONFIG_MC146818RTC=y CONFIG_ISA_TESTDEV=y CONFIG_RS6000_MC=y +CONFIG_DSRTCI2C=y
hw/ppc/Makefile.objs +1 -0
@@ -26,5 +26,6 @@ obj-$(CONFIG_MAC) += mac_newworld.o obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o obj-$(CONFIG_E500) += ppce500_spin.o obj-$(CONFIG_E500) += e500_ccsr.o +obj-$(CONFIG_E500) += mvme3100.o mvme3100_cpld.o # PowerPC 440 Xilinx ML507 reference board. obj-$(CONFIG_XILINX) += virtex_ml507.o
hw/ppc/mvme3100.c new file +740 -0
740 lines not on this page · raw message
hw/ppc/mvme3100_cpld.c new file +192 -0
192 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine
Quoted 134 lines · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>--- default-configs/ppc-softmmu.mak | 1 + hw/ppc/Makefile.objs | 1 + hw/ppc/mvme3100.c | 740 ++++++++++++++++++++++++++++++++++++++++ hw/ppc/mvme3100_cpld.c | 192 +++++++++++ 4 files changed, 934 insertions(+) create mode 100644 hw/ppc/mvme3100.c create mode 100644 hw/ppc/mvme3100_cpld.cdefault-configs/ppc-softmmu.mak +1
-0@@ -52,3 +52,4 @@ CONFIG_SERIAL_ISA=y CONFIG_MC146818RTC=y CONFIG_ISA_TESTDEV=y CONFIG_RS6000_MC=y +CONFIG_DSRTCI2C=yhw/ppc/Makefile.objs +1
-0@@ -26,5 +26,6 @@ obj-$(CONFIG_MAC) += mac_newworld.o obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o obj-$(CONFIG_E500) += ppce500_spin.o obj-$(CONFIG_E500) += e500_ccsr.o +obj-$(CONFIG_E500) += mvme3100.o mvme3100_cpld.o # PowerPC 440 Xilinx ML507 reference board. obj-$(CONFIG_XILINX) += virtex_ml507.ohw/ppc/mvme3100.c new file +98
-0@@ -0,0 +1,740 @@ +/* +* MVME3100 board emulation +* +* Copyright (c) 2015 Michael Davidsaver +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +* +* This model was developed according to the +* MVME3100 Single Board Computer Programmer's Reference +* P/N: 6806800G37B +* July 2014 +* +* mvme3100-1152 +* 677MHz core, 256MB ram, 64MB flash +* mvme3100-1263 +* 833MHz core, 512MB ram, 128MB flash +* +* MOTLoad on mvme3100-1152 says: +* MPU-Type =MPC8540 +* MPU-Int Clock Speed =666MHz +* MPU-CCB Clock Speed =333MHz +* MPU-DDR Clock Speed =166MHz +* MPU-PCI Clock Speed =66MHz, PCI, 64-bit +* MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300 +* Reset/Boot Vector =Flash0 +* Local Memory Found =10000000 (&268435456) +* +* MOTLoad on mvme3100-1263 says: +* MPU-Type =MPC8540 +* MPU-Int Clock Speed =833MHz +* MPU-CCB Clock Speed =333MHz +* MPU-DDR Clock Speed =166MHz +* MPU-PCI Clock Speed =66MHz, PCI, 64-bit +* MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300 +* Reset/Boot Vector =Flash0 +* Local Memory Found =20000000 (&536870912) +* +* Clock ratios +* CCB/PCI -> 5/1 +* core/CCB -> 2/1 (-1152) +* -> 5/2 (-1263) +* +* The overall memory map is determined by the Local Address Windows. +* We do not model the LAWs explicitly. +* +* MOTLoad configures as follows (a super set of table 1-4) +* (MOTLoad RTOS Version 2.0, PAL Version 1.2 RM04) +* LAW 0, 7 - disabled +* LAW 1 - 0x00000000 -> 0x7fffffff - RAM 2G +* LAW 2 - 0x80000000 -> 0xbfffffff - PCI 1G +* LAW 3 - 0xc0000000 -> 0xdfffffff - PCI 512MB +* LAW 4 - 0xe0000000 -> 0xe0ffffff - PCI 16MB +* gap - 0xe1000000 -> 0xbfffffff - CCSR @ 0xe1000000 +* LAW 5 - 0xe2000000 -> 0xe2ffffff - LBC 16MB +* gap - 0xe3000000 -> 0xefffffff +* LAW 6 - 0xf0000000 -> 0xffffffff - LBC 256MB +* +* And validated against the RTEMS 4.9.6 mvme3100 BSP +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "e500.h" +#include "cpu.h" +#include "qemu-common.h" +#include "cpu-qom.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" +#include "sysemu/block-backend.h" +#include "hw/loader.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" +#include "hw/ppc/ppc.h" +#include "hw/net/fsl_etsec/etsec.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" +#include "hw/ppc/openpic.h" +#include "qemu/error-report.h" + +/* Same as prep.c and other PPC boards */ +#define CFG_ADDR 0xf0000510 + +#define TYPE_MVME3100 MACHINE_TYPE_NAME("mvme3100") +#define MVME3100 (obj) OBJECT_CHECK(MVME3100State, (obj), TYPE_MVME3100) +#define MVME3100_GET_CLASS (obj) \ + OBJECT_GET_CLASS(MVME3100Class, (obj), TYPE_MVME3100) +#define MVME3100_CLASS (klass) \ + OBJECT_CLASS_CHECK(MVME3100Class, (klass), TYPE_MVME3100) + +#define E500_TSEC_OFFSET (N ) (0x24000 + (N) * 0x1000) + +/* Complex Core Bus frequency */ +#define CCB_FREQ (333333333u) + +typedef struct mvme3100_info { + const char *desc;
hw/ppc/mvme3100.c line 108
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+uint32_t cpu_freq; +uint32_t porpllsr; +uint32_t ram_size; +} mvme3100_info; +typedef struct MVME3100Class { + /*< private >*/ + MachineClass parent_class; + /*< public >*/ + + const mvme3100_info *info;
I'm not seeing a lot of point to having this as a separate structure, rather then embedding the fields directly in the MVME3100Class.
Quoted 12 lines
hw/ppc/mvme3100.c new file +12
-0+} MVME3100Class; + +typedef struct MVME3100State { +/*< private >*/ +MachineState parent_obj; +/*< public >*/ + +uint32_t load_address, + entry_address; + +MemoryRegion ram; +}MVME3100State ;
hw/ppc/mvme3100.c line 131
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+ + +/* motload "global environment" variables */ +static +const char *gev[] = { +/* TODO: somehow snoop in slirp_instances to pick up IP config? */ +"mot-/dev/enet0-cipa=10.0.2.15" , +"mot-/dev/enet0-gipa=10.0.2.2" , +"mot-/dev/enet0-snma=255.255.255.0" , +"mot-/dev/enet0-sipa=10.0.2.2" ,
Right, it does look like these are things that the user might want to configure. I won't insist on that for an initial merge, though.
Quoted 35 lines
hw/ppc/mvme3100.c new file +35
-0+/* RTEMS specific names for things motload doesn't have */ +"rtems-dns-server=10.0.2.3" , +"rtems-client-name=qemu" , + NULL, +}; + +/* Prepare Motorola Vital Product Data eeprom image. +* Provided to bootloader for use as a default. +* +* Begins with constant "MOTLOAD" followed by variable length records +* with a two byte header (ID code then body length in bytes). +* +* | ID | Length | body .... | repeated until ID=0xFF +* +* ID Codes: +* 1 - Product ID (string) +* 2 - Assembly # (string) +* 3 - Serial # (string) +* 5 - CPU Speed (Hz, 4 byte integer + 1 nil) +* 6 - Bus Speed (Hz, 4 byte integer + 1 nil) +* 8 - Ethernet MAC (6 bytes + 1 nil) +* 9 - CPU type +* A - VPD CRC (4 bytes) +* B - Flash Config (??) +* E - L2 Cache Config (??) +* F - VPD Version (4 bytes) +* 19 - L3 Cache Config (??) +* FF - End of VPD (size zero) +* +* Repeat entries for repeated units. eg. two ID=0x8 for two NICs +* +* MOTLoad uses the same eeprom to hold it's user configuration +* Global Environment Variable (GEV) list. +*/ +typedef struct vpdeeprom {
hw/ppc/mvme3100.c line 176
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+char *const base; +char *cur; +size_t total; +} vpdeeprom; + +static +void append_gev_vpd (vpdeeprom *vpd,const char *str) +{ +const size_t remaining = vpd->total - (vpd->cur - vpd->base), + len =strlen (str);
Just repeat the const size_t for the second declaration, it'll be easier to read.
hw/ppc/mvme3100.c line 180
Quoted 4 lines
hw/ppc/mvme3100.c new file +4
-0+ +if ((len ==0 && remaining <1 ) + || (remaining < len +2 )) + {
qemu style puts the { on the same line as the if. Best run your whole set through checkpatch.pl to catch other style errors.
hw/ppc/mvme3100.c line 181
Quoted 1 line
hw/ppc/mvme3100.c new file +1
-0+fprintf (stderr,"VPD GEV overflow\n" );
Use error_report() please. Or even error_setg() and add an Error ** parmaeter to this function (letting the caller decide whether it should be fatal or not).
Quoted 6 lines
hw/ppc/mvme3100.c new file +6
-0+return ; + } + +memcpy (vpd->cur, str, len +1 ); + + vpd->cur += len +1 ;
hw/ppc/mvme3100.c line 197
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+} + +static +void append_vpd (vpdeeprom *vpd,uint8_t id,size_t cnt,const void *val) +{ +const size_t remaining = vpd->total - (vpd->cur - vpd->base); + +/* must have enough space for this entry and final ID=0xff */ +if ((id ==0xff && remaining <2 ) + || (remaining +4 < cnt || cnt >255 ))
Odd bracketing here. || is associative, so the () around the last two clauses looks redundant.
Quoted 49 lines
hw/ppc/mvme3100.c new file +49
-0+ { +fprintf (stderr,"VPD overflow\n" ); +return ; + } + + vpd->cur[0 ] = id; + vpd->cur[1 ] = cnt; +memcpy (vpd->cur +2 , val, cnt); + + vpd->cur +=2 + cnt; +} + +static +void append_string_vpd (vpdeeprom *vpd,uint8_t id,const char *str) +{ +/* include trailing nil */ +append_vpd (vpd, id,strlen (str) +1 , str); +} + +static +void append_mac_vpd (vpdeeprom *vpd,uint8_t id,const MACAddr *addr) +{ +char buf[7 ]; +memcpy (buf, addr->a,6 ); + buf[6 ] =0 ; + +append_vpd (vpd, id,7 , buf); +} + +static +void append_u32_vpd (vpdeeprom *vpd,uint8_t id,uint32_t val) +{ +union { +uint32_t ival; +char bytes[5 ];/* include trailing nil */ + } buf; + buf.ival =cpu_to_be32 (val); + buf.bytes[4 ] =0 ; + +append_vpd (vpd, id,5 , buf.bytes); +} + +static +void build_vpd (const mvme3100_info *info,char *buf,size_t cnt, +const char *extra) +{ +vpdeeprom vpd = {buf, buf, cnt}; +size_t i; +
hw/ppc/mvme3100.c line 256
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+memset (buf,0 , cnt); + +strcpy (buf,"MOTOROLA" ); + vpd.cur +=8 ; + +/* Product ID (eg. "MVME3100-1152") */ +append_string_vpd (&vpd,1 , info->desc); + +/* serial number */ +append_string_vpd (&vpd,3 ,"E0120000" );
Giving a fixed serial number seems a bit bogus. Could you derive this from the qemu instance UUID, maybe?
Quoted 23 lines
hw/ppc/mvme3100.c new file +23
-0+/* CPU Freq. */ +append_u32_vpd (&vpd,5 , info->cpu_freq); + +/* PCI Bus Freq. */ +append_u32_vpd (&vpd,6 ,66666666 ); + +for (i =0 ; i <MAX_NICS ; i++) { +if (nd_table[i].used) { +append_mac_vpd (&vpd,8 , &nd_table[i].macaddr); + } + } + +append_vpd (&vpd,0xff ,0 ,NULL ); + +if (vpd.cur - vpd.base >0x10f8 ) { +fprintf (stderr,"VPD overflows GEV area.\n" ); +return ; + } + +/* MOTLOAD's Global Environment Variables +* start at offset 0x10f8. +* This is a set of nil terminated strings of the form "name=value" +* with a zero length string signaling the end.
hw/ppc/mvme3100.c line 290
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+*/ + vpd.cur = vpd.base +0x10f8 ; + +for (i =0 ; gev[i]; i++) { +append_gev_vpd (&vpd, gev[i]); + } + +if (extra) { +char *E =g_strdup (extra); +char **opts =g_strsplit (E ," " ,0 );
IIRC g_strsplit() is non destructive on the input, so you shouldn't need the E temporary.
Quoted 185 lines
hw/ppc/mvme3100.c new file +185
-0+size_t i; + +g_free (E ); + +for (i =0 ; opts[i]; i++) { +char *opt =g_strstrip (opts[i]); +size_t olen =strlen (opt); + +if (olen ==0 ) { +continue ; + }else if (!strchr (opt,'=' )) { +fprintf (stderr,"Missing '=' in -append %s\n" , extra); +continue ; + } + +append_gev_vpd (&vpd, opt); + } + +g_strfreev (opts); + } + +/* zero length string signals end */ +append_gev_vpd (&vpd,"" ); +} + +static +void set_map (CPUPPCState *env,unsigned way, +target_ulong va,hwaddr pa, +unsigned size) +{ +ppcmas_tlb_t *tlb =booke206_get_tlbm (env,1 ,0 , way); + + tlb->mas1 =MAS1_VALID | (size <<MAS1_TSIZE_SHIFT ); + tlb->mas2 = (va &TARGET_PAGE_MASK ) |MAS2_I |MAS2_G ; + tlb->mas7_3 = (pa &TARGET_PAGE_MASK ) |MAS3_SR |MAS3_SW |MAS3_SX ; +} + +static +void remap_tlb_bare (CPUPPCState *env) +{ +/* The MPC8540 ref. manual says only the upper 4KB (ROM) +* is mapped, but doesn't say exactly how this mapping +* is setup. So we arbitrarily decide to use TLB1 entry 0. +*/ +set_map (env,0 ,0xfffff000 ,0xfffff000 ,0x02 ); + + env->tlb_dirty = true; +} + +static void mvme3100_cpu_reset (void *opaque) +{ +PowerPCCPU *cpu = opaque; +CPUState *cs =CPU (cpu); +CPUPPCState *env = &cpu->env; + +cpu_reset (cs); + +/* HID0 clock control functions not modeled. +* Decrementer always enabled with CCB/8 as reference. +* HID0[EMCP] and HID0[TBEN] set +*/ + env->spr[SPR_HID0 ] |=0x80004000 ; + +remap_tlb_bare (&cpu->env); + env->nip =0xfffffffc ; +} + +static +void mvme3100_pci1_set_irq (void *opaque,int irq_num,int level) +{ +qemu_irq *pic = opaque; + +qemu_set_irq (pic[irq_num], level); +} + +/* PCI config from a real mvme3100 as configured by motload +* +* BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE +* 0:0x00:0 0x1057-0x0008: 0x0006 0x20B0 0x80000000 0x00000000 0 -> 0 (=0x00) +* 0:0x11:0 0x10E3-0x0148: 0x0146 0x02B0 0x80100004 0x00000000 1 -> 0 (=0x00) +* 0:0x12:0 0x10B5-0x6520: 0x0147 0x02B0 0x00000000 0x00000000 0 -> 0 (=0x00) +* 0:0x13:0 0x10B5-0x6520: 0x0147 0x02B0 0x00000000 0x00000000 0 -> 0 (=0x00) +* 0:0x14:0 0x8086-0x3200: 0x0145 0x02B0 0x00012001 0x00013001 1 -> 2 (=0x02) +* 2:0x00:0 0x1033-0x0035: 0x0146 0x0210 0x80300000 0x00000000 1 -> 4 (=0x04) +* 2:0x00:1 0x1033-0x0035: 0x0146 0x0210 0x80301000 0x00000000 2 -> 5 (=0x05) +* +* The modeled PCI host bridge differs. +* +* We model one PCI-PCI bridge (0:0x12:0) but with a different vendor/device +* +* We don't model: +* # The SATA controller GD31244 (0x8086-0x3200) +* # The USB (OHCI) controller uPD740101 (0x1033-0x0035) +* # The second PCI-PCI bridge (0:0x13:0) in front of the USB controllers +* +* (Note that the SATA controller found on newer boards is different) +*/ + +static void mvme3100_init (MachineState *machine) +{ +MVME3100State *mvme3100 =MVME3100 (machine); +const mvme3100_info *info; +DeviceState *dev; +BusState *i2c; +PCIBus *pci0, *pci1; +SysBusDevice *cpld, *pic; +qemu_irq *pci1_pins =g_malloc_n (4 ,sizeof (*pci1_pins)); +FWCfgState *fwinfo; +DriveInfo *drvinfo; +MemoryRegion *ccsr; + + { +MVME3100Class *klass =MVME3100_GET_CLASS (machine); + info = klass->info; + } + +/* Setup CPU */ + +ppce500_init (machine,CCB_FREQ /8u ); + +memory_region_allocate_system_memory (&mvme3100->ram,NULL , +"mvme3100.ram" , ram_size); +memory_region_add_subregion (get_system_memory (),0 , &mvme3100->ram); + +qemu_register_reset (mvme3100_cpu_reset,POWERPC_CPU (first_cpu)); + +/* Create CCSR and builtin periphrials */ + dev =qdev_create (NULL ,"e500-ccsr" ); +object_property_add_child (qdev_get_machine (),"e500-ccsr" , +OBJECT (dev),NULL ); +qdev_prop_set_uint32 (dev,"ccb-freq" ,CCB_FREQ ); +qdev_prop_set_uint32 (dev,"mpic-model" ,OPENPIC_MODEL_FSL_MPIC_20 ); +qdev_prop_set_uint32 (dev,"porpllsr" , info->porpllsr); +qdev_prop_set_uint32 (dev,"base" ,0xff700000ULL ); +qdev_prop_set_uint32 (dev,"ram-size" , ram_size); +qdev_prop_set_uint32 (dev,"pci_first_slot" ,0 ); +qdev_prop_set_uint32 (dev,"pci_first_pin_irq" ,1 ); +qdev_init_nofail (dev); + + ccsr =sysbus_mmio_get_region (SYS_BUS_DEVICE (dev),0 ); + + pic =SYS_BUS_DEVICE (object_resolve_path ("/machine/pic" ,NULL )); + +/* Setup mvme3100 specific CPLD device */ + cpld =SYS_BUS_DEVICE (qdev_create (NULL ,"mvme3100-cpld" )); +object_property_add_child (qdev_get_machine (),"cpld" , +OBJECT (cpld), &error_fatal); +qdev_init_nofail (DEVICE (cpld)); + +memory_region_add_subregion (get_system_memory (), +0xe2000000 , +sysbus_mmio_get_region (cpld,0 )); + + fwinfo =fw_cfg_init_mem (CFG_ADDR ,CFG_ADDR +2 ); +fw_cfg_add_i16 (fwinfo,FW_CFG_NB_CPUS ,1 ); +fw_cfg_add_i16 (fwinfo,FW_CFG_MAX_CPUS ,1 ); +fw_cfg_add_i64 (fwinfo,FW_CFG_RAM_SIZE , machine->ram_size); + + dev =DEVICE (object_resolve_path ("/machine/pci-host" ,NULL )); +assert (dev); + pci0 =PCI_BUS (qdev_get_child_bus (dev,"pci.0" )); +assert (pci0); + +/* Add expansion PCI bus (2x PMC sites) +* "pci-bridge" is not a PLX bridge, but shouldn't matter? +*/ + dev =qdev_create (BUS (pci0),"pci-bridge" ); + +qdev_prop_set_uint8 (dev,"chassis_nr" ,1 ); +qdev_prop_set_int32 (dev,"addr" ,PCI_DEVFN (0x12 ,0 )); + +qdev_init_nofail (dev); + + pci1 =PCI_BUS (qdev_get_child_bus (dev,"pci.1" )); +assert (pci1); + + pci1_pins[0 ] =qdev_get_gpio_in (DEVICE (pic),4 ); + pci1_pins[1 ] =qdev_get_gpio_in (DEVICE (pic),5 ); + pci1_pins[2 ] =qdev_get_gpio_in (DEVICE (pic),6 ); + pci1_pins[3 ] =qdev_get_gpio_in (DEVICE (pic),7 ); + +pci_bus_irqs (pci1, mvme3100_pci1_set_irq, + pci_swizzle_map_irq_fn, pci1_pins,4 ); + +/* the actual PLX bridge doesn't emit interrupts */
hw/ppc/mvme3100.c line 485
Quoted 10 lines
hw/ppc/mvme3100.c new file +10
-0+pci_set_byte (PCI_DEVICE (dev)->config +PCI_INTERRUPT_PIN ,0 ); + +/* root bus is only home to soldered devices, and has a +* an arbitrary IRQ pin mapping. +* Don't allow qdev_device_add() to consider it. +*/ + { +BusState *bpci0 =BUS (pci0); +BusClass *bcls =BUS_GET_CLASS (pci0); +assert (bpci0);
I think the BUS() macro will already abort() if pci0 is NULL or not a BUS.
Quoted 452 lines
hw/ppc/mvme3100.c new file +254
-0+/* bus 0 is thus declared to be full. +* as a side-effect, expansion PCI bus limited to 15 devices +*/ + bpci0->max_index = bcls->max_dev =15 ; + } + +/* I2C Controller */ + dev =DEVICE (object_resolve_path ("/machine/i2c[0]" ,NULL )); +assert (dev); +sysbus_connect_irq (SYS_BUS_DEVICE (dev),0 , +qdev_get_gpio_in (DEVICE (pic),16 +27 )); + i2c =qdev_get_child_bus (dev,"bus" ); +assert (i2c); + +/* NIC (2x TSEC and 1x FEC) */ +if (nd_table[0 ].used) { +qemu_check_nic_model (&nd_table[0 ],"eTSEC" ); + + dev =etsec_create (E500_TSEC_OFFSET (0 ), ccsr, &nd_table[0 ], +qdev_get_gpio_in (DEVICE (pic),16 +13 ), +qdev_get_gpio_in (DEVICE (pic),16 +14 ), +qdev_get_gpio_in (DEVICE (pic),16 +18 )); + + }else if (nd_table[1 ].used) { +qemu_check_nic_model (&nd_table[1 ],"eTSEC" ); + + dev =etsec_create (E500_TSEC_OFFSET (1 ), ccsr, &nd_table[1 ], +qdev_get_gpio_in (DEVICE (pic),16 +19 ), +qdev_get_gpio_in (DEVICE (pic),16 +20 ), +qdev_get_gpio_in (DEVICE (pic),16 +23 )); + + }else if (nd_table[2 ].used) { +qemu_log_mask (LOG_UNIMP ,"FEC (ethernet #3) not modeled\n" ); + } + +/* VPD EEPROM */ + dev =qdev_create (i2c,"at24c-eeprom" ); +object_property_add_child (qdev_get_machine (),"vpd" ,OBJECT (dev), + &error_fatal); +qdev_prop_set_uint8 (dev,"address" ,0xa8 >>1 ); +qdev_prop_set_uint32 (dev,"rom-size" ,8192 *8 ); + + drvinfo =drive_get (IF_PFLASH ,0 ,0 ); +if (drvinfo) { +qdev_prop_set_drive (dev,"drive" ,blk_by_legacy_dinfo (drvinfo), + &error_fatal); + } + +qdev_init_nofail (dev); + + { +char *buf; + + buf =g_malloc0 (8192 *8 ); + +build_vpd (info, buf,8192 *8 , machine->kernel_cmdline); + +fw_cfg_add_file (fwinfo,"tomload/vpd" , buf,8192 *8 ); + } + +/* DS1375 RTC */ + dev =qdev_create (i2c,"ds1375" ); +object_property_add_child (qdev_get_machine (),"rtc" ,OBJECT (dev), + &error_fatal); +qdev_prop_set_uint8 (dev,"address" ,0xd0 >>1 ); +qdev_init_nofail (dev); +qdev_connect_gpio_out (dev,0 ,qdev_get_gpio_in (DEVICE (pic),11 )); + +/* TODO: unmodeled i2c devices. +* 0x90 - ds1621 temperature sensor +* 0xa0 - 256*8 byte DDR SPD (???) +* 0xa4 - 64k*8 byte eeprom for "user" configuration +* 0xa6 - 64k*8 byte eeprom for "user" configuration +* 0xaa - 8k*8 byte eeprom for VPD of rear expansion card +*/ + +if (!bios_name) { + bios_name ="tomload.bin" ; + } + +if (!qtest_enabled ()) { +MemoryRegion *rom =g_malloc0 (sizeof (*rom)); +char *fullname =qemu_find_file (QEMU_FILE_TYPE_BIOS , bios_name); + +if (!fullname) { +fprintf (stderr,"qemu: could not find bios file '%s'\n" , + bios_name); +exit (1 ); + } + +memory_region_init_ram (rom,OBJECT (cpld),"rom" , +0x800000 , &error_fatal); + +memory_region_add_subregion (get_system_memory (), +0xff800000 , rom); + +/* BIOS == image in rom (last 8MB of address space). +* Execution starts with the final word 0xfffffffc +*/ +int bsize =get_image_size (fullname); +if (bsize !=8 *1024 *1024 || +-1 ==load_image_targphys (fullname, +0xff800000 ,8 *1024 *1024 )) + { +fprintf (stderr,"qemu: could not load bios file '%s'" +" (%u bytes, requires 8MB)\n" , + fullname, (unsigned )bsize); +exit (1 ); + } + +memory_region_set_readonly (rom, true); + +g_free (fullname); + } + + { +hwaddr image_addr = mvme3100->load_address; + +int image_size =load_image_targphys (machine->kernel_filename, + image_addr,0x01000000 ); +if (machine->kernel_filename && +-1 == image_size) + { +fprintf (stderr,"qemu: could not load file '%s'\n" , + machine->kernel_filename); +exit (1 ); + + }else if (mvme3100->entry_address ==0 ) { + mvme3100->entry_address = image_addr; + + }else if (mvme3100->entry_address < image_addr + || mvme3100->entry_address >= image_addr + image_size) + { +fprintf (stderr,"qemu: entry-address out of range\n" ); +exit (1 ); + } + +if (machine->kernel_cmdline) { +fw_cfg_add_i32 (fwinfo,FW_CFG_CMDLINE_SIZE , +strlen (machine->kernel_cmdline) +1 ); +fw_cfg_add_string (fwinfo,FW_CFG_CMDLINE_DATA , + machine->kernel_cmdline); + } + +fw_cfg_add_i32 (fwinfo,FW_CFG_KERNEL_ADDR , image_addr); +fw_cfg_add_i32 (fwinfo,FW_CFG_KERNEL_ENTRY , mvme3100->entry_address); +fw_cfg_add_i32 (fwinfo,FW_CFG_KERNEL_SIZE , image_size); + } +} + +static void mvme3100_inst_init (Object *obj) +{ +MVME3100State *mvme3100 =MVME3100 (obj); + mvme3100->load_address =0x10000 ; + mvme3100->entry_address =0 ; +} + +static void mvme3100_visit_addr (Object *obj, +Visitor *v, +const char *name, +void *opaque, +Error **errp) +{ +MVME3100State *mvme3100 =MVME3100 (obj); +uint32_t *ptr; + +if (strcmp (name,"load-address" ) ==0 ) { + ptr = &mvme3100->load_address; + }else if (strcmp (name,"entry-address" ) ==0 ) { + ptr = &mvme3100->entry_address; + }else { +fprintf (stderr,"logic error: mvme3100 has no prop '%s'\n" , name); +exit (1 ); + } + +visit_type_uint32 (v, name, ptr, errp); +} + +static void ppce500_machine_class_init (ObjectClass *klass,void *raw) +{ +mvme3100_info *info = raw; +MachineClass *mc =MACHINE_CLASS (klass); +MVME3100Class *m3c =MVME3100_CLASS (klass); + + m3c->info = info; + + mc->desc = info->desc; + mc->init = mvme3100_init; + mc->max_cpus =1 ; + mc->default_ram_size = info->ram_size; + mc->default_cpu_type =POWERPC_CPU_TYPE_NAME ("mpc8540_v21" ); + +object_class_property_add (OBJECT_CLASS (mc),"load-address" ,"uint32" , + &mvme3100_visit_addr, &mvme3100_visit_addr,NULL , +NULL , &error_fatal); +object_class_property_add (OBJECT_CLASS (mc),"entry-address" ,"uint32" , + &mvme3100_visit_addr, &mvme3100_visit_addr,NULL , +NULL , &error_fatal); +} + +static const TypeInfo mvme3100_type = { + .abstract = true, + .name =TYPE_MVME3100 , + .parent =TYPE_MACHINE , + .instance_size =sizeof (MVME3100State), + .instance_init = mvme3100_inst_init, + .class_size =sizeof (MVME3100Class), +}; + +static mvme3100_info mvme3100_1152 = { + .desc ="MVME3100-1152" , + .cpu_freq =666666666u , +/* CCB/PCI -> 5/1 +* core/CCB -> 2/1 +* +* plat ratio = 5 -> 5:1 CCB:PCI +* e500 ratio = 4 -> 4:1 e500:CCB +*/ + .porpllsr =0x0004000a , + .ram_size =256 * (1 <<20 ), +}; + +static const TypeInfo mvme3100_1152_type = { + .name =MACHINE_TYPE_NAME ("mvme3100-1152" ), + .parent =TYPE_MVME3100 , + .class_init = ppce500_machine_class_init, + .class_data = &mvme3100_1152, +}; + +static mvme3100_info mvme3100_1263 = { + .desc ="MVME3100-1263" , + .cpu_freq =833333333u , +/* CCB/PCI -> 5/1 +* core/CCB -> 5/2 +*/ + .porpllsr =0x0005000a , + .ram_size =512 * (1 <<20 ), +}; + +static const TypeInfo mvme3100_1263_type = { + .name =MACHINE_TYPE_NAME ("mvme3100-1263" ), + .parent =TYPE_MVME3100 , + .class_init = ppce500_machine_class_init, + .class_data = &mvme3100_1263, +}; + +static void mvme3100_machine_init (void ) +{ +type_register_static (&mvme3100_type); +type_register_static (&mvme3100_1152_type); +type_register_static (&mvme3100_1263_type); +} + +type_init (mvme3100_machine_init)hw/ppc/mvme3100_cpld.c new file +192
-0@@ -0,0 +1,192 @@ +/* +* MVME3100 board CPLD (local logic) +* +* Copyright (c) 2015 Michael Davidsaver +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the LICENSE file in the top-level directory. +* +* This model was developed according to the +* MVME3100 Single Board Computer Programmer's Reference +* P/N: 6806800G37B +* July 2014 +* +* And validated against the RTEMS 4.9.6 mvme3100 BSP +*/ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "qemu-common.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" + +/* #define DEBUG_3100CPLD */ + +#define TYPE_CPLD "mvme3100-cpld" + +#define CPLD (obj) OBJECT_CHECK(MVMECPLD, (obj), TYPE_CPLD) + +#ifdef DEBUG_3100CPLD +#define DPRINTK (FMT , ...) printf(TYPE_CPLD " : " FMT, ## __VA_ARGS__) +#else +#define DPRINTK (FMT , ...) do {} while (0) +#endif + +#define LOG (MSK ,FMT , ...) qemu_log_mask(MSK, TYPE_CPLD " : " FMT, \ + ## __VA_ARGS__) + +#define CPLD_SIZE 0x20 + +typedef struct { +SysBusDevice parent_obj; + +uint8_t mem[0x10 ]; +uint32_t test; + +MemoryRegion mmio; +}MVMECPLD ; + +static +uint64_t cpld_read (void *opaque,hwaddr addr,unsigned size) +{ +MVMECPLD *self = opaque; +uint32_t offset = addr; +uint32_t val,A ; + +switch (offset) { + case 1 ... 0xf: + val =0 ; +A = offset; +while (size--) { + val <<=8 ; + val |= self->mem[A ++]; + } +break ; +case 0x10 : + val = self->test; +break ; +case 0x14 : + val = ~self->test; +break ; +default : +LOG (LOG_UNIMP ,"read from unimplimented register %08x\n" , + (unsigned )offset); + val =0 ; + } + +DPRINTK ("read %08x -> %08x\n" , (unsigned )offset, (unsigned )val); + +return val; +} + +static +void cpld_write (void *opaque,hwaddr addr,uint64_t val,unsigned size) +{ +MVMECPLD *self = opaque; +uint32_t offset = addr; + +DPRINTK ("write %08x <- %08x\n" , (unsigned )offset, (unsigned )val); + +switch (offset) { +case 0 : +break ; +case 1 : +/* TODO: TSTAT_MASK and EEPROM_WPEEPROM */ +if ((val &0xe0 ) ==0xa0 ) { +qemu_system_reset_request (SHUTDOWN_CAUSE_GUEST_RESET ); + } + self->mem[offset >>2 ] = val &0x3 ; +break ; +case 2 : + self->mem[offset >>2 ] = val &0xf ; +break ; +case 3 : + self->mem[offset >>2 ] = val &0x18 ; +break ; + case 4 ... 9: +break ; + case 10 ... 13: +/* TODO: allow date to be changed? */ +break ; +case 0x10 : + self->test = val; +break ; +case 0x11 : + self->test = ~val; +break ; +default : +LOG (LOG_UNIMP ,"write to unimplimented register %08x\n" , + (unsigned )offset); +break ; + } +} + +static const MemoryRegionOps cpld_ops = { + .read = cpld_read, + .write = cpld_write, + .endianness =DEVICE_NATIVE_ENDIAN , +}; +static +void mvme3100_cpld_realize (DeviceState *dev,Error **errp) +{ +MVMECPLD *self =CPLD (dev); + +memory_region_init_io (&self->mmio,OBJECT (self), &cpld_ops, self, +TYPE_CPLD ,CPLD_SIZE ); + +sysbus_init_mmio (&self->parent_obj, &self->mmio); +} + +static Property mvme3100_cpld_props[] = { +DEFINE_PROP_END_OF_LIST () +}; + +static +void mvme3100_cpld_reset (DeviceState *dev) +{ +MVMECPLD *self =CPLD (dev); + + self->mem[0 ] =0 ;/* Type VME SBC, SAFE_START==0 */ + self->mem[1 ] =3 ; + self->mem[2 ] =1 ; + self->mem[3 ] =9 ; + self->mem[4 ] =9 ; + self->mem[5 ] =0xa9 ; + self->mem[6 ] =1 ; + self->mem[7 ] =0xe0 ;/* TODO, TSEC phy irq status */ + self->mem[8 ] =1 ;/* TODO: PMC presence ...? */ + self->mem[9 ] =1 ;/* TODO: real rev. # */ + self->mem[10 ] =15 ;/* TODO: real date code */ + self->mem[11 ] =11 ; + self->mem[12 ] =14 ; + self->mem[13 ] =1 ; + self->test =0 ; +} + +static +void mvme3100_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = &mvme3100_cpld_realize; + dc->reset = &mvme3100_cpld_reset; + dc->desc ="mvme3100 CPLD logic" ; + dc->props = mvme3100_cpld_props; +} + +static const TypeInfo mvme3100_cpld_info = { + .name =TYPE_CPLD , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (MVMECPLD ), + .class_size =sizeof (SysBusDeviceClass), + .class_init = mvme3100_class_init, +}; + +static +void mvme3100_cpld_register (void ) +{ +type_register_static (&mvme3100_cpld_info); +} + +type_init (mvme3100_cpld_register)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 16/17 tests: run ds-rtc-i2c-test w/ ppc/mvme3100
In reply to Michael Davidsaver--- tests/Makefile.include | 3 ++- tests/ds-rtc-i2c-test.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)
tests/Makefile.include +2 -1
@@ -308,6 +308,7 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc-y += tests/prom-env-test$(EXESUF) check-qtest-ppc-y += tests/drive_del-test$(EXESUF) check-qtest-ppc-y += tests/boot-serial-test$(EXESUF) +check-qtest-ppc-y += tests/ds-rtc-i2c-test$(EXESUF) check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF) gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c
@@ -745,7 +746,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) -tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) +tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) $(libqos-e500-obj-y) tests/m25p80-test$(EXESUF): tests/m25p80-test.o tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
tests/ds-rtc-i2c-test.c +8 -0
@@ -18,6 +18,9 @@#define IMX25_I2C_0_BASE 0x43F80000#define DS1338_ADDR 0x68 +#define E500_CCSR_BASE 0xff700000 +#define DS1375_ADDR 0xd0 +static I2CAdapter *i2c;static uint8_t addr;static bool use_century;
@@ -148,6 +151,11 @@ int main(int argc, char *argv[]) addr =DS1338_ADDR ; use_century = false; + }else if (strcmp (arch,"ppc" ) ==0 ) { +qtest_start ("-machine mvme3100-1152" ); + i2c =e500_i2c_create (E500_CCSR_BASE ); + addr =DS1375_ADDR ; + use_century = true; }qtest_add_data_func ("/ds-rtc-i2c/set24" , test_time_24, test_rtc_set);
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100
Quoted 1 line · Michael Davidsaver
Signed-off-by Michael Davidsaver <[email protected]>
But will need to be rebased on the other revised patches.
Quoted 52 lines
--- tests/Makefile.include | 3 ++- tests/ds-rtc-i2c-test.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)tests/Makefile.include +2
-1@@ -308,6 +308,7 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc-y += tests/prom-env-test$(EXESUF) check-qtest-ppc-y += tests/drive_del-test$(EXESUF) check-qtest-ppc-y += tests/boot-serial-test$(EXESUF) +check-qtest-ppc-y += tests/ds-rtc-i2c-test$(EXESUF) check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF) gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c@@ -745,7 +746,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) -tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) +tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) $(libqos-e500-obj-y) tests/m25p80-test$(EXESUF): tests/m25p80-test.o tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)tests/ds-rtc-i2c-test.c +8
-0@@ -18,6 +18,9 @@#define IMX25_I2C_0_BASE 0x43F80000#define DS1338_ADDR 0x68 +#define E500_CCSR_BASE 0xff700000 +#define DS1375_ADDR 0xd0 +static I2CAdapter *i2c;static uint8_t addr;static bool use_century;@@ -148,6 +151,11 @@ int main(int argc, char *argv[]) addr =DS1338_ADDR ; use_century = false; + }else if (strcmp (arch,"ppc" ) ==0 ) { +qtest_start ("-machine mvme3100-1152" ); + i2c =e500_i2c_create (E500_CCSR_BASE ); + addr =DS1375_ADDR ; + use_century = true; }qtest_add_data_func ("/ds-rtc-i2c/set24" , test_time_24, test_rtc_set);
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 17/17 tests: add mvme3100-test
In reply to Michael DavidsaverExercise some features of the mvme3100 CPLD logic
and read from the eeprom w/ VPD.
--- tests/Makefile.include | 3 ++ tests/mvme3100-test.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/mvme3100-test.c
tests/Makefile.include +3 -0
@@ -373,6 +373,8 @@ check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF) check-qtest-s390x-y += tests/virtio-console-test$(EXESUF) check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF) +check-qtest-ppc-$(CONFIG_E500) += tests/mvme3100-test$(EXESUF) + check-qtest-generic-y += tests/qom-test$(EXESUF) check-qtest-generic-y += tests/test-hmp$(EXESUF)
@@ -782,6 +784,7 @@ tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o tests/ac97-test$(EXESUF): tests/ac97-test.o tests/es1370-test$(EXESUF): tests/es1370-test.o tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o +tests/mvme3100-test$(EXESUF): tests/mvme3100-test.o $(libqos-e500-obj-y) tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y) tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
tests/mvme3100-test.c new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [Qemu-devel] [PATCH 17/17] tests: add mvme3100-test
Quoted 4 lines · Michael Davidsaver
Exercise some features of the mvme3100 CPLD logic
and read from the eeprom w/ VPD.Signed-off-by Michael Davidsaver <[email protected]>
Looks good, but will need a rebase.
Quoted 112 lines
--- tests/Makefile.include | 3 ++ tests/mvme3100-test.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/mvme3100-test.ctests/Makefile.include +3
-0@@ -373,6 +373,8 @@ check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF) check-qtest-s390x-y += tests/virtio-console-test$(EXESUF) check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF) +check-qtest-ppc-$(CONFIG_E500) += tests/mvme3100-test$(EXESUF) + check-qtest-generic-y += tests/qom-test$(EXESUF) check-qtest-generic-y += tests/test-hmp$(EXESUF)@@ -782,6 +784,7 @@ tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o tests/ac97-test$(EXESUF): tests/ac97-test.o tests/es1370-test$(EXESUF): tests/es1370-test.o tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o +tests/mvme3100-test$(EXESUF): tests/mvme3100-test.o $(libqos-e500-obj-y) tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y) tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)tests/mvme3100-test.c new file +79
-0@@ -0,0 +1,79 @@ +#include <stdio.h> + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/libqos.h" +#include "libqos/i2c.h" + +#define assert_equal (A ,B ) g_assert_cmphex((A), ==, (B)) + +static +I2CAdapter *i2c; + +static +void test_ccsr (void ) +{ +/* CCSRBAR is self referential */ +assert_equal (readl (0xff700000 ),0x000ff700 ); + +/* introspect memory size */ +assert_equal (readl (0xff702080 ),0x80000000 ); +/* value is (ram_size-1)>>24 */ +assert_equal (readl (0xff702000 ),15 ); +} + +static +void test_cpld (void ) +{ +/* read/write to test register */ +assert_equal (readl (0xe2000010 ),0x00000000 ); +assert_equal (readl (0xe2000014 ),0xffffffff ); + +writel (0xe2000010 ,0x12345678 ); + +assert_equal (readl (0xe2000010 ),0x12345678 ); +assert_equal (readl (0xe2000014 ),0x12345678 ^0xffffffff ); +} + +static +void test_eeprom (void ) +{ +char buf[] ="\x00\x00MOTOROLA" ; + +/* 1. zero address pointer +* 2. write 8 bytes, +* 3. re-zero address pointer +*/ +i2c_send (i2c,0xa8 , (uint8_t *)buf,10 ); +i2c_send (i2c,0xa8 , (uint8_t *)buf,2 ); + +/* read 8 bytes */ +i2c_recv (i2c,0xa8 , (uint8_t *)buf,8 ); + buf[8 ] ='\0' ; + +/* Read header for Motorola VPD info */ + g_assert_cmpstr(buf, ==, "MOTOROLA"); +} + +int main (int argc,char *argv[]) +{ +int ret; +g_test_init (&argc, &argv,NULL ); + +qtest_start ("-machine mvme3100-1152" ); + + i2c =e500_i2c_create (0xff700000 ); + +qtest_add_func ("/mvme3100/ccsr" , test_ccsr); +qtest_add_func ("/mvme3100/cpld" , test_cpld); +qtest_add_func ("/mvme3100/eeprom" , test_eeprom); + + ret =g_test_run (); + +printf ("Tests done\n" ); + +qtest_end (); +printf ("Tests end\n" ); + +return ret; +}
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson