1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <assert.h> 6#include <limits.h> 7#include <stdint.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <threads.h> 12#include <unistd.h> 13 14#include <ddk/binding.h> 15#include <ddk/debug.h> 16#include <ddk/device.h> 17#include <ddk/driver.h> 18#include <ddk/protocol/platform-defs.h> 19#include <hw/reg.h> 20 21#include <soc/imx8m/imx8m-hw.h> 22#include <soc/imx8m/imx8m-iomux.h> 23 24#include <zircon/assert.h> 25#include <zircon/process.h> 26#include <zircon/syscalls.h> 27#include <zircon/threads.h> 28 29#include "imx8mevk.h" 30 31static pbus_mmio_t imx8mevk_display_mmios[] = { 32 { 33 .base = IMX8M_AIPS_DC_MST1_BASE, 34 .length = IMX8M_AIPS_LENGTH, 35 }, 36}; 37 38static const pbus_bti_t imx8mevk_display_btis[] = { 39 { 40 .iommu_index = 0, 41 .bti_id = BTI_DISPLAY, 42 }, 43}; 44 45static const pbus_dev_t display_dev = { 46 .name = "display", 47 .vid = PDEV_VID_NXP, 48 .pid = PDEV_PID_IMX8MEVK, 49 .did = PDEV_DID_IMX_DISPLAY, 50 .mmios = imx8mevk_display_mmios, 51 .mmio_count = countof(imx8mevk_display_mmios), 52 .btis = imx8mevk_display_btis, 53 .bti_count = countof(imx8mevk_display_btis), 54}; 55 56/* iMX8M EVK Pin Mux Table TODO: Add all supported peripherals on EVK board */ 57iomux_cfg_struct imx8mevk_pinmux[] = { 58 // UART1 RX 59 MAKE_PIN_CFG_UART(0, SW_MUX_CTL_PAD_UART1_RXD, 60 SW_PAD_CTL_PAD_UART1_RXD, 61 UART1_RXD_SELECT_INPUT), 62 // UART1 TX 63 MAKE_PIN_CFG_UART(0, SW_MUX_CTL_PAD_UART1_TXD, 64 SW_PAD_CTL_PAD_UART1_TXD, 65 0x000ULL), 66 67 // PWR_LED (used for GPIO Driver) 68 MAKE_PIN_CFG_DEFAULT(0, SW_MUX_CTL_PAD_GPIO1_IO13), 69 70 // eMMC (USDHC1) Pinmux 71 MAKE_PIN_CFG_USDHC_CLK(0, SW_MUX_CTL_PAD_SD1_CLK, 72 SW_PAD_CTL_PAD_SD1_CLK), 73 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_CMD, 74 SW_PAD_CTL_PAD_SD1_CMD), 75 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA0, 76 SW_PAD_CTL_PAD_SD1_DATA0), 77 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA1, 78 SW_PAD_CTL_PAD_SD1_DATA1), 79 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA2, 80 SW_PAD_CTL_PAD_SD1_DATA2), 81 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA3, 82 SW_PAD_CTL_PAD_SD1_DATA3), 83 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA4, 84 SW_PAD_CTL_PAD_SD1_DATA4), 85 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA5, 86 SW_PAD_CTL_PAD_SD1_DATA5), 87 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA6, 88 SW_PAD_CTL_PAD_SD1_DATA6), 89 MAKE_PIN_CFG_USDHC(0, SW_MUX_CTL_PAD_SD1_DATA7, 90 SW_PAD_CTL_PAD_SD1_DATA7), 91 MAKE_PIN_CFG_USDHC_CLK(0, SW_MUX_CTL_PAD_SD1_STROBE, 92 SW_PAD_CTL_PAD_SD1_STROBE), 93 94 MAKE_PIN_CFG_DEFAULT(5, SW_MUX_CTL_PAD_SD1_RESET_B), 95}; 96 97static void imx8mevk_bus_release(void* ctx) { 98 imx8mevk_bus_t* bus = ctx; 99 free(bus); 100} 101 102static zx_protocol_device_t imx8mevk_bus_device_protocol = { 103 .version = DEVICE_OPS_VERSION, 104 .release = imx8mevk_bus_release, 105}; 106 107static int imx8mevk_start_thread(void* arg) { 108 zx_status_t status; 109 imx8mevk_bus_t* bus = arg; 110 111 // TODO: Power and Clocks 112 113 // start the gpio driver first so we can do our initial pinmux 114 if ((status = imx8m_gpio_init(bus)) != ZX_OK) { 115 zxlogf(ERROR, "%s: failed %d\n", __FUNCTION__, status); 116 goto fail; 117 } 118 119 // Pinmux 120 for (unsigned i = 0; i < sizeof(imx8mevk_pinmux) / sizeof(imx8mevk_pinmux[0]); i++) { 121 gpio_impl_set_alt_function(&bus->gpio, 0, imx8mevk_pinmux[i]); 122 } 123 124 if ((status = imx_i2c_init(bus)) != ZX_OK) { 125 zxlogf(ERROR, "%s: failed %d\n", __FUNCTION__, status); 126 goto fail; 127 } 128 129 if ((status = imx_usb_init(bus)) != ZX_OK) { 130 zxlogf(ERROR, "%s: failed %d\n", __FUNCTION__, status); 131 goto fail; 132 } 133 134 if ((status = imx_gpu_init(bus)) != ZX_OK) { 135 zxlogf(ERROR, "%s: imx_gpu_init failed %d\n", __FUNCTION__, status); 136 goto fail; 137 } 138 139 if ((status = imx8m_sdhci_init(bus)) != ZX_OK) { 140 zxlogf(ERROR, "%s: failed %d\n", __FUNCTION__, status); 141 goto fail; 142 } 143 144 if ((status = pbus_device_add(&bus->pbus, &display_dev)) != ZX_OK) { 145 zxlogf(ERROR, "%s could not add display_dev: %d\n", __FUNCTION__, status); 146 goto fail; 147 } 148 149 return ZX_OK; 150 151fail: 152 zxlogf(ERROR, "aml_start_thread failed, not all devices have been initialized\n"); 153 return status; 154} 155 156static zx_status_t imx8mevk_bus_bind(void* ctx, zx_device_t* parent) { 157 imx8mevk_bus_t* bus = calloc(1, sizeof(imx8mevk_bus_t)); 158 if (!bus) { 159 return ZX_ERR_NO_MEMORY; 160 } 161 bus->parent = parent; 162 163 zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_BUS, &bus->pbus); 164 if (status != ZX_OK) { 165 goto fail; 166 } 167 168 // get default BTI from the dummy IOMMU implementation in the platform bus 169 status = device_get_protocol(parent, ZX_PROTOCOL_IOMMU, &bus->iommu); 170 if (status != ZX_OK) { 171 zxlogf(ERROR, "%s: Could not get ZX_PROTOCOL_IOMMU\n", __FUNCTION__); 172 goto fail; 173 } 174 175 status = iommu_get_bti(&bus->iommu, 0, BTI_BOARD, &bus->bti_handle); 176 if (status != ZX_OK) { 177 zxlogf(ERROR, "%s: iommu_get_bti failed %d\n", __FUNCTION__, status); 178 goto fail; 179 } 180 181 device_add_args_t args = { 182 .version = DEVICE_ADD_ARGS_VERSION, 183 .name = "imx8mevk", 184 .ctx = bus, 185 .ops = &imx8mevk_bus_device_protocol, 186 .flags = DEVICE_ADD_NON_BINDABLE, 187 }; 188 189 status = device_add(parent, &args, NULL); 190 if (status != ZX_OK) { 191 goto fail; 192 } 193 194 thrd_t t; 195 int thrd_rc = thrd_create_with_name(&t, imx8mevk_start_thread, bus, "imx8mevk_start_thread"); 196 if (thrd_rc != thrd_success) { 197 status = thrd_status_to_zx_status(thrd_rc); 198 goto fail; 199 } 200 201 return ZX_OK; 202 203fail: 204 zxlogf(ERROR, "%s failed. %d\n", __FUNCTION__, status); 205 imx8mevk_bus_release(bus); 206 return status; 207} 208 209static zx_driver_ops_t imx8mevk_bus_driver_ops = { 210 .version = DRIVER_OPS_VERSION, 211 .bind = imx8mevk_bus_bind, 212}; 213 214ZIRCON_DRIVER_BEGIN(imx8mevk_bus, imx8mevk_bus_driver_ops, "zircon", "0.1", 6) 215 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PLATFORM_BUS), 216 BI_GOTO_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_NXP, 0), 217 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_IMX8MEVK), 218 BI_LABEL(0), 219 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_GOOGLE), 220 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_MADRONE), 221ZIRCON_DRIVER_END(imx8mevk_bus) 222