drm-misc-next for v5.3:
UAPI Changes: - Give each dma-buf their own inode, add DMA_BUF_SET_NAME ioctl and a show_fdinfo handler. Cross-subsystem Changes: - Pull in the topic/remove-fbcon-notifiers branch: * remove fbdev notifier usage for fbcon, as prep work to clean up the fbcon locking * assorted locking checks in vt/console code * assorted notifier and cleanups in fbdev and backlight code Core Changes: - Make drm_debugfs_create_files() never fail. - add debug print to update_vblank_count. - Add DP_DPCD_QUIRK_NO_SINK_COUNT quirk. - Add todo item for drm_gem_objects. - Unexport drm_gem_(un)pin/v(un)map. - Document struct drm_cmdline_mode. - Rewrite the command handler for mode names, and add support to specify rotation, reflection and overscan. With a new selftest! :) - Fixes to drm/client for improving rotation support, and fixing variable scope. - Small fixes to self refresh helper. Driver Changes: - Add rockchip RK3328 support. - Assorted driver fixes to rockchip, vc4, rcar-du, vkms. - Expose panfrost performance counters through unstable ioctl's, hidden behind a module parameter. - Enumerate CRC sources list in vkms. - Add a basic kms driver for the Ingenic JZ47xx SoC, which will be expanded soon with more advanced features. - Suspend/resume fix for stm. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAl0LqJIACgkQ/lWMcqZw E8OWPA/8DryVJQE8ld6SB9nRhd8BAYLPH2f/mNN2yttqElku1rEWCvVHq6v4zrmZ kOkJUsutFC9YEwKphCbfb24xtRS/o5bAk05BQMMzu0wTj/hga2uS9zkOfmgKtVFJ u73J5VThWQKqjCMGOgrInd8tGPq0Kazzc3TrFhjAicM3fhmkz5vd64MvJifTpAM9 nkG7cr53eUQfcKKv52rEY5DzV8NelnyASOMVdcsdqpcteJVhIcB0hXAULsLb3pGR dOADvzo8yIFERCCYnzBV85PO7vzTC+4zOFUZnfMHQ6THzvo3jzXkaOAyTV+KFv+M bJEJSPf9zRSqEehae9yekjMH0R819f1RnVQc7lteSMYiR/T+gciyZtf9wGoasuhd MoyhoOr3l2l4SGrGelrrKFIe3Ht1FUTA+Ni5cyJv0/FUms9sqMODTytXpSuUvxqg +4r95+Ly/06RxiUxfPZAtvamaQLr5PaiNdilytg0m4NzgJqcbx2xWeKo9bnt1QA4 7doC/USc0bsjtf9kDSDTTT1T0d/KYtUmpMHCSy0OmjnI4wPh9RxOyoSKfIs7uVSB 92q194KHTu0BmWeWS9XoIMs+vK7DiaeTX9PiHusbfhpapkoDFddG0JosrAfIyqKl cGs3ODdA6kM2/j4j4bsZHdULkVOPDrmxiz6qoq6mfPTBemxlcYA= =A67v -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2019-06-20' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for v5.3: UAPI Changes: - Give each dma-buf their own inode, add DMA_BUF_SET_NAME ioctl and a show_fdinfo handler. Cross-subsystem Changes: - Pull in the topic/remove-fbcon-notifiers branch: * remove fbdev notifier usage for fbcon, as prep work to clean up the fbcon locking * assorted locking checks in vt/console code * assorted notifier and cleanups in fbdev and backlight code Core Changes: - Make drm_debugfs_create_files() never fail. - add debug print to update_vblank_count. - Add DP_DPCD_QUIRK_NO_SINK_COUNT quirk. - Add todo item for drm_gem_objects. - Unexport drm_gem_(un)pin/v(un)map. - Document struct drm_cmdline_mode. - Rewrite the command handler for mode names, and add support to specify rotation, reflection and overscan. With a new selftest! :) - Fixes to drm/client for improving rotation support, and fixing variable scope. - Small fixes to self refresh helper. Driver Changes: - Add rockchip RK3328 support. - Assorted driver fixes to rockchip, vc4, rcar-du, vkms. - Expose panfrost performance counters through unstable ioctl's, hidden behind a module parameter. - Enumerate CRC sources list in vkms. - Add a basic kms driver for the Ingenic JZ47xx SoC, which will be expanded soon with more advanced features. - Suspend/resume fix for stm. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/18e22ec1-adf3-3a75-34a3-9fe09a91eef5@linux.intel.com
This commit is contained in:
commit
39a207d0cf
44
Documentation/devicetree/bindings/display/ingenic,lcd.txt
Normal file
44
Documentation/devicetree/bindings/display/ingenic,lcd.txt
Normal file
@ -0,0 +1,44 @@
|
||||
Ingenic JZ47xx LCD driver
|
||||
|
||||
Required properties:
|
||||
- compatible: one of:
|
||||
* ingenic,jz4740-lcd
|
||||
* ingenic,jz4725b-lcd
|
||||
- reg: LCD registers location and length
|
||||
- clocks: LCD pixclock and device clock specifiers.
|
||||
The device clock is only required on the JZ4740.
|
||||
- clock-names: "lcd_pclk" and "lcd"
|
||||
- interrupts: Specifies the interrupt line the LCD controller is connected to.
|
||||
|
||||
Example:
|
||||
|
||||
panel {
|
||||
compatible = "sharp,ls020b1dd01d";
|
||||
|
||||
backlight = <&backlight>;
|
||||
power-supply = <&vcc>;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&panel_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
lcd: lcd-controller@13050000 {
|
||||
compatible = "ingenic,jz4725b-lcd";
|
||||
reg = <0x13050000 0x1000>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <31>;
|
||||
|
||||
clocks = <&cgu JZ4725B_CLK_LCD>;
|
||||
clock-names = "lcd";
|
||||
|
||||
port {
|
||||
panel_output: endpoint {
|
||||
remote-endpoint = <&panel_input>;
|
||||
};
|
||||
};
|
||||
};
|
@ -12,6 +12,7 @@ following device-specific properties.
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of the following:
|
||||
"rockchip,rk3228-dw-hdmi"
|
||||
"rockchip,rk3288-dw-hdmi"
|
||||
"rockchip,rk3328-dw-hdmi"
|
||||
"rockchip,rk3399-dw-hdmi"
|
||||
|
@ -51,6 +51,20 @@ To force the VGA output to be enabled and drive a specific mode say:
|
||||
Specifying the option multiple times for different ports is possible, e.g.:
|
||||
video=LVDS-1:d video=HDMI-1:D
|
||||
|
||||
Options can also be passed after the mode, using commas as separator.
|
||||
|
||||
Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
|
||||
|
||||
Valid options are:
|
||||
|
||||
- margin_top, margin_bottom, margin_left, margin_right (integer):
|
||||
Number of pixels in the margins, typically to deal with overscan on TVs
|
||||
- reflect_x (boolean): Perform an axial symmetry on the X axis
|
||||
- reflect_y (boolean): Perform an axial symmetry on the Y axis
|
||||
- rotate (integer): Rotate the initial framebuffer by x
|
||||
degrees. Valid values are 0, 90, 180 and 270.
|
||||
|
||||
|
||||
***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
|
||||
|
||||
What is the VESA(TM) Coordinated Video Timings (CVT)?
|
||||
|
@ -228,6 +228,12 @@ struct drm_gem_object_funcs
|
||||
GEM objects can now have a function table instead of having the callbacks on the
|
||||
DRM driver struct. This is now the preferred way and drivers can be moved over.
|
||||
|
||||
DRM_GEM_CMA_VMAP_DRIVER_OPS, DRM_GEM_SHMEM_DRIVER_OPS already support this, but
|
||||
DRM_GEM_VRAM_DRIVER_PRIME does not yet and needs to be aligned with the previous
|
||||
two. We also need a 2nd version of the CMA define that doesn't require the
|
||||
vmapping to be present (different hook for prime importing). Plus this needs to
|
||||
be rolled out to all drivers using their own implementations, too.
|
||||
|
||||
Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate
|
||||
---------------------------------------------------------
|
||||
|
||||
|
@ -347,8 +347,17 @@ int __init am200_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* before anything else, we request notification for any fb
|
||||
* creation events */
|
||||
/*
|
||||
* Before anything else, we request notification for any fb
|
||||
* creation events.
|
||||
*
|
||||
* FIXME: This is terrible and needs to be nuked. The notifier is used
|
||||
* to get at the fb base address from the boot splash fb driver, which
|
||||
* is then passed to metronomefb. Instaed of metronomfb or this board
|
||||
* support file here figuring this out on their own.
|
||||
*
|
||||
* See also the #ifdef in fbmem.c.
|
||||
*/
|
||||
fb_register_client(&am200_fb_notif);
|
||||
|
||||
pxa2xx_mfp_config(ARRAY_AND_SIZE(am200_pin_config));
|
||||
|
@ -34,8 +34,10 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/reservation.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
#include <uapi/linux/dma-buf.h>
|
||||
#include <uapi/linux/magic.h>
|
||||
|
||||
static inline int is_dma_buf_file(struct file *);
|
||||
|
||||
@ -46,6 +48,41 @@ struct dma_buf_list {
|
||||
|
||||
static struct dma_buf_list db_list;
|
||||
|
||||
static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
|
||||
{
|
||||
struct dma_buf *dmabuf;
|
||||
char name[DMA_BUF_NAME_LEN];
|
||||
size_t ret = 0;
|
||||
|
||||
dmabuf = dentry->d_fsdata;
|
||||
mutex_lock(&dmabuf->lock);
|
||||
if (dmabuf->name)
|
||||
ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
|
||||
mutex_unlock(&dmabuf->lock);
|
||||
|
||||
return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
|
||||
dentry->d_name.name, ret > 0 ? name : "");
|
||||
}
|
||||
|
||||
static const struct dentry_operations dma_buf_dentry_ops = {
|
||||
.d_dname = dmabuffs_dname,
|
||||
};
|
||||
|
||||
static struct vfsmount *dma_buf_mnt;
|
||||
|
||||
static struct dentry *dma_buf_fs_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *name, void *data)
|
||||
{
|
||||
return mount_pseudo(fs_type, "dmabuf:", NULL, &dma_buf_dentry_ops,
|
||||
DMA_BUF_MAGIC);
|
||||
}
|
||||
|
||||
static struct file_system_type dma_buf_fs_type = {
|
||||
.name = "dmabuf",
|
||||
.mount = dma_buf_fs_mount,
|
||||
.kill_sb = kill_anon_super,
|
||||
};
|
||||
|
||||
static int dma_buf_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dma_buf *dmabuf;
|
||||
@ -280,6 +317,43 @@ out:
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_buf_set_name - Set a name to a specific dma_buf to track the usage.
|
||||
* The name of the dma-buf buffer can only be set when the dma-buf is not
|
||||
* attached to any devices. It could theoritically support changing the
|
||||
* name of the dma-buf if the same piece of memory is used for multiple
|
||||
* purpose between different devices.
|
||||
*
|
||||
* @dmabuf [in] dmabuf buffer that will be renamed.
|
||||
* @buf: [in] A piece of userspace memory that contains the name of
|
||||
* the dma-buf.
|
||||
*
|
||||
* Returns 0 on success. If the dma-buf buffer is already attached to
|
||||
* devices, return -EBUSY.
|
||||
*
|
||||
*/
|
||||
static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
|
||||
{
|
||||
char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
|
||||
long ret = 0;
|
||||
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
mutex_lock(&dmabuf->lock);
|
||||
if (!list_empty(&dmabuf->attachments)) {
|
||||
ret = -EBUSY;
|
||||
kfree(name);
|
||||
goto out_unlock;
|
||||
}
|
||||
kfree(dmabuf->name);
|
||||
dmabuf->name = name;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&dmabuf->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long dma_buf_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@ -318,11 +392,29 @@ static long dma_buf_ioctl(struct file *file,
|
||||
ret = dma_buf_begin_cpu_access(dmabuf, direction);
|
||||
|
||||
return ret;
|
||||
|
||||
case DMA_BUF_SET_NAME:
|
||||
return dma_buf_set_name(dmabuf, (const char __user *)arg);
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
static void dma_buf_show_fdinfo(struct seq_file *m, struct file *file)
|
||||
{
|
||||
struct dma_buf *dmabuf = file->private_data;
|
||||
|
||||
seq_printf(m, "size:\t%zu\n", dmabuf->size);
|
||||
/* Don't count the temporary reference taken inside procfs seq_show */
|
||||
seq_printf(m, "count:\t%ld\n", file_count(dmabuf->file) - 1);
|
||||
seq_printf(m, "exp_name:\t%s\n", dmabuf->exp_name);
|
||||
mutex_lock(&dmabuf->lock);
|
||||
if (dmabuf->name)
|
||||
seq_printf(m, "name:\t%s\n", dmabuf->name);
|
||||
mutex_unlock(&dmabuf->lock);
|
||||
}
|
||||
|
||||
static const struct file_operations dma_buf_fops = {
|
||||
.release = dma_buf_release,
|
||||
.mmap = dma_buf_mmap_internal,
|
||||
@ -332,6 +424,7 @@ static const struct file_operations dma_buf_fops = {
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = dma_buf_ioctl,
|
||||
#endif
|
||||
.show_fdinfo = dma_buf_show_fdinfo,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -342,6 +435,32 @@ static inline int is_dma_buf_file(struct file *file)
|
||||
return file->f_op == &dma_buf_fops;
|
||||
}
|
||||
|
||||
static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
|
||||
{
|
||||
struct file *file;
|
||||
struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb);
|
||||
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
inode->i_size = dmabuf->size;
|
||||
inode_set_bytes(inode, dmabuf->size);
|
||||
|
||||
file = alloc_file_pseudo(inode, dma_buf_mnt, "dmabuf",
|
||||
flags, &dma_buf_fops);
|
||||
if (IS_ERR(file))
|
||||
goto err_alloc_file;
|
||||
file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
|
||||
file->private_data = dmabuf;
|
||||
file->f_path.dentry->d_fsdata = dmabuf;
|
||||
|
||||
return file;
|
||||
|
||||
err_alloc_file:
|
||||
iput(inode);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: dma buf device access
|
||||
*
|
||||
@ -436,8 +555,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
|
||||
}
|
||||
dmabuf->resv = resv;
|
||||
|
||||
file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf,
|
||||
exp_info->flags);
|
||||
file = dma_buf_getfile(dmabuf, exp_info->flags);
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
goto err_dmabuf;
|
||||
@ -1055,8 +1173,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
return ret;
|
||||
|
||||
seq_puts(s, "\nDma-buf Objects:\n");
|
||||
seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\n",
|
||||
"size", "flags", "mode", "count");
|
||||
seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\n",
|
||||
"size", "flags", "mode", "count", "ino");
|
||||
|
||||
list_for_each_entry(buf_obj, &db_list.head, list_node) {
|
||||
ret = mutex_lock_interruptible(&buf_obj->lock);
|
||||
@ -1067,11 +1185,13 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
continue;
|
||||
}
|
||||
|
||||
seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n",
|
||||
seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\n",
|
||||
buf_obj->size,
|
||||
buf_obj->file->f_flags, buf_obj->file->f_mode,
|
||||
file_count(buf_obj->file),
|
||||
buf_obj->exp_name);
|
||||
buf_obj->exp_name,
|
||||
file_inode(buf_obj->file)->i_ino,
|
||||
buf_obj->name ?: "");
|
||||
|
||||
robj = buf_obj->resv;
|
||||
while (true) {
|
||||
@ -1167,6 +1287,10 @@ static inline void dma_buf_uninit_debugfs(void)
|
||||
|
||||
static int __init dma_buf_init(void)
|
||||
{
|
||||
dma_buf_mnt = kern_mount(&dma_buf_fs_type);
|
||||
if (IS_ERR(dma_buf_mnt))
|
||||
return PTR_ERR(dma_buf_mnt);
|
||||
|
||||
mutex_init(&db_list.lock);
|
||||
INIT_LIST_HEAD(&db_list.head);
|
||||
dma_buf_init_debugfs();
|
||||
@ -1177,5 +1301,6 @@ subsys_initcall(dma_buf_init);
|
||||
static void __exit dma_buf_deinit(void)
|
||||
{
|
||||
dma_buf_uninit_debugfs();
|
||||
kern_unmount(dma_buf_mnt);
|
||||
}
|
||||
__exitcall(dma_buf_deinit);
|
||||
|
@ -316,6 +316,8 @@ source "drivers/gpu/drm/sti/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/imx/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/ingenic/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/v3d/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/vc4/Kconfig"
|
||||
|
@ -99,6 +99,7 @@ obj-$(CONFIG_DRM_TEGRA) += tegra/
|
||||
obj-$(CONFIG_DRM_STM) += stm/
|
||||
obj-$(CONFIG_DRM_STI) += sti/
|
||||
obj-$(CONFIG_DRM_IMX) += imx/
|
||||
obj-$(CONFIG_DRM_INGENIC) += ingenic/
|
||||
obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
|
||||
obj-$(CONFIG_DRM_MESON) += meson/
|
||||
obj-y += i2c/
|
||||
|
@ -379,6 +379,24 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_connector_tv_reset - Resets TV connector properties
|
||||
* @connector: DRM connector
|
||||
*
|
||||
* Resets the TV-related properties attached to a connector.
|
||||
*/
|
||||
void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
|
||||
struct drm_connector_state *state = connector->state;
|
||||
|
||||
state->tv.margins.left = cmdline->tv_margins.left;
|
||||
state->tv.margins.right = cmdline->tv_margins.right;
|
||||
state->tv.margins.top = cmdline->tv_margins.top;
|
||||
state->tv.margins.bottom = cmdline->tv_margins.bottom;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
|
||||
|
||||
/**
|
||||
* __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
|
||||
* @connector: connector object
|
||||
|
@ -149,6 +149,10 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector)
|
||||
prefer_non_interlace = !cmdline_mode->interlace;
|
||||
again:
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
/* Check (optional) mode name first */
|
||||
if (!strcmp(mode->name, cmdline_mode->name))
|
||||
return mode;
|
||||
|
||||
/* check width/height */
|
||||
if (mode->hdisplay != cmdline_mode->xres ||
|
||||
mode->vdisplay != cmdline_mode->yres)
|
||||
@ -804,22 +808,23 @@ free_connectors:
|
||||
EXPORT_SYMBOL(drm_client_modeset_probe);
|
||||
|
||||
/**
|
||||
* drm_client_panel_rotation() - Check panel orientation
|
||||
* drm_client_rotation() - Check the initial rotation value
|
||||
* @modeset: DRM modeset
|
||||
* @rotation: Returned rotation value
|
||||
*
|
||||
* This function checks if the primary plane in @modeset can hw rotate to match
|
||||
* the panel orientation on its connector.
|
||||
* This function checks if the primary plane in @modeset can hw rotate
|
||||
* to match the rotation needed on its connector.
|
||||
*
|
||||
* Note: Currently only 0 and 180 degrees are supported.
|
||||
*
|
||||
* Return:
|
||||
* True if the plane can do the rotation, false otherwise.
|
||||
*/
|
||||
bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
|
||||
bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
|
||||
{
|
||||
struct drm_connector *connector = modeset->connectors[0];
|
||||
struct drm_plane *plane = modeset->crtc->primary;
|
||||
struct drm_cmdline_mode *cmdline;
|
||||
u64 valid_mask = 0;
|
||||
unsigned int i;
|
||||
|
||||
@ -840,12 +845,42 @@ bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotat
|
||||
*rotation = DRM_MODE_ROTATE_0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The panel already defined the default rotation
|
||||
* through its orientation. Whatever has been provided
|
||||
* on the command line needs to be added to that.
|
||||
*
|
||||
* Unfortunately, the rotations are at different bit
|
||||
* indices, so the math to add them up are not as
|
||||
* trivial as they could.
|
||||
*
|
||||
* Reflections on the other hand are pretty trivial to deal with, a
|
||||
* simple XOR between the two handle the addition nicely.
|
||||
*/
|
||||
cmdline = &connector->cmdline_mode;
|
||||
if (cmdline->specified) {
|
||||
unsigned int cmdline_rest, panel_rest;
|
||||
unsigned int cmdline_rot, panel_rot;
|
||||
unsigned int sum_rot, sum_rest;
|
||||
|
||||
panel_rot = ilog2(*rotation & DRM_MODE_ROTATE_MASK);
|
||||
cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
|
||||
sum_rot = (panel_rot + cmdline_rot) % 4;
|
||||
|
||||
panel_rest = *rotation & ~DRM_MODE_ROTATE_MASK;
|
||||
cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
|
||||
sum_rest = panel_rest ^ cmdline_rest;
|
||||
|
||||
*rotation = (1 << sum_rot) | sum_rest;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: support 90 / 270 degree hardware rotation,
|
||||
* depending on the hardware this may require the framebuffer
|
||||
* to be in a specific tiling format.
|
||||
*/
|
||||
if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
|
||||
if ((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180 ||
|
||||
!plane->rotation_property)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < plane->rotation_property->num_values; i++)
|
||||
@ -856,12 +891,11 @@ bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotat
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_panel_rotation);
|
||||
EXPORT_SYMBOL(drm_client_rotation);
|
||||
|
||||
static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_plane *plane;
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
@ -879,6 +913,8 @@ static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool
|
||||
state->acquire_ctx = &ctx;
|
||||
retry:
|
||||
drm_for_each_plane(plane, dev) {
|
||||
struct drm_plane_state *plane_state;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state, plane);
|
||||
if (IS_ERR(plane_state)) {
|
||||
ret = PTR_ERR(plane_state);
|
||||
@ -900,7 +936,9 @@ retry:
|
||||
struct drm_plane *primary = mode_set->crtc->primary;
|
||||
unsigned int rotation;
|
||||
|
||||
if (drm_client_panel_rotation(mode_set, &rotation)) {
|
||||
if (drm_client_rotation(mode_set, &rotation)) {
|
||||
struct drm_plane_state *plane_state;
|
||||
|
||||
/* Cannot fail as we've already gotten the plane state above */
|
||||
plane_state = drm_atomic_get_new_plane_state(state, primary);
|
||||
plane_state->rotation = rotation;
|
||||
|
@ -139,8 +139,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
|
||||
connector->force = mode->force;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
|
||||
DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
|
||||
connector->name,
|
||||
mode->name ? mode->name : "",
|
||||
mode->xres, mode->yres,
|
||||
mode->refresh_specified ? mode->refresh : 60,
|
||||
mode->rb ? " reduced blanking" : "",
|
||||
|
@ -176,9 +176,8 @@ int drm_debugfs_create_files(const struct drm_info_list *files, int count,
|
||||
struct dentry *root, struct drm_minor *minor)
|
||||
{
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct dentry *ent;
|
||||
struct drm_info_node *tmp;
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
u32 features = files[i].driver_features;
|
||||
@ -188,22 +187,13 @@ int drm_debugfs_create_files(const struct drm_info_list *files, int count,
|
||||
continue;
|
||||
|
||||
tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
|
||||
if (tmp == NULL) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
|
||||
root, tmp, &drm_debugfs_fops);
|
||||
if (!ent) {
|
||||
DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/%s\n",
|
||||
root, files[i].name);
|
||||
kfree(tmp);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
if (tmp == NULL)
|
||||
continue;
|
||||
|
||||
tmp->minor = minor;
|
||||
tmp->dent = ent;
|
||||
tmp->dent = debugfs_create_file(files[i].name,
|
||||
S_IFREG | S_IRUGO, root, tmp,
|
||||
&drm_debugfs_fops);
|
||||
tmp->info_ent = &files[i];
|
||||
|
||||
mutex_lock(&minor->debugfs_lock);
|
||||
@ -211,10 +201,6 @@ int drm_debugfs_create_files(const struct drm_info_list *files, int count,
|
||||
mutex_unlock(&minor->debugfs_lock);
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
drm_debugfs_remove_files(files, count, minor);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_debugfs_create_files);
|
||||
|
||||
|
@ -1280,7 +1280,9 @@ static const struct dpcd_quirk dpcd_quirk_list[] = {
|
||||
/* LG LP140WF6-SPM1 eDP panel */
|
||||
{ OUI(0x00, 0x22, 0xb9), DEVICE_ID('s', 'i', 'v', 'a', 'r', 'T'), false, BIT(DP_DPCD_QUIRK_CONSTANT_N) },
|
||||
/* Apple panels need some additional handling to support PSR */
|
||||
{ OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) }
|
||||
{ OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) },
|
||||
/* CH7511 seems to leave SINK_COUNT zeroed */
|
||||
{ OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) },
|
||||
};
|
||||
|
||||
#undef OUI
|
||||
|
@ -1722,7 +1722,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
|
||||
|
||||
modeset->fb = fb_helper->fb;
|
||||
|
||||
if (drm_client_panel_rotation(modeset, &rotation))
|
||||
if (drm_client_rotation(modeset, &rotation))
|
||||
/* Rotating in hardware, fbcon should not rotate */
|
||||
sw_rotations |= DRM_MODE_ROTATE_0;
|
||||
else
|
||||
|
@ -1216,15 +1216,6 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
|
||||
obj->dev->driver->gem_print_info(p, indent, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gem_pin - Pin backing buffer in memory
|
||||
* @obj: GEM object
|
||||
*
|
||||
* Make sure the backing buffer is pinned in memory.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_gem_pin(struct drm_gem_object *obj)
|
||||
{
|
||||
if (obj->funcs && obj->funcs->pin)
|
||||
@ -1234,14 +1225,7 @@ int drm_gem_pin(struct drm_gem_object *obj)
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_pin);
|
||||
|
||||
/**
|
||||
* drm_gem_unpin - Unpin backing buffer from memory
|
||||
* @obj: GEM object
|
||||
*
|
||||
* Relax the requirement that the backing buffer is pinned in memory.
|
||||
*/
|
||||
void drm_gem_unpin(struct drm_gem_object *obj)
|
||||
{
|
||||
if (obj->funcs && obj->funcs->unpin)
|
||||
@ -1249,16 +1233,7 @@ void drm_gem_unpin(struct drm_gem_object *obj)
|
||||
else if (obj->dev->driver->gem_prime_unpin)
|
||||
obj->dev->driver->gem_prime_unpin(obj);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_unpin);
|
||||
|
||||
/**
|
||||
* drm_gem_vmap - Map buffer into kernel virtual address space
|
||||
* @obj: GEM object
|
||||
*
|
||||
* Returns:
|
||||
* A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
|
||||
* error code on failure.
|
||||
*/
|
||||
void *drm_gem_vmap(struct drm_gem_object *obj)
|
||||
{
|
||||
void *vaddr;
|
||||
@ -1275,13 +1250,7 @@ void *drm_gem_vmap(struct drm_gem_object *obj)
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vmap);
|
||||
|
||||
/**
|
||||
* drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
|
||||
* @obj: GEM object
|
||||
* @vaddr: Virtual address (can be NULL)
|
||||
*/
|
||||
void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
|
||||
{
|
||||
if (!vaddr)
|
||||
@ -1292,7 +1261,6 @@ void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
|
||||
else if (obj->dev->driver->gem_prime_vunmap)
|
||||
obj->dev->driver->gem_prime_vunmap(obj, vaddr);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vunmap);
|
||||
|
||||
/**
|
||||
* drm_gem_lock_reservations - Sets up the ww context and acquires
|
||||
|
@ -133,6 +133,11 @@ void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
|
||||
void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
|
||||
const struct drm_gem_object *obj);
|
||||
|
||||
int drm_gem_pin(struct drm_gem_object *obj);
|
||||
void drm_gem_unpin(struct drm_gem_object *obj);
|
||||
void *drm_gem_vmap(struct drm_gem_object *obj);
|
||||
void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
|
||||
/* drm_debugfs.c drm_debugfs_crc.c */
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
|
||||
|
@ -30,6 +30,7 @@
|
||||
* authorization from the copyright holder(s) and author(s).
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/list_sort.h>
|
||||
#include <linux/export.h>
|
||||
@ -1408,6 +1409,260 @@ void drm_connector_list_update(struct drm_connector *connector)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_list_update);
|
||||
|
||||
static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
|
||||
struct drm_cmdline_mode *mode)
|
||||
{
|
||||
unsigned int bpp;
|
||||
|
||||
if (str[0] != '-')
|
||||
return -EINVAL;
|
||||
|
||||
str++;
|
||||
bpp = simple_strtol(str, end_ptr, 10);
|
||||
if (*end_ptr == str)
|
||||
return -EINVAL;
|
||||
|
||||
mode->bpp = bpp;
|
||||
mode->bpp_specified = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
|
||||
struct drm_cmdline_mode *mode)
|
||||
{
|
||||
unsigned int refresh;
|
||||
|
||||
if (str[0] != '@')
|
||||
return -EINVAL;
|
||||
|
||||
str++;
|
||||
refresh = simple_strtol(str, end_ptr, 10);
|
||||
if (*end_ptr == str)
|
||||
return -EINVAL;
|
||||
|
||||
mode->refresh = refresh;
|
||||
mode->refresh_specified = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_mode_parse_cmdline_extra(const char *str, int length,
|
||||
struct drm_connector *connector,
|
||||
struct drm_cmdline_mode *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
switch (str[i]) {
|
||||
case 'i':
|
||||
mode->interlace = true;
|
||||
break;
|
||||
case 'm':
|
||||
mode->margins = true;
|
||||
break;
|
||||
case 'D':
|
||||
if (mode->force != DRM_FORCE_UNSPECIFIED)
|
||||
return -EINVAL;
|
||||
|
||||
if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
|
||||
(connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
|
||||
mode->force = DRM_FORCE_ON;
|
||||
else
|
||||
mode->force = DRM_FORCE_ON_DIGITAL;
|
||||
break;
|
||||
case 'd':
|
||||
if (mode->force != DRM_FORCE_UNSPECIFIED)
|
||||
return -EINVAL;
|
||||
|
||||
mode->force = DRM_FORCE_OFF;
|
||||
break;
|
||||
case 'e':
|
||||
if (mode->force != DRM_FORCE_UNSPECIFIED)
|
||||
return -EINVAL;
|
||||
|
||||
mode->force = DRM_FORCE_ON;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
|
||||
bool extras,
|
||||
struct drm_connector *connector,
|
||||
struct drm_cmdline_mode *mode)
|
||||
{
|
||||
const char *str_start = str;
|
||||
bool rb = false, cvt = false;
|
||||
int xres = 0, yres = 0;
|
||||
int remaining, i;
|
||||
char *end_ptr;
|
||||
|
||||
xres = simple_strtol(str, &end_ptr, 10);
|
||||
if (end_ptr == str)
|
||||
return -EINVAL;
|
||||
|
||||
if (end_ptr[0] != 'x')
|
||||
return -EINVAL;
|
||||
end_ptr++;
|
||||
|
||||
str = end_ptr;
|
||||
yres = simple_strtol(str, &end_ptr, 10);
|
||||
if (end_ptr == str)
|
||||
return -EINVAL;
|
||||
|
||||
remaining = length - (end_ptr - str_start);
|
||||
if (remaining < 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < remaining; i++) {
|
||||
switch (end_ptr[i]) {
|
||||
case 'M':
|
||||
cvt = true;
|
||||
break;
|
||||
case 'R':
|
||||
rb = true;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Try to pass that to our extras parsing
|
||||
* function to handle the case where the
|
||||
* extras are directly after the resolution
|
||||
*/
|
||||
if (extras) {
|
||||
int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
|
||||
1,
|
||||
connector,
|
||||
mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode->xres = xres;
|
||||
mode->yres = yres;
|
||||
mode->cvt = cvt;
|
||||
mode->rb = rb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_mode_parse_cmdline_options(char *str, size_t len,
|
||||
struct drm_connector *connector,
|
||||
struct drm_cmdline_mode *mode)
|
||||
{
|
||||
unsigned int rotation = 0;
|
||||
char *sep = str;
|
||||
|
||||
while ((sep = strchr(sep, ','))) {
|
||||
char *delim, *option;
|
||||
|
||||
option = sep + 1;
|
||||
delim = strchr(option, '=');
|
||||
if (!delim) {
|
||||
delim = strchr(option, ',');
|
||||
|
||||
if (!delim)
|
||||
delim = str + len;
|
||||
}
|
||||
|
||||
if (!strncmp(option, "rotate", delim - option)) {
|
||||
const char *value = delim + 1;
|
||||
unsigned int deg;
|
||||
|
||||
deg = simple_strtol(value, &sep, 10);
|
||||
|
||||
/* Make sure we have parsed something */
|
||||
if (sep == value)
|
||||
return -EINVAL;
|
||||
|
||||
switch (deg) {
|
||||
case 0:
|
||||
rotation |= DRM_MODE_ROTATE_0;
|
||||
break;
|
||||
|
||||
case 90:
|
||||
rotation |= DRM_MODE_ROTATE_90;
|
||||
break;
|
||||
|
||||
case 180:
|
||||
rotation |= DRM_MODE_ROTATE_180;
|
||||
break;
|
||||
|
||||
case 270:
|
||||
rotation |= DRM_MODE_ROTATE_270;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!strncmp(option, "reflect_x", delim - option)) {
|
||||
rotation |= DRM_MODE_REFLECT_X;
|
||||
sep = delim;
|
||||
} else if (!strncmp(option, "reflect_y", delim - option)) {
|
||||
rotation |= DRM_MODE_REFLECT_Y;
|
||||
sep = delim;
|
||||
} else if (!strncmp(option, "margin_right", delim - option)) {
|
||||
const char *value = delim + 1;
|
||||
unsigned int margin;
|
||||
|
||||
margin = simple_strtol(value, &sep, 10);
|
||||
|
||||
/* Make sure we have parsed something */
|
||||
if (sep == value)
|
||||
return -EINVAL;
|
||||
|
||||
mode->tv_margins.right = margin;
|
||||
} else if (!strncmp(option, "margin_left", delim - option)) {
|
||||
const char *value = delim + 1;
|
||||
unsigned int margin;
|
||||
|
||||
margin = simple_strtol(value, &sep, 10);
|
||||
|
||||
/* Make sure we have parsed something */
|
||||
if (sep == value)
|
||||
return -EINVAL;
|
||||
|
||||
mode->tv_margins.left = margin;
|
||||
} else if (!strncmp(option, "margin_top", delim - option)) {
|
||||
const char *value = delim + 1;
|
||||
unsigned int margin;
|
||||
|
||||
margin = simple_strtol(value, &sep, 10);
|
||||
|
||||
/* Make sure we have parsed something */
|
||||
if (sep == value)
|
||||
return -EINVAL;
|
||||
|
||||
mode->tv_margins.top = margin;
|
||||
} else if (!strncmp(option, "margin_bottom", delim - option)) {
|
||||
const char *value = delim + 1;
|
||||
unsigned int margin;
|
||||
|
||||
margin = simple_strtol(value, &sep, 10);
|
||||
|
||||
/* Make sure we have parsed something */
|
||||
if (sep == value)
|
||||
return -EINVAL;
|
||||
|
||||
mode->tv_margins.bottom = margin;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
mode->rotation_reflection = rotation;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector
|
||||
* @mode_option: optional per connector mode option
|
||||
@ -1423,6 +1678,10 @@ EXPORT_SYMBOL(drm_connector_list_update);
|
||||
*
|
||||
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
|
||||
*
|
||||
* Additionals options can be provided following the mode, using a comma to
|
||||
* separate each option. Valid options can be found in
|
||||
* Documentation/fb/modedb.txt.
|
||||
*
|
||||
* The intermediate drm_cmdline_mode structure is required to store additional
|
||||
* options from the command line modline like the force-enable/disable flag.
|
||||
*
|
||||
@ -1434,13 +1693,13 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
|
||||
struct drm_cmdline_mode *mode)
|
||||
{
|
||||
const char *name;
|
||||
unsigned int namelen;
|
||||
bool res_specified = false, bpp_specified = false, refresh_specified = false;
|
||||
unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
|
||||
bool yres_specified = false, cvt = false, rb = false;
|
||||
bool interlace = false, margins = false, was_digit = false;
|
||||
int i;
|
||||
enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
|
||||
bool named_mode = false, parse_extras = false;
|
||||
unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
|
||||
unsigned int mode_end = 0;
|
||||
char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
|
||||
char *options_ptr = NULL;
|
||||
char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
if (!mode_option)
|
||||
@ -1453,127 +1712,111 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
|
||||
}
|
||||
|
||||
name = mode_option;
|
||||
namelen = strlen(name);
|
||||
for (i = namelen-1; i >= 0; i--) {
|
||||
switch (name[i]) {
|
||||
case '@':
|
||||
if (!refresh_specified && !bpp_specified &&
|
||||
!yres_specified && !cvt && !rb && was_digit) {
|
||||
refresh = simple_strtol(&name[i+1], NULL, 10);
|
||||
refresh_specified = true;
|
||||
was_digit = false;
|
||||
} else
|
||||
goto done;
|
||||
break;
|
||||
case '-':
|
||||
if (!bpp_specified && !yres_specified && !cvt &&
|
||||
!rb && was_digit) {
|
||||
bpp = simple_strtol(&name[i+1], NULL, 10);
|
||||
bpp_specified = true;
|
||||
was_digit = false;
|
||||
} else
|
||||
goto done;
|
||||
break;
|
||||
case 'x':
|
||||
if (!yres_specified && was_digit) {
|
||||
yres = simple_strtol(&name[i+1], NULL, 10);
|
||||
yres_specified = true;
|
||||
was_digit = false;
|
||||
} else
|
||||
goto done;
|
||||
break;
|
||||
case '0' ... '9':
|
||||
was_digit = true;
|
||||
break;
|
||||
case 'M':
|
||||
if (yres_specified || cvt || was_digit)
|
||||
goto done;
|
||||
cvt = true;
|
||||
break;
|
||||
case 'R':
|
||||
if (yres_specified || cvt || rb || was_digit)
|
||||
goto done;
|
||||
rb = true;
|
||||
break;
|
||||
case 'm':
|
||||
if (cvt || yres_specified || was_digit)
|
||||
goto done;
|
||||
margins = true;
|
||||
break;
|
||||
case 'i':
|
||||
if (cvt || yres_specified || was_digit)
|
||||
goto done;
|
||||
interlace = true;
|
||||
break;
|
||||
case 'e':
|
||||
if (yres_specified || bpp_specified || refresh_specified ||
|
||||
was_digit || (force != DRM_FORCE_UNSPECIFIED))
|
||||
goto done;
|
||||
|
||||
force = DRM_FORCE_ON;
|
||||
break;
|
||||
case 'D':
|
||||
if (yres_specified || bpp_specified || refresh_specified ||
|
||||
was_digit || (force != DRM_FORCE_UNSPECIFIED))
|
||||
goto done;
|
||||
/*
|
||||
* This is a bit convoluted. To differentiate between the
|
||||
* named modes and poorly formatted resolutions, we need a
|
||||
* bunch of things:
|
||||
* - We need to make sure that the first character (which
|
||||
* would be our resolution in X) is a digit.
|
||||
* - However, if the X resolution is missing, then we end up
|
||||
* with something like x<yres>, with our first character
|
||||
* being an alpha-numerical character, which would be
|
||||
* considered a named mode.
|
||||
*
|
||||
* If this isn't enough, we should add more heuristics here,
|
||||
* and matching unit-tests.
|
||||
*/
|
||||
if (!isdigit(name[0]) && name[0] != 'x')
|
||||
named_mode = true;
|
||||
|
||||
if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
|
||||
(connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
|
||||
force = DRM_FORCE_ON;
|
||||
else
|
||||
force = DRM_FORCE_ON_DIGITAL;
|
||||
break;
|
||||
case 'd':
|
||||
if (yres_specified || bpp_specified || refresh_specified ||
|
||||
was_digit || (force != DRM_FORCE_UNSPECIFIED))
|
||||
goto done;
|
||||
|
||||
force = DRM_FORCE_OFF;
|
||||
break;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0 && yres_specified) {
|
||||
char *ch;
|
||||
xres = simple_strtol(name, &ch, 10);
|
||||
if ((ch != NULL) && (*ch == 'x'))
|
||||
res_specified = true;
|
||||
else
|
||||
i = ch - name;
|
||||
} else if (!yres_specified && was_digit) {
|
||||
/* catch mode that begins with digits but has no 'x' */
|
||||
i = 0;
|
||||
}
|
||||
done:
|
||||
if (i >= 0) {
|
||||
pr_warn("[drm] parse error at position %i in video mode '%s'\n",
|
||||
i, name);
|
||||
mode->specified = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res_specified) {
|
||||
mode->specified = true;
|
||||
mode->xres = xres;
|
||||
mode->yres = yres;
|
||||
}
|
||||
|
||||
if (refresh_specified) {
|
||||
mode->refresh_specified = true;
|
||||
mode->refresh = refresh;
|
||||
}
|
||||
|
||||
if (bpp_specified) {
|
||||
/* Try to locate the bpp and refresh specifiers, if any */
|
||||
bpp_ptr = strchr(name, '-');
|
||||
if (bpp_ptr) {
|
||||
bpp_off = bpp_ptr - name;
|
||||
mode->bpp_specified = true;
|
||||
mode->bpp = bpp;
|
||||
}
|
||||
mode->rb = rb;
|
||||
mode->cvt = cvt;
|
||||
mode->interlace = interlace;
|
||||
mode->margins = margins;
|
||||
mode->force = force;
|
||||
|
||||
refresh_ptr = strchr(name, '@');
|
||||
if (refresh_ptr) {
|
||||
if (named_mode)
|
||||
return false;
|
||||
|
||||
refresh_off = refresh_ptr - name;
|
||||
mode->refresh_specified = true;
|
||||
}
|
||||
|
||||
/* Locate the start of named options */
|
||||
options_ptr = strchr(name, ',');
|
||||
if (options_ptr)
|
||||
options_off = options_ptr - name;
|
||||
|
||||
/* Locate the end of the name / resolution, and parse it */
|
||||
if (bpp_ptr) {
|
||||
mode_end = bpp_off;
|
||||
} else if (refresh_ptr) {
|
||||
mode_end = refresh_off;
|
||||
} else if (options_ptr) {
|
||||
mode_end = options_off;
|
||||
} else {
|
||||
mode_end = strlen(name);
|
||||
parse_extras = true;
|
||||
}
|
||||
|
||||
if (named_mode) {
|
||||
strncpy(mode->name, name, mode_end);
|
||||
} else {
|
||||
ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
|
||||
parse_extras,
|
||||
connector,
|
||||
mode);
|
||||
if (ret)
|
||||
return false;
|
||||
}
|
||||
mode->specified = true;
|
||||
|
||||
if (bpp_ptr) {
|
||||
ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
|
||||
if (ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (refresh_ptr) {
|
||||
ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
|
||||
&refresh_end_ptr, mode);
|
||||
if (ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the end of the bpp / refresh, and parse the extras
|
||||
* if relevant
|
||||
*/
|
||||
if (bpp_ptr && refresh_ptr)
|
||||
extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
|
||||
else if (bpp_ptr)
|
||||
extra_ptr = bpp_end_ptr;
|
||||
else if (refresh_ptr)
|
||||
extra_ptr = refresh_end_ptr;
|
||||
|
||||
if (extra_ptr &&
|
||||
extra_ptr != options_ptr) {
|
||||
int len = strlen(name) - (extra_ptr - name);
|
||||
|
||||
ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
|
||||
connector, mode);
|
||||
if (ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options_ptr) {
|
||||
int len = strlen(name) - (options_ptr - name);
|
||||
|
||||
ret = drm_mode_parse_cmdline_options(options_ptr, len,
|
||||
connector, mode);
|
||||
if (ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -69,14 +69,14 @@ static void drm_self_refresh_helper_entry_work(struct work_struct *work)
|
||||
struct drm_connector *conn;
|
||||
struct drm_connector_state *conn_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int i, ret;
|
||||
int i, ret = 0;
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
state = drm_atomic_state_alloc(dev);
|
||||
if (!state) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto out_drop_locks;
|
||||
}
|
||||
|
||||
retry:
|
||||
@ -116,6 +116,8 @@ out:
|
||||
}
|
||||
|
||||
drm_atomic_state_put(state);
|
||||
|
||||
out_drop_locks:
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
}
|
||||
@ -205,7 +207,7 @@ void drm_self_refresh_helper_cleanup(struct drm_crtc *crtc)
|
||||
struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
|
||||
|
||||
/* Helper is already uninitialized */
|
||||
if (sr_data)
|
||||
if (!sr_data)
|
||||
return;
|
||||
|
||||
crtc->self_refresh_data = NULL;
|
||||
|
@ -241,12 +241,16 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
||||
* on the difference in the timestamps and the
|
||||
* frame/field duration.
|
||||
*/
|
||||
|
||||
DRM_DEBUG_VBL("crtc %u: Calculating number of vblanks."
|
||||
" diff_ns = %lld, framedur_ns = %d)\n",
|
||||
pipe, (long long) diff_ns, framedur_ns);
|
||||
|
||||
diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
|
||||
|
||||
if (diff == 0 && in_vblank_irq)
|
||||
DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored."
|
||||
" diff_ns = %lld, framedur_ns = %d)\n",
|
||||
pipe, (long long) diff_ns, framedur_ns);
|
||||
DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored\n",
|
||||
pipe);
|
||||
} else {
|
||||
/* some kind of default for drivers w/o accurate vbl timestamping */
|
||||
diff = in_vblank_irq ? 1 : 0;
|
||||
|
@ -74,7 +74,8 @@ static pgprot_t drm_io_prot(struct drm_local_map *map,
|
||||
/* We don't want graphics memory to be mapped encrypted */
|
||||
tmp = pgprot_decrypted(tmp);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
|
||||
defined(__mips__)
|
||||
if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING))
|
||||
tmp = pgprot_noncached(tmp);
|
||||
else
|
||||
@ -85,7 +86,7 @@ static pgprot_t drm_io_prot(struct drm_local_map *map,
|
||||
tmp = pgprot_writecombine(tmp);
|
||||
else
|
||||
tmp = pgprot_noncached(tmp);
|
||||
#elif defined(__sparc__) || defined(__arm__) || defined(__mips__)
|
||||
#elif defined(__sparc__) || defined(__arm__)
|
||||
tmp = pgprot_noncached(tmp);
|
||||
#endif
|
||||
return tmp;
|
||||
|
16
drivers/gpu/drm/ingenic/Kconfig
Normal file
16
drivers/gpu/drm/ingenic/Kconfig
Normal file
@ -0,0 +1,16 @@
|
||||
config DRM_INGENIC
|
||||
tristate "DRM Support for Ingenic SoCs"
|
||||
depends on MIPS || COMPILE_TEST
|
||||
depends on DRM
|
||||
depends on CMA
|
||||
depends on OF
|
||||
select DRM_BRIDGE
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Choose this option for DRM support for the Ingenic SoCs.
|
||||
|
||||
If M is selected the module will be called ingenic-drm.
|
1
drivers/gpu/drm/ingenic/Makefile
Normal file
1
drivers/gpu/drm/ingenic/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-$(CONFIG_DRM_INGENIC) += ingenic-drm.o
|
818
drivers/gpu/drm/ingenic/ingenic-drm.c
Normal file
818
drivers/gpu/drm/ingenic/ingenic-drm.c
Normal file
@ -0,0 +1,818 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Ingenic JZ47xx KMS driver
|
||||
//
|
||||
// Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_irq.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#define JZ_REG_LCD_CFG 0x00
|
||||
#define JZ_REG_LCD_VSYNC 0x04
|
||||
#define JZ_REG_LCD_HSYNC 0x08
|
||||
#define JZ_REG_LCD_VAT 0x0C
|
||||
#define JZ_REG_LCD_DAH 0x10
|
||||
#define JZ_REG_LCD_DAV 0x14
|
||||
#define JZ_REG_LCD_PS 0x18
|
||||
#define JZ_REG_LCD_CLS 0x1C
|
||||
#define JZ_REG_LCD_SPL 0x20
|
||||
#define JZ_REG_LCD_REV 0x24
|
||||
#define JZ_REG_LCD_CTRL 0x30
|
||||
#define JZ_REG_LCD_STATE 0x34
|
||||
#define JZ_REG_LCD_IID 0x38
|
||||
#define JZ_REG_LCD_DA0 0x40
|
||||
#define JZ_REG_LCD_SA0 0x44
|
||||
#define JZ_REG_LCD_FID0 0x48
|
||||
#define JZ_REG_LCD_CMD0 0x4C
|
||||
#define JZ_REG_LCD_DA1 0x50
|
||||
#define JZ_REG_LCD_SA1 0x54
|
||||
#define JZ_REG_LCD_FID1 0x58
|
||||
#define JZ_REG_LCD_CMD1 0x5C
|
||||
|
||||
#define JZ_LCD_CFG_SLCD BIT(31)
|
||||
#define JZ_LCD_CFG_PS_DISABLE BIT(23)
|
||||
#define JZ_LCD_CFG_CLS_DISABLE BIT(22)
|
||||
#define JZ_LCD_CFG_SPL_DISABLE BIT(21)
|
||||
#define JZ_LCD_CFG_REV_DISABLE BIT(20)
|
||||
#define JZ_LCD_CFG_HSYNCM BIT(19)
|
||||
#define JZ_LCD_CFG_PCLKM BIT(18)
|
||||
#define JZ_LCD_CFG_INV BIT(17)
|
||||
#define JZ_LCD_CFG_SYNC_DIR BIT(16)
|
||||
#define JZ_LCD_CFG_PS_POLARITY BIT(15)
|
||||
#define JZ_LCD_CFG_CLS_POLARITY BIT(14)
|
||||
#define JZ_LCD_CFG_SPL_POLARITY BIT(13)
|
||||
#define JZ_LCD_CFG_REV_POLARITY BIT(12)
|
||||
#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
|
||||
#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
|
||||
#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
|
||||
#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
|
||||
#define JZ_LCD_CFG_18_BIT BIT(7)
|
||||
#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
|
||||
|
||||
#define JZ_LCD_CFG_MODE_GENERIC_16BIT 0
|
||||
#define JZ_LCD_CFG_MODE_GENERIC_18BIT BIT(7)
|
||||
#define JZ_LCD_CFG_MODE_GENERIC_24BIT BIT(6)
|
||||
|
||||
#define JZ_LCD_CFG_MODE_SPECIAL_TFT_1 1
|
||||
#define JZ_LCD_CFG_MODE_SPECIAL_TFT_2 2
|
||||
#define JZ_LCD_CFG_MODE_SPECIAL_TFT_3 3
|
||||
|
||||
#define JZ_LCD_CFG_MODE_TV_OUT_P 4
|
||||
#define JZ_LCD_CFG_MODE_TV_OUT_I 6
|
||||
|
||||
#define JZ_LCD_CFG_MODE_SINGLE_COLOR_STN 8
|
||||
#define JZ_LCD_CFG_MODE_SINGLE_MONOCHROME_STN 9
|
||||
#define JZ_LCD_CFG_MODE_DUAL_COLOR_STN 10
|
||||
#define JZ_LCD_CFG_MODE_DUAL_MONOCHROME_STN 11
|
||||
|
||||
#define JZ_LCD_CFG_MODE_8BIT_SERIAL 12
|
||||
#define JZ_LCD_CFG_MODE_LCM 13
|
||||
|
||||
#define JZ_LCD_VSYNC_VPS_OFFSET 16
|
||||
#define JZ_LCD_VSYNC_VPE_OFFSET 0
|
||||
|
||||
#define JZ_LCD_HSYNC_HPS_OFFSET 16
|
||||
#define JZ_LCD_HSYNC_HPE_OFFSET 0
|
||||
|
||||
#define JZ_LCD_VAT_HT_OFFSET 16
|
||||
#define JZ_LCD_VAT_VT_OFFSET 0
|
||||
|
||||
#define JZ_LCD_DAH_HDS_OFFSET 16
|
||||
#define JZ_LCD_DAH_HDE_OFFSET 0
|
||||
|
||||
#define JZ_LCD_DAV_VDS_OFFSET 16
|
||||
#define JZ_LCD_DAV_VDE_OFFSET 0
|
||||
|
||||
#define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
|
||||
#define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
|
||||
#define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
|
||||
#define JZ_LCD_CTRL_RGB555 BIT(27)
|
||||
#define JZ_LCD_CTRL_OFUP BIT(26)
|
||||
#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
|
||||
#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
|
||||
#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
|
||||
#define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
|
||||
#define JZ_LCD_CTRL_EOF_IRQ BIT(13)
|
||||
#define JZ_LCD_CTRL_SOF_IRQ BIT(12)
|
||||
#define JZ_LCD_CTRL_OFU_IRQ BIT(11)
|
||||
#define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
|
||||
#define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
|
||||
#define JZ_LCD_CTRL_DD_IRQ BIT(8)
|
||||
#define JZ_LCD_CTRL_QDD_IRQ BIT(7)
|
||||
#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
|
||||
#define JZ_LCD_CTRL_LSB_FISRT BIT(5)
|
||||
#define JZ_LCD_CTRL_DISABLE BIT(4)
|
||||
#define JZ_LCD_CTRL_ENABLE BIT(3)
|
||||
#define JZ_LCD_CTRL_BPP_1 0x0
|
||||
#define JZ_LCD_CTRL_BPP_2 0x1
|
||||
#define JZ_LCD_CTRL_BPP_4 0x2
|
||||
#define JZ_LCD_CTRL_BPP_8 0x3
|
||||
#define JZ_LCD_CTRL_BPP_15_16 0x4
|
||||
#define JZ_LCD_CTRL_BPP_18_24 0x5
|
||||
#define JZ_LCD_CTRL_BPP_MASK (JZ_LCD_CTRL_RGB555 | (0x7 << 0))
|
||||
|
||||
#define JZ_LCD_CMD_SOF_IRQ BIT(31)
|
||||
#define JZ_LCD_CMD_EOF_IRQ BIT(30)
|
||||
#define JZ_LCD_CMD_ENABLE_PAL BIT(28)
|
||||
|
||||
#define JZ_LCD_SYNC_MASK 0x3ff
|
||||
|
||||
#define JZ_LCD_STATE_EOF_IRQ BIT(5)
|
||||
#define JZ_LCD_STATE_SOF_IRQ BIT(4)
|
||||
#define JZ_LCD_STATE_DISABLED BIT(0)
|
||||
|
||||
struct ingenic_dma_hwdesc {
|
||||
u32 next;
|
||||
u32 addr;
|
||||
u32 id;
|
||||
u32 cmd;
|
||||
} __packed;
|
||||
|
||||
struct jz_soc_info {
|
||||
bool needs_dev_clk;
|
||||
};
|
||||
|
||||
struct ingenic_drm {
|
||||
struct drm_device drm;
|
||||
struct drm_plane primary;
|
||||
struct drm_crtc crtc;
|
||||
struct drm_encoder encoder;
|
||||
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
struct clk *lcd_clk, *pix_clk;
|
||||
|
||||
struct ingenic_dma_hwdesc *dma_hwdesc;
|
||||
dma_addr_t dma_hwdesc_phys;
|
||||
};
|
||||
|
||||
static const u32 ingenic_drm_primary_formats[] = {
|
||||
DRM_FORMAT_XRGB1555,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static bool ingenic_drm_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case JZ_REG_LCD_IID:
|
||||
case JZ_REG_LCD_SA0:
|
||||
case JZ_REG_LCD_FID0:
|
||||
case JZ_REG_LCD_CMD0:
|
||||
case JZ_REG_LCD_SA1:
|
||||
case JZ_REG_LCD_FID1:
|
||||
case JZ_REG_LCD_CMD1:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config ingenic_drm_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
|
||||
.max_register = JZ_REG_LCD_CMD1,
|
||||
.writeable_reg = ingenic_drm_writeable_reg,
|
||||
};
|
||||
|
||||
static inline struct ingenic_drm *drm_device_get_priv(struct drm_device *drm)
|
||||
{
|
||||
return container_of(drm, struct ingenic_drm, drm);
|
||||
}
|
||||
|
||||
static inline struct ingenic_drm *drm_crtc_get_priv(struct drm_crtc *crtc)
|
||||
{
|
||||
return container_of(crtc, struct ingenic_drm, crtc);
|
||||
}
|
||||
|
||||
static inline struct ingenic_drm *
|
||||
drm_encoder_get_priv(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct ingenic_drm, encoder);
|
||||
}
|
||||
|
||||
static inline struct ingenic_drm *drm_plane_get_priv(struct drm_plane *plane)
|
||||
{
|
||||
return container_of(plane, struct ingenic_drm, primary);
|
||||
}
|
||||
|
||||
static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_STATE, 0);
|
||||
|
||||
regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
|
||||
JZ_LCD_CTRL_ENABLE | JZ_LCD_CTRL_DISABLE,
|
||||
JZ_LCD_CTRL_ENABLE);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void ingenic_drm_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
|
||||
unsigned int var;
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
|
||||
JZ_LCD_CTRL_DISABLE, JZ_LCD_CTRL_DISABLE);
|
||||
|
||||
regmap_read_poll_timeout(priv->map, JZ_REG_LCD_STATE, var,
|
||||
var & JZ_LCD_STATE_DISABLED,
|
||||
1000, 0);
|
||||
}
|
||||
|
||||
static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
unsigned int vpe, vds, vde, vt, hpe, hds, hde, ht;
|
||||
|
||||
vpe = mode->vsync_end - mode->vsync_start;
|
||||
vds = mode->vtotal - mode->vsync_start;
|
||||
vde = vds + mode->vdisplay;
|
||||
vt = vde + mode->vsync_start - mode->vdisplay;
|
||||
|
||||
hpe = mode->hsync_end - mode->hsync_start;
|
||||
hds = mode->htotal - mode->hsync_start;
|
||||
hde = hds + mode->hdisplay;
|
||||
ht = hde + mode->hsync_start - mode->hdisplay;
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_VSYNC,
|
||||
0 << JZ_LCD_VSYNC_VPS_OFFSET |
|
||||
vpe << JZ_LCD_VSYNC_VPE_OFFSET);
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_HSYNC,
|
||||
0 << JZ_LCD_HSYNC_HPS_OFFSET |
|
||||
hpe << JZ_LCD_HSYNC_HPE_OFFSET);
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_VAT,
|
||||
ht << JZ_LCD_VAT_HT_OFFSET |
|
||||
vt << JZ_LCD_VAT_VT_OFFSET);
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_DAH,
|
||||
hds << JZ_LCD_DAH_HDS_OFFSET |
|
||||
hde << JZ_LCD_DAH_HDE_OFFSET);
|
||||
regmap_write(priv->map, JZ_REG_LCD_DAV,
|
||||
vds << JZ_LCD_DAV_VDS_OFFSET |
|
||||
vde << JZ_LCD_DAV_VDE_OFFSET);
|
||||
}
|
||||
|
||||
static void ingenic_drm_crtc_update_ctrl(struct ingenic_drm *priv,
|
||||
const struct drm_format_info *finfo)
|
||||
{
|
||||
unsigned int ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16;
|
||||
|
||||
switch (finfo->format) {
|
||||
case DRM_FORMAT_XRGB1555:
|
||||
ctrl |= JZ_LCD_CTRL_RGB555;
|
||||
/* fall-through */
|
||||
case DRM_FORMAT_RGB565:
|
||||
ctrl |= JZ_LCD_CTRL_BPP_15_16;
|
||||
break;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
ctrl |= JZ_LCD_CTRL_BPP_18_24;
|
||||
break;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
|
||||
JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16 |
|
||||
JZ_LCD_CTRL_BPP_MASK, ctrl);
|
||||
}
|
||||
|
||||
static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
|
||||
long rate;
|
||||
|
||||
if (!drm_atomic_crtc_needs_modeset(state))
|
||||
return 0;
|
||||
|
||||
rate = clk_round_rate(priv->pix_clk,
|
||||
state->adjusted_mode.clock * 1000);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *oldstate)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
|
||||
struct drm_crtc_state *state = crtc->state;
|
||||
struct drm_pending_vblank_event *event = state->event;
|
||||
struct drm_framebuffer *drm_fb = crtc->primary->state->fb;
|
||||
const struct drm_format_info *finfo;
|
||||
|
||||
if (drm_atomic_crtc_needs_modeset(state)) {
|
||||
finfo = drm_format_info(drm_fb->format->format);
|
||||
|
||||
ingenic_drm_crtc_update_timings(priv, &state->mode);
|
||||
ingenic_drm_crtc_update_ctrl(priv, finfo);
|
||||
|
||||
clk_set_rate(priv->pix_clk, state->adjusted_mode.clock * 1000);
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_DA0, priv->dma_hwdesc->next);
|
||||
}
|
||||
|
||||
if (event) {
|
||||
state->event = NULL;
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
if (drm_crtc_vblank_get(crtc) == 0)
|
||||
drm_crtc_arm_vblank_event(crtc, event);
|
||||
else
|
||||
drm_crtc_send_vblank_event(crtc, event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void ingenic_drm_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *oldstate)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_plane_get_priv(plane);
|
||||
struct drm_plane_state *state = plane->state;
|
||||
unsigned int width, height, cpp;
|
||||
|
||||
width = state->crtc->state->adjusted_mode.hdisplay;
|
||||
height = state->crtc->state->adjusted_mode.vdisplay;
|
||||
cpp = state->fb->format->cpp[plane->index];
|
||||
|
||||
priv->dma_hwdesc->addr = drm_fb_cma_get_gem_addr(state->fb, state, 0);
|
||||
priv->dma_hwdesc->cmd = width * height * cpp / 4;
|
||||
priv->dma_hwdesc->cmd |= JZ_LCD_CMD_EOF_IRQ;
|
||||
}
|
||||
|
||||
static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_encoder_get_priv(encoder);
|
||||
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
|
||||
struct drm_display_info *info = &conn_state->connector->display_info;
|
||||
unsigned int cfg = JZ_LCD_CFG_PS_DISABLE
|
||||
| JZ_LCD_CFG_CLS_DISABLE
|
||||
| JZ_LCD_CFG_SPL_DISABLE
|
||||
| JZ_LCD_CFG_REV_DISABLE;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW;
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW;
|
||||
if (info->bus_flags & DRM_BUS_FLAG_DE_LOW)
|
||||
cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW;
|
||||
if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
|
||||
cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE;
|
||||
|
||||
if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_TV) {
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
cfg |= JZ_LCD_CFG_MODE_TV_OUT_I;
|
||||
else
|
||||
cfg |= JZ_LCD_CFG_MODE_TV_OUT_P;
|
||||
} else {
|
||||
switch (*info->bus_formats) {
|
||||
case MEDIA_BUS_FMT_RGB565_1X16:
|
||||
cfg |= JZ_LCD_CFG_MODE_GENERIC_16BIT;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB666_1X18:
|
||||
cfg |= JZ_LCD_CFG_MODE_GENERIC_18BIT;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
cfg |= JZ_LCD_CFG_MODE_GENERIC_24BIT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
regmap_write(priv->map, JZ_REG_LCD_CFG, cfg);
|
||||
}
|
||||
|
||||
static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_display_info *info = &conn_state->connector->display_info;
|
||||
|
||||
if (info->num_bus_formats != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_TV)
|
||||
return 0;
|
||||
|
||||
switch (*info->bus_formats) {
|
||||
case MEDIA_BUS_FMT_RGB565_1X16:
|
||||
case MEDIA_BUS_FMT_RGB666_1X18:
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ingenic_drm_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct ingenic_drm *priv = arg;
|
||||
unsigned int state;
|
||||
|
||||
regmap_read(priv->map, JZ_REG_LCD_STATE, &state);
|
||||
|
||||
regmap_update_bits(priv->map, JZ_REG_LCD_STATE,
|
||||
JZ_LCD_STATE_EOF_IRQ, 0);
|
||||
|
||||
if (state & JZ_LCD_STATE_EOF_IRQ)
|
||||
drm_crtc_handle_vblank(&priv->crtc);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void ingenic_drm_release(struct drm_device *drm)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_device_get_priv(drm);
|
||||
|
||||
drm_mode_config_cleanup(drm);
|
||||
drm_dev_fini(drm);
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
static int ingenic_drm_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
|
||||
|
||||
regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
|
||||
JZ_LCD_CTRL_EOF_IRQ, JZ_LCD_CTRL_EOF_IRQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ingenic_drm_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
|
||||
|
||||
regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, JZ_LCD_CTRL_EOF_IRQ, 0);
|
||||
}
|
||||
|
||||
DEFINE_DRM_GEM_CMA_FOPS(ingenic_drm_fops);
|
||||
|
||||
static struct drm_driver ingenic_drm_driver_data = {
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
|
||||
| DRIVER_ATOMIC,
|
||||
.name = "ingenic-drm",
|
||||
.desc = "DRM module for Ingenic SoCs",
|
||||
.date = "20190422",
|
||||
.major = 1,
|
||||
.minor = 0,
|
||||
.patchlevel = 0,
|
||||
|
||||
.fops = &ingenic_drm_fops,
|
||||
|
||||
.dumb_create = drm_gem_cma_dumb_create,
|
||||
.gem_free_object_unlocked = drm_gem_cma_free_object,
|
||||
.gem_vm_ops = &drm_gem_cma_vm_ops,
|
||||
|
||||
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
|
||||
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
|
||||
.gem_prime_vmap = drm_gem_cma_prime_vmap,
|
||||
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
|
||||
.gem_prime_mmap = drm_gem_cma_prime_mmap,
|
||||
|
||||
.irq_handler = ingenic_drm_irq_handler,
|
||||
.release = ingenic_drm_release,
|
||||
};
|
||||
|
||||
static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.destroy = drm_plane_cleanup,
|
||||
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = {
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.destroy = drm_crtc_cleanup,
|
||||
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
|
||||
.enable_vblank = ingenic_drm_enable_vblank,
|
||||
.disable_vblank = ingenic_drm_disable_vblank,
|
||||
|
||||
.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
||||
};
|
||||
|
||||
static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = {
|
||||
.atomic_update = ingenic_drm_plane_atomic_update,
|
||||
.prepare_fb = drm_gem_fb_prepare_fb,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs = {
|
||||
.atomic_enable = ingenic_drm_crtc_atomic_enable,
|
||||
.atomic_disable = ingenic_drm_crtc_atomic_disable,
|
||||
.atomic_flush = ingenic_drm_crtc_atomic_flush,
|
||||
.atomic_check = ingenic_drm_crtc_atomic_check,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = {
|
||||
.atomic_mode_set = ingenic_drm_encoder_atomic_mode_set,
|
||||
.atomic_check = ingenic_drm_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const struct drm_mode_config_funcs ingenic_drm_mode_config_funcs = {
|
||||
.fb_create = drm_gem_fb_create,
|
||||
.output_poll_changed = drm_fb_helper_output_poll_changed,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs ingenic_drm_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static void ingenic_drm_free_dma_hwdesc(void *d)
|
||||
{
|
||||
struct ingenic_drm *priv = d;
|
||||
|
||||
dma_free_coherent(priv->dev, sizeof(*priv->dma_hwdesc),
|
||||
priv->dma_hwdesc, priv->dma_hwdesc_phys);
|
||||
}
|
||||
|
||||
static int ingenic_drm_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct jz_soc_info *soc_info;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ingenic_drm *priv;
|
||||
struct clk *parent_clk;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
struct drm_device *drm;
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
long parent_rate;
|
||||
int ret, irq;
|
||||
|
||||
soc_info = of_device_get_match_data(dev);
|
||||
if (!soc_info) {
|
||||
dev_err(dev, "Missing platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
drm = &priv->drm;
|
||||
drm->dev_private = priv;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = devm_drm_dev_init(dev, drm, &ingenic_drm_driver_data);
|
||||
if (ret) {
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_mode_config_init(drm);
|
||||
drm->mode_config.min_width = 0;
|
||||
drm->mode_config.min_height = 0;
|
||||
drm->mode_config.max_width = 800;
|
||||
drm->mode_config.max_height = 600;
|
||||
drm->mode_config.funcs = &ingenic_drm_mode_config_funcs;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(base)) {
|
||||
dev_err(dev, "Failed to get memory resource");
|
||||
return PTR_ERR(base);
|
||||
}
|
||||
|
||||
priv->map = devm_regmap_init_mmio(dev, base,
|
||||
&ingenic_drm_regmap_config);
|
||||
if (IS_ERR(priv->map)) {
|
||||
dev_err(dev, "Failed to create regmap");
|
||||
return PTR_ERR(priv->map);
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Failed to get platform irq");
|
||||
return irq;
|
||||
}
|
||||
|
||||
if (soc_info->needs_dev_clk) {
|
||||
priv->lcd_clk = devm_clk_get(dev, "lcd");
|
||||
if (IS_ERR(priv->lcd_clk)) {
|
||||
dev_err(dev, "Failed to get lcd clock");
|
||||
return PTR_ERR(priv->lcd_clk);
|
||||
}
|
||||
}
|
||||
|
||||
priv->pix_clk = devm_clk_get(dev, "lcd_pclk");
|
||||
if (IS_ERR(priv->pix_clk)) {
|
||||
dev_err(dev, "Failed to get pixel clock");
|
||||
return PTR_ERR(priv->pix_clk);
|
||||
}
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get panel handle");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (panel) {
|
||||
bridge = devm_drm_panel_bridge_add(dev, panel,
|
||||
DRM_MODE_CONNECTOR_Unknown);
|
||||
}
|
||||
|
||||
priv->dma_hwdesc = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc),
|
||||
&priv->dma_hwdesc_phys,
|
||||
GFP_KERNEL);
|
||||
if (!priv->dma_hwdesc)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, ingenic_drm_free_dma_hwdesc, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->dma_hwdesc->next = priv->dma_hwdesc_phys;
|
||||
priv->dma_hwdesc->id = 0xdeafbead;
|
||||
|
||||
drm_plane_helper_add(&priv->primary, &ingenic_drm_plane_helper_funcs);
|
||||
|
||||
ret = drm_universal_plane_init(drm, &priv->primary,
|
||||
0, &ingenic_drm_primary_plane_funcs,
|
||||
ingenic_drm_primary_formats,
|
||||
ARRAY_SIZE(ingenic_drm_primary_formats),
|
||||
NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register primary plane: %i", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_crtc_helper_add(&priv->crtc, &ingenic_drm_crtc_helper_funcs);
|
||||
|
||||
ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->primary,
|
||||
NULL, &ingenic_drm_crtc_funcs, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init CRTC: %i", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->encoder.possible_crtcs = 1;
|
||||
|
||||
drm_encoder_helper_add(&priv->encoder,
|
||||
&ingenic_drm_encoder_helper_funcs);
|
||||
|
||||
ret = drm_encoder_init(drm, &priv->encoder, &ingenic_drm_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DPI, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init encoder: %i", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_bridge_attach(&priv->encoder, bridge, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to attach bridge");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_irq_install(drm, irq);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to install IRQ handler");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_vblank_init(drm, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed calling drm_vblank_init()");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
ret = clk_prepare_enable(priv->pix_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to start pixel clock");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->lcd_clk) {
|
||||
parent_clk = clk_get_parent(priv->lcd_clk);
|
||||
parent_rate = clk_get_rate(parent_clk);
|
||||
|
||||
/* LCD Device clock must be 3x the pixel clock for STN panels,
|
||||
* or 1.5x the pixel clock for TFT panels. To avoid having to
|
||||
* check for the LCD device clock everytime we do a mode change,
|
||||
* we set the LCD device clock to the highest rate possible.
|
||||
*/
|
||||
ret = clk_set_rate(priv->lcd_clk, parent_rate);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to set LCD clock rate");
|
||||
goto err_pixclk_disable;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->lcd_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to start lcd clock");
|
||||
goto err_pixclk_disable;
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_dev_register(drm, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register DRM driver");
|
||||
goto err_devclk_disable;
|
||||
}
|
||||
|
||||
ret = drm_fbdev_generic_setup(drm, 32);
|
||||
if (ret)
|
||||
dev_warn(dev, "Unable to start fbdev emulation: %i", ret);
|
||||
|
||||
return 0;
|
||||
|
||||
err_devclk_disable:
|
||||
if (priv->lcd_clk)
|
||||
clk_disable_unprepare(priv->lcd_clk);
|
||||
err_pixclk_disable:
|
||||
clk_disable_unprepare(priv->pix_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ingenic_drm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ingenic_drm *priv = platform_get_drvdata(pdev);
|
||||
|
||||
if (priv->lcd_clk)
|
||||
clk_disable_unprepare(priv->lcd_clk);
|
||||
clk_disable_unprepare(priv->pix_clk);
|
||||
|
||||
drm_dev_unregister(&priv->drm);
|
||||
drm_atomic_helper_shutdown(&priv->drm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct jz_soc_info jz4740_soc_info = {
|
||||
.needs_dev_clk = true,
|
||||
};
|
||||
|
||||
static const struct jz_soc_info jz4725b_soc_info = {
|
||||
.needs_dev_clk = false,
|
||||
};
|
||||
|
||||
static const struct of_device_id ingenic_drm_of_match[] = {
|
||||
{ .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info },
|
||||
{ .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver ingenic_drm_driver = {
|
||||
.driver = {
|
||||
.name = "ingenic-drm",
|
||||
.of_match_table = of_match_ptr(ingenic_drm_of_match),
|
||||
},
|
||||
.probe = ingenic_drm_probe,
|
||||
.remove = ingenic_drm_remove,
|
||||
};
|
||||
module_platform_driver(ingenic_drm_driver);
|
||||
|
||||
MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
|
||||
MODULE_DESCRIPTION("DRM driver for the Ingenic SoCs\n");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -7,6 +7,7 @@ panfrost-y := \
|
||||
panfrost_gem.o \
|
||||
panfrost_gpu.o \
|
||||
panfrost_job.o \
|
||||
panfrost_mmu.o
|
||||
panfrost_mmu.o \
|
||||
panfrost_perfcnt.o
|
||||
|
||||
obj-$(CONFIG_DRM_PANFROST) += panfrost.o
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "panfrost_gpu.h"
|
||||
#include "panfrost_job.h"
|
||||
#include "panfrost_mmu.h"
|
||||
#include "panfrost_perfcnt.h"
|
||||
|
||||
static int panfrost_reset_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
@ -171,7 +172,13 @@ int panfrost_device_init(struct panfrost_device *pfdev)
|
||||
pm_runtime_mark_last_busy(pfdev->dev);
|
||||
pm_runtime_put_autosuspend(pfdev->dev);
|
||||
|
||||
err = panfrost_perfcnt_init(pfdev);
|
||||
if (err)
|
||||
goto err_out5;
|
||||
|
||||
return 0;
|
||||
err_out5:
|
||||
panfrost_job_fini(pfdev);
|
||||
err_out4:
|
||||
panfrost_mmu_fini(pfdev);
|
||||
err_out3:
|
||||
@ -187,6 +194,7 @@ err_out0:
|
||||
|
||||
void panfrost_device_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
panfrost_perfcnt_fini(pfdev);
|
||||
panfrost_job_fini(pfdev);
|
||||
panfrost_mmu_fini(pfdev);
|
||||
panfrost_gpu_fini(pfdev);
|
||||
|
@ -14,6 +14,7 @@ struct panfrost_device;
|
||||
struct panfrost_mmu;
|
||||
struct panfrost_job_slot;
|
||||
struct panfrost_job;
|
||||
struct panfrost_perfcnt;
|
||||
|
||||
#define NUM_JOB_SLOTS 3
|
||||
|
||||
@ -78,6 +79,8 @@ struct panfrost_device {
|
||||
struct panfrost_job *jobs[NUM_JOB_SLOTS];
|
||||
struct list_head scheduled_jobs;
|
||||
|
||||
struct panfrost_perfcnt *perfcnt;
|
||||
|
||||
struct mutex sched_lock;
|
||||
struct mutex reset_lock;
|
||||
|
||||
@ -110,11 +113,18 @@ static inline int panfrost_model_cmp(struct panfrost_device *pfdev, s32 id)
|
||||
return match_id - id;
|
||||
}
|
||||
|
||||
static inline bool panfrost_model_is_bifrost(struct panfrost_device *pfdev)
|
||||
{
|
||||
return panfrost_model_cmp(pfdev, 0x1000) >= 0;
|
||||
}
|
||||
|
||||
static inline bool panfrost_model_eq(struct panfrost_device *pfdev, s32 id)
|
||||
{
|
||||
return !panfrost_model_cmp(pfdev, id);
|
||||
}
|
||||
|
||||
int panfrost_unstable_ioctl_check(void);
|
||||
|
||||
int panfrost_device_init(struct panfrost_device *pfdev);
|
||||
void panfrost_device_fini(struct panfrost_device *pfdev);
|
||||
|
||||
|
@ -19,6 +19,10 @@
|
||||
#include "panfrost_mmu.h"
|
||||
#include "panfrost_job.h"
|
||||
#include "panfrost_gpu.h"
|
||||
#include "panfrost_perfcnt.h"
|
||||
|
||||
static bool unstable_ioctls;
|
||||
module_param_unsafe(unstable_ioctls, bool, 0600);
|
||||
|
||||
static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file)
|
||||
{
|
||||
@ -297,6 +301,14 @@ static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int panfrost_unstable_ioctl_check(void)
|
||||
{
|
||||
if (!unstable_ioctls)
|
||||
return -ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
panfrost_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
@ -318,6 +330,7 @@ panfrost_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct panfrost_file_priv *panfrost_priv = file->driver_priv;
|
||||
|
||||
panfrost_perfcnt_close(panfrost_priv);
|
||||
panfrost_job_close(panfrost_priv);
|
||||
|
||||
kfree(panfrost_priv);
|
||||
@ -337,6 +350,8 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = {
|
||||
PANFROST_IOCTL(MMAP_BO, mmap_bo, DRM_RENDER_ALLOW),
|
||||
PANFROST_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW),
|
||||
PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW),
|
||||
PANFROST_IOCTL(PERFCNT_ENABLE, perfcnt_enable, DRM_RENDER_ALLOW),
|
||||
PANFROST_IOCTL(PERFCNT_DUMP, perfcnt_dump, DRM_RENDER_ALLOW),
|
||||
};
|
||||
|
||||
DEFINE_DRM_GEM_SHMEM_FOPS(panfrost_drm_driver_fops);
|
||||
|
@ -52,6 +52,7 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t
|
||||
int ret;
|
||||
struct panfrost_device *pfdev = dev->dev_private;
|
||||
struct panfrost_gem_object *obj;
|
||||
u64 align;
|
||||
|
||||
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
||||
if (!obj)
|
||||
@ -59,9 +60,12 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t
|
||||
|
||||
obj->base.base.funcs = &panfrost_gem_funcs;
|
||||
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
align = size >= SZ_2M ? SZ_2M >> PAGE_SHIFT : 0;
|
||||
|
||||
spin_lock(&pfdev->mm_lock);
|
||||
ret = drm_mm_insert_node(&pfdev->mm, &obj->node,
|
||||
roundup(size, PAGE_SIZE) >> PAGE_SHIFT);
|
||||
ret = drm_mm_insert_node_generic(&pfdev->mm, &obj->node,
|
||||
size >> PAGE_SHIFT, align, 0, 0);
|
||||
spin_unlock(&pfdev->mm_lock);
|
||||
if (ret)
|
||||
goto free_obj;
|
||||
|
@ -15,11 +15,9 @@
|
||||
#include "panfrost_features.h"
|
||||
#include "panfrost_issues.h"
|
||||
#include "panfrost_gpu.h"
|
||||
#include "panfrost_perfcnt.h"
|
||||
#include "panfrost_regs.h"
|
||||
|
||||
#define gpu_write(dev, reg, data) writel(data, dev->iomem + reg)
|
||||
#define gpu_read(dev, reg) readl(dev->iomem + reg)
|
||||
|
||||
static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct panfrost_device *pfdev = data;
|
||||
@ -43,6 +41,12 @@ static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
|
||||
gpu_write(pfdev, GPU_INT_MASK, 0);
|
||||
}
|
||||
|
||||
if (state & GPU_IRQ_PERFCNT_SAMPLE_COMPLETED)
|
||||
panfrost_perfcnt_sample_done(pfdev);
|
||||
|
||||
if (state & GPU_IRQ_CLEAN_CACHES_COMPLETED)
|
||||
panfrost_perfcnt_clean_cache_done(pfdev);
|
||||
|
||||
gpu_write(pfdev, GPU_INT_CLEAR, state);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
329
drivers/gpu/drm/panfrost/panfrost_perfcnt.c
Normal file
329
drivers/gpu/drm/panfrost/panfrost_perfcnt.c
Normal file
@ -0,0 +1,329 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright 2019 Collabora Ltd */
|
||||
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/panfrost_drm.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "panfrost_device.h"
|
||||
#include "panfrost_features.h"
|
||||
#include "panfrost_gem.h"
|
||||
#include "panfrost_issues.h"
|
||||
#include "panfrost_job.h"
|
||||
#include "panfrost_mmu.h"
|
||||
#include "panfrost_regs.h"
|
||||
|
||||
#define COUNTERS_PER_BLOCK 64
|
||||
#define BYTES_PER_COUNTER 4
|
||||
#define BLOCKS_PER_COREGROUP 8
|
||||
#define V4_SHADERS_PER_COREGROUP 4
|
||||
|
||||
struct panfrost_perfcnt {
|
||||
struct panfrost_gem_object *bo;
|
||||
size_t bosize;
|
||||
void *buf;
|
||||
struct panfrost_file_priv *user;
|
||||
struct mutex lock;
|
||||
struct completion dump_comp;
|
||||
};
|
||||
|
||||
void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
|
||||
{
|
||||
complete(&pfdev->perfcnt->dump_comp);
|
||||
}
|
||||
|
||||
void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
|
||||
{
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
|
||||
{
|
||||
u64 gpuva;
|
||||
int ret;
|
||||
|
||||
reinit_completion(&pfdev->perfcnt->dump_comp);
|
||||
gpuva = pfdev->perfcnt->bo->node.start << PAGE_SHIFT;
|
||||
gpu_write(pfdev, GPU_PERFCNT_BASE_LO, gpuva);
|
||||
gpu_write(pfdev, GPU_PERFCNT_BASE_HI, gpuva >> 32);
|
||||
gpu_write(pfdev, GPU_INT_CLEAR,
|
||||
GPU_IRQ_CLEAN_CACHES_COMPLETED |
|
||||
GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
|
||||
ret = wait_for_completion_interruptible_timeout(&pfdev->perfcnt->dump_comp,
|
||||
msecs_to_jiffies(1000));
|
||||
if (!ret)
|
||||
ret = -ETIMEDOUT;
|
||||
else if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
|
||||
struct panfrost_file_priv *user,
|
||||
unsigned int counterset)
|
||||
{
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
struct drm_gem_shmem_object *bo;
|
||||
u32 cfg;
|
||||
int ret;
|
||||
|
||||
if (user == perfcnt->user)
|
||||
return 0;
|
||||
else if (perfcnt->user)
|
||||
return -EBUSY;
|
||||
|
||||
ret = pm_runtime_get_sync(pfdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize);
|
||||
if (IS_ERR(bo))
|
||||
return PTR_ERR(bo);
|
||||
|
||||
perfcnt->bo = to_panfrost_bo(&bo->base);
|
||||
|
||||
/* Map the perfcnt buf in the address space attached to file_priv. */
|
||||
ret = panfrost_mmu_map(perfcnt->bo);
|
||||
if (ret)
|
||||
goto err_put_bo;
|
||||
|
||||
perfcnt->buf = drm_gem_shmem_vmap(&bo->base);
|
||||
if (IS_ERR(perfcnt->buf)) {
|
||||
ret = PTR_ERR(perfcnt->buf);
|
||||
goto err_put_bo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate the cache and clear the counters to start from a fresh
|
||||
* state.
|
||||
*/
|
||||
reinit_completion(&pfdev->perfcnt->dump_comp);
|
||||
gpu_write(pfdev, GPU_INT_CLEAR,
|
||||
GPU_IRQ_CLEAN_CACHES_COMPLETED |
|
||||
GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_INV_CACHES);
|
||||
ret = wait_for_completion_timeout(&pfdev->perfcnt->dump_comp,
|
||||
msecs_to_jiffies(1000));
|
||||
if (!ret) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_vunmap;
|
||||
}
|
||||
|
||||
perfcnt->user = user;
|
||||
|
||||
/*
|
||||
* Always use address space 0 for now.
|
||||
* FIXME: this needs to be updated when we start using different
|
||||
* address space.
|
||||
*/
|
||||
cfg = GPU_PERFCNT_CFG_AS(0) |
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
|
||||
|
||||
/*
|
||||
* Bifrost GPUs have 2 set of counters, but we're only interested by
|
||||
* the first one for now.
|
||||
*/
|
||||
if (panfrost_model_is_bifrost(pfdev))
|
||||
cfg |= GPU_PERFCNT_CFG_SETSEL(counterset);
|
||||
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
|
||||
|
||||
/*
|
||||
* Due to PRLAM-8186 we need to disable the Tiler before we enable HW
|
||||
* counters.
|
||||
*/
|
||||
if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
else
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
|
||||
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
|
||||
|
||||
if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
|
||||
|
||||
return 0;
|
||||
|
||||
err_vunmap:
|
||||
drm_gem_shmem_vunmap(&perfcnt->bo->base.base, perfcnt->buf);
|
||||
err_put_bo:
|
||||
drm_gem_object_put_unlocked(&bo->base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
|
||||
struct panfrost_file_priv *user)
|
||||
{
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
|
||||
if (user != perfcnt->user)
|
||||
return -EINVAL;
|
||||
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
|
||||
perfcnt->user = NULL;
|
||||
drm_gem_shmem_vunmap(&perfcnt->bo->base.base, perfcnt->buf);
|
||||
perfcnt->buf = NULL;
|
||||
drm_gem_object_put_unlocked(&perfcnt->bo->base.base);
|
||||
perfcnt->bo = NULL;
|
||||
pm_runtime_mark_last_busy(pfdev->dev);
|
||||
pm_runtime_put_autosuspend(pfdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct panfrost_file_priv *pfile = file_priv->driver_priv;
|
||||
struct panfrost_device *pfdev = dev->dev_private;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
struct drm_panfrost_perfcnt_enable *req = data;
|
||||
int ret;
|
||||
|
||||
ret = panfrost_unstable_ioctl_check();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Only Bifrost GPUs have 2 set of counters. */
|
||||
if (req->counterset > (panfrost_model_is_bifrost(pfdev) ? 1 : 0))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&perfcnt->lock);
|
||||
if (req->enable)
|
||||
ret = panfrost_perfcnt_enable_locked(pfdev, pfile,
|
||||
req->counterset);
|
||||
else
|
||||
ret = panfrost_perfcnt_disable_locked(pfdev, pfile);
|
||||
mutex_unlock(&perfcnt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct panfrost_device *pfdev = dev->dev_private;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
struct drm_panfrost_perfcnt_dump *req = data;
|
||||
void __user *user_ptr = (void __user *)(uintptr_t)req->buf_ptr;
|
||||
int ret;
|
||||
|
||||
ret = panfrost_unstable_ioctl_check();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&perfcnt->lock);
|
||||
if (perfcnt->user != file_priv->driver_priv) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = panfrost_perfcnt_dump_locked(pfdev);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (copy_to_user(user_ptr, perfcnt->buf, perfcnt->bosize))
|
||||
ret = -EFAULT;
|
||||
|
||||
out:
|
||||
mutex_unlock(&perfcnt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void panfrost_perfcnt_close(struct panfrost_file_priv *pfile)
|
||||
{
|
||||
struct panfrost_device *pfdev = pfile->pfdev;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
|
||||
pm_runtime_get_sync(pfdev->dev);
|
||||
mutex_lock(&perfcnt->lock);
|
||||
if (perfcnt->user == pfile)
|
||||
panfrost_perfcnt_disable_locked(pfdev, pfile);
|
||||
mutex_unlock(&perfcnt->lock);
|
||||
pm_runtime_mark_last_busy(pfdev->dev);
|
||||
pm_runtime_put_autosuspend(pfdev->dev);
|
||||
}
|
||||
|
||||
int panfrost_perfcnt_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
struct panfrost_perfcnt *perfcnt;
|
||||
size_t size;
|
||||
|
||||
if (panfrost_has_hw_feature(pfdev, HW_FEATURE_V4)) {
|
||||
unsigned int ncoregroups;
|
||||
|
||||
ncoregroups = hweight64(pfdev->features.l2_present);
|
||||
size = ncoregroups * BLOCKS_PER_COREGROUP *
|
||||
COUNTERS_PER_BLOCK * BYTES_PER_COUNTER;
|
||||
} else {
|
||||
unsigned int nl2c, ncores;
|
||||
|
||||
/*
|
||||
* TODO: define a macro to extract the number of l2 caches from
|
||||
* mem_features.
|
||||
*/
|
||||
nl2c = ((pfdev->features.mem_features >> 8) & GENMASK(3, 0)) + 1;
|
||||
|
||||
/*
|
||||
* shader_present might be sparse, but the counters layout
|
||||
* forces to dump unused regions too, hence the fls64() call
|
||||
* instead of hweight64().
|
||||
*/
|
||||
ncores = fls64(pfdev->features.shader_present);
|
||||
|
||||
/*
|
||||
* There's always one JM and one Tiler block, hence the '+ 2'
|
||||
* here.
|
||||
*/
|
||||
size = (nl2c + ncores + 2) *
|
||||
COUNTERS_PER_BLOCK * BYTES_PER_COUNTER;
|
||||
}
|
||||
|
||||
perfcnt = devm_kzalloc(pfdev->dev, sizeof(*perfcnt), GFP_KERNEL);
|
||||
if (!perfcnt)
|
||||
return -ENOMEM;
|
||||
|
||||
perfcnt->bosize = size;
|
||||
|
||||
/* Start with everything disabled. */
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
|
||||
init_completion(&perfcnt->dump_comp);
|
||||
mutex_init(&perfcnt->lock);
|
||||
pfdev->perfcnt = perfcnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void panfrost_perfcnt_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
/* Disable everything before leaving. */
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
}
|
18
drivers/gpu/drm/panfrost/panfrost_perfcnt.h
Normal file
18
drivers/gpu/drm/panfrost/panfrost_perfcnt.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright 2019 Collabora Ltd */
|
||||
#ifndef __PANFROST_PERFCNT_H__
|
||||
#define __PANFROST_PERFCNT_H__
|
||||
|
||||
#include "panfrost_device.h"
|
||||
|
||||
void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev);
|
||||
void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev);
|
||||
int panfrost_perfcnt_init(struct panfrost_device *pfdev);
|
||||
void panfrost_perfcnt_fini(struct panfrost_device *pfdev);
|
||||
void panfrost_perfcnt_close(struct panfrost_file_priv *pfile);
|
||||
int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
#endif
|
@ -44,12 +44,31 @@
|
||||
GPU_IRQ_MULTIPLE_FAULT)
|
||||
#define GPU_CMD 0x30
|
||||
#define GPU_CMD_SOFT_RESET 0x01
|
||||
#define GPU_CMD_PERFCNT_CLEAR 0x03
|
||||
#define GPU_CMD_PERFCNT_SAMPLE 0x04
|
||||
#define GPU_CMD_CLEAN_CACHES 0x07
|
||||
#define GPU_CMD_CLEAN_INV_CACHES 0x08
|
||||
#define GPU_STATUS 0x34
|
||||
#define GPU_STATUS_PRFCNT_ACTIVE BIT(2)
|
||||
#define GPU_LATEST_FLUSH_ID 0x38
|
||||
#define GPU_FAULT_STATUS 0x3C
|
||||
#define GPU_FAULT_ADDRESS_LO 0x40
|
||||
#define GPU_FAULT_ADDRESS_HI 0x44
|
||||
|
||||
#define GPU_PERFCNT_BASE_LO 0x60
|
||||
#define GPU_PERFCNT_BASE_HI 0x64
|
||||
#define GPU_PERFCNT_CFG 0x68
|
||||
#define GPU_PERFCNT_CFG_MODE(x) (x)
|
||||
#define GPU_PERFCNT_CFG_MODE_OFF 0
|
||||
#define GPU_PERFCNT_CFG_MODE_MANUAL 1
|
||||
#define GPU_PERFCNT_CFG_MODE_TILE 2
|
||||
#define GPU_PERFCNT_CFG_AS(x) ((x) << 4)
|
||||
#define GPU_PERFCNT_CFG_SETSEL(x) ((x) << 8)
|
||||
#define GPU_PRFCNT_JM_EN 0x6c
|
||||
#define GPU_PRFCNT_SHADER_EN 0x70
|
||||
#define GPU_PRFCNT_TILER_EN 0x74
|
||||
#define GPU_PRFCNT_MMU_L2_EN 0x7c
|
||||
|
||||
#define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */
|
||||
#define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */
|
||||
#define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */
|
||||
@ -295,4 +314,7 @@
|
||||
#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8)
|
||||
#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8)
|
||||
|
||||
#define gpu_write(dev, reg, data) writel(data, dev->iomem + reg)
|
||||
#define gpu_read(dev, reg) readl(dev->iomem + reg)
|
||||
|
||||
#endif
|
||||
|
@ -115,8 +115,8 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
|
||||
|
||||
/* We're not allowed to modify the resolution. */
|
||||
crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
|
||||
if (!crtc_state)
|
||||
return -EINVAL;
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
|
||||
if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
|
||||
crtc_state->mode.vdisplay != panel_mode->vdisplay)
|
||||
|
@ -535,7 +535,7 @@ static int cdn_dp_get_training_status(struct cdn_dp_device *dp)
|
||||
if (ret)
|
||||
goto err_get_training_status;
|
||||
|
||||
dp->link.rate = status[0];
|
||||
dp->link.rate = drm_dp_bw_code_to_link_rate(status[0]);
|
||||
dp->link.num_lanes = status[1];
|
||||
|
||||
err_get_training_status:
|
||||
@ -639,7 +639,7 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
|
||||
bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
|
||||
(video->color_depth * 2) : (video->color_depth * 3);
|
||||
|
||||
link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000;
|
||||
link_rate = dp->link.rate / 1000;
|
||||
|
||||
ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
|
||||
if (ret)
|
||||
|
@ -19,6 +19,14 @@
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_vop.h"
|
||||
|
||||
#define RK3228_GRF_SOC_CON2 0x0408
|
||||
#define RK3228_HDMI_SDAIN_MSK BIT(14)
|
||||
#define RK3228_HDMI_SCLIN_MSK BIT(13)
|
||||
#define RK3228_GRF_SOC_CON6 0x0418
|
||||
#define RK3228_HDMI_HPD_VSEL BIT(6)
|
||||
#define RK3228_HDMI_SDA_VSEL BIT(5)
|
||||
#define RK3228_HDMI_SCL_VSEL BIT(4)
|
||||
|
||||
#define RK3288_GRF_SOC_CON6 0x025C
|
||||
#define RK3288_HDMI_LCDC_SEL BIT(4)
|
||||
#define RK3328_GRF_SOC_CON2 0x0408
|
||||
@ -321,6 +329,25 @@ static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
|
||||
phy_power_off(hdmi->phy);
|
||||
}
|
||||
|
||||
static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
|
||||
{
|
||||
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
|
||||
|
||||
dw_hdmi_phy_setup_hpd(dw_hdmi, data);
|
||||
|
||||
regmap_write(hdmi->regmap,
|
||||
RK3228_GRF_SOC_CON6,
|
||||
HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
|
||||
RK3228_HDMI_SCL_VSEL,
|
||||
RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
|
||||
RK3228_HDMI_SCL_VSEL));
|
||||
|
||||
regmap_write(hdmi->regmap,
|
||||
RK3228_GRF_SOC_CON2,
|
||||
HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK,
|
||||
RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK));
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
|
||||
{
|
||||
@ -366,6 +393,29 @@ static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
|
||||
RK3328_HDMI_HPD_IOE));
|
||||
}
|
||||
|
||||
static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {
|
||||
.init = dw_hdmi_rockchip_genphy_init,
|
||||
.disable = dw_hdmi_rockchip_genphy_disable,
|
||||
.read_hpd = dw_hdmi_phy_read_hpd,
|
||||
.update_hpd = dw_hdmi_phy_update_hpd,
|
||||
.setup_hpd = dw_hdmi_rk3228_setup_hpd,
|
||||
};
|
||||
|
||||
static struct rockchip_hdmi_chip_data rk3228_chip_data = {
|
||||
.lcdsel_grf_reg = -1,
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
|
||||
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
||||
.mpll_cfg = rockchip_mpll_cfg,
|
||||
.cur_ctr = rockchip_cur_ctr,
|
||||
.phy_config = rockchip_phy_config,
|
||||
.phy_data = &rk3228_chip_data,
|
||||
.phy_ops = &rk3228_hdmi_phy_ops,
|
||||
.phy_name = "inno_dw_hdmi_phy2",
|
||||
.phy_force_vendor = true,
|
||||
};
|
||||
|
||||
static struct rockchip_hdmi_chip_data rk3288_chip_data = {
|
||||
.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
|
||||
.lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
|
||||
@ -418,6 +468,9 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
|
||||
};
|
||||
|
||||
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
|
||||
{ .compatible = "rockchip,rk3228-dw-hdmi",
|
||||
.data = &rk3228_hdmi_drv_data
|
||||
},
|
||||
{ .compatible = "rockchip,rk3288-dw-hdmi",
|
||||
.data = &rk3288_hdmi_drv_data
|
||||
},
|
||||
|
@ -1006,7 +1006,8 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
struct vop *vop = to_vop(crtc);
|
||||
|
||||
adjusted_mode->clock =
|
||||
clk_round_rate(vop->dclk, mode->clock * 1000) / 1000;
|
||||
DIV_ROUND_UP(clk_round_rate(vop->dclk,
|
||||
adjusted_mode->clock * 1000), 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3,4 +3,4 @@ test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
|
||||
test-drm_format.o test-drm_framebuffer.o \
|
||||
test-drm_damage_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
|
||||
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o test-drm_cmdline_parser.o
|
||||
|
55
drivers/gpu/drm/selftests/drm_cmdline_selftests.h
Normal file
55
drivers/gpu/drm/selftests/drm_cmdline_selftests.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* List each unit test as selftest(function)
|
||||
*
|
||||
* The name is used as both an enum and expanded as igt__name to create
|
||||
* a module parameter. It must be unique and legal for a C identifier.
|
||||
*
|
||||
* Tests are executed in order by igt/drm_mm
|
||||
*/
|
||||
|
||||
#define cmdline_test(test) selftest(test, test)
|
||||
|
||||
cmdline_test(drm_cmdline_test_res)
|
||||
cmdline_test(drm_cmdline_test_res_missing_x)
|
||||
cmdline_test(drm_cmdline_test_res_missing_y)
|
||||
cmdline_test(drm_cmdline_test_res_bad_y)
|
||||
cmdline_test(drm_cmdline_test_res_missing_y_bpp)
|
||||
cmdline_test(drm_cmdline_test_res_vesa)
|
||||
cmdline_test(drm_cmdline_test_res_vesa_rblank)
|
||||
cmdline_test(drm_cmdline_test_res_rblank)
|
||||
cmdline_test(drm_cmdline_test_res_bpp)
|
||||
cmdline_test(drm_cmdline_test_res_bad_bpp)
|
||||
cmdline_test(drm_cmdline_test_res_refresh)
|
||||
cmdline_test(drm_cmdline_test_res_bad_refresh)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_margins)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_force_off)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_off)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_analog)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_digital)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on)
|
||||
cmdline_test(drm_cmdline_test_res_margins_force_on)
|
||||
cmdline_test(drm_cmdline_test_res_vesa_margins)
|
||||
cmdline_test(drm_cmdline_test_res_invalid_mode)
|
||||
cmdline_test(drm_cmdline_test_res_bpp_wrong_place_mode)
|
||||
cmdline_test(drm_cmdline_test_name)
|
||||
cmdline_test(drm_cmdline_test_name_bpp)
|
||||
cmdline_test(drm_cmdline_test_name_refresh)
|
||||
cmdline_test(drm_cmdline_test_name_bpp_refresh)
|
||||
cmdline_test(drm_cmdline_test_name_refresh_wrong_mode)
|
||||
cmdline_test(drm_cmdline_test_name_refresh_invalid_mode)
|
||||
cmdline_test(drm_cmdline_test_name_option)
|
||||
cmdline_test(drm_cmdline_test_name_bpp_option)
|
||||
cmdline_test(drm_cmdline_test_rotate_0)
|
||||
cmdline_test(drm_cmdline_test_rotate_90)
|
||||
cmdline_test(drm_cmdline_test_rotate_180)
|
||||
cmdline_test(drm_cmdline_test_rotate_270)
|
||||
cmdline_test(drm_cmdline_test_rotate_invalid_val)
|
||||
cmdline_test(drm_cmdline_test_rotate_truncated)
|
||||
cmdline_test(drm_cmdline_test_hmirror)
|
||||
cmdline_test(drm_cmdline_test_vmirror)
|
||||
cmdline_test(drm_cmdline_test_margin_options)
|
||||
cmdline_test(drm_cmdline_test_multiple_options)
|
||||
cmdline_test(drm_cmdline_test_invalid_option)
|
918
drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
Normal file
918
drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
Normal file
@ -0,0 +1,918 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2019 Bootlin
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "drm_cmdline: " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_modes.h>
|
||||
|
||||
#define TESTS "drm_cmdline_selftests.h"
|
||||
#include "drm_selftest.h"
|
||||
#include "test-drm_modeset_common.h"
|
||||
|
||||
static int drm_cmdline_test_res(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_missing_x(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("x480",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_missing_y(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("1024x",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bad_y(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_vesa(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(!mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_vesa_rblank(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(!mode.rb);
|
||||
FAIL_ON(!mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_rblank(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(!mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bad_bpp(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_refresh(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bad_refresh(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(!mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(!mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
connector.connector_type = DRM_MODE_CONNECTOR_DVII;
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(!mode.refresh_specified);
|
||||
FAIL_ON(mode.refresh != 60);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(!mode.interlace);
|
||||
FAIL_ON(!mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_margins_force_on(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(!mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_vesa_margins(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(!mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(!mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_invalid_mode(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(strcmp(mode.name, "NTSC"));
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_bpp(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(strcmp(mode.name, "NTSC"));
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_bpp_refresh(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_refresh(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_option(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(strcmp(mode.name, "NTSC"));
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_name_bpp_option(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(strcmp(mode.name, "NTSC"));
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
|
||||
FAIL_ON(!mode.bpp_specified);
|
||||
FAIL_ON(mode.bpp != 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_rotate_0(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_0);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_rotate_90(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_90);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_rotate_180(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_rotate_270(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_270);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_rotate_invalid_val(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_rotate_truncated(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_hmirror(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_REFLECT_X);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_vmirror(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != DRM_MODE_REFLECT_Y);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_margin_options(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.tv_margins.right != 14);
|
||||
FAIL_ON(mode.tv_margins.left != 24);
|
||||
FAIL_ON(mode.tv_margins.bottom != 36);
|
||||
FAIL_ON(mode.tv_margins.top != 42);
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_multiple_options(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x",
|
||||
&connector,
|
||||
&mode));
|
||||
FAIL_ON(!mode.specified);
|
||||
FAIL_ON(mode.xres != 720);
|
||||
FAIL_ON(mode.yres != 480);
|
||||
FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X));
|
||||
|
||||
FAIL_ON(mode.refresh_specified);
|
||||
|
||||
FAIL_ON(mode.bpp_specified);
|
||||
|
||||
FAIL_ON(mode.rb);
|
||||
FAIL_ON(mode.cvt);
|
||||
FAIL_ON(mode.interlace);
|
||||
FAIL_ON(mode.margins);
|
||||
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_cmdline_test_invalid_option(void *ignored)
|
||||
{
|
||||
struct drm_connector connector = { };
|
||||
struct drm_cmdline_mode mode = { };
|
||||
|
||||
FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42",
|
||||
&connector,
|
||||
&mode));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "drm_selftest.c"
|
||||
|
||||
static int __init test_drm_cmdline_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
|
||||
|
||||
return err > 0 ? 0 : err;
|
||||
}
|
||||
module_init(test_drm_cmdline_init);
|
||||
|
||||
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -136,8 +136,7 @@ static __maybe_unused int drv_suspend(struct device *dev)
|
||||
struct ltdc_device *ldev = ddev->dev_private;
|
||||
struct drm_atomic_state *state;
|
||||
|
||||
if (WARN_ON(!ldev->suspend_state))
|
||||
return -ENOENT;
|
||||
WARN_ON(ldev->suspend_state);
|
||||
|
||||
state = drm_atomic_helper_suspend(ddev);
|
||||
if (IS_ERR(state))
|
||||
@ -155,15 +154,17 @@ static __maybe_unused int drv_resume(struct device *dev)
|
||||
struct ltdc_device *ldev = ddev->dev_private;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!ldev->suspend_state))
|
||||
return -ENOENT;
|
||||
|
||||
pm_runtime_force_resume(dev);
|
||||
ret = drm_atomic_helper_resume(ddev, ldev->suspend_state);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
pm_runtime_force_suspend(dev);
|
||||
ldev->suspend_state = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ldev->suspend_state = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __maybe_unused int drv_runtime_suspend(struct device *dev)
|
||||
|
@ -539,13 +539,13 @@ pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp)
|
||||
tmp = pgprot_noncached(tmp);
|
||||
#endif
|
||||
#if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \
|
||||
defined(__powerpc__)
|
||||
defined(__powerpc__) || defined(__mips__)
|
||||
if (caching_flags & TTM_PL_FLAG_WC)
|
||||
tmp = pgprot_writecombine(tmp);
|
||||
else
|
||||
tmp = pgprot_noncached(tmp);
|
||||
#endif
|
||||
#if defined(__sparc__) || defined(__mips__)
|
||||
#if defined(__sparc__)
|
||||
tmp = pgprot_noncached(tmp);
|
||||
#endif
|
||||
return tmp;
|
||||
|
@ -29,13 +29,9 @@ vc4_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(minor->dev);
|
||||
struct vc4_debugfs_info_entry *entry;
|
||||
struct dentry *dentry;
|
||||
|
||||
dentry = debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
|
||||
minor->debugfs_root,
|
||||
&vc4->load_tracker_enabled);
|
||||
if (!dentry)
|
||||
return -ENOMEM;
|
||||
debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
|
||||
minor->debugfs_root, &vc4->load_tracker_enabled);
|
||||
|
||||
list_for_each_entry(entry, &vc4->debugfs_list, link) {
|
||||
int ret = drm_debugfs_create_files(&entry->info, 1,
|
||||
|
@ -255,11 +255,17 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vc4_hdmi_connector_reset(struct drm_connector *connector)
|
||||
{
|
||||
drm_atomic_helper_connector_reset(connector);
|
||||
drm_atomic_helper_connector_tv_reset(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
|
||||
.detect = vc4_hdmi_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = vc4_hdmi_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.reset = vc4_hdmi_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
@ -212,6 +212,15 @@ out:
|
||||
spin_unlock_irqrestore(&out->state_lock, flags);
|
||||
}
|
||||
|
||||
static const char * const pipe_crc_sources[] = {"auto"};
|
||||
|
||||
const char *const *vkms_get_crc_sources(struct drm_crtc *crtc,
|
||||
size_t *count)
|
||||
{
|
||||
*count = ARRAY_SIZE(pipe_crc_sources);
|
||||
return pipe_crc_sources;
|
||||
}
|
||||
|
||||
static int vkms_crc_parse_source(const char *src_name, bool *enabled)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -147,6 +147,7 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = {
|
||||
.atomic_destroy_state = vkms_atomic_crtc_destroy_state,
|
||||
.enable_vblank = vkms_enable_vblank,
|
||||
.disable_vblank = vkms_disable_vblank,
|
||||
.get_crc_sources = vkms_get_crc_sources,
|
||||
.set_crc_source = vkms_set_crc_source,
|
||||
.verify_crc_source = vkms_verify_crc_source,
|
||||
};
|
||||
|
@ -20,14 +20,6 @@
|
||||
|
||||
extern bool enable_cursor;
|
||||
|
||||
static const u32 vkms_formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static const u32 vkms_cursor_formats[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
};
|
||||
|
||||
struct vkms_crc_data {
|
||||
struct drm_framebuffer fb;
|
||||
struct drm_rect src, dst;
|
||||
@ -136,6 +128,8 @@ int vkms_gem_vmap(struct drm_gem_object *obj);
|
||||
void vkms_gem_vunmap(struct drm_gem_object *obj);
|
||||
|
||||
/* CRC Support */
|
||||
const char *const *vkms_get_crc_sources(struct drm_crtc *crtc,
|
||||
size_t *count);
|
||||
int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name);
|
||||
int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
|
||||
size_t *values_cnt);
|
||||
|
@ -6,6 +6,14 @@
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
||||
static const u32 vkms_formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static const u32 vkms_cursor_formats[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
};
|
||||
|
||||
static struct drm_plane_state *
|
||||
vkms_plane_duplicate_state(struct drm_plane *plane)
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fbcon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_domain.h>
|
||||
@ -734,14 +735,8 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
|
||||
if (!active->driver_power_control)
|
||||
set_audio_state(active->id, VGA_SWITCHEROO_OFF);
|
||||
|
||||
if (new_client->fb_info) {
|
||||
struct fb_event event;
|
||||
|
||||
console_lock();
|
||||
event.info = new_client->fb_info;
|
||||
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
|
||||
console_unlock();
|
||||
}
|
||||
if (new_client->fb_info)
|
||||
fbcon_remap_all(new_client->fb_info);
|
||||
|
||||
mutex_lock(&vgasr_priv.mux_hw_lock);
|
||||
ret = vgasr_priv.handler->switchto(new_client->id);
|
||||
|
@ -1246,11 +1246,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
|
||||
struct osd_info *oi = itv->osd_info;
|
||||
|
||||
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
|
||||
if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
|
||||
IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
|
||||
itv->instance);
|
||||
return 0;
|
||||
}
|
||||
unregister_framebuffer(&itv->osd_info->ivtvfb_info);
|
||||
IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
|
||||
itv->ivtvfb_restore = NULL;
|
||||
ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
|
||||
|
@ -891,7 +891,9 @@ int fbtft_unregister_framebuffer(struct fb_info *fb_info)
|
||||
if (par->fbtftops.unregister_backlight)
|
||||
par->fbtftops.unregister_backlight(par);
|
||||
fbtft_sysfs_exit(par);
|
||||
return unregister_framebuffer(fb_info);
|
||||
unregister_framebuffer(fb_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fbtft_unregister_framebuffer);
|
||||
|
||||
|
@ -1,4 +1,11 @@
|
||||
TODO:
|
||||
- complete rewrite:
|
||||
1. The underlying fbdev drivers need to be converted into drm kernel
|
||||
modesetting drivers.
|
||||
2. The dcon low-power display mode can then be integrated using the
|
||||
drm damage tracking and self-refresh helpers.
|
||||
This bolted-on self-refresh support that digs around in fbdev
|
||||
internals, but isn't properly integrated, is not the correct solution.
|
||||
- see if vx855 gpio API can be made similar enough to cs5535 so we can
|
||||
share more code
|
||||
- convert all uses of the old GPIO API from <linux/gpio.h> to the
|
||||
|
@ -250,11 +250,7 @@ static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank)
|
||||
int err;
|
||||
|
||||
console_lock();
|
||||
if (!lock_fb_info(dcon->fbinfo)) {
|
||||
console_unlock();
|
||||
dev_err(&dcon->client->dev, "unable to lock framebuffer\n");
|
||||
return false;
|
||||
}
|
||||
lock_fb_info(dcon->fbinfo);
|
||||
|
||||
dcon->ignore_fb_events = true;
|
||||
err = fb_blank(dcon->fbinfo,
|
||||
|
@ -3822,6 +3822,8 @@ int con_is_bound(const struct consw *csw)
|
||||
{
|
||||
int i, bound = 0;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (con_driver_map[i] == csw) {
|
||||
bound = 1;
|
||||
@ -3833,6 +3835,20 @@ int con_is_bound(const struct consw *csw)
|
||||
}
|
||||
EXPORT_SYMBOL(con_is_bound);
|
||||
|
||||
/**
|
||||
* con_is_visible - checks whether the current console is visible
|
||||
* @vc: virtual console
|
||||
*
|
||||
* RETURNS: zero if not visible, nonzero if visible
|
||||
*/
|
||||
bool con_is_visible(const struct vc_data *vc)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
return *vc->vc_display_fg == vc;
|
||||
}
|
||||
EXPORT_SYMBOL(con_is_visible);
|
||||
|
||||
/**
|
||||
* con_debug_enter - prepare the console for the kernel debugger
|
||||
* @sw: console driver
|
||||
@ -4166,6 +4182,8 @@ void do_blank_screen(int entering_gfx)
|
||||
struct vc_data *vc = vc_cons[fg_console].d;
|
||||
int i;
|
||||
|
||||
might_sleep();
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (console_blanked) {
|
||||
|
@ -47,7 +47,7 @@ static int fb_notifier_callback(struct notifier_block *self,
|
||||
int fb_blank = 0;
|
||||
|
||||
/* If we aren't interested in this event, skip it immediately ... */
|
||||
if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
|
||||
if (event != FB_EVENT_BLANK)
|
||||
return 0;
|
||||
|
||||
bd = container_of(self, struct backlight_device, fb_notif);
|
||||
|
@ -30,18 +30,6 @@ static int fb_notifier_callback(struct notifier_block *self,
|
||||
struct lcd_device *ld;
|
||||
struct fb_event *evdata = data;
|
||||
|
||||
/* If we aren't interested in this event, skip it immediately ... */
|
||||
switch (event) {
|
||||
case FB_EVENT_BLANK:
|
||||
case FB_EVENT_MODE_CHANGE:
|
||||
case FB_EVENT_MODE_CHANGE_ALL:
|
||||
case FB_EARLY_EVENT_BLANK:
|
||||
case FB_R_EARLY_EVENT_BLANK:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
ld = container_of(self, struct lcd_device, fb_notif);
|
||||
if (!ld->ops)
|
||||
return 0;
|
||||
|
@ -34,6 +34,8 @@ static bool dummycon_putc_called;
|
||||
|
||||
void dummycon_register_output_notifier(struct notifier_block *nb)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
raw_notifier_chain_register(&dummycon_output_nh, nb);
|
||||
|
||||
if (dummycon_putc_called)
|
||||
@ -42,11 +44,15 @@ void dummycon_register_output_notifier(struct notifier_block *nb)
|
||||
|
||||
void dummycon_unregister_output_notifier(struct notifier_block *nb)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
raw_notifier_chain_unregister(&dummycon_output_nh, nb);
|
||||
}
|
||||
|
||||
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
|
||||
{
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
dummycon_putc_called = true;
|
||||
raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
|
||||
}
|
||||
|
@ -2350,70 +2350,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Accelerated functions
|
||||
*/
|
||||
|
||||
static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
|
||||
u_int width, u_int height,
|
||||
struct fb_info_aty128 *par)
|
||||
{
|
||||
u32 save_dp_datatype, save_dp_cntl, dstval;
|
||||
|
||||
if (!width || !height)
|
||||
return;
|
||||
|
||||
dstval = depth_to_dst(par->current_par.crtc.depth);
|
||||
if (dstval == DST_24BPP) {
|
||||
srcx *= 3;
|
||||
dstx *= 3;
|
||||
width *= 3;
|
||||
} else if (dstval == -EINVAL) {
|
||||
printk("aty128fb: invalid depth or RGBA\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wait_for_fifo(2, par);
|
||||
save_dp_datatype = aty_ld_le32(DP_DATATYPE);
|
||||
save_dp_cntl = aty_ld_le32(DP_CNTL);
|
||||
|
||||
wait_for_fifo(6, par);
|
||||
aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
|
||||
aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
|
||||
aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
|
||||
aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR);
|
||||
|
||||
aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
|
||||
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
|
||||
|
||||
par->blitter_may_be_busy = 1;
|
||||
|
||||
wait_for_fifo(2, par);
|
||||
aty_st_le32(DP_DATATYPE, save_dp_datatype);
|
||||
aty_st_le32(DP_CNTL, save_dp_cntl);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Text mode accelerated functions
|
||||
*/
|
||||
|
||||
static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy,
|
||||
int dx, int height, int width)
|
||||
{
|
||||
sx *= fontwidth(p);
|
||||
sy *= fontheight(p);
|
||||
dx *= fontwidth(p);
|
||||
dy *= fontheight(p);
|
||||
width *= fontwidth(p);
|
||||
height *= fontheight(p);
|
||||
|
||||
aty128_rectcopy(sx, sy, dx, dy, width, height,
|
||||
(struct fb_info_aty128 *)p->fb_info);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
|
||||
{
|
||||
u32 pmgt;
|
||||
|
@ -3916,8 +3916,7 @@ static int atyfb_reboot_notify(struct notifier_block *nb,
|
||||
if (!reboot_info)
|
||||
goto out;
|
||||
|
||||
if (!lock_fb_info(reboot_info))
|
||||
goto out;
|
||||
lock_fb_info(reboot_info);
|
||||
|
||||
par = reboot_info->par;
|
||||
|
||||
|
@ -285,11 +285,7 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
|
||||
goto out;
|
||||
}
|
||||
umap.start = cmap->start;
|
||||
if (!lock_fb_info(info)) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_fb_info(info);
|
||||
rc = fb_set_cmap(&umap, info);
|
||||
unlock_fb_info(info);
|
||||
out:
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/crc32.h> /* For counting font checksums */
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/fb.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
@ -87,13 +88,32 @@
|
||||
# define DPRINTK(fmt, args...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIXME: Locking
|
||||
*
|
||||
* - fbcon state itself is protected by the console_lock, and the code does a
|
||||
* pretty good job at making sure that lock is held everywhere it's needed.
|
||||
*
|
||||
* - access to the registered_fb array is entirely unprotected. This should use
|
||||
* proper object lifetime handling, i.e. get/put_fb_info. This also means
|
||||
* switching from indices to proper pointers for fb_info everywhere.
|
||||
*
|
||||
* - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it
|
||||
* means concurrent access to the same fbdev from both fbcon and userspace
|
||||
* will blow up. To fix this all fbcon calls from fbmem.c need to be moved out
|
||||
* of fb_lock/unlock protected sections, since otherwise we'll recurse and
|
||||
* deadlock eventually. Aside: Due to these deadlock issues the fbdev code in
|
||||
* fbmem.c cannot use locking asserts, and there's lots of callers which get
|
||||
* the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too.
|
||||
*/
|
||||
|
||||
enum {
|
||||
FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */
|
||||
FBCON_LOGO_DRAW = -2, /* draw the logo to a console */
|
||||
FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */
|
||||
};
|
||||
|
||||
static struct display fb_display[MAX_NR_CONSOLES];
|
||||
static struct fbcon_display fb_display[MAX_NR_CONSOLES];
|
||||
|
||||
static signed char con2fb_map[MAX_NR_CONSOLES];
|
||||
static signed char con2fb_map_boot[MAX_NR_CONSOLES];
|
||||
@ -112,7 +132,6 @@ static int softback_lines;
|
||||
static int first_fb_vc;
|
||||
static int last_fb_vc = MAX_NR_CONSOLES - 1;
|
||||
static int fbcon_is_default = 1;
|
||||
static int fbcon_has_exited;
|
||||
static int primary_device = -1;
|
||||
static int fbcon_has_console_bind;
|
||||
|
||||
@ -185,11 +204,11 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count);
|
||||
static __inline__ void ywrap_down(struct vc_data *vc, int count);
|
||||
static __inline__ void ypan_up(struct vc_data *vc, int count);
|
||||
static __inline__ void ypan_down(struct vc_data *vc, int count);
|
||||
static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
|
||||
static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
|
||||
int dy, int dx, int height, int width, u_int y_break);
|
||||
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
int unit);
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy);
|
||||
static void fbcon_modechanged(struct fb_info *info);
|
||||
static void fbcon_set_all_vcs(struct fb_info *info);
|
||||
@ -220,7 +239,7 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate)
|
||||
fb_info = registered_fb[con2fb_map[ops->currcon]];
|
||||
|
||||
if (info == fb_info) {
|
||||
struct display *p = &fb_display[ops->currcon];
|
||||
struct fbcon_display *p = &fb_display[ops->currcon];
|
||||
|
||||
if (rotate < 4)
|
||||
p->con_rotate = rotate;
|
||||
@ -235,7 +254,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct vc_data *vc;
|
||||
struct display *p;
|
||||
struct fbcon_display *p;
|
||||
int i;
|
||||
|
||||
if (!ops || ops->currcon < 0 || rotate > 3)
|
||||
@ -900,7 +919,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
|
||||
* Low Level Operations
|
||||
*/
|
||||
/* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */
|
||||
static int var_to_display(struct display *disp,
|
||||
static int var_to_display(struct fbcon_display *disp,
|
||||
struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
@ -925,7 +944,7 @@ static int var_to_display(struct display *disp,
|
||||
}
|
||||
|
||||
static void display_to_var(struct fb_var_screeninfo *var,
|
||||
struct display *disp)
|
||||
struct fbcon_display *disp)
|
||||
{
|
||||
fb_videomode_to_var(var, disp->mode);
|
||||
var->xres_virtual = disp->xres_virtual;
|
||||
@ -946,7 +965,7 @@ static void display_to_var(struct fb_var_screeninfo *var,
|
||||
static const char *fbcon_startup(void)
|
||||
{
|
||||
const char *display_desc = "frame buffer device";
|
||||
struct display *p = &fb_display[fg_console];
|
||||
struct fbcon_display *p = &fb_display[fg_console];
|
||||
struct vc_data *vc = vc_cons[fg_console].d;
|
||||
const struct font_desc *font = NULL;
|
||||
struct module *owner;
|
||||
@ -1050,23 +1069,26 @@ static const char *fbcon_startup(void)
|
||||
info->var.bits_per_pixel);
|
||||
|
||||
fbcon_add_cursor_timer(info);
|
||||
fbcon_has_exited = 0;
|
||||
return display_desc;
|
||||
}
|
||||
|
||||
static void fbcon_init(struct vc_data *vc, int init)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fb_info *info;
|
||||
struct fbcon_ops *ops;
|
||||
struct vc_data **default_mode = vc->vc_display_fg;
|
||||
struct vc_data *svc = *default_mode;
|
||||
struct display *t, *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *t, *p = &fb_display[vc->vc_num];
|
||||
int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
|
||||
int cap, ret;
|
||||
|
||||
if (info_idx == -1 || info == NULL)
|
||||
if (WARN_ON(info_idx == -1))
|
||||
return;
|
||||
|
||||
if (con2fb_map[vc->vc_num] == -1)
|
||||
con2fb_map[vc->vc_num] = info_idx;
|
||||
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
cap = info->flags;
|
||||
|
||||
if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
|
||||
@ -1203,7 +1225,7 @@ static void fbcon_init(struct vc_data *vc, int init)
|
||||
ops->p = &fb_display[fg_console];
|
||||
}
|
||||
|
||||
static void fbcon_free_font(struct display *p, bool freefont)
|
||||
static void fbcon_free_font(struct fbcon_display *p, bool freefont)
|
||||
{
|
||||
if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
|
||||
kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
|
||||
@ -1215,7 +1237,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set);
|
||||
|
||||
static void fbcon_deinit(struct vc_data *vc)
|
||||
{
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fb_info *info;
|
||||
struct fbcon_ops *ops;
|
||||
int idx;
|
||||
@ -1288,7 +1310,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
u_int y_break;
|
||||
|
||||
if (fbcon_is_inactive(vc, info))
|
||||
@ -1324,7 +1346,7 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
|
||||
int count, int ypos, int xpos)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
if (!fbcon_is_inactive(vc, info))
|
||||
@ -1388,7 +1410,7 @@ static int scrollback_current = 0;
|
||||
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
int unit)
|
||||
{
|
||||
struct display *p, *t;
|
||||
struct fbcon_display *p, *t;
|
||||
struct vc_data **default_mode, *vc;
|
||||
struct vc_data *svc;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@ -1457,7 +1479,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll += count;
|
||||
if (p->yscroll >= p->vrows) /* Deal with wrap */
|
||||
@ -1476,7 +1498,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll -= count;
|
||||
if (p->yscroll < 0) /* Deal with wrap */
|
||||
@ -1494,7 +1516,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count)
|
||||
static __inline__ void ypan_up(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
p->yscroll += count;
|
||||
@ -1519,7 +1541,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll += count;
|
||||
|
||||
@ -1542,7 +1564,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
|
||||
static __inline__ void ypan_down(struct vc_data *vc, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
p->yscroll -= count;
|
||||
@ -1567,7 +1589,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
p->yscroll -= count;
|
||||
|
||||
@ -1587,7 +1609,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
static void fbcon_redraw_softback(struct vc_data *vc, struct display *p,
|
||||
static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
|
||||
long delta)
|
||||
{
|
||||
int count = vc->vc_rows;
|
||||
@ -1680,7 +1702,7 @@ static void fbcon_redraw_softback(struct vc_data *vc, struct display *p,
|
||||
}
|
||||
}
|
||||
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy)
|
||||
{
|
||||
unsigned short *s = (unsigned short *)
|
||||
@ -1715,7 +1737,7 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
|
||||
}
|
||||
|
||||
static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
|
||||
struct display *p, int line, int count, int ycount)
|
||||
struct fbcon_display *p, int line, int count, int ycount)
|
||||
{
|
||||
int offset = ycount * vc->vc_cols;
|
||||
unsigned short *d = (unsigned short *)
|
||||
@ -1764,7 +1786,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
|
||||
}
|
||||
}
|
||||
|
||||
static void fbcon_redraw(struct vc_data *vc, struct display *p,
|
||||
static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int offset)
|
||||
{
|
||||
unsigned short *d = (unsigned short *)
|
||||
@ -1848,7 +1870,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
enum con_scroll dir, unsigned int count)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
|
||||
|
||||
if (fbcon_is_inactive(vc, info))
|
||||
@ -2052,7 +2074,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
|
||||
int height, int width)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
|
||||
if (fbcon_is_inactive(vc, info))
|
||||
return;
|
||||
@ -2071,7 +2093,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
|
||||
p->vrows - p->yscroll);
|
||||
}
|
||||
|
||||
static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
|
||||
static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
|
||||
int dy, int dx, int height, int width, u_int y_break)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
@ -2113,7 +2135,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
|
||||
height, width);
|
||||
}
|
||||
|
||||
static void updatescrollmode(struct display *p,
|
||||
static void updatescrollmode(struct fbcon_display *p,
|
||||
struct fb_info *info,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
@ -2165,7 +2187,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fb_var_screeninfo var = info->var;
|
||||
int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
|
||||
|
||||
@ -2210,7 +2232,7 @@ static int fbcon_switch(struct vc_data *vc)
|
||||
{
|
||||
struct fb_info *info, *old_info = NULL;
|
||||
struct fbcon_ops *ops;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
struct fb_var_screeninfo var;
|
||||
int i, ret, prev_console, charcnt = 256;
|
||||
|
||||
@ -2348,8 +2370,6 @@ static int fbcon_switch(struct vc_data *vc)
|
||||
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
|
||||
int blank)
|
||||
{
|
||||
struct fb_event event;
|
||||
|
||||
if (blank) {
|
||||
unsigned short charmask = vc->vc_hi_font_mask ?
|
||||
0x1ff : 0xff;
|
||||
@ -2360,14 +2380,6 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
|
||||
fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
|
||||
vc->vc_video_erase_char = oldc;
|
||||
}
|
||||
|
||||
|
||||
if (!lock_fb_info(info))
|
||||
return;
|
||||
event.info = info;
|
||||
event.data = ␣
|
||||
fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
|
||||
unlock_fb_info(info);
|
||||
}
|
||||
|
||||
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
|
||||
@ -2394,9 +2406,8 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
|
||||
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
|
||||
ops->cursor_flash = (!blank);
|
||||
|
||||
if (!(info->flags & FBINFO_MISC_USEREVENT))
|
||||
if (fb_blank(info, blank))
|
||||
fbcon_generic_blank(vc, info, blank);
|
||||
if (fb_blank(info, blank))
|
||||
fbcon_generic_blank(vc, info, blank);
|
||||
}
|
||||
|
||||
if (!blank)
|
||||
@ -2553,7 +2564,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *p = &fb_display[vc->vc_num];
|
||||
struct fbcon_display *p = &fb_display[vc->vc_num];
|
||||
int resize;
|
||||
int cnt;
|
||||
char *old_data = NULL;
|
||||
@ -2601,7 +2612,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
|
||||
|
||||
static int fbcon_copy_font(struct vc_data *vc, int con)
|
||||
{
|
||||
struct display *od = &fb_display[con];
|
||||
struct fbcon_display *od = &fb_display[con];
|
||||
struct console_font *f = &vc->vc_font;
|
||||
|
||||
if (od->fontdata == f->data)
|
||||
@ -2826,7 +2837,7 @@ static void fbcon_scrolldelta(struct vc_data *vc, int lines)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[fg_console]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct display *disp = &fb_display[fg_console];
|
||||
struct fbcon_display *disp = &fb_display[fg_console];
|
||||
int offset, limit, scrollback_old;
|
||||
|
||||
if (softback_top) {
|
||||
@ -2918,7 +2929,7 @@ static int fbcon_set_origin(struct vc_data *vc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fbcon_suspended(struct fb_info *info)
|
||||
void fbcon_suspended(struct fb_info *info)
|
||||
{
|
||||
struct vc_data *vc = NULL;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@ -2931,7 +2942,7 @@ static void fbcon_suspended(struct fb_info *info)
|
||||
fbcon_cursor(vc, CM_ERASE);
|
||||
}
|
||||
|
||||
static void fbcon_resumed(struct fb_info *info)
|
||||
void fbcon_resumed(struct fb_info *info)
|
||||
{
|
||||
struct vc_data *vc;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@ -2947,7 +2958,7 @@ static void fbcon_modechanged(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct vc_data *vc;
|
||||
struct display *p;
|
||||
struct fbcon_display *p;
|
||||
int rows, cols;
|
||||
|
||||
if (!ops || ops->currcon < 0)
|
||||
@ -2987,7 +2998,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct vc_data *vc;
|
||||
struct display *p;
|
||||
struct fbcon_display *p;
|
||||
int i, rows, cols, fg = -1;
|
||||
|
||||
if (!ops || ops->currcon < 0)
|
||||
@ -3018,11 +3029,21 @@ static void fbcon_set_all_vcs(struct fb_info *info)
|
||||
fbcon_modechanged(info);
|
||||
}
|
||||
|
||||
static int fbcon_mode_deleted(struct fb_info *info,
|
||||
struct fb_videomode *mode)
|
||||
|
||||
void fbcon_update_vcs(struct fb_info *info, bool all)
|
||||
{
|
||||
if (all)
|
||||
fbcon_set_all_vcs(info);
|
||||
else
|
||||
fbcon_modechanged(info);
|
||||
}
|
||||
EXPORT_SYMBOL(fbcon_update_vcs);
|
||||
|
||||
int fbcon_mode_deleted(struct fb_info *info,
|
||||
struct fb_videomode *mode)
|
||||
{
|
||||
struct fb_info *fb_info;
|
||||
struct display *p;
|
||||
struct fbcon_display *p;
|
||||
int i, j, found = 0;
|
||||
|
||||
/* before deletion, ensure that mode is not in use */
|
||||
@ -3045,7 +3066,7 @@ static int fbcon_mode_deleted(struct fb_info *info,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
|
||||
static int fbcon_unbind(void)
|
||||
static void fbcon_unbind(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -3054,25 +3075,21 @@ static int fbcon_unbind(void)
|
||||
|
||||
if (!ret)
|
||||
fbcon_has_console_bind = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static inline int fbcon_unbind(void)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline void fbcon_unbind(void) {}
|
||||
#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
|
||||
|
||||
/* called with console_lock held */
|
||||
static int fbcon_fb_unbind(int idx)
|
||||
void fbcon_fb_unbind(struct fb_info *info)
|
||||
{
|
||||
int i, new_idx = -1, ret = 0;
|
||||
int idx = info->node;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (!fbcon_has_console_bind)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++) {
|
||||
if (con2fb_map[i] != idx &&
|
||||
@ -3105,26 +3122,24 @@ static int fbcon_fb_unbind(int idx)
|
||||
idx, 0);
|
||||
if (ret) {
|
||||
con2fb_map[i] = idx;
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = fbcon_unbind();
|
||||
fbcon_unbind();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* called with console_lock held */
|
||||
static int fbcon_fb_unregistered(struct fb_info *info)
|
||||
void fbcon_fb_unregistered(struct fb_info *info)
|
||||
{
|
||||
int i, idx;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (deferred_takeover)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
idx = info->node;
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++) {
|
||||
@ -3153,21 +3168,18 @@ static int fbcon_fb_unregistered(struct fb_info *info)
|
||||
|
||||
if (!num_registered_fb)
|
||||
do_unregister_con_driver(&fb_con);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called with console_lock held */
|
||||
static void fbcon_remap_all(int idx)
|
||||
void fbcon_remap_all(struct fb_info *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
int i, idx = info->node;
|
||||
|
||||
console_lock();
|
||||
if (deferred_takeover) {
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
||||
con2fb_map_boot[i] = idx;
|
||||
fbcon_map_override();
|
||||
console_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3180,6 +3192,7 @@ static void fbcon_remap_all(int idx)
|
||||
first_fb_vc + 1, last_fb_vc + 1);
|
||||
info_idx = idx;
|
||||
}
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
|
||||
@ -3213,7 +3226,7 @@ static inline void fbcon_select_primary(struct fb_info *info)
|
||||
#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
|
||||
|
||||
/* called with console_lock held */
|
||||
static int fbcon_fb_registered(struct fb_info *info)
|
||||
int fbcon_fb_registered(struct fb_info *info)
|
||||
{
|
||||
int ret = 0, i, idx;
|
||||
|
||||
@ -3247,7 +3260,7 @@ static int fbcon_fb_registered(struct fb_info *info)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fbcon_fb_blanked(struct fb_info *info, int blank)
|
||||
void fbcon_fb_blanked(struct fb_info *info, int blank)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct vc_data *vc;
|
||||
@ -3269,7 +3282,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank)
|
||||
ops->blank_state = blank;
|
||||
}
|
||||
|
||||
static void fbcon_new_modelist(struct fb_info *info)
|
||||
void fbcon_new_modelist(struct fb_info *info)
|
||||
{
|
||||
int i;
|
||||
struct vc_data *vc;
|
||||
@ -3290,11 +3303,11 @@ static void fbcon_new_modelist(struct fb_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
static void fbcon_get_requirement(struct fb_info *info,
|
||||
struct fb_blit_caps *caps)
|
||||
void fbcon_get_requirement(struct fb_info *info,
|
||||
struct fb_blit_caps *caps)
|
||||
{
|
||||
struct vc_data *vc;
|
||||
struct display *p;
|
||||
struct fbcon_display *p;
|
||||
|
||||
if (caps->flags) {
|
||||
int i, charcnt;
|
||||
@ -3326,80 +3339,47 @@ static void fbcon_get_requirement(struct fb_info *info,
|
||||
}
|
||||
}
|
||||
|
||||
static int fbcon_event_notify(struct notifier_block *self,
|
||||
unsigned long action, void *data)
|
||||
int fbcon_set_con2fb_map_ioctl(void __user *argp)
|
||||
{
|
||||
struct fb_event *event = data;
|
||||
struct fb_info *info = event->info;
|
||||
struct fb_videomode *mode;
|
||||
struct fb_con2fbmap *con2fb;
|
||||
struct fb_blit_caps *caps;
|
||||
int idx, ret = 0;
|
||||
struct fb_con2fbmap con2fb;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* ignore all events except driver registration and deregistration
|
||||
* if fbcon is not active
|
||||
*/
|
||||
if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
|
||||
action == FB_EVENT_FB_UNREGISTERED))
|
||||
goto done;
|
||||
|
||||
switch(action) {
|
||||
case FB_EVENT_SUSPEND:
|
||||
fbcon_suspended(info);
|
||||
break;
|
||||
case FB_EVENT_RESUME:
|
||||
fbcon_resumed(info);
|
||||
break;
|
||||
case FB_EVENT_MODE_CHANGE:
|
||||
fbcon_modechanged(info);
|
||||
break;
|
||||
case FB_EVENT_MODE_CHANGE_ALL:
|
||||
fbcon_set_all_vcs(info);
|
||||
break;
|
||||
case FB_EVENT_MODE_DELETE:
|
||||
mode = event->data;
|
||||
ret = fbcon_mode_deleted(info, mode);
|
||||
break;
|
||||
case FB_EVENT_FB_UNBIND:
|
||||
idx = info->node;
|
||||
ret = fbcon_fb_unbind(idx);
|
||||
break;
|
||||
case FB_EVENT_FB_REGISTERED:
|
||||
ret = fbcon_fb_registered(info);
|
||||
break;
|
||||
case FB_EVENT_FB_UNREGISTERED:
|
||||
ret = fbcon_fb_unregistered(info);
|
||||
break;
|
||||
case FB_EVENT_SET_CONSOLE_MAP:
|
||||
/* called with console lock held */
|
||||
con2fb = event->data;
|
||||
ret = set_con2fb_map(con2fb->console - 1,
|
||||
con2fb->framebuffer, 1);
|
||||
break;
|
||||
case FB_EVENT_GET_CONSOLE_MAP:
|
||||
con2fb = event->data;
|
||||
con2fb->framebuffer = con2fb_map[con2fb->console - 1];
|
||||
break;
|
||||
case FB_EVENT_BLANK:
|
||||
fbcon_fb_blanked(info, *(int *)event->data);
|
||||
break;
|
||||
case FB_EVENT_NEW_MODELIST:
|
||||
fbcon_new_modelist(info);
|
||||
break;
|
||||
case FB_EVENT_GET_REQ:
|
||||
caps = event->data;
|
||||
fbcon_get_requirement(info, caps);
|
||||
break;
|
||||
case FB_EVENT_REMAP_ALL_CONSOLE:
|
||||
idx = info->node;
|
||||
fbcon_remap_all(idx);
|
||||
break;
|
||||
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
|
||||
return -EFAULT;
|
||||
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
|
||||
return -EINVAL;
|
||||
if (con2fb.framebuffer >= FB_MAX)
|
||||
return -EINVAL;
|
||||
if (!registered_fb[con2fb.framebuffer])
|
||||
request_module("fb%d", con2fb.framebuffer);
|
||||
if (!registered_fb[con2fb.framebuffer]) {
|
||||
return -EINVAL;
|
||||
}
|
||||
done:
|
||||
|
||||
console_lock();
|
||||
ret = set_con2fb_map(con2fb.console - 1,
|
||||
con2fb.framebuffer, 1);
|
||||
console_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fbcon_get_con2fb_map_ioctl(void __user *argp)
|
||||
{
|
||||
struct fb_con2fbmap con2fb;
|
||||
|
||||
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
|
||||
return -EFAULT;
|
||||
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
|
||||
return -EINVAL;
|
||||
|
||||
console_lock();
|
||||
con2fb.framebuffer = con2fb_map[con2fb.console - 1];
|
||||
console_unlock();
|
||||
|
||||
return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The console `switch' structure for the frame buffer based console
|
||||
*/
|
||||
@ -3431,10 +3411,6 @@ static const struct consw fb_con = {
|
||||
.con_debug_leave = fbcon_debug_leave,
|
||||
};
|
||||
|
||||
static struct notifier_block fbcon_event_notifier = {
|
||||
.notifier_call = fbcon_event_notify,
|
||||
};
|
||||
|
||||
static ssize_t store_rotate(struct device *device,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
@ -3443,9 +3419,6 @@ static ssize_t store_rotate(struct device *device,
|
||||
int rotate, idx;
|
||||
char **last = NULL;
|
||||
|
||||
if (fbcon_has_exited)
|
||||
return count;
|
||||
|
||||
console_lock();
|
||||
idx = con2fb_map[fg_console];
|
||||
|
||||
@ -3468,9 +3441,6 @@ static ssize_t store_rotate_all(struct device *device,
|
||||
int rotate, idx;
|
||||
char **last = NULL;
|
||||
|
||||
if (fbcon_has_exited)
|
||||
return count;
|
||||
|
||||
console_lock();
|
||||
idx = con2fb_map[fg_console];
|
||||
|
||||
@ -3491,9 +3461,6 @@ static ssize_t show_rotate(struct device *device,
|
||||
struct fb_info *info;
|
||||
int rotate = 0, idx;
|
||||
|
||||
if (fbcon_has_exited)
|
||||
return 0;
|
||||
|
||||
console_lock();
|
||||
idx = con2fb_map[fg_console];
|
||||
|
||||
@ -3514,9 +3481,6 @@ static ssize_t show_cursor_blink(struct device *device,
|
||||
struct fbcon_ops *ops;
|
||||
int idx, blink = -1;
|
||||
|
||||
if (fbcon_has_exited)
|
||||
return 0;
|
||||
|
||||
console_lock();
|
||||
idx = con2fb_map[fg_console];
|
||||
|
||||
@ -3543,9 +3507,6 @@ static ssize_t store_cursor_blink(struct device *device,
|
||||
int blink, idx;
|
||||
char **last = NULL;
|
||||
|
||||
if (fbcon_has_exited)
|
||||
return count;
|
||||
|
||||
console_lock();
|
||||
idx = con2fb_map[fg_console];
|
||||
|
||||
@ -3668,9 +3629,6 @@ static void fbcon_exit(void)
|
||||
struct fb_info *info;
|
||||
int i, j, mapped;
|
||||
|
||||
if (fbcon_has_exited)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
if (deferred_takeover) {
|
||||
dummycon_unregister_output_notifier(&fbcon_output_nb);
|
||||
@ -3695,7 +3653,7 @@ static void fbcon_exit(void)
|
||||
for (j = first_fb_vc; j <= last_fb_vc; j++) {
|
||||
if (con2fb_map[j] == i) {
|
||||
mapped = 1;
|
||||
break;
|
||||
con2fb_map[j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3718,8 +3676,6 @@ static void fbcon_exit(void)
|
||||
info->queue.func = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fbcon_has_exited = 1;
|
||||
}
|
||||
|
||||
void __init fb_console_init(void)
|
||||
@ -3727,7 +3683,6 @@ void __init fb_console_init(void)
|
||||
int i;
|
||||
|
||||
console_lock();
|
||||
fb_register_client(&fbcon_event_notifier);
|
||||
fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL,
|
||||
"fbcon");
|
||||
|
||||
@ -3763,7 +3718,6 @@ static void __exit fbcon_deinit_device(void)
|
||||
void __exit fb_console_exit(void)
|
||||
{
|
||||
console_lock();
|
||||
fb_unregister_client(&fbcon_event_notifier);
|
||||
fbcon_deinit_device();
|
||||
device_destroy(fb_class, MKDEV(0, 0));
|
||||
fbcon_exit();
|
||||
|
@ -25,7 +25,7 @@
|
||||
* low-level frame buffer device
|
||||
*/
|
||||
|
||||
struct display {
|
||||
struct fbcon_display {
|
||||
/* Filled in by the low-level console driver */
|
||||
const u_char *fontdata;
|
||||
int userfont; /* != 0 if fontdata kmalloc()ed */
|
||||
@ -68,7 +68,7 @@ struct fbcon_ops {
|
||||
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
|
||||
struct timer_list cursor_timer; /* Cursor timer */
|
||||
struct fb_cursor cursor_state;
|
||||
struct display *p;
|
||||
struct fbcon_display *p;
|
||||
struct fb_info *info;
|
||||
int currcon; /* Current VC. */
|
||||
int cur_blink_jiffies;
|
||||
@ -225,7 +225,7 @@ extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
|
||||
#define FBCON_ATTRIBUTE_REVERSE 2
|
||||
#define FBCON_ATTRIBUTE_BOLD 4
|
||||
|
||||
static inline int real_y(struct display *p, int ypos)
|
||||
static inline int real_y(struct fbcon_display *p, int ypos)
|
||||
{
|
||||
int rows = p->vrows;
|
||||
|
||||
|
@ -80,17 +80,6 @@ static void put_fb_info(struct fb_info *fb_info)
|
||||
fb_info->fbops->fb_destroy(fb_info);
|
||||
}
|
||||
|
||||
int lock_fb_info(struct fb_info *info)
|
||||
{
|
||||
mutex_lock(&info->lock);
|
||||
if (!info->fbops) {
|
||||
mutex_unlock(&info->lock);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(lock_fb_info);
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
@ -943,16 +932,13 @@ EXPORT_SYMBOL(fb_pan_display);
|
||||
static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
u32 activate)
|
||||
{
|
||||
struct fb_event event;
|
||||
struct fb_blit_caps caps, fbcaps;
|
||||
int err = 0;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
memset(&fbcaps, 0, sizeof(fbcaps));
|
||||
caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
|
||||
event.info = info;
|
||||
event.data = ∩︀
|
||||
fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
|
||||
fbcon_get_requirement(info, &caps);
|
||||
info->fbops->fb_get_caps(info, &fbcaps, var);
|
||||
|
||||
if (((fbcaps.x ^ caps.x) & caps.x) ||
|
||||
@ -968,6 +954,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
{
|
||||
int flags = info->flags;
|
||||
int ret = 0;
|
||||
u32 activate;
|
||||
struct fb_var_screeninfo old_var;
|
||||
struct fb_videomode mode;
|
||||
struct fb_event event;
|
||||
|
||||
if (var->activate & FB_ACTIVATE_INV_MODE) {
|
||||
struct fb_videomode mode1, mode2;
|
||||
@ -977,100 +967,90 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
/* make sure we don't delete the videomode of current var */
|
||||
ret = fb_mode_is_equal(&mode1, &mode2);
|
||||
|
||||
if (!ret) {
|
||||
struct fb_event event;
|
||||
|
||||
event.info = info;
|
||||
event.data = &mode1;
|
||||
ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
|
||||
}
|
||||
if (!ret)
|
||||
fbcon_mode_deleted(info, &mode1);
|
||||
|
||||
if (!ret)
|
||||
fb_delete_videomode(&mode1, &info->modelist);
|
||||
fb_delete_videomode(&mode1, &info->modelist);
|
||||
|
||||
|
||||
ret = (ret) ? -EINVAL : 0;
|
||||
goto done;
|
||||
return ret ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
if ((var->activate & FB_ACTIVATE_FORCE) ||
|
||||
memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
|
||||
u32 activate = var->activate;
|
||||
if (!(var->activate & FB_ACTIVATE_FORCE) &&
|
||||
!memcmp(&info->var, var, sizeof(struct fb_var_screeninfo)))
|
||||
return 0;
|
||||
|
||||
/* When using FOURCC mode, make sure the red, green, blue and
|
||||
* transp fields are set to 0.
|
||||
*/
|
||||
if ((info->fix.capabilities & FB_CAP_FOURCC) &&
|
||||
var->grayscale > 1) {
|
||||
if (var->red.offset || var->green.offset ||
|
||||
var->blue.offset || var->transp.offset ||
|
||||
var->red.length || var->green.length ||
|
||||
var->blue.length || var->transp.length ||
|
||||
var->red.msb_right || var->green.msb_right ||
|
||||
var->blue.msb_right || var->transp.msb_right)
|
||||
return -EINVAL;
|
||||
}
|
||||
activate = var->activate;
|
||||
|
||||
if (!info->fbops->fb_check_var) {
|
||||
*var = info->var;
|
||||
goto done;
|
||||
}
|
||||
/* When using FOURCC mode, make sure the red, green, blue and
|
||||
* transp fields are set to 0.
|
||||
*/
|
||||
if ((info->fix.capabilities & FB_CAP_FOURCC) &&
|
||||
var->grayscale > 1) {
|
||||
if (var->red.offset || var->green.offset ||
|
||||
var->blue.offset || var->transp.offset ||
|
||||
var->red.length || var->green.length ||
|
||||
var->blue.length || var->transp.length ||
|
||||
var->red.msb_right || var->green.msb_right ||
|
||||
var->blue.msb_right || var->transp.msb_right)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = info->fbops->fb_check_var(var, info);
|
||||
if (!info->fbops->fb_check_var) {
|
||||
*var = info->var;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = info->fbops->fb_check_var(var, info);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
|
||||
return 0;
|
||||
|
||||
if (info->fbops->fb_get_caps) {
|
||||
ret = fb_check_caps(info, var, activate);
|
||||
|
||||
if (ret)
|
||||
goto done;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
|
||||
struct fb_var_screeninfo old_var;
|
||||
struct fb_videomode mode;
|
||||
old_var = info->var;
|
||||
info->var = *var;
|
||||
|
||||
if (info->fbops->fb_get_caps) {
|
||||
ret = fb_check_caps(info, var, activate);
|
||||
if (info->fbops->fb_set_par) {
|
||||
ret = info->fbops->fb_set_par(info);
|
||||
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
old_var = info->var;
|
||||
info->var = *var;
|
||||
|
||||
if (info->fbops->fb_set_par) {
|
||||
ret = info->fbops->fb_set_par(info);
|
||||
|
||||
if (ret) {
|
||||
info->var = old_var;
|
||||
printk(KERN_WARNING "detected "
|
||||
"fb_set_par error, "
|
||||
"error code: %d\n", ret);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
fb_pan_display(info, &info->var);
|
||||
fb_set_cmap(&info->cmap, info);
|
||||
fb_var_to_videomode(&mode, &info->var);
|
||||
|
||||
if (info->modelist.prev && info->modelist.next &&
|
||||
!list_empty(&info->modelist))
|
||||
ret = fb_add_videomode(&mode, &info->modelist);
|
||||
|
||||
if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
|
||||
struct fb_event event;
|
||||
int evnt = (activate & FB_ACTIVATE_ALL) ?
|
||||
FB_EVENT_MODE_CHANGE_ALL :
|
||||
FB_EVENT_MODE_CHANGE;
|
||||
|
||||
info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
event.info = info;
|
||||
event.data = &mode;
|
||||
fb_notifier_call_chain(evnt, &event);
|
||||
}
|
||||
if (ret) {
|
||||
info->var = old_var;
|
||||
printk(KERN_WARNING "detected "
|
||||
"fb_set_par error, "
|
||||
"error code: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
fb_pan_display(info, &info->var);
|
||||
fb_set_cmap(&info->cmap, info);
|
||||
fb_var_to_videomode(&mode, &info->var);
|
||||
|
||||
if (info->modelist.prev && info->modelist.next &&
|
||||
!list_empty(&info->modelist))
|
||||
ret = fb_add_videomode(&mode, &info->modelist);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
event.info = info;
|
||||
event.data = &mode;
|
||||
fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);
|
||||
|
||||
if (flags & FBINFO_MISC_USEREVENT)
|
||||
fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_set_var);
|
||||
|
||||
@ -1112,17 +1092,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
struct fb_ops *fb;
|
||||
struct fb_var_screeninfo var;
|
||||
struct fb_fix_screeninfo fix;
|
||||
struct fb_con2fbmap con2fb;
|
||||
struct fb_cmap cmap_from;
|
||||
struct fb_cmap_user cmap;
|
||||
struct fb_event event;
|
||||
void __user *argp = (void __user *)arg;
|
||||
long ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case FBIOGET_VSCREENINFO:
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
lock_fb_info(info);
|
||||
var = info->var;
|
||||
unlock_fb_info(info);
|
||||
|
||||
@ -1132,10 +1109,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
if (copy_from_user(&var, argp, sizeof(var)))
|
||||
return -EFAULT;
|
||||
console_lock();
|
||||
if (!lock_fb_info(info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
lock_fb_info(info);
|
||||
info->flags |= FBINFO_MISC_USEREVENT;
|
||||
ret = fb_set_var(info, &var);
|
||||
info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
@ -1145,8 +1119,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case FBIOGET_FSCREENINFO:
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
lock_fb_info(info);
|
||||
fix = info->fix;
|
||||
if (info->flags & FBINFO_HIDE_SMEM_START)
|
||||
fix.smem_start = 0;
|
||||
@ -1162,8 +1135,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
case FBIOGETCMAP:
|
||||
if (copy_from_user(&cmap, argp, sizeof(cmap)))
|
||||
return -EFAULT;
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
lock_fb_info(info);
|
||||
cmap_from = info->cmap;
|
||||
unlock_fb_info(info);
|
||||
ret = fb_cmap_to_user(&cmap_from, &cmap);
|
||||
@ -1172,10 +1144,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
if (copy_from_user(&var, argp, sizeof(var)))
|
||||
return -EFAULT;
|
||||
console_lock();
|
||||
if (!lock_fb_info(info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
lock_fb_info(info);
|
||||
ret = fb_pan_display(info, &var);
|
||||
unlock_fb_info(info);
|
||||
console_unlock();
|
||||
@ -1186,58 +1155,22 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case FBIOGET_CON2FBMAP:
|
||||
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
|
||||
return -EFAULT;
|
||||
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
|
||||
return -EINVAL;
|
||||
con2fb.framebuffer = -1;
|
||||
event.data = &con2fb;
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
event.info = info;
|
||||
fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
|
||||
unlock_fb_info(info);
|
||||
ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
|
||||
ret = fbcon_get_con2fb_map_ioctl(argp);
|
||||
break;
|
||||
case FBIOPUT_CON2FBMAP:
|
||||
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
|
||||
return -EFAULT;
|
||||
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
|
||||
return -EINVAL;
|
||||
if (con2fb.framebuffer >= FB_MAX)
|
||||
return -EINVAL;
|
||||
if (!registered_fb[con2fb.framebuffer])
|
||||
request_module("fb%d", con2fb.framebuffer);
|
||||
if (!registered_fb[con2fb.framebuffer]) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
event.data = &con2fb;
|
||||
console_lock();
|
||||
if (!lock_fb_info(info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
event.info = info;
|
||||
ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
|
||||
unlock_fb_info(info);
|
||||
console_unlock();
|
||||
ret = fbcon_set_con2fb_map_ioctl(argp);
|
||||
break;
|
||||
case FBIOBLANK:
|
||||
console_lock();
|
||||
if (!lock_fb_info(info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
info->flags |= FBINFO_MISC_USEREVENT;
|
||||
lock_fb_info(info);
|
||||
ret = fb_blank(info, arg);
|
||||
info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
/* might again call into fb_blank */
|
||||
fbcon_fb_blanked(info, arg);
|
||||
unlock_fb_info(info);
|
||||
console_unlock();
|
||||
break;
|
||||
default:
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
lock_fb_info(info);
|
||||
fb = info->fbops;
|
||||
if (fb->fb_ioctl)
|
||||
ret = fb->fb_ioctl(info, cmd, arg);
|
||||
@ -1357,8 +1290,7 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
|
||||
{
|
||||
struct fb_fix_screeninfo fix;
|
||||
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
lock_fb_info(info);
|
||||
fix = info->fix;
|
||||
if (info->flags & FBINFO_HIDE_SMEM_START)
|
||||
fix.smem_start = 0;
|
||||
@ -1418,8 +1350,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
|
||||
if (!info)
|
||||
return -ENODEV;
|
||||
fb = info->fbops;
|
||||
if (!fb)
|
||||
return -ENODEV;
|
||||
mutex_lock(&info->mm_lock);
|
||||
if (fb->fb_mmap) {
|
||||
int res;
|
||||
@ -1483,7 +1413,7 @@ __releases(&info->lock)
|
||||
if (IS_ERR(info))
|
||||
return PTR_ERR(info);
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
lock_fb_info(info);
|
||||
if (!try_module_get(info->fbops->owner)) {
|
||||
res = -ENODEV;
|
||||
goto out;
|
||||
@ -1499,7 +1429,7 @@ __releases(&info->lock)
|
||||
fb_deferred_io_open(info, inode, file);
|
||||
#endif
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
unlock_fb_info(info);
|
||||
if (res)
|
||||
put_fb_info(info);
|
||||
return res;
|
||||
@ -1512,11 +1442,11 @@ __releases(&info->lock)
|
||||
{
|
||||
struct fb_info * const info = file->private_data;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
lock_fb_info(info);
|
||||
if (info->fbops->fb_release)
|
||||
info->fbops->fb_release(info,1);
|
||||
module_put(info->fbops->owner);
|
||||
mutex_unlock(&info->lock);
|
||||
unlock_fb_info(info);
|
||||
put_fb_info(info);
|
||||
return 0;
|
||||
}
|
||||
@ -1621,13 +1551,13 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena,
|
||||
return false;
|
||||
}
|
||||
|
||||
static int do_unregister_framebuffer(struct fb_info *fb_info);
|
||||
static void do_unregister_framebuffer(struct fb_info *fb_info);
|
||||
|
||||
#define VGA_FB_PHYS 0xA0000
|
||||
static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
const char *name, bool primary)
|
||||
static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
const char *name, bool primary)
|
||||
{
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
/* check all firmware fbs and kick off if the base addr overlaps */
|
||||
for_each_registered_fb(i) {
|
||||
@ -1643,13 +1573,9 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
|
||||
printk(KERN_INFO "fb%d: switching to %s from %s\n",
|
||||
i, name, registered_fb[i]->fix.id);
|
||||
ret = do_unregister_framebuffer(registered_fb[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
do_unregister_framebuffer(registered_fb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool lockless_register_fb;
|
||||
@ -1660,17 +1586,14 @@ MODULE_PARM_DESC(lockless_register_fb,
|
||||
static int do_register_framebuffer(struct fb_info *fb_info)
|
||||
{
|
||||
int i, ret;
|
||||
struct fb_event event;
|
||||
struct fb_videomode mode;
|
||||
|
||||
if (fb_check_foreignness(fb_info))
|
||||
return -ENOSYS;
|
||||
|
||||
ret = do_remove_conflicting_framebuffers(fb_info->apertures,
|
||||
fb_info->fix.id,
|
||||
fb_is_primary_device(fb_info));
|
||||
if (ret)
|
||||
return ret;
|
||||
do_remove_conflicting_framebuffers(fb_info->apertures,
|
||||
fb_info->fix.id,
|
||||
fb_is_primary_device(fb_info));
|
||||
|
||||
if (num_registered_fb == FB_MAX)
|
||||
return -ENXIO;
|
||||
@ -1723,20 +1646,22 @@ static int do_register_framebuffer(struct fb_info *fb_info)
|
||||
fb_add_videomode(&mode, &fb_info->modelist);
|
||||
registered_fb[i] = fb_info;
|
||||
|
||||
event.info = fb_info;
|
||||
#ifdef CONFIG_GUMSTIX_AM200EPD
|
||||
{
|
||||
struct fb_event event;
|
||||
event.info = fb_info;
|
||||
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!lockless_register_fb)
|
||||
console_lock();
|
||||
else
|
||||
atomic_inc(&ignore_console_lock_warning);
|
||||
if (!lock_fb_info(fb_info)) {
|
||||
ret = -ENODEV;
|
||||
goto unlock_console;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
|
||||
lock_fb_info(fb_info);
|
||||
ret = fbcon_fb_registered(fb_info);
|
||||
unlock_fb_info(fb_info);
|
||||
unlock_console:
|
||||
|
||||
if (!lockless_register_fb)
|
||||
console_unlock();
|
||||
else
|
||||
@ -1744,44 +1669,44 @@ unlock_console:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int unbind_console(struct fb_info *fb_info)
|
||||
static void unbind_console(struct fb_info *fb_info)
|
||||
{
|
||||
struct fb_event event;
|
||||
int ret;
|
||||
int i = fb_info->node;
|
||||
|
||||
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
|
||||
return -EINVAL;
|
||||
if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
|
||||
return;
|
||||
|
||||
console_lock();
|
||||
if (!lock_fb_info(fb_info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
event.info = fb_info;
|
||||
ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
|
||||
lock_fb_info(fb_info);
|
||||
fbcon_fb_unbind(fb_info);
|
||||
unlock_fb_info(fb_info);
|
||||
console_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __unlink_framebuffer(struct fb_info *fb_info);
|
||||
|
||||
static int do_unregister_framebuffer(struct fb_info *fb_info)
|
||||
void unlink_framebuffer(struct fb_info *fb_info)
|
||||
{
|
||||
struct fb_event event;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = unbind_console(fb_info);
|
||||
i = fb_info->node;
|
||||
if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
|
||||
return;
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
if (!fb_info->dev)
|
||||
return;
|
||||
|
||||
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
|
||||
|
||||
pm_vt_switch_unregister(fb_info->dev);
|
||||
|
||||
__unlink_framebuffer(fb_info);
|
||||
unbind_console(fb_info);
|
||||
|
||||
fb_info->dev = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(unlink_framebuffer);
|
||||
|
||||
static void do_unregister_framebuffer(struct fb_info *fb_info)
|
||||
{
|
||||
unlink_framebuffer(fb_info);
|
||||
if (fb_info->pixmap.addr &&
|
||||
(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
|
||||
kfree(fb_info->pixmap.addr);
|
||||
@ -1789,46 +1714,21 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
|
||||
registered_fb[fb_info->node] = NULL;
|
||||
num_registered_fb--;
|
||||
fb_cleanup_device(fb_info);
|
||||
event.info = fb_info;
|
||||
#ifdef CONFIG_GUMSTIX_AM200EPD
|
||||
{
|
||||
struct fb_event event;
|
||||
event.info = fb_info;
|
||||
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
|
||||
}
|
||||
#endif
|
||||
console_lock();
|
||||
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
|
||||
fbcon_fb_unregistered(fb_info);
|
||||
console_unlock();
|
||||
|
||||
/* this may free fb info */
|
||||
put_fb_info(fb_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __unlink_framebuffer(struct fb_info *fb_info)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = fb_info->node;
|
||||
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
|
||||
return -EINVAL;
|
||||
|
||||
if (fb_info->dev) {
|
||||
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
|
||||
fb_info->dev = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unlink_framebuffer(struct fb_info *fb_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __unlink_framebuffer(fb_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
unbind_console(fb_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(unlink_framebuffer);
|
||||
|
||||
/**
|
||||
* remove_conflicting_framebuffers - remove firmware-configured framebuffers
|
||||
* @a: memory range, users of which are to be removed
|
||||
@ -1842,7 +1742,6 @@ EXPORT_SYMBOL(unlink_framebuffer);
|
||||
int remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
const char *name, bool primary)
|
||||
{
|
||||
int ret;
|
||||
bool do_free = false;
|
||||
|
||||
if (!a) {
|
||||
@ -1856,13 +1755,13 @@ int remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
}
|
||||
|
||||
mutex_lock(®istration_lock);
|
||||
ret = do_remove_conflicting_framebuffers(a, name, primary);
|
||||
do_remove_conflicting_framebuffers(a, name, primary);
|
||||
mutex_unlock(®istration_lock);
|
||||
|
||||
if (do_free)
|
||||
kfree(a);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(remove_conflicting_framebuffers);
|
||||
|
||||
@ -1959,16 +1858,12 @@ EXPORT_SYMBOL(register_framebuffer);
|
||||
* that the driver implements fb_open() and fb_release() to
|
||||
* check that no processes are using the device.
|
||||
*/
|
||||
int
|
||||
void
|
||||
unregister_framebuffer(struct fb_info *fb_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(®istration_lock);
|
||||
ret = do_unregister_framebuffer(fb_info);
|
||||
do_unregister_framebuffer(fb_info);
|
||||
mutex_unlock(®istration_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_framebuffer);
|
||||
|
||||
@ -1983,15 +1878,14 @@ EXPORT_SYMBOL(unregister_framebuffer);
|
||||
*/
|
||||
void fb_set_suspend(struct fb_info *info, int state)
|
||||
{
|
||||
struct fb_event event;
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
event.info = info;
|
||||
if (state) {
|
||||
fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
|
||||
fbcon_suspended(info);
|
||||
info->state = FBINFO_STATE_SUSPENDED;
|
||||
} else {
|
||||
info->state = FBINFO_STATE_RUNNING;
|
||||
fb_notifier_call_chain(FB_EVENT_RESUME, &event);
|
||||
fbcon_resumed(info);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(fb_set_suspend);
|
||||
@ -2059,7 +1953,6 @@ subsys_initcall(fbmem_init);
|
||||
|
||||
int fb_new_modelist(struct fb_info *info)
|
||||
{
|
||||
struct fb_event event;
|
||||
struct fb_var_screeninfo var = info->var;
|
||||
struct list_head *pos, *n;
|
||||
struct fb_modelist *modelist;
|
||||
@ -2079,14 +1972,12 @@ int fb_new_modelist(struct fb_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
err = 1;
|
||||
if (list_empty(&info->modelist))
|
||||
return 1;
|
||||
|
||||
if (!list_empty(&info->modelist)) {
|
||||
event.info = info;
|
||||
err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
|
||||
}
|
||||
fbcon_new_modelist(info);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fbcon.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@ -175,10 +176,7 @@ static ssize_t store_modes(struct device *device,
|
||||
return -EINVAL;
|
||||
|
||||
console_lock();
|
||||
if (!lock_fb_info(fb_info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
lock_fb_info(fb_info);
|
||||
|
||||
list_splice(&fb_info->modelist, &old_list);
|
||||
fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
|
||||
@ -304,12 +302,13 @@ static ssize_t store_blank(struct device *device,
|
||||
{
|
||||
struct fb_info *fb_info = dev_get_drvdata(device);
|
||||
char *last = NULL;
|
||||
int err;
|
||||
int err, arg;
|
||||
|
||||
arg = simple_strtoul(buf, &last, 0);
|
||||
console_lock();
|
||||
fb_info->flags |= FBINFO_MISC_USEREVENT;
|
||||
err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
|
||||
fb_info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
err = fb_blank(fb_info, arg);
|
||||
/* might again call into fb_blank */
|
||||
fbcon_fb_blanked(fb_info, arg);
|
||||
console_unlock();
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -405,10 +404,7 @@ static ssize_t store_fbstate(struct device *device,
|
||||
state = simple_strtoul(buf, &last, 0);
|
||||
|
||||
console_lock();
|
||||
if (!lock_fb_info(fb_info)) {
|
||||
console_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
lock_fb_info(fb_info);
|
||||
|
||||
fb_set_suspend(fb_info, (int)state);
|
||||
|
||||
|
@ -61,7 +61,6 @@
|
||||
struct cfb_info {
|
||||
struct fb_info fb;
|
||||
struct display_switch *dispsw;
|
||||
struct display *display;
|
||||
unsigned char __iomem *region;
|
||||
unsigned char __iomem *regs;
|
||||
u_int id;
|
||||
|
@ -2122,14 +2122,7 @@ static void neofb_remove(struct pci_dev *dev)
|
||||
DBG("neofb_remove");
|
||||
|
||||
if (info) {
|
||||
/*
|
||||
* If unregister_framebuffer fails, then
|
||||
* we will be leaving hooks that could cause
|
||||
* oopsen laying around.
|
||||
*/
|
||||
if (unregister_framebuffer(info))
|
||||
printk(KERN_WARNING
|
||||
"neofb: danger danger! Oopsen imminent!\n");
|
||||
unregister_framebuffer(info);
|
||||
|
||||
neo_unmap_video(info);
|
||||
fb_destroy_modedb(info->monspecs.modedb);
|
||||
|
@ -60,8 +60,7 @@ static ssize_t store_rotate_type(struct device *dev,
|
||||
if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
|
||||
return -EINVAL;
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
|
||||
r = 0;
|
||||
if (rot_type == ofbi->rotation_type)
|
||||
@ -112,8 +111,7 @@ static ssize_t store_mirror(struct device *dev,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
|
||||
ofbi->mirror = mirror;
|
||||
|
||||
@ -149,8 +147,7 @@ static ssize_t show_overlays(struct device *dev,
|
||||
ssize_t l = 0;
|
||||
int t;
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
for (t = 0; t < ofbi->num_overlays; t++) {
|
||||
@ -208,8 +205,7 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
|
||||
if (buf[len - 1] == '\n')
|
||||
len = len - 1;
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
if (len > 0) {
|
||||
@ -340,8 +336,7 @@ static ssize_t show_overlays_rotate(struct device *dev,
|
||||
ssize_t l = 0;
|
||||
int t;
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
|
||||
for (t = 0; t < ofbi->num_overlays; t++) {
|
||||
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
|
||||
@ -369,8 +364,7 @@ static ssize_t store_overlays_rotate(struct device *dev,
|
||||
if (buf[len - 1] == '\n')
|
||||
len = len - 1;
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
|
||||
if (len > 0) {
|
||||
char *p = (char *)buf;
|
||||
@ -453,8 +447,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (!lock_fb_info(fbi))
|
||||
return -ENODEV;
|
||||
lock_fb_info(fbi);
|
||||
|
||||
if (display && display->driver->sync)
|
||||
display->driver->sync(display);
|
||||
|
@ -974,35 +974,10 @@ static void sa1100fb_task(struct work_struct *w)
|
||||
*/
|
||||
static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
|
||||
{
|
||||
#if 0
|
||||
unsigned int min_period = (unsigned int)-1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
struct display *disp = &fb_display[i];
|
||||
unsigned int period;
|
||||
|
||||
/*
|
||||
* Do we own this display?
|
||||
*/
|
||||
if (disp->fb_info != &fbi->fb)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ok, calculate its DMA period
|
||||
*/
|
||||
period = sa1100fb_display_dma_period(&disp->var);
|
||||
if (period < min_period)
|
||||
min_period = period;
|
||||
}
|
||||
|
||||
return min_period;
|
||||
#else
|
||||
/*
|
||||
* FIXME: we need to verify _all_ consoles.
|
||||
*/
|
||||
return sa1100fb_display_dma_period(&fbi->fb.var);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2333,14 +2333,7 @@ static void savagefb_remove(struct pci_dev *dev)
|
||||
DBG("savagefb_remove");
|
||||
|
||||
if (info) {
|
||||
/*
|
||||
* If unregister_framebuffer fails, then
|
||||
* we will be leaving hooks that could cause
|
||||
* oopsen laying around.
|
||||
*/
|
||||
if (unregister_framebuffer(info))
|
||||
printk(KERN_WARNING "savagefb: danger danger! "
|
||||
"Oopsen imminent!\n");
|
||||
unregister_framebuffer(info);
|
||||
|
||||
#ifdef CONFIG_FB_SAVAGE_I2C
|
||||
savagefb_delete_i2c_busses(info);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fbcon.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -213,7 +214,6 @@ struct sh_mobile_lcdc_priv {
|
||||
struct sh_mobile_lcdc_chan ch[2];
|
||||
struct sh_mobile_lcdc_overlay overlays[4];
|
||||
|
||||
struct notifier_block notifier;
|
||||
int started;
|
||||
int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
|
||||
};
|
||||
@ -534,89 +534,9 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
|
||||
ch->tx_dev->ops->display_off(ch->tx_dev);
|
||||
}
|
||||
|
||||
static bool
|
||||
sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
|
||||
const struct fb_videomode *new_mode)
|
||||
{
|
||||
dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
|
||||
ch->display.mode.xres, ch->display.mode.yres,
|
||||
new_mode->xres, new_mode->yres);
|
||||
|
||||
/* It can be a different monitor with an equal video-mode */
|
||||
if (fb_mode_is_equal(&ch->display.mode, new_mode))
|
||||
return false;
|
||||
|
||||
dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
|
||||
ch->display.mode.yres, new_mode->yres);
|
||||
ch->display.mode = *new_mode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info);
|
||||
|
||||
static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
|
||||
enum sh_mobile_lcdc_entity_event event,
|
||||
const struct fb_videomode *mode,
|
||||
const struct fb_monspecs *monspec)
|
||||
{
|
||||
struct fb_info *info = ch->info;
|
||||
struct fb_var_screeninfo var;
|
||||
int ret = 0;
|
||||
|
||||
switch (event) {
|
||||
case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
|
||||
/* HDMI plug in */
|
||||
console_lock();
|
||||
if (lock_fb_info(info)) {
|
||||
|
||||
|
||||
ch->display.width = monspec->max_x * 10;
|
||||
ch->display.height = monspec->max_y * 10;
|
||||
|
||||
if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
|
||||
info->state == FBINFO_STATE_RUNNING) {
|
||||
/* First activation with the default monitor.
|
||||
* Just turn on, if we run a resume here, the
|
||||
* logo disappears.
|
||||
*/
|
||||
info->var.width = ch->display.width;
|
||||
info->var.height = ch->display.height;
|
||||
sh_mobile_lcdc_display_on(ch);
|
||||
} else {
|
||||
/* New monitor or have to wake up */
|
||||
fb_set_suspend(info, 0);
|
||||
}
|
||||
|
||||
|
||||
unlock_fb_info(info);
|
||||
}
|
||||
console_unlock();
|
||||
break;
|
||||
|
||||
case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
|
||||
/* HDMI disconnect */
|
||||
console_lock();
|
||||
if (lock_fb_info(info)) {
|
||||
fb_set_suspend(info, 1);
|
||||
unlock_fb_info(info);
|
||||
}
|
||||
console_unlock();
|
||||
break;
|
||||
|
||||
case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
|
||||
/* Validate a proposed new mode */
|
||||
fb_videomode_to_var(&var, mode);
|
||||
var.bits_per_pixel = info->var.bits_per_pixel;
|
||||
var.grayscale = info->var.grayscale;
|
||||
ret = sh_mobile_lcdc_check_var(&var, info);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Format helpers
|
||||
*/
|
||||
@ -1838,8 +1758,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
|
||||
struct sh_mobile_lcdc_chan *ch = info->par;
|
||||
struct fb_var_screeninfo var;
|
||||
struct fb_videomode mode;
|
||||
struct fb_event event;
|
||||
int evnt = FB_EVENT_MODE_CHANGE_ALL;
|
||||
|
||||
if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
|
||||
/* More framebuffer users are active */
|
||||
@ -1861,14 +1779,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
|
||||
/* Couldn't reconfigure, hopefully, can continue as before */
|
||||
return;
|
||||
|
||||
/*
|
||||
* fb_set_var() calls the notifier change internally, only if
|
||||
* FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
|
||||
* user event, we have to call the chain ourselves.
|
||||
*/
|
||||
event.info = info;
|
||||
event.data = &ch->display.mode;
|
||||
fb_notifier_call_chain(evnt, &event);
|
||||
fbcon_update_vcs(info, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2319,37 +2230,6 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
|
||||
* Framebuffer notifier
|
||||
*/
|
||||
|
||||
/* locking: called with info->lock held */
|
||||
static int sh_mobile_lcdc_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct fb_event *event = data;
|
||||
struct fb_info *info = event->info;
|
||||
struct sh_mobile_lcdc_chan *ch = info->par;
|
||||
|
||||
if (&ch->lcdc->notifier != nb)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
|
||||
__func__, action, event->data);
|
||||
|
||||
switch(action) {
|
||||
case FB_EVENT_SUSPEND:
|
||||
sh_mobile_lcdc_display_off(ch);
|
||||
sh_mobile_lcdc_stop(ch->lcdc);
|
||||
break;
|
||||
case FB_EVENT_RESUME:
|
||||
mutex_lock(&ch->open_lock);
|
||||
sh_mobile_fb_reconfig(info);
|
||||
mutex_unlock(&ch->open_lock);
|
||||
|
||||
sh_mobile_lcdc_display_on(ch);
|
||||
sh_mobile_lcdc_start(ch->lcdc);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Probe/remove and driver init/exit
|
||||
*/
|
||||
@ -2377,8 +2257,6 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
|
||||
struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
|
||||
fb_unregister_client(&priv->notifier);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
|
||||
sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
|
||||
@ -2540,8 +2418,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
|
||||
unsigned int max_size;
|
||||
unsigned int i;
|
||||
|
||||
ch->notify = sh_mobile_lcdc_display_notify;
|
||||
|
||||
/* Validate the format. */
|
||||
format = sh_mobile_format_info(cfg->fourcc);
|
||||
if (format == NULL) {
|
||||
@ -2770,10 +2646,6 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Failure ignored */
|
||||
priv->notifier.notifier_call = sh_mobile_lcdc_notify;
|
||||
fb_register_client(&priv->notifier);
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
sh_mobile_lcdc_remove(pdev);
|
||||
|
@ -87,11 +87,6 @@ struct sh_mobile_lcdc_chan {
|
||||
unsigned long base_addr_c;
|
||||
unsigned int line_size;
|
||||
|
||||
int (*notify)(struct sh_mobile_lcdc_chan *ch,
|
||||
enum sh_mobile_lcdc_entity_event event,
|
||||
const struct fb_videomode *mode,
|
||||
const struct fb_monspecs *monspec);
|
||||
|
||||
/* Backlight */
|
||||
struct backlight_device *bl;
|
||||
unsigned int bl_brightness;
|
||||
|
@ -62,6 +62,7 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
|
||||
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
|
||||
struct drm_connector_state *conn_state);
|
||||
void drm_atomic_helper_connector_reset(struct drm_connector *connector);
|
||||
void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
|
||||
void
|
||||
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
|
||||
struct drm_connector_state *state);
|
||||
|
@ -153,7 +153,7 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
|
||||
int drm_client_modeset_create(struct drm_client_dev *client);
|
||||
void drm_client_modeset_free(struct drm_client_dev *client);
|
||||
int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height);
|
||||
bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
|
||||
bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
|
||||
int drm_client_modeset_commit_force(struct drm_client_dev *client);
|
||||
int drm_client_modeset_commit(struct drm_client_dev *client);
|
||||
int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
|
||||
|
@ -463,14 +463,38 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
||||
const u32 *formats,
|
||||
unsigned int num_formats);
|
||||
|
||||
/**
|
||||
* struct drm_connector_tv_margins - TV connector related margins
|
||||
*
|
||||
* Describes the margins in pixels to put around the image on TV
|
||||
* connectors to deal with overscan.
|
||||
*/
|
||||
struct drm_connector_tv_margins {
|
||||
/**
|
||||
* @bottom: Bottom margin in pixels.
|
||||
*/
|
||||
unsigned int bottom;
|
||||
|
||||
/**
|
||||
* @left: Left margin in pixels.
|
||||
*/
|
||||
unsigned int left;
|
||||
|
||||
/**
|
||||
* @right: Right margin in pixels.
|
||||
*/
|
||||
unsigned int right;
|
||||
|
||||
/**
|
||||
* @top: Top margin in pixels.
|
||||
*/
|
||||
unsigned int top;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_tv_connector_state - TV connector related states
|
||||
* @subconnector: selected subconnector
|
||||
* @margins: margins (all margins are expressed in pixels)
|
||||
* @margins.left: left margin
|
||||
* @margins.right: right margin
|
||||
* @margins.top: top margin
|
||||
* @margins.bottom: bottom margin
|
||||
* @margins: TV margins
|
||||
* @mode: TV mode
|
||||
* @brightness: brightness in percent
|
||||
* @contrast: contrast in percent
|
||||
@ -481,12 +505,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
||||
*/
|
||||
struct drm_tv_connector_state {
|
||||
enum drm_mode_subconnector subconnector;
|
||||
struct {
|
||||
unsigned int left;
|
||||
unsigned int right;
|
||||
unsigned int top;
|
||||
unsigned int bottom;
|
||||
} margins;
|
||||
struct drm_connector_tv_margins margins;
|
||||
unsigned int mode;
|
||||
unsigned int brightness;
|
||||
unsigned int contrast;
|
||||
@ -923,19 +942,123 @@ struct drm_connector_funcs {
|
||||
const struct drm_connector_state *state);
|
||||
};
|
||||
|
||||
/* mode specified on the command line */
|
||||
/**
|
||||
* struct drm_cmdline_mode - DRM Mode passed through the kernel command-line
|
||||
*
|
||||
* Each connector can have an initial mode with additional options
|
||||
* passed through the kernel command line. This structure allows to
|
||||
* express those parameters and will be filled by the command-line
|
||||
* parser.
|
||||
*/
|
||||
struct drm_cmdline_mode {
|
||||
/**
|
||||
* @name:
|
||||
*
|
||||
* Name of the mode.
|
||||
*/
|
||||
char name[DRM_DISPLAY_MODE_LEN];
|
||||
|
||||
/**
|
||||
* @specified:
|
||||
*
|
||||
* Has a mode been read from the command-line?
|
||||
*/
|
||||
bool specified;
|
||||
|
||||
/**
|
||||
* @refresh_specified:
|
||||
*
|
||||
* Did the mode have a preferred refresh rate?
|
||||
*/
|
||||
bool refresh_specified;
|
||||
|
||||
/**
|
||||
* @bpp_specified:
|
||||
*
|
||||
* Did the mode have a preferred BPP?
|
||||
*/
|
||||
bool bpp_specified;
|
||||
int xres, yres;
|
||||
|
||||
/**
|
||||
* @xres:
|
||||
*
|
||||
* Active resolution on the X axis, in pixels.
|
||||
*/
|
||||
int xres;
|
||||
|
||||
/**
|
||||
* @yres:
|
||||
*
|
||||
* Active resolution on the Y axis, in pixels.
|
||||
*/
|
||||
int yres;
|
||||
|
||||
/**
|
||||
* @bpp:
|
||||
*
|
||||
* Bits per pixels for the mode.
|
||||
*/
|
||||
int bpp;
|
||||
|
||||
/**
|
||||
* @refresh:
|
||||
*
|
||||
* Refresh rate, in Hertz.
|
||||
*/
|
||||
int refresh;
|
||||
|
||||
/**
|
||||
* @rb:
|
||||
*
|
||||
* Do we need to use reduced blanking?
|
||||
*/
|
||||
bool rb;
|
||||
|
||||
/**
|
||||
* @interlace:
|
||||
*
|
||||
* The mode is interlaced.
|
||||
*/
|
||||
bool interlace;
|
||||
|
||||
/**
|
||||
* @cvt:
|
||||
*
|
||||
* The timings will be calculated using the VESA Coordinated
|
||||
* Video Timings instead of looking up the mode from a table.
|
||||
*/
|
||||
bool cvt;
|
||||
|
||||
/**
|
||||
* @margins:
|
||||
*
|
||||
* Add margins to the mode calculation (1.8% of xres rounded
|
||||
* down to 8 pixels and 1.8% of yres).
|
||||
*/
|
||||
bool margins;
|
||||
|
||||
/**
|
||||
* @force:
|
||||
*
|
||||
* Ignore the hotplug state of the connector, and force its
|
||||
* state to one of the DRM_FORCE_* values.
|
||||
*/
|
||||
enum drm_connector_force force;
|
||||
|
||||
/**
|
||||
* @rotation_reflection:
|
||||
*
|
||||
* Initial rotation and reflection of the mode setup from the
|
||||
* command line. See DRM_MODE_ROTATE_* and
|
||||
* DRM_MODE_REFLECT_*. The only rotations supported are
|
||||
* DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
|
||||
*/
|
||||
unsigned int rotation_reflection;
|
||||
|
||||
/**
|
||||
* @tv_margins: TV margins to apply to the mode.
|
||||
*/
|
||||
struct drm_connector_tv_margins tv_margins;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1414,6 +1414,13 @@ enum drm_dp_quirk {
|
||||
* driver still need to implement proper handling for such device.
|
||||
*/
|
||||
DP_DPCD_QUIRK_NO_PSR,
|
||||
/**
|
||||
* @DP_DPCD_QUIRK_NO_SINK_COUNT:
|
||||
*
|
||||
* The device does not set SINK_COUNT to a non-zero value.
|
||||
* The driver should ignore SINK_COUNT during detection.
|
||||
*/
|
||||
DP_DPCD_QUIRK_NO_SINK_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -401,9 +401,4 @@ int drm_gem_dumb_destroy(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
|
||||
int drm_gem_pin(struct drm_gem_object *obj);
|
||||
void drm_gem_unpin(struct drm_gem_object *obj);
|
||||
void *drm_gem_vmap(struct drm_gem_object *obj);
|
||||
void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
|
||||
#endif /* __DRM_GEM_H__ */
|
||||
|
@ -168,9 +168,6 @@ extern void vc_SAK(struct work_struct *work);
|
||||
|
||||
#define CUR_DEFAULT CUR_UNDERLINE
|
||||
|
||||
static inline bool con_is_visible(const struct vc_data *vc)
|
||||
{
|
||||
return *vc->vc_display_fg == vc;
|
||||
}
|
||||
bool con_is_visible(const struct vc_data *vc);
|
||||
|
||||
#endif /* _LINUX_CONSOLE_STRUCT_H */
|
||||
|
@ -280,10 +280,12 @@ struct dma_buf_ops {
|
||||
* @file: file pointer used for sharing buffers across, and for refcounting.
|
||||
* @attachments: list of dma_buf_attachment that denotes all devices attached.
|
||||
* @ops: dma_buf_ops associated with this buffer object.
|
||||
* @lock: used internally to serialize list manipulation, attach/detach and vmap/unmap
|
||||
* @lock: used internally to serialize list manipulation, attach/detach and
|
||||
* vmap/unmap, and accesses to name
|
||||
* @vmapping_counter: used internally to refcnt the vmaps
|
||||
* @vmap_ptr: the current vmap ptr if vmapping_counter > 0
|
||||
* @exp_name: name of the exporter; useful for debugging.
|
||||
* @name: userspace-provided name; useful for accounting and debugging.
|
||||
* @owner: pointer to exporter module; used for refcounting when exporter is a
|
||||
* kernel module.
|
||||
* @list_node: node for dma_buf accounting and debugging.
|
||||
@ -311,6 +313,7 @@ struct dma_buf {
|
||||
unsigned vmapping_counter;
|
||||
void *vmap_ptr;
|
||||
const char *exp_name;
|
||||
const char *name;
|
||||
struct module *owner;
|
||||
struct list_head list_node;
|
||||
void *priv;
|
||||
|
@ -126,39 +126,15 @@ struct fb_cursor_user {
|
||||
|
||||
/* The resolution of the passed in fb_info about to change */
|
||||
#define FB_EVENT_MODE_CHANGE 0x01
|
||||
/* The display on this fb_info is being suspended, no access to the
|
||||
* framebuffer is allowed any more after that call returns
|
||||
*/
|
||||
#define FB_EVENT_SUSPEND 0x02
|
||||
/* The display on this fb_info was resumed, you can restore the display
|
||||
* if you own it
|
||||
*/
|
||||
#define FB_EVENT_RESUME 0x03
|
||||
/* An entry from the modelist was removed */
|
||||
#define FB_EVENT_MODE_DELETE 0x04
|
||||
/* A driver registered itself */
|
||||
|
||||
#ifdef CONFIG_GUMSTIX_AM200EPD
|
||||
/* only used by mach-pxa/am200epd.c */
|
||||
#define FB_EVENT_FB_REGISTERED 0x05
|
||||
/* A driver unregistered itself */
|
||||
#define FB_EVENT_FB_UNREGISTERED 0x06
|
||||
/* CONSOLE-SPECIFIC: get console to framebuffer mapping */
|
||||
#define FB_EVENT_GET_CONSOLE_MAP 0x07
|
||||
/* CONSOLE-SPECIFIC: set console to framebuffer mapping */
|
||||
#define FB_EVENT_SET_CONSOLE_MAP 0x08
|
||||
/* A hardware display blank change occurred */
|
||||
#endif
|
||||
|
||||
/* A display blank is requested */
|
||||
#define FB_EVENT_BLANK 0x09
|
||||
/* Private modelist is to be replaced */
|
||||
#define FB_EVENT_NEW_MODELIST 0x0A
|
||||
/* The resolution of the passed in fb_info about to change and
|
||||
all vc's should be changed */
|
||||
#define FB_EVENT_MODE_CHANGE_ALL 0x0B
|
||||
/* A software display blank change occurred */
|
||||
#define FB_EVENT_CONBLANK 0x0C
|
||||
/* Get drawing requirements */
|
||||
#define FB_EVENT_GET_REQ 0x0D
|
||||
/* Unbind from the console if possible */
|
||||
#define FB_EVENT_FB_UNBIND 0x0E
|
||||
/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
|
||||
#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
|
||||
/* A hardware display blank early change occurred */
|
||||
#define FB_EARLY_EVENT_BLANK 0x10
|
||||
/* A hardware display blank revert early change occurred */
|
||||
@ -633,8 +609,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
|
||||
|
||||
/* drivers/video/fbmem.c */
|
||||
extern int register_framebuffer(struct fb_info *fb_info);
|
||||
extern int unregister_framebuffer(struct fb_info *fb_info);
|
||||
extern int unlink_framebuffer(struct fb_info *fb_info);
|
||||
extern void unregister_framebuffer(struct fb_info *fb_info);
|
||||
extern void unlink_framebuffer(struct fb_info *fb_info);
|
||||
extern int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id,
|
||||
const char *name);
|
||||
extern int remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
@ -660,7 +636,10 @@ extern struct class *fb_class;
|
||||
for (i = 0; i < FB_MAX; i++) \
|
||||
if (!registered_fb[i]) {} else
|
||||
|
||||
extern int lock_fb_info(struct fb_info *info);
|
||||
static inline void lock_fb_info(struct fb_info *info)
|
||||
{
|
||||
mutex_lock(&info->lock);
|
||||
}
|
||||
|
||||
static inline void unlock_fb_info(struct fb_info *info)
|
||||
{
|
||||
|
@ -4,9 +4,39 @@
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
|
||||
void __init fb_console_init(void);
|
||||
void __exit fb_console_exit(void);
|
||||
int fbcon_fb_registered(struct fb_info *info);
|
||||
void fbcon_fb_unregistered(struct fb_info *info);
|
||||
void fbcon_fb_unbind(struct fb_info *info);
|
||||
void fbcon_suspended(struct fb_info *info);
|
||||
void fbcon_resumed(struct fb_info *info);
|
||||
int fbcon_mode_deleted(struct fb_info *info,
|
||||
struct fb_videomode *mode);
|
||||
void fbcon_new_modelist(struct fb_info *info);
|
||||
void fbcon_get_requirement(struct fb_info *info,
|
||||
struct fb_blit_caps *caps);
|
||||
void fbcon_fb_blanked(struct fb_info *info, int blank);
|
||||
void fbcon_update_vcs(struct fb_info *info, bool all);
|
||||
void fbcon_remap_all(struct fb_info *info);
|
||||
int fbcon_set_con2fb_map_ioctl(void __user *argp);
|
||||
int fbcon_get_con2fb_map_ioctl(void __user *argp);
|
||||
#else
|
||||
static inline void fb_console_init(void) {}
|
||||
static inline void fb_console_exit(void) {}
|
||||
static inline int fbcon_fb_registered(struct fb_info *info) { return 0; }
|
||||
static inline void fbcon_fb_unregistered(struct fb_info *info) {}
|
||||
static inline void fbcon_fb_unbind(struct fb_info *info) {}
|
||||
static inline void fbcon_suspended(struct fb_info *info) {}
|
||||
static inline void fbcon_resumed(struct fb_info *info) {}
|
||||
static inline int fbcon_mode_deleted(struct fb_info *info,
|
||||
struct fb_videomode *mode) { return 0; }
|
||||
static inline void fbcon_new_modelist(struct fb_info *info) {}
|
||||
static inline void fbcon_get_requirement(struct fb_info *info,
|
||||
struct fb_blit_caps *caps) {}
|
||||
static inline void fbcon_fb_blanked(struct fb_info *info, int blank) {}
|
||||
static inline void fbcon_update_vcs(struct fb_info *info, bool all) {}
|
||||
static inline void fbcon_remap_all(struct fb_info *info) {}
|
||||
static inline int fbcon_set_con2fb_map_ioctl(void __user *argp) { return 0; }
|
||||
static inline int fbcon_get_con2fb_map_ioctl(void __user *argp) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_FBCON_H */
|
||||
|
@ -18,6 +18,8 @@ extern "C" {
|
||||
#define DRM_PANFROST_MMAP_BO 0x03
|
||||
#define DRM_PANFROST_GET_PARAM 0x04
|
||||
#define DRM_PANFROST_GET_BO_OFFSET 0x05
|
||||
#define DRM_PANFROST_PERFCNT_ENABLE 0x06
|
||||
#define DRM_PANFROST_PERFCNT_DUMP 0x07
|
||||
|
||||
#define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit)
|
||||
#define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo)
|
||||
@ -26,6 +28,15 @@ extern "C" {
|
||||
#define DRM_IOCTL_PANFROST_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_PARAM, struct drm_panfrost_get_param)
|
||||
#define DRM_IOCTL_PANFROST_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_BO_OFFSET, struct drm_panfrost_get_bo_offset)
|
||||
|
||||
/*
|
||||
* Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module
|
||||
* param is set to true.
|
||||
* All these ioctl(s) are subject to deprecation, so please don't rely on
|
||||
* them for anything but debugging purpose.
|
||||
*/
|
||||
#define DRM_IOCTL_PANFROST_PERFCNT_ENABLE DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_ENABLE, struct drm_panfrost_perfcnt_enable)
|
||||
#define DRM_IOCTL_PANFROST_PERFCNT_DUMP DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_DUMP, struct drm_panfrost_perfcnt_dump)
|
||||
|
||||
#define PANFROST_JD_REQ_FS (1 << 0)
|
||||
/**
|
||||
* struct drm_panfrost_submit - ioctl argument for submitting commands to the 3D
|
||||
@ -135,6 +146,19 @@ struct drm_panfrost_get_bo_offset {
|
||||
__u64 offset;
|
||||
};
|
||||
|
||||
struct drm_panfrost_perfcnt_enable {
|
||||
__u32 enable;
|
||||
/*
|
||||
* On bifrost we have 2 sets of counters, this parameter defines the
|
||||
* one to track.
|
||||
*/
|
||||
__u32 counterset;
|
||||
};
|
||||
|
||||
struct drm_panfrost_perfcnt_dump {
|
||||
__u64 buf_ptr;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
@ -35,7 +35,10 @@ struct dma_buf_sync {
|
||||
#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
|
||||
(DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
|
||||
|
||||
#define DMA_BUF_NAME_LEN 32
|
||||
|
||||
#define DMA_BUF_BASE 'b'
|
||||
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
|
||||
#define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 1, const char *)
|
||||
|
||||
#endif
|
||||
|
@ -91,5 +91,6 @@
|
||||
#define UDF_SUPER_MAGIC 0x15013346
|
||||
#define BALLOON_KVM_MAGIC 0x13661366
|
||||
#define ZSMALLOC_MAGIC 0x58295829
|
||||
#define DMA_BUF_MAGIC 0x444d4142 /* "DMAB" */
|
||||
|
||||
#endif /* __LINUX_MAGIC_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user