/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher */ #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/gcd.h> #include <asm/div64.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include <drm/radeon_drm.h> #include "atom.h" #include "radeon.h" #include "radeon_kms.h" static void avivo_crtc_load_lut(struct drm_crtc *crtc) { … } static void dce4_crtc_load_lut(struct drm_crtc *crtc) { … } static void dce5_crtc_load_lut(struct drm_crtc *crtc) { … } static void legacy_crtc_load_lut(struct drm_crtc *crtc) { … } void radeon_crtc_load_lut(struct drm_crtc *crtc) { … } static int radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t size, struct drm_modeset_acquire_ctx *ctx) { … } static void radeon_crtc_destroy(struct drm_crtc *crtc) { … } /** * radeon_unpin_work_func - unpin old buffer object * * @__work: kernel work item * * Unpin the old frame buffer object outside of the interrupt handler */ static void radeon_unpin_work_func(struct work_struct *__work) { … } void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) { … } /** * radeon_crtc_handle_flip - page flip completed * * @rdev: radeon device pointer * @crtc_id: crtc number this event is for * * Called when we are sure that a page flip for this crtc is completed. */ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) { … } /** * radeon_flip_work_func - page flip framebuffer * * @__work: kernel work item * * Wait for the buffer object to become idle and do the actual page flip */ static void radeon_flip_work_func(struct work_struct *__work) { … } static int radeon_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx) { … } static int radeon_crtc_set_config(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx) { … } static const struct drm_crtc_funcs radeon_crtc_funcs = …; static void radeon_crtc_init(struct drm_device *dev, int index) { … } static const char *encoder_names[38] = …; static const char *hpd_names[6] = …; static void radeon_print_display_setup(struct drm_device *dev) { … } static bool radeon_setup_enc_conn(struct drm_device *dev) { … } /* avivo */ /** * avivo_reduce_ratio - fractional number reduction * * @nom: nominator * @den: denominator * @nom_min: minimum value for nominator * @den_min: minimum value for denominator * * Find the greatest common divisor and apply it on both nominator and * denominator, but make nominator and denominator are at least as large * as their minimum values. */ static void avivo_reduce_ratio(unsigned *nom, unsigned *den, unsigned nom_min, unsigned den_min) { … } /** * avivo_get_fb_ref_div - feedback and ref divider calculation * * @nom: nominator * @den: denominator * @post_div: post divider * @fb_div_max: feedback divider maximum * @ref_div_max: reference divider maximum * @fb_div: resulting feedback divider * @ref_div: resulting reference divider * * Calculate feedback and reference divider for a given post divider. Makes * sure we stay within the limits. */ static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, unsigned fb_div_max, unsigned ref_div_max, unsigned *fb_div, unsigned *ref_div) { … } /** * radeon_compute_pll_avivo - compute PLL paramaters * * @pll: information about the PLL * @freq: target frequency * @dot_clock_p: resulting pixel clock * @fb_div_p: resulting feedback divider * @frac_fb_div_p: fractional part of the feedback divider * @ref_div_p: resulting reference divider * @post_div_p: resulting reference divider * * Try to calculate the PLL parameters to generate the given frequency: * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div) */ void radeon_compute_pll_avivo(struct radeon_pll *pll, u32 freq, u32 *dot_clock_p, u32 *fb_div_p, u32 *frac_fb_div_p, u32 *ref_div_p, u32 *post_div_p) { … } /* pre-avivo */ static inline uint32_t radeon_div(uint64_t n, uint32_t d) { … } void radeon_compute_pll_legacy(struct radeon_pll *pll, uint64_t freq, uint32_t *dot_clock_p, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, uint32_t *post_div_p) { … } static const struct drm_framebuffer_funcs radeon_fb_funcs = …; int radeon_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { … } static struct drm_framebuffer * radeon_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { … } static const struct drm_mode_config_funcs radeon_mode_funcs = …; static const struct drm_prop_enum_list radeon_tmds_pll_enum_list[] = …; static const struct drm_prop_enum_list radeon_tv_std_enum_list[] = …; static const struct drm_prop_enum_list radeon_underscan_enum_list[] = …; static const struct drm_prop_enum_list radeon_audio_enum_list[] = …; /* XXX support different dither options? spatial, temporal, both, etc. */ static const struct drm_prop_enum_list radeon_dither_enum_list[] = …; static const struct drm_prop_enum_list radeon_output_csc_enum_list[] = …; static int radeon_modeset_create_props(struct radeon_device *rdev) { … } void radeon_update_display_priority(struct radeon_device *rdev) { … } /* * Allocate hdmi structs and determine register offsets */ static void radeon_afmt_init(struct radeon_device *rdev) { … } static void radeon_afmt_fini(struct radeon_device *rdev) { … } int radeon_modeset_init(struct radeon_device *rdev) { … } void radeon_modeset_fini(struct radeon_device *rdev) { … } static bool is_hdtv_mode(const struct drm_display_mode *mode) { … } bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { … } /* * Retrieve current video scanout position of crtc on a given gpu, and * an optional accurate timestamp of when query happened. * * \param dev Device to query. * \param crtc Crtc to query. * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). * For driver internal use only also supports these flags: * * USE_REAL_VBLANKSTART to use the real start of vblank instead * of a fudged earlier start of vblank. * * GET_DISTANCE_TO_VBLANKSTART to return distance to the * fudged earlier start of vblank in *vpos and the distance * to true start of vblank in *hpos. * * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. * \param *stime Target location for timestamp taken immediately before * scanout position query. Can be NULL to skip timestamp. * \param *etime Target location for timestamp taken immediately after * scanout position query. Can be NULL to skip timestamp. * * Returns vpos as a positive number while in active scanout area. * Returns vpos as a negative number inside vblank, counting the number * of scanlines to go until end of vblank, e.g., -1 means "one scanline * until start of active scanout / end of vblank." * * \return Flags, or'ed together as follows: * * DRM_SCANOUTPOS_VALID = Query successful. * DRM_SCANOUTPOS_INVBL = Inside vblank. * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of * this flag means that returned position may be offset by a constant but * unknown small number of scanlines wrt. real scanout position. * */ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { … } bool radeon_get_crtc_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { … }