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, Universitaetstr. 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
130static struct allowed_registers* omap44xx[] = {
131    &usb,
132    &fdif,
133    &twl6030,
134    &cm2,
135    &mmchs,
136    &prcm,
137    &omap_uart,
138    &sdma,
139    NULL,
140};
141
142static struct allowed_registers vexpress_uart = {
143    .binary = "hw.arm.vexpress.uart",
144    .registers =
145    {
146        {VEXPRESS_MAP_UART0, VEXPRESS_MAP_UART0_SIZE},
147        {VEXPRESS_MAP_UART1, VEXPRESS_MAP_UART1_SIZE},
148        {VEXPRESS_MAP_UART2, VEXPRESS_MAP_UART2_SIZE},
149        {VEXPRESS_MAP_UART3, VEXPRESS_MAP_UART3_SIZE},
150        {0x0, 0x0}
151    }
152};
153
154static struct allowed_registers* vexpress[] = {
155    &vexpress_uart,
156    NULL,
157};
158
159/**
160 * \brief Startup function for ARMv7 drivers.
161 *
162 * Makes sure we get the device register capabilities.
163 */
164errval_t
165default_start_function(coreid_t where, struct module_info* driver,
166        char* record, struct driver_argument* int_arg)
167{
168    assert(driver != NULL);
169    assert(record != NULL);
170
171    errval_t err;
172
173    struct monitor_blocking_binding *m=
174        get_monitor_blocking_binding();
175    assert(m != NULL);
176
177    uint32_t arch, platform;
178    err = m->rpc_tx_vtbl.get_platform(m, &arch, &platform);
179    assert(err_is_ok(err));
180    assert(arch == PI_ARCH_ARMV7A);
181
182    struct allowed_registers **regs= NULL;
183    switch(platform) {
184        case PI_PLATFORM_OMAP44XX:
185            regs= omap44xx;
186            break;
187        case PI_PLATFORM_VEXPRESS:
188            regs= vexpress;
189            break;
190        default:
191            printf("Unrecognised ARMv7 platform\n");
192            abort();
193    }
194
195    // TODO Request the right set of caps and put in device_range_cap
196    struct cnoderef dev_cnode;
197    struct capref dev_cnode_cap;
198    err = cnode_create_l2(&dev_cnode_cap, &dev_cnode);
199    assert(err_is_ok(err));
200
201    struct capref device_cap;
202    device_cap.cnode = dev_cnode;
203    device_cap.slot = 0;
204
205    char* name;
206    err = oct_read(record, "%s", &name);
207    assert(err_is_ok(err));
208    KALUGA_DEBUG("%s:%d: Starting driver for %s\n", __FUNCTION__, __LINE__, name);
209    for (size_t i=0; regs[i] != NULL; i++) {
210
211        if(strcmp(name, regs[i]->binary) != 0) {
212            continue;
213        }
214
215        // Get the device cap from the managed capability tree
216        // put them all in a single cnode
217        for (size_t j=0; regs[i]->registers[j][0] != 0x0; j++) {
218            struct capref device_frame;
219            KALUGA_DEBUG("%s:%d: mapping 0x%"PRIxLPADDR" %"PRIuLPADDR"\n", __FUNCTION__, __LINE__,
220                   regs[i]->registers[j][0], regs[i]->registers[j][1]);
221
222            lpaddr_t base = regs[i]->registers[j][0] & ~(BASE_PAGE_SIZE-1);
223            err = get_device_cap(base,
224                                 regs[i]->registers[j][1],
225                                 &device_frame);
226            assert(err_is_ok(err));
227
228            KALUGA_DEBUG("get_device_cap worked\n");
229
230            err = cap_copy(device_cap, device_frame);
231            assert(err_is_ok(err));
232            device_cap.slot++;
233        }
234    }
235    free(name);
236
237    err = spawn_program_with_caps(0, driver->path, driver->argv, environ,
238            NULL_CAP, dev_cnode_cap, 0, driver->did);
239    if (err_is_fail(err)) {
240        DEBUG_ERR(err, "Spawning %s failed.", driver->path);
241        return err;
242    }
243
244    return SYS_ERR_OK;
245}
246
247static void provide_driver_with_caps(struct driver_instance* drv, char* name) {
248    errval_t err;
249
250    struct monitor_blocking_binding *m = get_monitor_blocking_binding();
251    assert(m != NULL);
252
253    uint32_t arch, platform;
254    err = m->rpc_tx_vtbl.get_platform(m, &arch, &platform);
255    assert(err_is_ok(err));
256    assert(arch == PI_ARCH_ARMV7A);
257
258    struct allowed_registers **regs= NULL;
259    switch(platform) {
260    case PI_PLATFORM_OMAP44XX:
261        regs= omap44xx;
262        break;
263    case PI_PLATFORM_VEXPRESS:
264        regs= vexpress;
265        break;
266    default:
267        printf("Unrecognised ARMv7 platform\n");
268        abort();
269    }
270
271
272    KALUGA_DEBUG("%s:%d: Finding caps for driver for %s\n", __FUNCTION__, __LINE__, name);
273    for (size_t i=0; regs[i] != NULL; i++) {
274        if(strcmp(name, regs[i]->binary) != 0) {
275            continue;
276        }
277
278        // Get the device cap from the managed capability tree
279        // put them all in a single cnode
280        for (size_t j=0; regs[i]->registers[j][0] != 0x0; j++) {
281            struct capref device_frame;
282            KALUGA_DEBUG("%s:%d: mapping 0x%"PRIxLPADDR" %"PRIuLPADDR"\n", __FUNCTION__, __LINE__,
283            regs[i]->registers[j][0], regs[i]->registers[j][1]);
284
285            lpaddr_t base = regs[i]->registers[j][0] & ~(BASE_PAGE_SIZE-1);
286            err = get_device_cap(base, regs[i]->registers[j][1], &device_frame);
287            assert(err_is_ok(err));
288
289            KALUGA_DEBUG("get_device_cap worked\n");
290            err = ddomain_driver_add_cap(drv, device_frame);
291            assert(err_is_ok(err));
292        }
293    }
294}
295
296
297/**
298 * \brief Startup function for new-style ARMv7 drivers.
299 *
300 * Launches the driver instance in a driver domain instead.
301 */
302errval_t
303newstyle_start_function(coreid_t where, struct module_info* driver, char* record,
304                        struct driver_argument* int_arg)
305{
306    assert(driver != NULL);
307    assert(record != NULL);
308    errval_t err;
309
310    struct domain_instance* inst = instantiate_driver_domain(driver->binary, where);
311
312    char* dep1;
313    err = oct_read(record, "_ { dep1: %s }", &dep1);
314    if (err_is_ok(err)) {
315        struct driver_instance* drv1 = ddomain_create_driver_instance(dep1, dep1);
316        provide_driver_with_caps(drv1, dep1);
317        free(dep1);
318        ddomain_instantiate_driver(inst, drv1);
319    }
320
321    char* dep2;
322    err = oct_read(record, "_ { dep2: %s }", &dep2);
323    if (err_is_ok(err)) {
324        struct driver_instance* drv2 = ddomain_create_driver_instance(dep2, dep2);
325        provide_driver_with_caps(drv2, dep2);
326        free(dep2);
327        ddomain_instantiate_driver(inst, drv2);
328    }
329
330    char* name;
331    err = oct_read(record, "%s", &name);
332    assert(err_is_ok(err));
333
334    struct driver_instance* drv = ddomain_create_driver_instance(name, name);
335    provide_driver_with_caps(drv, name);
336    free(name);
337
338    ddomain_instantiate_driver(inst, drv);
339    return SYS_ERR_OK;
340}
341