1.1 --- a/pkg/landfall-examples/hw_info/hw_info.c Thu Feb 01 22:41:30 2024 +0100
1.2 +++ b/pkg/landfall-examples/hw_info/hw_info.c Thu Feb 01 22:42:56 2024 +0100
1.3 @@ -1,7 +1,7 @@
1.4 /*
1.5 * Access various peripherals on the MIPS Creator CI20 board.
1.6 *
1.7 - * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
1.8 + * Copyright (C) 2023, 2024 Paul Boddie <paul@boddie.org.uk>
1.9 *
1.10 * This program is free software; you can redistribute it and/or
1.11 * modify it under the terms of the GNU General Public License as
1.12 @@ -248,9 +248,10 @@
1.13
1.14 static int get_memory_region(unsigned int size, l4_addr_t *addr)
1.15 {
1.16 - *addr = (l4_addr_t) calloc(size, sizeof(char));
1.17 -
1.18 - return !(*addr);
1.19 + void *a = calloc(size, sizeof(char));
1.20 +
1.21 + *addr = (l4_addr_t) a;
1.22 + return a == NULL ? 1 : 0;
1.23 }
1.24
1.25
1.26 @@ -897,8 +898,6 @@
1.27 unsigned int num;
1.28 void *channel;
1.29
1.30 - printf("i2c: channel\n\n");
1.31 -
1.32 for (num = 0; num < num_i2c_channels; num++)
1.33 {
1.34 printf("Channel %d: ", num);
1.35 @@ -1325,6 +1324,233 @@
1.36
1.37
1.38
1.39 +/* TCU configuration. */
1.40 +
1.41 +static l4_uint32_t tcu_irq_start = 0, tcu_irq_end = 0;
1.42 +
1.43 +/* TCU operations. */
1.44 +
1.45 +static int init_tcu(void)
1.46 +{
1.47 + /* Here, only one IRQ is used. */
1.48 +
1.49 + tcu_irq = l4re_util_cap_alloc();
1.50 + return init_irq(0, tcu_irq, tcu_irq_start, tcu_irq_end);
1.51 +}
1.52 +
1.53 +static void disable_tcu_counter(void)
1.54 +{
1.55 + int num = get_channel_number(num_tcu_channels);
1.56 + void *channel;
1.57 +
1.58 + if (num < 0)
1.59 + return;
1.60 +
1.61 + channel = tcu_channels[num];
1.62 +
1.63 + if (channel == NULL)
1.64 + return;
1.65 +
1.66 + tcu_disable(channel);
1.67 +}
1.68 +
1.69 +static void enable_tcu_counter(void)
1.70 +{
1.71 + int num = get_channel_number(num_tcu_channels);
1.72 + void *channel;
1.73 +
1.74 + if (num < 0)
1.75 + return;
1.76 +
1.77 + channel = tcu_channels[num];
1.78 +
1.79 + if (channel == NULL)
1.80 + return;
1.81 +
1.82 + tcu_enable(channel);
1.83 +}
1.84 +
1.85 +static void new_tcu_channel(void *tcu)
1.86 +{
1.87 + int num = get_channel_number(num_tcu_channels);
1.88 +
1.89 + if (num < 0)
1.90 + return;
1.91 +
1.92 + tcu_channels[num] = tcu_get_channel(tcu, num, tcu_irq);
1.93 +}
1.94 +
1.95 +static void list_tcu_channels(void)
1.96 +{
1.97 + unsigned int num;
1.98 + void *channel;
1.99 +
1.100 + printf(" Clock.. Counter......... Mask..............\n");
1.101 + printf("Channel Status C Pre Cnt Half Full Half Full Int\n");
1.102 +
1.103 + for (num = 0; num < num_tcu_channels; num++)
1.104 + {
1.105 + printf("%d ", num);
1.106 +
1.107 + channel = tcu_channels[num];
1.108 +
1.109 + if (channel == NULL)
1.110 + printf("inactive\n");
1.111 + else
1.112 + printf("%s %d %4d %04x %04x %04x %s %s %s\n",
1.113 + tcu_is_enabled(channel) ? "enabled " : "disabled",
1.114 + tcu_get_clock(channel),
1.115 + tcu_get_prescale(channel),
1.116 + tcu_get_counter(channel),
1.117 + tcu_get_half_data_value(channel),
1.118 + tcu_get_full_data_value(channel),
1.119 + tcu_get_half_data_mask(channel) ? "masked " : "unmasked",
1.120 + tcu_get_full_data_mask(channel) ? "masked " : "unmasked",
1.121 + tcu_have_interrupt(channel) ? "!" : "_");
1.122 + }
1.123 +}
1.124 +
1.125 +static void set_tcu_counter(void)
1.126 +{
1.127 + int num = get_channel_number(num_tcu_channels);
1.128 + void *channel;
1.129 + uint32_t counter;
1.130 +
1.131 + if (num < 0)
1.132 + return;
1.133 +
1.134 + channel = tcu_channels[num];
1.135 +
1.136 + if (channel == NULL)
1.137 + return;
1.138 +
1.139 + if (!read_number("Value", &counter))
1.140 + return;
1.141 +
1.142 + tcu_set_counter(channel, counter);
1.143 +}
1.144 +
1.145 +static void set_tcu_clock(void)
1.146 +{
1.147 + int num = get_channel_number(num_tcu_channels);
1.148 + void *channel;
1.149 + uint32_t clock;
1.150 +
1.151 + if (num < 0)
1.152 + return;
1.153 +
1.154 + channel = tcu_channels[num];
1.155 +
1.156 + if (channel == NULL)
1.157 + return;
1.158 +
1.159 + if (!read_number("Clock", &clock))
1.160 + return;
1.161 +
1.162 + tcu_set_clock(channel, clock);
1.163 +}
1.164 +
1.165 +static void set_tcu_full(void)
1.166 +{
1.167 + int num = get_channel_number(num_tcu_channels);
1.168 + void *channel;
1.169 + uint32_t value;
1.170 +
1.171 + if (num < 0)
1.172 + return;
1.173 +
1.174 + channel = tcu_channels[num];
1.175 +
1.176 + if (channel == NULL)
1.177 + return;
1.178 +
1.179 + if (!read_number("Full value", &value))
1.180 + return;
1.181 +
1.182 + tcu_set_full_data_value(channel, value);
1.183 +}
1.184 +
1.185 +static void set_tcu_half(void)
1.186 +{
1.187 + int num = get_channel_number(num_tcu_channels);
1.188 + void *channel;
1.189 + uint32_t value;
1.190 +
1.191 + if (num < 0)
1.192 + return;
1.193 +
1.194 + channel = tcu_channels[num];
1.195 +
1.196 + if (channel == NULL)
1.197 + return;
1.198 +
1.199 + if (!read_number("Half value", &value))
1.200 + return;
1.201 +
1.202 + tcu_set_half_data_value(channel, value);
1.203 +}
1.204 +
1.205 +static void set_tcu_mask(int full_mask, int masked)
1.206 +{
1.207 + int num = get_channel_number(num_tcu_channels);
1.208 + void *channel;
1.209 +
1.210 + if (num < 0)
1.211 + return;
1.212 +
1.213 + channel = tcu_channels[num];
1.214 +
1.215 + if (channel == NULL)
1.216 + return;
1.217 +
1.218 + if (full_mask)
1.219 + tcu_set_full_data_mask(channel, masked);
1.220 + else
1.221 + tcu_set_half_data_mask(channel, masked);
1.222 +}
1.223 +
1.224 +static void set_tcu_prescale(void)
1.225 +{
1.226 + int num = get_channel_number(num_tcu_channels);
1.227 + void *channel;
1.228 + uint32_t prescale;
1.229 +
1.230 + if (num < 0)
1.231 + return;
1.232 +
1.233 + channel = tcu_channels[num];
1.234 +
1.235 + if (channel == NULL)
1.236 + return;
1.237 +
1.238 + if (!read_number("Prescale", &prescale))
1.239 + return;
1.240 +
1.241 + tcu_set_prescale(channel, prescale);
1.242 +}
1.243 +
1.244 +static void tcu_wait(void)
1.245 +{
1.246 + int num = get_channel_number(num_tcu_channels);
1.247 + void *channel;
1.248 + uint32_t timeout;
1.249 +
1.250 + if (num < 0)
1.251 + return;
1.252 +
1.253 + channel = tcu_channels[num];
1.254 +
1.255 + if (channel == NULL)
1.256 + return;
1.257 +
1.258 + if (!read_number("Timeout", &timeout))
1.259 + return;
1.260 +
1.261 + printf("IRQ received: %s\n", tcu_wait_for_irq(channel, timeout) ? "yes" : "no");
1.262 +}
1.263 +
1.264 +
1.265 +
1.266 /* Command processing. */
1.267
1.268 static void handle_aic(void *aic)
1.269 @@ -1511,6 +1737,49 @@
1.270 list_channels(num_spi_channels, spi_channels);
1.271 }
1.272
1.273 +static void handle_tcu(void *tcu)
1.274 +{
1.275 + char *token;
1.276 +
1.277 + if ((token = read_token(NULL)) != NULL)
1.278 + {
1.279 + if (!strcmp(token, "l") || !strcmp(token, "list"))
1.280 + list_tcu_channels();
1.281 + else if (!strcmp(token, "c") || !strcmp(token, "channel"))
1.282 + new_tcu_channel(tcu);
1.283 + else if (!strcmp(token, "C") || !strcmp(token, "clock"))
1.284 + set_tcu_clock();
1.285 + else if (!strcmp(token, "d") || !strcmp(token, "disable"))
1.286 + disable_tcu_counter();
1.287 + else if (!strcmp(token, "e") || !strcmp(token, "enable"))
1.288 + enable_tcu_counter();
1.289 + else if (!strcmp(token, "f") || !strcmp(token, "full"))
1.290 + set_tcu_full();
1.291 + else if (!strcmp(token, "fm") || !strcmp(token, "full-mask"))
1.292 + set_tcu_mask(1, 1);
1.293 + else if (!strcmp(token, "fu") || !strcmp(token, "full-unmask"))
1.294 + set_tcu_mask(1, 0);
1.295 + else if (!strcmp(token, "h") || !strcmp(token, "half"))
1.296 + set_tcu_half();
1.297 + else if (!strcmp(token, "hm") || !strcmp(token, "half-mask"))
1.298 + set_tcu_mask(0, 1);
1.299 + else if (!strcmp(token, "hu") || !strcmp(token, "half-unmask"))
1.300 + set_tcu_mask(0, 0);
1.301 + else if (!strcmp(token, "p") || !strcmp(token, "prescale"))
1.302 + set_tcu_prescale();
1.303 + else if (!strcmp(token, "s") || !strcmp(token, "set"))
1.304 + set_tcu_counter();
1.305 + else if (!strcmp(token, "w") || !strcmp(token, "wait"))
1.306 + tcu_wait();
1.307 + else
1.308 + printf("tcu channel | clock | disable | enable | full | full-mask | " \
1.309 + "full-unmask | half | half-mask | half-unmask | list | mask | " \
1.310 + "prescale | set | unmask | wait\n");
1.311 + }
1.312 + else
1.313 + list_tcu_channels();
1.314 +}
1.315 +
1.316
1.317
1.318 int main(void)
1.319 @@ -1524,7 +1793,8 @@
1.320 l4_addr_t rtc_base = 0, rtc_base_end = 0;
1.321 l4_addr_t ssi_base = 0, ssi_base_end = 0;
1.322 l4_addr_t ssi_phys_base = 0, ssi_phys_base_end = 0;
1.323 - void *aic, *cpm, *dma, *gpio[num_gpio_ports], *i2c, *rtc, *spi;
1.324 + l4_addr_t tcu_base = 0, tcu_base_end = 0;
1.325 + void *aic, *cpm, *dma, *gpio[num_gpio_ports], *i2c, *rtc, *spi, *tcu;
1.326 int result = 0;
1.327 unsigned int port;
1.328
1.329 @@ -1614,9 +1884,26 @@
1.330
1.331 spi = spi_init(ssi_phys_base, ssi_base, ssi_base_end, cpm);
1.332
1.333 + printf("Access TCU...\n");
1.334 +
1.335 + if ((result = get_memory(io_memory_regions[TCU], &tcu_base, &tcu_base_end)) < 0)
1.336 + return 1;
1.337 +
1.338 + printf("TCU at 0x%lx...0x%lx.\n", tcu_base, tcu_base_end);
1.339 +
1.340 + tcu = tcu_init(tcu_base, tcu_base_end);
1.341 +
1.342 + if (get_irq(io_memory_regions[TCU], &tcu_irq_start, &tcu_irq_end) < 0)
1.343 + return 1;
1.344 +
1.345 + printf("IRQ range at %d...%d.\n", tcu_irq_start, tcu_irq_end);
1.346 +
1.347 + if (init_tcu())
1.348 + return 1;
1.349 +
1.350 /* Start the interactive session. */
1.351
1.352 - printf("aic, cpm, dma, gpio, i2c, rtc, spi\n");
1.353 + printf("aic, cpm, dma, gpio, i2c, rtc, spi, tcu\n");
1.354
1.355 while (1)
1.356 {
1.357 @@ -1672,6 +1959,11 @@
1.358 else if (!strcmp(token, "s") || !strcmp(token, "spi"))
1.359 handle_spi(spi, gpio);
1.360
1.361 + /* TCU commands. */
1.362 +
1.363 + else if (!strcmp(token, "t") || !strcmp(token, "tcu"))
1.364 + handle_tcu(tcu);
1.365 +
1.366 /* Comments and blank lines. */
1.367
1.368 else if (strncmp(token, "#", 1) && strlen(token))