Merge remote-tracking branch 'drm/drm-next' into drm-misc-next
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Wed, 19 Jun 2019 10:32:13 +0000 (12:32 +0200)
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Wed, 19 Jun 2019 10:32:13 +0000 (12:32 +0200)
remove-fbcon-notifiers topic branch is based on rc4, so we need a fresh
backmerge of drm-next to pull it in.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
47 files changed:
Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
Documentation/fb/modedb.txt
Documentation/gpu/todo.rst
drivers/dma-buf/dma-buf.c
drivers/gpu/drm/drm_atomic_state_helper.c
drivers/gpu/drm/drm_client_modeset.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_internal.h
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_vblank.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/panfrost/Makefile
drivers/gpu/drm/panfrost/panfrost_device.c
drivers/gpu/drm/panfrost/panfrost_device.h
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/panfrost/panfrost_gem.c
drivers/gpu/drm/panfrost/panfrost_gpu.c
drivers/gpu/drm/panfrost/panfrost_perfcnt.c [new file with mode: 0644]
drivers/gpu/drm/panfrost/panfrost_perfcnt.h [new file with mode: 0644]
drivers/gpu/drm/panfrost/panfrost_regs.h
drivers/gpu/drm/rcar-du/rcar_lvds.c
drivers/gpu/drm/rockchip/cdn-dp-reg.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/selftests/Makefile
drivers/gpu/drm/selftests/drm_cmdline_selftests.h [new file with mode: 0644]
drivers/gpu/drm/selftests/test-drm_cmdline_parser.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/vc4/vc4_debugfs.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vkms/vkms_crc.c
drivers/gpu/drm/vkms/vkms_crtc.c
drivers/gpu/drm/vkms/vkms_drv.h
drivers/gpu/drm/vkms/vkms_plane.c
include/drm/drm_atomic_state_helper.h
include/drm/drm_client.h
include/drm/drm_connector.h
include/drm/drm_dp_helper.h
include/drm/drm_gem.h
include/linux/dma-buf.h
include/uapi/drm/panfrost_drm.h
include/uapi/linux/dma-buf.h
include/uapi/linux/magic.h

index 8346bac81f1c2b75427a97ba61fed7757c14a879..3d32ce137e7f40883426e1b9a3e3db29eddd2527 100644 (file)
@@ -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"
index 16aa08453911cba57f0616f5a472e9c6ecc5e14e..1dd5a52f9390fe85dfeae72c2722fc3759939799 100644 (file)
@@ -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)?
index b4a76c2703e58b5d470f1f6d802e875b36fe7984..23583f0e3755e9211ae4ca3f582edae57ce28b59 100644 (file)
@@ -228,6 +228,10 @@ 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.
 
+Unfortunately some of the recently added GEM helpers are going in the wrong
+direction by adding OPS macros that use the old, deprecated hooks. See
+DRM_GEM_CMA_VMAP_DRIVER_OPS, DRM_GEM_SHMEM_DRIVER_OPS, and DRM_GEM_VRAM_DRIVER_PRIME.
+
 Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate
 ---------------------------------------------------------
 
index f4104a21b06907ebdb13a3b768e640f0f5ee0b79..6c15deb5d4ad8b60212826ea0487fdac12da9cb9 100644 (file)
 #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);
index 7d7347a6f19433a5a239a8e73111c28ec6cc7f9a..46dc264a248bf6d273b03c4b8db2a69b17539419 100644 (file)
@@ -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
index 006bf7390e7df828c972c2629fc2ba3964937010..e95fceac8f8bf38d3f837b636cd05bf0e41d2cac 100644 (file)
@@ -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;
index 3ccdcf3dfcde27c0ee5b5d8b70a4d2af0ee8ca44..3afed5677946689758acafd640ef65ec7985f035 100644 (file)
@@ -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" : "",
index 63b9951bb8f3852cae7858d28849484d8579d504..eab0f2687cd6ea31c757eacb2ee4cf88974ee636 100644 (file)
@@ -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);
 
