system_ab32vgx.c 12.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
/*
 * Copyright (c) 2020-2020, BLUETRUM Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "ab32vgx.h"

#ifndef ALIGN
#define ALIGN(n)                    __attribute__((aligned(n)))
#endif // ALIGN

typedef struct _sys_t {
    uint8_t cnt_1us;             //delay 1us cnt
    uint8_t main_start;          //Main是否已启动
    uint8_t clk_sel;             //system clock select
    uint8_t sys_clk;
//    uint8_t aupll_type;          //区分AUPLL的频率
    uint16_t rand_seed;
    uint32_t uart0baud;          //UART0BAUD
} sys_t;

const uint8_t sysclk_sel_tbl[] = {
    OSCDIV_2M,          //SYS_2M
    PLL0DIV_12M,        //SYS_12M
    OSCDIV_13M,         //SYS_13M
    PLL0DIV_24M,        //SYS_24M
    OSCDIV_26M,         //SYS_26M
    PLL0DIV_30M,        //SYS_30M
    PLL0DIV_48M,        //SYS_48M
    PLL0DIV_60M,        //SYS_60M
    PLL0DIV_80M,        //SYS_80M
    PLL0DIV_120M,       //SYS_120M
};

const uint8_t sysclk_index[] = {
    2,
    12,
    13,
    24,
    26,
    30,
    48,
    60,
    80,
    120,
};

sys_t sys = {0};
void my_printf(const char *format, ...);

static void delay_us(uint16_t nus)
{
   int i;
   for (i = 0; i < nus*10; i++) {
        asm("nop");
   }
}

uint8_t get_clksel_val(uint8_t val)
{
    return sysclk_sel_tbl[val];
}

uint8_t get_cur_sysclk(void)
{
    return sys.sys_clk;
}

uint32_t get_sysclk_nhz(void)
{
    return sysclk_index[sys.sys_clk] * 1000000;
}

////AT(.com_text.set_flash_safety)
//static ALWAYS_INLINE void set_flash_safety(uint32_t sys_clk)
//{
//    SPI0CON |= BIT(10);
//    if (sys_clk > SYS_48M) {
//        SPI0CON |= BIT(3);                          //2bit mode
//        spiflash_init(0x3b, 1);                     //dummy = 1
//    } else {
//        SPI0CON &= ~BIT(3);                         //2bit mode
//        spiflash_init(0x0b, 1);                     //dummy = 0
//    }
//}

uint8_t get_sd_rate(void)
{
    return 0;  //unit: M
}

uint8_t set_sd_baud(uint8_t sd_rate)
{
    uint8_t sd0baud=0;
    uint8_t sys_clk=0;
    if(sd_rate > 14){//不支持超过14M
        return 0;
    }
    if (sys.sys_clk <= SYSCLK_26M) {
        sys_clk=26;
    }else if (sys.sys_clk == SYSCLK_48M) {
        sys_clk=48;
    }  else if (sys.sys_clk <= SYSCLK_60M) {
        sys_clk=52;
    } else if (sys.sys_clk == SYSCLK_80M) {
        sys_clk=80;
    } else if (sys.sys_clk <= SYSCLK_120M) {
        sys_clk=120;
    }
    sd0baud = sys_clk/sd_rate-1;
    if(sys_clk%sd_rate*2/sd_rate) {
        sd0baud=sd0baud+1;
    }
    return sd0baud;
}

void update_sd0baud(void)
{
    if (!(SD0CON & BIT(0))) {
        return;
    }

    uint8_t sd_rate=get_sd_rate();
    if(sd_rate){
        uint8_t sd0baud=set_sd_baud(sd_rate);
        if(sd0baud){
             SD0BAUD=sd0baud;
             return ;
        }
    }

    if (sys.sys_clk <= SYSCLK_30M) {
        SD0BAUD = 1;
    } else if (sys.sys_clk <= SYSCLK_60M) {
        SD0BAUD = 3;
    } else if (sys.sys_clk == SYSCLK_80M) {
        SD0BAUD = 5;
    } else if (sys.sys_clk <= SYSCLK_120M) {
        SD0BAUD = 9;
    }
}

uint8_t sysclk_update_baud(uint8_t baud)
{
    uint8_t sd_rate=get_sd_rate();
    if(baud>20||!sd_rate) {
        if (sys.sys_clk == SYSCLK_120M) {
            return ((uint16_t)(baud + 1) * 25 / 10 - 1);
        } else if (sys.sys_clk >= SYSCLK_80M) {
            return ((baud + 1) * 2 - 1);
        } else if (sys.sys_clk <= SYSCLK_30M) {
            return (((baud + 1) >> 1) - 1);
        }
    } else if (sd_rate){
        return  set_sd_baud(sd_rate);
    }
    return baud;
}

//客户可能用到UART0(使用26M时钟源)做通信,这里可选设置系统时钟时不改波特率
WEAK void update_uart0baud_in_sysclk(uint32_t uart_baud)
{
    if(UART0CON & BIT(0)) {
        while (!(UART0CON & BIT(8)));
    }
    UART0BAUD = (uart_baud << 16) | uart_baud;
}

void set_sys_uart0baud(uint32_t baud)
{
    sys.uart0baud = baud;
}

//切系统时钟前,先设置模块时钟分频较大值,保证模块不会超频的情况
void set_peripherals_clkdiv_safety(void)
{
    uint32_t clkcon3 = CLKCON3;
    uint32_t clkcon2 = CLKCON2;

    //src clkdiv
    clkcon3 &= ~0xf0;                               //reset src clkdiv
    clkcon3 |= (1 << 4);                            //src clk = sys_clk / (n+1)

    //sbcenc硬件要小于48M
    clkcon3 &= ~(0x0f << 12);                       //reset sbcenc clkdiv
    clkcon3 |= (2 << 12);                           //src clk = sys_clk / (n+1)

    //aec ram硬件要小于50M
    clkcon3 &= ~0x0f;                               //reset aec clkdiv
    clkcon3 &= ~(0x0f << 19);                       //reset plc clkdiv
    clkcon3 &= ~(0x0f << 23);                       //reset cvsd clkdiv
    clkcon3 |= 0x02;                                //aec clk = sys_clk / (n+1)
    clkcon3 |= (2 << 19);                           //plc clk = sys_clk / (n+1)
    clkcon3 |= (2 << 23);                           //cvsd clk = sys_clk / (n+1)

    //audec硬件要小于48M
    clkcon2 &= ~(0x0f << 13);                       //reset audec clkdiv
    clkcon2 |= (2 << 13);                           //audec clk = sys_clk / (n+1)

    CLKCON3 = clkcon3;
    CLKCON2 = clkcon2;
}

//根据实际系统时钟,设置合适的模块时钟分频
void set_peripherals_clkdiv(void)
{
    uint32_t clkcon3 = CLKCON3;
    uint32_t clkcon2 = CLKCON2;
    uint32_t clkdiv;
    uint8_t  sys_clk = sys.sys_clk;

    //src clkdiv
    clkcon3 &= ~0xf0;                               //reset src clkdiv
    if (sys_clk > SYSCLK_80M) {
        clkcon3 |= (1 << 4);                        //src clk = sys_clk / (n+1)
    }

    //sbcec硬件要小于48M
    clkcon3 &= ~(0x0f << 12);
    if (sys_clk > SYSCLK_80M) {
        clkcon3 |= (2 << 12);
    } else if (sys_clk >= SYSCLK_60M) {
        clkcon3 |= (1 << 12);
    }

    //aec ram硬件要小于50M
    clkcon3 &= ~0x0f;                               //reset aec clkdiv
    clkcon3 &= ~(0x0f << 19);                       //reset plc clkdiv
    clkcon3 &= ~(0x0f << 23);                       //reset cvsd clkdiv
    if (sys_clk > SYSCLK_80M) {
        clkdiv = 2;
    } else if (sys_clk >= SYSCLK_60M) {
        clkdiv = 1;
    } else {
        clkdiv = 0;
    }
    clkcon3 |= clkdiv;                              //aec clk = sys_clk / (n+1)
    clkcon3 |= (clkdiv << 19);                      //plc clk = sys_clk / (n+1)
    clkcon3 |= (clkdiv << 23);                      //cvsd clk = sys_clk / (n+1)

    //audec硬件要小于48M
    clkcon2 &= ~(0x0f << 13);                       //reset audec clkdiv
    if (sys_clk > SYSCLK_80M) {
        clkdiv = 2;
    } else if (sys_clk >= SYSCLK_60M) {
        clkdiv = 1;
    } else {
        clkdiv = 0;
    }
    clkcon2 |= (clkdiv << 13);                     //audec clk = sys_clk / (n+1)

    CLKCON3 = clkcon3;
    CLKCON2 = clkcon2;

//    if (sys_clk <= SYS_48M) {
//        PWRCON0 = (PWRCON0 & ~0xf) | (sys_trim.vddcore);                //VDDCORE减一档
//    }
//    vddcore_other_offset();
}

ALIGN(512)  //注意:超过512byte时,要用lock cache
static void set_sysclk_do(uint32_t sys_clk, uint32_t clk_sel, uint32_t spll_div, uint32_t spi_baud, uint32_t spi1baud)
{
    uint32_t cpu_ie;
    cpu_ie = PICCON & BIT(0);
    PICCONCLR = BIT(0);                             //关中断,切换系统时钟
    set_peripherals_clkdiv_safety();

    CLKCON0 &= ~(BIT(2) | BIT(3));                  //sysclk sel rc2m
    CLKCON2 &= ~(0x1f << 8);                        //reset spll div

    if(clk_sel <= PLL0DIV_120M) {
        //sys_clk来源PLL0的分频配置
        CLKCON0 &= ~(BIT(4) | BIT(5) | BIT(6));     //sys_pll select pll0out
        if (PLL0DIV != (240 * 65536 / 26)) {
            PLL0DIV = 240 * 65536 / 26;             //pll: 240M, XOSC: 26M
            PLL0CON &= ~(BIT(3) | BIT(4) | BIT(5));
            PLL0CON |= BIT(3);                      //Select PLL/VCO frequency band (PLL大于206M vcos = 0x01, 否则为0)
            PLL0CON |= BIT(20);                     //update pll0div to pll0_clk
            CLKCON3 &= ~(7 << 16);
            CLKCON3 |= (4 << 16);                   //USB CLK 48M
        }
    } else if (clk_sel <= OSCDIV_26M) {
        //sys_clk来源于XOSC26M时钟分频, 无USB时关闭PLL0
//        if (!is_usb_support()) {
//            PLL0CON &= ~BIT(18);
//            PLL0CON &= ~(BIT(12) | BIT(6));         //close pll0
//        }

        CLKCON0 &= ~(BIT(4) | BIT(5) | BIT(6));
        CLKCON0 |= BIT(6);                          //spll select xosc26m_clk
    }

    CLKCON2 |= (spll_div << 8);
    CLKCON0 |= BIT(3);                          //sysclk sel spll
    SPI0BAUD = spi_baud;
    if (CLKGAT1 & BIT(12)) {
        SPI1BAUD = spi1baud;
    }
//    if (spiflash_speed_up_en()) {
//        set_flash_safety(sys_clk);
//    }
    PICCON |= cpu_ie;
}

void set_sysclk(uint32_t sys_clk)
{
    uint32_t uart_baud, spll_div = 0, spi_baud = 0, spi1baud;
    uint8_t cnt_1us, clk_sel;

    clk_sel = get_clksel_val(sys_clk);
    if(sys.clk_sel == clk_sel) {
        return;
    }
//    if (sys_clk > SYSCLK_48M) {
//        PWRCON0 = (PWRCON0 & ~0xf) | (sys_trim.vddcore + 1);            //VDDCORE加一档
//    }
//    vddcore_other_offset();

//    printf("%s: %d, %d\n", __func__, sys_clk, clk_sel);
    switch (sys_clk) {
    case SYSCLK_12M:
        spll_div = 19;                   //pll0 240M
        cnt_1us = 1;
        spi_baud = 0;
        spi1baud = 0;
        break;

    case SYSCLK_24M:
        spll_div = 9;                   //pll0 240M
        cnt_1us = 2;
        spi_baud = 0;
        spi1baud = 1;
        break;

    case SYSCLK_30M:
        spll_div = 7;                   //pll0 240M
        cnt_1us = 3;
        spi_baud = 1;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)
        spi1baud = 1;
        break;

    case SYSCLK_48M:
        spll_div = 4;                   //pll0 240M
        cnt_1us = 4;
        spi_baud = 1;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)
        spi1baud = 3;
        break;

    case SYSCLK_60M:
        spll_div = 3;                   //pll0 240M
        cnt_1us = 5;
        spi_baud = 2;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)
        spi1baud = 3;
        break;

    case SYSCLK_80M:
        spll_div = 2;                   //pll0 240M
        cnt_1us = 7;
        spi_baud = 3;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)
        spi1baud = 4;
        break;

    case SYSCLK_120M:
        spll_div = 1;                   //pll0 240M
        cnt_1us = 10;
        spi_baud = 4;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)     //spiclk 120/5 = 24M
        spi1baud = 9;
        break;

    case SYSCLK_26M:
        spll_div = 0;
        cnt_1us = 3;
        spi_baud = 1;
        spi1baud = 1;
        break;

    case SYSCLK_13M:
        spll_div = 1;
        cnt_1us = 1;
        spi_baud = 0;
        spi1baud = 0;
        break;

    case SYSCLK_2M:
        spll_div = 1;
        cnt_1us = 1;
        spi_baud = 0;
        spi1baud = 0;
        break;

    default:
        return;
    }

    //先判断PLL0是否打开
    if(clk_sel <= PLL0DIV_120M) {
        if (!(PLL0CON & BIT(12))) {
            PLL0CON &= ~(BIT(3) | BIT(4) | BIT(5));
            PLL0CON |= BIT(3);                     //Select PLL/VCO frequency band (PLL大于206M vcos = 0x01, 否则为0)
            PLL0CON |= BIT(12);                    //enable pll0 ldo
            delay_us(100);                         //delay 100us
            PLL0DIV = 240 * 65536 / 26;            //pll0: 240M, XOSC: 26M
            PLL0CON |= BIT(20);                    //update pll0div to pll0_clk
            PLL0CON |= BIT(6);                     //enable analog pll0
            PLL0CON |= BIT(18);                    //pll0 sdm enable
            delay_us(1000);                        //wait pll0 stable
        }
    }

    sys.cnt_1us = cnt_1us;
    sys.sys_clk = sys_clk;
    sys.clk_sel = clk_sel;
    uart_baud =  (((get_sysclk_nhz() + (sys.uart0baud / 2)) / sys.uart0baud) - 1);

    set_sysclk_do(sys_clk, clk_sel,spll_div, spi_baud, spi1baud);
    set_peripherals_clkdiv();
    update_sd0baud();       //更新下SD0BAUD
    update_uart0baud_in_sysclk(uart_baud);
}