15615e78eSJani Nikula // SPDX-License-Identifier: MIT 25615e78eSJani Nikula /* Copyright © 2025 Intel Corporation */ 35615e78eSJani Nikula 45615e78eSJani Nikula #include <drm/drm_print.h> 55615e78eSJani Nikula 65615e78eSJani Nikula #include "intel_display_core.h" 75615e78eSJani Nikula #include "intel_display_types.h" 85615e78eSJani Nikula #include "vlv_clock.h" 95615e78eSJani Nikula #include "vlv_sideband.h" 105615e78eSJani Nikula 117a356ee5SJani Nikula /* 127a356ee5SJani Nikula * FIXME: The caching of hpll_freq and czclk_freq relies on the first calls 137a356ee5SJani Nikula * occurring at a time when they can actually be read. This appears to be the 147a356ee5SJani Nikula * case, but is somewhat fragile. Make the initialization explicit at a point 157a356ee5SJani Nikula * where they can be reliably read. 167a356ee5SJani Nikula */ 177a356ee5SJani Nikula 185615e78eSJani Nikula /* returns HPLL frequency in kHz */ 195615e78eSJani Nikula int vlv_clock_get_hpll_vco(struct drm_device *drm) 205615e78eSJani Nikula { 215615e78eSJani Nikula struct intel_display *display = to_intel_display(drm); 225615e78eSJani Nikula int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; 235615e78eSJani Nikula 245615e78eSJani Nikula if (!display->vlv_clock.hpll_freq) { 255615e78eSJani Nikula vlv_cck_get(drm); 265615e78eSJani Nikula /* Obtain SKU information */ 275615e78eSJani Nikula hpll_freq = vlv_cck_read(drm, CCK_FUSE_REG) & 285615e78eSJani Nikula CCK_FUSE_HPLL_FREQ_MASK; 295615e78eSJani Nikula vlv_cck_put(drm); 305615e78eSJani Nikula 315615e78eSJani Nikula display->vlv_clock.hpll_freq = vco_freq[hpll_freq] * 1000; 325615e78eSJani Nikula 335615e78eSJani Nikula drm_dbg_kms(drm, "HPLL frequency: %d kHz\n", display->vlv_clock.hpll_freq); 345615e78eSJani Nikula } 355615e78eSJani Nikula 365615e78eSJani Nikula return display->vlv_clock.hpll_freq; 375615e78eSJani Nikula } 385615e78eSJani Nikula 39*90930b63SMichał Grzelak static int vlv_clock_get_cck(struct drm_device *drm, 405615e78eSJani Nikula const char *name, u32 reg, int ref_freq) 415615e78eSJani Nikula { 425615e78eSJani Nikula u32 val; 435615e78eSJani Nikula int divider; 445615e78eSJani Nikula 455615e78eSJani Nikula vlv_cck_get(drm); 465615e78eSJani Nikula val = vlv_cck_read(drm, reg); 475615e78eSJani Nikula vlv_cck_put(drm); 485615e78eSJani Nikula 495615e78eSJani Nikula divider = val & CCK_FREQUENCY_VALUES; 505615e78eSJani Nikula 515615e78eSJani Nikula drm_WARN(drm, (val & CCK_FREQUENCY_STATUS) != 525615e78eSJani Nikula (divider << CCK_FREQUENCY_STATUS_SHIFT), 535615e78eSJani Nikula "%s change in progress\n", name); 545615e78eSJani Nikula 555615e78eSJani Nikula return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1); 565615e78eSJani Nikula } 575615e78eSJani Nikula 585615e78eSJani Nikula int vlv_clock_get_hrawclk(struct drm_device *drm) 595615e78eSJani Nikula { 605615e78eSJani Nikula /* RAWCLK_FREQ_VLV register updated from power well code */ 61*90930b63SMichał Grzelak return vlv_clock_get_cck(drm, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL, 625615e78eSJani Nikula vlv_clock_get_hpll_vco(drm)); 635615e78eSJani Nikula } 645615e78eSJani Nikula 655615e78eSJani Nikula int vlv_clock_get_czclk(struct drm_device *drm) 665615e78eSJani Nikula { 675615e78eSJani Nikula struct intel_display *display = to_intel_display(drm); 685615e78eSJani Nikula 695615e78eSJani Nikula if (!display->vlv_clock.czclk_freq) { 70*90930b63SMichał Grzelak display->vlv_clock.czclk_freq = vlv_clock_get_cck(drm, "czclk", CCK_CZ_CLOCK_CONTROL, 715615e78eSJani Nikula vlv_clock_get_hpll_vco(drm)); 725615e78eSJani Nikula drm_dbg_kms(drm, "CZ clock rate: %d kHz\n", display->vlv_clock.czclk_freq); 735615e78eSJani Nikula } 745615e78eSJani Nikula 755615e78eSJani Nikula return display->vlv_clock.czclk_freq; 765615e78eSJani Nikula } 775615e78eSJani Nikula 785615e78eSJani Nikula int vlv_clock_get_cdclk(struct drm_device *drm) 795615e78eSJani Nikula { 80*90930b63SMichał Grzelak return vlv_clock_get_cck(drm, "cdclk", CCK_DISPLAY_CLOCK_CONTROL, 815615e78eSJani Nikula vlv_clock_get_hpll_vco(drm)); 825615e78eSJani Nikula } 835615e78eSJani Nikula 845615e78eSJani Nikula int vlv_clock_get_gpll(struct drm_device *drm) 855615e78eSJani Nikula { 86*90930b63SMichał Grzelak return vlv_clock_get_cck(drm, "GPLL ref", CCK_GPLL_CLOCK_CONTROL, 875615e78eSJani Nikula vlv_clock_get_czclk(drm)); 885615e78eSJani Nikula } 89