index e6af758a7d22426f5eaadabec19f334158da3906..0b994d083a8903580999f381ebf740e516db4162 100644 (file)
@@ -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
index 42852cae749b60622bee9bf864a10bef00dbbfb6..1984e5c54d580504fb3417d50afca9e1dd6aa105 100644 (file)
@@ -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
index 8a55f71325b1b3444953748146d8548e544b7b38..a8c4468f03d9166bd257f2bde65cbfbc7fe05ee5 100644 (file)
@@ -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
index d18c7b91a1a834c92581d5db6bec3f07c58ff71a..51a2055c8f18af96763f02a60406d9362ce4e9de 100644 (file)
@@ -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,
index 5a07a28fec6dd7fc8f9b9254a83642f700e7c488..57e6408288c80f6adb86c2b29b23a1b0e1829627 100644 (file)
@@ -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;
+       /* 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;
+       }
 
-                       force = DRM_FORCE_OFF;
-                       break;
-               default:
-                       goto done;
-               }
+       refresh_ptr = strchr(name, '@');
+       if (refresh_ptr) {
+               if (named_mode)
+                       return false;
+
+               refresh_off = refresh_ptr - name;
+               mode->refresh_specified = true;
        }
 
-       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;
+       /* 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;
        }
-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 (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 (res_specified) {
-               mode->specified = true;
-               mode->xres = xres;
-               mode->yres = yres;
+       if (bpp_ptr) {
+               ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
+               if (ret)
+                       return false;
        }
 
-       if (refresh_specified) {
-               mode->refresh_specified = true;
-               mode->refresh = refresh;
+       if (refresh_ptr) {
+               ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
+                                                    &refresh_end_ptr, mode);
+               if (ret)
+                       return false;
        }
 
-       if (bpp_specified) {
-               mode->bpp_specified = true;
-               mode->bpp = bpp;
+       /*
+        * 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;
        }
-       mode->rb = rb;
-       mode->cvt = cvt;
-       mode->interlace = interlace;
-       mode->margins = margins;
-       mode->force = force;
 
        return true;
 }
index 0d704bddb1a672f2679d6706577b5480ce41c856..603ab105125d4112aada8f72bb79a9b766f38c38 100644 (file)
@@ -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;
index 2f24ee6c7a92dfcef2c25d155bb1b8cd1840f23a..05f7c5833946dc551f655dde0eff142e50e6a05b 100644 (file)
@@ -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;
index 6de72d13c58f8b4afc8f9df0e87893327a539473..ecf0864cb515c2208faebdd0d0747c796625bf24 100644 (file)
@@ -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
index ccb8eb2a518ca6d544d108389c91cf02719146dd..8a111d7c0200b1fab2ed64ef0d9a93f7e525e67e 100644 (file)
@@ -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);
index 8074f221034bc1b42aab4ce2a288ea155013f23b..83cc01cafde1be5ea593202dd408d5ebad7ccf3d 100644 (file)
@@ -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);
 
index d11e2281dde625d57fd7f544b6bd55481a6baeee..e34e86a7378a1e3d469955724613e94bc1d4bf36 100644 (file)
 #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);
index a5528a360ef4f9ccef03dd5ebe6365594d59fd01..886875ae31d3253d4c93be5a41ce4d26cb10923f 100644 (file)
@@ -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;
index 58ef25573cda3a2d2f149a4520b79853b735af08..20ab333fc92529099a81601b21753860e8196db7 100644 (file)
 #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;
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
new file mode 100644 (file)
index 0000000..83c57d3
--- /dev/null
@@ -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);
+}
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.h b/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
new file mode 100644 (file)
index 0000000..13b8fda
--- /dev/null
@@ -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
index 578c5fc2188b63ced8633a4c36ffee70ab625243..ea38ac60581c6a93234b03de13dff15ac4d8ed59 100644 (file)
         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 */
 #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
index f2a5d4d997073ac46f0978645f65ae5e864bfbb4..1c62578590f462fbc4ab8fb1e102c6bfef57b8f5 100644 (file)
@@ -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)
index 66b2d4466eabc18d7cbaeac5af0beffc0a4e30b3..077c870219081afc4954bea1589c0e54e3539c12 100644 (file)
@@ -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)
index 40f3a4c538483547fd10d60f1200d8bd96be411c..cdc304d4cd02b1edcfd310e19da12b5b150f0b2f 100644 (file)
 #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
        },
index e4580d8f21e1e858e43ff3d9e1f51d6607622889..09a790c2f3a1ead32cd7360b645eca62a1d2f1a0 100644 (file)
@@ -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;
 }
index 8ec64ecf0e36a33dddce09ceb22539b623d417cf..aae88f8a016c20bc21ac6e30ef8d861a78e7f182 100644 (file)
@@ -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
diff --git a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
new file mode 100644 (file)
index 0000000..b45824e
--- /dev/null
@@ -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)
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
new file mode 100644 (file)
index 0000000..bef4edd
--- /dev/null
@@ -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");
index 895d77d799e4fd9aad3f8715ae4c10f1fe5a7c75..9f918b992f7e33a6c3276e335f313ba41751f0ef 100644 (file)
@@ -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;
index f9dec08267dc7a7e8957aca514388c50633b7f9d..f9b46911fa50c5096a59c3bf1d66f02dc89db349 100644 (file)
@@ -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,
index 99fc8569e0f5285d188cb481845905a759ba713a..43442c5619a3cb9ab0b702eadc5d90387a7243be 100644 (file)
@@ -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,
 };
index d7b409a3c0f8cfd5fcd20a7e628e5a8aafd2d3fe..e66ff25c008e6c10e3de7b9294a607e7efbb1015 100644 (file)
@@ -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;
index 1bbe099b7db812577161c2f23ae265aca009b707..4d11292bc6f386ee76d28f30cf8a665d8f5ffa50 100644 (file)
@@ -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,
 };
index 81f1cfbeb9362e4edc9a39f1688060d1d23124c0..b92c30c66a6f24a23591f6bc7eb43c283ef91fd1 100644 (file)
 
 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);
index 0e67d2d42f0cc4014fe88b263237fa347af07116..0fceb625842254ce4d288eb0b0a3ad15baabd017 100644 (file)
@@ -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)
 {
index 4e6d2e7a40b8ea38891317c764df1b4133608b5f..e4577cc116894db2b6c7982d0b2d51e13e1962e7 100644 (file)
@@ -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);
index f2d5ed74573383200a71d447a549013d40ce624a..72d51d1e9dd9ea33ea83b7c6fcdbdc0cc1f250ef 100644 (file)
@@ -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);
index c6f8486d8b8f37bfe9b221d459102d3368e36d4b..ca745d9feaf541949b44126408b0cc9626158fbf 100644 (file)
@@ -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;
 };
 
 /**
index 3fc534ee817468fb6ec99dc4574d04a61ba18a90..7e52eb81284ad07c38aef4fcb5d49a9643cf851e 100644 (file)
@@ -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,
 };
 
 /**
index 5047c7ee25f53519193ef11081ad56def08c6654..a9121fe66ea227c4ab01fef54213179fdefc1a48 100644 (file)
@@ -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__ */
index 8a327566d7f4e0d21fb6be1f903d237b07676786..01ad5b942a6f329298d84a4f1d1a24846667a8a1 100644 (file)
@@ -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;
index a52e0283b90d5711aa2e9b174ae4e69cdf7d480f..b5d3706388463c10f924eeff915786a5486dfdde 100644 (file)
@@ -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
index d75df5210a4a597b844f20ab8bcca2da7ddf227b..dbc7092e04b5a46afa54a80b45e227d5a20dfc05 100644 (file)
@@ -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
index f8c00045d537e4b810a768ace70211d0bc0e3686..665e18627f78ca9bb4e744f07a6a0e6b74190469 100644 (file)
@@ -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__ */