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 "../../arch/arm/clock.h"
14#include "../../common.h"
15
16#define MXO_SRC_CLK_INV    (1U << 12)
17#define MXO_SRC_BRANCH_ENA (1U << 11)
18#define PXO_SRC_CLK_INV    (1U << 10)
19#define PXO_SRC_BRANCH_ENA (1U <<  9)
20#define CLK_INV            (1U <<  5)
21#define CLK_BRANCH_ENA     (1U <<  4)
22#define SRC_SEL            (1U <<  0)
23#define SRC_SEL_PXO        (0U <<  0)
24#define SRC_SEL_MXO        (1U <<  0)
25#define PPSS_TIMER0_CLK_CTL 0x0090258C
26#define PPSS_TIMER1_CLK_CTL 0x00902590
27
28#define REG_READ(base, offset)     *(uint32_t*)((uintptr_t)base + (offset))
29#define REG_WRITE(base, offset, v) *(uint32_t*)((uintptr_t)base + (offset)) = v
30
31struct clock_sys_regs {
32    void* block0;
33    void* block1;
34    void* block2;
35    void* block3;
36};
37
38struct clock_sys_regs clk_sys_regs;
39
40static inline uint32_t reg_read(uintptr_t addr)
41{
42    uint32_t* reg;
43    switch (addr & 0x3000) {
44    case 0x0000:
45        reg = (uint32_t*)clk_sys_regs.block0;
46        break;
47    case 0x1000:
48        reg = (uint32_t*)clk_sys_regs.block1;
49        break;
50    case 0x2000:
51        reg = (uint32_t*)clk_sys_regs.block2;
52        break;
53    case 0x3000:
54        reg = (uint32_t*)clk_sys_regs.block3;
55        break;
56    default:
57        printf("Invalid memory access: 0x%x\n", (uint32_t)addr);
58        return 0;
59    }
60
61    if (addr & 0x3) {
62        printf("Unaligned memory access: 0x%x\n", (uint32_t)addr);
63    }
64    addr &= 0xfff;
65    addr /= 4;
66    return reg[addr];
67}
68
69static inline void reg_write(uintptr_t addr, uint32_t v)
70{
71    uint32_t* reg;
72    switch (addr & 0x3000) {
73    case 0x0000:
74        reg = (uint32_t*)clk_sys_regs.block0;
75        break;
76    case 0x1000:
77        reg = (uint32_t*)clk_sys_regs.block1;
78        break;
79    case 0x2000:
80        reg = (uint32_t*)clk_sys_regs.block2;
81        break;
82    case 0x3000:
83        reg = (uint32_t*)clk_sys_regs.block3;
84        break;
85    default:
86        printf("Invalid memory access: 0x%x\n", (uint32_t)addr);
87        return;
88    }
89
90    if (addr & 0x3) {
91        printf("Unaligned memory access: 0x%x\n", (uint32_t)addr);
92    }
93    addr &= 0xfff;
94    addr /= 4;
95    reg[addr] = v;
96}
97
98void test(void)
99{
100    reg_write(PPSS_TIMER0_CLK_CTL, CLK_BRANCH_ENA);
101    reg_write(PPSS_TIMER1_CLK_CTL, CLK_BRANCH_ENA);
102}
103
104static struct clock master_clk = { CLK_OPS_DEFAULT(MASTER) };
105static struct clock pxo_clk    = { CLK_OPS_DEFAULT(PXO)    };
106static struct clock tcxo_clk   = { CLK_OPS_DEFAULT(TCXO)   };
107static struct clock wcnxo_clk  = { CLK_OPS_DEFAULT(WCNXO)  };
108static struct clock slpxo_clk  = { CLK_OPS_DEFAULT(SLPXO)  };
109
110static int
111apq8064_gate_enable(clock_sys_t* sys, enum clock_gate gate, enum clock_gate_mode mode)
112{
113    (void)sys;
114    (void)gate;
115    (void)mode;
116    return 0;
117}
118
119void
120clk_print_clock_tree(clock_sys_t* sys)
121{
122    clk_t *clk = clk_get_clock(sys, CLK_MASTER);
123    clk_print_tree(clk, "");
124}
125
126static int apq8064_clock_sys_init_common(clock_sys_t* clk_sys)
127{
128    clk_sys->gate_enable = &apq8064_gate_enable;
129    clk_sys->get_clock = &ps_get_clock;
130    return 0;
131}
132
133int
134clock_sys_init(ps_io_ops_t* io_ops, clock_sys_t* clk_sys)
135{
136    struct clock_sys_regs* d = &clk_sys_regs;
137    MAP_IF_NULL(io_ops, APQ8064_CLK_CTL0, d->block0);
138    MAP_IF_NULL(io_ops, APQ8064_CLK_CTL1, d->block1);
139    MAP_IF_NULL(io_ops, APQ8064_CLK_CTL2, d->block2);
140    MAP_IF_NULL(io_ops, APQ8064_CLK_CTL3, d->block3);
141    clk_sys->priv = d;
142    return 0;
143}
144
145int
146apq8064_clock_sys_init(void* clk_ctl_base0, void* clk_ctl_base1,
147                       void* clk_ctl_base2, void* clk_ctl_base3,
148                       clock_sys_t* clk_sys)
149{
150    struct clock_sys_regs* d = &clk_sys_regs;
151    if (clk_ctl_base0) {
152        d->block0 = clk_ctl_base0;
153    }
154    if (clk_ctl_base1) {
155        d->block1 = clk_ctl_base1;
156    }
157    if (clk_ctl_base2) {
158        d->block2 = clk_ctl_base2;
159    }
160    if (clk_ctl_base3) {
161        d->block3 = clk_ctl_base3;
162    }
163    clk_sys->priv = d;
164    return apq8064_clock_sys_init_common(clk_sys);
165}
166
167clk_t* ps_clocks[] = {
168    [CLK_MASTER]   = &master_clk,
169    [CLK_PXO   ]   = &pxo_clk,
170    [CLK_WCNXO ]   = &wcnxo_clk,
171    [CLK_TCXO  ]   = &tcxo_clk,
172    [CLK_SLPXO ]   = &slpxo_clk
173};
174
175freq_t ps_freq_default[] = {
176    [CLK_MASTER]   = 24 * MHZ,
177    [CLK_PXO   ]   = 27 * MHZ,
178    [CLK_WCNXO ]   = 48 * MHZ,
179    [CLK_TCXO  ]   = 19200 * KHZ,
180    [CLK_SLPXO ]   = 32768
181};
182