linux/drivers/media/pci/cobalt/cobalt-cpld.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Cobalt CPLD functions
   4 *
   5 *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
   6 *  All rights reserved.
   7 */
   8
   9#include <linux/delay.h>
  10
  11#include "cobalt-cpld.h"
  12
  13#define ADRS(offset) (COBALT_BUS_CPLD_BASE + offset)
  14
  15static u16 cpld_read(struct cobalt *cobalt, u32 offset)
  16{
  17        return cobalt_bus_read32(cobalt->bar1, ADRS(offset));
  18}
  19
  20static void cpld_write(struct cobalt *cobalt, u32 offset, u16 val)
  21{
  22        return cobalt_bus_write32(cobalt->bar1, ADRS(offset), val);
  23}
  24
  25static void cpld_info_ver3(struct cobalt *cobalt)
  26{
  27        u32 rd;
  28        u32 tmp;
  29
  30        cobalt_info("CPLD System control register (read/write)\n");
  31        cobalt_info("\t\tSystem control:  0x%04x (0x0f00)\n",
  32                    cpld_read(cobalt, 0));
  33        cobalt_info("CPLD Clock control register (read/write)\n");
  34        cobalt_info("\t\tClock control:   0x%04x (0x0000)\n",
  35                    cpld_read(cobalt, 0x04));
  36        cobalt_info("CPLD HSMA Clk Osc register (read/write) - Must set wr trigger to load default values\n");
  37        cobalt_info("\t\tRegister #7:\t0x%04x (0x0022)\n",
  38                    cpld_read(cobalt, 0x08));
  39        cobalt_info("\t\tRegister #8:\t0x%04x (0x0047)\n",
  40                    cpld_read(cobalt, 0x0c));
  41        cobalt_info("\t\tRegister #9:\t0x%04x (0x00fa)\n",
  42                    cpld_read(cobalt, 0x10));
  43        cobalt_info("\t\tRegister #10:\t0x%04x (0x0061)\n",
  44                    cpld_read(cobalt, 0x14));
  45        cobalt_info("\t\tRegister #11:\t0x%04x (0x001e)\n",
  46                    cpld_read(cobalt, 0x18));
  47        cobalt_info("\t\tRegister #12:\t0x%04x (0x0045)\n",
  48                    cpld_read(cobalt, 0x1c));
  49        cobalt_info("\t\tRegister #135:\t0x%04x\n",
  50                    cpld_read(cobalt, 0x20));
  51        cobalt_info("\t\tRegister #137:\t0x%04x\n",
  52                    cpld_read(cobalt, 0x24));
  53        cobalt_info("CPLD System status register (read only)\n");
  54        cobalt_info("\t\tSystem status:  0x%04x\n",
  55                    cpld_read(cobalt, 0x28));
  56        cobalt_info("CPLD MAXII info register (read only)\n");
  57        cobalt_info("\t\tBoard serial number:     0x%04x\n",
  58                    cpld_read(cobalt, 0x2c));
  59        cobalt_info("\t\tMAXII program revision:  0x%04x\n",
  60                    cpld_read(cobalt, 0x30));
  61        cobalt_info("CPLD temp and voltage ADT7411 registers (read only)\n");
  62        cobalt_info("\t\tBoard temperature:  %u Celsius\n",
  63                    cpld_read(cobalt, 0x34) / 4);
  64        cobalt_info("\t\tFPGA temperature:   %u Celsius\n",
  65                    cpld_read(cobalt, 0x38) / 4);
  66        rd = cpld_read(cobalt, 0x3c);
  67        tmp = (rd * 33 * 1000) / (483 * 10);
  68        cobalt_info("\t\tVDD 3V3:      %u,%03uV\n", tmp / 1000, tmp % 1000);
  69        rd = cpld_read(cobalt, 0x40);
  70        tmp = (rd * 74 * 2197) / (27 * 1000);
  71        cobalt_info("\t\tADC ch3 5V:   %u,%03uV\n", tmp / 1000, tmp % 1000);
  72        rd = cpld_read(cobalt, 0x44);
  73        tmp = (rd * 74 * 2197) / (47 * 1000);
  74        cobalt_info("\t\tADC ch4 3V:   %u,%03uV\n", tmp / 1000, tmp % 1000);
  75        rd = cpld_read(cobalt, 0x48);
  76        tmp = (rd * 57 * 2197) / (47 * 1000);
  77        cobalt_info("\t\tADC ch5 2V5:  %u,%03uV\n", tmp / 1000, tmp % 1000);
  78        rd = cpld_read(cobalt, 0x4c);
  79        tmp = (rd * 2197) / 1000;
  80        cobalt_info("\t\tADC ch6 1V8:  %u,%03uV\n", tmp / 1000, tmp % 1000);
  81        rd = cpld_read(cobalt, 0x50);
  82        tmp = (rd * 2197) / 1000;
  83        cobalt_info("\t\tADC ch7 1V5:  %u,%03uV\n", tmp / 1000, tmp % 1000);
  84        rd = cpld_read(cobalt, 0x54);
  85        tmp = (rd * 2197) / 1000;
  86        cobalt_info("\t\tADC ch8 0V9:  %u,%03uV\n", tmp / 1000, tmp % 1000);
  87}
  88
  89void cobalt_cpld_status(struct cobalt *cobalt)
  90{
  91        u32 rev = cpld_read(cobalt, 0x30);
  92
  93        switch (rev) {
  94        case 3:
  95        case 4:
  96        case 5:
  97                cpld_info_ver3(cobalt);
  98                break;
  99        default:
 100                cobalt_info("CPLD revision %u is not supported!\n", rev);
 101                break;
 102        }
 103}
 104
 105#define DCO_MIN 4850000000ULL
 106#define DCO_MAX 5670000000ULL
 107
 108#define SI570_CLOCK_CTRL   0x04
 109#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER 0x200
 110#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER 0x100
 111#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL 0x80
 112#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN 0x40
 113
 114#define SI570_REG7   0x08
 115#define SI570_REG8   0x0c
 116#define SI570_REG9   0x10
 117#define SI570_REG10  0x14
 118#define SI570_REG11  0x18
 119#define SI570_REG12  0x1c
 120#define SI570_REG135 0x20
 121#define SI570_REG137 0x24
 122
 123struct multiplier {
 124        unsigned mult, hsdiv, n1;
 125};
 126
 127/* List all possible multipliers (= hsdiv * n1). There are lots of duplicates,
 128   which are all removed in this list to keep the list as short as possible.
 129   The values for hsdiv and n1 are the actual values, not the register values.
 130 */
 131static const struct multiplier multipliers[] = {
 132        {    4,  4,   1 }, {    5,  5,   1 }, {    6,  6,   1 },
 133        {    7,  7,   1 }, {    8,  4,   2 }, {    9,  9,   1 },
 134        {   10,  5,   2 }, {   11, 11,   1 }, {   12,  6,   2 },
 135        {   14,  7,   2 }, {   16,  4,   4 }, {   18,  9,   2 },
 136        {   20,  5,   4 }, {   22, 11,   2 }, {   24,  4,   6 },
 137        {   28,  7,   4 }, {   30,  5,   6 }, {   32,  4,   8 },
 138        {   36,  6,   6 }, {   40,  4,  10 }, {   42,  7,   6 },
 139        {   44, 11,   4 }, {   48,  4,  12 }, {   50,  5,  10 },
 140        {   54,  9,   6 }, {   56,  4,  14 }, {   60,  5,  12 },
 141        {   64,  4,  16 }, {   66, 11,   6 }, {   70,  5,  14 },
 142        {   72,  4,  18 }, {   80,  4,  20 }, {   84,  6,  14 },
 143        {   88, 11,   8 }, {   90,  5,  18 }, {   96,  4,  24 },
 144        {   98,  7,  14 }, {  100,  5,  20 }, {  104,  4,  26 },
 145        {  108,  6,  18 }, {  110, 11,  10 }, {  112,  4,  28 },
 146        {  120,  4,  30 }, {  126,  7,  18 }, {  128,  4,  32 },
 147        {  130,  5,  26 }, {  132, 11,  12 }, {  136,  4,  34 },
 148        {  140,  5,  28 }, {  144,  4,  36 }, {  150,  5,  30 },
 149        {  152,  4,  38 }, {  154, 11,  14 }, {  156,  6,  26 },
 150        {  160,  4,  40 }, {  162,  9,  18 }, {  168,  4,  42 },
 151        {  170,  5,  34 }, {  176, 11,  16 }, {  180,  5,  36 },
 152        {  182,  7,  26 }, {  184,  4,  46 }, {  190,  5,  38 },
 153        {  192,  4,  48 }, {  196,  7,  28 }, {  198, 11,  18 },
 154        {  198,  9,  22 }, {  200,  4,  50 }, {  204,  6,  34 },
 155        {  208,  4,  52 }, {  210,  5,  42 }, {  216,  4,  54 },
 156        {  220, 11,  20 }, {  224,  4,  56 }, {  228,  6,  38 },
 157        {  230,  5,  46 }, {  232,  4,  58 }, {  234,  9,  26 },
 158        {  238,  7,  34 }, {  240,  4,  60 }, {  242, 11,  22 },
 159        {  248,  4,  62 }, {  250,  5,  50 }, {  252,  6,  42 },
 160        {  256,  4,  64 }, {  260,  5,  52 }, {  264, 11,  24 },
 161        {  266,  7,  38 }, {  270,  5,  54 }, {  272,  4,  68 },
 162        {  276,  6,  46 }, {  280,  4,  70 }, {  286, 11,  26 },
 163        {  288,  4,  72 }, {  290,  5,  58 }, {  294,  7,  42 },
 164        {  296,  4,  74 }, {  300,  5,  60 }, {  304,  4,  76 },
 165        {  306,  9,  34 }, {  308, 11,  28 }, {  310,  5,  62 },
 166        {  312,  4,  78 }, {  320,  4,  80 }, {  322,  7,  46 },
 167        {  324,  6,  54 }, {  328,  4,  82 }, {  330, 11,  30 },
 168        {  336,  4,  84 }, {  340,  5,  68 }, {  342,  9,  38 },
 169        {  344,  4,  86 }, {  348,  6,  58 }, {  350,  5,  70 },
 170        {  352, 11,  32 }, {  360,  4,  90 }, {  364,  7,  52 },
 171        {  368,  4,  92 }, {  370,  5,  74 }, {  372,  6,  62 },
 172        {  374, 11,  34 }, {  376,  4,  94 }, {  378,  7,  54 },
 173        {  380,  5,  76 }, {  384,  4,  96 }, {  390,  5,  78 },
 174        {  392,  4,  98 }, {  396, 11,  36 }, {  400,  4, 100 },
 175        {  406,  7,  58 }, {  408,  4, 102 }, {  410,  5,  82 },
 176        {  414,  9,  46 }, {  416,  4, 104 }, {  418, 11,  38 },
 177        {  420,  5,  84 }, {  424,  4, 106 }, {  430,  5,  86 },
 178        {  432,  4, 108 }, {  434,  7,  62 }, {  440, 11,  40 },
 179        {  444,  6,  74 }, {  448,  4, 112 }, {  450,  5,  90 },
 180        {  456,  4, 114 }, {  460,  5,  92 }, {  462, 11,  42 },
 181        {  464,  4, 116 }, {  468,  6,  78 }, {  470,  5,  94 },
 182        {  472,  4, 118 }, {  476,  7,  68 }, {  480,  4, 120 },
 183        {  484, 11,  44 }, {  486,  9,  54 }, {  488,  4, 122 },
 184        {  490,  5,  98 }, {  492,  6,  82 }, {  496,  4, 124 },
 185        {  500,  5, 100 }, {  504,  4, 126 }, {  506, 11,  46 },
 186        {  510,  5, 102 }, {  512,  4, 128 }, {  516,  6,  86 },
 187        {  518,  7,  74 }, {  520,  5, 104 }, {  522,  9,  58 },
 188        {  528, 11,  48 }, {  530,  5, 106 }, {  532,  7,  76 },
 189        {  540,  5, 108 }, {  546,  7,  78 }, {  550, 11,  50 },
 190        {  552,  6,  92 }, {  558,  9,  62 }, {  560,  5, 112 },
 191        {  564,  6,  94 }, {  570,  5, 114 }, {  572, 11,  52 },
 192        {  574,  7,  82 }, {  576,  6,  96 }, {  580,  5, 116 },
 193        {  588,  6,  98 }, {  590,  5, 118 }, {  594, 11,  54 },
 194        {  600,  5, 120 }, {  602,  7,  86 }, {  610,  5, 122 },
 195        {  612,  6, 102 }, {  616, 11,  56 }, {  620,  5, 124 },
 196        {  624,  6, 104 }, {  630,  5, 126 }, {  636,  6, 106 },
 197        {  638, 11,  58 }, {  640,  5, 128 }, {  644,  7,  92 },
 198        {  648,  6, 108 }, {  658,  7,  94 }, {  660, 11,  60 },
 199        {  666,  9,  74 }, {  672,  6, 112 }, {  682, 11,  62 },
 200        {  684,  6, 114 }, {  686,  7,  98 }, {  696,  6, 116 },
 201        {  700,  7, 100 }, {  702,  9,  78 }, {  704, 11,  64 },
 202        {  708,  6, 118 }, {  714,  7, 102 }, {  720,  6, 120 },
 203        {  726, 11,  66 }, {  728,  7, 104 }, {  732,  6, 122 },
 204        {  738,  9,  82 }, {  742,  7, 106 }, {  744,  6, 124 },
 205        {  748, 11,  68 }, {  756,  6, 126 }, {  768,  6, 128 },
 206        {  770, 11,  70 }, {  774,  9,  86 }, {  784,  7, 112 },
 207        {  792, 11,  72 }, {  798,  7, 114 }, {  810,  9,  90 },
 208        {  812,  7, 116 }, {  814, 11,  74 }, {  826,  7, 118 },
 209        {  828,  9,  92 }, {  836, 11,  76 }, {  840,  7, 120 },
 210        {  846,  9,  94 }, {  854,  7, 122 }, {  858, 11,  78 },
 211        {  864,  9,  96 }, {  868,  7, 124 }, {  880, 11,  80 },
 212        {  882,  7, 126 }, {  896,  7, 128 }, {  900,  9, 100 },
 213        {  902, 11,  82 }, {  918,  9, 102 }, {  924, 11,  84 },
 214        {  936,  9, 104 }, {  946, 11,  86 }, {  954,  9, 106 },
 215        {  968, 11,  88 }, {  972,  9, 108 }, {  990, 11,  90 },
 216        { 1008,  9, 112 }, { 1012, 11,  92 }, { 1026,  9, 114 },
 217        { 1034, 11,  94 }, { 1044,  9, 116 }, { 1056, 11,  96 },
 218        { 1062,  9, 118 }, { 1078, 11,  98 }, { 1080,  9, 120 },
 219        { 1098,  9, 122 }, { 1100, 11, 100 }, { 1116,  9, 124 },
 220        { 1122, 11, 102 }, { 1134,  9, 126 }, { 1144, 11, 104 },
 221        { 1152,  9, 128 }, { 1166, 11, 106 }, { 1188, 11, 108 },
 222        { 1210, 11, 110 }, { 1232, 11, 112 }, { 1254, 11, 114 },
 223        { 1276, 11, 116 }, { 1298, 11, 118 }, { 1320, 11, 120 },
 224        { 1342, 11, 122 }, { 1364, 11, 124 }, { 1386, 11, 126 },
 225        { 1408, 11, 128 },
 226};
 227
 228bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out)
 229{
 230        const unsigned f_xtal = 39170000;       /* xtal for si598 */
 231        u64 dco;
 232        u64 rfreq;
 233        unsigned delta = 0xffffffff;
 234        unsigned i_best = 0;
 235        unsigned i;
 236        u8 n1, hsdiv;
 237        u8 regs[6];
 238        int found = 0;
 239        u16 clock_ctrl;
 240        int retries = 3;
 241
 242        for (i = 0; i < ARRAY_SIZE(multipliers); i++) {
 243                unsigned mult = multipliers[i].mult;
 244                u32 d;
 245
 246                dco = (u64)f_out * mult;
 247                if (dco < DCO_MIN || dco > DCO_MAX)
 248                        continue;
 249                div_u64_rem((dco << 28) + f_xtal / 2, f_xtal, &d);
 250                if (d < delta) {
 251                        found = 1;
 252                        i_best = i;
 253                        delta = d;
 254                }
 255        }
 256        if (!found)
 257                return false;
 258        dco = (u64)f_out * multipliers[i_best].mult;
 259        n1 = multipliers[i_best].n1 - 1;
 260        hsdiv = multipliers[i_best].hsdiv - 4;
 261        rfreq = div_u64(dco << 28, f_xtal);
 262
 263        clock_ctrl = cpld_read(cobalt, SI570_CLOCK_CTRL);
 264        clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL;
 265        clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN;
 266
 267        regs[0] = (hsdiv << 5) | (n1 >> 2);
 268        regs[1] = ((n1 & 0x3) << 6) | (rfreq >> 32);
 269        regs[2] = (rfreq >> 24) & 0xff;
 270        regs[3] = (rfreq >> 16) & 0xff;
 271        regs[4] = (rfreq >> 8) & 0xff;
 272        regs[5] = rfreq & 0xff;
 273
 274        /* The sequence of clock_ctrl flags to set is very weird. It looks
 275           like I have to reset it, then set the new frequency and reset it
 276           again. It shouldn't be necessary to do a reset, but if I don't,
 277           then a strange frequency is set (156.412034 MHz, or register values
 278           0x01, 0xc7, 0xfc, 0x7f, 0x53, 0x62).
 279         */
 280
 281        cobalt_dbg(1, "%u: %6ph\n", f_out, regs);
 282
 283        while (retries--) {
 284                u8 read_regs[6];
 285
 286                cpld_write(cobalt, SI570_CLOCK_CTRL,
 287                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN |
 288                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL);
 289                usleep_range(10000, 15000);
 290                cpld_write(cobalt, SI570_REG7, regs[0]);
 291                cpld_write(cobalt, SI570_REG8, regs[1]);
 292                cpld_write(cobalt, SI570_REG9, regs[2]);
 293                cpld_write(cobalt, SI570_REG10, regs[3]);
 294                cpld_write(cobalt, SI570_REG11, regs[4]);
 295                cpld_write(cobalt, SI570_REG12, regs[5]);
 296                cpld_write(cobalt, SI570_CLOCK_CTRL,
 297                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN |
 298                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER);
 299                usleep_range(10000, 15000);
 300                cpld_write(cobalt, SI570_CLOCK_CTRL,
 301                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN |
 302                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL);
 303                usleep_range(10000, 15000);
 304                read_regs[0] = cpld_read(cobalt, SI570_REG7);
 305                read_regs[1] = cpld_read(cobalt, SI570_REG8);
 306                read_regs[2] = cpld_read(cobalt, SI570_REG9);
 307                read_regs[3] = cpld_read(cobalt, SI570_REG10);
 308                read_regs[4] = cpld_read(cobalt, SI570_REG11);
 309                read_regs[5] = cpld_read(cobalt, SI570_REG12);
 310                cpld_write(cobalt, SI570_CLOCK_CTRL,
 311                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN |
 312                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL |
 313                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER);
 314                usleep_range(10000, 15000);
 315                cpld_write(cobalt, SI570_CLOCK_CTRL,
 316                        S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN);
 317                usleep_range(10000, 15000);
 318
 319                if (!memcmp(read_regs, regs, sizeof(read_regs)))
 320                        break;
 321                cobalt_dbg(1, "retry: %6ph\n", read_regs);
 322        }
 323        if (2 - retries)
 324                cobalt_info("Needed %d retries\n", 2 - retries);
 325
 326        return true;
 327}
 328