158 lines
2.2 KiB
C
158 lines
2.2 KiB
C
/*
|
|
* misc.c
|
|
*
|
|
* Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "config.h"
|
|
#include "misc.h"
|
|
#include "e1.h"
|
|
|
|
|
|
struct misc {
|
|
uint32_t warmboot;
|
|
struct {
|
|
uint16_t oe_out;
|
|
uint8_t in;
|
|
uint8_t _rsvd;
|
|
} gpio;
|
|
uint32_t e1_led;
|
|
uint32_t _rsvd;
|
|
struct {
|
|
uint16_t rx;
|
|
uint16_t tx;
|
|
} e1_tick[2];
|
|
struct {
|
|
uint32_t pps;
|
|
uint32_t now;
|
|
} time;
|
|
uint32_t pdm[8];
|
|
} __attribute__((packed,aligned(4)));
|
|
|
|
static volatile struct misc * const misc_regs = (void*)(MISC_BASE);
|
|
|
|
|
|
static const int pdm_bits[5] = { 12, 12, 8, 8, 8 };
|
|
|
|
|
|
void
|
|
pdm_set(int chan, bool enable, unsigned value, bool normalize)
|
|
{
|
|
if (normalize)
|
|
value >>= (16 - pdm_bits[chan]);
|
|
if (enable)
|
|
value |= 0x80000000;
|
|
misc_regs->pdm[chan] = value;
|
|
}
|
|
|
|
|
|
void
|
|
gpio_dir(int n, bool output)
|
|
{
|
|
uint16_t mask = 256 << n;
|
|
|
|
if (output)
|
|
misc_regs->gpio.oe_out |= mask;
|
|
else
|
|
misc_regs->gpio.oe_out &= ~mask;
|
|
}
|
|
|
|
void
|
|
gpio_out(int n, bool val)
|
|
{
|
|
uint16_t mask = 1 << n;
|
|
|
|
if (val)
|
|
misc_regs->gpio.oe_out |= mask;
|
|
else
|
|
misc_regs->gpio.oe_out &= ~mask;
|
|
}
|
|
|
|
bool
|
|
gpio_in(int n)
|
|
{
|
|
return (misc_regs->gpio.in & (1 << n)) != 0;
|
|
}
|
|
|
|
|
|
void
|
|
e1_led_run(void)
|
|
{
|
|
misc_regs->e1_led |= 0x100;
|
|
}
|
|
|
|
void
|
|
e1_led_pause(void)
|
|
{
|
|
misc_regs->e1_led &= 0xff;
|
|
}
|
|
|
|
void
|
|
e1_led_set(bool enable, uint8_t cfg)
|
|
{
|
|
misc_regs->e1_led = (enable ? 0x100 : 0x000) | cfg;
|
|
}
|
|
|
|
void
|
|
e1_platform_led_set(int port, enum e1_platform_led led,
|
|
enum e1_platform_led_state state)
|
|
{
|
|
uint32_t tmp;
|
|
unsigned int shift;
|
|
|
|
if (port >= 2)
|
|
return;
|
|
|
|
shift = 4*port + 2*led;
|
|
|
|
tmp = misc_regs->e1_led;
|
|
tmp &= ~(3 << shift);
|
|
tmp |= ((state & 3) << shift);
|
|
misc_regs->e1_led = tmp;
|
|
}
|
|
|
|
|
|
uint16_t
|
|
e1_tick_read(int port)
|
|
{
|
|
return misc_regs->e1_tick[port].tx;
|
|
}
|
|
|
|
|
|
bool
|
|
time_elapsed(uint32_t ref, unsigned int tick)
|
|
{
|
|
return ((misc_regs->time.now - ref) & 0x7fffffff) >= tick;
|
|
}
|
|
|
|
void
|
|
delay(unsigned int ms)
|
|
{
|
|
uint32_t ref = misc_regs->time.now;
|
|
ms *= SYS_CLK_FREQ / 1000;
|
|
while (!time_elapsed(ref, ms));
|
|
}
|
|
|
|
uint32_t
|
|
time_pps_read(void)
|
|
{
|
|
return misc_regs->time.pps;
|
|
}
|
|
|
|
uint32_t
|
|
time_now_read(void)
|
|
{
|
|
return misc_regs->time.now;
|
|
}
|
|
|
|
|
|
void
|
|
reboot(int fw)
|
|
{
|
|
misc_regs->warmboot = (1 << 2) | (fw << 0);
|
|
}
|