/* * Copyright 2005 Stephane Marchesin. * All Rights Reserved. * * 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 (including the next * paragraph) 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 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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. */ #ifndef __NOUVEAU_DRV_H__ #define __NOUVEAU_DRV_H__ #define DRIVER_AUTHOR "Stephane Marchesin" #define DRIVER_EMAIL "nouveau@lists.freedesktop.org" #define DRIVER_NAME "nouveau" #define DRIVER_DESC "nVidia Riva/TNT/GeForce" #define DRIVER_DATE "20120316" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 #include "ttm/ttm_bo_api.h" #include "ttm/ttm_bo_driver.h" #include "ttm/ttm_placement.h" #include "ttm/ttm_memory.h" #include "ttm/ttm_module.h" #define XXX_THIS_IS_A_HACK #include #include #include enum blah { NV_MEM_TYPE_UNKNOWN = 0, NV_MEM_TYPE_STOLEN, NV_MEM_TYPE_SGRAM, NV_MEM_TYPE_SDRAM, NV_MEM_TYPE_DDR1, NV_MEM_TYPE_DDR2, NV_MEM_TYPE_DDR3, NV_MEM_TYPE_GDDR2, NV_MEM_TYPE_GDDR3, NV_MEM_TYPE_GDDR4, NV_MEM_TYPE_GDDR5 }; #include #include "nouveau_reg.h" #include #include #include "nouveau_compat.h" #define nouveau_gpuobj_new(d,c,s,a,f,o) \ _nouveau_gpuobj_new((d), NULL, (s), (a), (f), (o)) #define nouveau_vm_new(d,o,l,m,v) \ _nouveau_vm_new((d), (o), (l), (m), (v)) #define nv50_vm_flush_engine(d,e) \ _nv50_vm_flush_engine((d), (e)) #include "nouveau_bo.h" #include "nouveau_gem.h" struct nouveau_page_flip_state { struct list_head head; struct drm_pending_vblank_event *event; int crtc, bpp, pitch, x, y; uint64_t offset; }; struct nouveau_display_engine { void *priv; int (*early_init)(struct drm_device *); void (*late_takedown)(struct drm_device *); int (*create)(struct drm_device *); void (*destroy)(struct drm_device *); int (*init)(struct drm_device *); void (*fini)(struct drm_device *); struct drm_property *dithering_mode; struct drm_property *dithering_depth; struct drm_property *underscan_property; struct drm_property *underscan_hborder_property; struct drm_property *underscan_vborder_property; /* not really hue and saturation: */ struct drm_property *vibrant_hue_property; struct drm_property *color_vibrance_property; }; struct nouveau_pm_voltage_level { u32 voltage; /* microvolts */ u8 vid; }; struct nouveau_pm_voltage { bool supported; u8 version; u8 vid_mask; struct nouveau_pm_voltage_level *level; int nr_level; }; /* Exclusive upper limits */ #define NV_MEM_CL_DDR2_MAX 8 #define NV_MEM_WR_DDR2_MAX 9 #define NV_MEM_CL_DDR3_MAX 17 #define NV_MEM_WR_DDR3_MAX 17 #define NV_MEM_CL_GDDR3_MAX 16 #define NV_MEM_WR_GDDR3_MAX 18 #define NV_MEM_CL_GDDR5_MAX 21 #define NV_MEM_WR_GDDR5_MAX 20 struct nouveau_pm_memtiming { int id; u32 reg[9]; u32 mr[4]; u8 tCWL; u8 odt; u8 drive_strength; }; struct nouveau_pm_tbl_header { u8 version; u8 header_len; u8 entry_cnt; u8 entry_len; }; struct nouveau_pm_tbl_entry { u8 tWR; u8 tWTR; u8 tCL; u8 tRC; u8 empty_4; u8 tRFC; /* Byte 5 */ u8 empty_6; u8 tRAS; /* Byte 7 */ u8 empty_8; u8 tRP; /* Byte 9 */ u8 tRCDRD; u8 tRCDWR; u8 tRRD; u8 tUNK_13; u8 RAM_FT1; /* 14, a bitmask of random RAM features */ u8 empty_15; u8 tUNK_16; u8 empty_17; u8 tUNK_18; u8 tCWL; u8 tUNK_20, tUNK_21; }; struct nouveau_pm_profile; struct nouveau_pm_profile_func { void (*destroy)(struct nouveau_pm_profile *); void (*init)(struct nouveau_pm_profile *); void (*fini)(struct nouveau_pm_profile *); struct nouveau_pm_level *(*select)(struct nouveau_pm_profile *); }; struct nouveau_pm_profile { const struct nouveau_pm_profile_func *func; struct list_head head; char name[8]; }; #define NOUVEAU_PM_MAX_LEVEL 8 struct nouveau_pm_level { struct nouveau_pm_profile profile; struct device_attribute dev_attr; char name[32]; int id; struct nouveau_pm_memtiming timing; u32 memory; u16 memscript; u32 core; u32 shader; u32 rop; u32 copy; u32 daemon; u32 vdec; u32 dom6; u32 unka0; /* nva3:nvc0 */ u32 hub01; /* nvc0- */ u32 hub06; /* nvc0- */ u32 hub07; /* nvc0- */ u32 volt_min; /* microvolts */ u32 volt_max; u8 fanspeed; }; struct nouveau_pm_temp_sensor_constants { u16 offset_constant; s16 offset_mult; s16 offset_div; s16 slope_mult; s16 slope_div; }; struct nouveau_pm_threshold_temp { s16 critical; s16 down_clock; s16 fan_boost; }; struct nouveau_pm_fan { u32 percent; u32 min_duty; u32 max_duty; u32 pwm_freq; u32 pwm_divisor; }; struct nouveau_pm_engine { struct nouveau_pm_voltage voltage; struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL]; int nr_perflvl; struct nouveau_pm_temp_sensor_constants sensor_constants; struct nouveau_pm_threshold_temp threshold_temp; struct nouveau_pm_fan fan; struct nouveau_pm_profile *profile_ac; struct nouveau_pm_profile *profile_dc; struct nouveau_pm_profile *profile; struct list_head profiles; struct nouveau_pm_level boot; struct nouveau_pm_level *cur; struct device *hwmon; struct notifier_block acpi_nb; int (*clocks_get)(struct drm_device *, struct nouveau_pm_level *); void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *); int (*clocks_set)(struct drm_device *, void *); int (*voltage_get)(struct drm_device *); int (*voltage_set)(struct drm_device *, int voltage); int (*pwm_get)(struct drm_device *, int line, u32*, u32*); int (*pwm_set)(struct drm_device *, int line, u32, u32); int (*temp_get)(struct drm_device *); }; struct nouveau_engine { struct nouveau_display_engine display; struct nouveau_pm_engine pm; }; enum nouveau_card_type { NV_04 = 0x04, NV_10 = 0x10, NV_20 = 0x20, NV_30 = 0x30, NV_40 = 0x40, NV_50 = 0x50, NV_C0 = 0xc0, NV_D0 = 0xd0, NV_E0 = 0xe0, }; struct drm_nouveau_private { struct drm_device *dev; void *newpriv; /* the card type, takes NV_* as values */ enum nouveau_card_type card_type; /* exact chipset, derived from NV_PMC_BOOT_0 */ int chipset; u32 crystal; /* interrupt handling */ void (*irq_handler[32])(struct drm_device *); bool msi_enabled; struct nouveau_engine engine; /* For PFIFO and PGRAPH. */ spinlock_t context_switch_lock; struct nvbios vbios; u8 *mxms; struct backlight_device *backlight; }; static inline struct drm_nouveau_private * nouveau_private(struct drm_device *dev) { return dev->dev_private; } /* nouveau_drv.c */ extern int nouveau_modeset; extern int nouveau_duallink; extern int nouveau_uscript_lvds; extern int nouveau_uscript_tmds; extern int nouveau_vram_pushbuf; extern int nouveau_vram_notify; extern char *nouveau_vram_type; extern int nouveau_fbpercrtc; extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_ignorelid; extern int nouveau_force_post; extern int nouveau_override_conntype; extern char *nouveau_perflvl; extern int nouveau_perflvl_wr; extern int nouveau_msi; extern int nouveau_ctxfw; extern int nouveau_mxmdcb; extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); extern int nouveau_pci_resume(struct pci_dev *pdev); /* nouveau_state.c */ extern int nouveau_load(struct drm_device *, unsigned long flags); extern int nouveau_firstopen(struct drm_device *); extern void nouveau_lastclose(struct drm_device *); extern int nouveau_unload(struct drm_device *); extern int nouveau_card_init(struct drm_device *); /* nouveau_mem.c */ extern int nouveau_mem_timing_calc(struct drm_device *, u32 freq, struct nouveau_pm_memtiming *); extern void nouveau_mem_timing_read(struct drm_device *, struct nouveau_pm_memtiming *); /* nouveau_irq.c */ extern int nouveau_irq_init(struct drm_device *); extern void nouveau_irq_fini(struct drm_device *); extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); extern void nouveau_irq_register(struct drm_device *, int status_bit, void (*)(struct drm_device *)); extern void nouveau_irq_unregister(struct drm_device *, int status_bit); extern void nouveau_irq_preinstall(struct drm_device *); extern int nouveau_irq_postinstall(struct drm_device *); extern void nouveau_irq_uninstall(struct drm_device *); /* nouveau_acpi.c */ #define ROM_BIOS_PAGE 4096 #if defined(CONFIG_ACPI) void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); void nouveau_switcheroo_optimus_dsm(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); int nouveau_acpi_edid(struct drm_device *, struct drm_connector *); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} static inline void nouveau_switcheroo_optimus_dsm(void) {} static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; } #endif /* nouveau_backlight.c */ #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT extern int nouveau_backlight_init(struct drm_device *); extern void nouveau_backlight_exit(struct drm_device *); #else static inline int nouveau_backlight_init(struct drm_device *dev) { return 0; } static inline void nouveau_backlight_exit(struct drm_device *dev) { } #endif /* nouveau_bios.c */ extern int nouveau_bios_init(struct drm_device *); extern void nouveau_bios_takedown(struct drm_device *dev); extern int nouveau_run_vbios_init(struct drm_device *); extern struct dcb_connector_table_entry * nouveau_bios_connector_entry(struct drm_device *, int index); extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk, struct dcb_output *, int crtc); extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *); extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *); extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk, bool *dl, bool *if_is_24bit); extern int run_tmds_table(struct drm_device *, struct dcb_output *, int head, int pxclk); extern int call_lvds_script(struct drm_device *, struct dcb_output *, int head, enum LVDS_script, int pxclk); bool bios_encoder_match(struct dcb_output *, u32 hash); /* nouveau_mxm.c */ int nouveau_mxm_init(struct drm_device *dev); void nouveau_mxm_fini(struct drm_device *dev); /* nouveau_ttm.c */ int nouveau_ttm_global_init(struct drm_nouveau_private *); void nouveau_ttm_global_release(struct drm_nouveau_private *); int nouveau_ttm_mmap(struct file *, struct vm_area_struct *); /* nouveau_hdmi.c */ void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* nvd0_display.c */ extern int nvd0_display_create(struct drm_device *); extern void nvd0_display_destroy(struct drm_device *); extern int nvd0_display_init(struct drm_device *); extern void nvd0_display_fini(struct drm_device *); struct nouveau_bo *nvd0_display_crtc_sema(struct drm_device *, int crtc); void nvd0_display_flip_stop(struct drm_crtc *); int nvd0_display_flip_next(struct drm_crtc *, struct drm_framebuffer *, struct nouveau_channel *, u32 swap_interval); /* nouveau_display.c */ int nouveau_display_create(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev); int nouveau_display_init(struct drm_device *dev); void nouveau_display_fini(struct drm_device *dev); int nouveau_vblank_enable(struct drm_device *dev, int crtc); void nouveau_vblank_disable(struct drm_device *dev, int crtc); int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); int nouveau_finish_page_flip(struct nouveau_channel *, struct nouveau_page_flip_state *); int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, struct drm_mode_create_dumb *args); int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, uint32_t handle, uint64_t *offset); int nouveau_display_dumb_destroy(struct drm_file *, struct drm_device *, uint32_t handle); #ifndef ioread32_native #ifdef __BIG_ENDIAN #define ioread16_native ioread16be #define iowrite16_native iowrite16be #define ioread32_native ioread32be #define iowrite32_native iowrite32be #else /* def __BIG_ENDIAN */ #define ioread16_native ioread16 #define iowrite16_native iowrite16 #define ioread32_native ioread32 #define iowrite32_native iowrite32 #endif /* def __BIG_ENDIAN else */ #endif /* !ioread32_native */ /* register access */ #define nv_rd08 _nv_rd08 #define nv_wr08 _nv_wr08 #define nv_rd32 _nv_rd32 #define nv_wr32 _nv_wr32 #define nv_mask _nv_mask #define nv_wait(dev, reg, mask, val) \ nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) #define nv_wait_ne(dev, reg, mask, val) \ nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) #define nv_wait_cb(dev, func, data) \ nouveau_wait_cb(dev, 2000000000ULL, (func), (data)) /* * Logging * Argument d is (struct drm_device *). */ #define NV_PRINTK(level, d, fmt, arg...) \ printk(level "[" DRM_NAME "] " DRIVER_NAME " %s: " fmt, \ pci_name(d->pdev), ##arg) #ifndef NV_DEBUG_NOTRACE #define NV_DEBUG(d, fmt, arg...) do { \ if (drm_debug & DRM_UT_DRIVER) { \ NV_PRINTK(KERN_DEBUG, d, "%s:%d - " fmt, __func__, \ __LINE__, ##arg); \ } \ } while (0) #define NV_DEBUG_KMS(d, fmt, arg...) do { \ if (drm_debug & DRM_UT_KMS) { \ NV_PRINTK(KERN_DEBUG, d, "%s:%d - " fmt, __func__, \ __LINE__, ##arg); \ } \ } while (0) #else #define NV_DEBUG(d, fmt, arg...) do { \ if (drm_debug & DRM_UT_DRIVER) \ NV_PRINTK(KERN_DEBUG, d, fmt, ##arg); \ } while (0) #define NV_DEBUG_KMS(d, fmt, arg...) do { \ if (drm_debug & DRM_UT_KMS) \ NV_PRINTK(KERN_DEBUG, d, fmt, ##arg); \ } while (0) #endif #define NV_ERROR(d, fmt, arg...) NV_PRINTK(KERN_ERR, d, fmt, ##arg) #define NV_INFO(d, fmt, arg...) NV_PRINTK(KERN_INFO, d, fmt, ##arg) #define NV_TRACEWARN(d, fmt, arg...) NV_PRINTK(KERN_NOTICE, d, fmt, ##arg) #define NV_TRACE(d, fmt, arg...) NV_PRINTK(KERN_INFO, d, fmt, ##arg) #define NV_WARN(d, fmt, arg...) NV_PRINTK(KERN_WARNING, d, fmt, ##arg) #define NV_WARNONCE(d, fmt, arg...) do { \ static int _warned = 0; \ if (!_warned) { \ NV_WARN(d, fmt, ##arg); \ _warned = 1; \ } \ } while(0) static inline bool nv_two_heads(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; const int impl = dev->pci_device & 0x0ff0; if (dev_priv->card_type >= NV_10 && impl != 0x0100 && impl != 0x0150 && impl != 0x01a0 && impl != 0x0200) return true; return false; } static inline bool nv_gf4_disp_arch(struct drm_device *dev) { return nv_two_heads(dev) && (dev->pci_device & 0x0ff0) != 0x0110; } static inline bool nv_two_reg_pll(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; const int impl = dev->pci_device & 0x0ff0; if (impl == 0x0310 || impl == 0x0340 || dev_priv->card_type >= NV_40) return true; return false; } static inline bool nv_match_device(struct drm_device *dev, unsigned device, unsigned sub_vendor, unsigned sub_device) { return dev->pdev->device == device && dev->pdev->subsystem_vendor == sub_vendor && dev->pdev->subsystem_device == sub_device; } #endif /* __NOUVEAU_DRV_H__ */