| /* |
| * Copyright (c) 2020 Antmicro <www.antmicro.com> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef LITEX_MMCM_H |
| #define LITEX_MMCM_H |
| |
| #include <zephyr/sys/util.h> |
| #include <zephyr/types.h> |
| |
| /* Common values */ |
| #define PICOS_IN_SEC 1000000000000 |
| |
| /* MMCM specific numbers */ |
| #define CLKOUT_MAX 7 |
| #define DELAY_TIME_MAX 63 |
| #define PHASE_MUX_MAX 7 |
| #define HIGH_LOW_TIME_REG_MAX 63 |
| #define PHASE_MUX_RES_FACTOR 8 |
| |
| /* DRP registers index */ |
| #define DRP_RESET 0 |
| #define DRP_LOCKED 1 |
| #define DRP_READ 2 |
| #define DRP_WRITE 3 |
| #define DRP_DRDY 4 |
| #define DRP_ADR 5 |
| #define DRP_DAT_W 6 |
| #define DRP_DAT_R 7 |
| |
| /* Base address */ |
| #define DRP_BASE DT_REG_ADDR_BY_IDX(MMCM, 0) |
| /* Register address */ |
| #define DRP_ADDR_RESET DT_REG_ADDR_BY_NAME(MMCM, drp_reset) |
| #define DRP_ADDR_LOCKED DT_REG_ADDR_BY_NAME(MMCM, drp_locked) |
| #define DRP_ADDR_READ DT_REG_ADDR_BY_NAME(MMCM, drp_read) |
| #define DRP_ADDR_WRITE DT_REG_ADDR_BY_NAME(MMCM, drp_write) |
| #define DRP_ADDR_DRDY DT_REG_ADDR_BY_NAME(MMCM, drp_drdy) |
| #define DRP_ADDR_ADR DT_REG_ADDR_BY_NAME(MMCM, drp_adr) |
| #define DRP_ADDR_DAT_W DT_REG_ADDR_BY_NAME(MMCM, drp_dat_w) |
| #define DRP_ADDR_DAT_R DT_REG_ADDR_BY_NAME(MMCM, drp_dat_r) |
| |
| /* Devicetree global defines */ |
| #define LOCK_TIMEOUT DT_PROP(MMCM, litex_lock_timeout) |
| #define DRDY_TIMEOUT DT_PROP(MMCM, litex_drdy_timeout) |
| #define DIVCLK_DIVIDE_MIN DT_PROP(MMCM, litex_divclk_divide_min) |
| #define DIVCLK_DIVIDE_MAX DT_PROP(MMCM, litex_divclk_divide_max) |
| #define CLKFBOUT_MULT_MIN DT_PROP(MMCM, litex_clkfbout_mult_min) |
| #define CLKFBOUT_MULT_MAX DT_PROP(MMCM, litex_clkfbout_mult_max) |
| #define VCO_FREQ_MIN DT_PROP(MMCM, litex_vco_freq_min) |
| #define VCO_FREQ_MAX DT_PROP(MMCM, litex_vco_freq_max) |
| #define CLKOUT_DIVIDE_MIN DT_PROP(MMCM, litex_clkout_divide_min) |
| #define CLKOUT_DIVIDE_MAX DT_PROP(MMCM, litex_clkout_divide_max) |
| #define VCO_MARGIN DT_PROP(MMCM, litex_vco_margin) |
| |
| #define CLKOUT_INIT(N) \ |
| BUILD_ASSERT(CLKOUT_DUTY_DEN(N) > 0 && \ |
| CLKOUT_DUTY_NUM(N) > 0 && \ |
| CLKOUT_DUTY_NUM(N) <= CLKOUT_DUTY_DEN(N), \ |
| "Invalid default duty"); \ |
| BUILD_ASSERT(CLKOUT_ID(N) < NCLKOUT, "Invalid CLKOUT index"); \ |
| lcko = &ldev->clkouts[N]; \ |
| lcko->id = CLKOUT_ID(N); \ |
| \ |
| lcko->clkout_div = clkout_div; \ |
| lcko->def.freq = CLKOUT_FREQ(N); \ |
| lcko->def.phase = CLKOUT_PHASE(N); \ |
| lcko->def.duty.num = CLKOUT_DUTY_NUM(N); \ |
| lcko->def.duty.den = CLKOUT_DUTY_DEN(N); \ |
| lcko->margin.m = CLKOUT_MARGIN(N); \ |
| lcko->margin.exp = CLKOUT_MARGIN_EXP(N); |
| |
| /* Devicetree clkout defines */ |
| #define CLKOUT_EXIST(N) DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(clk##N)) |
| #define CLKOUT_ID(N) DT_REG_ADDR(DT_NODELABEL(clk##N)) |
| #define CLKOUT_FREQ(N) DT_PROP(DT_NODELABEL(clk##N), \ |
| litex_clock_frequency) |
| #define CLKOUT_PHASE(N) DT_PROP(DT_NODELABEL(clk##N), \ |
| litex_clock_phase) |
| #define CLKOUT_DUTY_NUM(N) DT_PROP(DT_NODELABEL(clk##N), \ |
| litex_clock_duty_num) |
| #define CLKOUT_DUTY_DEN(N) DT_PROP(DT_NODELABEL(clk##N), \ |
| litex_clock_duty_den) |
| #define CLKOUT_MARGIN(N) DT_PROP(DT_NODELABEL(clk##N), \ |
| litex_clock_margin) |
| #define CLKOUT_MARGIN_EXP(N) DT_PROP(DT_NODELABEL(clk##N), \ |
| litex_clock_margin_exp) |
| |
| /* Register values */ |
| #define FULL_REG_16 0xFFFF |
| #define ZERO_REG 0x0 |
| #define KEEP_IN_MUL_REG1 0xF000 |
| #define KEEP_IN_MUL_REG2 0xFF3F |
| #define KEEP_IN_DIV 0xC000 |
| #define REG1_FREQ_MASK 0xF000 |
| #define REG2_FREQ_MASK 0x803F |
| #define REG1_DUTY_MASK 0xF000 |
| #define REG2_DUTY_MASK 0xFF7F |
| #define REG1_PHASE_MASK 0x1FFF |
| #define REG2_PHASE_MASK 0xFCC0 |
| #define FILT1_MASK 0x66FF |
| #define FILT2_MASK 0x666F |
| #define LOCK1_MASK 0xFC00 |
| #define LOCK23_MASK 0x8000 |
| /* Control bits extraction masks */ |
| #define HL_TIME_MASK 0x3F |
| #define FRAC_MASK 0x7 |
| #define EDGE_MASK 0x1 |
| #define NO_CNT_MASK 0x1 |
| #define FRAC_EN_MASK 0x1 |
| #define PHASE_MUX_MASK 0x7 |
| |
| /* Bit groups start position in DRP registers */ |
| #define HIGH_TIME_POS 6 |
| #define LOW_TIME_POS 0 |
| #define PHASE_MUX_POS 13 |
| #define FRAC_POS 12 |
| #define FRAC_EN_POS 11 |
| #define FRAC_WF_R_POS 10 |
| #define EDGE_POS 7 |
| #define NO_CNT_POS 6 |
| #define EDGE_DIVREG_POS 13 |
| #define NO_CNT_DIVREG_POS 12 |
| #define DELAY_TIME_POS 0 |
| |
| /* MMCM Register addresses */ |
| #define POWER_REG 0x28 |
| #define DIV_REG 0x16 |
| #define LOCK_REG1 0x18 |
| #define LOCK_REG2 0x19 |
| #define LOCK_REG3 0x1A |
| #define FILT_REG1 0x4E |
| #define FILT_REG2 0x4F |
| #define CLKOUT0_REG1 0x08 |
| #define CLKOUT0_REG2 0x09 |
| #define CLKOUT1_REG1 0x0A |
| #define CLKOUT1_REG2 0x0B |
| #define CLKOUT2_REG1 0x0C |
| #define CLKOUT2_REG2 0x0D |
| #define CLKOUT3_REG1 0x0E |
| #define CLKOUT3_REG2 0x0F |
| #define CLKOUT4_REG1 0x10 |
| #define CLKOUT4_REG2 0x11 |
| #define CLKOUT5_REG1 0x06 |
| #define CLKOUT5_REG2 0x07 |
| #define CLKOUT6_REG1 0x12 |
| #define CLKOUT6_REG2 0x13 |
| #define CLKFBOUT_REG1 0x14 |
| #define CLKFBOUT_REG2 0x15 |
| |
| /* Basic structure for DRP registers */ |
| struct litex_drp_reg { |
| uint32_t addr; |
| uint32_t size; |
| }; |
| |
| struct litex_clk_range { |
| uint32_t min; |
| uint32_t max; |
| }; |
| |
| struct clk_duty { |
| uint32_t num; |
| uint32_t den; |
| }; |
| |
| struct litex_clk_default { |
| struct clk_duty duty; |
| int phase; |
| uint32_t freq; |
| }; |
| |
| struct litex_clk_glob_params { |
| uint64_t freq; |
| uint32_t div; |
| uint32_t mul; |
| }; |
| |
| /* Divider configuration bits group */ |
| struct litex_clk_div_params { |
| uint8_t high_time; |
| uint8_t low_time; |
| uint8_t no_cnt; |
| uint8_t edge; |
| }; |
| |
| /* Phase configuration bits group */ |
| struct litex_clk_phase_params { |
| uint8_t phase_mux; |
| uint8_t delay_time; |
| uint8_t mx; |
| }; |
| |
| /* Fractional configuration bits group */ |
| struct litex_clk_frac_params { |
| uint8_t frac_en; |
| uint8_t frac; |
| uint8_t phase_mux_f; |
| uint8_t frac_wf_r; |
| uint8_t frac_wf_f; |
| }; |
| |
| struct litex_clk_params { |
| struct clk_duty duty; |
| int phase; |
| uint32_t freq; |
| uint32_t period_off; |
| uint8_t div; |
| }; |
| |
| struct litex_clk_timeout { |
| uint32_t lock; |
| uint32_t drdy; |
| }; |
| |
| /* Basic structure for MMCM reg addresses */ |
| struct litex_clk_clkout_addr { |
| uint8_t reg1; |
| uint8_t reg2; |
| }; |
| |
| /* Structure for all MMCM regs */ |
| struct litex_clk_regs_addr { |
| struct litex_clk_clkout_addr clkout[CLKOUT_MAX]; |
| }; |
| |
| struct litex_clk_clkout_margin { |
| uint32_t m; /* margin factor scaled to integer */ |
| uint32_t exp; |
| }; |
| |
| struct litex_clk_device { |
| uint32_t *base; |
| /*struct clk_hw clk_hw;*/ |
| struct litex_clk_clkout *clkouts; /* array of clock outputs */ |
| struct litex_clk_timeout timeout; /* timeouts for wait functions*/ |
| struct litex_clk_glob_params g_config; /* general MMCM settings */ |
| struct litex_clk_glob_params ts_g_config;/* settings to set*/ |
| struct litex_clk_range divclk; /* divclk_divide_range */ |
| struct litex_clk_range clkfbout; /* clkfbout_mult_frange */ |
| struct litex_clk_range vco; /* vco_freq_range */ |
| uint8_t *update_clkout; /* which clkout needs update */ |
| uint32_t vco_margin; |
| uint32_t nclkout; |
| }; |
| |
| struct litex_clk_clkout { |
| uint32_t *base; |
| struct litex_clk_device *ldev; /* global data */ |
| struct litex_clk_default def; /* DTS defaults */ |
| struct litex_clk_params config; /* real CLKOUT settings */ |
| struct litex_clk_params ts_config; /* CLKOUT settings to set */ |
| struct litex_clk_div_params div; /* CLKOUT configuration groups*/ |
| struct litex_clk_phase_params phase; |
| struct litex_clk_frac_params frac; |
| struct litex_clk_range clkout_div; /* clkout_divide_range */ |
| struct litex_clk_clkout_margin margin; |
| uint32_t id; |
| }; |
| |
| #endif /* LITEX_MMCM_H */ |