uboot/arch/arm/mach-mvebu/alleycat5/soc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Marvell International Ltd.
   4 */
   5
   6#include <common.h>
   7#include <asm/arch-armada8k/cache_llc.h>
   8#include <asm/io.h>
   9#include <asm/arch/cpu.h>
  10#include <asm/arch/soc.h>
  11#include <dm/device.h>
  12
  13#define DEVICE_ID_REG                   0x7F90004C
  14#define DEVICE_ID_MASK                  0xffff0
  15#define REV_ID_MASK                     0xf
  16#define DEVICE_ID_OFFSET                4
  17#define REV_ID_OFFSET                   0
  18
  19#define DEVICE_SAR_REG                  0x944F8204
  20
  21#define DEVICE_ID_SUB_REV               (MVEBU_REGISTER(0x2400230))
  22#define DEVICE_ID_SUB_REV_OFFSET        7
  23#define DEVICE_ID_SUB_REV_MASK          (0xffff << DEVICE_ID_SUB_REV_OFFSET)
  24
  25#define AC5X_DEV_ID                     0x9800
  26
  27struct soc_info {
  28        u32 dev_id;
  29        u32 rev_id;
  30        char *soc_name;
  31};
  32
  33static struct soc_info soc_info_table[] = {
  34        /* Two reserved entries for unidentified devices - don't change */
  35        { 0xB4FF, 0x0, "Unidentified Alleycat5"},
  36        { 0x98FF, 0x0, "Unidentified Alleycat5x"},
  37
  38        { 0xB400, 0x2, "Alleycat5-plus  98DX2538-A2"},
  39        { 0xB401, 0x2, "Alleycat5-plus  98DX2535-A2"},
  40        { 0xB402, 0x2, "Alleycat5-plus  98DX2532-A2"},
  41        { 0xB403, 0x2, "Alleycat5-plus  98DX2531-A2"},
  42        { 0xB408, 0x2, "Alleycat5  98DX2528-A2"},
  43        { 0xB409, 0x2, "Alleycat5  98DX2525-A2"},
  44        { 0xB40A, 0x2, "Alleycat5  98DX2522-A2"},
  45        { 0xB40B, 0x2, "Alleycat5  98DX2521-A2"},
  46        { 0xB410, 0x2, "Alleycat5-lite  98DX2518-A2"},
  47        { 0xB411, 0x2, "Alleycat5-lite  98DX2515-A2"},
  48        { 0xB412, 0x2, "Alleycat5-lite  98DX2512-A2"},
  49        { 0xB413, 0x2, "Alleycat5-lite  98DX2511-A2"},
  50
  51        { 0xB400, 0x1, "Alleycat5-plus  98DX2538-A1"},
  52        { 0xB401, 0x1, "Alleycat5-plus  98DX2535-A1"},
  53        { 0xB402, 0x1, "Alleycat5-plus  98DX2532-A1"},
  54        { 0xB403, 0x1, "Alleycat5-plus  98DX2531-A1"},
  55        { 0xB408, 0x1, "Alleycat5  98DX2528-A1"},
  56        { 0xB409, 0x1, "Alleycat5  98DX2525-A1"},
  57        { 0xB40A, 0x1, "Alleycat5  98DX2522-A1"},
  58        { 0xB40B, 0x1, "Alleycat5  98DX2521-A1"},
  59        { 0xB410, 0x1, "Alleycat5-lite  98DX2518-A1"},
  60        { 0xB411, 0x1, "Alleycat5-lite  98DX2515-A1"},
  61        { 0xB412, 0x1, "Alleycat5-lite  98DX2512-A1"},
  62        { 0xB413, 0x1, "Alleycat5-lite  98DX2511-A1"},
  63        { 0x9800, 0x1, "Alleycat5X 98DX3500M-A1"},
  64        { 0x9806, 0x1, "Alleycat5X 98DX3501M-A1"},
  65        { 0x9801, 0x1, "Alleycat5X 98DX3510M-A1"},
  66        { 0x9802, 0x1, "Alleycat5X 98DX3520M-A1"},
  67        { 0x9803, 0x1, "Alleycat5X 98DX3530M-A1"},
  68        { 0x9804, 0x1, "Alleycat5X 98DX3540M-A1"},
  69        { 0x9805, 0x1, "Alleycat5X 98DX3550M-A1"},
  70        { 0x9820, 0x1, "Alleycat5X 98DX3500-A1"},
  71        { 0x9826, 0x1, "Alleycat5X 98DX3501-A1"},
  72        { 0x9821, 0x1, "Alleycat5X 98DX3510-A1"},
  73        { 0x9861, 0x1, "Alleycat5X 98DX3510H-A1"},
  74        { 0x9841, 0x1, "Alleycat5X 98DX3510MH-A1"},
  75        { 0x9822, 0x1, "Alleycat5X 98DX3520-A1"},
  76        { 0x9823, 0x1, "Alleycat5X 98DX3530-A1"},
  77        { 0x9863, 0x1, "Alleycat5X 98DX3530H-A1"},
  78        { 0x9824, 0x1, "Alleycat5X 98DX3540-A1"},
  79        { 0x9825, 0x1, "Alleycat5X 98DX3550-A1"},
  80
  81        { 0xB400, 0x0, "Alleycat5-plus  98DX2538-A0"},
  82        { 0xB401, 0x0, "Alleycat5-plus  98DX2535-A0"},
  83        { 0xB402, 0x0, "Alleycat5-plus  98DX2532-A0"},
  84        { 0xB403, 0x0, "Alleycat5-plus  98DX2531-A0"},
  85        { 0xB408, 0x0, "Alleycat5  98DX2528-A0"},
  86        { 0xB409, 0x0, "Alleycat5  98DX2525-A0"},
  87        { 0xB40A, 0x0, "Alleycat5  98DX2522-A0"},
  88        { 0xB40B, 0x0, "Alleycat5  98DX2521-A0"},
  89        { 0xB410, 0x0, "Alleycat5-lite  98DX2518-A0"},
  90        { 0xB411, 0x0, "Alleycat5-lite  98DX2515-A0"},
  91        { 0xB412, 0x0, "Alleycat5-lite  98DX2512-A0"},
  92        { 0xB413, 0x0, "Alleycat5-lite  98DX2511-A0"},
  93        { 0x9800, 0x0, "Alleycat5X 98DX3500M-A0"},
  94        { 0x9806, 0x0, "Alleycat5X 98DX3501M-A0"},
  95        { 0x9801, 0x0, "Alleycat5X 98DX3510M-A0"},
  96        { 0x9802, 0x0, "Alleycat5X 98DX3520M-A0"},
  97        { 0x9803, 0x0, "Alleycat5X 98DX3530M-A0"},
  98        { 0x9804, 0x0, "Alleycat5X 98DX3540M-A0"},
  99        { 0x9805, 0x0, "Alleycat5X 98DX3550M-A0"},
 100        { 0x9820, 0x0, "Alleycat5X 98DX3500-A0"},
 101        { 0x9826, 0x0, "Alleycat5X 98DX3501-A0"},
 102        { 0x9821, 0x0, "Alleycat5X 98DX3510-A0"},
 103        { 0x9861, 0x0, "Alleycat5X 98DX3510H-A0"},
 104        { 0x9841, 0x0, "Alleycat5X 98DX3510MH-A0"},
 105        { 0x9822, 0x0, "Alleycat5X 98DX3520-A0"},
 106        { 0x9823, 0x0, "Alleycat5X 98DX3530-A0"},
 107        { 0x9863, 0x0, "Alleycat5X 98DX3530H-A0"},
 108        { 0x9824, 0x0, "Alleycat5X 98DX3540-A0"},
 109        { 0x9825, 0x0, "Alleycat5X 98DX3550-A0"},
 110};
 111
 112#define BIT_VAL(b)          ((1ULL << ((b) + 1)) - 1)
 113#define BIT_RANGE(bl, bh)   (BIT_VAL(bh) - BIT_VAL((bl) - 1))
 114
 115#define PLL_MAX_CHOICE  4
 116
 117#define CPU_TYPE_AC5    0
 118#define CPU_TYPE_AC5x   1
 119#define CPU_TYPE_LAST   2
 120
 121enum mvebu_sar_opts {
 122        SAR_CPU_FREQ = 0,
 123        SAR_DDR_FREQ,
 124        SAR_AP_FABRIC_FREQ,
 125        SAR_CP_FABRIC_FREQ,
 126        SAR_CP0_PCIE0_CLK,
 127        SAR_CP0_PCIE1_CLK,
 128        SAR_CP1_PCIE0_CLK,
 129        SAR_CP1_PCIE1_CLK,
 130        SAR_BOOT_SRC,
 131        SAR_MAX_IDX
 132};
 133
 134static const u32 pll_freq_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1][PLL_MAX_CHOICE] = {
 135        [CPU_TYPE_AC5] = {
 136                [SAR_CPU_FREQ] = {
 137                        800, 1200, 1400, 1000
 138                },
 139                [SAR_DDR_FREQ] = {
 140                        1200, 800, 0, 0
 141                },
 142                [SAR_AP_FABRIC_FREQ] = {
 143                        396, 290, 197, 0
 144                },
 145        },
 146        [CPU_TYPE_AC5x] = {
 147                [SAR_CPU_FREQ] = {
 148                        800, 1200, 1500, 1600
 149                },
 150                [SAR_DDR_FREQ] = {
 151                        1200, 800, 0, 0
 152                },
 153                [SAR_AP_FABRIC_FREQ] = {
 154                        0, 0, 0, 0
 155                }
 156        }
 157};
 158
 159static const u32 soc_sar_masks_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1] = {
 160        [CPU_TYPE_AC5] = {
 161                [SAR_CPU_FREQ] = BIT_RANGE(18, 20),
 162                [SAR_DDR_FREQ] = BIT_RANGE(16, 17),
 163                [SAR_AP_FABRIC_FREQ] = BIT_RANGE(22, 23),
 164        },
 165        [CPU_TYPE_AC5x] = {
 166                [SAR_CPU_FREQ] = BIT_RANGE(8, 10),
 167                [SAR_DDR_FREQ] = BIT_RANGE(6, 7),
 168                [SAR_AP_FABRIC_FREQ] = 1,
 169        },
 170};
 171
 172static int get_soc_type_rev(u32 *type, u32 *rev)
 173{
 174        *type = (readl(DEVICE_ID_REG) & DEVICE_ID_MASK) >> DEVICE_ID_OFFSET;
 175        *rev =  (readl(DEVICE_ID_REG) & REV_ID_MASK)    >> REV_ID_OFFSET;
 176
 177        return 0;
 178}
 179
 180static void get_one_sar_freq(int cpu_type, u32 sar_reg_val, enum mvebu_sar_opts sar_opt, u32 *freq)
 181{
 182        u32 mask;
 183        unsigned char choice;
 184
 185        mask = soc_sar_masks_tbl[cpu_type][sar_opt];
 186        choice = (sar_reg_val & mask) >> (__builtin_ffs(mask) - 1);
 187        *freq = pll_freq_tbl[cpu_type][sar_opt][choice];
 188}
 189
 190void get_sar_freq(struct sar_freq_modes *sar_freq)
 191{
 192        int cpu_type;
 193        u32 soc_type, rev;
 194        u32 sar_reg_val = readl(DEVICE_SAR_REG);
 195
 196        get_soc_type_rev(&soc_type, &rev);
 197        cpu_type = (soc_type & 0xFF00) == AC5X_DEV_ID ? CPU_TYPE_AC5x : CPU_TYPE_AC5;
 198
 199        get_one_sar_freq(cpu_type, sar_reg_val, SAR_CPU_FREQ, &sar_freq->p_clk);
 200        get_one_sar_freq(cpu_type, sar_reg_val, SAR_AP_FABRIC_FREQ, &sar_freq->nb_clk);
 201        get_one_sar_freq(cpu_type, sar_reg_val, SAR_DDR_FREQ, &sar_freq->d_clk);
 202}
 203
 204static int get_soc_table_index(u32 *index)
 205{
 206        u32 soc_type;
 207        u32 rev, i, ret = 1;
 208
 209        *index = 0;
 210        get_soc_type_rev(&soc_type, &rev);
 211
 212        for (i = 0; i < ARRAY_SIZE(soc_info_table) && ret != 0; i++) {
 213                if (soc_type != soc_info_table[i].dev_id ||
 214                    rev != soc_info_table[i].rev_id)
 215                        continue;
 216
 217                *index = i;
 218                ret = 0;
 219        }
 220
 221        if (ret && ((soc_type & 0xFF00) == AC5X_DEV_ID))
 222                *index = 1;
 223
 224        return ret;
 225}
 226
 227static int get_soc_name(char **soc_name)
 228{
 229        u32 index;
 230
 231        get_soc_table_index(&index);
 232        *soc_name = soc_info_table[index].soc_name;
 233
 234        return 0;
 235}
 236
 237/* Print device's SoC name and AP & CP information */
 238void soc_print_device_info(void)
 239{
 240        char *soc_name = NULL;
 241
 242        get_soc_name(&soc_name);
 243
 244        printf("SoC: %s\n", soc_name);
 245}
 246
 247void soc_print_clock_info(void)
 248{
 249        struct sar_freq_modes sar_freq;
 250
 251        get_sar_freq(&sar_freq);
 252        printf("Clock:  CPU     %4d MHz\n", sar_freq.p_clk);
 253        printf("\tDDR     %4d MHz\n", sar_freq.d_clk);
 254        printf("\tFABRIC  %4d MHz\n", sar_freq.nb_clk);
 255        printf("\tMSS     %4d MHz\n", 200);
 256}
 257
 258/*
 259 * Override of __weak int mach_cpu_init(void) :
 260 * SoC/machine dependent CPU setup
 261 */
 262int mach_cpu_init(void)
 263{
 264        u32 phy_i;
 265        u64 new_val, phy_base = 0x7F080800;
 266
 267        /* Init USB PHY */
 268#define USB_STEPPING    0x20000
 269#define WRITE_MASK(addr, mask, val)             \
 270        { new_val = (readl(addr) & (~(mask))) | (val);\
 271        writel(new_val, addr); }
 272
 273        for (phy_i = 0; phy_i < 2; phy_i++, phy_base += USB_STEPPING) {
 274                WRITE_MASK(phy_base + 0x4,     0x3,        0x2);
 275                WRITE_MASK(phy_base + 0xC,     0x3000000,   0x2000000);
 276                WRITE_MASK(phy_base + 0x1C,    0x3,         0x2);
 277                WRITE_MASK(phy_base + 0x0,     0x1FF007F,   0x600005);
 278                WRITE_MASK(phy_base + 0xC,     0x000F000,   0x0002000);
 279                /* Calibration Threshold Setting = 4*/
 280                WRITE_MASK(phy_base + 0x8,     0x700,      0x400)
 281                WRITE_MASK(phy_base + 0x14,    0x000000F,   0x000000a);
 282                /* Change AMP to 4*/
 283                WRITE_MASK(phy_base + 0xC,     0x3700000,   0x3400000);
 284                WRITE_MASK(phy_base + 0x4,     0x3,        0x3);
 285                /* Impedance calibration triggering is performed by USB probe */
 286        }
 287
 288        return 0;
 289}
 290