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:
parent
1a7bc06086
commit
dbff5861c4
2 changed files with 33 additions and 33 deletions
|
@ -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,23 +103,25 @@ 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
|
|
||||||
* and safe.
|
|
||||||
*/
|
*/
|
||||||
if (IS_ENABLED(CONFIG_SOF)) {
|
if (!IS_ENABLED(CONFIG_SOC_SERIES_INTEL_CAVS_V25)) {
|
||||||
CAVS_INTCTRL[cpu_num].l2.clear = CAVS_L2_IDC;
|
k_busy_wait(CAVS15_ROM_IDC_DELAY);
|
||||||
for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) {
|
}
|
||||||
IDC[c].busy_int |= IDC_ALL_CORES;
|
|
||||||
}
|
/* We set the interrupt controller up already, but the ROM on
|
||||||
|
* some platforms will mess it up.
|
||||||
|
*/
|
||||||
|
CAVS_INTCTRL[cpu_num].l2.clear = CAVS_L2_IDC;
|
||||||
|
for (int c = 0; c < CONFIG_MP_NUM_CPUS; c++) {
|
||||||
|
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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue