drm: mali-dp: Check hw version matches device-tree
authorMihail Atanassov <mihail.atanassov@arm.com>
Mon, 23 Jan 2017 13:46:41 +0000 (13:46 +0000)
committerLiviu Dudau <Liviu.Dudau@arm.com>
Thu, 26 Jan 2017 15:46:02 +0000 (15:46 +0000)
Refuse to bind if the device-tree compatible string
lists a different hardware version.

Reviewed-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
drivers/gpu/drm/arm/malidp_drv.c
drivers/gpu/drm/arm/malidp_regs.h

index 080f7631c672b2fb01c3b74d04dafff3ff70a177..6e59b3effb97c84634c7cf6fb490c06a0536c0a5 100644 (file)
@@ -255,6 +255,46 @@ static const struct of_device_id  malidp_drm_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, malidp_drm_of_match);
 
+static bool malidp_is_compatible_hw_id(struct malidp_hw_device *hwdev,
+                                      const struct of_device_id *dev_id)
+{
+       u32 core_id;
+       const char *compatstr_dp500 = "arm,mali-dp500";
+       bool is_dp500;
+       bool dt_is_dp500;
+
+       /*
+        * The DP500 CORE_ID register is in a different location, so check it
+        * first. If the product id field matches, then this is DP500, otherwise
+        * check the DP550/650 CORE_ID register.
+        */
+       core_id = malidp_hw_read(hwdev, MALIDP500_DC_BASE + MALIDP_DE_CORE_ID);
+       /* Offset 0x18 will never read 0x500 on products other than DP500. */
+       is_dp500 = (MALIDP_PRODUCT_ID(core_id) == 0x500);
+       dt_is_dp500 = strnstr(dev_id->compatible, compatstr_dp500,
+                             sizeof(dev_id->compatible)) != NULL;
+       if (is_dp500 != dt_is_dp500) {
+               DRM_ERROR("Device-tree expects %s, but hardware %s DP500.\n",
+                         dev_id->compatible, is_dp500 ? "is" : "is not");
+               return false;
+       } else if (!dt_is_dp500) {
+               u16 product_id;
+               char buf[32];
+
+               core_id = malidp_hw_read(hwdev,
+                                        MALIDP550_DC_BASE + MALIDP_DE_CORE_ID);
+               product_id = MALIDP_PRODUCT_ID(core_id);
+               snprintf(buf, sizeof(buf), "arm,mali-dp%X", product_id);
+               if (!strnstr(dev_id->compatible, buf,
+                            sizeof(dev_id->compatible))) {
+                       DRM_ERROR("Device-tree expects %s, but hardware is DP%03X.\n",
+                                 dev_id->compatible, product_id);
+                       return false;
+               }
+       }
+       return true;
+}
+
 #define MAX_OUTPUT_CHANNELS    3
 
 static int malidp_bind(struct device *dev)
@@ -265,6 +305,7 @@ static int malidp_bind(struct device *dev)
        struct malidp_drm *malidp;
        struct malidp_hw_device *hwdev;
        struct platform_device *pdev = to_platform_device(dev);
+       struct of_device_id const *dev_id;
        /* number of lines for the R, G and B output */
        u8 output_width[MAX_OUTPUT_CHANNELS];
        int ret = 0, i;
@@ -327,6 +368,17 @@ static int malidp_bind(struct device *dev)
        clk_prepare_enable(hwdev->aclk);
        clk_prepare_enable(hwdev->mclk);
 
+       dev_id = of_match_device(malidp_drm_of_match, dev);
+       if (!dev_id) {
+               ret = -EINVAL;
+               goto query_hw_fail;
+       }
+
+       if (!malidp_is_compatible_hw_id(hwdev, dev_id)) {
+               ret = -EINVAL;
+               goto query_hw_fail;
+       }
+
        ret = hwdev->query_hw(hwdev);
        if (ret) {
                DRM_ERROR("Invalid HW configuration\n");
index 73fecb38f9550b6cf7aa1e91cd310395ebf719ea..7a89997dd134962be173d750fc5756a07a2dc97d 100644 (file)
@@ -92,6 +92,8 @@
 #define MALIDP_DE_H_ACTIVE(x)          (((x) & 0x1fff) << 0)
 #define MALIDP_DE_V_ACTIVE(x)          (((x) & 0x1fff) << 16)
 
+#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16)
+
 /* register offsets and bits specific to DP500 */
 #define MALIDP500_DC_BASE              0x00000
 #define MALIDP500_DC_CONTROL           0x0000c