1/**
2 * \file
3 * \brief Provides a generic startup function for the ARM OMAP platform
4 */
5/*
6 * Copyright (c) 2013, ETH Zurich.
7 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <assert.h>
19
20#include <barrelfish/barrelfish.h>
21#include <barrelfish/spawn_client.h>
22#include <barrelfish_kpi/platform.h>
23#include <if/monitor_blocking_defs.h>
24
25#include <arch/arm/omap44xx/device_registers.h>
26#include <maps/omap44xx_map.h>
27#include <maps/vexpress_map.h>
28
29#include "kaluga.h"
30
31struct allowed_registers
32{
33    char* binary;
34    lpaddr_t registers[][2];
35};
36
37static struct allowed_registers usb = {
38    .binary = "hw.arm.omap44xx.usb",
39    .registers =
40    {
41        {OMAP44XX_MAP_L4_CFG_HSUSBHOST, OMAP44XX_MAP_L4_CFG_HSUSBHOST_SIZE},
42        {OMAP44XX_MAP_L4_CFG_HSUSBTLL, OMAP44XX_MAP_L4_CFG_HSUSBTLL_SIZE},
43        {OMAP44XX_MAP_L4_WKUP_SRCM, OMAP44XX_MAP_L4_WKUP_SRCM_SIZE},
44        {OMAP44XX_MAP_L4_WKUP_SYSCTRL_PADCONF_WKUP, OMAP44XX_MAP_L4_WKUP_SYSCTRL_PADCONF_WKUP_SIZE},
45        {OMAP44XX_MAP_L4_CFG_SYSCTRL_PADCONF_CORE, OMAP44XX_MAP_L4_CFG_SYSCTRL_PADCONF_CORE_SIZE},
46        {OMAP44XX_MAP_L4_CFG_CM2, OMAP44XX_MAP_L4_CFG_CM2_SIZE},
47        {OMAP44XX_MAP_L4_WKUP_GPIO1, OMAP44XX_MAP_L4_WKUP_GPIO1_SIZE},
48        {OMAP44XX_MAP_L4_PER_GPIO2, OMAP44XX_MAP_L4_PER_GPIO2_SIZE},
49        {OMAP44XX_MAP_L4_WKUP_PRM, OMAP44XX_MAP_L4_WKUP_PRM_SIZE},
50        {0x0, 0x0}
51    }
52};
53
54static struct allowed_registers fdif = {
55    .binary = "fdif",
56    .registers =
57    {
58        {OMAP44XX_CAM_CM2, 0x1000},
59        {OMAP44XX_DEVICE_PRM, 0x1000},
60        {OMAP44XX_CAM_PRM, 0x1000},
61        {OMAP44XX_MAP_L4_CFG_FACE_DETECT,OMAP44XX_MAP_L4_CFG_FACE_DETECT_SIZE},
62        {0x0, 0x0}
63    }
64};
65
66static struct allowed_registers twl6030 = {
67    .binary = "twl6030",
68    .registers =
69    {
70        {OMAP44XX_MAP_L4_PER_I2C1, OMAP44XX_MAP_L4_PER_I2C1_SIZE},
71        {0x0, 0x0}
72    }
73};
74
75static struct allowed_registers cm2 = {
76    .binary = "cm2",
77    .registers =
78    {
79        {OMAP44XX_CM2,        0x1000},
80        {0x0, 0x0}
81    }
82};
83
84
85static struct allowed_registers mmchs = {
86    .binary = "mmchs",
87    .registers =
88    {
89        {OMAP44XX_MAP_L4_CFG_SYSCTRL_PADCONF_CORE, OMAP44XX_MAP_L4_CFG_SYSCTRL_PADCONF_CORE_SIZE},
90        {OMAP44XX_MAP_L4_PER_HSMMC1, OMAP44XX_MAP_L4_PER_HSMMC1_SIZE},
91        {0x0, 0x0}
92    }
93};
94
95static struct allowed_registers prcm = {
96    .binary = "hw.arm.omap44xx.prcm",
97    .registers =
98    {
99        {OMAP44XX_MAP_L4_WKUP_PRM, OMAP44XX_MAP_L4_WKUP_PRM_SIZE},
100        {OMAP44XX_DEVICE_PRM, 0x1000},
101        {OMAP44XX_MAP_L4_PER_I2C1, OMAP44XX_MAP_L4_PER_I2C1_SIZE},
102        {OMAP44XX_MAP_L4_PER_I2C2, OMAP44XX_MAP_L4_PER_I2C2_SIZE},
103        {OMAP44XX_MAP_L4_PER_I2C3, OMAP44XX_MAP_L4_PER_I2C3_SIZE},
104        {OMAP44XX_MAP_L4_PER_I2C4, OMAP44XX_MAP_L4_PER_I2C4_SIZE},
105        {0x0, 0x0}
106    }
107};
108
109static struct allowed_registers omap_uart = {
110    .binary = "hw.arm.omap44xx.uart",
111    .registers =
112    {
113        {OMAP44XX_MAP_L4_PER_UART1,OMAP44XX_MAP_L4_PER_UART1_SIZE},
114        {OMAP44XX_MAP_L4_PER_UART2,OMAP44XX_MAP_L4_PER_UART2_SIZE},
115        {OMAP44XX_MAP_L4_PER_UART3,OMAP44XX_MAP_L4_PER_UART3_SIZE},
116        {OMAP44XX_MAP_L4_PER_UART4,OMAP44XX_MAP_L4_PER_UART4_SIZE},
117        {0x0, 0x0}
118    }
119};
120
121static struct allowed_registers sdma = {
122    .binary = "sdma",
123    .registers =
124    {
125        {OMAP44XX_MAP_L4_CFG_SDMA, OMAP44XX_MAP_L4_CFG_SDMA_SIZE},
126        {0x0, 0x0}
127    }
128};
129
130
131static struct allowed_registers* omap44xx[] = {
132    &usb,
133    &fdif,
134    &twl6030,
135    &cm2,
136    &mmchs,
137    &prcm,
138    &omap_uart,
139    &sdma,
140    NULL,
141};
142
143static struct allowed_registers vexpress_pl390_dist = {
144    .binary = "pl390_dist",
145    .registers =
146    {
147        {VEXPRESS_MAP_GIC_DIST, VEXPRESS_MAP_GIC_DIST_SIZE},
148        {0x0, 0x0}
149    }
150};
151
152static struct allowed_registers vexpress_uart = {
153    .binary = "hw.arm.vexpress.uart",
154    .registers =
155    {
156        {VEXPRESS_MAP_UART0, VEXPRESS_MAP_UART0_SIZE},
157        {VEXPRESS_MAP_UART1, VEXPRESS_MAP_UART1_SIZE},
158        {VEXPRESS_MAP_UART2, VEXPRESS_MAP_UART2_SIZE},
159        {VEXPRESS_MAP_UART3, VEXPRESS_MAP_UART3_SIZE},
160        {0x0, 0x0}
161    }
162};
163
164static struct allowed_registers* vexpress[] = {
165    &vexpress_uart,
166    &vexpress_pl390_dist,
167    NULL,
168};
169
170/**
171 * \brief Startup function for ARMv7 drivers.
172 *
173 * Makes sure we get the device register capabilities.
174 */
175errval_t
176default_start_function(coreid_t where, struct module_info* driver,
177        char* record, struct driver_argument* int_arg)
178{
179    assert(driver != NULL);
180    assert(record != NULL);
181
182    errval_t err;
183
184    struct monitor_blocking_binding *m=
185        get_monitor_blocking_binding();
186    assert(m != NULL);
187
188    uint32_t arch, platform;
189    err = m->rpc_tx_vtbl.get_platform(m, &arch, &platform);
190    assert(err_is_ok(err));
191    assert(arch == PI_ARCH_ARMV7A);
192
193    struct allowed_registers **regs= NULL;
194    switch(platform) {
195        case PI_PLATFORM_OMAP44XX:
196            regs= omap44xx;
197            break;
198        case PI_PLATFORM_VEXPRESS:
199            regs= vexpress;
200            break;
201        default:
202            printf("Unrecognised ARMv7 platform\n");
203            abort();
204    }
205
206    // TODO Request the right set of caps and put in device_range_cap
207    struct cnoderef dev_cnode;
208    struct capref dev_cnode_cap;
209    err = cnode_create_l2(&dev_cnode_cap, &dev_cnode);
210    assert(err_is_ok(err));
211
212    struct capref device_cap;
213    device_cap.cnode = dev_cnode;
214    device_cap.slot = 0;
215
216    char* name;
217    err = oct_read(record, "%s", &name);
218    assert(err_is_ok(err));
219    KALUGA_DEBUG("%s:%d: Starting driver for %s\n", __FUNCTION__, __LINE__, name);
220    for (size_t i=0; regs[i] != NULL; i++) {
221
222        if(strcmp(name, regs[i]->binary) != 0) {
223            continue;
224        }
225
226        // Get the device cap from the managed capability tree
227        // put them all in a single cnode
228        for (size_t j=0; regs[i]->registers[j][0] != 0x0; j++) {
229            struct capref device_frame;
230            KALUGA_DEBUG("%s:%d: mapping 0x%"PRIxLPADDR" %"PRIuLPADDR"\n", __FUNCTION__, __LINE__,
231                   regs[i]->registers[j][0], regs[i]->registers[j][1]);
232
233            lpaddr_t base = regs[i]->registers[j][0] & ~(BASE_PAGE_SIZE-1);
234            err = get_device_cap(base,
235                                 regs[i]->registers[j][1],
236                                 &device_frame);
237            assert(err_is_ok(err));
238
239            KALUGA_DEBUG("get_device_cap worked\n");
240
241            err = cap_copy(device_cap, device_frame);
242            assert(err_is_ok(err));
243            device_cap.slot++;
244        }
245    }
246    free(name);
247
248    err = spawn_program_with_caps(0, driver->path, driver->argv, environ,
249            NULL_CAP, dev_cnode_cap, 0, driver->did);
250    if (err_is_fail(err)) {
251        DEBUG_ERR(err, "Spawning %s failed.", driver->path);
252        return err;
253    }
254
255    return SYS_ERR_OK;
256}
257
258static void provide_driver_with_caps(struct driver_instance* drv, char* name) {
259    errval_t err;
260
261    struct monitor_blocking_binding *m = get_monitor_blocking_binding();
262    assert(m != NULL);
263
264    uint32_t arch, platform;
265    err = m->rpc_tx_vtbl.get_platform(m, &arch, &platform);
266    assert(err_is_ok(err));
267    assert(arch == PI_ARCH_ARMV7A);
268
269    struct allowed_registers **regs= NULL;
270    switch(platform) {
271    case PI_PLATFORM_OMAP44XX:
272        regs= omap44xx;
273        break;
274    case PI_PLATFORM_VEXPRESS:
275        regs= vexpress;
276        break;
277    default:
278        printf("Unrecognised ARMv7 platform\n");
279        abort();
280    }
281
282
283    KALUGA_DEBUG("%s:%d: Finding caps for driver for %s\n", __FUNCTION__, __LINE__, name);
284    for (size_t i=0; regs[i] != NULL; i++) {
285        if(strcmp(name, regs[i]->binary) != 0) {
286            continue;
287        }
288
289        // Get the device cap from the managed capability tree
290        // put them all in a single cnode
291        for (size_t j=0; regs[i]->registers[j][0] != 0x0; j++) {
292            struct capref device_frame;
293            KALUGA_DEBUG("%s:%d: mapping 0x%"PRIxLPADDR" %"PRIuLPADDR"\n", __FUNCTION__, __LINE__,
294            regs[i]->registers[j][0], regs[i]->registers[j][1]);
295
296            lpaddr_t base = regs[i]->registers[j][0] & ~(BASE_PAGE_SIZE-1);
297            err = get_device_cap(base, regs[i]->registers[j][1], &device_frame);
298            assert(err_is_ok(err));
299
300            KALUGA_DEBUG("get_device_cap worked\n");
301            err = ddomain_driver_add_cap(drv, device_frame);
302            assert(err_is_ok(err));
303        }
304    }
305}
306
307
308/**
309 * \brief Startup function for new-style ARMv7 drivers.
310 *
311 * Launches the driver instance in a driver domain instead.
312 */
313errval_t
314newstyle_start_function(coreid_t where, struct module_info* driver, char* record,
315                        struct driver_argument* int_arg)
316{
317    assert(driver != NULL);
318    assert(record != NULL);
319    errval_t err;
320
321    struct domain_instance* inst = instantiate_driver_domain(driver->binary, where);
322
323    char* dep1;
324    err = oct_read(record, "_ { dep1: %s }", &dep1);
325    if (err_is_ok(err)) {
326        struct driver_instance* drv1 = ddomain_create_driver_instance(dep1, dep1);
327        provide_driver_with_caps(drv1, dep1);
328        free(dep1);
329        ddomain_instantiate_driver(inst, drv1);
330    }
331
332    char* dep2;
333    err = oct_read(record, "_ { dep2: %s }", &dep2);
334    if (err_is_ok(err)) {
335        struct driver_instance* drv2 = ddomain_create_driver_instance(dep2, dep2);
336        provide_driver_with_caps(drv2, dep2);
337        free(dep2);
338        ddomain_instantiate_driver(inst, drv2);
339    }
340
341    char* name;
342    err = oct_read(record, "%s", &name);
343    assert(err_is_ok(err));
344
345    struct driver_instance* drv = ddomain_create_driver_instance(name, name);
346    provide_driver_with_caps(drv, name);
347    free(name);
348
349    ddomain_instantiate_driver(inst, drv);
350    return SYS_ERR_OK;
351}
352