soc/intel_adsp: Fixups for cavs18 SMP boot

This platform was stale for a long time and got a little left behind.
Basic OS stuff was working but secondary core bringup didn't.  It has
a slightly different set of choices from the "weird hardware
quirks" menu:

+ Like cAVS 1.5, it boots from a ROM that needs a short delay after
  power-up before it can receive the startup IDC.

+ But, like 2.5 and unlike 1.5, it doesn't start running until the
  PWRCTL bit for the core gets set by DSP software (1.5 gets launched
  by the host).  So the delay needed to move down a bit.

+ It wants that PWRCTL bit to be set last, after CLKCTL enables the
  clock.  (Which makes sense I guess: EE classes always tell you hold
  circuits in reset while an initial clock propagates). Not sure why
  it was in the reverse order originally; this way works for
  everything.

+ The ROM likes to scribble on the interrupt controller and mask its
  own IDC interrupts after we've already set it up.  They have to be
  unmasked.  We had code to do this already, thinking it was a
  workaround for legecy SOF code (that we never actually located).
  Now I'm thinking it was this behavior all along being detected by
  SOF's more extensive hardware CI.  Take out the test and do it
  always, it's like nine instructions.

+ The host/loader-side behavior is a mix of 1.5 and 2.5.  It won't
  actually start the secondary cores under host command, but it does
  need to see bits set for them in ADSPCS for the DSP-initiated
  power-up to work (2.5 would just ignore all but core 0's bits).

+ Also, like 1.5, it needs the host DMA stream to be explicitly
  stopped (and not just reset) or else further loads will be unstable.

Note that the loader changes now require more logic than just "1.5 or
not", so the platform detection has been enhanced to fully categorize
the device based on PCI ID (not quite: we don't have any 2.0 platform
hardware, so I left that alone for now).

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2022-01-21 16:22:37 -08:00 committed by Anas Nashif
commit dbff5861c4
2 changed files with 33 additions and 33 deletions

View file

@ -63,16 +63,6 @@ void soc_start_core(int cpu_num)
{ {
uint32_t curr_cpu = prid(); uint32_t curr_cpu = prid();
#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V15
/* On the older hardware, core power is managed by the host
* and aren't able to poll for anything to know it's
* available. Need a delay here so that the hardware and ROM
* firmware can complete initialization and be waiting for the
* IDC we're about to send.
*/
k_busy_wait(CAVS15_ROM_IDC_DELAY);
#endif
#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V25 #ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V25
/* On cAVS v2.5, MP startup works differently. The core has /* On cAVS v2.5, MP startup works differently. The core has
* no ROM, and starts running immediately upon receipt of an * no ROM, and starts running immediately upon receipt of an
@ -113,24 +103,26 @@ void soc_start_core(int cpu_num)
* turn itself off when it gets to the WAITI instruction in * turn itself off when it gets to the WAITI instruction in
* the idle thread. * the idle thread.
*/ */
CAVS_SHIM.pwrctl |= CAVS_PWRCTL_TCPDSPPG(cpu_num);
if (!IS_ENABLED(CONFIG_SOC_SERIES_INTEL_CAVS_V15)) { if (!IS_ENABLED(CONFIG_SOC_SERIES_INTEL_CAVS_V15)) {
CAVS_SHIM.clkctl |= CAVS_CLKCTL_TCPLCG(cpu_num); CAVS_SHIM.clkctl |= CAVS_CLKCTL_TCPLCG(cpu_num);
} }
CAVS_SHIM.pwrctl |= CAVS_PWRCTL_TCPDSPPG(cpu_num);
/* Workaround. SOF seems to have some older code on pre-2.5 /* Older devices boot from a ROM and needs some time to
* hardware that is remasking these interrupts (probably a * complete initialization and be waiting for the IDC we're
* variant of the same code we inherited earlier to mask it * about to send.
* while the ROM handles the startup IDC?). Unmask */
* unconditionally while we get this figured out, it's cheap if (!IS_ENABLED(CONFIG_SOC_SERIES_INTEL_CAVS_V25)) {
* and safe. k_busy_wait(CAVS15_ROM_IDC_DELAY);
}
/* We set the interrupt controller up already, but the ROM on
* some platforms will mess it up.
*/ */
if (IS_ENABLED(CONFIG_SOF)) {
CAVS_INTCTRL[cpu_num].l2.clear = CAVS_L2_IDC; CAVS_INTCTRL[cpu_num].l2.clear = CAVS_L2_IDC;
for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) { for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) {
IDC[c].busy_int |= IDC_ALL_CORES; IDC[c].busy_int |= IDC_ALL_CORES;
} }
}
/* Send power-up message to the other core. Start address /* Send power-up message to the other core. Start address
* gets passed via the IETC scratch register (only 30 bits * gets passed via the IETC scratch register (only 30 bits

View file

@ -27,7 +27,12 @@ def map_regs():
p = runx(f"grep -iPl 'PCI_CLASS=40(10|38)0' /sys/bus/pci/devices/*/uevent") p = runx(f"grep -iPl 'PCI_CLASS=40(10|38)0' /sys/bus/pci/devices/*/uevent")
pcidir = os.path.dirname(p) pcidir = os.path.dirname(p)
cavs15 = open(f"{pcidir}/device").read().rstrip() in [ "0x5a98", "0x1a98", "0x3198" ] # Platform/quirk detection. ID lists cribbed from the SOF kernel driver
global cavs15, cavs18, cavs25
did = int(open(f"{pcidir}/device").read().rstrip(), 16)
cavs15 = did in [ 0x5a98, 0x1a98, 0x3198 ]
cavs18 = did in [ 0x9dc8, 0xa348, 0x02c8, 0x06c8, 0xa3f0 ]
cavs25 = did in [ 0xa0c8, 0x43c8, 0x4b55, 0x4b58, 0x7ad0, 0x51c8 ]
# Check sysfs for a loaded driver and remove it # Check sysfs for a loaded driver and remove it
if os.path.exists(f"{pcidir}/driver"): if os.path.exists(f"{pcidir}/driver"):
@ -77,7 +82,7 @@ def map_regs():
dsp.SRAM_FW_STATUS = 0x80000 # Start of first SRAM window dsp.SRAM_FW_STATUS = 0x80000 # Start of first SRAM window
dsp.freeze() dsp.freeze()
return (hda, sd, dsp, hda_ostream_id, cavs15) return (hda, sd, dsp, hda_ostream_id)
def setup_dma_mem(fw_bytes): def setup_dma_mem(fw_bytes):
(mem, phys_addr) = map_phys_mem() (mem, phys_addr) = map_phys_mem()
@ -210,10 +215,12 @@ def load_firmware(fw_file):
hda.SPBFCTL |= (1 << hda_ostream_id) hda.SPBFCTL |= (1 << hda_ostream_id)
hda.SD_SPIB = len(fw_bytes) hda.SD_SPIB = len(fw_bytes)
# Start DSP. Just core 0 on 1.8+ (secondary core startup is handled # Start DSP. Host needs to provide power to all cores on 1.5
# internally), but on 1.5 the host controls the power levers. # (which also starts them) and 1.8 (merely gates power, DSP also
# has to set PWRCTL). The bits for cores other than 0 are ignored
# on 2.5 where the DSP has full control.
log.info(f"Starting DSP, ADSPCS = 0x{dsp.ADSPCS:x}") log.info(f"Starting DSP, ADSPCS = 0x{dsp.ADSPCS:x}")
dsp.ADSPCS = 0xff0000 if cavs15 else 0x01fefe dsp.ADSPCS = 0xff0000 if not cavs25 else 0x01fefe
while (dsp.ADSPCS & 0x1000000) == 0: pass while (dsp.ADSPCS & 0x1000000) == 0: pass
# Wait for the ROM to boot and signal it's ready. This short # Wait for the ROM to boot and signal it's ready. This short
@ -248,10 +255,11 @@ def load_firmware(fw_file):
if not alive: if not alive:
log.warning(f"Load failed? FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}") log.warning(f"Load failed? FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}")
# Turn DMA off and reset the stream. Clearing START first is a noop # Turn DMA off and reset the stream. Clearing START first is a
# per the spec, but required for 1.5, and makes the load on 1.8 # noop per the spec, but required for early versions (apparently
# unstable. Go figure. # the reset doesn't stop the stream and the next load fails), and
if cavs15: # makes the load on 2.5 unstable. Go figure.
if not cavs25:
sd.CTL &= ~2 # clear START sd.CTL &= ~2 # clear START
sd.CTL |= 1 sd.CTL |= 1
log.info(f"cAVS firmware load complete") log.info(f"cAVS firmware load complete")
@ -288,9 +296,9 @@ def winstream_read(last_seq):
return (seq, result.decode("utf-8")) return (seq, result.decode("utf-8"))
async def main(): async def main():
global hda, sd, dsp, hda_ostream_id, cavs15 global hda, sd, dsp, hda_ostream_id
try: try:
(hda, sd, dsp, hda_ostream_id, cavs15) = map_regs() (hda, sd, dsp, hda_ostream_id) = map_regs()
except Exception: except Exception:
log.error("Could not map device in sysfs; run as root.") log.error("Could not map device in sysfs; run as root.")
sys.exit(1) sys.exit(1)