1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <stdint.h>
14#include <stdbool.h>
15
16#include <utils/arith.h>
17#include <utils/attribute.h>
18#include <utils/force.h>
19#include <platsupport/io.h>
20
21#include "devcfg.h"
22
23#define XADC_MSTS_CFIFOE    BIT(10)     // XADC Interafce Command FIFO empty
24#define XADCIF_CFG_ENABLE   BIT(31)     // XADC Interface Configuration Enable
25#define XADCIF_MCTL_RESET   BIT(4)      // XADC Interface Miscellaneous Control Reset
26
27/* Constants/macros for formatting commands for the XADC */
28#define XADC_DATA_OFFSET    0
29#define XADC_DATA_MASK      MASK(16)
30
31#define XADC_ADDRESS_OFFSET 16
32#define XADC_ADDRESS_MASK   MASK(10)
33#define XADC_VALID_ADDRESS_MASK MASK(6)
34
35#define XADC_COMMAND_OFFSET 26
36#define XADC_COMMAND_MASK   MASK(4)
37
38#define FORMAT_XADC_COMMAND(command, address, data) (\
39        (((data) & XADC_DATA_MASK) << XADC_DATA_OFFSET) |\
40        (((address) & XADC_ADDRESS_MASK) << XADC_ADDRESS_OFFSET) |\
41        (((command) & XADC_COMMAND_MASK) << XADC_COMMAND_OFFSET))
42
43#define XADC_COMMAND_NOOP   0
44#define XADC_COMMAND_READ   1
45#define XADC_COMMAND_WRITE  2
46
47#define FORMAT_XADC_READ(address) FORMAT_XADC_COMMAND(XADC_COMMAND_READ, address, 0)
48#define XADC_NOOP FORMAT_XADC_COMMAND(XADC_COMMAND_NOOP, 0, 0)
49
50static bool initialized = false;
51
52int xadc_init(ps_io_ops_t* ops) {
53    if (initialized) {
54        return 0;
55    }
56
57    int error = devcfg_init(ops);
58    if (error != 0) {
59        return error;
60    }
61
62    devcfg_regs_t* devcfg_regs = devcfg_get_regs();
63    if (devcfg_regs == NULL) {
64        return -1;
65    }
66
67    devcfg_regs->xadcif_cfg |= XADCIF_CFG_ENABLE;
68    devcfg_regs->xadcif_mctl &= ~XADCIF_MCTL_RESET;
69
70    initialized = true;
71
72    return 0;
73}
74
75uint32_t xadc_read_register(uint32_t address) {
76    devcfg_regs_t* devcfg_regs = devcfg_get_regs();
77
78    // write the command
79    devcfg_regs->xadcif_cmdfifo = FORMAT_XADC_READ(address & XADC_VALID_ADDRESS_MASK);
80
81    // wait for the command to leave the fifo
82    while (!(devcfg_regs->xadcif_msts & XADC_MSTS_CFIFOE));
83
84    // do a dummy read
85    FORCE_READ(&devcfg_regs->xadcif_rdfifo);
86
87    // send a noop to shift the result into rdfifo
88    devcfg_regs->xadcif_cmdfifo = XADC_NOOP;
89
90    // read the result
91    return devcfg_regs->xadcif_rdfifo;
92}
93