| /* |
| * Copyright (c) 2017, Intel Corporation |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of the Intel Corporation nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> |
| * Keyon Jie <yang.jie@linux.intel.com> |
| */ |
| |
| #include <platform/memory.h> |
| #include <platform/mailbox.h> |
| #include <platform/shim.h> |
| #include <platform/dma.h> |
| #include <platform/clk.h> |
| #include <platform/timer.h> |
| #include <platform/interrupt.h> |
| #include <uapi/ipc.h> |
| #include <sof/mailbox.h> |
| #include <sof/dai.h> |
| #include <sof/dma.h> |
| #include <sof/sof.h> |
| #include <sof/agent.h> |
| #include <sof/work.h> |
| #include <sof/clock.h> |
| #include <sof/ipc.h> |
| #include <sof/io.h> |
| #include <sof/trace.h> |
| #include <sof/audio/component.h> |
| #include <string.h> |
| #include <version.h> |
| |
| static const struct sof_ipc_fw_ready ready = { |
| .hdr = { |
| .cmd = SOF_IPC_FW_READY, |
| .size = sizeof(struct sof_ipc_fw_ready), |
| }, |
| .version = { |
| .build = SOF_BUILD, |
| .minor = SOF_MINOR, |
| .major = SOF_MAJOR, |
| .date = __DATE__, |
| .time = __TIME__, |
| .tag = SOF_TAG, |
| }, |
| }; |
| |
| #define SRAM_WINDOW_HOST_OFFSET(x) (0x80000 + x * 0x20000) |
| |
| #define NUM_APL_WINDOWS 7 |
| |
| static const struct sof_ipc_window sram_window = { |
| .ext_hdr = { |
| .hdr.cmd = SOF_IPC_FW_READY, |
| .hdr.size = sizeof(struct sof_ipc_window) + |
| sizeof(struct sof_ipc_window_elem) * NUM_APL_WINDOWS, |
| .type = SOF_IPC_EXT_WINDOW, |
| }, |
| .num_windows = NUM_APL_WINDOWS, |
| .window = { |
| { |
| .type = SOF_IPC_REGION_REGS, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_SW_REG_SIZE, |
| .offset = 0, |
| }, |
| { |
| .type = SOF_IPC_REGION_UPBOX, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_DSPBOX_SIZE, |
| .offset = MAILBOX_SW_REG_SIZE, |
| }, |
| { |
| .type = SOF_IPC_REGION_DOWNBOX, |
| .id = 1, /* map to host window 1 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_HOSTBOX_SIZE, |
| .offset = 0, |
| }, |
| { |
| .type = SOF_IPC_REGION_DEBUG, |
| .id = 2, /* map to host window 2 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_EXCEPTION_SIZE + MAILBOX_DEBUG_SIZE, |
| .offset = 0, |
| }, |
| { |
| .type = SOF_IPC_REGION_EXCEPTION, |
| .id = 2, /* map to host window 2 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_EXCEPTION_SIZE, |
| .offset = MAILBOX_EXCEPTION_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_STREAM, |
| .id = 2, /* map to host window 2 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_STREAM_SIZE, |
| .offset = MAILBOX_STREAM_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_TRACE, |
| .id = 3, /* map to host window 3 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_TRACE_SIZE, |
| .offset = 0, |
| }, |
| }, |
| }; |
| |
| static struct work_queue_timesource platform_generic_queue = { |
| .timer = { |
| .id = TIMER3, /* external timer, XTAL 19.2M */ |
| .irq = IRQ_EXT_TSTAMP0_LVL2(0), |
| }, |
| .clk = CLK_SSP, |
| .notifier = NOTIFIER_ID_SSP_FREQ, |
| .timer_set = platform_timer_set, |
| .timer_clear = platform_timer_clear, |
| .timer_get = platform_timer_get, |
| }; |
| |
| struct timer *platform_timer = &platform_generic_queue.timer; |
| |
| int platform_boot_complete(uint32_t boot_message) |
| { |
| mailbox_dspbox_write(0, &ready, sizeof(ready)); |
| mailbox_dspbox_write(sizeof(ready), &sram_window, |
| sram_window.ext_hdr.hdr.size); |
| |
| /* boot now complete so we can relax the CPU */ |
| clock_set_freq(CLK_CPU, CLK_DEFAULT_CPU_HZ); |
| |
| /* tell host we are ready */ |
| ipc_write(IPC_DIPCIE, SRAM_WINDOW_HOST_OFFSET(0) >> 12); |
| ipc_write(IPC_DIPCI, 0x80000000 | SOF_IPC_FW_READY); |
| |
| return 0; |
| } |
| |
| static void platform_memory_windows_init(void) |
| { |
| /* window0, for fw status & outbox/uplink mbox */ |
| io_reg_write(DMWLO(0), HP_SRAM_WIN0_SIZE | 0x7); |
| io_reg_write(DMWBA(0), HP_SRAM_WIN0_BASE |
| | DMWBA_READONLY | DMWBA_ENABLE); |
| bzero((void *)(HP_SRAM_WIN0_BASE + SRAM_REG_FW_END), |
| HP_SRAM_WIN0_SIZE - SRAM_REG_FW_END); |
| dcache_writeback_region((void *)(HP_SRAM_WIN0_BASE + SRAM_REG_FW_END), |
| HP_SRAM_WIN0_SIZE - SRAM_REG_FW_END); |
| |
| /* window1, for inbox/downlink mbox */ |
| io_reg_write(DMWLO(1), HP_SRAM_WIN1_SIZE | 0x7); |
| io_reg_write(DMWBA(1), HP_SRAM_WIN1_BASE |
| | DMWBA_ENABLE); |
| bzero((void *)HP_SRAM_WIN1_BASE, HP_SRAM_WIN1_SIZE); |
| dcache_writeback_region((void *)HP_SRAM_WIN1_BASE, HP_SRAM_WIN1_SIZE); |
| |
| /* window2, for debug */ |
| io_reg_write(DMWLO(2), HP_SRAM_WIN2_SIZE | 0x7); |
| io_reg_write(DMWBA(2), HP_SRAM_WIN2_BASE |
| | DMWBA_READONLY | DMWBA_ENABLE); |
| bzero((void *)HP_SRAM_WIN2_BASE, HP_SRAM_WIN2_SIZE); |
| dcache_writeback_region((void *)HP_SRAM_WIN2_BASE, HP_SRAM_WIN2_SIZE); |
| |
| /* window3, for trace */ |
| io_reg_write(DMWLO(3), HP_SRAM_WIN3_SIZE | 0x7); |
| io_reg_write(DMWBA(3), HP_SRAM_WIN3_BASE |
| | DMWBA_READONLY | DMWBA_ENABLE); |
| bzero((void *)HP_SRAM_WIN3_BASE, HP_SRAM_WIN3_SIZE); |
| dcache_writeback_region((void *)HP_SRAM_WIN3_BASE, HP_SRAM_WIN3_SIZE); |
| } |
| |
| /* init HW */ |
| static void platform_init_hw(void) |
| { |
| io_reg_write(SHIM_GENO, SHIM_GENO_SHIMOSEL | |
| SHIM_GENO_MDIVOSEL | SHIM_GENO_DIOPTOSEL); |
| |
| io_reg_write(SHIM_DSPIOPO, |
| SHIM_DSPIOPO_DMICOSEL | SHIM_DSPIOPO_I2SOSEL); |
| |
| io_reg_write(SHIM_LPGPDMAC(0), |
| SHIM_LPGPDMAC_CHOSEL | SHIM_LPGPDMAC_CTLOSEL); |
| io_reg_write(SHIM_LPGPDMAC(1), |
| SHIM_LPGPDMAC_CHOSEL | SHIM_LPGPDMAC_CTLOSEL); |
| } |
| |
| int platform_init(struct sof *sof) |
| { |
| struct dai *ssp; |
| struct dai *dmic0; |
| int i, ret; |
| |
| trace_point(TRACE_BOOT_PLATFORM_ENTRY); |
| platform_init_hw(); |
| |
| platform_interrupt_init(); |
| |
| trace_point(TRACE_BOOT_PLATFORM_MBOX); |
| platform_memory_windows_init(); |
| |
| trace_point(TRACE_BOOT_PLATFORM_SHIM); |
| |
| /* init work queues and clocks */ |
| trace_point(TRACE_BOOT_PLATFORM_TIMER); |
| platform_timer_start(&platform_generic_queue.timer); |
| |
| trace_point(TRACE_BOOT_PLATFORM_CLOCK); |
| init_platform_clocks(); |
| |
| trace_point(TRACE_BOOT_SYS_WORK); |
| init_system_workq(&platform_generic_queue); |
| |
| /* init the system agent */ |
| sa_init(sof); |
| |
| /* Set CPU to default frequency for booting */ |
| trace_point(TRACE_BOOT_SYS_CPU_FREQ); |
| clock_set_freq(CLK_CPU, CLK_MAX_CPU_HZ); |
| |
| /* set SSP clock to 19.2M */ |
| trace_point(TRACE_BOOT_PLATFORM_SSP_FREQ); |
| clock_set_freq(CLK_SSP, 19200000); |
| |
| /* initialise the host IPC mechanisms */ |
| trace_point(TRACE_BOOT_PLATFORM_IPC); |
| ipc_init(sof); |
| |
| /* disable PM for boot */ |
| shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) | |
| SHIM_CLKCTL_LPGPDMAFDCGB(0) | |
| SHIM_CLKCTL_LPGPDMAFDCGB(1) | |
| SHIM_CLKCTL_I2SFDCGB(3) | |
| SHIM_CLKCTL_I2SFDCGB(2) | |
| SHIM_CLKCTL_I2SFDCGB(1) | |
| SHIM_CLKCTL_I2SFDCGB(0) | |
| SHIM_CLKCTL_DMICFDCGB | |
| SHIM_CLKCTL_I2SEFDCGB(1) | |
| SHIM_CLKCTL_I2SEFDCGB(0) | |
| SHIM_CLKCTL_TCPAPLLS | |
| SHIM_CLKCTL_RAPLLC | |
| SHIM_CLKCTL_RXOSCC | |
| SHIM_CLKCTL_RFROSCC | |
| SHIM_CLKCTL_TCPLCG(0) | SHIM_CLKCTL_TCPLCG(1)); |
| |
| shim_write(SHIM_LPSCTL, shim_read(SHIM_LPSCTL)); |
| |
| /* init DMACs */ |
| trace_point(TRACE_BOOT_PLATFORM_DMA); |
| ret = dmac_init(); |
| if (ret < 0) |
| return -ENODEV; |
| |
| |
| /* init SSP ports */ |
| trace_point(TRACE_BOOT_PLATFORM_SSP); |
| for (i = 0; i < PLATFORM_NUM_SSP; i++) { |
| ssp = dai_get(SOF_DAI_INTEL_SSP, i); |
| if (ssp == NULL) |
| return -ENODEV; |
| dai_probe(ssp); |
| } |
| |
| /* Init DMIC. Note that the two PDM controllers and four microphones |
| * supported max. those are available in platform are handled by dmic0. |
| */ |
| trace_point(TRACE_BOOT_PLATFORM_DMIC); |
| dmic0 = dai_get(SOF_DAI_INTEL_DMIC, 0); |
| if (!dmic0) |
| return -ENODEV; |
| |
| dai_probe(dmic0); |
| |
| /* Initialize DMA for Trace*/ |
| dma_trace_init_complete(sof->dmat); |
| |
| return 0; |
| } |