| /* |
| * Copyright (c) 2016, 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> |
| */ |
| |
| #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 <uapi/ipc.h> |
| #include <sof/mailbox.h> |
| #include <sof/dai.h> |
| #include <sof/dma.h> |
| #include <sof/interrupt.h> |
| #include <sof/sof.h> |
| #include <sof/work.h> |
| #include <sof/clock.h> |
| #include <sof/ipc.h> |
| #include <sof/trace.h> |
| #include <sof/agent.h> |
| #include <sof/io.h> |
| #include <sof/dma-trace.h> |
| #include <sof/audio/component.h> |
| #include <config.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), |
| }, |
| /* dspbox is for DSP initiated IPC, hostbox is for host initiated IPC */ |
| .version = { |
| .build = SOF_BUILD, |
| .minor = SOF_MINOR, |
| .major = SOF_MAJOR, |
| .date = __DATE__, |
| .time = __TIME__, |
| .tag = SOF_TAG, |
| }, |
| /* TODO: add capabilities */ |
| }; |
| |
| #define NUM_HSW_WINDOWS 6 |
| 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_HSW_WINDOWS, |
| .type = SOF_IPC_EXT_WINDOW, |
| }, |
| .num_windows = NUM_HSW_WINDOWS, |
| .window = { |
| { |
| .type = SOF_IPC_REGION_UPBOX, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_DSPBOX_SIZE, |
| .offset = MAILBOX_DSPBOX_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_DOWNBOX, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_HOSTBOX_SIZE, |
| .offset = MAILBOX_HOSTBOX_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_DEBUG, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_DEBUG_SIZE, |
| .offset = MAILBOX_DEBUG_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_TRACE, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_TRACE_SIZE, |
| .offset = MAILBOX_TRACE_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_STREAM, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_STREAM_SIZE, |
| .offset = MAILBOX_STREAM_OFFSET, |
| }, |
| { |
| .type = SOF_IPC_REGION_EXCEPTION, |
| .id = 0, /* map to host window 0 */ |
| .flags = 0, // TODO: set later |
| .size = MAILBOX_EXCEPTION_SIZE, |
| .offset = MAILBOX_EXCEPTION_OFFSET, |
| }, |
| }, |
| }; |
| |
| static struct work_queue_timesource platform_generic_queue = { |
| .timer = { |
| .id = TIMER1, /* internal timer */ |
| .irq = IRQ_NUM_TIMER2, |
| }, |
| .clk = CLK_CPU, |
| .notifier = NOTIFIER_ID_CPU_FREQ, |
| .timer_set = arch_timer_set, |
| .timer_clear = arch_timer_clear, |
| .timer_get = arch_timer_get_system, |
| }; |
| |
| struct timer *platform_timer = &platform_generic_queue.timer; |
| |
| int platform_boot_complete(uint32_t boot_message) |
| { |
| uint32_t outbox = MAILBOX_HOST_OFFSET >> 3; |
| |
| mailbox_dspbox_write(0, &ready, sizeof(ready)); |
| mailbox_dspbox_write(sizeof(ready), &sram_window, |
| sram_window.ext_hdr.hdr.size); |
| |
| /* now interrupt host to tell it we are done booting */ |
| shim_write(SHIM_IPCD, outbox | SHIM_IPCD_BUSY); |
| |
| /* boot now complete so we can relax the CPU */ |
| clock_set_freq(CLK_CPU, CLK_DEFAULT_CPU_HZ); |
| |
| return 0; |
| } |
| |
| void platform_interrupt_set(int irq) |
| { |
| arch_interrupt_set(irq); |
| } |
| |
| /* clear mask in PISR, bits are W1C in docs but some bits need preserved ?? */ |
| void platform_interrupt_clear(uint32_t irq, uint32_t mask) |
| { |
| switch (irq) { |
| case IRQ_NUM_EXT_DMAC0: |
| case IRQ_NUM_EXT_DMAC1: |
| case IRQ_NUM_EXT_SSP0: |
| case IRQ_NUM_EXT_SSP1: |
| interrupt_clear(irq); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* TODO: expand this to 64 bit - should we just return mask of IRQ numbers */ |
| uint32_t platform_interrupt_get_enabled(void) |
| { |
| return shim_read(SHIM_IMRD); |
| } |
| |
| void platform_interrupt_mask(uint32_t irq, uint32_t mask) |
| { |
| switch (irq) { |
| case IRQ_NUM_EXT_SSP0: |
| shim_write(SHIM_IMRD, SHIM_IMRD_SSP0); |
| break; |
| case IRQ_NUM_EXT_SSP1: |
| shim_write(SHIM_IMRD, SHIM_IMRD_SSP1); |
| break; |
| case IRQ_NUM_EXT_DMAC0: |
| shim_write(SHIM_IMRD, SHIM_IMRD_DMAC0); |
| break; |
| case IRQ_NUM_EXT_DMAC1: |
| shim_write(SHIM_IMRD, SHIM_IMRD_DMAC1); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void platform_interrupt_unmask(uint32_t irq, uint32_t mask) |
| { |
| switch (irq) { |
| case IRQ_NUM_EXT_SSP0: |
| shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) & ~SHIM_IMRD_SSP0); |
| break; |
| case IRQ_NUM_EXT_SSP1: |
| shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) & ~SHIM_IMRD_SSP1); |
| break; |
| case IRQ_NUM_EXT_DMAC0: |
| shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) & ~SHIM_IMRD_DMAC0); |
| break; |
| case IRQ_NUM_EXT_DMAC1: |
| shim_write(SHIM_IMRD, shim_read(SHIM_IMRD) & ~SHIM_IMRD_DMAC1); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* init shim registers */ |
| static void platform_init_shim(void) |
| { |
| /* disable power gate */ |
| io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL, |
| SHIM_CLKCTL_DCPLCG, |
| SHIM_CLKCTL_DCPLCG); |
| |
| /* disable parity check */ |
| io_reg_update_bits(SHIM_BASE + SHIM_CSR, SHIM_CSR_PCE, 0); |
| |
| /* enable DMA finsh on ssp ports */ |
| io_reg_update_bits(SHIM_BASE + SHIM_CSR2, |
| SHIM_CSR2_SDFD_SSP0 | SHIM_CSR2_SDFD_SSP1, |
| SHIM_CSR2_SDFD_SSP0 | SHIM_CSR2_SDFD_SSP1); |
| } |
| |
| int platform_init(struct sof *sof) |
| { |
| struct dai *ssp0; |
| struct dai *ssp1; |
| int ret; |
| |
| trace_point(TRACE_BOOT_PLATFORM_MBOX); |
| |
| /* clear mailbox for early trace and debug */ |
| bzero((void *)MAILBOX_BASE, IPC_MAX_MAILBOX_BYTES); |
| |
| trace_point(TRACE_BOOT_PLATFORM_SHIM); |
| platform_init_shim(); |
| |
| trace_point(TRACE_BOOT_PLATFORM_CLOCK); |
| init_platform_clocks(); |
| |
| /* init work queues and clocks */ |
| trace_point(TRACE_BOOT_SYS_WORK); |
| init_system_workq(&platform_generic_queue); |
| |
| trace_point(TRACE_BOOT_PLATFORM_TIMER); |
| platform_timer_start(platform_timer); |
| |
| /* 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 25M */ |
| trace_point(TRACE_BOOT_PLATFORM_SSP_FREQ); |
| clock_set_freq(CLK_SSP, 25000000); |
| |
| /* initialise the host IPC mechanisms */ |
| trace_point(TRACE_BOOT_PLATFORM_IPC); |
| ipc_init(sof); |
| |
| /* 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); |
| ssp0 = dai_get(SOF_DAI_INTEL_SSP, 0); |
| if (ssp0 == NULL) |
| return -ENODEV; |
| dai_probe(ssp0); |
| |
| ssp1 = dai_get(SOF_DAI_INTEL_SSP, 1); |
| if (ssp1 == NULL) |
| return -ENODEV; |
| dai_probe(ssp1); |
| |
| /* Initialize DMA for Trace*/ |
| dma_trace_init_complete(sof->dmat); |
| |
| return 0; |
| } |