drm/i915: Update to match Linux 3.8.13
This update brings initial support for Haswell GPUs. Tested by: Many users of FreeBSD, PC-BSD and HardenedBSD Relnotes: yes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D5554
This commit is contained in:
parent
a87488d1e4
commit
740be6d755
@ -250,6 +250,10 @@ struct agp_i810_driver {
|
||||
void (*chipset_flush)(device_t);
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct intel_gtt base;
|
||||
} intel_private;
|
||||
|
||||
static const struct agp_i810_driver agp_i810_i810_driver = {
|
||||
.chiptype = CHIP_I810,
|
||||
.gen = 1,
|
||||
@ -526,6 +530,29 @@ static const struct agp_i810_driver agp_i810_hsw_driver = {
|
||||
.chipset_flush = agp_i810_chipset_flush,
|
||||
};
|
||||
|
||||
static const struct agp_i810_driver agp_i810_valleyview_driver = {
|
||||
.chiptype = CHIP_SB,
|
||||
.gen = 7,
|
||||
.busdma_addr_mask_sz = 40,
|
||||
.res_spec = agp_g4x_res_spec,
|
||||
.check_active = agp_sb_check_active,
|
||||
.set_desc = agp_i810_set_desc,
|
||||
.dump_regs = agp_sb_dump_regs,
|
||||
.get_stolen_size = agp_sb_get_stolen_size,
|
||||
.get_gtt_mappable_entries = agp_i915_get_gtt_mappable_entries,
|
||||
.get_gtt_total_entries = agp_sb_get_gtt_total_entries,
|
||||
.install_gatt = agp_g4x_install_gatt,
|
||||
.deinstall_gatt = agp_i830_deinstall_gatt,
|
||||
.write_gtt = agp_sb_write_gtt,
|
||||
.install_gtt_pte = agp_sb_install_gtt_pte,
|
||||
.read_gtt_pte = agp_g4x_read_gtt_pte,
|
||||
.read_gtt_pte_paddr = agp_sb_read_gtt_pte_paddr,
|
||||
.set_aperture = agp_i915_set_aperture,
|
||||
.chipset_flush_setup = agp_i810_chipset_flush_setup,
|
||||
.chipset_flush_teardown = agp_i810_chipset_flush_teardown,
|
||||
.chipset_flush = agp_i810_chipset_flush,
|
||||
};
|
||||
|
||||
/* For adding new devices, devid is the id of the graphics controller
|
||||
* (pci:0:2:0, for example). The placeholder (usually at pci:0:2:1) for the
|
||||
* second head should never be added. The bridge_offset is the offset to
|
||||
@ -763,39 +790,199 @@ static const struct agp_i810_match {
|
||||
},
|
||||
{
|
||||
.devid = 0x04028086,
|
||||
.name = "Haswell desktop GT1",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x04128086,
|
||||
.name = "Haswell desktop GT2",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x040a8086,
|
||||
.name = "Haswell server GT1",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x041a8086,
|
||||
.name = "Haswell server GT2",
|
||||
.name = "Haswell GT1 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x04068086,
|
||||
.name = "Haswell mobile GT1",
|
||||
.name = "Haswell GT1 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x040A8086,
|
||||
.name = "Haswell GT1 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x04128086,
|
||||
.name = "Haswell GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x04168086,
|
||||
.name = "Haswell mobile GT2",
|
||||
.name = "Haswell GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0c168086,
|
||||
.name = "Haswell SDV",
|
||||
.devid = 0x041A8086,
|
||||
.name = "Haswell GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x04228086,
|
||||
.name = "Haswell GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x04268086,
|
||||
.name = "Haswell GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x042A8086,
|
||||
.name = "Haswell GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A028086,
|
||||
.name = "Haswell ULT GT1 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A068086,
|
||||
.name = "Haswell ULT GT1 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A0A8086,
|
||||
.name = "Haswell ULT GT1 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A128086,
|
||||
.name = "Haswell ULT GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A168086,
|
||||
.name = "Haswell ULT GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A1A8086,
|
||||
.name = "Haswell ULT GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A228086,
|
||||
.name = "Haswell ULT GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A268086,
|
||||
.name = "Haswell ULT GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0A2A8086,
|
||||
.name = "Haswell ULT GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C028086,
|
||||
.name = "Haswell SDV GT1 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C068086,
|
||||
.name = "Haswell SDV GT1 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C0A8086,
|
||||
.name = "Haswell SDV GT1 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C128086,
|
||||
.name = "Haswell SDV GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C168086,
|
||||
.name = "Haswell SDV GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C1A8086,
|
||||
.name = "Haswell SDV GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C228086,
|
||||
.name = "Haswell SDV GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C268086,
|
||||
.name = "Haswell SDV GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0C2A8086,
|
||||
.name = "Haswell SDV GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D028086,
|
||||
.name = "Haswell CRW GT1 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D068086,
|
||||
.name = "Haswell CRW GT1 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D0A8086,
|
||||
.name = "Haswell CRW GT1 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D128086,
|
||||
.name = "Haswell CRW GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D168086,
|
||||
.name = "Haswell CRW GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D1A8086,
|
||||
.name = "Haswell CRW GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D228086,
|
||||
.name = "Haswell CRW GT2 desktop",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D268086,
|
||||
.name = "Haswell CRW GT2 mobile",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0D2A8086,
|
||||
.name = "Haswell CRW GT2 server",
|
||||
.driver = &agp_i810_hsw_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x01558086,
|
||||
.name = "Valleyview (desktop)",
|
||||
.driver = &agp_i810_valleyview_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x01578086,
|
||||
.name = "Valleyview (mobile)",
|
||||
.driver = &agp_i810_valleyview_driver
|
||||
},
|
||||
{
|
||||
.devid = 0x0F308086,
|
||||
.name = "Valleyview (mobile)",
|
||||
.driver = &agp_i810_valleyview_driver
|
||||
},
|
||||
{
|
||||
.devid = 0,
|
||||
}
|
||||
@ -2285,6 +2472,10 @@ agp_intel_gtt_get(device_t dev)
|
||||
res.gtt_mappable_entries = sc->gtt_mappable_entries;
|
||||
res.do_idle_maps = 0;
|
||||
res.scratch_page_dma = VM_PAGE_TO_PHYS(bogus_page);
|
||||
if (sc->agp.as_aperture != NULL)
|
||||
res.gma_bus_addr = rman_get_start(sc->agp.as_aperture);
|
||||
else
|
||||
res.gma_bus_addr = 0;
|
||||
return (res);
|
||||
}
|
||||
|
||||
@ -2588,11 +2779,12 @@ intel_gtt_insert_pages(u_int first_entry, u_int num_entries, vm_page_t *pages,
|
||||
pages, flags);
|
||||
}
|
||||
|
||||
struct intel_gtt
|
||||
struct intel_gtt *
|
||||
intel_gtt_get(void)
|
||||
{
|
||||
|
||||
return (agp_intel_gtt_get(intel_agp));
|
||||
intel_private.base = agp_intel_gtt_get(intel_agp);
|
||||
return (&intel_private.base);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -33,6 +33,7 @@
|
||||
#define AGP_AGP_I810_H
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sglist.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
@ -51,24 +52,23 @@
|
||||
|
||||
struct intel_gtt {
|
||||
/* Size of memory reserved for graphics by the BIOS */
|
||||
u_int stolen_size;
|
||||
unsigned int stolen_size;
|
||||
/* Total number of gtt entries. */
|
||||
u_int gtt_total_entries;
|
||||
/*
|
||||
* Part of the gtt that is mappable by the cpu, for those
|
||||
* chips where this is not the full gtt.
|
||||
*/
|
||||
u_int gtt_mappable_entries;
|
||||
|
||||
/*
|
||||
* Always false.
|
||||
*/
|
||||
u_int do_idle_maps;
|
||||
|
||||
/*
|
||||
* Share the scratch page dma with ppgtts.
|
||||
*/
|
||||
unsigned int gtt_total_entries;
|
||||
/* Part of the gtt that is mappable by the cpu, for those chips where
|
||||
* this is not the full gtt. */
|
||||
unsigned int gtt_mappable_entries;
|
||||
/* Whether i915 needs to use the dmar apis or not. */
|
||||
unsigned int needs_dmar : 1;
|
||||
/* Whether we idle the gpu before mapping/unmapping */
|
||||
unsigned int do_idle_maps : 1;
|
||||
/* Share the scratch page dma with ppgtts. */
|
||||
vm_paddr_t scratch_page_dma;
|
||||
vm_page_t scratch_page;
|
||||
/* for ppgtt PDE access */
|
||||
uint32_t *gtt;
|
||||
/* needed for ioremap in drm/i915 */
|
||||
bus_addr_t gma_bus_addr;
|
||||
};
|
||||
|
||||
struct intel_gtt agp_intel_gtt_get(device_t dev);
|
||||
@ -83,7 +83,7 @@ void agp_intel_gtt_insert_sg_entries(device_t dev, struct sglist *sg_list,
|
||||
void agp_intel_gtt_insert_pages(device_t dev, u_int first_entry,
|
||||
u_int num_entries, vm_page_t *pages, u_int flags);
|
||||
|
||||
struct intel_gtt intel_gtt_get(void);
|
||||
struct intel_gtt *intel_gtt_get(void);
|
||||
int intel_gtt_chipset_flush(void);
|
||||
void intel_gtt_unmap_memory(struct sglist *sg_list);
|
||||
void intel_gtt_clear_range(u_int first_entry, u_int num_entries);
|
||||
|
@ -238,7 +238,6 @@ struct drm_device;
|
||||
__func__ , ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*@}*/
|
||||
|
||||
/***********************************************************************/
|
||||
@ -700,6 +699,8 @@ struct drm_driver {
|
||||
void (*postclose) (struct drm_device *, struct drm_file *);
|
||||
void (*lastclose) (struct drm_device *);
|
||||
int (*unload) (struct drm_device *);
|
||||
int (*suspend) (struct drm_device *, pm_message_t state);
|
||||
int (*resume) (struct drm_device *);
|
||||
int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
int (*dma_quiescent) (struct drm_device *);
|
||||
int (*context_dtor) (struct drm_device *dev, int context);
|
||||
@ -1118,7 +1119,7 @@ struct drm_device {
|
||||
char busid_str[128];
|
||||
int modesetting;
|
||||
|
||||
drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */
|
||||
const drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */
|
||||
};
|
||||
|
||||
#define DRM_SWITCH_POWER_ON 0
|
||||
@ -1581,6 +1582,8 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map)
|
||||
{
|
||||
}
|
||||
|
||||
#include <dev/drm2/drm_mem_util.h>
|
||||
|
||||
extern int drm_fill_in_dev(struct drm_device *dev,
|
||||
struct drm_driver *driver);
|
||||
extern void drm_cancel_fill_in_dev(struct drm_device *dev);
|
||||
@ -1758,9 +1761,11 @@ struct dmi_system_id {
|
||||
bool dmi_check_system(const struct dmi_system_id *);
|
||||
|
||||
/* Device setup support (drm_drv.c) */
|
||||
int drm_probe_helper(device_t kdev, drm_pci_id_list_t *idlist);
|
||||
int drm_attach_helper(device_t kdev, drm_pci_id_list_t *idlist,
|
||||
int drm_probe_helper(device_t kdev, const drm_pci_id_list_t *idlist);
|
||||
int drm_attach_helper(device_t kdev, const drm_pci_id_list_t *idlist,
|
||||
struct drm_driver *driver);
|
||||
int drm_generic_suspend(device_t kdev);
|
||||
int drm_generic_resume(device_t kdev);
|
||||
int drm_generic_detach(device_t kdev);
|
||||
|
||||
void drm_event_wakeup(struct drm_pending_event *e);
|
||||
|
@ -39,8 +39,8 @@ typedef uint64_t atomic64_t;
|
||||
#define NB_BITS_PER_LONG (sizeof(long) * NBBY)
|
||||
#define BITS_TO_LONGS(x) howmany(x, NB_BITS_PER_LONG)
|
||||
|
||||
#define atomic_read(p) (*(volatile u_int *)(p))
|
||||
#define atomic_set(p, v) do { *(u_int *)(p) = (v); } while (0)
|
||||
#define atomic_read(p) atomic_load_acq_int(p)
|
||||
#define atomic_set(p, v) atomic_store_rel_int(p, v)
|
||||
|
||||
#define atomic64_read(p) atomic_load_acq_64(p)
|
||||
#define atomic64_set(p, v) atomic_store_rel_64(p, v)
|
||||
@ -78,6 +78,9 @@ typedef uint64_t atomic64_t;
|
||||
#define cmpxchg(ptr, old, new) \
|
||||
(atomic_cmpset_int((volatile u_int *)(ptr),(old),(new)) ? (old) : (0))
|
||||
|
||||
#define atomic_inc_not_zero(p) atomic_inc(p)
|
||||
#define atomic_clear_mask(b, p) atomic_clear_int((p), (b))
|
||||
|
||||
static __inline u_long
|
||||
find_first_zero_bit(const u_long *p, u_long max)
|
||||
{
|
||||
|
@ -149,7 +149,7 @@ iic_dp_aux_xfer(device_t idev, struct iic_msg *msgs, uint32_t num)
|
||||
buf = msgs[m].buf;
|
||||
reading = (msgs[m].flags & IIC_M_RD) != 0;
|
||||
ret = iic_dp_aux_address(idev, msgs[m].slave >> 1, reading);
|
||||
if (ret != 0)
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (reading) {
|
||||
for (b = 0; b < len; b++) {
|
||||
@ -160,7 +160,7 @@ iic_dp_aux_xfer(device_t idev, struct iic_msg *msgs, uint32_t num)
|
||||
} else {
|
||||
for (b = 0; b < len; b++) {
|
||||
ret = iic_dp_aux_put_byte(idev, buf[b]);
|
||||
if (ret != 0)
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -470,6 +470,14 @@ int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags,
|
||||
|
||||
err_i1:
|
||||
atomic_dec(&dev->ioctl_count);
|
||||
if (retcode == -ERESTARTSYS) {
|
||||
/*
|
||||
* FIXME: Find where in i915 ERESTARTSYS should be
|
||||
* converted to EINTR.
|
||||
*/
|
||||
DRM_DEBUG("ret = %d -> %d\n", retcode, -EINTR);
|
||||
retcode = -EINTR;
|
||||
}
|
||||
if (retcode)
|
||||
DRM_DEBUG("ret = %d\n", retcode);
|
||||
if (retcode != 0 &&
|
||||
|
@ -40,7 +40,6 @@ struct list_head {
|
||||
};
|
||||
|
||||
#define list_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
static __inline__ void
|
||||
INIT_LIST_HEAD(struct list_head *head) {
|
||||
@ -179,4 +178,123 @@ list_splice(const struct list_head *list, struct list_head *head)
|
||||
void drm_list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
|
||||
struct list_head *a, struct list_head *b));
|
||||
|
||||
/* hlist, copied from sys/dev/ofed/linux/list.h */
|
||||
|
||||
struct hlist_head {
|
||||
struct hlist_node *first;
|
||||
};
|
||||
|
||||
struct hlist_node {
|
||||
struct hlist_node *next, **pprev;
|
||||
};
|
||||
|
||||
#define HLIST_HEAD_INIT { }
|
||||
#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT
|
||||
#define INIT_HLIST_HEAD(head) (head)->first = NULL
|
||||
#define INIT_HLIST_NODE(node) \
|
||||
do { \
|
||||
(node)->next = NULL; \
|
||||
(node)->pprev = NULL; \
|
||||
} while (0)
|
||||
|
||||
static inline int
|
||||
hlist_unhashed(const struct hlist_node *h)
|
||||
{
|
||||
|
||||
return !h->pprev;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
|
||||
return !h->first;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlist_del(struct hlist_node *n)
|
||||
{
|
||||
|
||||
if (n->next)
|
||||
n->next->pprev = n->pprev;
|
||||
*n->pprev = n->next;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlist_del_init(struct hlist_node *n)
|
||||
{
|
||||
|
||||
if (hlist_unhashed(n))
|
||||
return;
|
||||
hlist_del(n);
|
||||
INIT_HLIST_NODE(n);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
|
||||
n->next = h->first;
|
||||
if (h->first)
|
||||
h->first->pprev = &n->next;
|
||||
h->first = n;
|
||||
n->pprev = &h->first;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlist_add_before(struct hlist_node *n, struct hlist_node *next)
|
||||
{
|
||||
|
||||
n->pprev = next->pprev;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
*(n->pprev) = n;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlist_add_after(struct hlist_node *n, struct hlist_node *next)
|
||||
{
|
||||
|
||||
next->next = n->next;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
if (next->next)
|
||||
next->next->pprev = &next->next;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlist_move_list(struct hlist_head *old, struct hlist_head *new)
|
||||
{
|
||||
|
||||
new->first = old->first;
|
||||
if (new->first)
|
||||
new->first->pprev = &new->first;
|
||||
old->first = NULL;
|
||||
}
|
||||
|
||||
#define hlist_entry(ptr, type, field) container_of(ptr, type, field)
|
||||
|
||||
#define hlist_for_each(p, head) \
|
||||
for (p = (head)->first; p; p = p->next)
|
||||
|
||||
#define hlist_for_each_safe(p, n, head) \
|
||||
for (p = (head)->first; p && ({ n = p->next; 1; }); p = n)
|
||||
|
||||
#define hlist_for_each_entry(tp, p, head, field) \
|
||||
for (p = (head)->first; \
|
||||
p ? (tp = hlist_entry(p, typeof(*tp), field)): NULL; p = p->next)
|
||||
|
||||
#define hlist_for_each_entry_continue(tp, p, field) \
|
||||
for (p = (p)->next; \
|
||||
p ? (tp = hlist_entry(p, typeof(*tp), field)): NULL; p = p->next)
|
||||
|
||||
#define hlist_for_each_entry_from(tp, p, field) \
|
||||
for (; p ? (tp = hlist_entry(p, typeof(*tp), field)): NULL; p = p->next)
|
||||
|
||||
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
(pos) != 0 && ({ n = (pos)->next; \
|
||||
tpos = hlist_entry((pos), typeof(*(tpos)), member); 1;}); \
|
||||
pos = (n))
|
||||
|
||||
#endif /* _DRM_LINUX_LIST_H_ */
|
||||
|
59
sys/dev/drm2/drm_mem_util.h
Normal file
59
sys/dev/drm2/drm_mem_util.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright © 2008 Intel Corporation
|
||||
*
|
||||
* 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
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
|
||||
* Jesse Barnes <jbarnes@virtuousgeek.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifndef _DRM_MEM_UTIL_H_
|
||||
#define _DRM_MEM_UTIL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
|
||||
{
|
||||
if (size != 0 && nmemb > SIZE_MAX / size)
|
||||
return NULL;
|
||||
|
||||
return malloc(nmemb * size, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
|
||||
}
|
||||
|
||||
/* Modeled after cairo's malloc_ab, it's like calloc but without the zeroing. */
|
||||
static __inline__ void *drm_malloc_ab(size_t nmemb, size_t size)
|
||||
{
|
||||
if (size != 0 && nmemb > SIZE_MAX / size)
|
||||
return NULL;
|
||||
|
||||
return malloc(nmemb * size, DRM_MEM_DRIVER, M_NOWAIT);
|
||||
}
|
||||
|
||||
static __inline void drm_free_large(void *ptr)
|
||||
{
|
||||
free(ptr, DRM_MEM_DRIVER);
|
||||
}
|
||||
|
||||
#endif
|
@ -67,8 +67,27 @@ ns_to_timeval(const int64_t nsec)
|
||||
return (tv);
|
||||
}
|
||||
|
||||
static drm_pci_id_list_t *
|
||||
drm_find_description(int vendor, int device, drm_pci_id_list_t *idlist)
|
||||
/* Copied from OFED. */
|
||||
unsigned long drm_linux_timer_hz_mask;
|
||||
|
||||
static void
|
||||
drm_linux_timer_init(void *arg)
|
||||
{
|
||||
|
||||
/*
|
||||
* Compute an internal HZ value which can divide 2**32 to
|
||||
* avoid timer rounding problems when the tick value wraps
|
||||
* around 2**32:
|
||||
*/
|
||||
drm_linux_timer_hz_mask = 1;
|
||||
while (drm_linux_timer_hz_mask < (unsigned long)hz)
|
||||
drm_linux_timer_hz_mask *= 2;
|
||||
drm_linux_timer_hz_mask--;
|
||||
}
|
||||
SYSINIT(drm_linux_timer, SI_SUB_DRIVERS, SI_ORDER_FIRST, drm_linux_timer_init, NULL);
|
||||
|
||||
static const drm_pci_id_list_t *
|
||||
drm_find_description(int vendor, int device, const drm_pci_id_list_t *idlist)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@ -87,9 +106,9 @@ drm_find_description(int vendor, int device, drm_pci_id_list_t *idlist)
|
||||
* method.
|
||||
*/
|
||||
int
|
||||
drm_probe_helper(device_t kdev, drm_pci_id_list_t *idlist)
|
||||
drm_probe_helper(device_t kdev, const drm_pci_id_list_t *idlist)
|
||||
{
|
||||
drm_pci_id_list_t *id_entry;
|
||||
const drm_pci_id_list_t *id_entry;
|
||||
int vendor, device;
|
||||
|
||||
vendor = pci_get_vendor(kdev);
|
||||
@ -118,7 +137,7 @@ drm_probe_helper(device_t kdev, drm_pci_id_list_t *idlist)
|
||||
* method.
|
||||
*/
|
||||
int
|
||||
drm_attach_helper(device_t kdev, drm_pci_id_list_t *idlist,
|
||||
drm_attach_helper(device_t kdev, const drm_pci_id_list_t *idlist,
|
||||
struct drm_driver *driver)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
@ -136,6 +155,55 @@ drm_attach_helper(device_t kdev, drm_pci_id_list_t *idlist,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
drm_generic_suspend(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
int error;
|
||||
|
||||
DRM_DEBUG_KMS("Starting suspend\n");
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
if (dev->driver->suspend) {
|
||||
pm_message_t state;
|
||||
|
||||
state.event = PM_EVENT_SUSPEND;
|
||||
error = -dev->driver->suspend(dev, state);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = bus_generic_suspend(kdev);
|
||||
|
||||
out:
|
||||
DRM_DEBUG_KMS("Finished suspend: %d\n", error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
drm_generic_resume(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
int error;
|
||||
|
||||
DRM_DEBUG_KMS("Starting resume\n");
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
if (dev->driver->resume) {
|
||||
error = -dev->driver->resume(dev);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = bus_generic_resume(kdev);
|
||||
|
||||
out:
|
||||
DRM_DEBUG_KMS("Finished resume: %d\n", error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
drm_generic_detach(device_t kdev)
|
||||
{
|
||||
@ -331,6 +399,42 @@ drm_clflush_virt_range(char *addr, unsigned long length)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
|
||||
char *linebuf, size_t linebuflen, bool ascii __unused)
|
||||
{
|
||||
int i, j, c;
|
||||
|
||||
i = j = 0;
|
||||
|
||||
while (i < len && j <= linebuflen) {
|
||||
c = ((const char *)buf)[i];
|
||||
|
||||
if (i != 0) {
|
||||
if (i % rowsize == 0) {
|
||||
/* Newline required. */
|
||||
sprintf(linebuf + j, "\n");
|
||||
++j;
|
||||
} else if (i % groupsize == 0) {
|
||||
/* Space required. */
|
||||
sprintf(linebuf + j, " ");
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
if (j > linebuflen - 1)
|
||||
break;
|
||||
|
||||
sprintf(linebuf + j, "%02X", c);
|
||||
j += 2;
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (j <= linebuflen)
|
||||
sprintf(linebuf + j, "\n");
|
||||
}
|
||||
|
||||
#if DRM_LINUX
|
||||
|
||||
#include <sys/sysproto.h>
|
||||
|
@ -10,6 +10,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define _DRM_OS_FREEBSD_H_
|
||||
|
||||
#include <sys/fbio.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#if _BYTE_ORDER == _BIG_ENDIAN
|
||||
#define __BIG_ENDIAN 4321
|
||||
@ -24,10 +25,22 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
|
||||
#ifndef __user
|
||||
#define __user
|
||||
#define __user
|
||||
#endif
|
||||
#ifndef __iomem
|
||||
#define __iomem
|
||||
#define __iomem
|
||||
#endif
|
||||
#ifndef __always_unused
|
||||
#define __always_unused
|
||||
#endif
|
||||
#ifndef __must_check
|
||||
#define __must_check
|
||||
#endif
|
||||
#ifndef __force
|
||||
#define __force
|
||||
#endif
|
||||
#ifndef uninitialized_var
|
||||
#define uninitialized_var(x) x
|
||||
#endif
|
||||
|
||||
#define cpu_to_le16(x) htole16(x)
|
||||
@ -69,9 +82,23 @@ typedef void irqreturn_t;
|
||||
#define __exit
|
||||
#define __read_mostly
|
||||
|
||||
#define WARN_ON(cond) KASSERT(!(cond), ("WARN ON: " #cond))
|
||||
#define BUILD_BUG_ON(x) CTASSERT(!(x))
|
||||
#define BUILD_BUG_ON_NOT_POWER_OF_2(x)
|
||||
|
||||
#ifndef WARN
|
||||
#define WARN(condition, format, ...) ({ \
|
||||
int __ret_warn_on = !!(condition); \
|
||||
if (unlikely(__ret_warn_on)) \
|
||||
DRM_ERROR(format, ##__VA_ARGS__); \
|
||||
unlikely(__ret_warn_on); \
|
||||
})
|
||||
#endif
|
||||
#define WARN_ONCE(condition, format, ...) \
|
||||
WARN(condition, format, ##__VA_ARGS__)
|
||||
#define WARN_ON(cond) WARN(cond, "WARN ON: " #cond)
|
||||
#define WARN_ON_SMP(cond) WARN_ON(cond)
|
||||
#define BUG_ON(cond) KASSERT(!(cond), ("BUG ON: " #cond))
|
||||
#define BUG() panic("BUG")
|
||||
#define BUG_ON(cond) KASSERT(!(cond), ("BUG ON: " #cond " -> 0x%jx", (uintmax_t)(cond)))
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
@ -93,6 +120,15 @@ typedef void irqreturn_t;
|
||||
#define DRM_UDELAY(udelay) DELAY(udelay)
|
||||
#define drm_msleep(x, msg) pause((msg), ((int64_t)(x)) * hz / 1000)
|
||||
#define DRM_MSLEEP(msecs) drm_msleep((msecs), "drm_msleep")
|
||||
#define get_seconds() time_second
|
||||
|
||||
#define ioread8(addr) *(volatile uint8_t *)((char *)addr)
|
||||
#define ioread16(addr) *(volatile uint16_t *)((char *)addr)
|
||||
#define ioread32(addr) *(volatile uint32_t *)((char *)addr)
|
||||
|
||||
#define iowrite8(data, addr) *(volatile uint8_t *)((char *)addr) = data;
|
||||
#define iowrite16(data, addr) *(volatile uint16_t *)((char *)addr) = data;
|
||||
#define iowrite32(data, addr) *(volatile uint32_t *)((char *)addr) = data;
|
||||
|
||||
#define DRM_READ8(map, offset) \
|
||||
*(volatile u_int8_t *)(((vm_offset_t)(map)->handle) + \
|
||||
@ -127,12 +163,18 @@ typedef void irqreturn_t;
|
||||
#define DRM_WRITEMEMORYBARRIER() wmb()
|
||||
#define DRM_MEMORYBARRIER() mb()
|
||||
#define smp_rmb() rmb()
|
||||
#define smp_wmb() wmb()
|
||||
#define smp_mb__before_atomic_inc() mb()
|
||||
#define smp_mb__after_atomic_inc() mb()
|
||||
#define barrier() __compiler_membar()
|
||||
|
||||
#define do_div(a, b) ((a) /= (b))
|
||||
#define div64_u64(a, b) ((a) / (b))
|
||||
#define lower_32_bits(n) ((u32)(n))
|
||||
#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
|
||||
|
||||
#define __set_bit(n, s) set_bit((n), (s))
|
||||
#define __clear_bit(n, s) clear_bit((n), (s))
|
||||
|
||||
#define min_t(type, x, y) ({ \
|
||||
type __min1 = (x); \
|
||||
@ -148,6 +190,10 @@ typedef void irqreturn_t;
|
||||
#define memcpy_fromio(a, b, c) memcpy((a), (b), (c))
|
||||
#define memcpy_toio(a, b, c) memcpy((a), (b), (c))
|
||||
|
||||
#define VERIFY_READ VM_PROT_READ
|
||||
#define VERIFY_WRITE VM_PROT_WRITE
|
||||
#define access_ok(prot, p, l) useracc((p), (l), (prot))
|
||||
|
||||
/* XXXKIB what is the right code for the FreeBSD ? */
|
||||
/* kib@ used ENXIO here -- dumbbell@ */
|
||||
#define EREMOTEIO EIO
|
||||
@ -170,8 +216,10 @@ typedef void irqreturn_t;
|
||||
#define PCI_VENDOR_ID_SONY 0x104d
|
||||
#define PCI_VENDOR_ID_VIA 0x1106
|
||||
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
#define hweight32(i) bitcount32(i)
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
#define DIV_ROUND_CLOSEST(n,d) (((n) + (d) / 2) / (d))
|
||||
#define div_u64(n, d) ((n) / (d))
|
||||
#define hweight32(i) bitcount32(i)
|
||||
|
||||
static inline unsigned long
|
||||
roundup_pow_of_two(unsigned long x)
|
||||
@ -195,6 +243,8 @@ ror32(uint32_t word, unsigned int shift)
|
||||
}
|
||||
|
||||
#define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0)
|
||||
#define round_down(x, y) rounddown2((x), (y))
|
||||
#define round_up(x, y) roundup2((x), (y))
|
||||
#define get_unaligned(ptr) \
|
||||
({ __typeof__(*(ptr)) __tmp; \
|
||||
memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
|
||||
@ -251,7 +301,9 @@ abs64(int64_t x)
|
||||
int64_t timeval_to_ns(const struct timeval *tv);
|
||||
struct timeval ns_to_timeval(const int64_t nsec);
|
||||
|
||||
#define PAGE_ALIGN(addr) round_page(addr)
|
||||
#define PAGE_ALIGN(addr) round_page(addr)
|
||||
#define page_to_phys(x) VM_PAGE_TO_PHYS(x)
|
||||
#define offset_in_page(x) ((x) & PAGE_MASK)
|
||||
|
||||
#define drm_get_device_from_kdev(_kdev) (((struct drm_minor *)(_kdev)->si_drv1)->dev)
|
||||
|
||||
@ -295,20 +347,193 @@ __get_user(size_t size, const void *ptr, void *x)
|
||||
}
|
||||
#define get_user(x, ptr) __get_user(sizeof(*ptr), (ptr), &(x))
|
||||
|
||||
static inline int
|
||||
__copy_to_user_inatomic(void __user *to, const void *from, unsigned n)
|
||||
{
|
||||
|
||||
return (copyout_nofault(from, to, n) != 0 ? n : 0);
|
||||
}
|
||||
#define __copy_to_user_inatomic_nocache(to, from, n) \
|
||||
__copy_to_user_inatomic((to), (from), (n))
|
||||
|
||||
static inline unsigned long
|
||||
__copy_from_user_inatomic(void *to, const void __user *from,
|
||||
unsigned long n)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXXKIB. Equivalent Linux function is implemented using
|
||||
* MOVNTI for aligned moves. For unaligned head and tail,
|
||||
* normal move is performed. As such, it is not incorrect, if
|
||||
* only somewhat slower, to use normal copyin. All uses
|
||||
* except shmem_pwrite_fast() have the destination mapped WC.
|
||||
*/
|
||||
return ((copyin_nofault(__DECONST(void *, from), to, n) != 0 ? n : 0));
|
||||
}
|
||||
#define __copy_from_user_inatomic_nocache(to, from, n) \
|
||||
__copy_from_user_inatomic((to), (from), (n))
|
||||
|
||||
static inline int
|
||||
fault_in_multipages_readable(const char __user *uaddr, int size)
|
||||
{
|
||||
char c;
|
||||
int ret = 0;
|
||||
const char __user *end = uaddr + size - 1;
|
||||
|
||||
if (unlikely(size == 0))
|
||||
return ret;
|
||||
|
||||
while (uaddr <= end) {
|
||||
ret = -copyin(uaddr, &c, 1);
|
||||
if (ret != 0)
|
||||
return -EFAULT;
|
||||
uaddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* Check whether the range spilled into the next page. */
|
||||
if (((unsigned long)uaddr & ~PAGE_MASK) ==
|
||||
((unsigned long)end & ~PAGE_MASK)) {
|
||||
ret = -copyin(end, &c, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
fault_in_multipages_writeable(char __user *uaddr, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
char __user *end = uaddr + size - 1;
|
||||
|
||||
if (unlikely(size == 0))
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Writing zeroes into userspace here is OK, because we know that if
|
||||
* the zero gets there, we'll be overwriting it.
|
||||
*/
|
||||
while (uaddr <= end) {
|
||||
ret = subyte(uaddr, 0);
|
||||
if (ret != 0)
|
||||
return -EFAULT;
|
||||
uaddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* Check whether the range spilled into the next page. */
|
||||
if (((unsigned long)uaddr & ~PAGE_MASK) ==
|
||||
((unsigned long)end & ~PAGE_MASK))
|
||||
ret = subyte(end, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum __drm_capabilities {
|
||||
CAP_SYS_ADMIN
|
||||
};
|
||||
|
||||
static inline bool
|
||||
capable(enum __drm_capabilities cap)
|
||||
{
|
||||
|
||||
switch (cap) {
|
||||
case CAP_SYS_ADMIN:
|
||||
return DRM_SUSER(curthread);
|
||||
}
|
||||
}
|
||||
|
||||
#define to_user_ptr(x) ((void *)(uintptr_t)(x))
|
||||
#define sigemptyset(set) SIGEMPTYSET(set)
|
||||
#define sigaddset(set, sig) SIGADDSET(set, sig)
|
||||
|
||||
#define DRM_LOCK(dev) sx_xlock(&(dev)->dev_struct_lock)
|
||||
#define DRM_UNLOCK(dev) sx_xunlock(&(dev)->dev_struct_lock)
|
||||
|
||||
extern unsigned long drm_linux_timer_hz_mask;
|
||||
#define jiffies ticks
|
||||
#define jiffies_to_msecs(x) (((int64_t)(x)) * 1000 / hz)
|
||||
#define msecs_to_jiffies(x) (((int64_t)(x)) * hz / 1000)
|
||||
#define timespec_to_jiffies(x) (((x)->tv_sec * 1000000 + (x)->tv_nsec) * hz / 1000000)
|
||||
#define time_after(a,b) ((long)(b) - (long)(a) < 0)
|
||||
#define time_after_eq(a,b) ((long)(b) - (long)(a) <= 0)
|
||||
#define round_jiffies(j) ((unsigned long)(((j) + drm_linux_timer_hz_mask) & ~drm_linux_timer_hz_mask))
|
||||
#define round_jiffies_up(j) round_jiffies(j) /* TODO */
|
||||
#define round_jiffies_up_relative(j) round_jiffies_up(j) /* TODO */
|
||||
|
||||
#define wake_up(queue) wakeup((void *)queue)
|
||||
#define wake_up_interruptible(queue) wakeup((void *)queue)
|
||||
#define getrawmonotonic(ts) getnanouptime(ts)
|
||||
|
||||
#define wake_up(queue) wakeup_one((void *)queue)
|
||||
#define wake_up_interruptible(queue) wakeup_one((void *)queue)
|
||||
#define wake_up_all(queue) wakeup((void *)queue)
|
||||
#define wake_up_interruptible_all(queue) wakeup((void *)queue)
|
||||
|
||||
struct completion {
|
||||
unsigned int done;
|
||||
struct mtx lock;
|
||||
};
|
||||
|
||||
#define INIT_COMPLETION(c) ((c).done = 0);
|
||||
|
||||
static inline void
|
||||
init_completion(struct completion *c)
|
||||
{
|
||||
|
||||
mtx_init(&c->lock, "drmcompl", NULL, MTX_DEF);
|
||||
c->done = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_completion(struct completion *c)
|
||||
{
|
||||
|
||||
mtx_destroy(&c->lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
complete_all(struct completion *c)
|
||||
{
|
||||
|
||||
mtx_lock(&c->lock);
|
||||
c->done++;
|
||||
mtx_unlock(&c->lock);
|
||||
wakeup(c);
|
||||
}
|
||||
|
||||
static inline long
|
||||
wait_for_completion_interruptible_timeout(struct completion *c,
|
||||
unsigned long timeout)
|
||||
{
|
||||
unsigned long start_jiffies, elapsed_jiffies;
|
||||
bool timeout_expired = false, awakened = false;
|
||||
long ret = timeout;
|
||||
|
||||
start_jiffies = ticks;
|
||||
|
||||
mtx_lock(&c->lock);
|
||||
while (c->done == 0 && !timeout_expired) {
|
||||
ret = -msleep(c, &c->lock, PCATCH, "drmwco", timeout);
|
||||
switch(ret) {
|
||||
case -EWOULDBLOCK:
|
||||
timeout_expired = true;
|
||||
ret = 0;
|
||||
break;
|
||||
case -EINTR:
|
||||
case -ERESTART:
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
case 0:
|
||||
awakened = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mtx_unlock(&c->lock);
|
||||
|
||||
if (awakened) {
|
||||
elapsed_jiffies = ticks - start_jiffies;
|
||||
ret = timeout > elapsed_jiffies ? timeout - elapsed_jiffies : 1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
MALLOC_DECLARE(DRM_MEM_DMA);
|
||||
MALLOC_DECLARE(DRM_MEM_SAREA);
|
||||
@ -356,6 +581,12 @@ typedef struct drm_pci_id_list
|
||||
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
#define CONFIG_ACPI
|
||||
#define CONFIG_DRM_I915_KMS
|
||||
#undef CONFIG_INTEL_IOMMU
|
||||
#endif
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
#define CONFIG_COMPAT
|
||||
#endif
|
||||
|
||||
#define CONFIG_AGP 1
|
||||
@ -364,19 +595,102 @@ typedef struct drm_pci_id_list
|
||||
#define CONFIG_FB 1
|
||||
extern const char *fb_mode_option;
|
||||
|
||||
#undef CONFIG_DEBUG_FS
|
||||
#undef CONFIG_VGA_CONSOLE
|
||||
|
||||
#define EXPORT_SYMBOL(x)
|
||||
#define EXPORT_SYMBOL_GPL(x)
|
||||
#define MODULE_AUTHOR(author)
|
||||
#define MODULE_DESCRIPTION(desc)
|
||||
#define MODULE_LICENSE(license)
|
||||
#define MODULE_PARM_DESC(name, desc)
|
||||
#define MODULE_DEVICE_TABLE(name, list)
|
||||
#define module_param_named(name, var, type, perm)
|
||||
|
||||
#define printk printf
|
||||
#define pr_err DRM_ERROR
|
||||
#define pr_warn DRM_WARNING
|
||||
#define pr_warn_once DRM_WARNING
|
||||
#define KERN_DEBUG ""
|
||||
|
||||
/* I2C compatibility. */
|
||||
#define I2C_M_RD IIC_M_RD
|
||||
#define I2C_M_WR IIC_M_WR
|
||||
#define I2C_M_NOSTART IIC_M_NOSTART
|
||||
|
||||
struct fb_info * framebuffer_alloc(void);
|
||||
void framebuffer_release(struct fb_info *info);
|
||||
|
||||
#define console_lock()
|
||||
#define console_unlock()
|
||||
#define console_trylock() true
|
||||
|
||||
#define PM_EVENT_SUSPEND 0x0002
|
||||
#define PM_EVENT_QUIESCE 0x0008
|
||||
#define PM_EVENT_PRETHAW PM_EVENT_QUIESCE
|
||||
|
||||
typedef struct pm_message {
|
||||
int event;
|
||||
} pm_message_t;
|
||||
|
||||
static inline int
|
||||
pci_read_config_byte(device_t kdev, int where, u8 *val)
|
||||
{
|
||||
|
||||
*val = (u8)pci_read_config(kdev, where, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pci_write_config_byte(device_t kdev, int where, u8 val)
|
||||
{
|
||||
|
||||
pci_write_config(kdev, where, val, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pci_read_config_word(device_t kdev, int where, uint16_t *val)
|
||||
{
|
||||
|
||||
*val = (uint16_t)pci_read_config(kdev, where, 2);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pci_write_config_word(device_t kdev, int where, uint16_t val)
|
||||
{
|
||||
|
||||
pci_write_config(kdev, where, val, 2);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pci_read_config_dword(device_t kdev, int where, uint32_t *val)
|
||||
{
|
||||
|
||||
*val = (uint32_t)pci_read_config(kdev, where, 4);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pci_write_config_dword(device_t kdev, int where, uint32_t val)
|
||||
{
|
||||
|
||||
pci_write_config(kdev, where, val, 4);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
on_each_cpu(void callback(void *data), void *data, int wait)
|
||||
{
|
||||
|
||||
smp_rendezvous(NULL, callback, NULL, data);
|
||||
}
|
||||
|
||||
void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
|
||||
int groupsize, char *linebuf, size_t linebuflen, bool ascii);
|
||||
|
||||
#define KIB_NOTYET() \
|
||||
do { \
|
||||
if (drm_debug && drm_notyet) \
|
||||
|
@ -33,57 +33,89 @@
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define i915_PCI_IDS \
|
||||
{0x8086, 0x0042, CHIP_I9XX|CHIP_I915, "Intel IronLake"}, \
|
||||
{0x8086, 0x0046, CHIP_I9XX|CHIP_I915, "Intel IronLake"}, \
|
||||
{0x8086, 0x0102, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0106, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x010A, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0112, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0116, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0122, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0126, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0152, CHIP_I9XX|CHIP_I915, "Intel IvyBridge"}, \
|
||||
{0x8086, 0x0156, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (M)"}, \
|
||||
{0x8086, 0x015A, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (S)"}, \
|
||||
{0x8086, 0x0162, CHIP_I9XX|CHIP_I915, "Intel IvyBridge"}, \
|
||||
{0x8086, 0x0166, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (M)"}, \
|
||||
{0x8086, 0x016A, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (S)"}, \
|
||||
{0x8086, 0x0402, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \
|
||||
{0x8086, 0x0406, CHIP_I9XX|CHIP_I915, "Intel Haswell (M)"}, \
|
||||
{0x8086, 0x040A, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \
|
||||
{0x8086, 0x0412, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \
|
||||
{0x8086, 0x0416, CHIP_I9XX|CHIP_I915, "Intel Haswell (M)"}, \
|
||||
{0x8086, 0x041A, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \
|
||||
{0x8086, 0x0C16, CHIP_I9XX|CHIP_I915, "Intel Haswell (SDV)"}, \
|
||||
{0x8086, 0x2562, CHIP_I8XX, "Intel i845G GMCH"}, \
|
||||
{0x8086, 0x2572, CHIP_I8XX, "Intel i865G GMCH"}, \
|
||||
{0x8086, 0x2582, CHIP_I9XX|CHIP_I915, "Intel i915G"}, \
|
||||
{0x8086, 0x258A, CHIP_I9XX|CHIP_I915, "Intel E7221 (i915)"}, \
|
||||
{0x8086, 0x2592, CHIP_I9XX|CHIP_I915, "Intel i915GM"}, \
|
||||
{0x8086, 0x2772, CHIP_I9XX|CHIP_I915, "Intel i945G"}, \
|
||||
{0x8086, 0x27A2, CHIP_I9XX|CHIP_I915, "Intel i945GM"}, \
|
||||
{0x8086, 0x27AE, CHIP_I9XX|CHIP_I915, "Intel i945GME"}, \
|
||||
{0x8086, 0x2972, CHIP_I9XX|CHIP_I965, "Intel i946GZ"}, \
|
||||
{0x8086, 0x2982, CHIP_I9XX|CHIP_I965, "Intel i965G"}, \
|
||||
{0x8086, 0x2992, CHIP_I9XX|CHIP_I965, "Intel i965Q"}, \
|
||||
{0x8086, 0x29A2, CHIP_I9XX|CHIP_I965, "Intel i965G"}, \
|
||||
{0x8086, 0x29B2, CHIP_I9XX|CHIP_I915, "Intel Q35"}, \
|
||||
{0x8086, 0x29C2, CHIP_I9XX|CHIP_I915, "Intel G33"}, \
|
||||
{0x8086, 0x29D2, CHIP_I9XX|CHIP_I915, "Intel Q33"}, \
|
||||
{0x8086, 0x2A02, CHIP_I9XX|CHIP_I965, "Intel i965GM"}, \
|
||||
{0x8086, 0x2A12, CHIP_I9XX|CHIP_I965, "Intel i965GME/GLE"}, \
|
||||
{0x8086, 0x2A42, CHIP_I9XX|CHIP_I965, "Mobile Intel® GM45 Express Chipset"}, \
|
||||
{0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel Eaglelake"}, \
|
||||
{0x8086, 0x2E12, CHIP_I9XX|CHIP_I965, "Intel Q45/Q43"}, \
|
||||
{0x8086, 0x2E22, CHIP_I9XX|CHIP_I965, "Intel G45/G43"}, \
|
||||
{0x8086, 0x2E32, CHIP_I9XX|CHIP_I965, "Intel G41"}, \
|
||||
{0x8086, 0x2E42, CHIP_I9XX|CHIP_I915, "Intel G43 ?"}, \
|
||||
{0x8086, 0x2E92, CHIP_I9XX|CHIP_I915, "Intel G43 ?"}, \
|
||||
{0x8086, 0x3577, CHIP_I8XX, "Intel i830M GMCH"}, \
|
||||
{0x8086, 0x3582, CHIP_I8XX, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0x358E, CHIP_I8XX, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0xA001, CHIP_I9XX|CHIP_I965, "Intel Pineview"}, \
|
||||
{0x8086, 0xA011, CHIP_I9XX|CHIP_I965, "Intel Pineview (M)"}, \
|
||||
{0x8086, 0x0042, 0, "Intel IronLake"}, \
|
||||
{0x8086, 0x0046, 0, "Intel IronLake"}, \
|
||||
{0x8086, 0x0102, 0, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0106, 0, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x010A, 0, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0112, 0, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0116, 0, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0122, 0, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0126, 0, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0152, 0, "Intel IvyBridge"}, \
|
||||
{0x8086, 0x0156, 0, "Intel IvyBridge (M)"}, \
|
||||
{0x8086, 0x015A, 0, "Intel IvyBridge (S)"}, \
|
||||
{0x8086, 0x0162, 0, "Intel IvyBridge"}, \
|
||||
{0x8086, 0x0166, 0, "Intel IvyBridge (M)"}, \
|
||||
{0x8086, 0x016A, 0, "Intel IvyBridge (S)"}, \
|
||||
{0x8086, 0x0402, 0, "Intel Haswell (GT1 desktop)"}, \
|
||||
{0x8086, 0x0406, 0, "Intel Haswell (GT1 mobile)"}, \
|
||||
{0x8086, 0x040A, 0, "Intel Haswell (GT1 server)"}, \
|
||||
{0x8086, 0x0412, 0, "Intel Haswell (GT2 desktop)"}, \
|
||||
{0x8086, 0x0416, 0, "Intel Haswell (GT2 mobile)"}, \
|
||||
{0x8086, 0x041A, 0, "Intel Haswell (GT2 server)"}, \
|
||||
{0x8086, 0x0422, 0, "Intel Haswell (GT2 desktop)"}, \
|
||||
{0x8086, 0x0426, 0, "Intel Haswell (GT2 mobile)"}, \
|
||||
{0x8086, 0x042A, 0, "Intel Haswell (GT2 server)"}, \
|
||||
{0x8086, 0x0A02, 0, "Intel Haswell (ULT GT1 desktop)"}, \
|
||||
{0x8086, 0x0A06, 0, "Intel Haswell (ULT GT1 mobile)"}, \
|
||||
{0x8086, 0x0A0A, 0, "Intel Haswell (ULT GT1 server)"}, \
|
||||
{0x8086, 0x0A12, 0, "Intel Haswell (ULT GT2 desktop)"}, \
|
||||
{0x8086, 0x0A16, 0, "Intel Haswell (ULT GT2 mobile)"}, \
|
||||
{0x8086, 0x0A1A, 0, "Intel Haswell (ULT GT2 server)"}, \
|
||||
{0x8086, 0x0A22, 0, "Intel Haswell (ULT GT2 desktop)"}, \
|
||||
{0x8086, 0x0A26, 0, "Intel Haswell (ULT GT2 mobile)"}, \
|
||||
{0x8086, 0x0A2A, 0, "Intel Haswell (ULT GT2 server)"}, \
|
||||
{0x8086, 0x0C02, 0, "Intel Haswell (SDV GT1 desktop)"}, \
|
||||
{0x8086, 0x0C06, 0, "Intel Haswell (SDV GT1 mobile)"}, \
|
||||
{0x8086, 0x0C0A, 0, "Intel Haswell (SDV GT1 server)"}, \
|
||||
{0x8086, 0x0C12, 0, "Intel Haswell (SDV GT2 desktop)"}, \
|
||||
{0x8086, 0x0C16, 0, "Intel Haswell (SDV GT2 mobile)"}, \
|
||||
{0x8086, 0x0C1A, 0, "Intel Haswell (SDV GT2 server)"}, \
|
||||
{0x8086, 0x0C22, 0, "Intel Haswell (SDV GT2 desktop)"}, \
|
||||
{0x8086, 0x0C26, 0, "Intel Haswell (SDV GT2 mobile)"}, \
|
||||
{0x8086, 0x0C2A, 0, "Intel Haswell (SDV GT2 server)"}, \
|
||||
{0x8086, 0x0D02, 0, "Intel Haswell (CRW GT1 desktop)"}, \
|
||||
{0x8086, 0x0D06, 0, "Intel Haswell (CRW GT1 mobile)"}, \
|
||||
{0x8086, 0x0D0A, 0, "Intel Haswell (CRW GT1 server)"}, \
|
||||
{0x8086, 0x0D12, 0, "Intel Haswell (CRW GT2 desktop)"}, \
|
||||
{0x8086, 0x0D16, 0, "Intel Haswell (CRW GT2 mobile)"}, \
|
||||
{0x8086, 0x0D1A, 0, "Intel Haswell (CRW GT2 server)"}, \
|
||||
{0x8086, 0x0D22, 0, "Intel Haswell (CRW GT2 desktop)"}, \
|
||||
{0x8086, 0x0D26, 0, "Intel Haswell (CRW GT2 mobile)"}, \
|
||||
{0x8086, 0x0D2A, 0, "Intel Haswell (CRW GT2 server)"}, \
|
||||
{0x8086, 0x0155, 0, "Intel Valleyview (desktop)"}, \
|
||||
{0x8086, 0x0157, 0, "Intel Valleyview (mobile)"}, \
|
||||
{0x8086, 0x0F30, 0, "Intel Valleyview (mobile)"}, \
|
||||
{0x8086, 0x2562, 0, "Intel i845G GMCH"}, \
|
||||
{0x8086, 0x2572, 0, "Intel i865G GMCH"}, \
|
||||
{0x8086, 0x2582, 0, "Intel i915G"}, \
|
||||
{0x8086, 0x258A, 0, "Intel E7221 (i915)"}, \
|
||||
{0x8086, 0x2592, 0, "Intel i915GM"}, \
|
||||
{0x8086, 0x2772, 0, "Intel i945G"}, \
|
||||
{0x8086, 0x27A2, 0, "Intel i945GM"}, \
|
||||
{0x8086, 0x27AE, 0, "Intel i945GME"}, \
|
||||
{0x8086, 0x2972, 0, "Intel i946GZ"}, \
|
||||
{0x8086, 0x2982, 0, "Intel i965G"}, \
|
||||
{0x8086, 0x2992, 0, "Intel i965Q"}, \
|
||||
{0x8086, 0x29A2, 0, "Intel i965G"}, \
|
||||
{0x8086, 0x29B2, 0, "Intel Q35"}, \
|
||||
{0x8086, 0x29C2, 0, "Intel G33"}, \
|
||||
{0x8086, 0x29D2, 0, "Intel Q33"}, \
|
||||
{0x8086, 0x2A02, 0, "Intel i965GM"}, \
|
||||
{0x8086, 0x2A12, 0, "Intel i965GME/GLE"}, \
|
||||
{0x8086, 0x2A42, 0, "Mobile Intel® GM45 Express Chipset"}, \
|
||||
{0x8086, 0x2E02, 0, "Intel Eaglelake"}, \
|
||||
{0x8086, 0x2E12, 0, "Intel Q45/Q43"}, \
|
||||
{0x8086, 0x2E22, 0, "Intel G45/G43"}, \
|
||||
{0x8086, 0x2E32, 0, "Intel G41"}, \
|
||||
{0x8086, 0x2E42, 0, "Intel G43 ?"}, \
|
||||
{0x8086, 0x2E92, 0, "Intel G43 ?"}, \
|
||||
{0x8086, 0x3577, 0, "Intel i830M GMCH"}, \
|
||||
{0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0x358E, 0, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0xA001, 0, "Intel Pineview"}, \
|
||||
{0x8086, 0xA011, 0, "Intel Pineview (M)"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define imagine_PCI_IDS \
|
||||
|
155
sys/dev/drm2/i915/dvo.h
Normal file
155
sys/dev/drm2/i915/dvo.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright © 2006 Eric Anholt
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_DVO_H
|
||||
#define _INTEL_DVO_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/bus.h>
|
||||
#include <dev/iicbus/iic.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include "intel_drv.h"
|
||||
|
||||
struct intel_dvo_device {
|
||||
const char *name;
|
||||
int type;
|
||||
/* DVOA/B/C output register */
|
||||
u32 dvo_reg;
|
||||
/* GPIO register used for i2c bus to control this device */
|
||||
u32 gpio;
|
||||
int slave_addr;
|
||||
|
||||
const struct intel_dvo_dev_ops *dev_ops;
|
||||
void *dev_priv;
|
||||
device_t i2c_bus;
|
||||
};
|
||||
|
||||
struct intel_dvo_dev_ops {
|
||||
/*
|
||||
* Initialize the device at startup time.
|
||||
* Returns NULL if the device does not exist.
|
||||
*/
|
||||
bool (*init)(struct intel_dvo_device *dvo,
|
||||
device_t i2cbus);
|
||||
|
||||
/*
|
||||
* Called to allow the output a chance to create properties after the
|
||||
* RandR objects have been created.
|
||||
*/
|
||||
void (*create_resources)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Turn on/off output.
|
||||
*
|
||||
* Because none of our dvo drivers support an intermediate power levels,
|
||||
* we don't expose this in the interfac.
|
||||
*/
|
||||
void (*dpms)(struct intel_dvo_device *dvo, bool enable);
|
||||
|
||||
/*
|
||||
* Callback for testing a video mode for a given output.
|
||||
*
|
||||
* This function should only check for cases where a mode can't
|
||||
* be supported on the output specifically, and not represent
|
||||
* generic CRTC limitations.
|
||||
*
|
||||
* \return MODE_OK if the mode is valid, or another MODE_* otherwise.
|
||||
*/
|
||||
int (*mode_valid)(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
/*
|
||||
* Callback to adjust the mode to be set in the CRTC.
|
||||
*
|
||||
* This allows an output to adjust the clock or even the entire set of
|
||||
* timings, which is used for panels with fixed timings or for
|
||||
* buses with clock limitations.
|
||||
*/
|
||||
bool (*mode_fixup)(struct intel_dvo_device *dvo,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
|
||||
/*
|
||||
* Callback for preparing mode changes on an output
|
||||
*/
|
||||
void (*prepare)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Callback for committing mode changes on an output
|
||||
*/
|
||||
void (*commit)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Callback for setting up a video mode after fixups have been made.
|
||||
*
|
||||
* This is only called while the output is disabled. The dpms callback
|
||||
* must be all that's necessary for the output, to turn the output on
|
||||
* after this function is called.
|
||||
*/
|
||||
void (*mode_set)(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
|
||||
/*
|
||||
* Probe for a connected output, and return detect_status.
|
||||
*/
|
||||
enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Probe the current hw status, returning true if the connected output
|
||||
* is active.
|
||||
*/
|
||||
bool (*get_hw_state)(struct intel_dvo_device *dev);
|
||||
|
||||
/**
|
||||
* Query the device for the modes it provides.
|
||||
*
|
||||
* This function may also update MonInfo, mm_width, and mm_height.
|
||||
*
|
||||
* \return singly-linked list of modes or NULL if no modes found.
|
||||
*/
|
||||
struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
|
||||
|
||||
/**
|
||||
* Clean up driver-specific bits of the output
|
||||
*/
|
||||
void (*destroy) (struct intel_dvo_device *dvo);
|
||||
|
||||
/**
|
||||
* Debugging hook to dump device registers to log file
|
||||
*/
|
||||
void (*dump_regs)(struct intel_dvo_device *dvo);
|
||||
};
|
||||
|
||||
extern struct intel_dvo_dev_ops sil164_ops;
|
||||
extern struct intel_dvo_dev_ops ch7xxx_ops;
|
||||
extern struct intel_dvo_dev_ops ivch_ops;
|
||||
extern struct intel_dvo_dev_ops tfp410_ops;
|
||||
extern struct intel_dvo_dev_ops ch7017_ops;
|
||||
extern struct intel_dvo_dev_ops ns2501_ops;
|
||||
|
||||
#endif /* _INTEL_DVO_H */
|
418
sys/dev/drm2/i915/dvo_ch7017.c
Normal file
418
sys/dev/drm2/i915/dvo_ch7017.c
Normal file
@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* 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
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "dvo.h"
|
||||
|
||||
#define CH7017_TV_DISPLAY_MODE 0x00
|
||||
#define CH7017_FLICKER_FILTER 0x01
|
||||
#define CH7017_VIDEO_BANDWIDTH 0x02
|
||||
#define CH7017_TEXT_ENHANCEMENT 0x03
|
||||
#define CH7017_START_ACTIVE_VIDEO 0x04
|
||||
#define CH7017_HORIZONTAL_POSITION 0x05
|
||||
#define CH7017_VERTICAL_POSITION 0x06
|
||||
#define CH7017_BLACK_LEVEL 0x07
|
||||
#define CH7017_CONTRAST_ENHANCEMENT 0x08
|
||||
#define CH7017_TV_PLL 0x09
|
||||
#define CH7017_TV_PLL_M 0x0a
|
||||
#define CH7017_TV_PLL_N 0x0b
|
||||
#define CH7017_SUB_CARRIER_0 0x0c
|
||||
#define CH7017_CIV_CONTROL 0x10
|
||||
#define CH7017_CIV_0 0x11
|
||||
#define CH7017_CHROMA_BOOST 0x14
|
||||
#define CH7017_CLOCK_MODE 0x1c
|
||||
#define CH7017_INPUT_CLOCK 0x1d
|
||||
#define CH7017_GPIO_CONTROL 0x1e
|
||||
#define CH7017_INPUT_DATA_FORMAT 0x1f
|
||||
#define CH7017_CONNECTION_DETECT 0x20
|
||||
#define CH7017_DAC_CONTROL 0x21
|
||||
#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22
|
||||
#define CH7017_DEFEAT_VSYNC 0x47
|
||||
#define CH7017_TEST_PATTERN 0x48
|
||||
|
||||
#define CH7017_POWER_MANAGEMENT 0x49
|
||||
/** Enables the TV output path. */
|
||||
#define CH7017_TV_EN (1 << 0)
|
||||
#define CH7017_DAC0_POWER_DOWN (1 << 1)
|
||||
#define CH7017_DAC1_POWER_DOWN (1 << 2)
|
||||
#define CH7017_DAC2_POWER_DOWN (1 << 3)
|
||||
#define CH7017_DAC3_POWER_DOWN (1 << 4)
|
||||
/** Powers down the TV out block, and DAC0-3 */
|
||||
#define CH7017_TV_POWER_DOWN_EN (1 << 5)
|
||||
|
||||
#define CH7017_VERSION_ID 0x4a
|
||||
|
||||
#define CH7017_DEVICE_ID 0x4b
|
||||
#define CH7017_DEVICE_ID_VALUE 0x1b
|
||||
#define CH7018_DEVICE_ID_VALUE 0x1a
|
||||
#define CH7019_DEVICE_ID_VALUE 0x19
|
||||
|
||||
#define CH7017_XCLK_D2_ADJUST 0x53
|
||||
#define CH7017_UP_SCALER_COEFF_0 0x55
|
||||
#define CH7017_UP_SCALER_COEFF_1 0x56
|
||||
#define CH7017_UP_SCALER_COEFF_2 0x57
|
||||
#define CH7017_UP_SCALER_COEFF_3 0x58
|
||||
#define CH7017_UP_SCALER_COEFF_4 0x59
|
||||
#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a
|
||||
#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b
|
||||
#define CH7017_GPIO_INVERT 0x5c
|
||||
#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d
|
||||
#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e
|
||||
|
||||
#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f
|
||||
/**< Low bits of horizontal active pixel input */
|
||||
|
||||
#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60
|
||||
/** High bits of horizontal active pixel input */
|
||||
#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0)
|
||||
/** High bits of vertical active line output */
|
||||
#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3)
|
||||
|
||||
#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61
|
||||
/**< Low bits of vertical active line output */
|
||||
|
||||
#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62
|
||||
/**< Low bits of horizontal active pixel output */
|
||||
|
||||
#define CH7017_LVDS_POWER_DOWN 0x63
|
||||
/** High bits of horizontal active pixel output */
|
||||
#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0)
|
||||
/** Enables the LVDS power down state transition */
|
||||
#define CH7017_LVDS_POWER_DOWN_EN (1 << 6)
|
||||
/** Enables the LVDS upscaler */
|
||||
#define CH7017_LVDS_UPSCALER_EN (1 << 7)
|
||||
#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08
|
||||
|
||||
#define CH7017_LVDS_ENCODING 0x64
|
||||
#define CH7017_LVDS_DITHER_2D (1 << 2)
|
||||
#define CH7017_LVDS_DITHER_DIS (1 << 3)
|
||||
#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4)
|
||||
#define CH7017_LVDS_24_BIT (1 << 5)
|
||||
|
||||
#define CH7017_LVDS_ENCODING_2 0x65
|
||||
|
||||
#define CH7017_LVDS_PLL_CONTROL 0x66
|
||||
/** Enables the LVDS panel output path */
|
||||
#define CH7017_LVDS_PANEN (1 << 0)
|
||||
/** Enables the LVDS panel backlight */
|
||||
#define CH7017_LVDS_BKLEN (1 << 3)
|
||||
|
||||
#define CH7017_POWER_SEQUENCING_T1 0x67
|
||||
#define CH7017_POWER_SEQUENCING_T2 0x68
|
||||
#define CH7017_POWER_SEQUENCING_T3 0x69
|
||||
#define CH7017_POWER_SEQUENCING_T4 0x6a
|
||||
#define CH7017_POWER_SEQUENCING_T5 0x6b
|
||||
#define CH7017_GPIO_DRIVER_TYPE 0x6c
|
||||
#define CH7017_GPIO_DATA 0x6d
|
||||
#define CH7017_GPIO_DIRECTION_CONTROL 0x6e
|
||||
|
||||
#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71
|
||||
# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4
|
||||
# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0
|
||||
# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80
|
||||
|
||||
#define CH7017_LVDS_PLL_VCO_CONTROL 0x72
|
||||
# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80
|
||||
# define CH7017_LVDS_PLL_VCO_SHIFT 4
|
||||
# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0
|
||||
|
||||
#define CH7017_OUTPUTS_ENABLE 0x73
|
||||
# define CH7017_CHARGE_PUMP_LOW 0x0
|
||||
# define CH7017_CHARGE_PUMP_HIGH 0x3
|
||||
# define CH7017_LVDS_CHANNEL_A (1 << 3)
|
||||
# define CH7017_LVDS_CHANNEL_B (1 << 4)
|
||||
# define CH7017_TV_DAC_A (1 << 5)
|
||||
# define CH7017_TV_DAC_B (1 << 6)
|
||||
# define CH7017_DDC_SELECT_DC2 (1 << 7)
|
||||
|
||||
#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74
|
||||
#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75
|
||||
#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
|
||||
|
||||
#define CH7017_LVDS_CONTROL_2 0x78
|
||||
# define CH7017_LOOP_FILTER_SHIFT 5
|
||||
# define CH7017_PHASE_DETECTOR_SHIFT 0
|
||||
|
||||
#define CH7017_BANG_LIMIT_CONTROL 0x7f
|
||||
|
||||
struct ch7017_priv {
|
||||
uint8_t dummy;
|
||||
};
|
||||
|
||||
static void ch7017_dump_regs(struct intel_dvo_device *dvo);
|
||||
static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable);
|
||||
|
||||
static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
|
||||
{
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &addr,
|
||||
},
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = val,
|
||||
}
|
||||
};
|
||||
return -iicbus_transfer(dvo->i2c_bus, msgs, 2) == 0;
|
||||
}
|
||||
|
||||
static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
|
||||
{
|
||||
uint8_t buf[2] = { addr, val };
|
||||
struct iic_msg msg = {
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = buf,
|
||||
};
|
||||
return -iicbus_transfer(dvo->i2c_bus, &msg, 1) == 0;
|
||||
}
|
||||
|
||||
/** Probes for a CH7017 on the given bus and slave address. */
|
||||
static bool ch7017_init(struct intel_dvo_device *dvo,
|
||||
device_t adapter)
|
||||
{
|
||||
struct ch7017_priv *priv;
|
||||
const char *str;
|
||||
u8 val;
|
||||
|
||||
priv = malloc(sizeof(struct ch7017_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
|
||||
if (priv == NULL)
|
||||
return false;
|
||||
|
||||
dvo->i2c_bus = adapter;
|
||||
dvo->dev_priv = priv;
|
||||
|
||||
if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
|
||||
goto fail;
|
||||
|
||||
switch (val) {
|
||||
case CH7017_DEVICE_ID_VALUE:
|
||||
str = "ch7017";
|
||||
break;
|
||||
case CH7018_DEVICE_ID_VALUE:
|
||||
str = "ch7018";
|
||||
break;
|
||||
case CH7019_DEVICE_ID_VALUE:
|
||||
str = "ch7019";
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
|
||||
"slave %d.\n",
|
||||
val, device_get_nameunit(adapter),
|
||||
dvo->slave_addr);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
|
||||
str, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
free(priv, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 160000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void ch7017_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
uint8_t lvds_pll_feedback_div, lvds_pll_vco_control;
|
||||
uint8_t outputs_enable, lvds_control_2, lvds_power_down;
|
||||
uint8_t horizontal_active_pixel_input;
|
||||
uint8_t horizontal_active_pixel_output, vertical_active_line_output;
|
||||
uint8_t active_input_line_output;
|
||||
|
||||
DRM_DEBUG_KMS("Registers before mode setting\n");
|
||||
ch7017_dump_regs(dvo);
|
||||
|
||||
/* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
|
||||
if (mode->clock < 100000) {
|
||||
outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW;
|
||||
lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
|
||||
(2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
|
||||
(13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
|
||||
lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
|
||||
(2 << CH7017_LVDS_PLL_VCO_SHIFT) |
|
||||
(3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
|
||||
lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
|
||||
(0 << CH7017_PHASE_DETECTOR_SHIFT);
|
||||
} else {
|
||||
outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH;
|
||||
lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
|
||||
(2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
|
||||
(3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
|
||||
lvds_pll_feedback_div = 35;
|
||||
lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
|
||||
(0 << CH7017_PHASE_DETECTOR_SHIFT);
|
||||
if (1) { /* XXX: dual channel panel detection. Assume yes for now. */
|
||||
outputs_enable |= CH7017_LVDS_CHANNEL_B;
|
||||
lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
|
||||
(2 << CH7017_LVDS_PLL_VCO_SHIFT) |
|
||||
(13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
|
||||
} else {
|
||||
lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
|
||||
(1 << CH7017_LVDS_PLL_VCO_SHIFT) |
|
||||
(13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
horizontal_active_pixel_input = mode->hdisplay & 0x00ff;
|
||||
|
||||
vertical_active_line_output = mode->vdisplay & 0x00ff;
|
||||
horizontal_active_pixel_output = mode->hdisplay & 0x00ff;
|
||||
|
||||
active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) |
|
||||
(((mode->vdisplay & 0x0700) >> 8) << 3);
|
||||
|
||||
lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
|
||||
(mode->hdisplay & 0x0700) >> 8;
|
||||
|
||||
ch7017_dpms(dvo, false);
|
||||
ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
|
||||
horizontal_active_pixel_input);
|
||||
ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
|
||||
horizontal_active_pixel_output);
|
||||
ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
|
||||
vertical_active_line_output);
|
||||
ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT,
|
||||
active_input_line_output);
|
||||
ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
|
||||
ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
|
||||
ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2);
|
||||
ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable);
|
||||
|
||||
/* Turn the LVDS back on with new settings. */
|
||||
ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down);
|
||||
|
||||
DRM_DEBUG_KMS("Registers after mode setting\n");
|
||||
ch7017_dump_regs(dvo);
|
||||
}
|
||||
|
||||
/* set the CH7017 power state */
|
||||
static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
|
||||
|
||||
/* Turn off TV/VGA, and never turn it on since we don't support it. */
|
||||
ch7017_write(dvo, CH7017_POWER_MANAGEMENT,
|
||||
CH7017_DAC0_POWER_DOWN |
|
||||
CH7017_DAC1_POWER_DOWN |
|
||||
CH7017_DAC2_POWER_DOWN |
|
||||
CH7017_DAC3_POWER_DOWN |
|
||||
CH7017_TV_POWER_DOWN_EN);
|
||||
|
||||
if (enable) {
|
||||
/* Turn on the LVDS */
|
||||
ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
|
||||
val & ~CH7017_LVDS_POWER_DOWN_EN);
|
||||
} else {
|
||||
/* Turn off the LVDS */
|
||||
ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
|
||||
val | CH7017_LVDS_POWER_DOWN_EN);
|
||||
}
|
||||
|
||||
/* XXX: Should actually wait for update power status somehow */
|
||||
drm_msleep(20, "ch7017");
|
||||
}
|
||||
|
||||
static bool ch7017_get_hw_state(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
|
||||
|
||||
if (val & CH7017_LVDS_POWER_DOWN_EN)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ch7017_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
#define DUMP(reg) \
|
||||
do { \
|
||||
ch7017_read(dvo, reg, &val); \
|
||||
DRM_DEBUG_KMS(#reg ": %02x\n", val); \
|
||||
} while (0)
|
||||
|
||||
DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
|
||||
DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
|
||||
DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
|
||||
DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT);
|
||||
DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
|
||||
DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
|
||||
DUMP(CH7017_LVDS_CONTROL_2);
|
||||
DUMP(CH7017_OUTPUTS_ENABLE);
|
||||
DUMP(CH7017_LVDS_POWER_DOWN);
|
||||
}
|
||||
|
||||
static void ch7017_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct ch7017_priv *priv = dvo->dev_priv;
|
||||
|
||||
if (priv) {
|
||||
free(priv, DRM_MEM_KMS);
|
||||
dvo->dev_priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_dvo_dev_ops ch7017_ops = {
|
||||
.init = ch7017_init,
|
||||
.detect = ch7017_detect,
|
||||
.mode_valid = ch7017_mode_valid,
|
||||
.mode_set = ch7017_mode_set,
|
||||
.dpms = ch7017_dpms,
|
||||
.get_hw_state = ch7017_get_hw_state,
|
||||
.dump_regs = ch7017_dump_regs,
|
||||
.destroy = ch7017_destroy,
|
||||
};
|
347
sys/dev/drm2/i915/dvo_ch7xxx.c
Normal file
347
sys/dev/drm2/i915/dvo_ch7xxx.c
Normal file
@ -0,0 +1,347 @@
|
||||
/**************************************************************************
|
||||
|
||||
Copyright © 2006 Dave Airlie
|
||||
|
||||
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, sub license, 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 NON-INFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHOR 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.
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "dvo.h"
|
||||
|
||||
#define CH7xxx_REG_VID 0x4a
|
||||
#define CH7xxx_REG_DID 0x4b
|
||||
|
||||
#define CH7011_VID 0x83 /* 7010 as well */
|
||||
#define CH7009A_VID 0x84
|
||||
#define CH7009B_VID 0x85
|
||||
#define CH7301_VID 0x95
|
||||
|
||||
#define CH7xxx_VID 0x84
|
||||
#define CH7xxx_DID 0x17
|
||||
|
||||
#define CH7xxx_NUM_REGS 0x4c
|
||||
|
||||
#define CH7xxx_CM 0x1c
|
||||
#define CH7xxx_CM_XCM (1<<0)
|
||||
#define CH7xxx_CM_MCP (1<<2)
|
||||
#define CH7xxx_INPUT_CLOCK 0x1d
|
||||
#define CH7xxx_GPIO 0x1e
|
||||
#define CH7xxx_GPIO_HPIR (1<<3)
|
||||
#define CH7xxx_IDF 0x1f
|
||||
|
||||
#define CH7xxx_IDF_HSP (1<<3)
|
||||
#define CH7xxx_IDF_VSP (1<<4)
|
||||
|
||||
#define CH7xxx_CONNECTION_DETECT 0x20
|
||||
#define CH7xxx_CDET_DVI (1<<5)
|
||||
|
||||
#define CH7301_DAC_CNTL 0x21
|
||||
#define CH7301_HOTPLUG 0x23
|
||||
#define CH7xxx_TCTL 0x31
|
||||
#define CH7xxx_TVCO 0x32
|
||||
#define CH7xxx_TPCP 0x33
|
||||
#define CH7xxx_TPD 0x34
|
||||
#define CH7xxx_TPVT 0x35
|
||||
#define CH7xxx_TLPF 0x36
|
||||
#define CH7xxx_TCT 0x37
|
||||
#define CH7301_TEST_PATTERN 0x48
|
||||
|
||||
#define CH7xxx_PM 0x49
|
||||
#define CH7xxx_PM_FPD (1<<0)
|
||||
#define CH7301_PM_DACPD0 (1<<1)
|
||||
#define CH7301_PM_DACPD1 (1<<2)
|
||||
#define CH7301_PM_DACPD2 (1<<3)
|
||||
#define CH7xxx_PM_DVIL (1<<6)
|
||||
#define CH7xxx_PM_DVIP (1<<7)
|
||||
|
||||
#define CH7301_SYNC_POLARITY 0x56
|
||||
#define CH7301_SYNC_RGB_YUV (1<<0)
|
||||
#define CH7301_SYNC_POL_DVI (1<<5)
|
||||
|
||||
/** @file
|
||||
* driver for the Chrontel 7xxx DVI chip over DVO.
|
||||
*/
|
||||
|
||||
static struct ch7xxx_id_struct {
|
||||
uint8_t vid;
|
||||
char *name;
|
||||
} ch7xxx_ids[] = {
|
||||
{ CH7011_VID, "CH7011" },
|
||||
{ CH7009A_VID, "CH7009A" },
|
||||
{ CH7009B_VID, "CH7009B" },
|
||||
{ CH7301_VID, "CH7301" },
|
||||
};
|
||||
|
||||
struct ch7xxx_priv {
|
||||
bool quiet;
|
||||
};
|
||||
|
||||
static char *ch7xxx_get_id(uint8_t vid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
|
||||
if (ch7xxx_ids[i].vid == vid)
|
||||
return ch7xxx_ids[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Reads an 8 bit register */
|
||||
static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
|
||||
{
|
||||
struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
u8 out_buf[2];
|
||||
u8 in_buf[2];
|
||||
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = in_buf,
|
||||
}
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = 0;
|
||||
|
||||
if (-iicbus_transfer(adapter, msgs, 2) == 0) {
|
||||
*ch = in_buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ch7xxx->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Writes an 8 bit register */
|
||||
static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
|
||||
{
|
||||
struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
uint8_t out_buf[2];
|
||||
struct iic_msg msg = {
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = out_buf,
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = ch;
|
||||
|
||||
if (-iicbus_transfer(adapter, &msg, 1) == 0)
|
||||
return true;
|
||||
|
||||
if (!ch7xxx->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ch7xxx_init(struct intel_dvo_device *dvo,
|
||||
device_t adapter)
|
||||
{
|
||||
/* this will detect the CH7xxx chip on the specified i2c bus */
|
||||
struct ch7xxx_priv *ch7xxx;
|
||||
uint8_t vendor, device;
|
||||
char *name;
|
||||
|
||||
ch7xxx = malloc(sizeof(struct ch7xxx_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
|
||||
if (ch7xxx == NULL)
|
||||
return false;
|
||||
|
||||
dvo->i2c_bus = adapter;
|
||||
dvo->dev_priv = ch7xxx;
|
||||
ch7xxx->quiet = true;
|
||||
|
||||
if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
|
||||
goto out;
|
||||
|
||||
name = ch7xxx_get_id(vendor);
|
||||
if (!name) {
|
||||
DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
|
||||
"slave %d.\n",
|
||||
vendor, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
|
||||
goto out;
|
||||
|
||||
if (device != CH7xxx_DID) {
|
||||
DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
|
||||
"slave %d.\n",
|
||||
vendor, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch7xxx->quiet = false;
|
||||
DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
|
||||
name, vendor, device);
|
||||
return true;
|
||||
out:
|
||||
free(ch7xxx, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t cdet, orig_pm, pm;
|
||||
|
||||
ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
|
||||
|
||||
pm = orig_pm;
|
||||
pm &= ~CH7xxx_PM_FPD;
|
||||
pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
|
||||
|
||||
ch7xxx_writeb(dvo, CH7xxx_PM, pm);
|
||||
|
||||
ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
|
||||
|
||||
ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
|
||||
|
||||
if (cdet & CH7xxx_CDET_DVI)
|
||||
return connector_status_connected;
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 165000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
uint8_t tvco, tpcp, tpd, tlpf, idf;
|
||||
|
||||
if (mode->clock <= 65000) {
|
||||
tvco = 0x23;
|
||||
tpcp = 0x08;
|
||||
tpd = 0x16;
|
||||
tlpf = 0x60;
|
||||
} else {
|
||||
tvco = 0x2d;
|
||||
tpcp = 0x06;
|
||||
tpd = 0x26;
|
||||
tlpf = 0xa0;
|
||||
}
|
||||
|
||||
ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
|
||||
ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
|
||||
ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
|
||||
ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
|
||||
ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
|
||||
ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
|
||||
ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
|
||||
|
||||
ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
|
||||
|
||||
idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
|
||||
if (mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
idf |= CH7xxx_IDF_HSP;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
idf |= CH7xxx_IDF_HSP;
|
||||
|
||||
ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
|
||||
}
|
||||
|
||||
/* set the CH7xxx power state */
|
||||
static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
|
||||
else
|
||||
ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
|
||||
}
|
||||
|
||||
static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
ch7xxx_readb(dvo, CH7xxx_PM, &val);
|
||||
|
||||
if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CH7xxx_NUM_REGS; i++) {
|
||||
uint8_t val;
|
||||
if ((i % 8) == 0)
|
||||
DRM_LOG_KMS("\n %02X: ", i);
|
||||
ch7xxx_readb(dvo, i, &val);
|
||||
DRM_LOG_KMS("%02X ", val);
|
||||
}
|
||||
}
|
||||
|
||||
static void ch7xxx_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
|
||||
|
||||
if (ch7xxx) {
|
||||
free(ch7xxx, DRM_MEM_KMS);
|
||||
dvo->dev_priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_dvo_dev_ops ch7xxx_ops = {
|
||||
.init = ch7xxx_init,
|
||||
.detect = ch7xxx_detect,
|
||||
.mode_valid = ch7xxx_mode_valid,
|
||||
.mode_set = ch7xxx_mode_set,
|
||||
.dpms = ch7xxx_dpms,
|
||||
.get_hw_state = ch7xxx_get_hw_state,
|
||||
.dump_regs = ch7xxx_dump_regs,
|
||||
.destroy = ch7xxx_destroy,
|
||||
};
|
439
sys/dev/drm2/i915/dvo_ivch.c
Normal file
439
sys/dev/drm2/i915/dvo_ivch.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* 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
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "dvo.h"
|
||||
|
||||
/*
|
||||
* register definitions for the i82807aa.
|
||||
*
|
||||
* Documentation on this chipset can be found in datasheet #29069001 at
|
||||
* intel.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* VCH Revision & GMBus Base Addr
|
||||
*/
|
||||
#define VR00 0x00
|
||||
# define VR00_BASE_ADDRESS_MASK 0x007f
|
||||
|
||||
/*
|
||||
* Functionality Enable
|
||||
*/
|
||||
#define VR01 0x01
|
||||
|
||||
/*
|
||||
* Enable the panel fitter
|
||||
*/
|
||||
# define VR01_PANEL_FIT_ENABLE (1 << 3)
|
||||
/*
|
||||
* Enables the LCD display.
|
||||
*
|
||||
* This must not be set while VR01_DVO_BYPASS_ENABLE is set.
|
||||
*/
|
||||
# define VR01_LCD_ENABLE (1 << 2)
|
||||
/** Enables the DVO repeater. */
|
||||
# define VR01_DVO_BYPASS_ENABLE (1 << 1)
|
||||
/** Enables the DVO clock */
|
||||
# define VR01_DVO_ENABLE (1 << 0)
|
||||
|
||||
/*
|
||||
* LCD Interface Format
|
||||
*/
|
||||
#define VR10 0x10
|
||||
/** Enables LVDS output instead of CMOS */
|
||||
# define VR10_LVDS_ENABLE (1 << 4)
|
||||
/** Enables 18-bit LVDS output. */
|
||||
# define VR10_INTERFACE_1X18 (0 << 2)
|
||||
/** Enables 24-bit LVDS or CMOS output */
|
||||
# define VR10_INTERFACE_1X24 (1 << 2)
|
||||
/** Enables 2x18-bit LVDS or CMOS output. */
|
||||
# define VR10_INTERFACE_2X18 (2 << 2)
|
||||
/** Enables 2x24-bit LVDS output */
|
||||
# define VR10_INTERFACE_2X24 (3 << 2)
|
||||
|
||||
/*
|
||||
* VR20 LCD Horizontal Display Size
|
||||
*/
|
||||
#define VR20 0x20
|
||||
|
||||
/*
|
||||
* LCD Vertical Display Size
|
||||
*/
|
||||
#define VR21 0x20
|
||||
|
||||
/*
|
||||
* Panel power down status
|
||||
*/
|
||||
#define VR30 0x30
|
||||
/** Read only bit indicating that the panel is not in a safe poweroff state. */
|
||||
# define VR30_PANEL_ON (1 << 15)
|
||||
|
||||
#define VR40 0x40
|
||||
# define VR40_STALL_ENABLE (1 << 13)
|
||||
# define VR40_VERTICAL_INTERP_ENABLE (1 << 12)
|
||||
# define VR40_ENHANCED_PANEL_FITTING (1 << 11)
|
||||
# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10)
|
||||
# define VR40_AUTO_RATIO_ENABLE (1 << 9)
|
||||
# define VR40_CLOCK_GATING_ENABLE (1 << 8)
|
||||
|
||||
/*
|
||||
* Panel Fitting Vertical Ratio
|
||||
* (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
|
||||
*/
|
||||
#define VR41 0x41
|
||||
|
||||
/*
|
||||
* Panel Fitting Horizontal Ratio
|
||||
* (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
|
||||
*/
|
||||
#define VR42 0x42
|
||||
|
||||
/*
|
||||
* Horizontal Image Size
|
||||
*/
|
||||
#define VR43 0x43
|
||||
|
||||
/* VR80 GPIO 0
|
||||
*/
|
||||
#define VR80 0x80
|
||||
#define VR81 0x81
|
||||
#define VR82 0x82
|
||||
#define VR83 0x83
|
||||
#define VR84 0x84
|
||||
#define VR85 0x85
|
||||
#define VR86 0x86
|
||||
#define VR87 0x87
|
||||
|
||||
/* VR88 GPIO 8
|
||||
*/
|
||||
#define VR88 0x88
|
||||
|
||||
/* Graphics BIOS scratch 0
|
||||
*/
|
||||
#define VR8E 0x8E
|
||||
# define VR8E_PANEL_TYPE_MASK (0xf << 0)
|
||||
# define VR8E_PANEL_INTERFACE_CMOS (0 << 4)
|
||||
# define VR8E_PANEL_INTERFACE_LVDS (1 << 4)
|
||||
# define VR8E_FORCE_DEFAULT_PANEL (1 << 5)
|
||||
|
||||
/* Graphics BIOS scratch 1
|
||||
*/
|
||||
#define VR8F 0x8F
|
||||
# define VR8F_VCH_PRESENT (1 << 0)
|
||||
# define VR8F_DISPLAY_CONN (1 << 1)
|
||||
# define VR8F_POWER_MASK (0x3c)
|
||||
# define VR8F_POWER_POS (2)
|
||||
|
||||
|
||||
struct ivch_priv {
|
||||
bool quiet;
|
||||
|
||||
uint16_t width, height;
|
||||
};
|
||||
|
||||
|
||||
static void ivch_dump_regs(struct intel_dvo_device *dvo);
|
||||
|
||||
/**
|
||||
* Reads a register on the ivch.
|
||||
*
|
||||
* Each of the 256 registers are 16 bits long.
|
||||
*/
|
||||
static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
|
||||
{
|
||||
struct ivch_priv *priv = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
u8 out_buf[1];
|
||||
u8 in_buf[2];
|
||||
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 0,
|
||||
},
|
||||
{
|
||||
.slave = 0 << 1,
|
||||
.flags = I2C_M_NOSTART,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD | I2C_M_NOSTART,
|
||||
.len = 2,
|
||||
.buf = in_buf,
|
||||
}
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
|
||||
if (-iicbus_transfer(adapter, msgs, 3) == 0) {
|
||||
*data = (in_buf[1] << 8) | in_buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!priv->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to read register 0x%02x from "
|
||||
"%s:%02x.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Writes a 16-bit register on the ivch */
|
||||
static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
|
||||
{
|
||||
struct ivch_priv *priv = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
u8 out_buf[3];
|
||||
struct iic_msg msg = {
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 3,
|
||||
.buf = out_buf,
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = data & 0xff;
|
||||
out_buf[2] = data >> 8;
|
||||
|
||||
if (-iicbus_transfer(adapter, &msg, 1) == 0)
|
||||
return true;
|
||||
|
||||
if (!priv->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Probes the given bus and slave address for an ivch */
|
||||
static bool ivch_init(struct intel_dvo_device *dvo,
|
||||
device_t adapter)
|
||||
{
|
||||
struct ivch_priv *priv;
|
||||
uint16_t temp;
|
||||
|
||||
priv = malloc(sizeof(struct ivch_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
|
||||
if (priv == NULL)
|
||||
return false;
|
||||
|
||||
dvo->i2c_bus = adapter;
|
||||
dvo->dev_priv = priv;
|
||||
priv->quiet = true;
|
||||
|
||||
if (!ivch_read(dvo, VR00, &temp))
|
||||
goto out;
|
||||
priv->quiet = false;
|
||||
|
||||
/* Since the identification bits are probably zeroes, which doesn't seem
|
||||
* very unique, check that the value in the base address field matches
|
||||
* the address it's responding on.
|
||||
*/
|
||||
if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
|
||||
DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
|
||||
"(%d vs %d)\n",
|
||||
(temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ivch_read(dvo, VR20, &priv->width);
|
||||
ivch_read(dvo, VR21, &priv->height);
|
||||
|
||||
return true;
|
||||
|
||||
out:
|
||||
free(priv, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 112000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
/** Sets the power state of the panel connected to the ivch */
|
||||
static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
int i;
|
||||
uint16_t vr01, vr30, backlight;
|
||||
|
||||
/* Set the new power state of the panel. */
|
||||
if (!ivch_read(dvo, VR01, &vr01))
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
backlight = 1;
|
||||
else
|
||||
backlight = 0;
|
||||
ivch_write(dvo, VR80, backlight);
|
||||
|
||||
if (enable)
|
||||
vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
|
||||
else
|
||||
vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
|
||||
|
||||
ivch_write(dvo, VR01, vr01);
|
||||
|
||||
/* Wait for the panel to make its state transition */
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (!ivch_read(dvo, VR30, &vr30))
|
||||
break;
|
||||
|
||||
if (((vr30 & VR30_PANEL_ON) != 0) == enable)
|
||||
break;
|
||||
udelay(1000);
|
||||
}
|
||||
/* wait some more; vch may fail to resync sometimes without this */
|
||||
udelay(16 * 1000);
|
||||
}
|
||||
|
||||
static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint16_t vr01;
|
||||
|
||||
/* Set the new power state of the panel. */
|
||||
if (!ivch_read(dvo, VR01, &vr01))
|
||||
return false;
|
||||
|
||||
if (vr01 & VR01_LCD_ENABLE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ivch_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
uint16_t vr40 = 0;
|
||||
uint16_t vr01;
|
||||
|
||||
vr01 = 0;
|
||||
vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
|
||||
VR40_HORIZONTAL_INTERP_ENABLE);
|
||||
|
||||
if (mode->hdisplay != adjusted_mode->hdisplay ||
|
||||
mode->vdisplay != adjusted_mode->vdisplay) {
|
||||
uint16_t x_ratio, y_ratio;
|
||||
|
||||
vr01 |= VR01_PANEL_FIT_ENABLE;
|
||||
vr40 |= VR40_CLOCK_GATING_ENABLE;
|
||||
x_ratio = (((mode->hdisplay - 1) << 16) /
|
||||
(adjusted_mode->hdisplay - 1)) >> 2;
|
||||
y_ratio = (((mode->vdisplay - 1) << 16) /
|
||||
(adjusted_mode->vdisplay - 1)) >> 2;
|
||||
ivch_write(dvo, VR42, x_ratio);
|
||||
ivch_write(dvo, VR41, y_ratio);
|
||||
} else {
|
||||
vr01 &= ~VR01_PANEL_FIT_ENABLE;
|
||||
vr40 &= ~VR40_CLOCK_GATING_ENABLE;
|
||||
}
|
||||
vr40 &= ~VR40_AUTO_RATIO_ENABLE;
|
||||
|
||||
ivch_write(dvo, VR01, vr01);
|
||||
ivch_write(dvo, VR40, vr40);
|
||||
|
||||
ivch_dump_regs(dvo);
|
||||
}
|
||||
|
||||
static void ivch_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
ivch_read(dvo, VR00, &val);
|
||||
DRM_LOG_KMS("VR00: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR01, &val);
|
||||
DRM_LOG_KMS("VR01: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR30, &val);
|
||||
DRM_LOG_KMS("VR30: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR40, &val);
|
||||
DRM_LOG_KMS("VR40: 0x%04x\n", val);
|
||||
|
||||
/* GPIO registers */
|
||||
ivch_read(dvo, VR80, &val);
|
||||
DRM_LOG_KMS("VR80: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR81, &val);
|
||||
DRM_LOG_KMS("VR81: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR82, &val);
|
||||
DRM_LOG_KMS("VR82: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR83, &val);
|
||||
DRM_LOG_KMS("VR83: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR84, &val);
|
||||
DRM_LOG_KMS("VR84: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR85, &val);
|
||||
DRM_LOG_KMS("VR85: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR86, &val);
|
||||
DRM_LOG_KMS("VR86: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR87, &val);
|
||||
DRM_LOG_KMS("VR87: 0x%04x\n", val);
|
||||
ivch_read(dvo, VR88, &val);
|
||||
DRM_LOG_KMS("VR88: 0x%04x\n", val);
|
||||
|
||||
/* Scratch register 0 - AIM Panel type */
|
||||
ivch_read(dvo, VR8E, &val);
|
||||
DRM_LOG_KMS("VR8E: 0x%04x\n", val);
|
||||
|
||||
/* Scratch register 1 - Status register */
|
||||
ivch_read(dvo, VR8F, &val);
|
||||
DRM_LOG_KMS("VR8F: 0x%04x\n", val);
|
||||
}
|
||||
|
||||
static void ivch_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct ivch_priv *priv = dvo->dev_priv;
|
||||
|
||||
if (priv) {
|
||||
free(priv, DRM_MEM_KMS);
|
||||
dvo->dev_priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_dvo_dev_ops ivch_ops = {
|
||||
.init = ivch_init,
|
||||
.dpms = ivch_dpms,
|
||||
.get_hw_state = ivch_get_hw_state,
|
||||
.mode_valid = ivch_mode_valid,
|
||||
.mode_set = ivch_mode_set,
|
||||
.detect = ivch_detect,
|
||||
.dump_regs = ivch_dump_regs,
|
||||
.destroy = ivch_destroy,
|
||||
};
|
601
sys/dev/drm2/i915/dvo_ns2501.c
Normal file
601
sys/dev/drm2/i915/dvo_ns2501.c
Normal file
@ -0,0 +1,601 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
|
||||
*
|
||||
* 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, sub license, 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 NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHOR 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "dvo.h"
|
||||
#include "i915_reg.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#define NS2501_VID 0x1305
|
||||
#define NS2501_DID 0x6726
|
||||
|
||||
#define NS2501_VID_LO 0x00
|
||||
#define NS2501_VID_HI 0x01
|
||||
#define NS2501_DID_LO 0x02
|
||||
#define NS2501_DID_HI 0x03
|
||||
#define NS2501_REV 0x04
|
||||
#define NS2501_RSVD 0x05
|
||||
#define NS2501_FREQ_LO 0x06
|
||||
#define NS2501_FREQ_HI 0x07
|
||||
|
||||
#define NS2501_REG8 0x08
|
||||
#define NS2501_8_VEN (1<<5)
|
||||
#define NS2501_8_HEN (1<<4)
|
||||
#define NS2501_8_DSEL (1<<3)
|
||||
#define NS2501_8_BPAS (1<<2)
|
||||
#define NS2501_8_RSVD (1<<1)
|
||||
#define NS2501_8_PD (1<<0)
|
||||
|
||||
#define NS2501_REG9 0x09
|
||||
#define NS2501_9_VLOW (1<<7)
|
||||
#define NS2501_9_MSEL_MASK (0x7<<4)
|
||||
#define NS2501_9_TSEL (1<<3)
|
||||
#define NS2501_9_RSEN (1<<2)
|
||||
#define NS2501_9_RSVD (1<<1)
|
||||
#define NS2501_9_MDI (1<<0)
|
||||
|
||||
#define NS2501_REGC 0x0c
|
||||
|
||||
struct ns2501_priv {
|
||||
//I2CDevRec d;
|
||||
bool quiet;
|
||||
int reg_8_shadow;
|
||||
int reg_8_set;
|
||||
// Shadow registers for i915
|
||||
int dvoc;
|
||||
int pll_a;
|
||||
int srcdim;
|
||||
int fw_blc;
|
||||
};
|
||||
|
||||
#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
|
||||
|
||||
/*
|
||||
* For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens
|
||||
* laptops does not react on the i2c bus unless
|
||||
* both the PLL is running and the display is configured in its native
|
||||
* resolution.
|
||||
* This function forces the DVO on, and stores the registers it touches.
|
||||
* Afterwards, registers are restored to regular values.
|
||||
*
|
||||
* This is pretty much a hack, though it works.
|
||||
* Without that, ns2501_readb and ns2501_writeb fail
|
||||
* when switching the resolution.
|
||||
*/
|
||||
|
||||
static void enable_dvo(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
/*
|
||||
* FIXME Linux<->FreeBSD: device_get_softc() returns a struct
|
||||
* intel_iic_softc in reality, where struct intel_gmbus is
|
||||
* the first member. struct intel_iic_softc is defined in
|
||||
* intel_iic.c.
|
||||
*/
|
||||
struct intel_gmbus *bus =
|
||||
(struct intel_gmbus *)device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
|
||||
DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__);
|
||||
|
||||
ns->dvoc = I915_READ(DVO_C);
|
||||
ns->pll_a = I915_READ(_DPLL_A);
|
||||
ns->srcdim = I915_READ(DVOC_SRCDIM);
|
||||
ns->fw_blc = I915_READ(FW_BLC);
|
||||
|
||||
I915_WRITE(DVOC, 0x10004084);
|
||||
I915_WRITE(_DPLL_A, 0xd0820000);
|
||||
I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768
|
||||
I915_WRITE(FW_BLC, 0x1080304);
|
||||
|
||||
I915_WRITE(DVOC, 0x90004084);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the I915 registers modified by the above
|
||||
* trigger function.
|
||||
*/
|
||||
static void restore_dvo(struct intel_dvo_device *dvo)
|
||||
{
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
/*
|
||||
* FIXME Linux<->FreeBSD: device_get_softc() returns a struct
|
||||
* intel_iic_softc in reality, where struct intel_gmbus is
|
||||
* the first member. struct intel_iic_softc is defined in
|
||||
* intel_iic.c.
|
||||
*/
|
||||
struct intel_gmbus *bus =
|
||||
(struct intel_gmbus *)device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
|
||||
I915_WRITE(DVOC, ns->dvoc);
|
||||
I915_WRITE(_DPLL_A, ns->pll_a);
|
||||
I915_WRITE(DVOC_SRCDIM, ns->srcdim);
|
||||
I915_WRITE(FW_BLC, ns->fw_blc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a register from the ns2501.
|
||||
** Returns true if successful, false otherwise.
|
||||
** If it returns false, it might be wise to enable the
|
||||
** DVO with the above function.
|
||||
*/
|
||||
static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
|
||||
{
|
||||
struct ns2501_priv *ns = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
u8 out_buf[2];
|
||||
u8 in_buf[2];
|
||||
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = in_buf,
|
||||
}
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = 0;
|
||||
|
||||
if (-iicbus_transfer(adapter, msgs, 2) == 0) {
|
||||
*ch = in_buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ns->quiet) {
|
||||
DRM_DEBUG_KMS
|
||||
("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
|
||||
device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a register to the ns2501.
|
||||
** Returns true if successful, false otherwise.
|
||||
** If it returns false, it might be wise to enable the
|
||||
** DVO with the above function.
|
||||
*/
|
||||
static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
|
||||
{
|
||||
struct ns2501_priv *ns = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
uint8_t out_buf[2];
|
||||
|
||||
struct iic_msg msg = {
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = out_buf,
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = ch;
|
||||
|
||||
if (-iicbus_transfer(adapter, &msg, 1) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ns->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* National Semiconductor 2501 driver for chip on i2c bus
|
||||
* scan for the chip on the bus.
|
||||
* Hope the VBIOS initialized the PLL correctly so we can
|
||||
* talk to it. If not, it will not be seen and not detected.
|
||||
* Bummer!
|
||||
*/
|
||||
static bool ns2501_init(struct intel_dvo_device *dvo,
|
||||
device_t adapter)
|
||||
{
|
||||
/* this will detect the NS2501 chip on the specified i2c bus */
|
||||
struct ns2501_priv *ns;
|
||||
unsigned char ch;
|
||||
|
||||
ns = malloc(sizeof(struct ns2501_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
|
||||
if (ns == NULL)
|
||||
return false;
|
||||
|
||||
dvo->i2c_bus = adapter;
|
||||
dvo->dev_priv = ns;
|
||||
ns->quiet = true;
|
||||
|
||||
if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
|
||||
goto out;
|
||||
|
||||
if (ch != (NS2501_VID & 0xff)) {
|
||||
DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
|
||||
ch, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
|
||||
goto out;
|
||||
|
||||
if (ch != (NS2501_DID & 0xff)) {
|
||||
DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
|
||||
ch, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
ns->quiet = false;
|
||||
ns->reg_8_set = 0;
|
||||
ns->reg_8_shadow =
|
||||
NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN;
|
||||
|
||||
DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
|
||||
return true;
|
||||
|
||||
out:
|
||||
free(ns, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
|
||||
{
|
||||
/*
|
||||
* This is a Laptop display, it doesn't have hotplugging.
|
||||
* Even if not, the detection bit of the 2501 is unreliable as
|
||||
* it only works for some display types.
|
||||
* It is even more unreliable as the PLL must be active for
|
||||
* allowing reading from the chiop.
|
||||
*/
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
DRM_DEBUG_KMS
|
||||
("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
|
||||
__FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
|
||||
mode->vtotal);
|
||||
|
||||
/*
|
||||
* Currently, these are all the modes I have data from.
|
||||
* More might exist. Unclear how to find the native resolution
|
||||
* of the panel in here so we could always accept it
|
||||
* by disabling the scaler.
|
||||
*/
|
||||
if ((mode->hdisplay == 800 && mode->vdisplay == 600) ||
|
||||
(mode->hdisplay == 640 && mode->vdisplay == 480) ||
|
||||
(mode->hdisplay == 1024 && mode->vdisplay == 768)) {
|
||||
return MODE_OK;
|
||||
} else {
|
||||
return MODE_ONE_SIZE; /* Is this a reasonable error? */
|
||||
}
|
||||
}
|
||||
|
||||
static void ns2501_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
bool ok;
|
||||
bool restore = false;
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
|
||||
DRM_DEBUG_KMS
|
||||
("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
|
||||
__FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay,
|
||||
mode->vtotal);
|
||||
|
||||
/*
|
||||
* Where do I find the native resolution for which scaling is not required???
|
||||
*
|
||||
* First trigger the DVO on as otherwise the chip does not appear on the i2c
|
||||
* bus.
|
||||
*/
|
||||
do {
|
||||
ok = true;
|
||||
|
||||
if (mode->hdisplay == 800 && mode->vdisplay == 600) {
|
||||
/* mode 277 */
|
||||
ns->reg_8_shadow &= ~NS2501_8_BPAS;
|
||||
DRM_DEBUG_KMS("%s: switching to 800x600\n",
|
||||
__FUNCTION__);
|
||||
|
||||
/*
|
||||
* No, I do not know where this data comes from.
|
||||
* It is just what the video bios left in the DVO, so
|
||||
* I'm just copying it here over.
|
||||
* This also means that I cannot support any other modes
|
||||
* except the ones supported by the bios.
|
||||
*/
|
||||
ok &= ns2501_writeb(dvo, 0x11, 0xc8); // 0xc7 also works.
|
||||
ok &= ns2501_writeb(dvo, 0x1b, 0x19);
|
||||
ok &= ns2501_writeb(dvo, 0x1c, 0x62); // VBIOS left 0x64 here, but 0x62 works nicer
|
||||
ok &= ns2501_writeb(dvo, 0x1d, 0x02);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x34, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0x35, 0xff);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x80, 0x27);
|
||||
ok &= ns2501_writeb(dvo, 0x81, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0x82, 0x41);
|
||||
ok &= ns2501_writeb(dvo, 0x83, 0x05);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x8d, 0x02);
|
||||
ok &= ns2501_writeb(dvo, 0x8e, 0x04);
|
||||
ok &= ns2501_writeb(dvo, 0x8f, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x90, 0xfe); /* vertical. VBIOS left 0xff here, but 0xfe works better */
|
||||
ok &= ns2501_writeb(dvo, 0x91, 0x07);
|
||||
ok &= ns2501_writeb(dvo, 0x94, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x95, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x96, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x99, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9a, 0x88);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x9c, 0x23); /* Looks like first and last line of the image. */
|
||||
ok &= ns2501_writeb(dvo, 0x9d, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9e, 0x25);
|
||||
ok &= ns2501_writeb(dvo, 0x9f, 0x03);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xa4, 0x80);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb6, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb9, 0xc8); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xc1, 0xd7);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc2, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc3, 0xf8);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc4, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0xc5, 0x1a);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc6, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc7, 0x73);
|
||||
ok &= ns2501_writeb(dvo, 0xc8, 0x02);
|
||||
|
||||
} else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
|
||||
/* mode 274 */
|
||||
DRM_DEBUG_KMS("%s: switching to 640x480\n",
|
||||
__FUNCTION__);
|
||||
/*
|
||||
* No, I do not know where this data comes from.
|
||||
* It is just what the video bios left in the DVO, so
|
||||
* I'm just copying it here over.
|
||||
* This also means that I cannot support any other modes
|
||||
* except the ones supported by the bios.
|
||||
*/
|
||||
ns->reg_8_shadow &= ~NS2501_8_BPAS;
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x11, 0xa0);
|
||||
ok &= ns2501_writeb(dvo, 0x1b, 0x11);
|
||||
ok &= ns2501_writeb(dvo, 0x1c, 0x54);
|
||||
ok &= ns2501_writeb(dvo, 0x1d, 0x03);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x34, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0x35, 0xff);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x80, 0xff);
|
||||
ok &= ns2501_writeb(dvo, 0x81, 0x07);
|
||||
ok &= ns2501_writeb(dvo, 0x82, 0x3d);
|
||||
ok &= ns2501_writeb(dvo, 0x83, 0x05);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x8d, 0x02);
|
||||
ok &= ns2501_writeb(dvo, 0x8e, 0x10);
|
||||
ok &= ns2501_writeb(dvo, 0x8f, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x90, 0xff); /* vertical */
|
||||
ok &= ns2501_writeb(dvo, 0x91, 0x07);
|
||||
ok &= ns2501_writeb(dvo, 0x94, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x95, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x96, 0x05);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x99, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9a, 0x88);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x9c, 0x24);
|
||||
ok &= ns2501_writeb(dvo, 0x9d, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9e, 0x25);
|
||||
ok &= ns2501_writeb(dvo, 0x9f, 0x03);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xa4, 0x84);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb6, 0x09);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb9, 0xa0); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xc1, 0x90);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc2, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc3, 0x0f);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc4, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0xc5, 0x16);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc6, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc7, 0x02);
|
||||
ok &= ns2501_writeb(dvo, 0xc8, 0x02);
|
||||
|
||||
} else if (mode->hdisplay == 1024 && mode->vdisplay == 768) {
|
||||
/* mode 280 */
|
||||
DRM_DEBUG_KMS("%s: switching to 1024x768\n",
|
||||
__FUNCTION__);
|
||||
/*
|
||||
* This might or might not work, actually. I'm silently
|
||||
* assuming here that the native panel resolution is
|
||||
* 1024x768. If not, then this leaves the scaler disabled
|
||||
* generating a picture that is likely not the expected.
|
||||
*
|
||||
* Problem is that I do not know where to take the panel
|
||||
* dimensions from.
|
||||
*
|
||||
* Enable the bypass, scaling not required.
|
||||
*
|
||||
* The scaler registers are irrelevant here....
|
||||
*
|
||||
*/
|
||||
ns->reg_8_shadow |= NS2501_8_BPAS;
|
||||
ok &= ns2501_writeb(dvo, 0x37, 0x44);
|
||||
} else {
|
||||
/*
|
||||
* Data not known. Bummer!
|
||||
* Hopefully, the code should not go here
|
||||
* as mode_OK delivered no other modes.
|
||||
*/
|
||||
ns->reg_8_shadow |= NS2501_8_BPAS;
|
||||
}
|
||||
ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow);
|
||||
|
||||
if (!ok) {
|
||||
if (restore)
|
||||
restore_dvo(dvo);
|
||||
enable_dvo(dvo);
|
||||
restore = true;
|
||||
}
|
||||
} while (!ok);
|
||||
/*
|
||||
* Restore the old i915 registers before
|
||||
* forcing the ns2501 on.
|
||||
*/
|
||||
if (restore)
|
||||
restore_dvo(dvo);
|
||||
}
|
||||
|
||||
/* set the NS2501 power state */
|
||||
static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
if (!ns2501_readb(dvo, NS2501_REG8, &ch))
|
||||
return false;
|
||||
|
||||
if (ch & NS2501_8_PD)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* set the NS2501 power state */
|
||||
static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
bool ok;
|
||||
bool restore = false;
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
unsigned char ch;
|
||||
|
||||
DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %i\n",
|
||||
__FUNCTION__, enable);
|
||||
|
||||
ch = ns->reg_8_shadow;
|
||||
|
||||
if (enable)
|
||||
ch |= NS2501_8_PD;
|
||||
else
|
||||
ch &= ~NS2501_8_PD;
|
||||
|
||||
if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) {
|
||||
ns->reg_8_set = 1;
|
||||
ns->reg_8_shadow = ch;
|
||||
|
||||
do {
|
||||
ok = true;
|
||||
ok &= ns2501_writeb(dvo, NS2501_REG8, ch);
|
||||
ok &=
|
||||
ns2501_writeb(dvo, 0x34,
|
||||
enable ? 0x03 : 0x00);
|
||||
ok &=
|
||||
ns2501_writeb(dvo, 0x35,
|
||||
enable ? 0xff : 0x00);
|
||||
if (!ok) {
|
||||
if (restore)
|
||||
restore_dvo(dvo);
|
||||
enable_dvo(dvo);
|
||||
restore = true;
|
||||
}
|
||||
} while (!ok);
|
||||
|
||||
if (restore)
|
||||
restore_dvo(dvo);
|
||||
}
|
||||
}
|
||||
|
||||
static void ns2501_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
ns2501_readb(dvo, NS2501_FREQ_LO, &val);
|
||||
DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_FREQ_HI, &val);
|
||||
DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_REG8, &val);
|
||||
DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_REG9, &val);
|
||||
DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_REGC, &val);
|
||||
DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val);
|
||||
}
|
||||
|
||||
static void ns2501_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct ns2501_priv *ns = dvo->dev_priv;
|
||||
|
||||
if (ns) {
|
||||
free(ns, DRM_MEM_KMS);
|
||||
dvo->dev_priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_dvo_dev_ops ns2501_ops = {
|
||||
.init = ns2501_init,
|
||||
.detect = ns2501_detect,
|
||||
.mode_valid = ns2501_mode_valid,
|
||||
.mode_set = ns2501_mode_set,
|
||||
.dpms = ns2501_dpms,
|
||||
.get_hw_state = ns2501_get_hw_state,
|
||||
.dump_regs = ns2501_dump_regs,
|
||||
.destroy = ns2501_destroy,
|
||||
};
|
282
sys/dev/drm2/i915/dvo_sil164.c
Normal file
282
sys/dev/drm2/i915/dvo_sil164.c
Normal file
@ -0,0 +1,282 @@
|
||||
/**************************************************************************
|
||||
|
||||
Copyright © 2006 Dave Airlie
|
||||
|
||||
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, sub license, 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 NON-INFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHOR 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.
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "dvo.h"
|
||||
|
||||
#define SIL164_VID 0x0001
|
||||
#define SIL164_DID 0x0006
|
||||
|
||||
#define SIL164_VID_LO 0x00
|
||||
#define SIL164_VID_HI 0x01
|
||||
#define SIL164_DID_LO 0x02
|
||||
#define SIL164_DID_HI 0x03
|
||||
#define SIL164_REV 0x04
|
||||
#define SIL164_RSVD 0x05
|
||||
#define SIL164_FREQ_LO 0x06
|
||||
#define SIL164_FREQ_HI 0x07
|
||||
|
||||
#define SIL164_REG8 0x08
|
||||
#define SIL164_8_VEN (1<<5)
|
||||
#define SIL164_8_HEN (1<<4)
|
||||
#define SIL164_8_DSEL (1<<3)
|
||||
#define SIL164_8_BSEL (1<<2)
|
||||
#define SIL164_8_EDGE (1<<1)
|
||||
#define SIL164_8_PD (1<<0)
|
||||
|
||||
#define SIL164_REG9 0x09
|
||||
#define SIL164_9_VLOW (1<<7)
|
||||
#define SIL164_9_MSEL_MASK (0x7<<4)
|
||||
#define SIL164_9_TSEL (1<<3)
|
||||
#define SIL164_9_RSEN (1<<2)
|
||||
#define SIL164_9_HTPLG (1<<1)
|
||||
#define SIL164_9_MDI (1<<0)
|
||||
|
||||
#define SIL164_REGC 0x0c
|
||||
|
||||
struct sil164_priv {
|
||||
//I2CDevRec d;
|
||||
bool quiet;
|
||||
};
|
||||
|
||||
#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
|
||||
|
||||
static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
|
||||
{
|
||||
struct sil164_priv *sil = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
u8 out_buf[2];
|
||||
u8 in_buf[2];
|
||||
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = in_buf,
|
||||
}
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = 0;
|
||||
|
||||
if (-iicbus_transfer(adapter, msgs, 2) == 0) {
|
||||
*ch = in_buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sil->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
|
||||
{
|
||||
struct sil164_priv *sil = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
uint8_t out_buf[2];
|
||||
struct iic_msg msg = {
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = out_buf,
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = ch;
|
||||
|
||||
if (-iicbus_transfer(adapter, &msg, 1) == 0)
|
||||
return true;
|
||||
|
||||
if (!sil->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Silicon Image 164 driver for chip on i2c bus */
|
||||
static bool sil164_init(struct intel_dvo_device *dvo,
|
||||
device_t adapter)
|
||||
{
|
||||
/* this will detect the SIL164 chip on the specified i2c bus */
|
||||
struct sil164_priv *sil;
|
||||
unsigned char ch;
|
||||
|
||||
sil = malloc(sizeof(struct sil164_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
|
||||
if (sil == NULL)
|
||||
return false;
|
||||
|
||||
dvo->i2c_bus = adapter;
|
||||
dvo->dev_priv = sil;
|
||||
sil->quiet = true;
|
||||
|
||||
if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
|
||||
goto out;
|
||||
|
||||
if (ch != (SIL164_VID & 0xff)) {
|
||||
DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
|
||||
ch, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
|
||||
goto out;
|
||||
|
||||
if (ch != (SIL164_DID & 0xff)) {
|
||||
DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
|
||||
ch, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
sil->quiet = false;
|
||||
|
||||
DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
|
||||
return true;
|
||||
|
||||
out:
|
||||
free(sil, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t reg9;
|
||||
|
||||
sil164_readb(dvo, SIL164_REG9, ®9);
|
||||
|
||||
if (reg9 & SIL164_9_HTPLG)
|
||||
return connector_status_connected;
|
||||
else
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void sil164_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
/* As long as the basics are set up, since we don't have clock
|
||||
* dependencies in the mode setup, we can just leave the
|
||||
* registers alone and everything will work fine.
|
||||
*/
|
||||
/* recommended programming sequence from doc */
|
||||
/*sil164_writeb(sil, 0x08, 0x30);
|
||||
sil164_writeb(sil, 0x09, 0x00);
|
||||
sil164_writeb(sil, 0x0a, 0x90);
|
||||
sil164_writeb(sil, 0x0c, 0x89);
|
||||
sil164_writeb(sil, 0x08, 0x31);*/
|
||||
/* don't do much */
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the SIL164 power state */
|
||||
static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
int ret;
|
||||
unsigned char ch;
|
||||
|
||||
ret = sil164_readb(dvo, SIL164_REG8, &ch);
|
||||
if (ret == false)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
ch |= SIL164_8_PD;
|
||||
else
|
||||
ch &= ~SIL164_8_PD;
|
||||
|
||||
sil164_writeb(dvo, SIL164_REG8, ch);
|
||||
return;
|
||||
}
|
||||
|
||||
static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
|
||||
{
|
||||
int ret;
|
||||
unsigned char ch;
|
||||
|
||||
ret = sil164_readb(dvo, SIL164_REG8, &ch);
|
||||
if (ret == false)
|
||||
return false;
|
||||
|
||||
if (ch & SIL164_8_PD)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void sil164_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
sil164_readb(dvo, SIL164_FREQ_LO, &val);
|
||||
DRM_LOG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
|
||||
sil164_readb(dvo, SIL164_FREQ_HI, &val);
|
||||
DRM_LOG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
|
||||
sil164_readb(dvo, SIL164_REG8, &val);
|
||||
DRM_LOG_KMS("SIL164_REG8: 0x%02x\n", val);
|
||||
sil164_readb(dvo, SIL164_REG9, &val);
|
||||
DRM_LOG_KMS("SIL164_REG9: 0x%02x\n", val);
|
||||
sil164_readb(dvo, SIL164_REGC, &val);
|
||||
DRM_LOG_KMS("SIL164_REGC: 0x%02x\n", val);
|
||||
}
|
||||
|
||||
static void sil164_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct sil164_priv *sil = dvo->dev_priv;
|
||||
|
||||
if (sil) {
|
||||
free(sil, DRM_MEM_KMS);
|
||||
dvo->dev_priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_dvo_dev_ops sil164_ops = {
|
||||
.init = sil164_init,
|
||||
.detect = sil164_detect,
|
||||
.mode_valid = sil164_mode_valid,
|
||||
.mode_set = sil164_mode_set,
|
||||
.dpms = sil164_dpms,
|
||||
.get_hw_state = sil164_get_hw_state,
|
||||
.dump_regs = sil164_dump_regs,
|
||||
.destroy = sil164_destroy,
|
||||
};
|
321
sys/dev/drm2/i915/dvo_tfp410.c
Normal file
321
sys/dev/drm2/i915/dvo_tfp410.c
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright © 2007 Dave Mueller
|
||||
*
|
||||
* 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
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS 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 Mueller <dave.mueller@gmx.ch>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "dvo.h"
|
||||
|
||||
/* register definitions according to the TFP410 data sheet */
|
||||
#define TFP410_VID 0x014C
|
||||
#define TFP410_DID 0x0410
|
||||
|
||||
#define TFP410_VID_LO 0x00
|
||||
#define TFP410_VID_HI 0x01
|
||||
#define TFP410_DID_LO 0x02
|
||||
#define TFP410_DID_HI 0x03
|
||||
#define TFP410_REV 0x04
|
||||
|
||||
#define TFP410_CTL_1 0x08
|
||||
#define TFP410_CTL_1_TDIS (1<<6)
|
||||
#define TFP410_CTL_1_VEN (1<<5)
|
||||
#define TFP410_CTL_1_HEN (1<<4)
|
||||
#define TFP410_CTL_1_DSEL (1<<3)
|
||||
#define TFP410_CTL_1_BSEL (1<<2)
|
||||
#define TFP410_CTL_1_EDGE (1<<1)
|
||||
#define TFP410_CTL_1_PD (1<<0)
|
||||
|
||||
#define TFP410_CTL_2 0x09
|
||||
#define TFP410_CTL_2_VLOW (1<<7)
|
||||
#define TFP410_CTL_2_MSEL_MASK (0x7<<4)
|
||||
#define TFP410_CTL_2_MSEL (1<<4)
|
||||
#define TFP410_CTL_2_TSEL (1<<3)
|
||||
#define TFP410_CTL_2_RSEN (1<<2)
|
||||
#define TFP410_CTL_2_HTPLG (1<<1)
|
||||
#define TFP410_CTL_2_MDI (1<<0)
|
||||
|
||||
#define TFP410_CTL_3 0x0A
|
||||
#define TFP410_CTL_3_DK_MASK (0x7<<5)
|
||||
#define TFP410_CTL_3_DK (1<<5)
|
||||
#define TFP410_CTL_3_DKEN (1<<4)
|
||||
#define TFP410_CTL_3_CTL_MASK (0x7<<1)
|
||||
#define TFP410_CTL_3_CTL (1<<1)
|
||||
|
||||
#define TFP410_USERCFG 0x0B
|
||||
|
||||
#define TFP410_DE_DLY 0x32
|
||||
|
||||
#define TFP410_DE_CTL 0x33
|
||||
#define TFP410_DE_CTL_DEGEN (1<<6)
|
||||
#define TFP410_DE_CTL_VSPOL (1<<5)
|
||||
#define TFP410_DE_CTL_HSPOL (1<<4)
|
||||
#define TFP410_DE_CTL_DEDLY8 (1<<0)
|
||||
|
||||
#define TFP410_DE_TOP 0x34
|
||||
|
||||
#define TFP410_DE_CNT_LO 0x36
|
||||
#define TFP410_DE_CNT_HI 0x37
|
||||
|
||||
#define TFP410_DE_LIN_LO 0x38
|
||||
#define TFP410_DE_LIN_HI 0x39
|
||||
|
||||
#define TFP410_H_RES_LO 0x3A
|
||||
#define TFP410_H_RES_HI 0x3B
|
||||
|
||||
#define TFP410_V_RES_LO 0x3C
|
||||
#define TFP410_V_RES_HI 0x3D
|
||||
|
||||
struct tfp410_priv {
|
||||
bool quiet;
|
||||
};
|
||||
|
||||
static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
|
||||
{
|
||||
struct tfp410_priv *tfp = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
u8 out_buf[2];
|
||||
u8 in_buf[2];
|
||||
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = in_buf,
|
||||
}
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = 0;
|
||||
|
||||
if (-iicbus_transfer(adapter, msgs, 2) == 0) {
|
||||
*ch = in_buf[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!tfp->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
|
||||
{
|
||||
struct tfp410_priv *tfp = dvo->dev_priv;
|
||||
device_t adapter = dvo->i2c_bus;
|
||||
uint8_t out_buf[2];
|
||||
struct iic_msg msg = {
|
||||
.slave = dvo->slave_addr << 1,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = out_buf,
|
||||
};
|
||||
|
||||
out_buf[0] = addr;
|
||||
out_buf[1] = ch;
|
||||
|
||||
if (-iicbus_transfer(adapter, &msg, 1) == 0)
|
||||
return true;
|
||||
|
||||
if (!tfp->quiet) {
|
||||
DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
|
||||
addr, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
|
||||
{
|
||||
uint8_t ch1, ch2;
|
||||
|
||||
if (tfp410_readb(dvo, addr+0, &ch1) &&
|
||||
tfp410_readb(dvo, addr+1, &ch2))
|
||||
return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ti TFP410 driver for chip on i2c bus */
|
||||
static bool tfp410_init(struct intel_dvo_device *dvo,
|
||||
device_t adapter)
|
||||
{
|
||||
/* this will detect the tfp410 chip on the specified i2c bus */
|
||||
struct tfp410_priv *tfp;
|
||||
int id;
|
||||
|
||||
tfp = malloc(sizeof(struct tfp410_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
|
||||
if (tfp == NULL)
|
||||
return false;
|
||||
|
||||
dvo->i2c_bus = adapter;
|
||||
dvo->dev_priv = tfp;
|
||||
tfp->quiet = true;
|
||||
|
||||
if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
|
||||
DRM_DEBUG_KMS("tfp410 not detected got VID %X: from %s "
|
||||
"Slave %d.\n",
|
||||
id, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
|
||||
DRM_DEBUG_KMS("tfp410 not detected got DID %X: from %s "
|
||||
"Slave %d.\n",
|
||||
id, device_get_nameunit(adapter), dvo->slave_addr);
|
||||
goto out;
|
||||
}
|
||||
tfp->quiet = false;
|
||||
return true;
|
||||
out:
|
||||
free(tfp, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
|
||||
{
|
||||
enum drm_connector_status ret = connector_status_disconnected;
|
||||
uint8_t ctl2;
|
||||
|
||||
if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
|
||||
if (ctl2 & TFP410_CTL_2_RSEN)
|
||||
ret = connector_status_connected;
|
||||
else
|
||||
ret = connector_status_disconnected;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void tfp410_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
/* As long as the basics are set up, since we don't have clock dependencies
|
||||
* in the mode setup, we can just leave the registers alone and everything
|
||||
* will work fine.
|
||||
*/
|
||||
/* don't do much */
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the tfp410 power state */
|
||||
static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
uint8_t ctl1;
|
||||
|
||||
if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
ctl1 |= TFP410_CTL_1_PD;
|
||||
else
|
||||
ctl1 &= ~TFP410_CTL_1_PD;
|
||||
|
||||
tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
|
||||
}
|
||||
|
||||
static bool tfp410_get_hw_state(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t ctl1;
|
||||
|
||||
if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
|
||||
return false;
|
||||
|
||||
if (ctl1 & TFP410_CTL_1_PD)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tfp410_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t val, val2;
|
||||
|
||||
tfp410_readb(dvo, TFP410_REV, &val);
|
||||
DRM_LOG_KMS("TFP410_REV: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_CTL_1, &val);
|
||||
DRM_LOG_KMS("TFP410_CTL1: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_CTL_2, &val);
|
||||
DRM_LOG_KMS("TFP410_CTL2: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_CTL_3, &val);
|
||||
DRM_LOG_KMS("TFP410_CTL3: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_USERCFG, &val);
|
||||
DRM_LOG_KMS("TFP410_USERCFG: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_DE_DLY, &val);
|
||||
DRM_LOG_KMS("TFP410_DE_DLY: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_DE_CTL, &val);
|
||||
DRM_LOG_KMS("TFP410_DE_CTL: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_DE_TOP, &val);
|
||||
DRM_LOG_KMS("TFP410_DE_TOP: 0x%02X\n", val);
|
||||
tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
|
||||
tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
|
||||
DRM_LOG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
|
||||
tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
|
||||
tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
|
||||
DRM_LOG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
|
||||
tfp410_readb(dvo, TFP410_H_RES_LO, &val);
|
||||
tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
|
||||
DRM_LOG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);
|
||||
tfp410_readb(dvo, TFP410_V_RES_LO, &val);
|
||||
tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
|
||||
DRM_LOG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
|
||||
}
|
||||
|
||||
static void tfp410_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct tfp410_priv *tfp = dvo->dev_priv;
|
||||
|
||||
if (tfp) {
|
||||
free(tfp, DRM_MEM_KMS);
|
||||
dvo->dev_priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct intel_dvo_dev_ops tfp410_ops = {
|
||||
.init = tfp410_init,
|
||||
.detect = tfp410_detect,
|
||||
.mode_valid = tfp410_mode_valid,
|
||||
.mode_set = tfp410_mode_set,
|
||||
.dpms = tfp410_dpms,
|
||||
.get_hw_state = tfp410_get_hw_state,
|
||||
.dump_regs = tfp410_dump_regs,
|
||||
.destroy = tfp410_destroy,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/*-
|
||||
/*
|
||||
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
@ -24,17 +24,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_I915_DRM_H_
|
||||
#define _UAPI_I915_DRM_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifndef _I915_DRM_H_
|
||||
#define _I915_DRM_H_
|
||||
#include <dev/drm2/drm.h>
|
||||
|
||||
/* Please note that modifications to all structs defined here are
|
||||
* subject to backwards-compatibility constraints.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drm.h>
|
||||
|
||||
/* Each region is a minimum of 16k, and there are at most 255 of them.
|
||||
*/
|
||||
@ -46,12 +47,7 @@ typedef struct _drm_i915_init {
|
||||
enum {
|
||||
I915_INIT_DMA = 0x01,
|
||||
I915_CLEANUP_DMA = 0x02,
|
||||
I915_RESUME_DMA = 0x03,
|
||||
|
||||
/* Since this struct isn't versioned, just used a new
|
||||
* 'func' code to indicate the presence of dri2 sarea
|
||||
* info. */
|
||||
I915_INIT_DMA2 = 0x04
|
||||
I915_RESUME_DMA = 0x03
|
||||
} func;
|
||||
unsigned int mmio_offset;
|
||||
int sarea_priv_offset;
|
||||
@ -69,7 +65,6 @@ typedef struct _drm_i915_init {
|
||||
unsigned int depth_pitch;
|
||||
unsigned int cpp;
|
||||
unsigned int chipset;
|
||||
unsigned int sarea_handle;
|
||||
} drm_i915_init_t;
|
||||
|
||||
typedef struct _drm_i915_sarea {
|
||||
@ -123,20 +118,18 @@ typedef struct _drm_i915_sarea {
|
||||
int pipeB_w;
|
||||
int pipeB_h;
|
||||
|
||||
/* Triple buffering */
|
||||
drm_handle_t third_handle;
|
||||
int third_offset;
|
||||
int third_size;
|
||||
unsigned int third_tiled;
|
||||
/* fill out some space for old userspace triple buffer */
|
||||
drm_handle_t unused_handle;
|
||||
__u32 unused1, unused2, unused3;
|
||||
|
||||
/* buffer object handles for the static buffers. May change
|
||||
* over the lifetime of the client, though it doesn't in our current
|
||||
* implementation.
|
||||
/* buffer object handles for static buffers. May change
|
||||
* over the lifetime of the client.
|
||||
*/
|
||||
__u32 front_bo_handle;
|
||||
__u32 back_bo_handle;
|
||||
__u32 third_bo_handle;
|
||||
__u32 unused_bo_handle;
|
||||
__u32 depth_bo_handle;
|
||||
|
||||
} drm_i915_sarea_t;
|
||||
|
||||
/* due to userspace building against these headers we need some compat here */
|
||||
@ -149,16 +142,6 @@ typedef struct _drm_i915_sarea {
|
||||
#define planeB_w pipeB_w
|
||||
#define planeB_h pipeB_h
|
||||
|
||||
/* Driver specific fence types and classes.
|
||||
*/
|
||||
|
||||
/* The only fence class we support */
|
||||
#define DRM_I915_FENCE_CLASS_ACCEL 0
|
||||
/* Fence type that guarantees read-write flush */
|
||||
#define DRM_I915_FENCE_TYPE_RW 2
|
||||
/* MI_FLUSH programmed just before the fence */
|
||||
#define DRM_I915_FENCE_FLAG_FLUSHED 0x01000000
|
||||
|
||||
/* Flags for perf_boxes
|
||||
*/
|
||||
#define I915_BOX_RING_EMPTY 0x1
|
||||
@ -186,9 +169,7 @@ typedef struct _drm_i915_sarea {
|
||||
#define DRM_I915_SET_VBLANK_PIPE 0x0d
|
||||
#define DRM_I915_GET_VBLANK_PIPE 0x0e
|
||||
#define DRM_I915_VBLANK_SWAP 0x0f
|
||||
#define DRM_I915_MMIO 0x10
|
||||
#define DRM_I915_HWS_ADDR 0x11
|
||||
#define DRM_I915_EXECBUFFER 0x12
|
||||
#define DRM_I915_GEM_INIT 0x13
|
||||
#define DRM_I915_GEM_EXECBUFFER 0x14
|
||||
#define DRM_I915_GEM_PIN 0x15
|
||||
@ -212,14 +193,18 @@ typedef struct _drm_i915_sarea {
|
||||
#define DRM_I915_OVERLAY_PUT_IMAGE 0x27
|
||||
#define DRM_I915_OVERLAY_ATTRS 0x28
|
||||
#define DRM_I915_GEM_EXECBUFFER2 0x29
|
||||
#define DRM_I915_GET_SPRITE_COLORKEY 0x2a
|
||||
#define DRM_I915_SET_SPRITE_COLORKEY 0x2b
|
||||
#define DRM_I915_GET_SPRITE_COLORKEY 0x2a
|
||||
#define DRM_I915_SET_SPRITE_COLORKEY 0x2b
|
||||
#define DRM_I915_GEM_WAIT 0x2c
|
||||
#define DRM_I915_GEM_CONTEXT_CREATE 0x2d
|
||||
#define DRM_I915_GEM_CONTEXT_DESTROY 0x2e
|
||||
#define DRM_I915_GEM_SET_CACHING 0x2f
|
||||
#define DRM_I915_GEM_GET_CACHING 0x30
|
||||
#define DRM_I915_REG_READ 0x31
|
||||
|
||||
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
|
||||
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
|
||||
#define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t)
|
||||
#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP)
|
||||
#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t)
|
||||
#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t)
|
||||
#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t)
|
||||
@ -233,13 +218,15 @@ typedef struct _drm_i915_sarea {
|
||||
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
|
||||
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
|
||||
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
|
||||
#define DRM_IOCTL_I915_MMIO DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_MMIO, drm_i915_mmio)
|
||||
#define DRM_IOCTL_I915_HWS_ADDR DRM_IOW(DRM_COMMAND_BASE + DRM_I915_HWS_ADDR, struct drm_i915_gem_init)
|
||||
#define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init)
|
||||
#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
|
||||
#define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
|
||||
#define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
|
||||
#define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
|
||||
#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
|
||||
#define DRM_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_CACHING, struct drm_i915_gem_caching)
|
||||
#define DRM_IOCTL_I915_GEM_GET_CACHING DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GET_CACHING, struct drm_i915_gem_caching)
|
||||
#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
|
||||
#define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
|
||||
#define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
|
||||
@ -255,24 +242,14 @@ typedef struct _drm_i915_sarea {
|
||||
#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
|
||||
#define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id)
|
||||
#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
|
||||
#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
|
||||
#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
|
||||
#define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
|
||||
#define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
|
||||
#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
|
||||
#define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
|
||||
#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create)
|
||||
#define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
|
||||
|
||||
/* Asynchronous page flipping:
|
||||
*/
|
||||
typedef struct drm_i915_flip {
|
||||
/*
|
||||
* This is really talking about planes, and we could rename it
|
||||
* except for the fact that some of the duplicated i915_drm.h files
|
||||
* out there check for HAVE_I915_FLIP and so might pick up this
|
||||
* version.
|
||||
*/
|
||||
int pipes;
|
||||
} drm_i915_flip_t;
|
||||
#define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
|
||||
|
||||
/* Allow drivers to submit batchbuffers directly to hardware, relying
|
||||
* on the security mechanisms provided by hardware.
|
||||
@ -310,15 +287,15 @@ typedef struct drm_i915_irq_wait {
|
||||
|
||||
/* Ioctl to query kernel params:
|
||||
*/
|
||||
#define I915_PARAM_IRQ_ACTIVE 1
|
||||
#define I915_PARAM_ALLOW_BATCHBUFFER 2
|
||||
#define I915_PARAM_LAST_DISPATCH 3
|
||||
#define I915_PARAM_CHIPSET_ID 4
|
||||
#define I915_PARAM_HAS_GEM 5
|
||||
#define I915_PARAM_NUM_FENCES_AVAIL 6
|
||||
#define I915_PARAM_HAS_OVERLAY 7
|
||||
#define I915_PARAM_IRQ_ACTIVE 1
|
||||
#define I915_PARAM_ALLOW_BATCHBUFFER 2
|
||||
#define I915_PARAM_LAST_DISPATCH 3
|
||||
#define I915_PARAM_CHIPSET_ID 4
|
||||
#define I915_PARAM_HAS_GEM 5
|
||||
#define I915_PARAM_NUM_FENCES_AVAIL 6
|
||||
#define I915_PARAM_HAS_OVERLAY 7
|
||||
#define I915_PARAM_HAS_PAGEFLIPPING 8
|
||||
#define I915_PARAM_HAS_EXECBUF2 9
|
||||
#define I915_PARAM_HAS_EXECBUF2 9
|
||||
#define I915_PARAM_HAS_BSD 10
|
||||
#define I915_PARAM_HAS_BLT 11
|
||||
#define I915_PARAM_HAS_RELAXED_FENCING 12
|
||||
@ -326,8 +303,14 @@ typedef struct drm_i915_irq_wait {
|
||||
#define I915_PARAM_HAS_EXEC_CONSTANTS 14
|
||||
#define I915_PARAM_HAS_RELAXED_DELTA 15
|
||||
#define I915_PARAM_HAS_GEN7_SOL_RESET 16
|
||||
#define I915_PARAM_HAS_LLC 17
|
||||
#define I915_PARAM_HAS_LLC 17
|
||||
#define I915_PARAM_HAS_ALIASING_PPGTT 18
|
||||
#define I915_PARAM_HAS_WAIT_TIMEOUT 19
|
||||
#define I915_PARAM_HAS_SEMAPHORES 20
|
||||
#define I915_PARAM_HAS_PRIME_VMAP_FLUSH 21
|
||||
#define I915_PARAM_RSVD_FOR_FUTURE_USE 22
|
||||
#define I915_PARAM_HAS_SECURE_BATCHES 23
|
||||
#define I915_PARAM_HAS_PINNED_BATCHES 24
|
||||
|
||||
typedef struct drm_i915_getparam {
|
||||
int param;
|
||||
@ -392,70 +375,10 @@ typedef struct drm_i915_vblank_swap {
|
||||
unsigned int sequence;
|
||||
} drm_i915_vblank_swap_t;
|
||||
|
||||
#define I915_MMIO_READ 0
|
||||
#define I915_MMIO_WRITE 1
|
||||
|
||||
#define I915_MMIO_MAY_READ 0x1
|
||||
#define I915_MMIO_MAY_WRITE 0x2
|
||||
|
||||
#define MMIO_REGS_IA_PRIMATIVES_COUNT 0
|
||||
#define MMIO_REGS_IA_VERTICES_COUNT 1
|
||||
#define MMIO_REGS_VS_INVOCATION_COUNT 2
|
||||
#define MMIO_REGS_GS_PRIMITIVES_COUNT 3
|
||||
#define MMIO_REGS_GS_INVOCATION_COUNT 4
|
||||
#define MMIO_REGS_CL_PRIMITIVES_COUNT 5
|
||||
#define MMIO_REGS_CL_INVOCATION_COUNT 6
|
||||
#define MMIO_REGS_PS_INVOCATION_COUNT 7
|
||||
#define MMIO_REGS_PS_DEPTH_COUNT 8
|
||||
|
||||
typedef struct drm_i915_mmio_entry {
|
||||
unsigned int flag;
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
} drm_i915_mmio_entry_t;
|
||||
|
||||
typedef struct drm_i915_mmio {
|
||||
unsigned int read_write:1;
|
||||
unsigned int reg:31;
|
||||
void __user *data;
|
||||
} drm_i915_mmio_t;
|
||||
|
||||
typedef struct drm_i915_hws_addr {
|
||||
__u64 addr;
|
||||
} drm_i915_hws_addr_t;
|
||||
|
||||
/*
|
||||
* Relocation header is 4 uint32_ts
|
||||
* 0 - 32 bit reloc count
|
||||
* 1 - 32-bit relocation type
|
||||
* 2-3 - 64-bit user buffer handle ptr for another list of relocs.
|
||||
*/
|
||||
#define I915_RELOC_HEADER 4
|
||||
|
||||
/*
|
||||
* type 0 relocation has 4-uint32_t stride
|
||||
* 0 - offset into buffer
|
||||
* 1 - delta to add in
|
||||
* 2 - buffer handle
|
||||
* 3 - reserved (for optimisations later).
|
||||
*/
|
||||
/*
|
||||
* type 1 relocation has 4-uint32_t stride.
|
||||
* Hangs off the first item in the op list.
|
||||
* Performed after all valiations are done.
|
||||
* Try to group relocs into the same relocatee together for
|
||||
* performance reasons.
|
||||
* 0 - offset into buffer
|
||||
* 1 - delta to add in
|
||||
* 2 - buffer index in op list.
|
||||
* 3 - relocatee index in op list.
|
||||
*/
|
||||
#define I915_RELOC_TYPE_0 0
|
||||
#define I915_RELOC0_STRIDE 4
|
||||
#define I915_RELOC_TYPE_1 1
|
||||
#define I915_RELOC1_STRIDE 4
|
||||
|
||||
|
||||
struct drm_i915_gem_init {
|
||||
/**
|
||||
* Beginning offset in the GTT to be managed by the DRM memory
|
||||
@ -493,8 +416,12 @@ struct drm_i915_gem_pread {
|
||||
__u64 offset;
|
||||
/** Length of data to read */
|
||||
__u64 size;
|
||||
/** Pointer to write the data into. */
|
||||
__u64 data_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
/**
|
||||
* Pointer to write the data into.
|
||||
*
|
||||
* This is a fixed-size type for 32/64 compatibility.
|
||||
*/
|
||||
__u64 data_ptr;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_pwrite {
|
||||
@ -505,8 +432,12 @@ struct drm_i915_gem_pwrite {
|
||||
__u64 offset;
|
||||
/** Length of data to write */
|
||||
__u64 size;
|
||||
/** Pointer to read the data from. */
|
||||
__u64 data_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
/**
|
||||
* Pointer to read the data from.
|
||||
*
|
||||
* This is a fixed-size type for 32/64 compatibility.
|
||||
*/
|
||||
__u64 data_ptr;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_mmap {
|
||||
@ -521,8 +452,12 @@ struct drm_i915_gem_mmap {
|
||||
* The value will be page-aligned.
|
||||
*/
|
||||
__u64 size;
|
||||
/** Returned pointer the data was mapped at */
|
||||
__u64 addr_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
/**
|
||||
* Returned pointer the data was mapped at.
|
||||
*
|
||||
* This is a fixed-size type for 32/64 compatibility.
|
||||
*/
|
||||
__u64 addr_ptr;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_mmap_gtt {
|
||||
@ -667,7 +602,8 @@ struct drm_i915_gem_execbuffer {
|
||||
__u32 DR1;
|
||||
__u32 DR4;
|
||||
__u32 num_cliprects;
|
||||
__u64 cliprects_ptr; /* struct drm_clip_rect *cliprects */
|
||||
/** This is a struct drm_clip_rect *cliprects */
|
||||
__u64 cliprects_ptr;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_exec_object2 {
|
||||
@ -696,7 +632,7 @@ struct drm_i915_gem_exec_object2 {
|
||||
|
||||
#define EXEC_OBJECT_NEEDS_FENCE (1<<0)
|
||||
__u64 flags;
|
||||
__u64 rsvd1; /* now used for context info */
|
||||
__u64 rsvd1;
|
||||
__u64 rsvd2;
|
||||
};
|
||||
|
||||
@ -733,13 +669,27 @@ struct drm_i915_gem_execbuffer2 {
|
||||
#define I915_EXEC_CONSTANTS_ABSOLUTE (1<<6)
|
||||
#define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) /* gen4/5 only */
|
||||
__u64 flags;
|
||||
__u64 rsvd1;
|
||||
__u64 rsvd1; /* now used for context info */
|
||||
__u64 rsvd2;
|
||||
};
|
||||
|
||||
/** Resets the SO write offset registers for transform feedback on gen7. */
|
||||
#define I915_EXEC_GEN7_SOL_RESET (1<<8)
|
||||
|
||||
/** Request a privileged ("secure") batch buffer. Note only available for
|
||||
* DRM_ROOT_ONLY | DRM_MASTER processes.
|
||||
*/
|
||||
#define I915_EXEC_SECURE (1<<9)
|
||||
|
||||
/** Inform the kernel that the batch is and will always be pinned. This
|
||||
* negates the requirement for a workaround to be performed to avoid
|
||||
* an incoherent CS (such as can be found on 830/845). If this flag is
|
||||
* not passed, the kernel will endeavour to make sure the batch is
|
||||
* coherent with the CS before execution. If this flag is passed,
|
||||
* userspace assumes the responsibility for ensuring the same.
|
||||
*/
|
||||
#define I915_EXEC_IS_PINNED (1<<10)
|
||||
|
||||
#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff)
|
||||
#define i915_execbuffer2_set_context_id(eb2, context) \
|
||||
(eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK
|
||||
@ -768,10 +718,31 @@ struct drm_i915_gem_busy {
|
||||
/** Handle of the buffer to check for busy */
|
||||
__u32 handle;
|
||||
|
||||
/** Return busy status (1 if busy, 0 if idle) */
|
||||
/** Return busy status (1 if busy, 0 if idle).
|
||||
* The high word is used to indicate on which rings the object
|
||||
* currently resides:
|
||||
* 16:31 - busy (r or r/w) rings (16 render, 17 bsd, 18 blt, etc)
|
||||
*/
|
||||
__u32 busy;
|
||||
};
|
||||
|
||||
#define I915_CACHING_NONE 0
|
||||
#define I915_CACHING_CACHED 1
|
||||
|
||||
struct drm_i915_gem_caching {
|
||||
/**
|
||||
* Handle of the buffer to set/get the caching level of. */
|
||||
__u32 handle;
|
||||
|
||||
/**
|
||||
* Cacheing level to apply or return value
|
||||
*
|
||||
* bits0-15 are for generic caching control (i.e. the above defined
|
||||
* values). bits16-31 are reserved for platform-specific variations
|
||||
* (e.g. l3$ caching on gen7). */
|
||||
__u32 caching;
|
||||
};
|
||||
|
||||
#define I915_TILING_NONE 0
|
||||
#define I915_TILING_X 1
|
||||
#define I915_TILING_Y 2
|
||||
@ -856,7 +827,7 @@ struct drm_i915_get_pipe_from_crtc_id {
|
||||
|
||||
#define I915_MADV_WILLNEED 0
|
||||
#define I915_MADV_DONTNEED 1
|
||||
#define I915_MADV_PURGED_INTERNAL 2 /* internal state */
|
||||
#define __I915_MADV_PURGED 2 /* internal state */
|
||||
|
||||
struct drm_i915_gem_madvise {
|
||||
/** Handle of the buffer to change the backing store advice */
|
||||
@ -871,6 +842,7 @@ struct drm_i915_gem_madvise {
|
||||
__u32 retained;
|
||||
};
|
||||
|
||||
/* flags */
|
||||
#define I915_OVERLAY_TYPE_MASK 0xff
|
||||
#define I915_OVERLAY_YUV_PLANAR 0x01
|
||||
#define I915_OVERLAY_YUV_PACKED 0x02
|
||||
@ -968,6 +940,14 @@ struct drm_intel_sprite_colorkey {
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_wait {
|
||||
/** Handle of BO we shall wait on */
|
||||
__u32 bo_handle;
|
||||
__u32 flags;
|
||||
/** Number of nanoseconds to wait, Returns time remaining. */
|
||||
__s64 timeout_ns;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_context_create {
|
||||
/* output: id of new context*/
|
||||
__u32 ctx_id;
|
||||
@ -979,4 +959,15 @@ struct drm_i915_gem_context_destroy {
|
||||
__u32 pad;
|
||||
};
|
||||
|
||||
#endif /* _I915_DRM_H_ */
|
||||
struct drm_i915_reg_read {
|
||||
__u64 offset;
|
||||
__u64 val; /* Return value */
|
||||
};
|
||||
|
||||
/* For use by IPS driver */
|
||||
extern unsigned long i915_read_mch_val(void);
|
||||
extern bool i915_gpu_raise(void);
|
||||
extern bool i915_gpu_lower(void);
|
||||
extern bool i915_gpu_busy(void);
|
||||
extern bool i915_gpu_turbo_disable(void);
|
||||
#endif /* _UAPI_I915_DRM_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -115,11 +115,9 @@ static int get_context_size(struct drm_device *dev)
|
||||
break;
|
||||
case 7:
|
||||
reg = I915_READ(GEN7_CXT_SIZE);
|
||||
#ifdef FREEBSD_WIP
|
||||
if (IS_HASWELL(dev))
|
||||
ret = HSW_CXT_TOTAL_SIZE(reg) * 64;
|
||||
else
|
||||
#endif
|
||||
ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
|
||||
break;
|
||||
default:
|
||||
@ -140,7 +138,7 @@ static void do_destroy(struct i915_hw_context *ctx)
|
||||
if (ctx->file_priv)
|
||||
drm_gem_names_remove(&ctx->file_priv->context_idr, ctx->id);
|
||||
else
|
||||
KASSERT(ctx == dev_priv->rings[RCS].default_context,
|
||||
KASSERT(ctx == dev_priv->ring[RCS].default_context,
|
||||
("i915_gem_context: ctx != default_context"));
|
||||
|
||||
drm_gem_object_unreference(&ctx->obj->base);
|
||||
@ -178,7 +176,7 @@ create_hw_context(struct drm_device *dev,
|
||||
* object tracking code. We give an initial ring value simple to pass an
|
||||
* assertion in the context switch code.
|
||||
*/
|
||||
ctx->ring = &dev_priv->rings[RCS];
|
||||
ctx->ring = &dev_priv->ring[RCS];
|
||||
|
||||
/* Default context will never have a file_priv */
|
||||
if (file_priv == NULL) {
|
||||
@ -234,8 +232,8 @@ static int create_default_context(struct drm_i915_private *dev_priv)
|
||||
* may not be available. To avoid this we always pin the
|
||||
* default context.
|
||||
*/
|
||||
dev_priv->rings[RCS].default_context = ctx;
|
||||
ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false);
|
||||
dev_priv->ring[RCS].default_context = ctx;
|
||||
ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
|
||||
if (ret)
|
||||
goto err_destroy;
|
||||
|
||||
@ -265,12 +263,12 @@ void i915_gem_context_init(struct drm_device *dev)
|
||||
|
||||
/* If called from reset, or thaw... we've been here already */
|
||||
if (dev_priv->hw_contexts_disabled ||
|
||||
dev_priv->rings[RCS].default_context)
|
||||
dev_priv->ring[RCS].default_context)
|
||||
return;
|
||||
|
||||
ctx_size = get_context_size(dev);
|
||||
dev_priv->hw_context_size = get_context_size(dev);
|
||||
dev_priv->hw_context_size = roundup(dev_priv->hw_context_size, 4096);
|
||||
dev_priv->hw_context_size = round_up(dev_priv->hw_context_size, 4096);
|
||||
|
||||
if (ctx_size <= 0 || ctx_size > (1<<20)) {
|
||||
dev_priv->hw_contexts_disabled = true;
|
||||
@ -297,9 +295,9 @@ void i915_gem_context_fini(struct drm_device *dev)
|
||||
* other code, leading to spurious errors. */
|
||||
intel_gpu_reset(dev);
|
||||
|
||||
i915_gem_object_unpin(dev_priv->rings[RCS].default_context->obj);
|
||||
i915_gem_object_unpin(dev_priv->ring[RCS].default_context->obj);
|
||||
|
||||
do_destroy(dev_priv->rings[RCS].default_context);
|
||||
do_destroy(dev_priv->ring[RCS].default_context);
|
||||
}
|
||||
|
||||
static int context_idr_cleanup(uint32_t id, void *p, void *data)
|
||||
@ -389,7 +387,7 @@ static int do_switch(struct i915_hw_context *to)
|
||||
if (from_obj == to->obj)
|
||||
return 0;
|
||||
|
||||
ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false);
|
||||
ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -426,8 +424,7 @@ static int do_switch(struct i915_hw_context *to)
|
||||
*/
|
||||
if (from_obj != NULL) {
|
||||
from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
|
||||
i915_gem_object_move_to_active(from_obj, ring,
|
||||
i915_gem_next_request_seqno(ring));
|
||||
i915_gem_object_move_to_active(from_obj, ring);
|
||||
/* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
|
||||
* whole damn pipeline, we don't need to explicitly mark the
|
||||
* object dirty. The only exception is that the context must be
|
||||
@ -472,7 +469,7 @@ int i915_switch_context(struct intel_ring_buffer *ring,
|
||||
if (dev_priv->hw_contexts_disabled)
|
||||
return 0;
|
||||
|
||||
if (ring != &dev_priv->rings[RCS])
|
||||
if (ring != &dev_priv->ring[RCS])
|
||||
return 0;
|
||||
|
||||
if (to_id == DEFAULT_CONTEXT_ID) {
|
||||
|
@ -30,9 +30,8 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
|
||||
static bool
|
||||
mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
|
||||
@ -46,7 +45,8 @@ mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
|
||||
|
||||
int
|
||||
i915_gem_evict_something(struct drm_device *dev, int min_size,
|
||||
unsigned alignment, bool mappable)
|
||||
unsigned alignment, unsigned cache_level,
|
||||
bool mappable, bool nonblocking)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct list_head eviction_list, unwind_list;
|
||||
@ -81,11 +81,12 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
|
||||
|
||||
INIT_LIST_HEAD(&unwind_list);
|
||||
if (mappable)
|
||||
drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size,
|
||||
alignment, 0, 0,
|
||||
dev_priv->mm.gtt_mappable_end);
|
||||
drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space,
|
||||
min_size, alignment, cache_level,
|
||||
0, dev_priv->mm.gtt_mappable_end);
|
||||
else
|
||||
drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment, 0);
|
||||
drm_mm_init_scan(&dev_priv->mm.gtt_space,
|
||||
min_size, alignment, cache_level);
|
||||
|
||||
/* First see if there is a large enough contiguous idle region... */
|
||||
list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
|
||||
@ -93,29 +94,16 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (nonblocking)
|
||||
goto none;
|
||||
|
||||
/* Now merge in the soon-to-be-expired objects... */
|
||||
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
|
||||
/* Does the object require an outstanding flush? */
|
||||
if (obj->base.write_domain)
|
||||
continue;
|
||||
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Finally add anything with a pending flush (in order of retirement) */
|
||||
list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
|
||||
if (!obj->base.write_domain)
|
||||
continue;
|
||||
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
|
||||
none:
|
||||
/* Nothing found, clean up and bail out! */
|
||||
while (!list_empty(&unwind_list)) {
|
||||
obj = list_first_entry(&unwind_list,
|
||||
@ -123,7 +111,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
|
||||
exec_list);
|
||||
|
||||
ret = drm_mm_scan_remove_block(obj->gtt_space);
|
||||
KASSERT(ret == 0, ("drm_mm_scan_remove_block failed %d", ret));
|
||||
BUG_ON(ret);
|
||||
|
||||
list_del_init(&obj->exec_list);
|
||||
}
|
||||
@ -166,7 +154,7 @@ found:
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
||||
i915_gem_evict_everything(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj, *next;
|
||||
@ -174,12 +162,11 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
||||
int ret;
|
||||
|
||||
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
|
||||
list_empty(&dev_priv->mm.flushing_list) &&
|
||||
list_empty(&dev_priv->mm.active_list));
|
||||
if (lists_empty)
|
||||
return -ENOSPC;
|
||||
|
||||
CTR2(KTR_DRM, "evict_everything %p %d", dev, purgeable_only);
|
||||
CTR1(KTR_DRM, "evict_everything %p", dev);
|
||||
|
||||
/* The gpu_idle will flush everything in the write domain to the
|
||||
* active list. Then we must move everything off the active list
|
||||
@ -191,17 +178,11 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
||||
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
KASSERT(list_empty(&dev_priv->mm.flushing_list),
|
||||
("flush list not empty"));
|
||||
|
||||
/* Having flushed everything, unbind() should never raise an error */
|
||||
list_for_each_entry_safe(obj, next,
|
||||
&dev_priv->mm.inactive_list, mm_list) {
|
||||
if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
|
||||
if (obj->pin_count == 0)
|
||||
i915_gem_object_unbind(obj);
|
||||
}
|
||||
}
|
||||
&dev_priv->mm.inactive_list, mm_list)
|
||||
if (obj->pin_count == 0)
|
||||
WARN_ON(i915_gem_object_unbind(obj));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,28 +26,75 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/sf_buf.h>
|
||||
#include <vm/vm_pageout.h>
|
||||
|
||||
typedef uint32_t gtt_pte_t;
|
||||
|
||||
/* PPGTT stuff */
|
||||
#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
|
||||
|
||||
#define GEN6_PDE_VALID (1 << 0)
|
||||
/* gen6+ has bit 11-4 for physical addr bit 39-32 */
|
||||
#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
|
||||
|
||||
#define GEN6_PTE_VALID (1 << 0)
|
||||
#define GEN6_PTE_UNCACHED (1 << 1)
|
||||
#define HSW_PTE_UNCACHED (0)
|
||||
#define GEN6_PTE_CACHE_LLC (2 << 1)
|
||||
#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
|
||||
#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
|
||||
|
||||
static inline gtt_pte_t pte_encode(struct drm_device *dev,
|
||||
dma_addr_t addr,
|
||||
enum i915_cache_level level)
|
||||
{
|
||||
gtt_pte_t pte = GEN6_PTE_VALID;
|
||||
pte |= GEN6_PTE_ADDR_ENCODE(addr);
|
||||
|
||||
switch (level) {
|
||||
case I915_CACHE_LLC_MLC:
|
||||
/* Haswell doesn't set L3 this way */
|
||||
if (IS_HASWELL(dev))
|
||||
pte |= GEN6_PTE_CACHE_LLC;
|
||||
else
|
||||
pte |= GEN6_PTE_CACHE_LLC_MLC;
|
||||
break;
|
||||
case I915_CACHE_LLC:
|
||||
pte |= GEN6_PTE_CACHE_LLC;
|
||||
break;
|
||||
case I915_CACHE_NONE:
|
||||
if (IS_HASWELL(dev))
|
||||
pte |= HSW_PTE_UNCACHED;
|
||||
else
|
||||
pte |= GEN6_PTE_UNCACHED;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
/* PPGTT support for Sandybdrige/Gen6 and later */
|
||||
static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
unsigned first_entry,
|
||||
unsigned num_entries)
|
||||
{
|
||||
uint32_t *pt_vaddr;
|
||||
uint32_t scratch_pte;
|
||||
gtt_pte_t *pt_vaddr;
|
||||
gtt_pte_t scratch_pte;
|
||||
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
unsigned last_pte, i;
|
||||
struct sf_buf *sf;
|
||||
unsigned act_pd, first_pte, last_pte, i;
|
||||
|
||||
act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
|
||||
scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr);
|
||||
scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC;
|
||||
scratch_pte = pte_encode(ppgtt->dev, ppgtt->scratch_page_dma_addr,
|
||||
I915_CACHE_LLC);
|
||||
|
||||
while (num_entries) {
|
||||
last_pte = first_pte + num_entries;
|
||||
@ -68,7 +115,6 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
first_pte = 0;
|
||||
act_pd++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
|
||||
@ -77,47 +123,125 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
unsigned first_pd_entry_in_global_pt;
|
||||
int i;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
|
||||
* entries. For aliasing ppgtt support we just steal them at the end for
|
||||
* now. */
|
||||
first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES;
|
||||
* now. */
|
||||
first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES;
|
||||
|
||||
ppgtt = malloc(sizeof(*ppgtt), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
if (!ppgtt)
|
||||
return ret;
|
||||
|
||||
ppgtt->dev = dev;
|
||||
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
|
||||
ppgtt->pt_pages = malloc(sizeof(vm_page_t) * ppgtt->num_pd_entries,
|
||||
DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
ppgtt->pt_pages = malloc(sizeof(struct page *)*ppgtt->num_pd_entries,
|
||||
DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
if (!ppgtt->pt_pages)
|
||||
goto err_ppgtt;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
ppgtt->pt_pages[i] = vm_page_alloc(NULL, 0,
|
||||
VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
|
||||
VM_ALLOC_ZERO);
|
||||
if (ppgtt->pt_pages[i] == NULL) {
|
||||
dev_priv->mm.aliasing_ppgtt = ppgtt;
|
||||
i915_gem_cleanup_aliasing_ppgtt(dev);
|
||||
return (-ENOMEM);
|
||||
}
|
||||
if (!ppgtt->pt_pages[i])
|
||||
goto err_pt_alloc;
|
||||
}
|
||||
|
||||
ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt.scratch_page_dma;
|
||||
if (dev_priv->mm.gtt->needs_dmar) {
|
||||
ppgtt->pt_dma_addr = malloc(sizeof(dma_addr_t)
|
||||
*ppgtt->num_pd_entries,
|
||||
DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
if (!ppgtt->pt_dma_addr)
|
||||
goto err_pt_alloc;
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU /* <- Added as a marker on FreeBSD. */
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
dma_addr_t pt_addr;
|
||||
|
||||
pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i],
|
||||
0, 4096,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
if (pci_dma_mapping_error(dev->pdev,
|
||||
pt_addr)) {
|
||||
ret = -EIO;
|
||||
goto err_pd_pin;
|
||||
|
||||
}
|
||||
ppgtt->pt_dma_addr[i] = pt_addr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma;
|
||||
|
||||
i915_ppgtt_clear_range(ppgtt, 0,
|
||||
ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
|
||||
|
||||
ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t);
|
||||
|
||||
i915_ppgtt_clear_range(ppgtt, 0, ppgtt->num_pd_entries *
|
||||
I915_PPGTT_PT_ENTRIES);
|
||||
ppgtt->pd_offset = (first_pd_entry_in_global_pt) * sizeof(uint32_t);
|
||||
dev_priv->mm.aliasing_ppgtt = ppgtt;
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU /* <- Added as a marker on FreeBSD. */
|
||||
err_pd_pin:
|
||||
if (ppgtt->pt_dma_addr) {
|
||||
for (i--; i >= 0; i--)
|
||||
pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
|
||||
4096, PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
#endif
|
||||
err_pt_alloc:
|
||||
free(ppgtt->pt_dma_addr, DRM_I915_GEM);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
if (ppgtt->pt_pages[i]) {
|
||||
vm_page_unwire(ppgtt->pt_pages[i], PQ_INACTIVE);
|
||||
vm_page_free(ppgtt->pt_pages[i]);
|
||||
}
|
||||
}
|
||||
free(ppgtt->pt_pages, DRM_I915_GEM);
|
||||
err_ppgtt:
|
||||
free(ppgtt, DRM_I915_GEM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
int i;
|
||||
|
||||
if (!ppgtt)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU /* <- Added as a marker on FreeBSD. */
|
||||
if (ppgtt->pt_dma_addr) {
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++)
|
||||
pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
|
||||
4096, PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
free(ppgtt->pt_dma_addr, DRM_I915_GEM);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
vm_page_unwire(ppgtt->pt_pages[i], PQ_INACTIVE);
|
||||
vm_page_free(ppgtt->pt_pages[i]);
|
||||
}
|
||||
free(ppgtt->pt_pages, DRM_I915_GEM);
|
||||
free(ppgtt, DRM_I915_GEM);
|
||||
}
|
||||
|
||||
static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt,
|
||||
vm_page_t *pages,
|
||||
unsigned first_entry,
|
||||
unsigned num_entries,
|
||||
vm_page_t *pages,
|
||||
uint32_t pte_flags)
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
uint32_t *pt_vaddr, pte;
|
||||
uint32_t *pt_vaddr;
|
||||
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
unsigned j, last_pte;
|
||||
@ -135,8 +259,8 @@ static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt,
|
||||
|
||||
for (j = first_pte; j < last_pte; j++) {
|
||||
page_addr = VM_PAGE_TO_PHYS(*pages);
|
||||
pte = GEN6_PTE_ADDR_ENCODE(page_addr);
|
||||
pt_vaddr[j] = pte | pte_flags;
|
||||
pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr,
|
||||
cache_level);
|
||||
|
||||
pages++;
|
||||
}
|
||||
@ -154,30 +278,11 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
uint32_t pte_flags;
|
||||
|
||||
dev = obj->base.dev;
|
||||
dev_priv = dev->dev_private;
|
||||
pte_flags = GEN6_PTE_VALID;
|
||||
|
||||
switch (cache_level) {
|
||||
case I915_CACHE_LLC_MLC:
|
||||
pte_flags |= GEN6_PTE_CACHE_LLC_MLC;
|
||||
break;
|
||||
case I915_CACHE_LLC:
|
||||
pte_flags |= GEN6_PTE_CACHE_LLC;
|
||||
break;
|
||||
case I915_CACHE_NONE:
|
||||
pte_flags |= GEN6_PTE_UNCACHED;
|
||||
break;
|
||||
default:
|
||||
panic("cache mode");
|
||||
}
|
||||
|
||||
i915_ppgtt_insert_pages(ppgtt, obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT, obj->pages, pte_flags);
|
||||
i915_ppgtt_insert_pages(ppgtt,
|
||||
obj->pages,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT,
|
||||
cache_level);
|
||||
}
|
||||
|
||||
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
@ -194,7 +299,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
||||
uint32_t pd_offset;
|
||||
struct intel_ring_buffer *ring;
|
||||
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
u_int first_pd_entry_in_global_pt;
|
||||
uint32_t __iomem *pd_addr;
|
||||
uint32_t pd_entry;
|
||||
int i;
|
||||
|
||||
@ -202,17 +307,22 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
||||
return;
|
||||
|
||||
|
||||
first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES;
|
||||
pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t);
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
vm_paddr_t pt_addr;
|
||||
|
||||
pt_addr = VM_PAGE_TO_PHYS(ppgtt->pt_pages[i]);
|
||||
if (dev_priv->mm.gtt->needs_dmar)
|
||||
pt_addr = ppgtt->pt_dma_addr[i];
|
||||
else
|
||||
pt_addr = VM_PAGE_TO_PHYS(ppgtt->pt_pages[i]);
|
||||
|
||||
pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
|
||||
pd_entry |= GEN6_PDE_VALID;
|
||||
|
||||
intel_gtt_write(first_pd_entry_in_global_pt + i, pd_entry);
|
||||
/* NOTE Linux<->FreeBSD: Arguments of writel() are reversed. */
|
||||
writel(pd_addr + i, pd_entry);
|
||||
}
|
||||
intel_gtt_read_pte(first_pd_entry_in_global_pt);
|
||||
readl(pd_addr);
|
||||
|
||||
pd_offset = ppgtt->pd_offset;
|
||||
pd_offset /= 64; /* in cachelines, */
|
||||
@ -250,12 +360,12 @@ static bool do_idling(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
bool ret = dev_priv->mm.interruptible;
|
||||
|
||||
if (dev_priv->mm.gtt.do_idle_maps) {
|
||||
if (unlikely(dev_priv->mm.gtt->do_idle_maps)) {
|
||||
dev_priv->mm.interruptible = false;
|
||||
if (i915_gpu_idle(dev_priv->dev)) {
|
||||
DRM_ERROR("Couldn't idle GPU\n");
|
||||
/* Wait a bit, in hopes it avoids the hang */
|
||||
DELAY(10);
|
||||
udelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,57 +374,35 @@ static bool do_idling(struct drm_i915_private *dev_priv)
|
||||
|
||||
static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
|
||||
{
|
||||
if (dev_priv->mm.gtt.do_idle_maps)
|
||||
if (unlikely(dev_priv->mm.gtt->do_idle_maps))
|
||||
dev_priv->mm.interruptible = interruptible;
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
|
||||
|
||||
static void i915_ggtt_clear_range(struct drm_device *dev,
|
||||
unsigned first_entry,
|
||||
unsigned num_entries)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
vm_page_t m;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
gtt_pte_t scratch_pte;
|
||||
gtt_pte_t __iomem *gtt_base = dev_priv->mm.gtt->gtt + first_entry;
|
||||
const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
|
||||
int i;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
if (ppgtt == NULL)
|
||||
if (INTEL_INFO(dev)->gen < 6) {
|
||||
intel_gtt_clear_range(first_entry, num_entries);
|
||||
return;
|
||||
dev_priv->mm.aliasing_ppgtt = NULL;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
m = ppgtt->pt_pages[i];
|
||||
if (m != NULL) {
|
||||
vm_page_unwire(m, PQ_INACTIVE);
|
||||
vm_page_free(m);
|
||||
}
|
||||
}
|
||||
free(ppgtt->pt_pages, DRM_I915_GEM);
|
||||
free(ppgtt, DRM_I915_GEM);
|
||||
}
|
||||
|
||||
if (WARN(num_entries > max_entries,
|
||||
"First entry = %d; Num entries = %d (max=%d)\n",
|
||||
first_entry, num_entries, max_entries))
|
||||
num_entries = max_entries;
|
||||
|
||||
static unsigned int
|
||||
cache_level_to_agp_type(struct drm_device *dev, enum i915_cache_level
|
||||
cache_level)
|
||||
{
|
||||
|
||||
switch (cache_level) {
|
||||
case I915_CACHE_LLC_MLC:
|
||||
if (INTEL_INFO(dev)->gen >= 6)
|
||||
return (AGP_USER_CACHED_MEMORY_LLC_MLC);
|
||||
/*
|
||||
* Older chipsets do not have this extra level of CPU
|
||||
* cacheing, so fallthrough and request the PTE simply
|
||||
* as cached.
|
||||
*/
|
||||
case I915_CACHE_LLC:
|
||||
return (AGP_USER_CACHED_MEMORY);
|
||||
|
||||
default:
|
||||
case I915_CACHE_NONE:
|
||||
return (AGP_USER_MEMORY);
|
||||
}
|
||||
scratch_pte = pte_encode(dev, dev_priv->mm.gtt->scratch_page_dma, I915_CACHE_LLC);
|
||||
for (i = 0; i < num_entries; i++)
|
||||
iowrite32(scratch_pte, >t_base[i]);
|
||||
readl(gtt_base);
|
||||
}
|
||||
|
||||
void i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
||||
@ -323,45 +411,99 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
/* First fill our portion of the GTT with scratch pages */
|
||||
intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
|
||||
i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE,
|
||||
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
|
||||
|
||||
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
|
||||
list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
|
||||
i915_gem_clflush_object(obj);
|
||||
i915_gem_gtt_bind_object(obj, obj->cache_level);
|
||||
}
|
||||
|
||||
intel_gtt_chipset_flush();
|
||||
i915_gem_chipset_flush(dev);
|
||||
}
|
||||
|
||||
int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
if (obj->has_dma_mapping)
|
||||
return 0;
|
||||
|
||||
#ifdef FREEBSD_WIP
|
||||
if (!dma_map_sg(&obj->base.dev->pdev->dev,
|
||||
obj->pages->sgl, obj->pages->nents,
|
||||
PCI_DMA_BIDIRECTIONAL))
|
||||
return -ENOSPC;
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binds an object into the global gtt with the specified cache level. The object
|
||||
* will be accessible to the GPU via commands whose operands reference offsets
|
||||
* within the global GTT as well as accessible by the GPU through the GMADR
|
||||
* mapped BAR (dev_priv->mm.gtt->gtt).
|
||||
*/
|
||||
static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level level)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
const int first_entry = obj->gtt_space->start >> PAGE_SHIFT;
|
||||
#if defined(INVARIANTS)
|
||||
const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry;
|
||||
#endif
|
||||
gtt_pte_t __iomem *gtt_entries = dev_priv->mm.gtt->gtt + first_entry;
|
||||
int i = 0;
|
||||
vm_paddr_t addr;
|
||||
|
||||
for (i = 0; i < obj->base.size >> PAGE_SHIFT; ++i) {
|
||||
addr = VM_PAGE_TO_PHYS(obj->pages[i]);
|
||||
iowrite32(pte_encode(dev, addr, level), >t_entries[i]);
|
||||
}
|
||||
|
||||
BUG_ON(i > max_entries);
|
||||
BUG_ON(i != obj->base.size / PAGE_SIZE);
|
||||
|
||||
/* XXX: This serves as a posting read to make sure that the PTE has
|
||||
* actually been updated. There is some concern that even though
|
||||
* registers and PTEs are within the same BAR that they are potentially
|
||||
* of NUMA access patterns. Therefore, even with the way we assume
|
||||
* hardware should work, we must keep this posting read for paranoia.
|
||||
*/
|
||||
if (i != 0)
|
||||
WARN_ON(readl(>t_entries[i-1]) != pte_encode(dev, addr, level));
|
||||
|
||||
/* This next bit makes the above posting read even more important. We
|
||||
* want to flush the TLBs only after we're certain all the PTE updates
|
||||
* have finished.
|
||||
*/
|
||||
I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
||||
POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
||||
}
|
||||
|
||||
void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
unsigned int agp_type;
|
||||
|
||||
dev = obj->base.dev;
|
||||
dev_priv = dev->dev_private;
|
||||
agp_type = cache_level_to_agp_type(dev, cache_level);
|
||||
|
||||
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT, obj->pages, agp_type);
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
if (INTEL_INFO(dev)->gen < 6) {
|
||||
unsigned int flags = (cache_level == I915_CACHE_NONE) ?
|
||||
AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
|
||||
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT,
|
||||
obj->pages,
|
||||
flags);
|
||||
} else {
|
||||
gen6_ggtt_bind_object(obj, cache_level);
|
||||
}
|
||||
|
||||
obj->has_global_gtt_mapping = 1;
|
||||
}
|
||||
|
||||
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
|
||||
intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
i915_ggtt_clear_range(obj->base.dev,
|
||||
obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
|
||||
obj->has_global_gtt_mapping = 0;
|
||||
}
|
||||
@ -374,35 +516,244 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
|
||||
|
||||
interruptible = do_idling(dev_priv);
|
||||
|
||||
#ifdef FREEBSD_WIP
|
||||
if (!obj->has_dma_mapping)
|
||||
dma_unmap_sg(&dev->pdev->dev,
|
||||
obj->pages->sgl, obj->pages->nents,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
undo_idling(dev_priv, interruptible);
|
||||
}
|
||||
|
||||
int i915_gem_init_global_gtt(struct drm_device *dev,
|
||||
static void i915_gtt_color_adjust(struct drm_mm_node *node,
|
||||
unsigned long color,
|
||||
unsigned long *start,
|
||||
unsigned long *end)
|
||||
{
|
||||
if (node->color != color)
|
||||
*start += 4096;
|
||||
|
||||
if (!list_empty(&node->node_list)) {
|
||||
node = list_entry(node->node_list.next,
|
||||
struct drm_mm_node,
|
||||
node_list);
|
||||
if (node->allocated && node->color != color)
|
||||
*end -= 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void i915_gem_init_global_gtt(struct drm_device *dev,
|
||||
unsigned long start,
|
||||
unsigned long mappable_end,
|
||||
unsigned long end)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
unsigned long mappable;
|
||||
int error;
|
||||
|
||||
mappable = min(end, mappable_end) - start;
|
||||
|
||||
/* Substract the guard page ... */
|
||||
drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
|
||||
if (!HAS_LLC(dev))
|
||||
dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
|
||||
|
||||
dev_priv->mm.gtt_start = start;
|
||||
dev_priv->mm.gtt_mappable_end = mappable_end;
|
||||
dev_priv->mm.gtt_end = end;
|
||||
dev_priv->mm.gtt_total = end - start;
|
||||
dev_priv->mm.mappable_gtt_total = mappable;
|
||||
dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
|
||||
|
||||
/* ... but ensure that we clear the entire range. */
|
||||
intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE);
|
||||
i915_ggtt_clear_range(dev, start / PAGE_SIZE, (end-start) / PAGE_SIZE);
|
||||
|
||||
device_printf(dev->dev,
|
||||
"taking over the fictitious range 0x%lx-0x%lx\n",
|
||||
dev->agp->base + start, dev->agp->base + start + mappable);
|
||||
error = -vm_phys_fictitious_reg_range(dev->agp->base + start,
|
||||
dev->agp->base + start + mappable, VM_MEMATTR_WRITE_COMBINING);
|
||||
return (error);
|
||||
dev_priv->mm.gtt_base_addr + start,
|
||||
dev_priv->mm.gtt_base_addr + start + dev_priv->mm.mappable_gtt_total);
|
||||
vm_phys_fictitious_reg_range(dev_priv->mm.gtt_base_addr + start,
|
||||
dev_priv->mm.gtt_base_addr + start + dev_priv->mm.mappable_gtt_total,
|
||||
VM_MEMATTR_WRITE_COMBINING);
|
||||
}
|
||||
|
||||
static int setup_scratch_page(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
vm_page_t page;
|
||||
dma_addr_t dma_addr;
|
||||
int tries = 0;
|
||||
int req = VM_ALLOC_ZERO | VM_ALLOC_NOOBJ;
|
||||
|
||||
retry:
|
||||
page = vm_page_alloc_contig(NULL, 0, req, 1, 0, 0xffffffff,
|
||||
PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE);
|
||||
if (page == NULL) {
|
||||
if (tries < 1) {
|
||||
if (!vm_page_reclaim_contig(req, 1, 0, 0xffffffff,
|
||||
PAGE_SIZE, 0))
|
||||
VM_WAIT;
|
||||
tries++;
|
||||
goto retry;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
if ((page->flags & PG_ZERO) == 0)
|
||||
pmap_zero_page(page);
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
if (pci_dma_mapping_error(dev->pdev, dma_addr))
|
||||
return -EINVAL;
|
||||
#else
|
||||
dma_addr = VM_PAGE_TO_PHYS(page);
|
||||
#endif
|
||||
dev_priv->mm.gtt->scratch_page = page;
|
||||
dev_priv->mm.gtt->scratch_page_dma = dma_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown_scratch_page(struct drm_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_INTEL_IOMMU /* <- Added as a marker on FreeBSD. */
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
pci_unmap_page(dev->pdev, dev_priv->mm.gtt->scratch_page_dma,
|
||||
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
|
||||
{
|
||||
snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT;
|
||||
snb_gmch_ctl &= SNB_GMCH_GGMS_MASK;
|
||||
return snb_gmch_ctl << 20;
|
||||
}
|
||||
|
||||
static inline unsigned int gen6_get_stolen_size(u16 snb_gmch_ctl)
|
||||
{
|
||||
snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT;
|
||||
snb_gmch_ctl &= SNB_GMCH_GMS_MASK;
|
||||
return snb_gmch_ctl << 25; /* 32 MB units */
|
||||
}
|
||||
|
||||
static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl)
|
||||
{
|
||||
static const int stolen_decoder[] = {
|
||||
0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352};
|
||||
snb_gmch_ctl >>= IVB_GMCH_GMS_SHIFT;
|
||||
snb_gmch_ctl &= IVB_GMCH_GMS_MASK;
|
||||
return stolen_decoder[snb_gmch_ctl] << 20;
|
||||
}
|
||||
|
||||
int i915_gem_gtt_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
vm_paddr_t gtt_bus_addr;
|
||||
u16 snb_gmch_ctl;
|
||||
int ret;
|
||||
|
||||
/* On modern platforms we need not worry ourself with the legacy
|
||||
* hostbridge query stuff. Skip it entirely
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen < 6) {
|
||||
#ifdef FREEBSD_WIP
|
||||
ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL);
|
||||
if (!ret) {
|
||||
DRM_ERROR("failed to set up gmch\n");
|
||||
return -EIO;
|
||||
}
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
dev_priv->mm.gtt = intel_gtt_get();
|
||||
if (!dev_priv->mm.gtt) {
|
||||
DRM_ERROR("Failed to initialize GTT\n");
|
||||
#ifdef FREEBSD_WIP
|
||||
intel_gmch_remove();
|
||||
#endif /* FREEBSD_WIP */
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_priv->mm.gtt = malloc(sizeof(*dev_priv->mm.gtt), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
if (!dev_priv->mm.gtt)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef FREEBSD_WIP
|
||||
if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40)))
|
||||
pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40));
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
dev_priv->mm.gtt->needs_dmar = 1;
|
||||
#endif
|
||||
|
||||
/* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */
|
||||
gtt_bus_addr = drm_get_resource_start(dev, 0) + (2<<20);
|
||||
dev_priv->mm.gtt->gma_bus_addr = drm_get_resource_start(dev, 2);
|
||||
|
||||
/* i9xx_setup */
|
||||
pci_read_config_word(dev->dev, SNB_GMCH_CTRL, &snb_gmch_ctl);
|
||||
dev_priv->mm.gtt->gtt_total_entries =
|
||||
gen6_get_total_gtt_size(snb_gmch_ctl) / sizeof(gtt_pte_t);
|
||||
if (INTEL_INFO(dev)->gen < 7)
|
||||
dev_priv->mm.gtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl);
|
||||
else
|
||||
dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl);
|
||||
|
||||
dev_priv->mm.gtt->gtt_mappable_entries = drm_get_resource_len(dev, 2) >> PAGE_SHIFT;
|
||||
/* 64/512MB is the current min/max we actually know of, but this is just a
|
||||
* coarse sanity check.
|
||||
*/
|
||||
if ((dev_priv->mm.gtt->gtt_mappable_entries >> 8) < 64 ||
|
||||
dev_priv->mm.gtt->gtt_mappable_entries > dev_priv->mm.gtt->gtt_total_entries) {
|
||||
DRM_ERROR("Unknown GMADR entries (%d)\n",
|
||||
dev_priv->mm.gtt->gtt_mappable_entries);
|
||||
ret = -ENXIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = setup_scratch_page(dev);
|
||||
if (ret) {
|
||||
DRM_ERROR("Scratch setup failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
dev_priv->mm.gtt->gtt = pmap_mapdev_attr(gtt_bus_addr,
|
||||
/* The size is used later by pmap_unmapdev. */
|
||||
dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t),
|
||||
VM_MEMATTR_WRITE_COMBINING);
|
||||
if (!dev_priv->mm.gtt->gtt) {
|
||||
DRM_ERROR("Failed to map the gtt page table\n");
|
||||
teardown_scratch_page(dev);
|
||||
ret = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */
|
||||
DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8);
|
||||
DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8);
|
||||
DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
free(dev_priv->mm.gtt, DRM_I915_GEM);
|
||||
#ifdef FREEBSD_WIP
|
||||
if (INTEL_INFO(dev)->gen < 6)
|
||||
intel_gmch_remove();
|
||||
#endif /* FREEBSD_WIP */
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i915_gem_gtt_fini(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
pmap_unmapdev((vm_offset_t)dev_priv->mm.gtt->gtt,
|
||||
dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t));
|
||||
teardown_scratch_page(dev);
|
||||
#ifdef FREEBSD_WIP
|
||||
if (INTEL_INFO(dev)->gen < 6)
|
||||
intel_gmch_remove();
|
||||
#endif /* FREEBSD_WIP */
|
||||
if (INTEL_INFO(dev)->gen >= 6)
|
||||
free(dev_priv->mm.gtt, DRM_I915_GEM);
|
||||
}
|
||||
|
@ -30,7 +30,6 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
|
||||
@ -46,56 +45,48 @@ __FBSDID("$FreeBSD$");
|
||||
* for is a boon.
|
||||
*/
|
||||
|
||||
#define PTE_ADDRESS_MASK 0xfffff000
|
||||
#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
|
||||
#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
|
||||
#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
|
||||
#define PTE_MAPPING_TYPE_CACHED (3 << 1)
|
||||
#define PTE_MAPPING_TYPE_MASK (3 << 1)
|
||||
#define PTE_VALID (1 << 0)
|
||||
|
||||
/**
|
||||
* i915_stolen_to_phys - take an offset into stolen memory and turn it into
|
||||
* a physical one
|
||||
* @dev: drm device
|
||||
* @offset: address to translate
|
||||
*
|
||||
* Some chip functions require allocations from stolen space and need the
|
||||
* physical address of the memory in question.
|
||||
*/
|
||||
static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset)
|
||||
static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
device_t pdev = dev_priv->bridge_dev;
|
||||
u32 base;
|
||||
|
||||
#if 0
|
||||
/* On the machines I have tested the Graphics Base of Stolen Memory
|
||||
* is unreliable, so compute the base by subtracting the stolen memory
|
||||
* from the Top of Low Usable DRAM which is where the BIOS places
|
||||
* the graphics stolen memory.
|
||||
* is unreliable, so on those compute the base by subtracting the
|
||||
* stolen memory from the Top of Low Usable DRAM which is where the
|
||||
* BIOS places the graphics stolen memory.
|
||||
*
|
||||
* On gen2, the layout is slightly different with the Graphics Segment
|
||||
* immediately following Top of Memory (or Top of Usable DRAM). Note
|
||||
* it appears that TOUD is only reported by 865g, so we just use the
|
||||
* top of memory as determined by the e820 probe.
|
||||
*
|
||||
* XXX gen2 requires an unavailable symbol and 945gm fails with
|
||||
* its value of TOLUD.
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
|
||||
/* top 32bits are reserved = 0 */
|
||||
pci_read_config_dword(pdev, 0xA4, &base);
|
||||
} else {
|
||||
/* XXX presume 8xx is the same as i915 */
|
||||
pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base);
|
||||
}
|
||||
#else
|
||||
if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
|
||||
u16 val;
|
||||
val = pci_read_config(pdev, 0xb0, 2);
|
||||
base = val >> 4 << 20;
|
||||
} else {
|
||||
base = 0;
|
||||
if (INTEL_INFO(dev)->gen >= 6) {
|
||||
/* Read Base Data of Stolen Memory Register (BDSM) directly.
|
||||
* Note that there is also a MCHBAR miror at 0x1080c0 or
|
||||
* we could use device 2:0x5c instead.
|
||||
*/
|
||||
pci_read_config_dword(dev->dev, 0xB0, &base);
|
||||
base &= ~4095; /* lower bits used for locking register */
|
||||
} else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
|
||||
/* Read Graphics Base of Stolen Memory directly */
|
||||
pci_read_config_dword(dev->dev, 0xA4, &base);
|
||||
#if 0
|
||||
} else if (IS_GEN3(dev)) {
|
||||
u8 val;
|
||||
val = pci_read_config(pdev, 0x9c, 1);
|
||||
/* Stolen is immediately below Top of Low Usable DRAM */
|
||||
pci_read_config_byte(pdev, 0x9c, &val);
|
||||
base = val >> 3 << 27;
|
||||
}
|
||||
base -= dev_priv->mm.gtt.stolen_size;
|
||||
base -= dev_priv->mm.gtt->stolen_size;
|
||||
} else {
|
||||
/* Stolen is immediately above Top of Memory */
|
||||
base = max_low_pfn_mapped << PAGE_SHIFT;
|
||||
#endif
|
||||
}
|
||||
|
||||
return base + offset;
|
||||
return base;
|
||||
}
|
||||
|
||||
static void i915_warn_stolen(struct drm_device *dev)
|
||||
@ -107,7 +98,7 @@ static void i915_warn_stolen(struct drm_device *dev)
|
||||
static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_mm_node *compressed_fb, *compressed_llb;
|
||||
struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb);
|
||||
unsigned long cfb_base;
|
||||
unsigned long ll_base = 0;
|
||||
|
||||
@ -120,7 +111,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
if (!compressed_fb)
|
||||
goto err;
|
||||
|
||||
cfb_base = i915_stolen_to_phys(dev, compressed_fb->start);
|
||||
cfb_base = dev_priv->mm.stolen_base + compressed_fb->start;
|
||||
if (!cfb_base)
|
||||
goto err_fb;
|
||||
|
||||
@ -133,7 +124,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
if (!compressed_llb)
|
||||
goto err_fb;
|
||||
|
||||
ll_base = i915_stolen_to_phys(dev, compressed_llb->start);
|
||||
ll_base = dev_priv->mm.stolen_base + compressed_llb->start;
|
||||
if (!ll_base)
|
||||
goto err_llb;
|
||||
}
|
||||
@ -152,7 +143,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
|
||||
cfb_base, ll_base, size >> 20);
|
||||
(long)cfb_base, (long)ll_base, size >> 20);
|
||||
return;
|
||||
|
||||
err_llb:
|
||||
@ -182,7 +173,14 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
|
||||
int i915_gem_init_stolen(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long prealloc_size = dev_priv->mm.gtt.stolen_size;
|
||||
unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size;
|
||||
|
||||
dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
|
||||
if (dev_priv->mm.stolen_base == 0)
|
||||
return 0;
|
||||
|
||||
DRM_DEBUG_KMS("found %d bytes of stolen memory at %08lx\n",
|
||||
dev_priv->mm.gtt->stolen_size, dev_priv->mm.stolen_base);
|
||||
|
||||
/* Basic memrange allocator for stolen space */
|
||||
drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
|
||||
|
@ -29,7 +29,6 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
|
||||
@ -95,7 +94,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||||
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 6) {
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||
} else if (INTEL_INFO(dev)->gen >= 6) {
|
||||
uint32_t dimm_c0, dimm_c1;
|
||||
dimm_c0 = I915_READ(MAD_DIMM_C0);
|
||||
dimm_c1 = I915_READ(MAD_DIMM_C1);
|
||||
@ -313,12 +315,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
||||
|
||||
if (!i915_tiling_ok(dev,
|
||||
args->stride, obj->base.size, args->tiling_mode)) {
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
drm_gem_object_unreference_unlocked(&obj->base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->pin_count) {
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
drm_gem_object_unreference_unlocked(&obj->base);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -483,7 +485,8 @@ i915_gem_object_do_bit_17_swizzle_page(struct drm_i915_gem_object *obj,
|
||||
return;
|
||||
|
||||
new_bit_17 = VM_PAGE_TO_PHYS(m) >> 17;
|
||||
if ((new_bit_17 & 0x1) != (test_bit(m->pindex, obj->bit_17) != 0)) {
|
||||
if ((new_bit_17 & 0x1) !=
|
||||
(test_bit(m->pindex, obj->bit_17) != 0)) {
|
||||
i915_gem_swizzle_page(m);
|
||||
vm_page_dirty(m);
|
||||
}
|
||||
@ -499,11 +502,12 @@ i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
|
||||
return;
|
||||
|
||||
for (i = 0; i < page_count; i++) {
|
||||
char new_bit_17 = VM_PAGE_TO_PHYS(obj->pages[i]) >> 17;
|
||||
vm_page_t page = obj->pages[i];
|
||||
char new_bit_17 = VM_PAGE_TO_PHYS(page) >> 17;
|
||||
if ((new_bit_17 & 0x1) !=
|
||||
(test_bit(i, obj->bit_17) != 0)) {
|
||||
i915_gem_swizzle_page(obj->pages[i]);
|
||||
vm_page_dirty(obj->pages[i]);
|
||||
i915_gem_swizzle_page(page);
|
||||
vm_page_dirty(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -516,14 +520,20 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
|
||||
|
||||
if (obj->bit_17 == NULL) {
|
||||
obj->bit_17 = malloc(BITS_TO_LONGS(page_count) *
|
||||
sizeof(long), DRM_I915_GEM, M_WAITOK);
|
||||
sizeof(long), DRM_I915_GEM, M_WAITOK);
|
||||
if (obj->bit_17 == NULL) {
|
||||
DRM_ERROR("Failed to allocate memory for bit 17 "
|
||||
"record\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXXKIB: review locking, atomics might be not needed there */
|
||||
for (i = 0; i < page_count; i++) {
|
||||
if (VM_PAGE_TO_PHYS(obj->pages[i]) & (1 << 17))
|
||||
set_bit(i, obj->bit_17);
|
||||
vm_page_t page = obj->pages[i];
|
||||
if (VM_PAGE_TO_PHYS(page) & (1 << 17))
|
||||
__set_bit(i, obj->bit_17);
|
||||
else
|
||||
clear_bit(i, obj->bit_17);
|
||||
__clear_bit(i, obj->bit_17);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -117,21 +117,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define GEN6_GRDOM_MEDIA (1 << 2)
|
||||
#define GEN6_GRDOM_BLT (1 << 3)
|
||||
|
||||
#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
|
||||
|
||||
#define GEN6_PDE_VALID (1 << 0)
|
||||
#define GEN6_PDE_LARGE_PAGE (2 << 0) /* use 32kb pages */
|
||||
/* gen6+ has bit 11-4 for physical addr bit 39-32 */
|
||||
#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
|
||||
|
||||
#define GEN6_PTE_VALID (1 << 0)
|
||||
#define GEN6_PTE_UNCACHED (1 << 1)
|
||||
#define GEN6_PTE_CACHE_LLC (2 << 1)
|
||||
#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
|
||||
#define GEN6_PTE_CACHE_BITS (3 << 1)
|
||||
#define GEN6_PTE_GFDT (1 << 3)
|
||||
#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
|
||||
|
||||
#define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228)
|
||||
#define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518)
|
||||
#define RING_PP_DIR_DCLV(ring) ((ring)->mmio_base+0x220)
|
||||
@ -740,10 +725,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
|
||||
#define GEN6_BSD_SLEEP_INDICATOR (1 << 3)
|
||||
#define GEN6_BSD_GO_INDICATOR (1 << 4)
|
||||
#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK (1 << 16)
|
||||
#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE (1 << 0)
|
||||
#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE 0
|
||||
#define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3)
|
||||
|
||||
#define GEN6_BSD_HWSTAM 0x12098
|
||||
#define GEN6_BSD_IMR 0x120a8
|
||||
@ -1682,21 +1663,19 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define PORT_HOTPLUG_STAT 0x61114
|
||||
/* HDMI/DP bits are gen4+ */
|
||||
#define HDMIB_HOTPLUG_INT_STATUS (1 << 29)
|
||||
#define DPB_HOTPLUG_INT_STATUS (1 << 29)
|
||||
#define HDMIC_HOTPLUG_INT_STATUS (1 << 28)
|
||||
#define DPC_HOTPLUG_INT_STATUS (1 << 28)
|
||||
#define HDMID_HOTPLUG_INT_STATUS (1 << 27)
|
||||
#define DPD_HOTPLUG_INT_STATUS (1 << 27)
|
||||
#define DPB_HOTPLUG_LIVE_STATUS (1 << 29)
|
||||
#define DPC_HOTPLUG_LIVE_STATUS (1 << 28)
|
||||
#define DPD_HOTPLUG_LIVE_STATUS (1 << 27)
|
||||
#define DPD_HOTPLUG_INT_STATUS (3 << 21)
|
||||
#define DPC_HOTPLUG_INT_STATUS (3 << 19)
|
||||
#define DPB_HOTPLUG_INT_STATUS (3 << 17)
|
||||
/* HDMI bits are shared with the DP bits */
|
||||
/*
|
||||
#define HDMIB_HOTPLUG_LIVE_STATUS (1 << 29)
|
||||
#define HDMIC_HOTPLUG_LIVE_STATUS (1 << 28)
|
||||
#define HDMID_HOTPLUG_LIVE_STATUS (1 << 27)
|
||||
#define HDMID_HOTPLUG_INT_STATUS (3 << 21)
|
||||
#define HDMIC_HOTPLUG_INT_STATUS (3 << 19)
|
||||
#define HDMIB_HOTPLUG_INT_STATUS (3 << 17)
|
||||
*/
|
||||
/* CRT/TV common between gen3+ */
|
||||
#define CRT_HOTPLUG_INT_STATUS (1 << 11)
|
||||
#define TV_HOTPLUG_INT_STATUS (1 << 10)
|
||||
@ -1704,8 +1683,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define CRT_HOTPLUG_MONITOR_COLOR (3 << 8)
|
||||
#define CRT_HOTPLUG_MONITOR_MONO (2 << 8)
|
||||
#define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
|
||||
#define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
|
||||
#define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
|
||||
/* SDVO is different across gen3/4 */
|
||||
#define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3)
|
||||
#define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2)
|
||||
@ -3307,12 +3284,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define DISPLAY_PORT_PLL_BIOS_1 0x46010
|
||||
#define DISPLAY_PORT_PLL_BIOS_2 0x46014
|
||||
|
||||
#define PCH_DSPCLK_GATE_D 0x42020
|
||||
# define DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9)
|
||||
# define DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8)
|
||||
# define DPFDUNIT_CLOCK_GATE_DISABLE (1 << 7)
|
||||
# define DPARBUNIT_CLOCK_GATE_DISABLE (1 << 5)
|
||||
|
||||
#define PCH_3DCGDIS0 0x46020
|
||||
# define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18)
|
||||
# define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1)
|
||||
@ -3486,15 +3457,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define ILK_HDCP_DISABLE (1<<25)
|
||||
#define ILK_eDP_A_DISABLE (1<<24)
|
||||
#define ILK_DESKTOP (1<<23)
|
||||
#define ILK_DSPCLK_GATE 0x42020
|
||||
#define IVB_VRHUNIT_CLK_GATE (1<<28)
|
||||
#define ILK_DPARB_CLK_GATE (1<<5)
|
||||
#define ILK_DPFD_CLK_GATE (1<<7)
|
||||
|
||||
/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
|
||||
#define ILK_CLK_FBC (1<<7)
|
||||
#define ILK_DPFC_DIS1 (1<<8)
|
||||
#define ILK_DPFC_DIS2 (1<<9)
|
||||
|
||||
#define ILK_DSPCLK_GATE_D 0x42020
|
||||
#define ILK_VRHUNIT_CLOCK_GATE_DISABLE (1 << 28)
|
||||
@ -3763,7 +3725,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
|
||||
#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
|
||||
|
||||
#define VLV_VIDEO_DIP_CTL_A 0x60220
|
||||
#define VLV_VIDEO_DIP_CTL_A 0x60200
|
||||
#define VLV_VIDEO_DIP_DATA_A 0x60208
|
||||
#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210
|
||||
|
||||
@ -3879,7 +3841,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define _TRANSA_CHICKEN2 0xf0064
|
||||
#define _TRANSB_CHICKEN2 0xf1064
|
||||
#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
|
||||
#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31)
|
||||
#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31)
|
||||
#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29)
|
||||
|
||||
@ -4030,33 +3991,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define FDI_PLL_CTL_1 0xfe000
|
||||
#define FDI_PLL_CTL_2 0xfe004
|
||||
|
||||
/* CRT */
|
||||
#define PCH_ADPA 0xe1100
|
||||
#define ADPA_TRANS_SELECT_MASK (1<<30)
|
||||
#define ADPA_TRANS_A_SELECT 0
|
||||
#define ADPA_TRANS_B_SELECT (1<<30)
|
||||
#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */
|
||||
#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24)
|
||||
#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24)
|
||||
#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
|
||||
#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24)
|
||||
#define ADPA_CRT_HOTPLUG_ENABLE (1<<23)
|
||||
#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22)
|
||||
#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22)
|
||||
#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21)
|
||||
#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21)
|
||||
#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20)
|
||||
#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20)
|
||||
#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18)
|
||||
#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18)
|
||||
#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18)
|
||||
#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18)
|
||||
#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17)
|
||||
#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17)
|
||||
#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
|
||||
|
||||
/* or SDVOB */
|
||||
#define VLV_HDMIB 0x61140
|
||||
#define HDMIB 0xe1140
|
||||
#define PORT_ENABLE (1 << 31)
|
||||
#define TRANSCODER(pipe) ((pipe) << 30)
|
||||
@ -4100,21 +4035,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define PIPEB_PP_OFF_DELAYS 0x6130c
|
||||
#define PIPEB_PP_DIVISOR 0x61310
|
||||
|
||||
#define BLC_PWM_CPU_CTL2 0x48250
|
||||
#define PWM_ENABLE (1 << 31)
|
||||
#define PWM_PIPE_A (0 << 29)
|
||||
#define PWM_PIPE_B (1 << 29)
|
||||
#define BLC_PWM_CPU_CTL 0x48254
|
||||
|
||||
#define BLC_PWM_PCH_CTL1 0xc8250
|
||||
#define PWM_PCH_ENABLE (1 << 31)
|
||||
#define PWM_POLARITY_ACTIVE_LOW (1 << 29)
|
||||
#define PWM_POLARITY_ACTIVE_HIGH (0 << 29)
|
||||
#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28)
|
||||
#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28)
|
||||
|
||||
#define BLC_PWM_PCH_CTL2 0xc8254
|
||||
|
||||
#define PCH_PP_STATUS 0xc7200
|
||||
#define PCH_PP_CONTROL 0xc7204
|
||||
#define PANEL_UNLOCK_REGS (0xabcd << 16)
|
||||
@ -4701,15 +4621,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define TRANS_CLK_SEL_DISABLED (0x0<<29)
|
||||
#define TRANS_CLK_SEL_PORT(x) ((x+1)<<29)
|
||||
|
||||
/* Pipe clock selection */
|
||||
#define PIPE_CLK_SEL_A 0x46140
|
||||
#define PIPE_CLK_SEL_B 0x46144
|
||||
#define PIPE_CLK_SEL(pipe) _PIPE(pipe, \
|
||||
PIPE_CLK_SEL_A, \
|
||||
PIPE_CLK_SEL_B)
|
||||
/* For each pipe, we need to select the corresponding port clock */
|
||||
#define PIPE_CLK_SEL_DISABLED (0x0<<29)
|
||||
#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29)
|
||||
#define _TRANSA_MSA_MISC 0x60410
|
||||
#define _TRANSB_MSA_MISC 0x61410
|
||||
#define TRANS_MSA_MISC(tran) _TRANSCODER(tran, _TRANSA_MSA_MISC, \
|
||||
|
File diff suppressed because it is too large
Load Diff
256
sys/dev/drm2/i915/intel_acpi.c
Normal file
256
sys/dev/drm2/i915/intel_acpi.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Intel ACPI functions
|
||||
*
|
||||
* _DSM related code stolen from nouveau_acpi.c.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <dev/acpica/acpivar.h>
|
||||
|
||||
#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
|
||||
|
||||
#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
|
||||
#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
|
||||
|
||||
static struct intel_dsm_priv {
|
||||
ACPI_HANDLE dhandle;
|
||||
} intel_dsm_priv;
|
||||
|
||||
static const u8 intel_dsm_guid[] = {
|
||||
0xd3, 0x73, 0xd8, 0x7e,
|
||||
0xd0, 0xc2,
|
||||
0x4f, 0x4e,
|
||||
0xa8, 0x54,
|
||||
0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
|
||||
};
|
||||
|
||||
static int intel_dsm(ACPI_HANDLE handle, int func, int arg)
|
||||
{
|
||||
ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
ACPI_OBJECT_LIST input;
|
||||
ACPI_OBJECT params[4];
|
||||
ACPI_OBJECT *obj;
|
||||
u32 result;
|
||||
int ret = 0;
|
||||
|
||||
input.Count = 4;
|
||||
input.Pointer = params;
|
||||
params[0].Type = ACPI_TYPE_BUFFER;
|
||||
params[0].Buffer.Length = sizeof(intel_dsm_guid);
|
||||
params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid);
|
||||
params[1].Type = ACPI_TYPE_INTEGER;
|
||||
params[1].Integer.Value = INTEL_DSM_REVISION_ID;
|
||||
params[2].Type = ACPI_TYPE_INTEGER;
|
||||
params[2].Integer.Value = func;
|
||||
params[3].Type = ACPI_TYPE_INTEGER;
|
||||
params[3].Integer.Value = arg;
|
||||
|
||||
ret = AcpiEvaluateObject(handle, "_DSM", &input, &output);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
obj = (ACPI_OBJECT *)output.Pointer;
|
||||
|
||||
result = 0;
|
||||
switch (obj->Type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
result = obj->Integer.Value;
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER:
|
||||
if (obj->Buffer.Length == 4) {
|
||||
result = (obj->Buffer.Pointer[0] |
|
||||
(obj->Buffer.Pointer[1] << 8) |
|
||||
(obj->Buffer.Pointer[2] << 16) |
|
||||
(obj->Buffer.Pointer[3] << 24));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (result == 0x80000002)
|
||||
ret = -ENODEV;
|
||||
|
||||
AcpiOsFree(output.Pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *intel_dsm_port_name(u8 id)
|
||||
{
|
||||
switch (id) {
|
||||
case 0:
|
||||
return "Reserved";
|
||||
case 1:
|
||||
return "Analog VGA";
|
||||
case 2:
|
||||
return "LVDS";
|
||||
case 3:
|
||||
return "Reserved";
|
||||
case 4:
|
||||
return "HDMI/DVI_B";
|
||||
case 5:
|
||||
return "HDMI/DVI_C";
|
||||
case 6:
|
||||
return "HDMI/DVI_D";
|
||||
case 7:
|
||||
return "DisplayPort_A";
|
||||
case 8:
|
||||
return "DisplayPort_B";
|
||||
case 9:
|
||||
return "DisplayPort_C";
|
||||
case 0xa:
|
||||
return "DisplayPort_D";
|
||||
case 0xb:
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
return "Reserved";
|
||||
case 0xe:
|
||||
return "WiDi";
|
||||
default:
|
||||
return "bad type";
|
||||
}
|
||||
}
|
||||
|
||||
static char *intel_dsm_mux_type(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case 0:
|
||||
return "unknown";
|
||||
case 1:
|
||||
return "No MUX, iGPU only";
|
||||
case 2:
|
||||
return "No MUX, dGPU only";
|
||||
case 3:
|
||||
return "MUXed between iGPU and dGPU";
|
||||
default:
|
||||
return "bad type";
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_dsm_platform_mux_info(void)
|
||||
{
|
||||
ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
ACPI_OBJECT_LIST input;
|
||||
ACPI_OBJECT params[4];
|
||||
ACPI_OBJECT *pkg;
|
||||
int i, ret;
|
||||
|
||||
input.Count = 4;
|
||||
input.Pointer = params;
|
||||
params[0].Type = ACPI_TYPE_BUFFER;
|
||||
params[0].Buffer.Length = sizeof(intel_dsm_guid);
|
||||
params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid);
|
||||
params[1].Type = ACPI_TYPE_INTEGER;
|
||||
params[1].Integer.Value = INTEL_DSM_REVISION_ID;
|
||||
params[2].Type = ACPI_TYPE_INTEGER;
|
||||
params[2].Integer.Value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
|
||||
params[3].Type = ACPI_TYPE_INTEGER;
|
||||
params[3].Integer.Value = 0;
|
||||
|
||||
ret = AcpiEvaluateObject(intel_dsm_priv.dhandle, "_DSM", &input,
|
||||
&output);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pkg = (ACPI_OBJECT *)output.Pointer;
|
||||
|
||||
if (pkg->Type == ACPI_TYPE_PACKAGE) {
|
||||
ACPI_OBJECT *connector_count = &pkg->Package.Elements[0];
|
||||
DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
|
||||
(unsigned long long)connector_count->Integer.Value);
|
||||
for (i = 1; i < pkg->Package.Count; i++) {
|
||||
ACPI_OBJECT *obj = &pkg->Package.Elements[i];
|
||||
ACPI_OBJECT *connector_id =
|
||||
&obj->Package.Elements[0];
|
||||
ACPI_OBJECT *info = &obj->Package.Elements[1];
|
||||
DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
|
||||
(unsigned long long)connector_id->Integer.Value);
|
||||
DRM_DEBUG_DRIVER(" port id: %s\n",
|
||||
intel_dsm_port_name(info->Buffer.Pointer[0]));
|
||||
DRM_DEBUG_DRIVER(" display mux info: %s\n",
|
||||
intel_dsm_mux_type(info->Buffer.Pointer[1]));
|
||||
DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
|
||||
intel_dsm_mux_type(info->Buffer.Pointer[2]));
|
||||
DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
|
||||
intel_dsm_mux_type(info->Buffer.Pointer[3]));
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
AcpiOsFree(output.Pointer);
|
||||
}
|
||||
|
||||
static bool intel_dsm_pci_probe(device_t dev)
|
||||
{
|
||||
ACPI_HANDLE dhandle, intel_handle;
|
||||
ACPI_STATUS status;
|
||||
int ret;
|
||||
|
||||
dhandle = acpi_get_handle(dev);
|
||||
if (!dhandle)
|
||||
return false;
|
||||
|
||||
status = AcpiGetHandle(dhandle, "_DSM", &intel_handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
DRM_DEBUG_KMS("no _DSM method for intel device\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
|
||||
if (ret < 0) {
|
||||
DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
intel_dsm_priv.dhandle = dhandle;
|
||||
|
||||
intel_dsm_platform_mux_info();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intel_dsm_detect(void)
|
||||
{
|
||||
char acpi_method_name[255] = { 0 };
|
||||
ACPI_BUFFER buffer = {sizeof(acpi_method_name), acpi_method_name};
|
||||
device_t dev = NULL;
|
||||
bool has_dsm = false;
|
||||
int vga_count = 0;
|
||||
|
||||
#ifdef FREEBSD_WIP
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
#endif /* FREEBSD_WIP */
|
||||
if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) {
|
||||
vga_count++;
|
||||
has_dsm |= intel_dsm_pci_probe(dev);
|
||||
}
|
||||
|
||||
if (vga_count == 2 && has_dsm) {
|
||||
AcpiGetName(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
|
||||
DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
|
||||
acpi_method_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void intel_register_dsm_handler(void)
|
||||
{
|
||||
if (!intel_dsm_detect())
|
||||
return;
|
||||
}
|
||||
|
||||
void intel_unregister_dsm_handler(void)
|
||||
{
|
||||
}
|
@ -23,10 +23,12 @@
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_dp_helper.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
@ -169,8 +171,7 @@ get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
|
||||
int dvo_timing_offset =
|
||||
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
|
||||
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
|
||||
const char *entry = (const char *)lvds_lfp_data->data +
|
||||
lfp_data_size * index;
|
||||
const char *entry = (const char *)lvds_lfp_data->data + lfp_data_size * index;
|
||||
|
||||
return (const struct lvds_dvo_timing *)(entry + dvo_timing_offset);
|
||||
}
|
||||
@ -188,7 +189,7 @@ get_lvds_fp_timing(const struct bdb_header *bdb,
|
||||
u16 data_size = ((const u16 *)data)[-1]; /* stored in header */
|
||||
size_t ofs;
|
||||
|
||||
if (index >= DRM_ARRAY_SIZE(ptrs->ptr))
|
||||
if (index >= ARRAY_SIZE(ptrs->ptr))
|
||||
return NULL;
|
||||
ofs = ptrs->ptr[index].fp_timing_offset;
|
||||
if (ofs < data_ofs ||
|
||||
@ -234,8 +235,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
lvds_lfp_data_ptrs,
|
||||
lvds_options->panel_type);
|
||||
|
||||
panel_fixed_mode = malloc(sizeof(*panel_fixed_mode), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
panel_fixed_mode = malloc(sizeof(*panel_fixed_mode), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!panel_fixed_mode)
|
||||
return;
|
||||
|
||||
fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
|
||||
|
||||
@ -263,9 +265,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
|
||||
dev_priv->lvds_downclock_avail = 1;
|
||||
dev_priv->lvds_downclock = downclock * 10;
|
||||
DRM_DEBUG("LVDS downclock is found in VBT. "
|
||||
DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
|
||||
"Normal Clock %dKHz, downclock %dKHz\n",
|
||||
panel_fixed_mode->clock, 10 * downclock);
|
||||
panel_fixed_mode->clock, 10*downclock);
|
||||
}
|
||||
|
||||
fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data,
|
||||
@ -311,8 +313,9 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
|
||||
if (!dvo_timing)
|
||||
return;
|
||||
|
||||
panel_fixed_mode = malloc(sizeof(*panel_fixed_mode), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
panel_fixed_mode = malloc(sizeof(*panel_fixed_mode), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!panel_fixed_mode)
|
||||
return;
|
||||
|
||||
fill_detail_timing_data(panel_fixed_mode, dvo_timing + index);
|
||||
|
||||
@ -351,12 +354,14 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
||||
dev_priv->lvds_ssc_freq =
|
||||
intel_bios_ssc_frequency(dev, general->ssc_freq);
|
||||
dev_priv->display_clock_mode = general->display_clock_mode;
|
||||
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n",
|
||||
dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
|
||||
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n",
|
||||
dev_priv->int_tv_support,
|
||||
dev_priv->int_crt_support,
|
||||
dev_priv->lvds_use_ssc,
|
||||
dev_priv->lvds_ssc_freq,
|
||||
dev_priv->display_clock_mode);
|
||||
dev_priv->display_clock_mode,
|
||||
dev_priv->fdi_rx_polarity_inverted);
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,12 +504,8 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
|
||||
edp = find_section(bdb, BDB_EDP);
|
||||
if (!edp) {
|
||||
if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
|
||||
DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
|
||||
"supported, assume %dbpp panel color "
|
||||
"depth.\n",
|
||||
dev_priv->edp.bpp);
|
||||
}
|
||||
if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support)
|
||||
DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,8 +614,11 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
|
||||
DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
|
||||
return;
|
||||
}
|
||||
dev_priv->child_dev = malloc(sizeof(*p_child) * count, DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
dev_priv->child_dev = malloc(count * sizeof(*p_child), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!dev_priv->child_dev) {
|
||||
DRM_DEBUG_KMS("No memory space for child device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev_priv->child_dev_num = count;
|
||||
count = 0;
|
||||
@ -654,12 +658,9 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
|
||||
dev_priv->lvds_use_ssc = 1;
|
||||
dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
|
||||
DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
|
||||
|
||||
/* eDP data */
|
||||
dev_priv->edp.bpp = 18;
|
||||
}
|
||||
|
||||
static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
|
||||
static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_DEBUG_KMS("Falling back to manually reading VBT from "
|
||||
"VBIOS ROM for %s\n",
|
||||
@ -688,12 +689,13 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = {
|
||||
*
|
||||
* Returns 0 on success, nonzero on failure.
|
||||
*/
|
||||
bool
|
||||
int
|
||||
intel_parse_bios(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
device_t vga_dev = device_get_parent(dev->dev);;
|
||||
struct bdb_header *bdb = NULL;
|
||||
u8 *bios;
|
||||
u8 __iomem *bios = NULL;
|
||||
|
||||
init_vbt_defaults(dev_priv);
|
||||
|
||||
@ -707,20 +709,13 @@ intel_parse_bios(struct drm_device *dev)
|
||||
} else
|
||||
dev_priv->opregion.vbt = NULL;
|
||||
}
|
||||
bios = NULL;
|
||||
|
||||
#if 1
|
||||
if (bdb == NULL) {
|
||||
KIB_NOTYET();
|
||||
return (-1);
|
||||
}
|
||||
#else
|
||||
if (bdb == NULL) {
|
||||
struct vbt_header *vbt = NULL;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
bios = pci_map_rom(pdev, &size);
|
||||
bios = vga_pci_map_bios(vga_dev, &size);
|
||||
if (!bios)
|
||||
return -1;
|
||||
|
||||
@ -734,13 +729,12 @@ intel_parse_bios(struct drm_device *dev)
|
||||
|
||||
if (!vbt) {
|
||||
DRM_DEBUG_DRIVER("VBT signature missing\n");
|
||||
pci_unmap_rom(pdev, bios);
|
||||
vga_pci_unmap_bios(vga_dev, bios);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Grab useful general definitions */
|
||||
parse_general_features(dev_priv, bdb);
|
||||
@ -752,14 +746,31 @@ intel_parse_bios(struct drm_device *dev)
|
||||
parse_driver_features(dev_priv, bdb);
|
||||
parse_edp(dev_priv, bdb);
|
||||
|
||||
#if 0
|
||||
if (bios)
|
||||
pci_unmap_rom(pdev, bios);
|
||||
#endif
|
||||
vga_pci_unmap_bios(vga_dev, bios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE Linux<->FreeBSD:
|
||||
* Apparently, Linux doesn't free those pointers.
|
||||
* TODO: Report that upstream.
|
||||
*/
|
||||
void
|
||||
intel_free_parsed_bios_data(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
free(dev_priv->lfp_lvds_vbt_mode, DRM_MEM_KMS);
|
||||
free(dev_priv->sdvo_lvds_vbt_mode, DRM_MEM_KMS);
|
||||
free(dev_priv->child_dev, DRM_MEM_KMS);
|
||||
|
||||
dev_priv->lfp_lvds_vbt_mode = NULL;
|
||||
dev_priv->sdvo_lvds_vbt_mode = NULL;
|
||||
dev_priv->child_dev = NULL;
|
||||
}
|
||||
|
||||
/* Ensure that vital registers have been initialised, even if the BIOS
|
||||
* is absent or just failing to do its job.
|
||||
*/
|
||||
@ -768,7 +779,8 @@ void intel_setup_bios(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Set the Panel Power On/Off timings if uninitialized. */
|
||||
if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) {
|
||||
if (!HAS_PCH_SPLIT(dev) &&
|
||||
I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) {
|
||||
/* Set T2 to 40ms and T5 to 200ms */
|
||||
I915_WRITE(PP_ON_DELAYS, 0x019007d0);
|
||||
|
||||
|
@ -128,7 +128,9 @@ struct bdb_general_features {
|
||||
/* bits 3 */
|
||||
u8 disable_smooth_vision:1;
|
||||
u8 single_dvi:1;
|
||||
u8 rsvd9:6; /* finish byte */
|
||||
u8 rsvd9:1;
|
||||
u8 fdi_rx_polarity_inverted:1;
|
||||
u8 rsvd10:4; /* finish byte */
|
||||
|
||||
/* bits 4 */
|
||||
u8 legacy_monitor_detect;
|
||||
@ -477,7 +479,8 @@ struct bdb_edp {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
void intel_setup_bios(struct drm_device *dev);
|
||||
bool intel_parse_bios(struct drm_device *dev);
|
||||
int intel_parse_bios(struct drm_device *dev);
|
||||
void intel_free_parsed_bios_data(struct drm_device *dev);
|
||||
|
||||
/*
|
||||
* Driver<->VBIOS interaction occurs through scratch bits in
|
||||
|
@ -28,13 +28,12 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_crtc_helper.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
/* Here's the desired hotplug mode */
|
||||
#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \
|
||||
@ -46,7 +45,11 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
struct intel_crt {
|
||||
struct intel_encoder base;
|
||||
/* DPMS state is stored in the connector, which we need in the
|
||||
* encoder's enable/disable callbacks */
|
||||
struct intel_connector *connector;
|
||||
bool force_hotplug_required;
|
||||
u32 adpa_reg;
|
||||
};
|
||||
|
||||
static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
|
||||
@ -55,36 +58,42 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
|
||||
struct intel_crt, base);
|
||||
}
|
||||
|
||||
static void pch_crt_dpms(struct drm_encoder *encoder, int mode)
|
||||
static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 temp;
|
||||
|
||||
temp = I915_READ(PCH_ADPA);
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
temp |= ADPA_DAC_ENABLE;
|
||||
break;
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
/* Just leave port enable cleared */
|
||||
break;
|
||||
}
|
||||
|
||||
I915_WRITE(PCH_ADPA, temp);
|
||||
return container_of(encoder, struct intel_crt, base);
|
||||
}
|
||||
|
||||
static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
|
||||
static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
|
||||
enum pipe *pipe)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crt *crt = intel_encoder_to_crt(encoder);
|
||||
u32 tmp;
|
||||
|
||||
tmp = I915_READ(crt->adpa_reg);
|
||||
|
||||
if (!(tmp & ADPA_DAC_ENABLE))
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
*pipe = PORT_TO_PIPE_CPT(tmp);
|
||||
else
|
||||
*pipe = PORT_TO_PIPE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Note: The caller is required to filter out dpms modes not supported by the
|
||||
* platform. */
|
||||
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crt *crt = intel_encoder_to_crt(encoder);
|
||||
u32 temp;
|
||||
|
||||
temp = I915_READ(ADPA);
|
||||
temp = I915_READ(crt->adpa_reg);
|
||||
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
@ -103,7 +112,64 @@ static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
|
||||
break;
|
||||
}
|
||||
|
||||
I915_WRITE(ADPA, temp);
|
||||
I915_WRITE(crt->adpa_reg, temp);
|
||||
}
|
||||
|
||||
static void intel_disable_crt(struct intel_encoder *encoder)
|
||||
{
|
||||
intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static void intel_enable_crt(struct intel_encoder *encoder)
|
||||
{
|
||||
struct intel_crt *crt = intel_encoder_to_crt(encoder);
|
||||
|
||||
intel_crt_set_dpms(encoder, crt->connector->base.dpms);
|
||||
}
|
||||
|
||||
|
||||
static void intel_crt_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_encoder *encoder = intel_attached_encoder(connector);
|
||||
struct drm_crtc *crtc;
|
||||
int old_dpms;
|
||||
|
||||
/* PCH platforms and VLV only support on/off. */
|
||||
if (INTEL_INFO(dev)->gen >= 5 && mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (mode == connector->dpms)
|
||||
return;
|
||||
|
||||
old_dpms = connector->dpms;
|
||||
connector->dpms = mode;
|
||||
|
||||
/* Only need to change hw state when actually enabled */
|
||||
crtc = encoder->base.crtc;
|
||||
if (!crtc) {
|
||||
encoder->connectors_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need the pipe to run for anything but OFF. */
|
||||
if (mode == DRM_MODE_DPMS_OFF)
|
||||
encoder->connectors_active = false;
|
||||
else
|
||||
encoder->connectors_active = true;
|
||||
|
||||
if (mode < old_dpms) {
|
||||
/* From off to on, enable the pipe first. */
|
||||
intel_crtc_update_dpms(crtc);
|
||||
|
||||
intel_crt_set_dpms(encoder, mode);
|
||||
} else {
|
||||
intel_crt_set_dpms(encoder, mode);
|
||||
|
||||
intel_crtc_update_dpms(crtc);
|
||||
}
|
||||
|
||||
intel_modeset_check_state(connector->dev);
|
||||
}
|
||||
|
||||
static int intel_crt_mode_valid(struct drm_connector *connector,
|
||||
@ -125,6 +191,11 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
|
||||
if (mode->clock > max_clock)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
/* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */
|
||||
if (HAS_PCH_LPT(dev) &&
|
||||
(ironlake_get_lanes_required(mode->clock, 270000, 24) > 2))
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
@ -142,37 +213,26 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
|
||||
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crt *crt =
|
||||
intel_encoder_to_crt(to_intel_encoder(encoder));
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int dpll_md_reg;
|
||||
u32 adpa, dpll_md;
|
||||
u32 adpa_reg;
|
||||
|
||||
dpll_md_reg = DPLL_MD(intel_crtc->pipe);
|
||||
u32 adpa;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
adpa_reg = PCH_ADPA;
|
||||
adpa = ADPA_HOTPLUG_BITS;
|
||||
else
|
||||
adpa_reg = ADPA;
|
||||
adpa = 0;
|
||||
|
||||
/*
|
||||
* Disable separate mode multiplier used when cloning SDVO to CRT
|
||||
* XXX this needs to be adjusted when we really are cloning
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
dpll_md = I915_READ(dpll_md_reg);
|
||||
I915_WRITE(dpll_md_reg,
|
||||
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
|
||||
}
|
||||
|
||||
adpa = ADPA_HOTPLUG_BITS;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
/* For CPT allow 3 pipe config, for others just use A or B */
|
||||
if (HAS_PCH_CPT(dev))
|
||||
if (HAS_PCH_LPT(dev))
|
||||
; /* Those bits don't exist here */
|
||||
else if (HAS_PCH_CPT(dev))
|
||||
adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
|
||||
else if (intel_crtc->pipe == 0)
|
||||
adpa |= ADPA_PIPE_A_SELECT;
|
||||
@ -182,7 +242,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
|
||||
|
||||
I915_WRITE(adpa_reg, adpa);
|
||||
I915_WRITE(crt->adpa_reg, adpa);
|
||||
}
|
||||
|
||||
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
@ -209,10 +269,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
1000, 1, "915crt"))
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n");
|
||||
if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
1000))
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
|
||||
|
||||
if (turn_off_dac) {
|
||||
I915_WRITE(PCH_ADPA, save_adpa);
|
||||
@ -231,6 +290,42 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 adpa;
|
||||
bool ret;
|
||||
u32 save_adpa;
|
||||
|
||||
save_adpa = adpa = I915_READ(ADPA);
|
||||
DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
|
||||
|
||||
adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
|
||||
|
||||
I915_WRITE(ADPA, adpa);
|
||||
|
||||
if (wait_for((I915_READ(ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
1000)) {
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
|
||||
I915_WRITE(ADPA, save_adpa);
|
||||
}
|
||||
|
||||
/* Check the status to see if both blue and green are on now */
|
||||
adpa = I915_READ(ADPA);
|
||||
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
|
||||
ret = true;
|
||||
else
|
||||
ret = false;
|
||||
|
||||
DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
|
||||
|
||||
/* FIXME: debug force function and remove */
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
|
||||
*
|
||||
@ -250,6 +345,9 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
return intel_ironlake_crt_detect_hotplug(connector);
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
return valleyview_crt_detect_hotplug(connector);
|
||||
|
||||
/*
|
||||
* On 4 series desktop, CRT detect sequence need to be done twice
|
||||
* to get a reliable result.
|
||||
@ -266,9 +364,9 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
|
||||
/* turn on the FORCE_DETECT */
|
||||
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
|
||||
/* wait for FORCE_DETECT to go off */
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
|
||||
1000, 1, "915cr2"))
|
||||
if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
|
||||
CRT_HOTPLUG_FORCE_DETECT) == 0,
|
||||
1000))
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
|
||||
}
|
||||
|
||||
@ -285,42 +383,72 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct edid *intel_crt_get_edid(struct drm_connector *connector,
|
||||
device_t i2c)
|
||||
{
|
||||
struct edid *edid;
|
||||
|
||||
edid = drm_get_edid(connector, i2c);
|
||||
|
||||
if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
|
||||
DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n");
|
||||
intel_gmbus_force_bit(i2c, true);
|
||||
edid = drm_get_edid(connector, i2c);
|
||||
intel_gmbus_force_bit(i2c, false);
|
||||
}
|
||||
|
||||
return edid;
|
||||
}
|
||||
|
||||
/* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */
|
||||
static int intel_crt_ddc_get_modes(struct drm_connector *connector,
|
||||
device_t adapter)
|
||||
{
|
||||
struct edid *edid;
|
||||
int ret;
|
||||
|
||||
edid = intel_crt_get_edid(connector, adapter);
|
||||
if (!edid)
|
||||
return 0;
|
||||
|
||||
ret = intel_connector_update_modes(connector, edid);
|
||||
free(edid, DRM_MEM_KMS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool intel_crt_detect_ddc(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
|
||||
struct edid *edid;
|
||||
device_t i2c;
|
||||
|
||||
/* CRT should always be at 0, but check anyway */
|
||||
if (crt->base.type != INTEL_OUTPUT_ANALOG)
|
||||
return false;
|
||||
BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
|
||||
|
||||
if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
|
||||
struct edid *edid;
|
||||
bool is_digital = false;
|
||||
device_t iic;
|
||||
i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
|
||||
edid = intel_crt_get_edid(connector, i2c);
|
||||
|
||||
if (edid) {
|
||||
bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
|
||||
|
||||
iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
|
||||
edid = drm_get_edid(connector, iic);
|
||||
/*
|
||||
* This may be a DVI-I connector with a shared DDC
|
||||
* link between analog and digital outputs, so we
|
||||
* have to check the EDID input spec of the attached device.
|
||||
*
|
||||
* On the other hand, what should we do if it is a broken EDID?
|
||||
*/
|
||||
if (edid != NULL) {
|
||||
is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
|
||||
free(edid, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
if (!is_digital) {
|
||||
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
|
||||
return true;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
|
||||
} else {
|
||||
DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
|
||||
}
|
||||
|
||||
free(edid, DRM_MEM_KMS);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -453,30 +581,37 @@ intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
struct intel_load_detect_pipe tmp;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
/* We can not rely on the HPD pin always being correctly wired
|
||||
* up, for example many KVM do not pass it through, and so
|
||||
* only trust an assertion that the monitor is connected.
|
||||
*/
|
||||
if (intel_crt_detect_hotplug(connector)) {
|
||||
DRM_DEBUG_KMS("CRT detected via hotplug\n");
|
||||
return connector_status_connected;
|
||||
} else {
|
||||
} else
|
||||
DRM_DEBUG_KMS("CRT not detected via hotplug\n");
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
if (intel_crt_detect_ddc(connector))
|
||||
return connector_status_connected;
|
||||
|
||||
/* Load detection is broken on HPD capable machines. Whoever wants a
|
||||
* broken monitor (without edid) to work behind a broken kvm (that fails
|
||||
* to have the right resistors for HP detection) needs to fix this up.
|
||||
* For now just bail out. */
|
||||
if (I915_HAS_HOTPLUG(dev))
|
||||
return connector_status_disconnected;
|
||||
|
||||
if (!force)
|
||||
return connector->status;
|
||||
|
||||
/* for pre-945g platforms use load detect */
|
||||
if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
|
||||
&tmp)) {
|
||||
if (intel_get_load_detect_pipe(connector, NULL, &tmp)) {
|
||||
if (intel_crt_detect_ddc(connector))
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = intel_crt_load_detect(crt);
|
||||
intel_release_load_detect_pipe(&crt->base, connector,
|
||||
&tmp);
|
||||
intel_release_load_detect_pipe(connector, &tmp);
|
||||
} else
|
||||
status = connector_status_unknown;
|
||||
|
||||
@ -485,10 +620,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
|
||||
static void intel_crt_destroy(struct drm_connector *connector)
|
||||
{
|
||||
|
||||
#if 0
|
||||
drm_sysfs_connector_remove(connector);
|
||||
#endif
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
@ -501,13 +632,13 @@ static int intel_crt_get_modes(struct drm_connector *connector)
|
||||
device_t i2c;
|
||||
|
||||
i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
|
||||
ret = intel_ddc_get_modes(connector, i2c);
|
||||
ret = intel_crt_ddc_get_modes(connector, i2c);
|
||||
if (ret || !IS_G4X(dev))
|
||||
return ret;
|
||||
|
||||
/* Try to probe digital port for output in DVI-I -> VGA mode. */
|
||||
i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
|
||||
return intel_ddc_get_modes(connector, i2c);
|
||||
return intel_crt_ddc_get_modes(connector, i2c);
|
||||
}
|
||||
|
||||
static int intel_crt_set_property(struct drm_connector *connector,
|
||||
@ -520,36 +651,37 @@ static int intel_crt_set_property(struct drm_connector *connector,
|
||||
static void intel_crt_reset(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 adpa;
|
||||
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
||||
adpa |= ADPA_HOTPLUG_BITS;
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
POSTING_READ(PCH_ADPA);
|
||||
|
||||
DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
|
||||
crt->force_hotplug_required = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines for controlling stuff on the analog port
|
||||
*/
|
||||
|
||||
static const struct drm_encoder_helper_funcs pch_encoder_funcs = {
|
||||
static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
|
||||
.mode_fixup = intel_crt_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.commit = intel_encoder_commit,
|
||||
.mode_set = intel_crt_mode_set,
|
||||
.dpms = pch_crt_dpms,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
|
||||
.mode_fixup = intel_crt_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.commit = intel_encoder_commit,
|
||||
.mode_set = intel_crt_mode_set,
|
||||
.dpms = gmch_crt_dpms,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_crt_connector_funcs = {
|
||||
.reset = intel_crt_reset,
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = intel_crt_dpms,
|
||||
.detect = intel_crt_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = intel_crt_destroy,
|
||||
@ -566,7 +698,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
|
||||
.destroy = intel_encoder_destroy,
|
||||
};
|
||||
|
||||
static int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
|
||||
static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_INFO("Skipping CRT initialization for %s\n", id->ident);
|
||||
return 1;
|
||||
@ -590,17 +722,23 @@ void intel_crt_init(struct drm_device *dev)
|
||||
struct intel_crt *crt;
|
||||
struct intel_connector *intel_connector;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
const struct drm_encoder_helper_funcs *encoder_helper_funcs;
|
||||
|
||||
/* Skip machines without VGA that falsely report hotplug events */
|
||||
if (dmi_check_system(intel_no_crt))
|
||||
return;
|
||||
|
||||
crt = malloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!crt)
|
||||
return;
|
||||
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_connector) {
|
||||
free(crt, DRM_MEM_KMS);
|
||||
return;
|
||||
}
|
||||
|
||||
connector = &intel_connector->base;
|
||||
crt->connector = intel_connector;
|
||||
drm_connector_init(dev, &intel_connector->base,
|
||||
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
|
||||
|
||||
@ -610,13 +748,11 @@ void intel_crt_init(struct drm_device *dev)
|
||||
intel_connector_attach_encoder(intel_connector, &crt->base);
|
||||
|
||||
crt->base.type = INTEL_OUTPUT_ANALOG;
|
||||
crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
|
||||
1 << INTEL_ANALOG_CLONE_BIT |
|
||||
1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
if (IS_HASWELL(dev))
|
||||
crt->base.cloneable = true;
|
||||
if (IS_I830(dev))
|
||||
crt->base.crtc_mask = (1 << 0);
|
||||
else
|
||||
crt->base.crtc_mask = (1 << 0) | (1 << 1);
|
||||
crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
connector->interlace_allowed = 0;
|
||||
@ -625,17 +761,23 @@ void intel_crt_init(struct drm_device *dev)
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
encoder_helper_funcs = &pch_encoder_funcs;
|
||||
crt->adpa_reg = PCH_ADPA;
|
||||
else if (IS_VALLEYVIEW(dev))
|
||||
crt->adpa_reg = VLV_ADPA;
|
||||
else
|
||||
encoder_helper_funcs = &gmch_encoder_funcs;
|
||||
crt->adpa_reg = ADPA;
|
||||
|
||||
drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
|
||||
crt->base.disable = intel_disable_crt;
|
||||
crt->base.enable = intel_enable_crt;
|
||||
if (IS_HASWELL(dev))
|
||||
crt->base.get_hw_state = intel_ddi_get_hw_state;
|
||||
else
|
||||
crt->base.get_hw_state = intel_crt_get_hw_state;
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
|
||||
drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
|
||||
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
|
||||
|
||||
#if 0
|
||||
drm_sysfs_connector_add(connector);
|
||||
#endif
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev))
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
else
|
||||
@ -645,18 +787,18 @@ void intel_crt_init(struct drm_device *dev)
|
||||
* Configure the automatic hotplug detection stuff
|
||||
*/
|
||||
crt->force_hotplug_required = 0;
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 adpa;
|
||||
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
||||
adpa |= ADPA_HOTPLUG_BITS;
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
POSTING_READ(PCH_ADPA);
|
||||
|
||||
DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
|
||||
crt->force_hotplug_required = 1;
|
||||
}
|
||||
|
||||
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
|
||||
|
||||
/*
|
||||
* TODO: find a proper way to discover whether we need to set the the
|
||||
* polarity and link reversal bits or not, instead of relying on the
|
||||
* BIOS.
|
||||
*/
|
||||
if (HAS_PCH_LPT(dev)) {
|
||||
u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
|
||||
FDI_RX_LINK_REVERSAL_OVERRIDE;
|
||||
|
||||
dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -24,15 +24,15 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef DRM_INTEL_DRV_H
|
||||
#define DRM_INTEL_DRV_H
|
||||
#ifndef __INTEL_DRV_H__
|
||||
#define __INTEL_DRV_H__
|
||||
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_crtc_helper.h>
|
||||
#include <dev/drm2/drm_fb_helper.h>
|
||||
#include <dev/drm2/drm_dp_helper.h>
|
||||
|
||||
#define _intel_wait_for(DEV, COND, MS, W, WMSG) \
|
||||
({ \
|
||||
@ -55,6 +55,23 @@
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define _wait_for(COND, MS, W, WMSG) ({ \
|
||||
int timeout__ = ticks + (MS) * hz / 1000; \
|
||||
int ret__ = 0; \
|
||||
while (!(COND)) { \
|
||||
if (time_after(ticks, timeout__)) { \
|
||||
ret__ = -ETIMEDOUT; \
|
||||
break; \
|
||||
} \
|
||||
if (W) { \
|
||||
pause((WMSG), 1); \
|
||||
} else { \
|
||||
DELAY(1000); \
|
||||
} \
|
||||
} \
|
||||
ret__; \
|
||||
})
|
||||
|
||||
#define wait_for_atomic_us(COND, US) ({ \
|
||||
int i, ret__ = -ETIMEDOUT; \
|
||||
for (i = 0; i < (US); i++) { \
|
||||
@ -67,8 +84,8 @@
|
||||
ret__; \
|
||||
})
|
||||
|
||||
#define wait_for(COND, MS) _intel_wait_for(NULL, COND, MS, 1, "915wfi")
|
||||
#define wait_for_atomic(COND, MS) _intel_wait_for(NULL, COND, MS, 0, "915wfa")
|
||||
#define wait_for(COND, MS) _intel_wait_for(NULL, COND, MS, 1, "915wfi")
|
||||
#define wait_for_atomic(COND, MS) _intel_wait_for(NULL, COND, MS, 0, "915wfa")
|
||||
|
||||
#define KHz(x) (1000*x)
|
||||
#define MHz(x) KHz(1000*x)
|
||||
@ -100,25 +117,6 @@
|
||||
#define INTEL_OUTPUT_EDP 8
|
||||
#define INTEL_OUTPUT_UNKNOWN 9
|
||||
|
||||
/* Intel Pipe Clone Bit */
|
||||
#define INTEL_HDMIB_CLONE_BIT 1
|
||||
#define INTEL_HDMIC_CLONE_BIT 2
|
||||
#define INTEL_HDMID_CLONE_BIT 3
|
||||
#define INTEL_HDMIE_CLONE_BIT 4
|
||||
#define INTEL_HDMIF_CLONE_BIT 5
|
||||
#define INTEL_SDVO_NON_TV_CLONE_BIT 6
|
||||
#define INTEL_SDVO_TV_CLONE_BIT 7
|
||||
#define INTEL_SDVO_LVDS_CLONE_BIT 8
|
||||
#define INTEL_ANALOG_CLONE_BIT 9
|
||||
#define INTEL_TV_CLONE_BIT 10
|
||||
#define INTEL_DP_B_CLONE_BIT 11
|
||||
#define INTEL_DP_C_CLONE_BIT 12
|
||||
#define INTEL_DP_D_CLONE_BIT 13
|
||||
#define INTEL_LVDS_CLONE_BIT 14
|
||||
#define INTEL_DVO_TMDS_CLONE_BIT 15
|
||||
#define INTEL_DVO_LVDS_CLONE_BIT 16
|
||||
#define INTEL_EDP_CLONE_BIT 17
|
||||
|
||||
#define INTEL_DVO_CHIP_NONE 0
|
||||
#define INTEL_DVO_CHIP_LVDS 1
|
||||
#define INTEL_DVO_CHIP_TMDS 2
|
||||
@ -161,32 +159,87 @@ struct intel_fbdev {
|
||||
|
||||
struct intel_encoder {
|
||||
struct drm_encoder base;
|
||||
/*
|
||||
* The new crtc this encoder will be driven from. Only differs from
|
||||
* base->crtc while a modeset is in progress.
|
||||
*/
|
||||
struct intel_crtc *new_crtc;
|
||||
|
||||
int type;
|
||||
bool needs_tv_clock;
|
||||
/*
|
||||
* Intel hw has only one MUX where encoders could be clone, hence a
|
||||
* simple flag is enough to compute the possible_clones mask.
|
||||
*/
|
||||
bool cloneable;
|
||||
bool connectors_active;
|
||||
void (*hot_plug)(struct intel_encoder *);
|
||||
void (*pre_enable)(struct intel_encoder *);
|
||||
void (*enable)(struct intel_encoder *);
|
||||
void (*disable)(struct intel_encoder *);
|
||||
void (*post_disable)(struct intel_encoder *);
|
||||
/* Read out the current hw state of this connector, returning true if
|
||||
* the encoder is active. If the encoder is enabled it also set the pipe
|
||||
* it is connected to in the pipe parameter. */
|
||||
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
|
||||
int crtc_mask;
|
||||
int clone_mask;
|
||||
};
|
||||
|
||||
struct intel_panel {
|
||||
struct drm_display_mode *fixed_mode;
|
||||
int fitting_mode;
|
||||
};
|
||||
|
||||
struct intel_connector {
|
||||
struct drm_connector base;
|
||||
/*
|
||||
* The fixed encoder this connector is connected to.
|
||||
*/
|
||||
struct intel_encoder *encoder;
|
||||
|
||||
/*
|
||||
* The new encoder this connector will be driven. Only differs from
|
||||
* encoder while a modeset is in progress.
|
||||
*/
|
||||
struct intel_encoder *new_encoder;
|
||||
|
||||
/* Reads out the current hw, returning true if the connector is enabled
|
||||
* and active (i.e. dpms ON state). */
|
||||
bool (*get_hw_state)(struct intel_connector *);
|
||||
|
||||
/* Panel info for eDP and LVDS */
|
||||
struct intel_panel panel;
|
||||
|
||||
/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
|
||||
struct edid *edid;
|
||||
int edid_err;
|
||||
};
|
||||
|
||||
struct intel_crtc {
|
||||
struct drm_crtc base;
|
||||
enum pipe pipe;
|
||||
enum plane plane;
|
||||
enum transcoder cpu_transcoder;
|
||||
u8 lut_r[256], lut_g[256], lut_b[256];
|
||||
int dpms_mode;
|
||||
bool active; /* is the crtc on? independent of the dpms mode */
|
||||
bool busy; /* is scanout buffer being updated frequently? */
|
||||
struct callout idle_callout;
|
||||
/*
|
||||
* Whether the crtc and the connected output pipeline is active. Implies
|
||||
* that crtc->enabled is set, i.e. the current mode configuration has
|
||||
* some outputs connected to this crtc.
|
||||
*/
|
||||
bool active;
|
||||
bool primary_disabled; /* is the crtc obscured by a plane? */
|
||||
bool lowfreq_avail;
|
||||
struct intel_overlay *overlay;
|
||||
struct intel_unpin_work *unpin_work;
|
||||
int fdi_lanes;
|
||||
|
||||
atomic_t unpin_work_count;
|
||||
|
||||
/* Display surface base address adjustement for pageflips. Note that on
|
||||
* gen4+ this only adjusts up to a tile, offsets within a tile are
|
||||
* handled in the hw itself (with the TILEOFF register). */
|
||||
unsigned long dspaddr_offset;
|
||||
|
||||
struct drm_i915_gem_object *cursor_bo;
|
||||
uint32_t cursor_addr;
|
||||
int16_t cursor_x, cursor_y;
|
||||
@ -196,13 +249,14 @@ struct intel_crtc {
|
||||
|
||||
/* We can share PLLs across outputs if the timings match */
|
||||
struct intel_pch_pll *pch_pll;
|
||||
uint32_t ddi_pll_sel;
|
||||
};
|
||||
|
||||
struct intel_plane {
|
||||
struct drm_plane base;
|
||||
enum pipe pipe;
|
||||
struct drm_i915_gem_object *obj;
|
||||
bool primary_disabled;
|
||||
bool can_scale;
|
||||
int max_downscale;
|
||||
u32 lut_r[1024], lut_g[1024], lut_b[1024];
|
||||
void (*update_plane)(struct drm_plane *plane,
|
||||
@ -302,16 +356,52 @@ struct dip_infoframe {
|
||||
} __attribute__((packed));
|
||||
|
||||
struct intel_hdmi {
|
||||
struct intel_encoder base;
|
||||
u32 sdvox_reg;
|
||||
int ddc_bus;
|
||||
int ddi_port;
|
||||
uint32_t color_range;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
void (*write_infoframe)(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame);
|
||||
void (*set_infoframes)(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
};
|
||||
|
||||
#define DP_MAX_DOWNSTREAM_PORTS 0x10
|
||||
#define DP_LINK_CONFIGURATION_SIZE 9
|
||||
|
||||
struct intel_dp {
|
||||
uint32_t output_reg;
|
||||
uint32_t DP;
|
||||
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
uint32_t color_range;
|
||||
uint8_t link_bw;
|
||||
uint8_t lane_count;
|
||||
uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
|
||||
device_t dp_iic_bus;
|
||||
device_t adapter;
|
||||
bool is_pch_edp;
|
||||
uint8_t train_set[4];
|
||||
int panel_power_up_delay;
|
||||
int panel_power_down_delay;
|
||||
int panel_power_cycle_delay;
|
||||
int backlight_on_delay;
|
||||
int backlight_off_delay;
|
||||
struct timeout_task panel_vdd_work;
|
||||
bool want_panel_vdd;
|
||||
struct intel_connector *attached_connector;
|
||||
};
|
||||
|
||||
struct intel_digital_port {
|
||||
struct intel_encoder base;
|
||||
enum port port;
|
||||
u32 port_reversal;
|
||||
struct intel_dp dp;
|
||||
struct intel_hdmi hdmi;
|
||||
};
|
||||
|
||||
static inline struct drm_crtc *
|
||||
@ -329,56 +419,88 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
|
||||
}
|
||||
|
||||
struct intel_unpin_work {
|
||||
struct task task;
|
||||
struct drm_device *dev;
|
||||
struct task work;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_i915_gem_object *old_fb_obj;
|
||||
struct drm_i915_gem_object *pending_flip_obj;
|
||||
struct drm_pending_vblank_event *event;
|
||||
int pending;
|
||||
atomic_t pending;
|
||||
#define INTEL_FLIP_INACTIVE 0
|
||||
#define INTEL_FLIP_PENDING 1
|
||||
#define INTEL_FLIP_COMPLETE 2
|
||||
bool enable_stall_check;
|
||||
};
|
||||
|
||||
struct intel_fbc_work {
|
||||
struct timeout_task task;
|
||||
struct timeout_task work;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_framebuffer *fb;
|
||||
int interval;
|
||||
};
|
||||
|
||||
int intel_pch_rawclk(struct drm_device *dev);
|
||||
|
||||
int intel_connector_update_modes(struct drm_connector *connector,
|
||||
struct edid *edid);
|
||||
int intel_ddc_get_modes(struct drm_connector *c, device_t adapter);
|
||||
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
|
||||
|
||||
extern void intel_attach_force_audio_property(struct drm_connector *connector);
|
||||
extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
|
||||
|
||||
extern void intel_crt_init(struct drm_device *dev);
|
||||
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
|
||||
extern void intel_hdmi_init(struct drm_device *dev,
|
||||
int sdvox_reg, enum port port);
|
||||
extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
|
||||
extern void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder);
|
||||
extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
||||
extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
|
||||
bool is_sdvob);
|
||||
extern void intel_dvo_init(struct drm_device *dev);
|
||||
extern void intel_tv_init(struct drm_device *dev);
|
||||
extern void intel_mark_busy(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj);
|
||||
extern void intel_mark_busy(struct drm_device *dev);
|
||||
extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj);
|
||||
extern void intel_mark_idle(struct drm_device *dev);
|
||||
extern bool intel_lvds_init(struct drm_device *dev);
|
||||
extern void intel_dp_init(struct drm_device *dev, int dp_reg);
|
||||
extern void intel_dp_init(struct drm_device *dev, int output_reg,
|
||||
enum port port);
|
||||
extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
void
|
||||
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_dp_init_link_config(struct intel_dp *intel_dp);
|
||||
extern void intel_dp_start_link_train(struct intel_dp *intel_dp);
|
||||
extern void intel_dp_complete_link_train(struct intel_dp *intel_dp);
|
||||
extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
|
||||
extern void intel_dp_encoder_destroy(struct drm_encoder *encoder);
|
||||
extern void intel_dp_check_link_status(struct intel_dp *intel_dp);
|
||||
extern bool intel_dp_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern bool intel_dpd_is_edp(struct drm_device *dev);
|
||||
extern void ironlake_edp_backlight_on(struct intel_dp *intel_dp);
|
||||
extern void ironlake_edp_backlight_off(struct intel_dp *intel_dp);
|
||||
extern void ironlake_edp_panel_on(struct intel_dp *intel_dp);
|
||||
extern void ironlake_edp_panel_off(struct intel_dp *intel_dp);
|
||||
extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp);
|
||||
extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
|
||||
extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
|
||||
extern int intel_edp_target_clock(struct intel_encoder *,
|
||||
struct drm_display_mode *mode);
|
||||
extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
|
||||
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
|
||||
extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
|
||||
enum plane plane);
|
||||
|
||||
void intel_sanitize_pm(struct drm_device *dev);
|
||||
|
||||
/* intel_panel.c */
|
||||
extern int intel_panel_init(struct intel_panel *panel,
|
||||
struct drm_display_mode *fixed_mode);
|
||||
extern void intel_panel_fini(struct intel_panel *panel);
|
||||
|
||||
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_pch_panel_fitting(struct drm_device *dev,
|
||||
@ -386,24 +508,66 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
|
||||
extern u32 intel_panel_get_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
|
||||
extern int intel_panel_setup_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_enable_backlight(struct drm_device *dev);
|
||||
extern int intel_panel_setup_backlight(struct drm_connector *connector);
|
||||
extern void intel_panel_enable_backlight(struct drm_device *dev,
|
||||
enum pipe pipe);
|
||||
extern void intel_panel_disable_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_destroy_backlight(struct drm_device *dev);
|
||||
extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
|
||||
|
||||
struct intel_set_config {
|
||||
struct drm_encoder **save_connector_encoders;
|
||||
struct drm_crtc **save_encoder_crtcs;
|
||||
|
||||
bool fb_changed;
|
||||
bool mode_changed;
|
||||
};
|
||||
|
||||
extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
int x, int y, struct drm_framebuffer *old_fb);
|
||||
extern void intel_modeset_disable(struct drm_device *dev);
|
||||
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
|
||||
extern void intel_encoder_prepare(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_commit(struct drm_encoder *encoder);
|
||||
extern void intel_crtc_update_dpms(struct drm_crtc *crtc);
|
||||
extern void intel_encoder_noop(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_destroy(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
|
||||
extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
|
||||
extern void intel_connector_dpms(struct drm_connector *, int mode);
|
||||
extern bool intel_connector_get_hw_state(struct intel_connector *connector);
|
||||
extern void intel_modeset_check_state(struct drm_device *dev);
|
||||
|
||||
|
||||
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
|
||||
{
|
||||
return to_intel_connector(connector)->encoder;
|
||||
}
|
||||
|
||||
static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
container_of(encoder, struct intel_digital_port, base.base);
|
||||
return &intel_dig_port->dp;
|
||||
}
|
||||
|
||||
static inline struct intel_digital_port *
|
||||
enc_to_dig_port(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct intel_digital_port, base.base);
|
||||
}
|
||||
|
||||
static inline struct intel_digital_port *
|
||||
dp_to_dig_port(struct intel_dp *intel_dp)
|
||||
{
|
||||
return container_of(intel_dp, struct intel_digital_port, dp);
|
||||
}
|
||||
|
||||
static inline struct intel_digital_port *
|
||||
hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
|
||||
{
|
||||
return container_of(intel_hdmi, struct intel_digital_port, hdmi);
|
||||
}
|
||||
|
||||
extern void intel_connector_attach_encoder(struct intel_connector *connector,
|
||||
struct intel_encoder *encoder);
|
||||
extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
|
||||
@ -412,20 +576,22 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
|
||||
struct drm_crtc *crtc);
|
||||
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern enum transcoder
|
||||
intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe);
|
||||
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
|
||||
extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
|
||||
extern int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
|
||||
|
||||
struct intel_load_detect_pipe {
|
||||
struct drm_framebuffer *release_fb;
|
||||
bool load_detect_temp;
|
||||
int dpms_mode;
|
||||
};
|
||||
extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
|
||||
struct drm_connector *connector,
|
||||
extern bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct intel_load_detect_pipe *old);
|
||||
extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
|
||||
struct drm_connector *connector,
|
||||
extern void intel_release_load_detect_pipe(struct drm_connector *connector,
|
||||
struct intel_load_detect_pipe *old);
|
||||
|
||||
extern void intelfb_restore(void);
|
||||
@ -434,19 +600,6 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
|
||||
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, int regno);
|
||||
extern void intel_enable_clock_gating(struct drm_device *dev);
|
||||
extern void ironlake_disable_rc6(struct drm_device *dev);
|
||||
extern void ironlake_enable_drps(struct drm_device *dev);
|
||||
extern void ironlake_disable_drps(struct drm_device *dev);
|
||||
extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
|
||||
extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
|
||||
extern void gen6_disable_rps(struct drm_device *dev);
|
||||
extern void intel_init_emon(struct drm_device *dev);
|
||||
extern int intel_enable_rc6(const struct drm_device *dev);
|
||||
|
||||
extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
|
||||
extern void intel_ddi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
|
||||
extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj,
|
||||
@ -459,7 +612,7 @@ extern int intel_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj);
|
||||
extern int intel_fbdev_init(struct drm_device *dev);
|
||||
extern void intel_fbdev_fini(struct drm_device *dev);
|
||||
|
||||
extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
|
||||
extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
|
||||
extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
|
||||
extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
|
||||
@ -496,6 +649,11 @@ extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
|
||||
extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
extern unsigned long intel_gen4_compute_page_offset(int *x, int *y,
|
||||
unsigned int tiling_mode,
|
||||
unsigned int bpp,
|
||||
unsigned int pitch);
|
||||
|
||||
extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
|
||||
@ -509,5 +667,32 @@ extern void intel_init_pm(struct drm_device *dev);
|
||||
extern bool intel_fbc_enabled(struct drm_device *dev);
|
||||
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
|
||||
extern void intel_update_fbc(struct drm_device *dev);
|
||||
/* IPS */
|
||||
extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
|
||||
extern void intel_gpu_ips_teardown(void);
|
||||
|
||||
extern void intel_init_power_wells(struct drm_device *dev);
|
||||
extern void intel_enable_gt_powersave(struct drm_device *dev);
|
||||
extern void intel_disable_gt_powersave(struct drm_device *dev);
|
||||
extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
|
||||
extern void ironlake_teardown_rc6(struct drm_device *dev);
|
||||
|
||||
extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
|
||||
enum pipe *pipe);
|
||||
extern int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv);
|
||||
extern void intel_ddi_pll_init(struct drm_device *dev);
|
||||
extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc);
|
||||
extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
|
||||
enum transcoder cpu_transcoder);
|
||||
extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc);
|
||||
extern void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc);
|
||||
extern void intel_ddi_setup_hw_pll_state(struct drm_device *dev);
|
||||
extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock);
|
||||
extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc);
|
||||
extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
|
||||
extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
|
||||
extern bool
|
||||
intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
|
||||
extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
|
||||
|
||||
#endif /* __INTEL_DRV_H__ */
|
||||
|
534
sys/dev/drm2/i915/intel_dvo.c
Normal file
534
sys/dev/drm2/i915/intel_dvo.c
Normal file
@ -0,0 +1,534 @@
|
||||
/*
|
||||
* Copyright 2006 Dave Airlie <airlied@linux.ie>
|
||||
* Copyright © 2006-2007 Intel Corporation
|
||||
*
|
||||
* 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
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/dvo.h>
|
||||
|
||||
#define SIL164_ADDR 0x38
|
||||
#define CH7xxx_ADDR 0x76
|
||||
#define TFP410_ADDR 0x38
|
||||
#define NS2501_ADDR 0x38
|
||||
|
||||
static const struct intel_dvo_device intel_dvo_devices[] = {
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_TMDS,
|
||||
.name = "sil164",
|
||||
.dvo_reg = DVOC,
|
||||
.slave_addr = SIL164_ADDR,
|
||||
.dev_ops = &sil164_ops,
|
||||
},
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_TMDS,
|
||||
.name = "ch7xxx",
|
||||
.dvo_reg = DVOC,
|
||||
.slave_addr = CH7xxx_ADDR,
|
||||
.dev_ops = &ch7xxx_ops,
|
||||
},
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_LVDS,
|
||||
.name = "ivch",
|
||||
.dvo_reg = DVOA,
|
||||
.slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
|
||||
.dev_ops = &ivch_ops,
|
||||
},
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_TMDS,
|
||||
.name = "tfp410",
|
||||
.dvo_reg = DVOC,
|
||||
.slave_addr = TFP410_ADDR,
|
||||
.dev_ops = &tfp410_ops,
|
||||
},
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_LVDS,
|
||||
.name = "ch7017",
|
||||
.dvo_reg = DVOC,
|
||||
.slave_addr = 0x75,
|
||||
.gpio = GMBUS_PORT_DPB,
|
||||
.dev_ops = &ch7017_ops,
|
||||
},
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_TMDS,
|
||||
.name = "ns2501",
|
||||
.dvo_reg = DVOC,
|
||||
.slave_addr = NS2501_ADDR,
|
||||
.dev_ops = &ns2501_ops,
|
||||
}
|
||||
};
|
||||
|
||||
struct intel_dvo {
|
||||
struct intel_encoder base;
|
||||
|
||||
struct intel_dvo_device dev;
|
||||
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
bool panel_wants_dither;
|
||||
};
|
||||
|
||||
static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct intel_dvo, base.base);
|
||||
}
|
||||
|
||||
static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(intel_attached_encoder(connector),
|
||||
struct intel_dvo, base);
|
||||
}
|
||||
|
||||
static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
|
||||
|
||||
return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
|
||||
}
|
||||
|
||||
static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
|
||||
enum pipe *pipe)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
|
||||
u32 tmp;
|
||||
|
||||
tmp = I915_READ(intel_dvo->dev.dvo_reg);
|
||||
|
||||
if (!(tmp & DVO_ENABLE))
|
||||
return false;
|
||||
|
||||
*pipe = PORT_TO_PIPE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_disable_dvo(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
|
||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
|
||||
u32 dvo_reg = intel_dvo->dev.dvo_reg;
|
||||
u32 temp = I915_READ(dvo_reg);
|
||||
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
|
||||
I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
|
||||
I915_READ(dvo_reg);
|
||||
}
|
||||
|
||||
static void intel_enable_dvo(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
|
||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
|
||||
u32 dvo_reg = intel_dvo->dev.dvo_reg;
|
||||
u32 temp = I915_READ(dvo_reg);
|
||||
|
||||
I915_WRITE(dvo_reg, temp | DVO_ENABLE);
|
||||
I915_READ(dvo_reg);
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
|
||||
}
|
||||
|
||||
static void intel_dvo_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
/* dvo supports only 2 dpms states. */
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (mode == connector->dpms)
|
||||
return;
|
||||
|
||||
connector->dpms = mode;
|
||||
|
||||
/* Only need to change hw state when actually enabled */
|
||||
crtc = intel_dvo->base.base.crtc;
|
||||
if (!crtc) {
|
||||
intel_dvo->base.connectors_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == DRM_MODE_DPMS_ON) {
|
||||
intel_dvo->base.connectors_active = true;
|
||||
|
||||
intel_crtc_update_dpms(crtc);
|
||||
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
|
||||
} else {
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
|
||||
|
||||
intel_dvo->base.connectors_active = false;
|
||||
|
||||
intel_crtc_update_dpms(crtc);
|
||||
}
|
||||
|
||||
intel_modeset_check_state(connector->dev);
|
||||
}
|
||||
|
||||
static int intel_dvo_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
/* XXX: Validate clock range */
|
||||
|
||||
if (intel_dvo->panel_fixed_mode) {
|
||||
if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay)
|
||||
return MODE_PANEL;
|
||||
if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay)
|
||||
return MODE_PANEL;
|
||||
}
|
||||
|
||||
return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
|
||||
}
|
||||
|
||||
static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
|
||||
|
||||
/* If we have timings from the BIOS for the panel, put them in
|
||||
* to the adjusted mode. The CRTC will be set up for this mode,
|
||||
* with the panel scaling set up to source from the H/VDisplay
|
||||
* of the original mode.
|
||||
*/
|
||||
if (intel_dvo->panel_fixed_mode != NULL) {
|
||||
#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x
|
||||
C(hdisplay);
|
||||
C(hsync_start);
|
||||
C(hsync_end);
|
||||
C(htotal);
|
||||
C(vdisplay);
|
||||
C(vsync_start);
|
||||
C(vsync_end);
|
||||
C(vtotal);
|
||||
C(clock);
|
||||
#undef C
|
||||
}
|
||||
|
||||
if (intel_dvo->dev.dev_ops->mode_fixup)
|
||||
return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev, mode, adjusted_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_dvo_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
|
||||
int pipe = intel_crtc->pipe;
|
||||
u32 dvo_val;
|
||||
u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg;
|
||||
int dpll_reg = DPLL(pipe);
|
||||
|
||||
switch (dvo_reg) {
|
||||
case DVOA:
|
||||
default:
|
||||
dvo_srcdim_reg = DVOA_SRCDIM;
|
||||
break;
|
||||
case DVOB:
|
||||
dvo_srcdim_reg = DVOB_SRCDIM;
|
||||
break;
|
||||
case DVOC:
|
||||
dvo_srcdim_reg = DVOC_SRCDIM;
|
||||
break;
|
||||
}
|
||||
|
||||
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, mode, adjusted_mode);
|
||||
|
||||
/* Save the data order, since I don't know what it should be set to. */
|
||||
dvo_val = I915_READ(dvo_reg) &
|
||||
(DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
|
||||
dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |
|
||||
DVO_BLANK_ACTIVE_HIGH;
|
||||
|
||||
if (pipe == 1)
|
||||
dvo_val |= DVO_PIPE_B_SELECT;
|
||||
dvo_val |= DVO_PIPE_STALL;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
dvo_val |= DVO_HSYNC_ACTIVE_HIGH;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED);
|
||||
|
||||
/*I915_WRITE(DVOB_SRCDIM,
|
||||
(adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
|
||||
(adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
|
||||
I915_WRITE(dvo_srcdim_reg,
|
||||
(adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
|
||||
(adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
|
||||
/*I915_WRITE(DVOB, dvo_val);*/
|
||||
I915_WRITE(dvo_reg, dvo_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the output connection on our DVO device.
|
||||
*
|
||||
* Unimplemented.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
intel_dvo_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
|
||||
return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
|
||||
}
|
||||
|
||||
static int intel_dvo_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
|
||||
/* We should probably have an i2c driver get_modes function for those
|
||||
* devices which will have a fixed set of modes determined by the chip
|
||||
* (TV-out, for example), but for now with just TMDS and LVDS,
|
||||
* that's not the case.
|
||||
*/
|
||||
intel_ddc_get_modes(connector,
|
||||
intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPC));
|
||||
if (!list_empty(&connector->probed_modes))
|
||||
return 1;
|
||||
|
||||
if (intel_dvo->panel_fixed_mode != NULL) {
|
||||
struct drm_display_mode *mode;
|
||||
mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode);
|
||||
if (mode) {
|
||||
drm_mode_probed_add(connector, mode);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_dvo_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
|
||||
.mode_fixup = intel_dvo_mode_fixup,
|
||||
.mode_set = intel_dvo_mode_set,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_dvo_connector_funcs = {
|
||||
.dpms = intel_dvo_dpms,
|
||||
.detect = intel_dvo_detect,
|
||||
.destroy = intel_dvo_destroy,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
|
||||
.mode_valid = intel_dvo_mode_valid,
|
||||
.get_modes = intel_dvo_get_modes,
|
||||
.best_encoder = intel_best_encoder,
|
||||
};
|
||||
|
||||
static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
|
||||
|
||||
if (intel_dvo->dev.dev_ops->destroy)
|
||||
intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
|
||||
|
||||
free(intel_dvo->panel_fixed_mode, DRM_MEM_KMS);
|
||||
|
||||
intel_encoder_destroy(encoder);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
|
||||
.destroy = intel_dvo_enc_destroy,
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts to get a fixed panel timing for LVDS (currently only the i830).
|
||||
*
|
||||
* Other chips with DVO LVDS will need to extend this to deal with the LVDS
|
||||
* chip being on DVOB/C and having multiple pipes.
|
||||
*/
|
||||
static struct drm_display_mode *
|
||||
intel_dvo_get_current_mode(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
|
||||
uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
|
||||
struct drm_display_mode *mode = NULL;
|
||||
|
||||
/* If the DVO port is active, that'll be the LVDS, so we can pull out
|
||||
* its timings to get how the BIOS set up the panel.
|
||||
*/
|
||||
if (dvo_val & DVO_ENABLE) {
|
||||
struct drm_crtc *crtc;
|
||||
int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
|
||||
|
||||
crtc = intel_get_crtc_for_pipe(dev, pipe);
|
||||
if (crtc) {
|
||||
mode = intel_crtc_mode_get(dev, crtc);
|
||||
if (mode) {
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)
|
||||
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
if (dvo_val & DVO_VSYNC_ACTIVE_HIGH)
|
||||
mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void intel_dvo_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct intel_dvo *intel_dvo;
|
||||
struct intel_connector *intel_connector;
|
||||
int i;
|
||||
int encoder_type = DRM_MODE_ENCODER_NONE;
|
||||
|
||||
intel_dvo = malloc(sizeof(struct intel_dvo), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_dvo)
|
||||
return;
|
||||
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_connector) {
|
||||
free(intel_dvo, DRM_MEM_KMS);
|
||||
return;
|
||||
}
|
||||
|
||||
intel_encoder = &intel_dvo->base;
|
||||
drm_encoder_init(dev, &intel_encoder->base,
|
||||
&intel_dvo_enc_funcs, encoder_type);
|
||||
|
||||
intel_encoder->disable = intel_disable_dvo;
|
||||
intel_encoder->enable = intel_enable_dvo;
|
||||
intel_encoder->get_hw_state = intel_dvo_get_hw_state;
|
||||
intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
|
||||
|
||||
/* Now, try to find a controller */
|
||||
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
|
||||
struct drm_connector *connector = &intel_connector->base;
|
||||
const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
|
||||
device_t i2c;
|
||||
int gpio;
|
||||
bool dvoinit;
|
||||
|
||||
/* Allow the I2C driver info to specify the GPIO to be used in
|
||||
* special cases, but otherwise default to what's defined
|
||||
* in the spec.
|
||||
*/
|
||||
if (intel_gmbus_is_port_valid(dvo->gpio))
|
||||
gpio = dvo->gpio;
|
||||
else if (dvo->type == INTEL_DVO_CHIP_LVDS)
|
||||
gpio = GMBUS_PORT_SSC;
|
||||
else
|
||||
gpio = GMBUS_PORT_DPB;
|
||||
|
||||
/* Set up the I2C bus necessary for the chip we're probing.
|
||||
* It appears that everything is on GPIOE except for panels
|
||||
* on i830 laptops, which are on GPIOB (DVOA).
|
||||
*/
|
||||
i2c = intel_gmbus_get_adapter(dev_priv, gpio);
|
||||
|
||||
intel_dvo->dev = *dvo;
|
||||
|
||||
/* GMBUS NAK handling seems to be unstable, hence let the
|
||||
* transmitter detection run in bit banging mode for now.
|
||||
*/
|
||||
intel_gmbus_force_bit(i2c, true);
|
||||
|
||||
dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c);
|
||||
|
||||
intel_gmbus_force_bit(i2c, false);
|
||||
|
||||
if (!dvoinit)
|
||||
continue;
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_DVO;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
||||
switch (dvo->type) {
|
||||
case INTEL_DVO_CHIP_TMDS:
|
||||
intel_encoder->cloneable = true;
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DVII);
|
||||
encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
break;
|
||||
case INTEL_DVO_CHIP_LVDS:
|
||||
intel_encoder->cloneable = false;
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
break;
|
||||
}
|
||||
|
||||
drm_connector_helper_add(connector,
|
||||
&intel_dvo_connector_helper_funcs);
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
|
||||
drm_encoder_helper_add(&intel_encoder->base,
|
||||
&intel_dvo_helper_funcs);
|
||||
|
||||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
if (dvo->type == INTEL_DVO_CHIP_LVDS) {
|
||||
/* For our LVDS chipsets, we should hopefully be able
|
||||
* to dig the fixed panel mode out of the BIOS data.
|
||||
* However, it's in a different format from the BIOS
|
||||
* data on chipsets with integrated LVDS (stored in AIM
|
||||
* headers, likely), so for now, just get the current
|
||||
* mode being output through DVO.
|
||||
*/
|
||||
intel_dvo->panel_fixed_mode =
|
||||
intel_dvo_get_current_mode(connector);
|
||||
intel_dvo->panel_wants_dither = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
drm_encoder_cleanup(&intel_encoder->base);
|
||||
free(intel_dvo, DRM_MEM_KMS);
|
||||
free(intel_connector, DRM_MEM_KMS);
|
||||
}
|
@ -29,20 +29,33 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_syscons.h"
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_fb_helper.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
static struct fb_ops intelfb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_check_var = drm_fb_helper_check_var,
|
||||
.fb_set_par = drm_fb_helper_set_par,
|
||||
.fb_fillrect = cfb_fillrect,
|
||||
.fb_copyarea = cfb_copyarea,
|
||||
.fb_imageblit = cfb_imageblit,
|
||||
.fb_pan_display = drm_fb_helper_pan_display,
|
||||
.fb_blank = drm_fb_helper_blank,
|
||||
.fb_setcmap = drm_fb_helper_setcmap,
|
||||
.fb_debug_enter = drm_fb_helper_debug_enter,
|
||||
.fb_debug_leave = drm_fb_helper_debug_leave,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct drm_device *dev = ifbdev->helper.dev;
|
||||
#if 0
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
#endif
|
||||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_mode_fb_cmd2 mode_cmd = {};
|
||||
@ -85,17 +98,12 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
#if 0
|
||||
info->par = ifbdev;
|
||||
#else
|
||||
info->fb_size = size;
|
||||
info->fb_bpp = sizes->surface_bpp;
|
||||
info->fb_pbase = dev->agp->base + obj->gtt_offset;
|
||||
info->fb_pbase = dev_priv->mm.gtt_base_addr + obj->gtt_offset;
|
||||
info->fb_vbase = (vm_offset_t)pmap_mapdev_attr(info->fb_pbase, size,
|
||||
PAT_WRITE_COMBINING);
|
||||
|
||||
#endif
|
||||
|
||||
ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
|
||||
if (ret)
|
||||
goto out_unpin;
|
||||
@ -104,40 +112,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
|
||||
ifbdev->helper.fb = fb;
|
||||
ifbdev->helper.fbdev = info;
|
||||
#if 0
|
||||
|
||||
strcpy(info->fix.id, "inteldrmfb");
|
||||
|
||||
info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
|
||||
info->fbops = &intelfb_ops;
|
||||
|
||||
ret = fb_alloc_cmap(&info->cmap, 256, 0);
|
||||
if (ret) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unpin;
|
||||
}
|
||||
/* setup aperture base/size for vesafb takeover */
|
||||
info->apertures = alloc_apertures(1);
|
||||
if (!info->apertures) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unpin;
|
||||
}
|
||||
info->apertures->ranges[0].base = dev->mode_config.fb_base;
|
||||
info->apertures->ranges[0].size =
|
||||
dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||||
|
||||
info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
|
||||
info->fix.smem_len = size;
|
||||
|
||||
info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size);
|
||||
if (!info->screen_base) {
|
||||
ret = -ENOSPC;
|
||||
goto out_unpin;
|
||||
}
|
||||
info->screen_size = size;
|
||||
|
||||
// memset(info->screen_base, 0, size);
|
||||
#endif
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
|
||||
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
|
||||
@ -148,10 +122,9 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
fb->width, fb->height, fb->depth,
|
||||
obj->gtt_offset, obj);
|
||||
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
#if 1
|
||||
KIB_NOTYET();
|
||||
#else
|
||||
#ifdef __linux__
|
||||
vga_switcheroo_client_fb_set(dev->pdev, info);
|
||||
#endif
|
||||
return 0;
|
||||
@ -195,12 +168,8 @@ static void intel_fbdev_destroy(struct drm_device *dev,
|
||||
|
||||
if (ifbdev->helper.fbdev) {
|
||||
info = ifbdev->helper.fbdev;
|
||||
#if 0
|
||||
unregister_framebuffer(info);
|
||||
iounmap(info->screen_base);
|
||||
if (info->cmap.len)
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
#endif
|
||||
if (info->fb_fbd_dev != NULL)
|
||||
device_delete_child(dev->dev, info->fb_fbd_dev);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
|
||||
@ -224,6 +193,8 @@ int intel_fbdev_init(struct drm_device *dev)
|
||||
int ret;
|
||||
|
||||
ifbdev = malloc(sizeof(struct intel_fbdev), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!ifbdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_priv->fbdev = ifbdev;
|
||||
ifbdev->helper.funcs = &intel_fb_helper_funcs;
|
||||
@ -255,6 +226,19 @@ void intel_fbdev_fini(struct drm_device *dev)
|
||||
dev_priv->fbdev = NULL;
|
||||
}
|
||||
|
||||
void intel_fbdev_set_suspend(struct drm_device *dev, int state)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
if (!dev_priv->fbdev)
|
||||
return;
|
||||
|
||||
#ifdef FREEBSD_WIP
|
||||
fb_set_suspend(dev_priv->fbdev->helper.fbdev, state);
|
||||
#endif /* FREEBSD_WIP */
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
void intel_fb_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
@ -30,22 +30,42 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
#define mmiowb() barrier()
|
||||
|
||||
static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
|
||||
{
|
||||
return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
|
||||
}
|
||||
|
||||
static void
|
||||
assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
|
||||
{
|
||||
struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t enabled_bits;
|
||||
|
||||
enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
|
||||
|
||||
WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits,
|
||||
"HDMI port enabled, expecting disabled\n");
|
||||
}
|
||||
|
||||
struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct intel_hdmi, base.base);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
container_of(encoder, struct intel_digital_port, base.base);
|
||||
return &intel_dig_port->hdmi;
|
||||
}
|
||||
|
||||
static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(intel_attached_encoder(connector),
|
||||
struct intel_hdmi, base);
|
||||
return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base);
|
||||
}
|
||||
|
||||
void intel_dip_infoframe_csum(struct dip_infoframe *frame)
|
||||
@ -121,36 +141,34 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 val = I915_READ(VIDEO_DIP_CTL);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
|
||||
val &= ~VIDEO_DIP_PORT_MASK;
|
||||
if (intel_hdmi->sdvox_reg == SDVOB)
|
||||
val |= VIDEO_DIP_PORT_B;
|
||||
else if (intel_hdmi->sdvox_reg == SDVOC)
|
||||
val |= VIDEO_DIP_PORT_C;
|
||||
else
|
||||
return;
|
||||
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(VIDEO_DIP_CTL, val);
|
||||
|
||||
mmiowb();
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(VIDEO_DIP_DATA, *data);
|
||||
data++;
|
||||
}
|
||||
/* Write every possible data byte to force correct ECC calculation. */
|
||||
for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||||
I915_WRITE(VIDEO_DIP_DATA, 0);
|
||||
mmiowb();
|
||||
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(VIDEO_DIP_CTL, val);
|
||||
POSTING_READ(VIDEO_DIP_CTL);
|
||||
}
|
||||
|
||||
static void ibx_write_infoframe(struct drm_encoder *encoder,
|
||||
@ -160,46 +178,35 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
val &= ~VIDEO_DIP_PORT_MASK;
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case HDMIB:
|
||||
val |= VIDEO_DIP_PORT_B;
|
||||
break;
|
||||
case HDMIC:
|
||||
val |= VIDEO_DIP_PORT_C;
|
||||
break;
|
||||
case HDMID:
|
||||
val |= VIDEO_DIP_PORT_D;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
|
||||
mmiowb();
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
/* Write every possible data byte to force correct ECC calculation. */
|
||||
for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
|
||||
mmiowb();
|
||||
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
}
|
||||
|
||||
static void cpt_write_infoframe(struct drm_encoder *encoder,
|
||||
@ -213,32 +220,34 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
/* The DIP control register spec says that we need to update the AVI
|
||||
* infoframe without clearing its enable bit */
|
||||
if (frame->type == DIP_TYPE_AVI)
|
||||
val |= VIDEO_DIP_ENABLE_AVI;
|
||||
else
|
||||
if (frame->type != DIP_TYPE_AVI)
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
|
||||
mmiowb();
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
/* Write every possible data byte to force correct ECC calculation. */
|
||||
for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
|
||||
mmiowb();
|
||||
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
}
|
||||
|
||||
static void vlv_write_infoframe(struct drm_encoder *encoder,
|
||||
@ -252,26 +261,31 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
val |= g4x_infoframe_index(frame);
|
||||
|
||||
val &= ~g4x_infoframe_enable(frame);
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
|
||||
mmiowb();
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
/* Write every possible data byte to force correct ECC calculation. */
|
||||
for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||||
I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
|
||||
mmiowb();
|
||||
|
||||
val |= g4x_infoframe_enable(frame);
|
||||
val &= ~VIDEO_DIP_FREQ_MASK;
|
||||
val |= VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
}
|
||||
|
||||
static void hsw_write_infoframe(struct drm_encoder *encoder,
|
||||
@ -289,18 +303,22 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
|
||||
if (data_reg == 0)
|
||||
return;
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
val &= ~hsw_infoframe_enable(frame);
|
||||
I915_WRITE(ctl_reg, val);
|
||||
|
||||
mmiowb();
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(data_reg + i, *data);
|
||||
data++;
|
||||
}
|
||||
/* Write every possible data byte to force correct ECC calculation. */
|
||||
for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
|
||||
I915_WRITE(data_reg + i, 0);
|
||||
mmiowb();
|
||||
|
||||
val |= hsw_infoframe_enable(frame);
|
||||
I915_WRITE(ctl_reg, val);
|
||||
POSTING_READ(ctl_reg);
|
||||
}
|
||||
|
||||
static void intel_set_infoframe(struct drm_encoder *encoder,
|
||||
@ -308,14 +326,11 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink)
|
||||
return;
|
||||
|
||||
intel_dip_infoframe_csum(frame);
|
||||
intel_hdmi->write_infoframe(encoder, frame);
|
||||
}
|
||||
|
||||
void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct dip_infoframe avi_if = {
|
||||
@ -327,10 +342,12 @@ void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
|
||||
|
||||
avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode);
|
||||
|
||||
intel_set_infoframe(encoder, &avi_if);
|
||||
}
|
||||
|
||||
void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
||||
static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dip_infoframe spd_if;
|
||||
|
||||
@ -345,6 +362,225 @@ void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
||||
intel_set_infoframe(encoder, &spd_if);
|
||||
}
|
||||
|
||||
static void g4x_set_infoframes(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 reg = VIDEO_DIP_CTL;
|
||||
u32 val = I915_READ(reg);
|
||||
u32 port;
|
||||
|
||||
assert_hdmi_port_disabled(intel_hdmi);
|
||||
|
||||
/* If the registers were not initialized yet, they might be zeroes,
|
||||
* which means we're selecting the AVI DIP and we're setting its
|
||||
* frequency to once. This seems to really confuse the HW and make
|
||||
* things stop working (the register spec says the AVI always needs to
|
||||
* be sent every VSync). So here we avoid writing to the register more
|
||||
* than we need and also explicitly select the AVI DIP and explicitly
|
||||
* set its frequency to every VSync. Avoiding to write it twice seems to
|
||||
* be enough to solve the problem, but being defensive shouldn't hurt us
|
||||
* either. */
|
||||
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink) {
|
||||
if (!(val & VIDEO_DIP_ENABLE))
|
||||
return;
|
||||
val &= ~VIDEO_DIP_ENABLE;
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case SDVOB:
|
||||
port = VIDEO_DIP_PORT_B;
|
||||
break;
|
||||
case SDVOC:
|
||||
port = VIDEO_DIP_PORT_C;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
if (port != (val & VIDEO_DIP_PORT_MASK)) {
|
||||
if (val & VIDEO_DIP_ENABLE) {
|
||||
val &= ~VIDEO_DIP_ENABLE;
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
}
|
||||
val &= ~VIDEO_DIP_PORT_MASK;
|
||||
val |= port;
|
||||
}
|
||||
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
val &= ~VIDEO_DIP_ENABLE_VENDOR;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
static void ibx_set_infoframes(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 val = I915_READ(reg);
|
||||
u32 port;
|
||||
|
||||
assert_hdmi_port_disabled(intel_hdmi);
|
||||
|
||||
/* See the big comment in g4x_set_infoframes() */
|
||||
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink) {
|
||||
if (!(val & VIDEO_DIP_ENABLE))
|
||||
return;
|
||||
val &= ~VIDEO_DIP_ENABLE;
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case HDMIB:
|
||||
port = VIDEO_DIP_PORT_B;
|
||||
break;
|
||||
case HDMIC:
|
||||
port = VIDEO_DIP_PORT_C;
|
||||
break;
|
||||
case HDMID:
|
||||
port = VIDEO_DIP_PORT_D;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
if (port != (val & VIDEO_DIP_PORT_MASK)) {
|
||||
if (val & VIDEO_DIP_ENABLE) {
|
||||
val &= ~VIDEO_DIP_ENABLE;
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
}
|
||||
val &= ~VIDEO_DIP_PORT_MASK;
|
||||
val |= port;
|
||||
}
|
||||
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
|
||||
VIDEO_DIP_ENABLE_GCP);
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
static void cpt_set_infoframes(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
assert_hdmi_port_disabled(intel_hdmi);
|
||||
|
||||
/* See the big comment in g4x_set_infoframes() */
|
||||
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink) {
|
||||
if (!(val & VIDEO_DIP_ENABLE))
|
||||
return;
|
||||
val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI);
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set both together, unset both together: see the spec. */
|
||||
val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
|
||||
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
|
||||
VIDEO_DIP_ENABLE_GCP);
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
static void vlv_set_infoframes(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
assert_hdmi_port_disabled(intel_hdmi);
|
||||
|
||||
/* See the big comment in g4x_set_infoframes() */
|
||||
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink) {
|
||||
if (!(val & VIDEO_DIP_ENABLE))
|
||||
return;
|
||||
val &= ~VIDEO_DIP_ENABLE;
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
return;
|
||||
}
|
||||
|
||||
val |= VIDEO_DIP_ENABLE;
|
||||
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
|
||||
VIDEO_DIP_ENABLE_GCP);
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
static void hsw_set_infoframes(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 val = I915_READ(reg);
|
||||
|
||||
assert_hdmi_port_disabled(intel_hdmi);
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink) {
|
||||
I915_WRITE(reg, 0);
|
||||
POSTING_READ(reg);
|
||||
return;
|
||||
}
|
||||
|
||||
val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
|
||||
VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW);
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
POSTING_READ(reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
@ -355,7 +591,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 sdvox;
|
||||
|
||||
sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
|
||||
sdvox = SDVO_ENCODING_HDMI;
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
sdvox |= intel_hdmi->color_range;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
@ -373,7 +609,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
sdvox |= HDMI_MODE_SELECT;
|
||||
|
||||
if (intel_hdmi->has_audio) {
|
||||
DRM_DEBUG_KMS("Enabling HDMI audio on pipe %c\n",
|
||||
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
sdvox |= SDVO_AUDIO_ENABLE;
|
||||
sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
|
||||
@ -382,21 +618,41 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
|
||||
else if (intel_crtc->pipe == 1)
|
||||
else if (intel_crtc->pipe == PIPE_B)
|
||||
sdvox |= SDVO_PIPE_B_SELECT;
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
intel_hdmi->set_infoframes(encoder, adjusted_mode);
|
||||
}
|
||||
|
||||
static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
||||
static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
|
||||
enum pipe *pipe)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
u32 tmp;
|
||||
|
||||
tmp = I915_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
if (!(tmp & SDVO_ENABLE))
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
*pipe = PORT_TO_PIPE_CPT(tmp);
|
||||
else
|
||||
*pipe = PORT_TO_PIPE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_enable_hdmi(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
u32 temp;
|
||||
u32 enable_bits = SDVO_ENABLE;
|
||||
|
||||
@ -405,6 +661,17 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
||||
|
||||
temp = I915_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* HW workaround for IBX, we need to move the port to transcoder A
|
||||
* before disabling it. */
|
||||
if (HAS_PCH_IBX(dev)) {
|
||||
struct drm_crtc *crtc = encoder->base.crtc;
|
||||
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
|
||||
|
||||
/* Restore the transcoder select bit. */
|
||||
if (pipe == PIPE_B)
|
||||
enable_bits |= SDVO_PIPE_B_SELECT;
|
||||
}
|
||||
|
||||
/* HW workaround, need to toggle enable bit off and on for 12bpc, but
|
||||
* we do this anyway which shows more stable in testing.
|
||||
*/
|
||||
@ -413,11 +680,63 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
}
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
temp &= ~enable_bits;
|
||||
} else {
|
||||
temp |= enable_bits;
|
||||
temp |= enable_bits;
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* HW workaround, need to write this twice for issue that may result
|
||||
* in first write getting masked.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_disable_hdmi(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
u32 temp;
|
||||
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
|
||||
|
||||
temp = I915_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* HW workaround for IBX, we need to move the port to transcoder A
|
||||
* before disabling it. */
|
||||
if (HAS_PCH_IBX(dev)) {
|
||||
struct drm_crtc *crtc = encoder->base.crtc;
|
||||
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
|
||||
|
||||
if (temp & SDVO_PIPE_B_SELECT) {
|
||||
temp &= ~SDVO_PIPE_B_SELECT;
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* Again we need to write this twice. */
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* Transcoder selection bits only update
|
||||
* effectively on vblank. */
|
||||
if (crtc)
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
else
|
||||
DRM_MSLEEP(50);
|
||||
}
|
||||
}
|
||||
|
||||
/* HW workaround, need to toggle enable bit off and on for 12bpc, but
|
||||
* we do this anyway which shows more stable in testing.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
}
|
||||
|
||||
temp &= ~enable_bits;
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
@ -445,25 +764,53 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector,
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi)
|
||||
{
|
||||
struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t bit;
|
||||
|
||||
switch (intel_hdmi->sdvox_reg) {
|
||||
case SDVOB:
|
||||
bit = HDMIB_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
case SDVOC:
|
||||
bit = HDMIC_HOTPLUG_LIVE_STATUS;
|
||||
break;
|
||||
default:
|
||||
bit = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return I915_READ(PORT_HOTPLUG_STAT) & bit;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
hdmi_to_dig_port(intel_hdmi);
|
||||
struct intel_encoder *intel_encoder = &intel_dig_port->base;
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
struct edid *edid;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
|
||||
return status;
|
||||
|
||||
intel_hdmi->has_hdmi_sink = false;
|
||||
intel_hdmi->has_audio = false;
|
||||
edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
@ -474,16 +821,13 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
|
||||
}
|
||||
free(edid, DRM_MEM_KMS);
|
||||
} else {
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] got no edid, ddc port %d\n",
|
||||
connector->base.id, drm_get_connector_name(connector),
|
||||
intel_hdmi->ddc_bus);
|
||||
}
|
||||
|
||||
if (status == connector_status_connected) {
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
|
||||
intel_hdmi->has_audio =
|
||||
(intel_hdmi->force_audio == HDMI_AUDIO_ON);
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -517,7 +861,6 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL)
|
||||
has_audio = drm_detect_monitor_audio(edid);
|
||||
|
||||
free(edid, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
@ -526,10 +869,12 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
|
||||
|
||||
static int
|
||||
intel_hdmi_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
hdmi_to_dig_port(intel_hdmi);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
int ret;
|
||||
|
||||
@ -569,11 +914,10 @@ intel_hdmi_set_property(struct drm_connector *connector,
|
||||
return -EINVAL;
|
||||
|
||||
done:
|
||||
if (intel_hdmi->base.base.crtc) {
|
||||
struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y,
|
||||
crtc->fb);
|
||||
if (intel_dig_port->base.base.crtc) {
|
||||
struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -581,31 +925,18 @@ done:
|
||||
|
||||
static void intel_hdmi_destroy(struct drm_connector *connector)
|
||||
{
|
||||
#if 0
|
||||
drm_sysfs_connector_remove(connector);
|
||||
#endif
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
|
||||
.dpms = intel_ddi_dpms,
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.mode_set = intel_ddi_mode_set,
|
||||
.commit = intel_encoder_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
|
||||
.dpms = intel_hdmi_dpms,
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.mode_set = intel_hdmi_mode_set,
|
||||
.commit = intel_encoder_commit,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = intel_connector_dpms,
|
||||
.detect = intel_hdmi_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = intel_hdmi_set_property,
|
||||
@ -629,117 +960,68 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
|
||||
intel_attach_broadcast_rgb_property(connector);
|
||||
}
|
||||
|
||||
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||||
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
struct intel_connector *intel_connector)
|
||||
{
|
||||
struct drm_connector *connector = &intel_connector->base;
|
||||
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
|
||||
struct intel_encoder *intel_encoder = &intel_dig_port->base;
|
||||
struct drm_device *dev = intel_encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_connector *connector;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct intel_connector *intel_connector;
|
||||
struct intel_hdmi *intel_hdmi;
|
||||
int i;
|
||||
enum port port = intel_dig_port->port;
|
||||
|
||||
intel_hdmi = malloc(sizeof(struct intel_hdmi), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
intel_encoder = &intel_hdmi->base;
|
||||
drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
connector = &intel_connector->base;
|
||||
drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
if (sdvox_reg == SDVOB) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
|
||||
switch (port) {
|
||||
case PORT_B:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == SDVOC) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
|
||||
break;
|
||||
case PORT_C:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == HDMIB) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == HDMIC) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == HDMID) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
|
||||
break;
|
||||
case PORT_D:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) {
|
||||
DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n");
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
intel_hdmi->ddi_port = PORT_B;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) {
|
||||
DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n");
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
intel_hdmi->ddi_port = PORT_C;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) {
|
||||
DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n");
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
intel_hdmi->ddi_port = PORT_D;
|
||||
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
|
||||
} else {
|
||||
/* If we got an unknown sdvox_reg, things are pretty much broken
|
||||
* in a way that we should let the kernel know about it */
|
||||
DRM_DEBUG_KMS("unknown sdvox_reg %d\n", sdvox_reg);
|
||||
break;
|
||||
case PORT_A:
|
||||
/* Internal port only for eDP. */
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
intel_hdmi->sdvox_reg = sdvox_reg;
|
||||
if (!HAS_PCH_SPLIT(dev)) {
|
||||
intel_hdmi->write_infoframe = g4x_write_infoframe;
|
||||
I915_WRITE(VIDEO_DIP_CTL, 0);
|
||||
intel_hdmi->set_infoframes = g4x_set_infoframes;
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
intel_hdmi->write_infoframe = vlv_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0);
|
||||
intel_hdmi->set_infoframes = vlv_set_infoframes;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
/* FIXME: Haswell has a new set of DIP frame registers, but we are
|
||||
* just doing the minimal required for HDMI to work at this stage.
|
||||
*/
|
||||
intel_hdmi->write_infoframe = hsw_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0);
|
||||
intel_hdmi->set_infoframes = hsw_set_infoframes;
|
||||
} else if (HAS_PCH_IBX(dev)) {
|
||||
intel_hdmi->write_infoframe = ibx_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
|
||||
intel_hdmi->set_infoframes = ibx_set_infoframes;
|
||||
} else {
|
||||
intel_hdmi->write_infoframe = cpt_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
|
||||
intel_hdmi->set_infoframes = cpt_set_infoframes;
|
||||
}
|
||||
|
||||
if (IS_HASWELL(dev))
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
|
||||
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
|
||||
else
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
|
||||
intel_hdmi_add_properties(intel_hdmi, connector);
|
||||
|
||||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
#if 0
|
||||
drm_sysfs_connector_add(connector);
|
||||
#endif
|
||||
|
||||
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
|
||||
* 0xd. Failure to do so will result in spurious interrupts being
|
||||
@ -750,3 +1032,42 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||||
I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
|
||||
}
|
||||
}
|
||||
|
||||
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct drm_encoder *encoder;
|
||||
struct intel_connector *intel_connector;
|
||||
|
||||
intel_dig_port = malloc(sizeof(struct intel_digital_port), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_dig_port)
|
||||
return;
|
||||
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_connector) {
|
||||
free(intel_dig_port, DRM_MEM_KMS);
|
||||
return;
|
||||
}
|
||||
|
||||
intel_encoder = &intel_dig_port->base;
|
||||
encoder = &intel_encoder->base;
|
||||
|
||||
drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
|
||||
|
||||
intel_encoder->enable = intel_enable_hdmi;
|
||||
intel_encoder->disable = intel_disable_hdmi;
|
||||
intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
intel_encoder->cloneable = false;
|
||||
|
||||
intel_dig_port->port = port;
|
||||
intel_dig_port->hdmi.sdvox_reg = sdvox_reg;
|
||||
intel_dig_port->dp.output_reg = 0;
|
||||
|
||||
intel_hdmi_init_connector(intel_dig_port, intel_connector);
|
||||
}
|
||||
|
@ -25,50 +25,20 @@
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||||
*
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Konstantin Belousov under sponsorship from
|
||||
* the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/iicbus/iic.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include "iicbus_if.h"
|
||||
#include "iicbb_if.h"
|
||||
|
||||
static void intel_teardown_gmbus_m(struct drm_device *dev, int m);
|
||||
|
||||
struct gmbus_port {
|
||||
const char *name;
|
||||
int reg;
|
||||
@ -87,17 +57,37 @@ static const struct gmbus_port gmbus_ports[] = {
|
||||
|
||||
#define I2C_RISEFALL_TIME 10
|
||||
|
||||
/*
|
||||
* FIXME Linux<->FreeBSD: dvo_ns2501.C wants the struct intel_gmbus
|
||||
* below but it just has the device_t at hand. It still uses
|
||||
* device_get_softc(), thus expects struct intel_gmbus to remain the
|
||||
* first member.
|
||||
*/
|
||||
struct intel_iic_softc {
|
||||
struct drm_device *drm_dev;
|
||||
struct intel_gmbus *bus;
|
||||
device_t iic_dev;
|
||||
bool force_bit_dev;
|
||||
char name[32];
|
||||
uint32_t reg;
|
||||
uint32_t reg0;
|
||||
};
|
||||
|
||||
static inline struct intel_gmbus *
|
||||
to_intel_gmbus(device_t i2c)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
|
||||
sc = device_get_softc(i2c);
|
||||
return sc->bus;
|
||||
}
|
||||
|
||||
bool intel_gmbus_is_forced_bit(device_t adapter)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
|
||||
return bus->force_bit;
|
||||
}
|
||||
|
||||
void
|
||||
intel_iic_reset(struct drm_device *dev)
|
||||
intel_i2c_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0);
|
||||
@ -110,9 +100,9 @@ intel_iicbus_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr)
|
||||
struct drm_device *dev;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev = sc->drm_dev;
|
||||
dev = sc->bus->dev_priv->dev;
|
||||
|
||||
intel_iic_reset(dev);
|
||||
intel_i2c_reset(dev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -132,15 +122,15 @@ static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
|
||||
I915_WRITE(DSPCLK_GATE_D, val);
|
||||
}
|
||||
|
||||
static u32 get_reserved(device_t idev)
|
||||
static u32 get_reserved(struct intel_gmbus *bus)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(idev);
|
||||
struct drm_device *dev = sc->drm_dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
u32 reserved = 0;
|
||||
|
||||
/* On most chips, these bits must be preserved in software. */
|
||||
if (!IS_I830(dev) && !IS_845G(dev))
|
||||
reserved = I915_READ_NOTRACE(sc->reg) &
|
||||
reserved = I915_READ_NOTRACE(bus->gpio_reg) &
|
||||
(GPIO_DATA_PULLUP_DISABLE |
|
||||
GPIO_CLOCK_PULLUP_DISABLE);
|
||||
|
||||
@ -150,28 +140,31 @@ static u32 get_reserved(device_t idev)
|
||||
static int get_clock(device_t adapter)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
u32 reserved = get_reserved(adapter);
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_CLOCK_DIR_MASK);
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved);
|
||||
return ((I915_READ_NOTRACE(sc->reg) & GPIO_CLOCK_VAL_IN) != 0);
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
u32 reserved = get_reserved(bus);
|
||||
I915_WRITE_NOTRACE(bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
|
||||
I915_WRITE_NOTRACE(bus->gpio_reg, reserved);
|
||||
return (I915_READ_NOTRACE(bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
|
||||
}
|
||||
|
||||
static int get_data(device_t adapter)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
u32 reserved = get_reserved(adapter);
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_DATA_DIR_MASK);
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved);
|
||||
return ((I915_READ_NOTRACE(sc->reg) & GPIO_DATA_VAL_IN) != 0);
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
u32 reserved = get_reserved(bus);
|
||||
I915_WRITE_NOTRACE(bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
|
||||
I915_WRITE_NOTRACE(bus->gpio_reg, reserved);
|
||||
return (I915_READ_NOTRACE(bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
|
||||
}
|
||||
|
||||
static void set_clock(device_t adapter, int state_high)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
u32 reserved = get_reserved(adapter);
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
u32 reserved = get_reserved(bus);
|
||||
u32 clock_bits;
|
||||
|
||||
if (state_high)
|
||||
@ -180,15 +173,16 @@ static void set_clock(device_t adapter, int state_high)
|
||||
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
|
||||
GPIO_CLOCK_VAL_MASK;
|
||||
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | clock_bits);
|
||||
POSTING_READ(sc->reg);
|
||||
I915_WRITE_NOTRACE(bus->gpio_reg, reserved | clock_bits);
|
||||
POSTING_READ(bus->gpio_reg);
|
||||
}
|
||||
|
||||
static void set_data(device_t adapter, int state_high)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
u32 reserved = get_reserved(adapter);
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
u32 reserved = get_reserved(bus);
|
||||
u32 data_bits;
|
||||
|
||||
if (state_high)
|
||||
@ -197,21 +191,22 @@ static void set_data(device_t adapter, int state_high)
|
||||
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
|
||||
GPIO_DATA_VAL_MASK;
|
||||
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | data_bits);
|
||||
POSTING_READ(sc->reg);
|
||||
I915_WRITE_NOTRACE(bus->gpio_reg, reserved | data_bits);
|
||||
POSTING_READ(bus->gpio_reg);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_gpio_pre_xfer(device_t adapter)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
|
||||
intel_iic_reset(sc->drm_dev);
|
||||
intel_i2c_reset(dev_priv->dev);
|
||||
intel_i2c_quirk_set(dev_priv, true);
|
||||
IICBB_SETSDA(adapter, 1);
|
||||
IICBB_SETSCL(adapter, 1);
|
||||
DELAY(I2C_RISEFALL_TIME);
|
||||
udelay(I2C_RISEFALL_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -219,13 +214,23 @@ static void
|
||||
intel_gpio_post_xfer(device_t adapter)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
|
||||
IICBB_SETSDA(adapter, 1);
|
||||
IICBB_SETSCL(adapter, 1);
|
||||
intel_i2c_quirk_set(dev_priv, false);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
|
||||
/* -1 to map pin pair to gmbus index */
|
||||
bus->gpio_reg = dev_priv->gpio_mmio_base + gmbus_ports[pin - 1].reg;
|
||||
}
|
||||
|
||||
static int
|
||||
gmbus_xfer_read(struct drm_i915_private *dev_priv, struct iic_msg *msg,
|
||||
u32 gmbus1_index)
|
||||
@ -245,10 +250,9 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct iic_msg *msg,
|
||||
u32 val, loop = 0;
|
||||
u32 gmbus2;
|
||||
|
||||
ret = _intel_wait_for(sc->drm_dev,
|
||||
((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY)),
|
||||
50, 1, "915gbr");
|
||||
ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY),
|
||||
50);
|
||||
if (ret)
|
||||
return -ETIMEDOUT;
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
@ -295,10 +299,9 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct iic_msg *msg)
|
||||
|
||||
I915_WRITE(GMBUS3 + reg_offset, val);
|
||||
|
||||
ret = _intel_wait_for(sc->drm_dev,
|
||||
((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY)),
|
||||
50, 1, "915gbw");
|
||||
ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY),
|
||||
50);
|
||||
if (ret)
|
||||
return -ETIMEDOUT;
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
@ -315,8 +318,8 @@ static bool
|
||||
gmbus_is_index_read(struct iic_msg *msgs, int i, int num)
|
||||
{
|
||||
return (i + 1 < num &&
|
||||
!(msgs[i].flags & IIC_M_RD) && msgs[i].len <= 2 &&
|
||||
(msgs[i + 1].flags & IIC_M_RD));
|
||||
!(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 &&
|
||||
(msgs[i + 1].flags & I2C_M_RD));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -353,43 +356,42 @@ gmbus_xfer(device_t adapter,
|
||||
uint32_t num)
|
||||
{
|
||||
struct intel_iic_softc *sc = device_get_softc(adapter);
|
||||
struct drm_i915_private *dev_priv = sc->drm_dev->dev_private;
|
||||
int error, i, ret, reg_offset, unit;
|
||||
struct intel_gmbus *bus = sc->bus;
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
int i, reg_offset;
|
||||
int ret = 0;
|
||||
|
||||
error = 0;
|
||||
unit = device_get_unit(adapter);
|
||||
sx_xlock(&dev_priv->gmbus_mutex);
|
||||
|
||||
sx_xlock(&dev_priv->gmbus_sx);
|
||||
if (sc->force_bit_dev) {
|
||||
error = -IICBUS_TRANSFER(dev_priv->bbbus[unit], msgs, num);
|
||||
if (bus->force_bit) {
|
||||
ret = -IICBUS_TRANSFER(bus->bbbus, msgs, num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg_offset = dev_priv->gpio_mmio_base;
|
||||
|
||||
I915_WRITE(GMBUS0 + reg_offset, sc->reg0);
|
||||
I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
u32 gmbus2;
|
||||
|
||||
if (gmbus_is_index_read(msgs, i, num)) {
|
||||
error = gmbus_xfer_index_read(dev_priv, &msgs[i]);
|
||||
ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
|
||||
i += 1; /* set i to the index of the read xfer */
|
||||
} else if (msgs[i].flags & IIC_M_RD) {
|
||||
error = gmbus_xfer_read(dev_priv, &msgs[i], 0);
|
||||
} else if (msgs[i].flags & I2C_M_RD) {
|
||||
ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
|
||||
} else {
|
||||
error = gmbus_xfer_write(dev_priv, &msgs[i]);
|
||||
ret = gmbus_xfer_write(dev_priv, &msgs[i]);
|
||||
}
|
||||
|
||||
if (error == -ETIMEDOUT)
|
||||
if (ret == -ETIMEDOUT)
|
||||
goto timeout;
|
||||
if (error == -ENXIO)
|
||||
if (ret == -ENXIO)
|
||||
goto clear_err;
|
||||
|
||||
ret = _intel_wait_for(sc->drm_dev,
|
||||
((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE)),
|
||||
50, 1, "915gbh");
|
||||
ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
|
||||
(GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
|
||||
50);
|
||||
if (ret)
|
||||
goto timeout;
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
@ -406,12 +408,11 @@ gmbus_xfer(device_t adapter,
|
||||
* We will re-enable it at the start of the next xfer,
|
||||
* till then let it sleep.
|
||||
*/
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10, 1, "915gbu")) {
|
||||
if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10)) {
|
||||
DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
|
||||
sc->name);
|
||||
error = -ETIMEDOUT;
|
||||
device_get_desc(adapter));
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
I915_WRITE(GMBUS0 + reg_offset, 0);
|
||||
goto out;
|
||||
@ -421,11 +422,22 @@ clear_err:
|
||||
* Wait for bus to IDLE before clearing NAK.
|
||||
* If we clear the NAK while bus is still active, then it will stay
|
||||
* active and the next transaction may fail.
|
||||
*
|
||||
* If no ACK is received during the address phase of a transaction, the
|
||||
* adapter must report -ENXIO. It is not clear what to return if no ACK
|
||||
* is received at other times. But we have to be careful to not return
|
||||
* spurious -ENXIO because that will prevent i2c and drm edid functions
|
||||
* from retrying. So return -ENXIO only when gmbus properly quiescents -
|
||||
* timing out seems to happen when there _is_ a ddc chip present, but
|
||||
* it's slow responding and only answers on the 2nd retry.
|
||||
*/
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10, 1, "915gbu"))
|
||||
DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n", sc->name);
|
||||
ret = -ENXIO;
|
||||
if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10)) {
|
||||
DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
|
||||
device_get_desc(adapter));
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Toggle the Software Clear Interrupt bit. This has the effect
|
||||
* of resetting the GMBUS controller and so clearing the
|
||||
@ -436,31 +448,23 @@ clear_err:
|
||||
I915_WRITE(GMBUS0 + reg_offset, 0);
|
||||
|
||||
DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
|
||||
sc->name, msgs[i].slave,
|
||||
(msgs[i].flags & IIC_M_RD) ? 'r' : 'w', msgs[i].len);
|
||||
device_get_desc(adapter), msgs[i].slave >> 1,
|
||||
(msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
|
||||
|
||||
/*
|
||||
* If no ACK is received during the address phase of a transaction,
|
||||
* the adapter must report -ENXIO.
|
||||
* It is not clear what to return if no ACK is received at other times.
|
||||
* So, we always return -ENXIO in all NAK cases, to ensure we send
|
||||
* it at least during the one case that is specified.
|
||||
*/
|
||||
error = -ENXIO;
|
||||
goto out;
|
||||
|
||||
timeout:
|
||||
DRM_INFO("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
|
||||
sc->name, sc->reg0 & 0xff);
|
||||
device_get_desc(adapter), bus->reg0 & 0xff);
|
||||
I915_WRITE(GMBUS0 + reg_offset, 0);
|
||||
|
||||
/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
|
||||
sc->force_bit_dev = true;
|
||||
error = -IICBUS_TRANSFER(dev_priv->bbbus[unit], msgs, num);
|
||||
bus->force_bit = 1;
|
||||
ret = -IICBUS_TRANSFER(bus->bbbus, msgs, num);
|
||||
|
||||
out:
|
||||
sx_xunlock(&dev_priv->gmbus_sx);
|
||||
return -error;
|
||||
sx_xunlock(&dev_priv->gmbus_mutex);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -473,32 +477,23 @@ intel_gmbus_probe(device_t dev)
|
||||
static int
|
||||
intel_gmbus_attach(device_t idev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
int pin, port;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
sc->drm_dev = device_get_softc(device_get_parent(idev));
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
pin = device_get_unit(idev);
|
||||
port = pin + 1;
|
||||
port = pin + 1; /* +1 to map gmbus index to pin pair */
|
||||
|
||||
snprintf(sc->name, sizeof(sc->name), "gmbus %s",
|
||||
snprintf(sc->name, sizeof(sc->name), "i915 gmbus %s",
|
||||
intel_gmbus_is_port_valid(port) ? gmbus_ports[pin].name :
|
||||
"reserved");
|
||||
device_set_desc(idev, sc->name);
|
||||
|
||||
/* By default use a conservative clock rate */
|
||||
sc->reg0 = port | GMBUS_RATE_100KHZ;
|
||||
|
||||
/* gmbus seems to be broken on i830 */
|
||||
if (IS_I830(sc->drm_dev))
|
||||
sc->force_bit_dev = true;
|
||||
#if 0
|
||||
if (IS_GEN2(sc->drm_dev)) {
|
||||
sc->force_bit_dev = true;
|
||||
}
|
||||
#endif
|
||||
dev = device_get_softc(device_get_parent(idev));
|
||||
dev_priv = dev->dev_private;
|
||||
sc->bus = &dev_priv->gmbus[pin];
|
||||
|
||||
/* add bus interface device */
|
||||
sc->iic_dev = device_add_child(idev, "iicbus", -1);
|
||||
@ -513,78 +508,13 @@ intel_gmbus_attach(device_t idev)
|
||||
static int
|
||||
intel_gmbus_detach(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
device_t child;
|
||||
int u;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
u = device_get_unit(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
child = sc->iic_dev;
|
||||
bus_generic_detach(idev);
|
||||
if (child != NULL)
|
||||
device_delete_child(idev, child);
|
||||
device_delete_children(idev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_probe(device_t dev)
|
||||
{
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_attach(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
int pin, port;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
sc->drm_dev = device_get_softc(device_get_parent(idev));
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
pin = device_get_unit(idev);
|
||||
port = pin + 1;
|
||||
|
||||
snprintf(sc->name, sizeof(sc->name), "i915 iicbb %s",
|
||||
intel_gmbus_is_port_valid(port) ? gmbus_ports[pin].name :
|
||||
"reserved");
|
||||
device_set_desc(idev, sc->name);
|
||||
|
||||
if (!intel_gmbus_is_port_valid(port))
|
||||
pin = 1 ; /* GPIOA, VGA */
|
||||
sc->reg0 = pin | GMBUS_RATE_100KHZ;
|
||||
sc->reg = dev_priv->gpio_mmio_base + gmbus_ports[pin].reg;
|
||||
|
||||
/* add generic bit-banging code */
|
||||
sc->iic_dev = device_add_child(idev, "iicbb", -1);
|
||||
if (sc->iic_dev == NULL)
|
||||
return (ENXIO);
|
||||
device_quiet(sc->iic_dev);
|
||||
bus_generic_attach(idev);
|
||||
iicbus_set_nostop(idev, true);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_detach(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
device_t child;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
child = sc->iic_dev;
|
||||
bus_generic_detach(idev);
|
||||
if (child)
|
||||
device_delete_child(idev, child);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t intel_gmbus_methods[] = {
|
||||
DEVMETHOD(device_probe, intel_gmbus_probe),
|
||||
DEVMETHOD(device_attach, intel_gmbus_attach),
|
||||
@ -603,6 +533,55 @@ DRIVER_MODULE_ORDERED(intel_gmbus, drmn, intel_gmbus_driver,
|
||||
intel_gmbus_devclass, 0, 0, SI_ORDER_FIRST);
|
||||
DRIVER_MODULE(iicbus, intel_gmbus, iicbus_driver, iicbus_devclass, 0, 0);
|
||||
|
||||
static int
|
||||
intel_iicbb_probe(device_t dev)
|
||||
{
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_attach(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
int pin, port;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
pin = device_get_unit(idev);
|
||||
port = pin + 1;
|
||||
|
||||
snprintf(sc->name, sizeof(sc->name), "i915 iicbb %s",
|
||||
intel_gmbus_is_port_valid(port) ? gmbus_ports[pin].name :
|
||||
"reserved");
|
||||
device_set_desc(idev, sc->name);
|
||||
|
||||
dev = device_get_softc(device_get_parent(idev));
|
||||
dev_priv = dev->dev_private;
|
||||
sc->bus = &dev_priv->gmbus[pin];
|
||||
|
||||
/* add generic bit-banging code */
|
||||
sc->iic_dev = device_add_child(idev, "iicbb", -1);
|
||||
if (sc->iic_dev == NULL)
|
||||
return (ENXIO);
|
||||
device_quiet(sc->iic_dev);
|
||||
bus_generic_attach(idev);
|
||||
iicbus_set_nostop(idev, true);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_detach(device_t idev)
|
||||
{
|
||||
|
||||
bus_generic_detach(idev);
|
||||
device_delete_children(idev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t intel_iicbb_methods[] = {
|
||||
DEVMETHOD(device_probe, intel_iicbb_probe),
|
||||
DEVMETHOD(device_attach, intel_iicbb_attach),
|
||||
@ -631,6 +610,10 @@ DRIVER_MODULE_ORDERED(intel_iicbb, drmn, intel_iicbb_driver,
|
||||
intel_iicbb_devclass, 0, 0, SI_ORDER_FIRST);
|
||||
DRIVER_MODULE(iicbb, intel_iicbb, iicbb_driver, iicbb_devclass, 0, 0);
|
||||
|
||||
/**
|
||||
* intel_gmbus_setup - instantiate all Intel i2c GMBuses
|
||||
* @dev: DRM device
|
||||
*/
|
||||
int intel_setup_gmbus(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -642,7 +625,7 @@ int intel_setup_gmbus(struct drm_device *dev)
|
||||
else
|
||||
dev_priv->gpio_mmio_base = 0;
|
||||
|
||||
sx_init(&dev_priv->gmbus_sx, "gmbus");
|
||||
sx_init(&dev_priv->gmbus_mutex, "gmbus");
|
||||
|
||||
/*
|
||||
* The Giant there is recursed, most likely. Normally, the
|
||||
@ -650,29 +633,46 @@ int intel_setup_gmbus(struct drm_device *dev)
|
||||
* driver.
|
||||
*/
|
||||
mtx_lock(&Giant);
|
||||
for (i = 0; i <= GMBUS_NUM_PORTS; i++) {
|
||||
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
|
||||
struct intel_gmbus *bus = &dev_priv->gmbus[i];
|
||||
u32 port = i + 1; /* +1 to map gmbus index to pin pair */
|
||||
|
||||
bus->dev_priv = dev_priv;
|
||||
|
||||
/* By default use a conservative clock rate */
|
||||
bus->reg0 = port | GMBUS_RATE_100KHZ;
|
||||
|
||||
/* gmbus seems to be broken on i830 */
|
||||
if (IS_I830(dev))
|
||||
bus->force_bit = 1;
|
||||
|
||||
intel_gpio_setup(bus, port);
|
||||
|
||||
/*
|
||||
* bbbus_bridge
|
||||
*
|
||||
* Initialized bbbus_bridge before gmbus_bridge, since
|
||||
* gmbus may decide to force quirk transfer in the
|
||||
* attachment code.
|
||||
*/
|
||||
dev_priv->bbbus_bridge[i] = device_add_child(dev->dev,
|
||||
bus->bbbus_bridge = device_add_child(dev->dev,
|
||||
"intel_iicbb", i);
|
||||
if (dev_priv->bbbus_bridge[i] == NULL) {
|
||||
if (bus->bbbus_bridge == NULL) {
|
||||
DRM_ERROR("bbbus bridge %d creation failed\n", i);
|
||||
ret = -ENXIO;
|
||||
goto err;
|
||||
}
|
||||
device_quiet(dev_priv->bbbus_bridge[i]);
|
||||
ret = -device_probe_and_attach(dev_priv->bbbus_bridge[i]);
|
||||
device_quiet(bus->bbbus_bridge);
|
||||
ret = -device_probe_and_attach(bus->bbbus_bridge);
|
||||
if (ret != 0) {
|
||||
DRM_ERROR("bbbus bridge %d attach failed, %d\n", i,
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
iic_dev = device_find_child(dev_priv->bbbus_bridge[i], "iicbb",
|
||||
-1);
|
||||
/* bbbus */
|
||||
iic_dev = device_find_child(bus->bbbus_bridge,
|
||||
"iicbb", -1);
|
||||
if (iic_dev == NULL) {
|
||||
DRM_ERROR("bbbus bridge doesn't have iicbb child\n");
|
||||
goto err;
|
||||
@ -684,17 +684,18 @@ int intel_setup_gmbus(struct drm_device *dev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_priv->bbbus[i] = iic_dev;
|
||||
bus->bbbus = iic_dev;
|
||||
|
||||
dev_priv->gmbus_bridge[i] = device_add_child(dev->dev,
|
||||
/* gmbus_bridge */
|
||||
bus->gmbus_bridge = device_add_child(dev->dev,
|
||||
"intel_gmbus", i);
|
||||
if (dev_priv->gmbus_bridge[i] == NULL) {
|
||||
if (bus->gmbus_bridge == NULL) {
|
||||
DRM_ERROR("gmbus bridge %d creation failed\n", i);
|
||||
ret = -ENXIO;
|
||||
goto err;
|
||||
}
|
||||
device_quiet(dev_priv->gmbus_bridge[i]);
|
||||
ret = -device_probe_and_attach(dev_priv->gmbus_bridge[i]);
|
||||
device_quiet(bus->gmbus_bridge);
|
||||
ret = -device_probe_and_attach(bus->gmbus_bridge);
|
||||
if (ret != 0) {
|
||||
DRM_ERROR("gmbus bridge %d attach failed, %d\n", i,
|
||||
ret);
|
||||
@ -702,67 +703,84 @@ int intel_setup_gmbus(struct drm_device *dev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
iic_dev = device_find_child(dev_priv->gmbus_bridge[i],
|
||||
/* gmbus */
|
||||
iic_dev = device_find_child(bus->gmbus_bridge,
|
||||
"iicbus", -1);
|
||||
if (iic_dev == NULL) {
|
||||
DRM_ERROR("gmbus bridge doesn't have iicbus child\n");
|
||||
goto err;
|
||||
}
|
||||
dev_priv->gmbus[i] = iic_dev;
|
||||
|
||||
intel_iic_reset(dev);
|
||||
bus->gmbus = iic_dev;
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
intel_i2c_reset(dev_priv->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
intel_teardown_gmbus_m(dev, i);
|
||||
while (--i) {
|
||||
struct intel_gmbus *bus = &dev_priv->gmbus[i];
|
||||
if (bus->gmbus_bridge != NULL)
|
||||
device_delete_child(dev->dev, bus->gmbus_bridge);
|
||||
if (bus->bbbus_bridge != NULL)
|
||||
device_delete_child(dev->dev, bus->bbbus_bridge);
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
sx_destroy(&dev_priv->gmbus_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_t intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
|
||||
unsigned port)
|
||||
{
|
||||
|
||||
if (!intel_gmbus_is_port_valid(port))
|
||||
DRM_ERROR("GMBUS get adapter %d: invalid port\n", port);
|
||||
return (intel_gmbus_is_port_valid(port) ? dev_priv->gmbus[port - 1] :
|
||||
NULL);
|
||||
WARN_ON(!intel_gmbus_is_port_valid(port));
|
||||
/* -1 to map pin pair to gmbus index */
|
||||
return (intel_gmbus_is_port_valid(port)) ?
|
||||
dev_priv->gmbus[port - 1].gmbus : NULL;
|
||||
}
|
||||
|
||||
void intel_gmbus_set_speed(device_t adapter, int speed)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct intel_gmbus *bus = to_intel_gmbus(adapter);
|
||||
|
||||
sc = device_get_softc(device_get_parent(adapter));
|
||||
|
||||
sc->reg0 = (sc->reg0 & ~(0x3 << 8)) | speed;
|
||||
bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | speed;
|
||||
}
|
||||
|
||||
void intel_gmbus_force_bit(device_t adapter, bool force_bit)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct intel_gmbus *bus = to_intel_gmbus(adapter);
|
||||
|
||||
sc = device_get_softc(device_get_parent(adapter));
|
||||
sc->force_bit_dev = force_bit;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_teardown_gmbus_m(struct drm_device *dev, int m)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
sx_destroy(&dev_priv->gmbus_sx);
|
||||
bus->force_bit += force_bit ? 1 : -1;
|
||||
DRM_DEBUG_KMS("%sabling bit-banging on %s. force bit now %d\n",
|
||||
force_bit ? "en" : "dis", device_get_desc(adapter),
|
||||
bus->force_bit);
|
||||
}
|
||||
|
||||
void intel_teardown_gmbus(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
intel_teardown_gmbus_m(dev, GMBUS_NUM_PORTS);
|
||||
mtx_unlock(&Giant);
|
||||
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
|
||||
struct intel_gmbus *bus = &dev_priv->gmbus[i];
|
||||
|
||||
mtx_lock(&Giant);
|
||||
ret = device_delete_child(dev->dev, bus->gmbus_bridge);
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
KASSERT(ret == 0, ("unable to detach iic gmbus %s: %d",
|
||||
device_get_desc(bus->gmbus_bridge), ret));
|
||||
|
||||
mtx_lock(&Giant);
|
||||
ret = device_delete_child(dev->dev, bus->bbbus_bridge);
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
KASSERT(ret == 0, ("unable to detach iic bbbus %s: %d",
|
||||
device_get_desc(bus->bbbus_bridge), ret));
|
||||
}
|
||||
|
||||
sx_destroy(&dev_priv->gmbus_mutex);
|
||||
}
|
||||
|
@ -31,44 +31,75 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
/* Private structure for the integrated LVDS support */
|
||||
struct intel_lvds {
|
||||
struct intel_lvds_connector {
|
||||
struct intel_connector base;
|
||||
|
||||
#ifdef FREEBSD_WIP
|
||||
struct notifier_block lid_notifier;
|
||||
#endif /* FREEBSD_WIP */
|
||||
};
|
||||
|
||||
struct intel_lvds_encoder {
|
||||
struct intel_encoder base;
|
||||
|
||||
struct edid *edid;
|
||||
|
||||
int fitting_mode;
|
||||
u32 pfit_control;
|
||||
u32 pfit_pgm_ratios;
|
||||
bool pfit_dirty;
|
||||
|
||||
struct drm_display_mode *fixed_mode;
|
||||
struct intel_lvds_connector *attached_connector;
|
||||
};
|
||||
|
||||
static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder)
|
||||
static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct intel_lvds, base.base);
|
||||
return container_of(encoder, struct intel_lvds_encoder, base.base);
|
||||
}
|
||||
|
||||
static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
|
||||
static struct intel_lvds_connector *to_lvds_connector(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(intel_attached_encoder(connector),
|
||||
struct intel_lvds, base);
|
||||
return container_of(connector, struct intel_lvds_connector, base.base);
|
||||
}
|
||||
|
||||
static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
|
||||
enum pipe *pipe)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 lvds_reg, tmp;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
lvds_reg = PCH_LVDS;
|
||||
} else {
|
||||
lvds_reg = LVDS;
|
||||
}
|
||||
|
||||
tmp = I915_READ(lvds_reg);
|
||||
|
||||
if (!(tmp & LVDS_PORT_EN))
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
*pipe = PORT_TO_PIPE_CPT(tmp);
|
||||
else
|
||||
*pipe = PORT_TO_PIPE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the power state for the panel.
|
||||
*/
|
||||
static void intel_lvds_enable(struct intel_lvds *intel_lvds)
|
||||
static void intel_enable_lvds(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = intel_lvds->base.base.dev;
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 ctl_reg, lvds_reg, stat_reg;
|
||||
|
||||
@ -84,7 +115,7 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
|
||||
|
||||
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
|
||||
|
||||
if (intel_lvds->pfit_dirty) {
|
||||
if (lvds_encoder->pfit_dirty) {
|
||||
/*
|
||||
* Enable automatic panel scaling so that non-native modes
|
||||
* fill the screen. The panel fitter should only be
|
||||
@ -92,27 +123,26 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
|
||||
* register description and PRM.
|
||||
*/
|
||||
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
|
||||
intel_lvds->pfit_control,
|
||||
intel_lvds->pfit_pgm_ratios);
|
||||
lvds_encoder->pfit_control,
|
||||
lvds_encoder->pfit_pgm_ratios);
|
||||
|
||||
I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
|
||||
I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
|
||||
intel_lvds->pfit_dirty = false;
|
||||
I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios);
|
||||
I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control);
|
||||
lvds_encoder->pfit_dirty = false;
|
||||
}
|
||||
|
||||
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
|
||||
POSTING_READ(lvds_reg);
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(stat_reg) & PP_ON) == 0, 1000,
|
||||
1, "915lvds"))
|
||||
DRM_ERROR("timed out waiting for panel to power off\n");
|
||||
if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power on\n");
|
||||
|
||||
intel_panel_enable_backlight(dev);
|
||||
intel_panel_enable_backlight(dev, intel_crtc->pipe);
|
||||
}
|
||||
|
||||
static void intel_lvds_disable(struct intel_lvds *intel_lvds)
|
||||
static void intel_disable_lvds(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = intel_lvds->base.base.dev;
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 ctl_reg, lvds_reg, stat_reg;
|
||||
|
||||
@ -129,37 +159,23 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)
|
||||
intel_panel_disable_backlight(dev);
|
||||
|
||||
I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(stat_reg) & PP_ON) == 0, 1000,
|
||||
1, "915lvo"))
|
||||
if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
|
||||
DRM_ERROR("timed out waiting for panel to power off\n");
|
||||
|
||||
if (intel_lvds->pfit_control) {
|
||||
if (lvds_encoder->pfit_control) {
|
||||
I915_WRITE(PFIT_CONTROL, 0);
|
||||
intel_lvds->pfit_dirty = true;
|
||||
lvds_encoder->pfit_dirty = true;
|
||||
}
|
||||
|
||||
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
|
||||
POSTING_READ(lvds_reg);
|
||||
}
|
||||
|
||||
static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
|
||||
|
||||
if (mode == DRM_MODE_DPMS_ON)
|
||||
intel_lvds_enable(intel_lvds);
|
||||
else
|
||||
intel_lvds_disable(intel_lvds);
|
||||
|
||||
/* XXX: We never power down the LVDS pairs. */
|
||||
}
|
||||
|
||||
static int intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
|
||||
struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;
|
||||
struct intel_connector *intel_connector = to_intel_connector(connector);
|
||||
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
|
||||
|
||||
if (mode->hdisplay > fixed_mode->hdisplay)
|
||||
return MODE_PANEL;
|
||||
@ -235,9 +251,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
|
||||
struct drm_encoder *tmp_encoder;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
|
||||
struct intel_connector *intel_connector =
|
||||
&lvds_encoder->attached_connector->base;
|
||||
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
|
||||
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
|
||||
int pipe;
|
||||
|
||||
@ -247,14 +264,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Should never happen!! */
|
||||
list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) {
|
||||
DRM_ERROR("Can't enable LVDS and another "
|
||||
"encoder on the same pipe\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (intel_encoder_check_is_cloned(&lvds_encoder->base))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We have timings from the BIOS for the panel, put them in
|
||||
@ -262,10 +273,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
* with the panel scaling set up to source from the H/VDisplay
|
||||
* of the original mode.
|
||||
*/
|
||||
intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
|
||||
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
|
||||
adjusted_mode);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
|
||||
intel_pch_panel_fitting(dev,
|
||||
intel_connector->panel.fitting_mode,
|
||||
mode, adjusted_mode);
|
||||
return true;
|
||||
}
|
||||
@ -291,7 +304,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
|
||||
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||
|
||||
switch (intel_lvds->fitting_mode) {
|
||||
switch (intel_connector->panel.fitting_mode) {
|
||||
case DRM_MODE_SCALE_CENTER:
|
||||
/*
|
||||
* For centered modes, we have to calculate border widths &
|
||||
@ -389,11 +402,11 @@ out:
|
||||
if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
|
||||
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
|
||||
|
||||
if (pfit_control != intel_lvds->pfit_control ||
|
||||
pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
|
||||
intel_lvds->pfit_control = pfit_control;
|
||||
intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
|
||||
intel_lvds->pfit_dirty = true;
|
||||
if (pfit_control != lvds_encoder->pfit_control ||
|
||||
pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) {
|
||||
lvds_encoder->pfit_control = pfit_control;
|
||||
lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios;
|
||||
lvds_encoder->pfit_dirty = true;
|
||||
}
|
||||
dev_priv->lvds_border_bits = border;
|
||||
|
||||
@ -406,29 +419,6 @@ out:
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_lvds_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
|
||||
|
||||
/*
|
||||
* Prior to Ironlake, we must disable the pipe if we want to adjust
|
||||
* the panel fitter. However at all other times we can just reset
|
||||
* the registers regardless.
|
||||
*/
|
||||
if (!HAS_PCH_SPLIT(encoder->dev) && intel_lvds->pfit_dirty)
|
||||
intel_lvds_disable(intel_lvds);
|
||||
}
|
||||
|
||||
static void intel_lvds_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
|
||||
|
||||
/* Always do a full power on as we do not know what state
|
||||
* we were left in.
|
||||
*/
|
||||
intel_lvds_enable(intel_lvds);
|
||||
}
|
||||
|
||||
static void intel_lvds_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
@ -465,14 +455,15 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
|
||||
*/
|
||||
static int intel_lvds_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
|
||||
struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector);
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
if (intel_lvds->edid)
|
||||
return drm_add_edid_modes(connector, intel_lvds->edid);
|
||||
/* use cached edid if we have one */
|
||||
if (lvds_connector->base.edid)
|
||||
return drm_add_edid_modes(connector, lvds_connector->base.edid);
|
||||
|
||||
mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
|
||||
mode = drm_mode_duplicate(dev, lvds_connector->base.panel.fixed_mode);
|
||||
if (mode == NULL)
|
||||
return 0;
|
||||
|
||||
@ -500,7 +491,7 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = {
|
||||
{ } /* terminating entry */
|
||||
};
|
||||
|
||||
#ifdef NOTYET
|
||||
#ifdef FREEBSD_WIP
|
||||
/*
|
||||
* Lid events. Note the use of 'modeset_on_lid':
|
||||
* - we set it on lid close, and reset it on open
|
||||
@ -513,10 +504,11 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = {
|
||||
static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
void *unused)
|
||||
{
|
||||
struct drm_i915_private *dev_priv =
|
||||
container_of(nb, struct drm_i915_private, lid_notifier);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct drm_connector *connector = dev_priv->int_lvds_connector;
|
||||
struct intel_lvds_connector *lvds_connector =
|
||||
container_of(nb, struct intel_lvds_connector, lid_notifier);
|
||||
struct drm_connector *connector = &lvds_connector->base.base;
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
|
||||
return NOTIFY_OK;
|
||||
@ -525,9 +517,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
* check and update the status of LVDS connector after receiving
|
||||
* the LID nofication event.
|
||||
*/
|
||||
if (connector)
|
||||
connector->status = connector->funcs->detect(connector,
|
||||
false);
|
||||
connector->status = connector->funcs->detect(connector, false);
|
||||
|
||||
/* Don't force modeset on machines where it causes a GPU lockup */
|
||||
if (dmi_check_system(intel_no_modeset_on_lid))
|
||||
@ -543,12 +533,12 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_helper_resume_force_mode(dev);
|
||||
intel_modeset_setup_hw_state(dev, true);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
/**
|
||||
* intel_lvds_destroy - unregister and free LVDS structures
|
||||
@ -559,20 +549,18 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
*/
|
||||
static void intel_lvds_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
#if 0
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
#endif
|
||||
struct intel_lvds_connector *lvds_connector =
|
||||
to_lvds_connector(connector);
|
||||
|
||||
intel_panel_destroy_backlight(dev);
|
||||
#ifdef FREEBSD_WIP
|
||||
if (lvds_connector->lid_notifier.notifier_call)
|
||||
acpi_lid_notifier_unregister(&lvds_connector->lid_notifier);
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
free(lvds_connector->base.edid, DRM_MEM_KMS);
|
||||
|
||||
intel_panel_fini(&lvds_connector->base.panel);
|
||||
|
||||
#if 0
|
||||
if (dev_priv->lid_notifier.notifier_call)
|
||||
acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
|
||||
#endif
|
||||
#if 0
|
||||
drm_sysfs_connector_remove(connector);
|
||||
#endif
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
@ -581,29 +569,31 @@ static int intel_lvds_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t value)
|
||||
{
|
||||
struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
|
||||
struct intel_connector *intel_connector = to_intel_connector(connector);
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
if (property == dev->mode_config.scaling_mode_property) {
|
||||
struct drm_crtc *crtc = intel_lvds->base.base.crtc;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
if (value == DRM_MODE_SCALE_NONE) {
|
||||
DRM_DEBUG_KMS("no scaling not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (intel_lvds->fitting_mode == value) {
|
||||
if (intel_connector->panel.fitting_mode == value) {
|
||||
/* the LVDS scaling property is not changed */
|
||||
return 0;
|
||||
}
|
||||
intel_lvds->fitting_mode = value;
|
||||
intel_connector->panel.fitting_mode = value;
|
||||
|
||||
crtc = intel_attached_encoder(connector)->base.crtc;
|
||||
if (crtc && crtc->enabled) {
|
||||
/*
|
||||
* If the CRTC is enabled, the display will be changed
|
||||
* according to the new panel fitting mode.
|
||||
*/
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -611,11 +601,9 @@ static int intel_lvds_set_property(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
|
||||
.dpms = intel_lvds_dpms,
|
||||
.mode_fixup = intel_lvds_mode_fixup,
|
||||
.prepare = intel_lvds_prepare,
|
||||
.mode_set = intel_lvds_mode_set,
|
||||
.commit = intel_lvds_commit,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
|
||||
@ -625,7 +613,7 @@ static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_lvds_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = intel_connector_dpms,
|
||||
.detect = intel_lvds_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = intel_lvds_set_property,
|
||||
@ -636,7 +624,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
|
||||
.destroy = intel_encoder_destroy,
|
||||
};
|
||||
|
||||
static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
|
||||
static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_INFO("Skipping LVDS initialization for %s\n", id->ident);
|
||||
return 1;
|
||||
@ -755,6 +743,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "Hewlett-Packard HP t5740e Thin Client",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "Hewlett-Packard t5745",
|
||||
@ -779,6 +775,30 @@ static const struct dmi_system_id intel_no_lvds[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "MS-7469"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "Gigabyte GA-D525TUD",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "D525TUD"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "Supermicro X7SPA-H",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "Fujitsu Esprimo Q900",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
|
||||
},
|
||||
},
|
||||
|
||||
{ } /* terminating entry */
|
||||
};
|
||||
@ -906,12 +926,16 @@ static bool intel_lvds_supported(struct drm_device *dev)
|
||||
bool intel_lvds_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_lvds *intel_lvds;
|
||||
struct intel_lvds_encoder *lvds_encoder;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct intel_lvds_connector *lvds_connector;
|
||||
struct intel_connector *intel_connector;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_display_mode *scan; /* *modes, *bios_mode; */
|
||||
struct drm_display_mode *fixed_mode = NULL;
|
||||
struct edid *edid;
|
||||
int edid_err = 0;
|
||||
struct drm_crtc *crtc;
|
||||
u32 lvds;
|
||||
int pipe;
|
||||
@ -939,17 +963,25 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
intel_lvds = malloc(sizeof(struct intel_lvds), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
lvds_encoder = malloc(sizeof(struct intel_lvds_encoder), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!lvds_encoder)
|
||||
return false;
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev)) {
|
||||
intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
|
||||
lvds_connector = malloc(sizeof(struct intel_lvds_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!lvds_connector) {
|
||||
free(lvds_encoder, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
||||
intel_encoder = &intel_lvds->base;
|
||||
lvds_encoder->attached_connector = lvds_connector;
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev)) {
|
||||
lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL);
|
||||
}
|
||||
|
||||
intel_encoder = &lvds_encoder->base;
|
||||
encoder = &intel_encoder->base;
|
||||
intel_connector = &lvds_connector->base;
|
||||
connector = &intel_connector->base;
|
||||
drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
@ -957,12 +989,19 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
|
||||
intel_encoder->enable = intel_enable_lvds;
|
||||
intel_encoder->disable = intel_disable_lvds;
|
||||
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
|
||||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
intel_encoder->type = INTEL_OUTPUT_LVDS;
|
||||
|
||||
intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
|
||||
intel_encoder->cloneable = false;
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
else if (IS_GEN4(dev))
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
||||
else
|
||||
intel_encoder->crtc_mask = (1 << 1);
|
||||
|
||||
@ -974,14 +1013,10 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
|
||||
/* create the scaling mode property */
|
||||
drm_mode_create_scaling_mode_property(dev);
|
||||
/*
|
||||
* the initial panel fitting mode will be FULL_SCREEN.
|
||||
*/
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.scaling_mode_property,
|
||||
DRM_MODE_SCALE_ASPECT);
|
||||
intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT;
|
||||
intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT;
|
||||
/*
|
||||
* LVDS discovery:
|
||||
* 1) check for EDID on DDC
|
||||
@ -996,19 +1031,24 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
* Attempt to get the fixed panel mode from DDC. Assume that the
|
||||
* preferred mode is the right one.
|
||||
*/
|
||||
intel_lvds->edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv, pin));
|
||||
if (intel_lvds->edid) {
|
||||
if (drm_add_edid_modes(connector,
|
||||
intel_lvds->edid)) {
|
||||
edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin));
|
||||
if (edid) {
|
||||
if (drm_add_edid_modes(connector, edid)) {
|
||||
drm_mode_connector_update_edid_property(connector,
|
||||
intel_lvds->edid);
|
||||
edid);
|
||||
} else {
|
||||
free(intel_lvds->edid, DRM_MEM_KMS);
|
||||
intel_lvds->edid = NULL;
|
||||
free(edid, DRM_MEM_KMS);
|
||||
edid = NULL;
|
||||
edid_err = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
edid = NULL;
|
||||
edid_err = -ENOENT;
|
||||
}
|
||||
if (!intel_lvds->edid) {
|
||||
lvds_connector->base.edid = edid;
|
||||
lvds_connector->base.edid_err = edid_err;
|
||||
|
||||
if (edid_err) {
|
||||
/* Didn't get an EDID, so
|
||||
* Set wide sync ranges so we get all modes
|
||||
* handed to valid_mode for checking
|
||||
@ -1021,22 +1061,26 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
|
||||
list_for_each_entry(scan, &connector->probed_modes, head) {
|
||||
if (scan->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
intel_lvds->fixed_mode =
|
||||
drm_mode_duplicate(dev, scan);
|
||||
intel_find_lvds_downclock(dev,
|
||||
intel_lvds->fixed_mode,
|
||||
connector);
|
||||
goto out;
|
||||
DRM_DEBUG_KMS("using preferred mode from EDID: ");
|
||||
drm_mode_debug_printmodeline(scan);
|
||||
|
||||
fixed_mode = drm_mode_duplicate(dev, scan);
|
||||
if (fixed_mode) {
|
||||
intel_find_lvds_downclock(dev, fixed_mode,
|
||||
connector);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to get EDID, what about VBT? */
|
||||
if (dev_priv->lfp_lvds_vbt_mode) {
|
||||
intel_lvds->fixed_mode =
|
||||
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
||||
if (intel_lvds->fixed_mode) {
|
||||
intel_lvds->fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
DRM_DEBUG_KMS("using mode from VBT: ");
|
||||
drm_mode_debug_printmodeline(dev_priv->lfp_lvds_vbt_mode);
|
||||
|
||||
fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
||||
if (fixed_mode) {
|
||||
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -1056,71 +1100,51 @@ bool intel_lvds_init(struct drm_device *dev)
|
||||
crtc = intel_get_crtc_for_pipe(dev, pipe);
|
||||
|
||||
if (crtc && (lvds & LVDS_PORT_EN)) {
|
||||
intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
|
||||
if (intel_lvds->fixed_mode) {
|
||||
intel_lvds->fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
fixed_mode = intel_crtc_mode_get(dev, crtc);
|
||||
if (fixed_mode) {
|
||||
DRM_DEBUG_KMS("using current (BIOS) mode: ");
|
||||
drm_mode_debug_printmodeline(fixed_mode);
|
||||
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we still don't have a mode after all that, give up. */
|
||||
if (!intel_lvds->fixed_mode)
|
||||
if (!fixed_mode)
|
||||
goto failed;
|
||||
|
||||
out:
|
||||
/*
|
||||
* Unlock registers and just
|
||||
* leave them unlocked
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 pwm;
|
||||
|
||||
pipe = (I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT) ? 1 : 0;
|
||||
|
||||
/* make sure PWM is enabled and locked to the LVDS pipe */
|
||||
pwm = I915_READ(BLC_PWM_CPU_CTL2);
|
||||
if (pipe == 0 && (pwm & PWM_PIPE_B))
|
||||
I915_WRITE(BLC_PWM_CPU_CTL2, pwm & ~PWM_ENABLE);
|
||||
if (pipe)
|
||||
pwm |= PWM_PIPE_B;
|
||||
else
|
||||
pwm &= ~PWM_PIPE_B;
|
||||
I915_WRITE(BLC_PWM_CPU_CTL2, pwm | PWM_ENABLE);
|
||||
|
||||
pwm = I915_READ(BLC_PWM_PCH_CTL1);
|
||||
pwm |= PWM_PCH_ENABLE;
|
||||
I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
|
||||
/*
|
||||
* Unlock registers and just
|
||||
* leave them unlocked
|
||||
*/
|
||||
I915_WRITE(PCH_PP_CONTROL,
|
||||
I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
|
||||
} else {
|
||||
/*
|
||||
* Unlock registers and just
|
||||
* leave them unlocked
|
||||
*/
|
||||
I915_WRITE(PP_CONTROL,
|
||||
I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
|
||||
}
|
||||
#ifdef NOTYET
|
||||
dev_priv->lid_notifier.notifier_call = intel_lid_notify;
|
||||
if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
|
||||
#ifdef FREEBSD_WIP
|
||||
lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
|
||||
if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
|
||||
DRM_DEBUG_KMS("lid notifier registration failed\n");
|
||||
dev_priv->lid_notifier.notifier_call = NULL;
|
||||
lvds_connector->lid_notifier.notifier_call = NULL;
|
||||
}
|
||||
#endif
|
||||
/* keep the LVDS connector */
|
||||
dev_priv->int_lvds_connector = connector;
|
||||
#if 0
|
||||
drm_sysfs_connector_add(connector);
|
||||
#endif
|
||||
intel_panel_setup_backlight(dev);
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
intel_panel_init(&intel_connector->panel, fixed_mode);
|
||||
intel_panel_setup_backlight(connector);
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
|
||||
drm_connector_cleanup(connector);
|
||||
drm_encoder_cleanup(encoder);
|
||||
free(intel_lvds, DRM_MEM_KMS);
|
||||
free(intel_connector, DRM_MEM_KMS);
|
||||
if (fixed_mode)
|
||||
drm_mode_destroy(dev, fixed_mode);
|
||||
free(lvds_encoder, DRM_MEM_KMS);
|
||||
free(lvds_connector, DRM_MEM_KMS);
|
||||
return false;
|
||||
}
|
||||
|
@ -27,39 +27,26 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
|
||||
/**
|
||||
* intel_ddc_probe
|
||||
*
|
||||
* intel_connector_update_modes - update connector from edid
|
||||
* @connector: DRM connector device to use
|
||||
* @edid: previously read EDID information
|
||||
*/
|
||||
bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
|
||||
int intel_connector_update_modes(struct drm_connector *connector,
|
||||
struct edid *edid)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
|
||||
u8 out_buf[] = { 0x0, 0x0};
|
||||
u8 buf[2];
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = DDC_ADDR << 1,
|
||||
.flags = IIC_M_WR,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = DDC_ADDR << 1,
|
||||
.flags = IIC_M_RD,
|
||||
.len = 1,
|
||||
.buf = buf,
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
return (iicbus_transfer(intel_gmbus_get_adapter(dev_priv, ddc_bus),
|
||||
msgs, 2) == 0/* XXXKIB 2*/);
|
||||
drm_mode_connector_update_edid_property(connector, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
drm_edid_to_eld(connector, edid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,19 +56,18 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
|
||||
*
|
||||
* Fetch the EDID information from @connector using the DDC bus.
|
||||
*/
|
||||
int
|
||||
intel_ddc_get_modes(struct drm_connector *connector, device_t adapter)
|
||||
int intel_ddc_get_modes(struct drm_connector *connector,
|
||||
device_t adapter)
|
||||
{
|
||||
struct edid *edid;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
edid = drm_get_edid(connector, adapter);
|
||||
if (edid) {
|
||||
drm_mode_connector_update_edid_property(connector, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
drm_edid_to_eld(connector, edid);
|
||||
free(edid, DRM_MEM_KMS);
|
||||
}
|
||||
if (!edid)
|
||||
return 0;
|
||||
|
||||
ret = intel_connector_update_modes(connector, edid);
|
||||
free(edid, DRM_MEM_KMS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -129,9 +115,9 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector)
|
||||
prop = dev_priv->broadcast_rgb_property;
|
||||
if (prop == NULL) {
|
||||
prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
|
||||
"Broadcast RGB",
|
||||
broadcast_rgb_names,
|
||||
ARRAY_SIZE(broadcast_rgb_names));
|
||||
"Broadcast RGB",
|
||||
broadcast_rgb_names,
|
||||
ARRAY_SIZE(broadcast_rgb_names));
|
||||
if (prop == NULL)
|
||||
return;
|
||||
|
||||
|
@ -28,10 +28,13 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <dev/acpica/acpivar.h>
|
||||
@ -147,13 +150,15 @@ struct opregion_asle {
|
||||
#define ACPI_DIGITAL_OUTPUT (3<<8)
|
||||
#define ACPI_LVDS_OUTPUT (4<<8)
|
||||
|
||||
#if defined(CONFIG_ACPI)
|
||||
#ifdef CONFIG_ACPI
|
||||
static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
|
||||
u32 max;
|
||||
|
||||
DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
|
||||
|
||||
if (!(bclp & ASLE_BCLP_VALID))
|
||||
return ASLE_BACKLIGHT_FAILED;
|
||||
|
||||
@ -163,7 +168,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||
|
||||
max = intel_panel_get_max_backlight(dev);
|
||||
intel_panel_set_backlight(dev, bclp * max / 255);
|
||||
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
||||
iowrite32((bclp*0x64)/0xff | ASLE_CBLV_VALID, &asle->cblv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -200,71 +205,71 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
|
||||
void intel_opregion_asle_intr(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
|
||||
u32 asle_stat = 0;
|
||||
u32 asle_req;
|
||||
|
||||
if (!asle)
|
||||
return;
|
||||
|
||||
asle_req = asle->aslc & ASLE_REQ_MSK;
|
||||
asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK;
|
||||
|
||||
if (!asle_req) {
|
||||
DRM_DEBUG("non asle set request??\n");
|
||||
DRM_DEBUG_DRIVER("non asle set request??\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_ALS_ILLUM)
|
||||
asle_stat |= asle_set_als_illum(dev, asle->alsi);
|
||||
asle_stat |= asle_set_als_illum(dev, ioread32(&asle->alsi));
|
||||
|
||||
if (asle_req & ASLE_SET_BACKLIGHT)
|
||||
asle_stat |= asle_set_backlight(dev, asle->bclp);
|
||||
asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
|
||||
|
||||
if (asle_req & ASLE_SET_PFIT)
|
||||
asle_stat |= asle_set_pfit(dev, asle->pfit);
|
||||
asle_stat |= asle_set_pfit(dev, ioread32(&asle->pfit));
|
||||
|
||||
if (asle_req & ASLE_SET_PWM_FREQ)
|
||||
asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
|
||||
asle_stat |= asle_set_pwm_freq(dev, ioread32(&asle->pfmb));
|
||||
|
||||
asle->aslc = asle_stat;
|
||||
iowrite32(asle_stat, &asle->aslc);
|
||||
}
|
||||
|
||||
void intel_opregion_gse_intr(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
|
||||
u32 asle_stat = 0;
|
||||
u32 asle_req;
|
||||
|
||||
if (!asle)
|
||||
return;
|
||||
|
||||
asle_req = asle->aslc & ASLE_REQ_MSK;
|
||||
asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK;
|
||||
|
||||
if (!asle_req) {
|
||||
DRM_DEBUG("non asle set request??\n");
|
||||
DRM_DEBUG_DRIVER("non asle set request??\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_ALS_ILLUM) {
|
||||
DRM_DEBUG("Illum is not supported\n");
|
||||
DRM_DEBUG_DRIVER("Illum is not supported\n");
|
||||
asle_stat |= ASLE_ALS_ILLUM_FAILED;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_BACKLIGHT)
|
||||
asle_stat |= asle_set_backlight(dev, asle->bclp);
|
||||
asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
|
||||
|
||||
if (asle_req & ASLE_SET_PFIT) {
|
||||
DRM_DEBUG("Pfit is not supported\n");
|
||||
DRM_DEBUG_DRIVER("Pfit is not supported\n");
|
||||
asle_stat |= ASLE_PFIT_FAILED;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_PWM_FREQ) {
|
||||
DRM_DEBUG("PWM freq is not supported\n");
|
||||
DRM_DEBUG_DRIVER("PWM freq is not supported\n");
|
||||
asle_stat |= ASLE_PWM_FREQ_FAILED;
|
||||
}
|
||||
|
||||
asle->aslc = asle_stat;
|
||||
iowrite32(asle_stat, &asle->aslc);
|
||||
}
|
||||
#define ASLE_ALS_EN (1<<0)
|
||||
#define ASLE_BLC_EN (1<<1)
|
||||
@ -274,15 +279,16 @@ void intel_opregion_gse_intr(struct drm_device *dev)
|
||||
void intel_opregion_enable_asle(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
|
||||
|
||||
if (asle) {
|
||||
if (IS_MOBILE(dev))
|
||||
intel_enable_asle(dev);
|
||||
|
||||
asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
|
||||
ASLE_PFMB_EN;
|
||||
asle->ardy = 1;
|
||||
iowrite32(ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
|
||||
ASLE_PFMB_EN,
|
||||
&asle->tche);
|
||||
iowrite32(1, &asle->ardy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,7 +298,7 @@ void intel_opregion_enable_asle(struct drm_device *dev)
|
||||
|
||||
static struct intel_opregion *system_opregion;
|
||||
|
||||
#if 0
|
||||
#ifdef FREEBSD_WIP
|
||||
static int intel_opregion_video_event(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
@ -300,7 +306,8 @@ static int intel_opregion_video_event(struct notifier_block *nb,
|
||||
either a docking event, lid switch or display switch request. In
|
||||
Linux, these are handled by the dock, button and video drivers.
|
||||
*/
|
||||
struct opregion_acpi *acpi;
|
||||
|
||||
struct opregion_acpi __iomem *acpi;
|
||||
struct acpi_bus_event *event = data;
|
||||
int ret = NOTIFY_OK;
|
||||
|
||||
@ -312,10 +319,11 @@ static int intel_opregion_video_event(struct notifier_block *nb,
|
||||
|
||||
acpi = system_opregion->acpi;
|
||||
|
||||
if (event->type == 0x80 && !(acpi->cevt & 0x1))
|
||||
if (event->type == 0x80 &&
|
||||
(ioread32(&acpi->cevt) & 1) == 0)
|
||||
ret = NOTIFY_BAD;
|
||||
|
||||
acpi->csts = 0;
|
||||
iowrite32(0, &acpi->csts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -323,7 +331,7 @@ static int intel_opregion_video_event(struct notifier_block *nb,
|
||||
static struct notifier_block intel_opregion_notifier = {
|
||||
.notifier_call = intel_opregion_video_event,
|
||||
};
|
||||
#endif
|
||||
#endif /* FREEBSD_WIP */
|
||||
|
||||
/*
|
||||
* Initialise the DIDL field in opregion. This passes a list of devices to
|
||||
@ -345,9 +353,10 @@ static void intel_didl_outputs(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||
struct drm_connector *connector;
|
||||
ACPI_HANDLE handle, acpi_cdev, acpi_video_bus = NULL;
|
||||
u32 device_id;
|
||||
ACPI_HANDLE handle, acpi_video_bus, acpi_cdev;
|
||||
ACPI_STATUS status;
|
||||
u32 temp;
|
||||
int i = 0;
|
||||
|
||||
handle = acpi_get_handle(dev->dev);
|
||||
@ -358,7 +367,6 @@ static void intel_didl_outputs(struct drm_device *dev)
|
||||
acpi_video_bus = handle;
|
||||
else {
|
||||
acpi_cdev = NULL;
|
||||
acpi_video_bus = NULL;
|
||||
while (AcpiGetNextObject(ACPI_TYPE_DEVICE, handle, acpi_cdev,
|
||||
&acpi_cdev) != AE_NOT_FOUND) {
|
||||
if (acpi_is_video_device(acpi_cdev)) {
|
||||
@ -366,14 +374,6 @@ static void intel_didl_outputs(struct drm_device *dev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
|
||||
if (acpi_is_video_device(acpi_cdev)) {
|
||||
acpi_video_bus = acpi_cdev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!acpi_video_bus) {
|
||||
@ -388,37 +388,22 @@ static void intel_didl_outputs(struct drm_device *dev)
|
||||
device_printf(dev->dev, "More than 8 outputs detected\n");
|
||||
return;
|
||||
}
|
||||
status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (!device_id)
|
||||
goto blind_set;
|
||||
opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
|
||||
if (i >= 8) {
|
||||
dev_printk(KERN_ERR, &dev->pdev->dev,
|
||||
"More than 8 outputs detected\n");
|
||||
return;
|
||||
}
|
||||
status =
|
||||
acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
|
||||
NULL, &device_id);
|
||||
acpi_GetInteger(acpi_cdev, "_ADR",
|
||||
&device_id);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (!device_id)
|
||||
goto blind_set;
|
||||
opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
|
||||
iowrite32((u32)(device_id & 0x0f0f),
|
||||
&opregion->acpi->didl[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
/* If fewer than 8 outputs, the list must be null terminated */
|
||||
if (i < 8)
|
||||
opregion->acpi->didl[i] = 0;
|
||||
iowrite32(0, &opregion->acpi->didl[i]);
|
||||
return;
|
||||
|
||||
blind_set:
|
||||
@ -452,7 +437,9 @@ blind_set:
|
||||
output_type = ACPI_LVDS_OUTPUT;
|
||||
break;
|
||||
}
|
||||
opregion->acpi->didl[i] |= (1<<31) | output_type | i;
|
||||
temp = ioread32(&opregion->acpi->didl[i]);
|
||||
iowrite32(temp | (1<<31) | output_type | i,
|
||||
&opregion->acpi->didl[i]);
|
||||
i++;
|
||||
}
|
||||
goto end;
|
||||
@ -472,8 +459,8 @@ static void intel_setup_cadls(struct drm_device *dev)
|
||||
* display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
|
||||
* there are less than eight devices. */
|
||||
do {
|
||||
disp_id = opregion->acpi->didl[i];
|
||||
opregion->acpi->cadl[i] = disp_id;
|
||||
disp_id = ioread32(&opregion->acpi->didl[i]);
|
||||
iowrite32(disp_id, &opregion->acpi->cadl[i]);
|
||||
} while (++i < 8 && disp_id != 0);
|
||||
}
|
||||
|
||||
@ -494,13 +481,13 @@ void intel_opregion_init(struct drm_device *dev)
|
||||
/* Notify BIOS we are ready to handle ACPI video ext notifs.
|
||||
* Right now, all the events are handled by the ACPI video module.
|
||||
* We don't actually need to do anything with them. */
|
||||
opregion->acpi->csts = 0;
|
||||
opregion->acpi->drdy = 1;
|
||||
iowrite32(0, &opregion->acpi->csts);
|
||||
iowrite32(1, &opregion->acpi->drdy);
|
||||
|
||||
system_opregion = opregion;
|
||||
#if 0
|
||||
#ifdef FREEBSD_WIP
|
||||
register_acpi_notifier(&intel_opregion_notifier);
|
||||
#endif
|
||||
#endif /* FREEBSD_WIP */
|
||||
}
|
||||
|
||||
if (opregion->asle)
|
||||
@ -516,12 +503,12 @@ void intel_opregion_fini(struct drm_device *dev)
|
||||
return;
|
||||
|
||||
if (opregion->acpi) {
|
||||
opregion->acpi->drdy = 0;
|
||||
iowrite32(0, &opregion->acpi->drdy);
|
||||
|
||||
system_opregion = NULL;
|
||||
#if 0
|
||||
#ifdef FREEBSD_WIP
|
||||
unregister_acpi_notifier(&intel_opregion_notifier);
|
||||
#endif
|
||||
#endif /* FREEBSD_WIP */
|
||||
}
|
||||
|
||||
/* just clear all opregion memory pointers now */
|
||||
@ -532,45 +519,21 @@ void intel_opregion_fini(struct drm_device *dev)
|
||||
opregion->asle = NULL;
|
||||
opregion->vbt = NULL;
|
||||
}
|
||||
#else
|
||||
void
|
||||
intel_opregion_init(struct drm_device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
intel_opregion_fini(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct intel_opregion *opregion;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
opregion = &dev_priv->opregion;
|
||||
|
||||
if (opregion->header == NULL)
|
||||
return;
|
||||
|
||||
pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
|
||||
opregion->header = NULL;
|
||||
opregion->acpi = NULL;
|
||||
opregion->swsci = NULL;
|
||||
opregion->asle = NULL;
|
||||
opregion->vbt = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int intel_opregion_setup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||
char *base;
|
||||
void __iomem *base;
|
||||
u32 asls, mboxes;
|
||||
char buf[sizeof(OPREGION_SIGNATURE)];
|
||||
int err = 0;
|
||||
|
||||
asls = pci_read_config(dev->dev, PCI_ASLS, 4);
|
||||
DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
|
||||
pci_read_config_dword(dev->dev, PCI_ASLS, &asls);
|
||||
DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
|
||||
if (asls == 0) {
|
||||
DRM_DEBUG("ACPI OpRegion not supported!\n");
|
||||
DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@ -578,31 +541,33 @@ int intel_opregion_setup(struct drm_device *dev)
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
if (memcmp(base, OPREGION_SIGNATURE, 16)) {
|
||||
DRM_DEBUG("opregion signature mismatch\n");
|
||||
memcpy_fromio(buf, base, sizeof(buf));
|
||||
|
||||
if (memcmp(buf, OPREGION_SIGNATURE, 16)) {
|
||||
DRM_DEBUG_DRIVER("opregion signature mismatch\n");
|
||||
err = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
opregion->header = (struct opregion_header *)base;
|
||||
opregion->vbt = base + OPREGION_VBT_OFFSET;
|
||||
opregion->vbt = (char *)base + OPREGION_VBT_OFFSET;
|
||||
|
||||
opregion->lid_state = (u32 *)(base + ACPI_CLID);
|
||||
opregion->lid_state = (u32 *)((char *)base + ACPI_CLID);
|
||||
|
||||
mboxes = opregion->header->mboxes;
|
||||
if (mboxes & MBOX_ACPI) {
|
||||
DRM_DEBUG("Public ACPI methods supported\n");
|
||||
opregion->acpi = (struct opregion_acpi *)(base +
|
||||
DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
|
||||
opregion->acpi = (struct opregion_acpi *)((char *)base +
|
||||
OPREGION_ACPI_OFFSET);
|
||||
}
|
||||
|
||||
if (mboxes & MBOX_SWSCI) {
|
||||
DRM_DEBUG("SWSCI supported\n");
|
||||
opregion->swsci = (struct opregion_swsci *)(base +
|
||||
DRM_DEBUG_DRIVER("SWSCI supported\n");
|
||||
opregion->swsci = (struct opregion_swsci *)((char *)base +
|
||||
OPREGION_SWSCI_OFFSET);
|
||||
}
|
||||
if (mboxes & MBOX_ASLE) {
|
||||
DRM_DEBUG("ASLE supported\n");
|
||||
opregion->asle = (struct opregion_asle *)(base +
|
||||
DRM_DEBUG_DRIVER("ASLE supported\n");
|
||||
opregion->asle = (struct opregion_asle *)((char *)base +
|
||||
OPREGION_ASLE_OFFSET);
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,10 @@
|
||||
*
|
||||
* Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/i915_reg.h>
|
||||
@ -191,46 +189,44 @@ struct intel_overlay {
|
||||
void (*flip_tail)(struct intel_overlay *);
|
||||
};
|
||||
|
||||
static struct overlay_registers *
|
||||
static struct overlay_registers __iomem *
|
||||
intel_overlay_map_regs(struct intel_overlay *overlay)
|
||||
{
|
||||
struct overlay_registers *regs;
|
||||
drm_i915_private_t *dev_priv = overlay->dev->dev_private;
|
||||
struct overlay_registers __iomem *regs;
|
||||
|
||||
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) {
|
||||
regs = overlay->reg_bo->phys_obj->handle->vaddr;
|
||||
} else {
|
||||
regs = pmap_mapdev_attr(overlay->dev->agp->base +
|
||||
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
|
||||
regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr;
|
||||
else
|
||||
regs = pmap_mapdev_attr(dev_priv->mm.gtt_base_addr +
|
||||
overlay->reg_bo->gtt_offset, PAGE_SIZE,
|
||||
PAT_WRITE_COMBINING);
|
||||
}
|
||||
return (regs);
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
|
||||
struct overlay_registers *regs)
|
||||
struct overlay_registers __iomem *regs)
|
||||
{
|
||||
if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
|
||||
pmap_unmapdev((vm_offset_t)regs, PAGE_SIZE);
|
||||
}
|
||||
|
||||
static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
|
||||
struct drm_i915_gem_request *request,
|
||||
void (*tail)(struct intel_overlay *))
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring = &dev_priv->rings[RCS];
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
|
||||
int ret;
|
||||
|
||||
KASSERT(!overlay->last_flip_req, ("Overlay already has flip req"));
|
||||
ret = i915_add_request(ring, NULL, request);
|
||||
if (ret) {
|
||||
free(request, DRM_I915_GEM);
|
||||
BUG_ON(overlay->last_flip_req);
|
||||
ret = i915_add_request(ring, NULL, &overlay->last_flip_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
overlay->last_flip_req = request->seqno;
|
||||
|
||||
overlay->flip_tail = tail;
|
||||
ret = i915_wait_request(ring, overlay->last_flip_req);
|
||||
ret = i915_wait_seqno(ring, overlay->last_flip_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
i915_gem_retire_requests(dev);
|
||||
@ -239,80 +235,22 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Workaround for i830 bug where pipe a must be enable to change control regs */
|
||||
static int
|
||||
i830_activate_pipe_a(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *crtc;
|
||||
struct drm_crtc_helper_funcs *crtc_funcs;
|
||||
struct drm_display_mode vesa_640x480 = {
|
||||
DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 489, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
|
||||
}, *mode;
|
||||
|
||||
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
|
||||
if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
|
||||
return 0;
|
||||
|
||||
/* most i8xx have pipe a forced on, so don't trust dpms mode */
|
||||
if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE)
|
||||
return 0;
|
||||
|
||||
crtc_funcs = crtc->base.helper_private;
|
||||
if (crtc_funcs->dpms == NULL)
|
||||
return 0;
|
||||
|
||||
DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
|
||||
|
||||
mode = drm_mode_duplicate(dev, &vesa_640x480);
|
||||
|
||||
if (!drm_crtc_helper_set_mode(&crtc->base, mode,
|
||||
crtc->base.x, crtc->base.y,
|
||||
crtc->base.fb))
|
||||
return 0;
|
||||
|
||||
crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
i830_deactivate_pipe_a(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
|
||||
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
|
||||
|
||||
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
/* overlay needs to be disable in OCMD reg */
|
||||
static int intel_overlay_on(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring = &dev_priv->rings[RCS];
|
||||
struct drm_i915_gem_request *request;
|
||||
int pipe_a_quirk = 0;
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
|
||||
int ret;
|
||||
|
||||
KASSERT(!overlay->active, ("Overlay is active"));
|
||||
BUG_ON(overlay->active);
|
||||
overlay->active = 1;
|
||||
|
||||
if (IS_I830(dev)) {
|
||||
pipe_a_quirk = i830_activate_pipe_a(dev);
|
||||
if (pipe_a_quirk < 0)
|
||||
return pipe_a_quirk;
|
||||
}
|
||||
|
||||
request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
|
||||
|
||||
ret = intel_ring_begin(ring, 4);
|
||||
if (ret) {
|
||||
free(request, DRM_I915_GEM);
|
||||
goto out;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
|
||||
intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
|
||||
@ -320,12 +258,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_advance(ring);
|
||||
|
||||
ret = intel_overlay_do_wait_request(overlay, request, NULL);
|
||||
out:
|
||||
if (pipe_a_quirk)
|
||||
i830_deactivate_pipe_a(dev);
|
||||
|
||||
return ret;
|
||||
return intel_overlay_do_wait_request(overlay, NULL);
|
||||
}
|
||||
|
||||
/* overlay needs to be enabled in OCMD reg */
|
||||
@ -334,15 +267,12 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring = &dev_priv->rings[RCS];
|
||||
struct drm_i915_gem_request *request;
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
|
||||
u32 flip_addr = overlay->flip_addr;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
KASSERT(overlay->active, ("Overlay not active"));
|
||||
|
||||
request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
BUG_ON(!overlay->active);
|
||||
|
||||
if (load_polyphase_filter)
|
||||
flip_addr |= OFC_UPDATE;
|
||||
@ -353,22 +283,14 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
|
||||
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
|
||||
|
||||
ret = intel_ring_begin(ring, 2);
|
||||
if (ret) {
|
||||
free(request, DRM_I915_GEM);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
|
||||
intel_ring_emit(ring, flip_addr);
|
||||
intel_ring_advance(ring);
|
||||
|
||||
ret = i915_add_request(ring, NULL, request);
|
||||
if (ret) {
|
||||
free(request, DRM_I915_GEM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
overlay->last_flip_req = request->seqno;
|
||||
return 0;
|
||||
return i915_add_request(ring, NULL, &overlay->last_flip_req);
|
||||
}
|
||||
|
||||
static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
|
||||
@ -386,7 +308,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay)
|
||||
struct drm_i915_gem_object *obj = overlay->vid_bo;
|
||||
|
||||
/* never have the overlay hw on without showing a frame */
|
||||
KASSERT(overlay->vid_bo != NULL, ("No vid_bo"));
|
||||
BUG_ON(!overlay->vid_bo);
|
||||
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
@ -402,14 +324,11 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring = &dev_priv->rings[RCS];
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
|
||||
u32 flip_addr = overlay->flip_addr;
|
||||
struct drm_i915_gem_request *request;
|
||||
int ret;
|
||||
|
||||
KASSERT(overlay->active, ("Overlay is not active"));
|
||||
|
||||
request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
BUG_ON(!overlay->active);
|
||||
|
||||
/* According to intel docs the overlay hw may hang (when switching
|
||||
* off) without loading the filter coeffs. It is however unclear whether
|
||||
@ -418,22 +337,28 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
||||
flip_addr |= OFC_UPDATE;
|
||||
|
||||
ret = intel_ring_begin(ring, 6);
|
||||
if (ret) {
|
||||
free(request, DRM_I915_GEM);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* wait for overlay to go idle */
|
||||
intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
|
||||
intel_ring_emit(ring, flip_addr);
|
||||
intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
/* turn overlay off */
|
||||
intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
|
||||
intel_ring_emit(ring, flip_addr);
|
||||
intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
if (IS_I830(dev)) {
|
||||
/* Workaround: Don't disable the overlay fully, since otherwise
|
||||
* it dies on the next OVERLAY_ON cmd. */
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
} else {
|
||||
intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
|
||||
intel_ring_emit(ring, flip_addr);
|
||||
intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
}
|
||||
intel_ring_advance(ring);
|
||||
|
||||
return intel_overlay_do_wait_request(overlay, request,
|
||||
intel_overlay_off_tail);
|
||||
return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail);
|
||||
}
|
||||
|
||||
/* recover from an interruption due to a signal
|
||||
@ -442,13 +367,13 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring = &dev_priv->rings[RCS];
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
|
||||
int ret;
|
||||
|
||||
if (overlay->last_flip_req == 0)
|
||||
return 0;
|
||||
|
||||
ret = i915_wait_request(ring, overlay->last_flip_req);
|
||||
ret = i915_wait_seqno(ring, overlay->last_flip_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
i915_gem_retire_requests(dev);
|
||||
@ -468,7 +393,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring = &dev_priv->rings[RCS];
|
||||
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
|
||||
int ret;
|
||||
|
||||
/* Only wait if there is actually an old frame to release to
|
||||
@ -478,22 +403,16 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
|
||||
return 0;
|
||||
|
||||
if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
|
||||
struct drm_i915_gem_request *request;
|
||||
|
||||
/* synchronous slowpath */
|
||||
request = malloc(sizeof(*request), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
|
||||
ret = intel_ring_begin(ring, 2);
|
||||
if (ret) {
|
||||
free(request, DRM_I915_GEM);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_advance(ring);
|
||||
|
||||
ret = intel_overlay_do_wait_request(overlay, request,
|
||||
ret = intel_overlay_do_wait_request(overlay,
|
||||
intel_overlay_release_old_vid_tail);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -619,14 +538,15 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
|
||||
0x3000, 0x0800, 0x3000
|
||||
};
|
||||
|
||||
static void update_polyphase_filter(struct overlay_registers *regs)
|
||||
static void update_polyphase_filter(struct overlay_registers __iomem *regs)
|
||||
{
|
||||
memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
|
||||
memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
|
||||
memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
|
||||
memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
|
||||
sizeof(uv_static_hcoeffs));
|
||||
}
|
||||
|
||||
static bool update_scaling_factors(struct intel_overlay *overlay,
|
||||
struct overlay_registers *regs,
|
||||
struct overlay_registers __iomem *regs,
|
||||
struct put_image_params *params)
|
||||
{
|
||||
/* fixed point with a 12 bit shift */
|
||||
@ -665,16 +585,19 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
|
||||
overlay->old_xscale = xscale;
|
||||
overlay->old_yscale = yscale;
|
||||
|
||||
regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
|
||||
((xscale >> FP_SHIFT) << 16) |
|
||||
((xscale & FRACT_MASK) << 3));
|
||||
iowrite32(((yscale & FRACT_MASK) << 20) |
|
||||
((xscale >> FP_SHIFT) << 16) |
|
||||
((xscale & FRACT_MASK) << 3),
|
||||
®s->YRGBSCALE);
|
||||
|
||||
regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
|
||||
((xscale_UV >> FP_SHIFT) << 16) |
|
||||
((xscale_UV & FRACT_MASK) << 3));
|
||||
iowrite32(((yscale_UV & FRACT_MASK) << 20) |
|
||||
((xscale_UV >> FP_SHIFT) << 16) |
|
||||
((xscale_UV & FRACT_MASK) << 3),
|
||||
®s->UVSCALE);
|
||||
|
||||
regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) |
|
||||
((yscale_UV >> FP_SHIFT) << 0)));
|
||||
iowrite32((((yscale >> FP_SHIFT) << 16) |
|
||||
((yscale_UV >> FP_SHIFT) << 0)),
|
||||
®s->UVSCALEV);
|
||||
|
||||
if (scale_changed)
|
||||
update_polyphase_filter(regs);
|
||||
@ -683,30 +606,32 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
|
||||
}
|
||||
|
||||
static void update_colorkey(struct intel_overlay *overlay,
|
||||
struct overlay_registers *regs)
|
||||
struct overlay_registers __iomem *regs)
|
||||
{
|
||||
u32 key = overlay->color_key;
|
||||
|
||||
switch (overlay->crtc->base.fb->bits_per_pixel) {
|
||||
case 8:
|
||||
regs->DCLRKV = 0;
|
||||
regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
|
||||
iowrite32(0, ®s->DCLRKV);
|
||||
iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, ®s->DCLRKM);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
if (overlay->crtc->base.fb->depth == 15) {
|
||||
regs->DCLRKV = RGB15_TO_COLORKEY(key);
|
||||
regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
|
||||
iowrite32(RGB15_TO_COLORKEY(key), ®s->DCLRKV);
|
||||
iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
|
||||
®s->DCLRKM);
|
||||
} else {
|
||||
regs->DCLRKV = RGB16_TO_COLORKEY(key);
|
||||
regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
|
||||
iowrite32(RGB16_TO_COLORKEY(key), ®s->DCLRKV);
|
||||
iowrite32(CLK_RGB16_MASK | DST_KEY_ENABLE,
|
||||
®s->DCLRKM);
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
case 32:
|
||||
regs->DCLRKV = key;
|
||||
regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
|
||||
iowrite32(key, ®s->DCLRKV);
|
||||
iowrite32(CLK_RGB24_MASK | DST_KEY_ENABLE, ®s->DCLRKM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -756,24 +681,21 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static u32
|
||||
max_u32(u32 a, u32 b)
|
||||
{
|
||||
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||
struct drm_i915_gem_object *new_bo,
|
||||
struct put_image_params *params)
|
||||
{
|
||||
int ret, tmp_width;
|
||||
struct overlay_registers *regs;
|
||||
struct overlay_registers __iomem *regs;
|
||||
bool scale_changed = false;
|
||||
#ifdef INVARIANTS
|
||||
struct drm_device *dev = overlay->dev;
|
||||
#endif
|
||||
u32 swidth, swidthsw, sheight, ostride;
|
||||
|
||||
KASSERT(overlay != NULL, ("No overlay ?"));
|
||||
DRM_LOCK_ASSERT(overlay->dev);
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
sx_assert(&dev->mode_config.mutex, SA_XLOCKED);
|
||||
BUG_ON(!overlay);
|
||||
|
||||
ret = intel_overlay_release_old_vid(overlay);
|
||||
if (ret != 0)
|
||||
@ -781,7 +703,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||
|
||||
ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
|
||||
if (ret != 0)
|
||||
goto out_unpin;
|
||||
return ret;
|
||||
|
||||
ret = i915_gem_object_put_fence(new_bo);
|
||||
if (ret)
|
||||
@ -799,7 +721,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||
oconfig |= OCONF_CSC_MODE_BT709;
|
||||
oconfig |= overlay->crtc->pipe == 0 ?
|
||||
OCONF_PIPE_A : OCONF_PIPE_B;
|
||||
regs->OCONFIG = oconfig;
|
||||
iowrite32(oconfig, ®s->OCONFIG);
|
||||
intel_overlay_unmap_regs(overlay, regs);
|
||||
|
||||
ret = intel_overlay_on(overlay);
|
||||
@ -813,8 +735,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
|
||||
regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
|
||||
iowrite32((params->dst_y << 16) | params->dst_x, ®s->DWINPOS);
|
||||
iowrite32((params->dst_h << 16) | params->dst_w, ®s->DWINSZ);
|
||||
|
||||
if (params->format & I915_OVERLAY_YUV_PACKED)
|
||||
tmp_width = packed_width_bytes(params->format, params->src_w);
|
||||
@ -824,7 +746,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||
swidth = params->src_w;
|
||||
swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width);
|
||||
sheight = params->src_h;
|
||||
regs->OBUF_0Y = new_bo->gtt_offset + params->offset_Y;
|
||||
iowrite32(new_bo->gtt_offset + params->offset_Y, ®s->OBUF_0Y);
|
||||
ostride = params->stride_Y;
|
||||
|
||||
if (params->format & I915_OVERLAY_YUV_PLANAR) {
|
||||
@ -836,23 +758,23 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||
params->src_w/uv_hscale);
|
||||
tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
|
||||
params->src_w/uv_hscale);
|
||||
swidthsw |= max_u32(tmp_U, tmp_V) << 16;
|
||||
swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
|
||||
sheight |= (params->src_h/uv_vscale) << 16;
|
||||
regs->OBUF_0U = new_bo->gtt_offset + params->offset_U;
|
||||
regs->OBUF_0V = new_bo->gtt_offset + params->offset_V;
|
||||
iowrite32(new_bo->gtt_offset + params->offset_U, ®s->OBUF_0U);
|
||||
iowrite32(new_bo->gtt_offset + params->offset_V, ®s->OBUF_0V);
|
||||
ostride |= params->stride_UV << 16;
|
||||
}
|
||||
|
||||
regs->SWIDTH = swidth;
|
||||
regs->SWIDTHSW = swidthsw;
|
||||
regs->SHEIGHT = sheight;
|
||||
regs->OSTRIDE = ostride;
|
||||
iowrite32(swidth, ®s->SWIDTH);
|
||||
iowrite32(swidthsw, ®s->SWIDTHSW);
|
||||
iowrite32(sheight, ®s->SHEIGHT);
|
||||
iowrite32(ostride, ®s->OSTRIDE);
|
||||
|
||||
scale_changed = update_scaling_factors(overlay, regs, params);
|
||||
|
||||
update_colorkey(overlay, regs);
|
||||
|
||||
regs->OCMD = overlay_cmd_reg(params);
|
||||
iowrite32(overlay_cmd_reg(params), ®s->OCMD);
|
||||
|
||||
intel_overlay_unmap_regs(overlay, regs);
|
||||
|
||||
@ -872,10 +794,14 @@ out_unpin:
|
||||
|
||||
int intel_overlay_switch_off(struct intel_overlay *overlay)
|
||||
{
|
||||
struct overlay_registers *regs;
|
||||
struct overlay_registers __iomem *regs;
|
||||
#ifdef INVARIANTS
|
||||
struct drm_device *dev = overlay->dev;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
DRM_LOCK_ASSERT(overlay->dev);
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
sx_assert(&dev->mode_config.mutex, SA_XLOCKED);
|
||||
|
||||
ret = intel_overlay_recover_from_interrupt(overlay);
|
||||
if (ret != 0)
|
||||
@ -889,7 +815,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
|
||||
return ret;
|
||||
|
||||
regs = intel_overlay_map_regs(overlay);
|
||||
regs->OCMD = 0;
|
||||
iowrite32(0, ®s->OCMD);
|
||||
intel_overlay_unmap_regs(overlay, regs);
|
||||
|
||||
ret = intel_overlay_off(overlay);
|
||||
@ -1138,7 +1064,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
return ret;
|
||||
}
|
||||
|
||||
params = malloc(sizeof(struct put_image_params), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
params = malloc(sizeof(struct put_image_params), DRM_I915_GEM, M_WAITOK);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC);
|
||||
@ -1254,10 +1182,11 @@ out_free:
|
||||
}
|
||||
|
||||
static void update_reg_attrs(struct intel_overlay *overlay,
|
||||
struct overlay_registers *regs)
|
||||
struct overlay_registers __iomem *regs)
|
||||
{
|
||||
regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
|
||||
regs->OCLRC1 = overlay->saturation;
|
||||
iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
|
||||
®s->OCLRC0);
|
||||
iowrite32(overlay->saturation, ®s->OCLRC1);
|
||||
}
|
||||
|
||||
static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
|
||||
@ -1310,7 +1239,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
|
||||
struct drm_intel_overlay_attrs *attrs = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_overlay *overlay;
|
||||
struct overlay_registers *regs;
|
||||
struct overlay_registers __iomem *regs;
|
||||
int ret;
|
||||
|
||||
/* No need to check for DRIVER_MODESET - we don't set it up then. */
|
||||
@ -1396,16 +1325,20 @@ void intel_setup_overlay(struct drm_device *dev)
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_overlay *overlay;
|
||||
struct drm_i915_gem_object *reg_bo;
|
||||
struct overlay_registers *regs;
|
||||
struct overlay_registers __iomem *regs;
|
||||
int ret;
|
||||
|
||||
if (!HAS_OVERLAY(dev))
|
||||
return;
|
||||
|
||||
overlay = malloc(sizeof(struct intel_overlay), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
if (!overlay)
|
||||
return;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
if (dev_priv->overlay != NULL)
|
||||
if (WARN_ON(dev_priv->overlay))
|
||||
goto out_free;
|
||||
|
||||
overlay->dev = dev;
|
||||
|
||||
reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
|
||||
@ -1423,7 +1356,7 @@ void intel_setup_overlay(struct drm_device *dev)
|
||||
}
|
||||
overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
|
||||
} else {
|
||||
ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
|
||||
ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin overlay register bo\n");
|
||||
goto out_free_bo;
|
||||
@ -1447,7 +1380,7 @@ void intel_setup_overlay(struct drm_device *dev)
|
||||
if (!regs)
|
||||
goto out_unpin_bo;
|
||||
|
||||
memset(regs, 0, sizeof(struct overlay_registers));
|
||||
memset_io(regs, 0, sizeof(struct overlay_registers));
|
||||
update_polyphase_filter(regs);
|
||||
update_reg_attrs(overlay, regs);
|
||||
|
||||
@ -1479,12 +1412,15 @@ void intel_cleanup_overlay(struct drm_device *dev)
|
||||
/* The bo's should be free'd by the generic code already.
|
||||
* Furthermore modesetting teardown happens beforehand so the
|
||||
* hardware should be off already */
|
||||
KASSERT(!dev_priv->overlay->active, ("Overlay still active"));
|
||||
BUG_ON(dev_priv->overlay->active);
|
||||
|
||||
drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
|
||||
free(dev_priv->overlay, DRM_I915_GEM);
|
||||
}
|
||||
|
||||
//#ifdef CONFIG_DEBUG_FS
|
||||
#define seq_printf(m, fmt, ...) sbuf_printf((m), (fmt), ##__VA_ARGS__)
|
||||
|
||||
struct intel_overlay_error_state {
|
||||
struct overlay_registers regs;
|
||||
unsigned long base;
|
||||
@ -1492,6 +1428,11 @@ struct intel_overlay_error_state {
|
||||
u32 isr;
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE Linux<->FreeBSD: We use the normal intel_overlay_map_regs() and
|
||||
* intel_overlay_unmap_regs() defined at the top of this file.
|
||||
*/
|
||||
|
||||
struct intel_overlay_error_state *
|
||||
intel_overlay_capture_error_state(struct drm_device *dev)
|
||||
{
|
||||
@ -1510,15 +1451,15 @@ intel_overlay_capture_error_state(struct drm_device *dev)
|
||||
error->dovsta = I915_READ(DOVSTA);
|
||||
error->isr = I915_READ(ISR);
|
||||
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
|
||||
error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
|
||||
error->base = (__force long)overlay->reg_bo->phys_obj->handle->vaddr;
|
||||
else
|
||||
error->base = (long) overlay->reg_bo->gtt_offset;
|
||||
error->base = overlay->reg_bo->gtt_offset;
|
||||
|
||||
regs = intel_overlay_map_regs(overlay);
|
||||
if (!regs)
|
||||
goto err;
|
||||
|
||||
memcpy(&error->regs, regs, sizeof(struct overlay_registers));
|
||||
memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
|
||||
intel_overlay_unmap_regs(overlay, regs);
|
||||
|
||||
return error;
|
||||
@ -1531,12 +1472,12 @@ err:
|
||||
void
|
||||
intel_overlay_print_error_state(struct sbuf *m, struct intel_overlay_error_state *error)
|
||||
{
|
||||
sbuf_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
|
||||
error->dovsta, error->isr);
|
||||
sbuf_printf(m, " Register file at 0x%08lx:\n",
|
||||
error->base);
|
||||
seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
|
||||
error->dovsta, error->isr);
|
||||
seq_printf(m, " Register file at 0x%08lx:\n",
|
||||
error->base);
|
||||
|
||||
#define P(x) sbuf_printf(m, " " #x ": 0x%08x\n", error->regs.x)
|
||||
#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
|
||||
P(OBUF_0Y);
|
||||
P(OBUF_1Y);
|
||||
P(OBUF_0U);
|
||||
@ -1580,3 +1521,4 @@ intel_overlay_print_error_state(struct sbuf *m, struct intel_overlay_error_state
|
||||
P(UVSCALEV);
|
||||
#undef P
|
||||
}
|
||||
//#endif
|
||||
|
@ -31,9 +31,9 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
|
||||
@ -95,7 +95,7 @@ intel_pch_panel_fitting(struct drm_device *dev,
|
||||
} else if (scaled_width < scaled_height) { /* letter */
|
||||
height = scaled_width / mode->hdisplay;
|
||||
if (height & 1)
|
||||
height++;
|
||||
height++;
|
||||
y = (adjusted_mode->vdisplay - height + 1) / 2;
|
||||
x = 0;
|
||||
width = adjusted_mode->hdisplay;
|
||||
@ -133,53 +133,45 @@ static int is_backlight_combination_mode(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
|
||||
static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
/* Restore the CTL value if it lost, e.g. GPU reset */
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv->dev)) {
|
||||
val = I915_READ(BLC_PWM_PCH_CTL2);
|
||||
if (dev_priv->saveBLC_PWM_CTL2 == 0) {
|
||||
dev_priv->saveBLC_PWM_CTL2 = val;
|
||||
if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) {
|
||||
dev_priv->regfile.saveBLC_PWM_CTL2 = val;
|
||||
} else if (val == 0) {
|
||||
I915_WRITE(BLC_PWM_PCH_CTL2,
|
||||
dev_priv->saveBLC_PWM_CTL2);
|
||||
val = dev_priv->saveBLC_PWM_CTL2;
|
||||
val = dev_priv->regfile.saveBLC_PWM_CTL2;
|
||||
I915_WRITE(BLC_PWM_PCH_CTL2, val);
|
||||
}
|
||||
} else {
|
||||
val = I915_READ(BLC_PWM_CTL);
|
||||
if (dev_priv->saveBLC_PWM_CTL == 0) {
|
||||
dev_priv->saveBLC_PWM_CTL = val;
|
||||
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
|
||||
if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
|
||||
dev_priv->regfile.saveBLC_PWM_CTL = val;
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
dev_priv->regfile.saveBLC_PWM_CTL2 =
|
||||
I915_READ(BLC_PWM_CTL2);
|
||||
} else if (val == 0) {
|
||||
I915_WRITE(BLC_PWM_CTL,
|
||||
dev_priv->saveBLC_PWM_CTL);
|
||||
I915_WRITE(BLC_PWM_CTL2,
|
||||
dev_priv->saveBLC_PWM_CTL2);
|
||||
val = dev_priv->saveBLC_PWM_CTL;
|
||||
val = dev_priv->regfile.saveBLC_PWM_CTL;
|
||||
I915_WRITE(BLC_PWM_CTL, val);
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
I915_WRITE(BLC_PWM_CTL2,
|
||||
dev_priv->regfile.saveBLC_PWM_CTL2);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 intel_panel_get_max_backlight(struct drm_device *dev)
|
||||
static u32 _intel_panel_get_max_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 max;
|
||||
|
||||
max = i915_read_blc_pwm_ctl(dev_priv);
|
||||
if (max == 0) {
|
||||
/* XXX add code here to query mode clock or hardware clock
|
||||
* and program max PWM appropriately.
|
||||
*/
|
||||
#if 0
|
||||
printf("fixme: max PWM is zero.\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
max = i915_read_blc_pwm_ctl(dev);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
max >>= 16;
|
||||
@ -193,10 +185,34 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
|
||||
max *= 0xff;
|
||||
}
|
||||
|
||||
DRM_DEBUG("max backlight PWM = %d\n", max);
|
||||
return max;
|
||||
}
|
||||
|
||||
u32 intel_panel_get_max_backlight(struct drm_device *dev)
|
||||
{
|
||||
u32 max;
|
||||
|
||||
max = _intel_panel_get_max_backlight(dev);
|
||||
if (max == 0) {
|
||||
/* XXX add code here to query mode clock or hardware clock
|
||||
* and program max PWM appropriately.
|
||||
*/
|
||||
pr_warn_once("fixme: max PWM is zero\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
|
||||
return max;
|
||||
}
|
||||
|
||||
static int i915_panel_invert_brightness;
|
||||
TUNABLE_INT("drm.i915.invert_brightness", &i915_panel_invert_brightness);
|
||||
MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
|
||||
"(-1 force normal, 0 machine defaults, 1 force inversion), please "
|
||||
"report PCI device ID, subsystem vendor and subsystem device ID "
|
||||
"to dri-devel@lists.freedesktop.org, if your machine needs it. "
|
||||
"It will then be included in an upcoming module version.");
|
||||
module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
|
||||
static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -211,7 +227,7 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||
static u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
@ -226,7 +242,7 @@ u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||
if (is_backlight_combination_mode(dev)) {
|
||||
u8 lbpc;
|
||||
|
||||
lbpc = pci_read_config(dev->dev, PCI_LBPC, 1);
|
||||
pci_read_config_byte(dev->dev, PCI_LBPC, &lbpc);
|
||||
val *= lbpc;
|
||||
}
|
||||
}
|
||||
@ -260,11 +276,11 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level
|
||||
|
||||
lbpc = level * 0xfe / max + 1;
|
||||
level /= lbpc;
|
||||
pci_write_config(dev->dev, PCI_LBPC, lbpc, 4);
|
||||
pci_write_config_byte(dev->dev, PCI_LBPC, lbpc);
|
||||
}
|
||||
|
||||
tmp = I915_READ(BLC_PWM_CTL);
|
||||
if (INTEL_INFO(dev)->gen < 4)
|
||||
if (INTEL_INFO(dev)->gen < 4)
|
||||
level <<= 1;
|
||||
tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
I915_WRITE(BLC_PWM_CTL, tmp | level);
|
||||
@ -285,15 +301,69 @@ void intel_panel_disable_backlight(struct drm_device *dev)
|
||||
|
||||
dev_priv->backlight_enabled = false;
|
||||
intel_panel_actually_set_backlight(dev, 0);
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
uint32_t reg, tmp;
|
||||
|
||||
reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
|
||||
|
||||
I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
tmp = I915_READ(BLC_PWM_PCH_CTL1);
|
||||
tmp &= ~BLM_PCH_PWM_ENABLE;
|
||||
I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void intel_panel_enable_backlight(struct drm_device *dev)
|
||||
void intel_panel_enable_backlight(struct drm_device *dev,
|
||||
enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->backlight_level == 0)
|
||||
dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
uint32_t reg, tmp;
|
||||
|
||||
reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2;
|
||||
|
||||
|
||||
tmp = I915_READ(reg);
|
||||
|
||||
/* Note that this can also get called through dpms changes. And
|
||||
* we don't track the backlight dpms state, hence check whether
|
||||
* we have to do anything first. */
|
||||
if (tmp & BLM_PWM_ENABLE)
|
||||
goto set_level;
|
||||
|
||||
if (dev_priv->num_pipe == 3)
|
||||
tmp &= ~BLM_PIPE_SELECT_IVB;
|
||||
else
|
||||
tmp &= ~BLM_PIPE_SELECT;
|
||||
|
||||
tmp |= BLM_PIPE(pipe);
|
||||
tmp &= ~BLM_PWM_ENABLE;
|
||||
|
||||
I915_WRITE(reg, tmp);
|
||||
POSTING_READ(reg);
|
||||
I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
tmp = I915_READ(BLC_PWM_PCH_CTL1);
|
||||
tmp |= BLM_PCH_PWM_ENABLE;
|
||||
tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
|
||||
I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
set_level:
|
||||
/* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
|
||||
* BLC_PWM_CPU_CTL may be cleared to zero automatically when these
|
||||
* registers are set.
|
||||
*/
|
||||
dev_priv->backlight_enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
|
||||
}
|
||||
@ -309,31 +379,90 @@ static void intel_panel_init_backlight(struct drm_device *dev)
|
||||
enum drm_connector_status
|
||||
intel_panel_detect(struct drm_device *dev)
|
||||
{
|
||||
#if 0
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
#endif
|
||||
|
||||
if (i915_panel_ignore_lid)
|
||||
return i915_panel_ignore_lid > 0 ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
|
||||
/* opregion lid state on HP 2540p is wrong at boot up,
|
||||
* appears to be either the BIOS or Linux ACPI fault */
|
||||
#if 0
|
||||
/* Assume that the BIOS does not lie through the OpRegion... */
|
||||
if (dev_priv->opregion.lid_state)
|
||||
if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) {
|
||||
return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
#endif
|
||||
}
|
||||
|
||||
return connector_status_unknown;
|
||||
switch (i915_panel_ignore_lid) {
|
||||
case -2:
|
||||
return connector_status_connected;
|
||||
case -1:
|
||||
return connector_status_disconnected;
|
||||
default:
|
||||
return connector_status_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
int intel_panel_setup_backlight(struct drm_device *dev)
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
static int intel_panel_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev = bl_get_data(bd);
|
||||
intel_panel_set_backlight(dev, bd->props.brightness);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_panel_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev = bl_get_data(bd);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->backlight_level;
|
||||
}
|
||||
|
||||
static const struct backlight_ops intel_panel_bl_ops = {
|
||||
.update_status = intel_panel_update_status,
|
||||
.get_brightness = intel_panel_get_brightness,
|
||||
};
|
||||
|
||||
int intel_panel_setup_backlight(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct backlight_properties props;
|
||||
|
||||
intel_panel_init_backlight(dev);
|
||||
|
||||
if (WARN_ON(dev_priv->backlight))
|
||||
return -ENODEV;
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.max_brightness = _intel_panel_get_max_backlight(dev);
|
||||
if (props.max_brightness == 0) {
|
||||
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_priv->backlight =
|
||||
backlight_device_register("intel_backlight",
|
||||
&connector->kdev, dev,
|
||||
&intel_panel_bl_ops, &props);
|
||||
|
||||
if (IS_ERR(dev_priv->backlight)) {
|
||||
DRM_ERROR("Failed to register backlight: %ld\n",
|
||||
PTR_ERR(dev_priv->backlight));
|
||||
dev_priv->backlight = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_panel_destroy_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
if (dev_priv->backlight) {
|
||||
backlight_device_unregister(dev_priv->backlight);
|
||||
dev_priv->backlight = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int intel_panel_setup_backlight(struct drm_connector *connector)
|
||||
{
|
||||
intel_panel_init_backlight(connector->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -341,3 +470,21 @@ void intel_panel_destroy_backlight(struct drm_device *dev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int intel_panel_init(struct intel_panel *panel,
|
||||
struct drm_display_mode *fixed_mode)
|
||||
{
|
||||
panel->fixed_mode = fixed_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_panel_fini(struct intel_panel *panel)
|
||||
{
|
||||
struct intel_connector *intel_connector =
|
||||
container_of(panel, struct intel_connector, panel);
|
||||
|
||||
if (panel->fixed_mode)
|
||||
drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,9 @@
|
||||
/*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_RINGBUFFER_H_
|
||||
#define _INTEL_RINGBUFFER_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use"
|
||||
* Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use"
|
||||
@ -50,7 +49,7 @@ struct intel_ring_buffer {
|
||||
} id;
|
||||
#define I915_NUM_RINGS 3
|
||||
u32 mmio_base;
|
||||
void *virtual_start;
|
||||
void __iomem *virtual_start;
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
@ -75,21 +74,28 @@ struct intel_ring_buffer {
|
||||
u32 irq_enable_mask; /* bitmask to enable ring interrupt */
|
||||
u32 trace_irq_seqno;
|
||||
u32 sync_seqno[I915_NUM_RINGS-1];
|
||||
bool (*irq_get)(struct intel_ring_buffer *ring);
|
||||
bool __must_check (*irq_get)(struct intel_ring_buffer *ring);
|
||||
void (*irq_put)(struct intel_ring_buffer *ring);
|
||||
|
||||
int (*init)(struct intel_ring_buffer *ring);
|
||||
|
||||
void (*write_tail)(struct intel_ring_buffer *ring,
|
||||
u32 value);
|
||||
int (*flush)(struct intel_ring_buffer *ring,
|
||||
int __must_check (*flush)(struct intel_ring_buffer *ring,
|
||||
u32 invalidate_domains,
|
||||
u32 flush_domains);
|
||||
int (*add_request)(struct intel_ring_buffer *ring,
|
||||
uint32_t *seqno);
|
||||
uint32_t (*get_seqno)(struct intel_ring_buffer *ring);
|
||||
int (*add_request)(struct intel_ring_buffer *ring);
|
||||
/* Some chipsets are not quite as coherent as advertised and need
|
||||
* an expensive kick to force a true read of the up-to-date seqno.
|
||||
* However, the up-to-date seqno is not always required and the last
|
||||
* seen value is good enough. Note that the seqno will always be
|
||||
* monotonic, even if not coherent.
|
||||
*/
|
||||
u32 (*get_seqno)(struct intel_ring_buffer *ring,
|
||||
bool lazy_coherency);
|
||||
int (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
|
||||
u32 offset, u32 length);
|
||||
u32 offset, u32 length,
|
||||
unsigned flags);
|
||||
#define I915_DISPATCH_SECURE 0x1
|
||||
#define I915_DISPATCH_PINNED 0x2
|
||||
void (*cleanup)(struct intel_ring_buffer *ring);
|
||||
@ -117,19 +123,13 @@ struct intel_ring_buffer {
|
||||
*/
|
||||
struct list_head request_list;
|
||||
|
||||
/**
|
||||
* List of objects currently pending a GPU write flush.
|
||||
*
|
||||
* All elements on this list will belong to either the
|
||||
* active_list or flushing_list, last_rendering_seqno can
|
||||
* be used to differentiate between the two elements.
|
||||
*/
|
||||
struct list_head gpu_write_list;
|
||||
|
||||
/**
|
||||
* Do we have some not yet emitted requests outstanding?
|
||||
*/
|
||||
u32 outstanding_lazy_request;
|
||||
bool gpu_caches_dirty;
|
||||
|
||||
wait_queue_head_t irq_queue;
|
||||
|
||||
/**
|
||||
* Do an explicit TLB flush before MI_SET_CONTEXT
|
||||
@ -138,8 +138,6 @@ struct intel_ring_buffer {
|
||||
struct i915_hw_context *default_context;
|
||||
struct drm_i915_gem_object *last_context_obj;
|
||||
|
||||
drm_local_map_t map;
|
||||
|
||||
void *private;
|
||||
};
|
||||
|
||||
@ -179,32 +177,43 @@ intel_read_status_page(struct intel_ring_buffer *ring,
|
||||
int reg)
|
||||
{
|
||||
/* Ensure that the compiler doesn't optimize away the load. */
|
||||
__compiler_membar();
|
||||
barrier();
|
||||
return atomic_load_acq_32(ring->status_page.page_addr + reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a dword out of the status page, which is written to from the command
|
||||
* queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
|
||||
* MI_STORE_DATA_IMM.
|
||||
*
|
||||
* The following dwords have a reserved meaning:
|
||||
* 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
|
||||
* 0x04: ring 0 head pointer
|
||||
* 0x05: ring 1 head pointer (915-class)
|
||||
* 0x06: ring 2 head pointer (915-class)
|
||||
* 0x10-0x1b: Context status DWords (GM45)
|
||||
* 0x1f: Last written status offset. (GM45)
|
||||
*
|
||||
* The area from dword 0x20 to 0x3ff is available for driver usage.
|
||||
*/
|
||||
#define I915_GEM_HWS_INDEX 0x20
|
||||
#define I915_GEM_HWS_SCRATCH_INDEX 0x30
|
||||
#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
|
||||
|
||||
void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
|
||||
|
||||
int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
|
||||
static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
|
||||
{
|
||||
|
||||
return (intel_wait_ring_buffer(ring, ring->size - 8));
|
||||
}
|
||||
|
||||
int intel_ring_begin(struct intel_ring_buffer *ring, int n);
|
||||
|
||||
int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
|
||||
static inline void intel_ring_emit(struct intel_ring_buffer *ring,
|
||||
u32 data)
|
||||
{
|
||||
*(volatile uint32_t *)((char *)ring->virtual_start +
|
||||
ring->tail) = data;
|
||||
iowrite32(data, ring->virtual_start + ring->tail);
|
||||
ring->tail += 4;
|
||||
}
|
||||
|
||||
void intel_ring_advance(struct intel_ring_buffer *ring);
|
||||
int __must_check intel_ring_idle(struct intel_ring_buffer *ring);
|
||||
|
||||
uint32_t intel_ring_get_seqno(struct intel_ring_buffer *ring);
|
||||
int intel_ring_flush_all_caches(struct intel_ring_buffer *ring);
|
||||
int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring);
|
||||
|
||||
int intel_init_render_ring_buffer(struct drm_device *dev);
|
||||
int intel_init_bsd_ring_buffer(struct drm_device *dev);
|
||||
@ -218,7 +227,19 @@ static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring)
|
||||
return ring->tail;
|
||||
}
|
||||
|
||||
void i915_trace_irq_get(struct intel_ring_buffer *ring, uint32_t seqno);
|
||||
static inline u32 intel_ring_get_seqno(struct intel_ring_buffer *ring)
|
||||
{
|
||||
BUG_ON(ring->outstanding_lazy_request == 0);
|
||||
return ring->outstanding_lazy_request;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno)
|
||||
{
|
||||
if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
|
||||
ring->trace_irq_seqno = seqno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* DRI warts */
|
||||
int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -34,11 +34,11 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_fourcc.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/drm_fourcc.h>
|
||||
|
||||
static void
|
||||
ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
@ -52,7 +52,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe;
|
||||
u32 sprctl, sprscale = 0;
|
||||
int pixel_size;
|
||||
unsigned long sprsurf_offset, linear_offset;
|
||||
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
||||
|
||||
sprctl = I915_READ(SPRCTL(pipe));
|
||||
|
||||
@ -60,37 +61,29 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
sprctl &= ~SPRITE_PIXFORMAT_MASK;
|
||||
sprctl &= ~SPRITE_RGB_ORDER_RGBX;
|
||||
sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
|
||||
sprctl &= ~SPRITE_TILED;
|
||||
|
||||
switch (fb->pixel_format) {
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
sprctl |= SPRITE_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
|
||||
break;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
|
||||
pixel_size = 4;
|
||||
sprctl |= SPRITE_FORMAT_RGBX888;
|
||||
break;
|
||||
case DRM_FORMAT_YUYV:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_YVYU:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_UYVY:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_VYUY:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
|
||||
sprctl |= DVS_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
@ -130,18 +123,27 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
|
||||
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
|
||||
I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
|
||||
if (obj->tiling_mode != I915_TILING_NONE) {
|
||||
I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
|
||||
} else {
|
||||
unsigned long offset;
|
||||
|
||||
offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
|
||||
I915_WRITE(SPRLINOFF(pipe), offset);
|
||||
}
|
||||
linear_offset = y * fb->pitches[0] + x * pixel_size;
|
||||
sprsurf_offset =
|
||||
intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
|
||||
pixel_size, fb->pitches[0]);
|
||||
linear_offset -= sprsurf_offset;
|
||||
|
||||
/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
|
||||
* register */
|
||||
if (IS_HASWELL(dev))
|
||||
I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
|
||||
else if (obj->tiling_mode != I915_TILING_NONE)
|
||||
I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
|
||||
else
|
||||
I915_WRITE(SPRLINOFF(pipe), linear_offset);
|
||||
|
||||
I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
|
||||
I915_WRITE(SPRSCALE(pipe), sprscale);
|
||||
if (intel_plane->can_scale)
|
||||
I915_WRITE(SPRSCALE(pipe), sprscale);
|
||||
I915_WRITE(SPRCTL(pipe), sprctl);
|
||||
I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset);
|
||||
I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset);
|
||||
POSTING_READ(SPRSURF(pipe));
|
||||
}
|
||||
|
||||
@ -155,7 +157,8 @@ ivb_disable_plane(struct drm_plane *plane)
|
||||
|
||||
I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
|
||||
/* Can't leave the scaler enabled... */
|
||||
I915_WRITE(SPRSCALE(pipe), 0);
|
||||
if (intel_plane->can_scale)
|
||||
I915_WRITE(SPRSCALE(pipe), 0);
|
||||
/* Activate double buffered register update */
|
||||
I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
|
||||
POSTING_READ(SPRSURF(pipe));
|
||||
@ -228,8 +231,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe, pixel_size;
|
||||
int pipe = intel_plane->pipe;
|
||||
unsigned long dvssurf_offset, linear_offset;
|
||||
u32 dvscntr, dvsscale;
|
||||
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
||||
|
||||
dvscntr = I915_READ(DVSCNTR(pipe));
|
||||
|
||||
@ -237,37 +242,29 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
dvscntr &= ~DVS_PIXFORMAT_MASK;
|
||||
dvscntr &= ~DVS_RGB_ORDER_XBGR;
|
||||
dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
|
||||
dvscntr &= ~DVS_TILED;
|
||||
|
||||
switch (fb->pixel_format) {
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
dvscntr |= DVS_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
case DRM_FORMAT_YUYV:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_YVYU:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_UYVY:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_VYUY:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
|
||||
dvscntr |= DVS_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
@ -291,18 +288,22 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
|
||||
I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
|
||||
I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
|
||||
if (obj->tiling_mode != I915_TILING_NONE) {
|
||||
I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
|
||||
} else {
|
||||
unsigned long offset;
|
||||
|
||||
offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
|
||||
I915_WRITE(DVSLINOFF(pipe), offset);
|
||||
}
|
||||
linear_offset = y * fb->pitches[0] + x * pixel_size;
|
||||
dvssurf_offset =
|
||||
intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
|
||||
pixel_size, fb->pitches[0]);
|
||||
linear_offset -= dvssurf_offset;
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
|
||||
else
|
||||
I915_WRITE(DVSLINOFF(pipe), linear_offset);
|
||||
|
||||
I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
|
||||
I915_WRITE(DVSSCALE(pipe), dvsscale);
|
||||
I915_WRITE(DVSCNTR(pipe), dvscntr);
|
||||
I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset);
|
||||
I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset);
|
||||
POSTING_READ(DVSSURF(pipe));
|
||||
}
|
||||
|
||||
@ -330,6 +331,12 @@ intel_enable_primary(struct drm_crtc *crtc)
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int reg = DSPCNTR(intel_crtc->plane);
|
||||
|
||||
if (!intel_crtc->primary_disabled)
|
||||
return;
|
||||
|
||||
intel_crtc->primary_disabled = false;
|
||||
intel_update_fbc(dev);
|
||||
|
||||
I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
|
||||
}
|
||||
|
||||
@ -341,7 +348,13 @@ intel_disable_primary(struct drm_crtc *crtc)
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int reg = DSPCNTR(intel_crtc->plane);
|
||||
|
||||
if (intel_crtc->primary_disabled)
|
||||
return;
|
||||
|
||||
I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
|
||||
|
||||
intel_crtc->primary_disabled = true;
|
||||
intel_update_fbc(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -412,6 +425,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
struct intel_framebuffer *intel_fb;
|
||||
struct drm_i915_gem_object *obj, *old_obj;
|
||||
int pipe = intel_plane->pipe;
|
||||
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
||||
pipe);
|
||||
int ret = 0;
|
||||
int x = src_x >> 16, y = src_y >> 16;
|
||||
int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
|
||||
@ -426,7 +441,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
src_h = src_h >> 16;
|
||||
|
||||
/* Pipe must be running... */
|
||||
if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
|
||||
if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
if (crtc_x >= primary_w || crtc_y >= primary_h)
|
||||
@ -436,6 +451,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
if (intel_plane->pipe != intel_crtc->pipe)
|
||||
return -EINVAL;
|
||||
|
||||
/* Sprite planes can be linear or x-tiled surfaces */
|
||||
switch (obj->tiling_mode) {
|
||||
case I915_TILING_NONE:
|
||||
case I915_TILING_X:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clamp the width & height into the visible area. Note we don't
|
||||
* try to scale the source if part of the visible region is offscreen.
|
||||
@ -462,6 +486,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
if (!crtc_w || !crtc_h) /* Again, nothing to display */
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We may not have a scaler, eg. HSW does not have it any more
|
||||
*/
|
||||
if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* We can take a larger source and scale it down, but
|
||||
* only so much... 16x is the max on SNB.
|
||||
@ -489,18 +519,14 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
* Be sure to re-enable the primary before the sprite is no longer
|
||||
* covering it fully.
|
||||
*/
|
||||
if (!disable_primary && intel_plane->primary_disabled) {
|
||||
if (!disable_primary)
|
||||
intel_enable_primary(crtc);
|
||||
intel_plane->primary_disabled = false;
|
||||
}
|
||||
|
||||
intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
|
||||
crtc_w, crtc_h, x, y, src_w, src_h);
|
||||
|
||||
if (disable_primary) {
|
||||
if (disable_primary)
|
||||
intel_disable_primary(crtc);
|
||||
intel_plane->primary_disabled = true;
|
||||
}
|
||||
|
||||
/* Unpin old obj after new one is active to avoid ugliness */
|
||||
if (old_obj) {
|
||||
@ -531,11 +557,8 @@ intel_disable_plane(struct drm_plane *plane)
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int ret = 0;
|
||||
|
||||
if (intel_plane->primary_disabled) {
|
||||
if (plane->crtc)
|
||||
intel_enable_primary(plane->crtc);
|
||||
intel_plane->primary_disabled = false;
|
||||
}
|
||||
|
||||
intel_plane->disable_plane(plane);
|
||||
|
||||
if (!intel_plane->obj)
|
||||
@ -575,7 +598,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
return -EINVAL;
|
||||
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
|
||||
|
||||
obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
|
||||
if (!obj) {
|
||||
ret = -EINVAL;
|
||||
@ -655,12 +678,14 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
|
||||
if (INTEL_INFO(dev)->gen < 5)
|
||||
return -ENODEV;
|
||||
|
||||
intel_plane = malloc(sizeof(struct intel_plane), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
intel_plane = malloc(sizeof(struct intel_plane), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_plane)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 5:
|
||||
case 6:
|
||||
intel_plane->can_scale = true;
|
||||
intel_plane->max_downscale = 16;
|
||||
intel_plane->update_plane = ilk_update_plane;
|
||||
intel_plane->disable_plane = ilk_disable_plane;
|
||||
@ -669,14 +694,18 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
|
||||
|
||||
if (IS_GEN6(dev)) {
|
||||
plane_formats = snb_plane_formats;
|
||||
num_plane_formats = DRM_ARRAY_SIZE(snb_plane_formats);
|
||||
num_plane_formats = ARRAY_SIZE(snb_plane_formats);
|
||||
} else {
|
||||
plane_formats = ilk_plane_formats;
|
||||
num_plane_formats = DRM_ARRAY_SIZE(ilk_plane_formats);
|
||||
num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev))
|
||||
intel_plane->can_scale = false;
|
||||
else
|
||||
intel_plane->can_scale = true;
|
||||
intel_plane->max_downscale = 2;
|
||||
intel_plane->update_plane = ivb_update_plane;
|
||||
intel_plane->disable_plane = ivb_disable_plane;
|
||||
@ -684,10 +713,11 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
|
||||
intel_plane->get_colorkey = ivb_get_colorkey;
|
||||
|
||||
plane_formats = snb_plane_formats;
|
||||
num_plane_formats = DRM_ARRAY_SIZE(snb_plane_formats);
|
||||
num_plane_formats = ARRAY_SIZE(snb_plane_formats);
|
||||
break;
|
||||
|
||||
default:
|
||||
free(intel_plane, DRM_MEM_KMS);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -702,4 +732,3 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -34,12 +34,11 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
enum tv_margin {
|
||||
TV_MARGIN_LEFT, TV_MARGIN_TOP,
|
||||
@ -676,6 +675,54 @@ static const struct tv_mode tv_modes[] = {
|
||||
|
||||
.filter_table = filter_table,
|
||||
},
|
||||
{
|
||||
.name = "480p",
|
||||
.clock = 107520,
|
||||
.refresh = 59940,
|
||||
.oversample = TV_OVERSAMPLE_4X,
|
||||
.component_only = 1,
|
||||
|
||||
.hsync_end = 64, .hblank_end = 122,
|
||||
.hblank_start = 842, .htotal = 857,
|
||||
|
||||
.progressive = true, .trilevel_sync = false,
|
||||
|
||||
.vsync_start_f1 = 12, .vsync_start_f2 = 12,
|
||||
.vsync_len = 12,
|
||||
|
||||
.veq_ena = false,
|
||||
|
||||
.vi_end_f1 = 44, .vi_end_f2 = 44,
|
||||
.nbr_end = 479,
|
||||
|
||||
.burst_ena = false,
|
||||
|
||||
.filter_table = filter_table,
|
||||
},
|
||||
{
|
||||
.name = "576p",
|
||||
.clock = 107520,
|
||||
.refresh = 50000,
|
||||
.oversample = TV_OVERSAMPLE_4X,
|
||||
.component_only = 1,
|
||||
|
||||
.hsync_end = 64, .hblank_end = 139,
|
||||
.hblank_start = 859, .htotal = 863,
|
||||
|
||||
.progressive = true, .trilevel_sync = false,
|
||||
|
||||
.vsync_start_f1 = 10, .vsync_start_f2 = 10,
|
||||
.vsync_len = 10,
|
||||
|
||||
.veq_ena = false,
|
||||
|
||||
.vi_end_f1 = 48, .vi_end_f2 = 48,
|
||||
.nbr_end = 575,
|
||||
|
||||
.burst_ena = false,
|
||||
|
||||
.filter_table = filter_table,
|
||||
},
|
||||
{
|
||||
.name = "720p@60Hz",
|
||||
.clock = 148800,
|
||||
@ -791,22 +838,37 @@ static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
|
||||
base);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_tv_dpms(struct drm_encoder *encoder, int mode)
|
||||
static bool
|
||||
intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 tmp = I915_READ(TV_CTL);
|
||||
|
||||
if (!(tmp & TV_ENC_ENABLE))
|
||||
return false;
|
||||
|
||||
*pipe = PORT_TO_PIPE(tmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_enable_tv(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
|
||||
break;
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
|
||||
break;
|
||||
}
|
||||
I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_disable_tv(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
|
||||
}
|
||||
|
||||
static const struct tv_mode *
|
||||
@ -814,7 +876,7 @@ intel_tv_mode_lookup(const char *tv_format)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DRM_ARRAY_SIZE(tv_modes); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
|
||||
const struct tv_mode *tv_mode = &tv_modes[i];
|
||||
|
||||
if (!strcmp(tv_format, tv_mode->name))
|
||||
@ -846,24 +908,18 @@ intel_tv_mode_valid(struct drm_connector *connector,
|
||||
|
||||
|
||||
static bool
|
||||
intel_tv_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode,
|
||||
intel_tv_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_mode_config *drm_config = &dev->mode_config;
|
||||
struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
|
||||
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
|
||||
struct drm_encoder *other_encoder;
|
||||
|
||||
if (!tv_mode)
|
||||
return false;
|
||||
|
||||
/* FIXME: lock encoder list */
|
||||
list_for_each_entry(other_encoder, &drm_config->encoder_list, head) {
|
||||
if (other_encoder != encoder &&
|
||||
other_encoder->crtc == encoder->crtc)
|
||||
return false;
|
||||
}
|
||||
if (intel_encoder_check_is_cloned(&intel_tv->base))
|
||||
return false;
|
||||
|
||||
adjusted_mode->clock = tv_mode->clock;
|
||||
return true;
|
||||
@ -1035,13 +1091,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||
int dspcntr_reg = DSPCNTR(intel_crtc->plane);
|
||||
int pipeconf = I915_READ(pipeconf_reg);
|
||||
int dspcntr = I915_READ(dspcntr_reg);
|
||||
int dspbase_reg = DSPADDR(intel_crtc->plane);
|
||||
int xpos = 0x0, ypos = 0x0;
|
||||
unsigned int xsize, ysize;
|
||||
/* Pipe must be off here */
|
||||
I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
|
||||
/* Flush the plane changes */
|
||||
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
|
||||
intel_flush_display_plane(dev_priv, intel_crtc->plane);
|
||||
|
||||
/* Wait for vblank for the disable to take effect */
|
||||
if (IS_GEN2(dev))
|
||||
@ -1070,8 +1124,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||
|
||||
I915_WRITE(pipeconf_reg, pipeconf);
|
||||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
/* Flush the plane changes */
|
||||
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
|
||||
intel_flush_display_plane(dev_priv, intel_crtc->plane);
|
||||
}
|
||||
|
||||
j = 0;
|
||||
@ -1196,6 +1249,11 @@ intel_tv_detect_type(struct intel_tv *intel_tv,
|
||||
|
||||
I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
|
||||
I915_WRITE(TV_CTL, save_tv_ctl);
|
||||
POSTING_READ(TV_CTL);
|
||||
|
||||
/* For unknown reasons the hw barfs if we don't do this vblank wait. */
|
||||
intel_wait_for_vblank(intel_tv->base.base.dev,
|
||||
to_intel_crtc(intel_tv->base.base.crtc)->pipe);
|
||||
|
||||
/* Restore interrupt config */
|
||||
if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
|
||||
@ -1251,17 +1309,13 @@ intel_tv_detect(struct drm_connector *connector, bool force)
|
||||
int type;
|
||||
|
||||
mode = reported_modes[0];
|
||||
drm_mode_set_crtcinfo(&mode, 0);
|
||||
|
||||
if (force) {
|
||||
struct intel_load_detect_pipe tmp;
|
||||
|
||||
if (intel_get_load_detect_pipe(&intel_tv->base, connector,
|
||||
&mode, &tmp)) {
|
||||
if (intel_get_load_detect_pipe(connector, &mode, &tmp)) {
|
||||
type = intel_tv_detect_type(intel_tv, connector);
|
||||
intel_release_load_detect_pipe(&intel_tv->base,
|
||||
connector,
|
||||
&tmp);
|
||||
intel_release_load_detect_pipe(connector, &tmp);
|
||||
} else
|
||||
return connector_status_unknown;
|
||||
} else
|
||||
@ -1360,7 +1414,7 @@ intel_tv_get_modes(struct drm_connector *connector)
|
||||
|
||||
tmp = (u64) tv_mode->refresh * mode_ptr->vtotal;
|
||||
tmp *= mode_ptr->htotal;
|
||||
tmp = tmp / 1000000;
|
||||
tmp = div_u64(tmp, 1000000);
|
||||
mode_ptr->clock = (int) tmp;
|
||||
|
||||
mode_ptr->type = DRM_MODE_TYPE_DRIVER;
|
||||
@ -1375,9 +1429,6 @@ intel_tv_get_modes(struct drm_connector *connector)
|
||||
static void
|
||||
intel_tv_destroy(struct drm_connector *connector)
|
||||
{
|
||||
#if 0
|
||||
drm_sysfs_connector_remove(connector);
|
||||
#endif
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
@ -1429,22 +1480,20 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
|
||||
}
|
||||
|
||||
if (changed && crtc)
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
|
||||
crtc->y, crtc->fb);
|
||||
intel_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y, crtc->fb);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
|
||||
.dpms = intel_tv_dpms,
|
||||
.mode_fixup = intel_tv_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.mode_set = intel_tv_mode_set,
|
||||
.commit = intel_encoder_commit,
|
||||
.disable = intel_encoder_noop,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_tv_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.dpms = intel_connector_dpms,
|
||||
.detect = intel_tv_detect,
|
||||
.destroy = intel_tv_destroy,
|
||||
.set_property = intel_tv_set_property,
|
||||
@ -1543,10 +1592,16 @@ intel_tv_init(struct drm_device *dev)
|
||||
(tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
|
||||
return;
|
||||
|
||||
intel_tv = malloc(sizeof(struct intel_tv), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
intel_tv = malloc(sizeof(struct intel_tv), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_tv) {
|
||||
return;
|
||||
}
|
||||
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
if (!intel_connector) {
|
||||
free(intel_tv, DRM_MEM_KMS);
|
||||
return;
|
||||
}
|
||||
|
||||
intel_encoder = &intel_tv->base;
|
||||
connector = &intel_connector->base;
|
||||
@ -1568,10 +1623,15 @@ intel_tv_init(struct drm_device *dev)
|
||||
drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
|
||||
DRM_MODE_ENCODER_TVDAC);
|
||||
|
||||
intel_encoder->enable = intel_enable_tv;
|
||||
intel_encoder->disable = intel_disable_tv;
|
||||
intel_encoder->get_hw_state = intel_tv_get_hw_state;
|
||||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
|
||||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
intel_encoder->type = INTEL_OUTPUT_TVOUT;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
||||
intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
|
||||
intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
|
||||
intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
|
||||
@ -1610,7 +1670,4 @@ intel_tv_init(struct drm_device *dev)
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.tv_bottom_margin_property,
|
||||
intel_tv->margin[TV_MARGIN_BOTTOM]);
|
||||
#if 0
|
||||
drm_sysfs_connector_add(connector);
|
||||
#endif
|
||||
}
|
||||
|
@ -3,23 +3,31 @@
|
||||
.PATH: ${.CURDIR}/../../../dev/drm2/i915
|
||||
KMOD = i915kms
|
||||
SRCS = \
|
||||
dvo_ch7017.c \
|
||||
dvo_ch7xxx.c \
|
||||
dvo_ivch.c \
|
||||
dvo_ns2501.c \
|
||||
dvo_sil164.c \
|
||||
dvo_tfp410.c \
|
||||
i915_debug.c \
|
||||
i915_dma.c \
|
||||
i915_drv.c \
|
||||
i915_gem.c \
|
||||
i915_gem_context.c \
|
||||
i915_gem_execbuffer.c \
|
||||
i915_gem_evict.c \
|
||||
i915_gem_execbuffer.c \
|
||||
i915_gem_gtt.c \
|
||||
i915_gem_stolen.c \
|
||||
i915_gem_tiling.c \
|
||||
i915_irq.c \
|
||||
i915_suspend.c \
|
||||
intel_acpi.c \
|
||||
intel_bios.c \
|
||||
intel_crt.c \
|
||||
intel_ddi.c \
|
||||
intel_display.c \
|
||||
intel_dp.c \
|
||||
intel_dvo.c \
|
||||
intel_fb.c \
|
||||
intel_hdmi.c \
|
||||
intel_iic.c \
|
||||
|
Loading…
x
Reference in New Issue
Block a user