diff options
Diffstat (limited to 'drivers/gpu')
41 files changed, 699 insertions, 230 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 792c3e3795ca..dd64a06dc5b4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -2326,7 +2326,6 @@ int drm_mode_addfb(struct drm_device *dev, | |||
| 2326 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); | 2326 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); |
| 2327 | if (IS_ERR(fb)) { | 2327 | if (IS_ERR(fb)) { |
| 2328 | DRM_DEBUG_KMS("could not create framebuffer\n"); | 2328 | DRM_DEBUG_KMS("could not create framebuffer\n"); |
| 2329 | drm_modeset_unlock_all(dev); | ||
| 2330 | return PTR_ERR(fb); | 2329 | return PTR_ERR(fb); |
| 2331 | } | 2330 | } |
| 2332 | 2331 | ||
| @@ -2506,7 +2505,6 @@ int drm_mode_addfb2(struct drm_device *dev, | |||
| 2506 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); | 2505 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); |
| 2507 | if (IS_ERR(fb)) { | 2506 | if (IS_ERR(fb)) { |
| 2508 | DRM_DEBUG_KMS("could not create framebuffer\n"); | 2507 | DRM_DEBUG_KMS("could not create framebuffer\n"); |
| 2509 | drm_modeset_unlock_all(dev); | ||
| 2510 | return PTR_ERR(fb); | 2508 | return PTR_ERR(fb); |
| 2511 | } | 2509 | } |
| 2512 | 2510 | ||
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c194f4e680ad..e2acfdbf7d3c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -1634,7 +1634,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | |||
| 1634 | unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; | 1634 | unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; |
| 1635 | unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo; | 1635 | unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo; |
| 1636 | unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo; | 1636 | unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo; |
| 1637 | unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; | 1637 | unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 2 | pt->vsync_offset_pulse_width_lo >> 4; |
| 1638 | unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf); | 1638 | unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf); |
| 1639 | 1639 | ||
| 1640 | /* ignore tiny modes */ | 1640 | /* ignore tiny modes */ |
| @@ -1715,6 +1715,7 @@ set_size: | |||
| 1715 | } | 1715 | } |
| 1716 | 1716 | ||
| 1717 | mode->type = DRM_MODE_TYPE_DRIVER; | 1717 | mode->type = DRM_MODE_TYPE_DRIVER; |
| 1718 | mode->vrefresh = drm_mode_vrefresh(mode); | ||
| 1718 | drm_mode_set_name(mode); | 1719 | drm_mode_set_name(mode); |
| 1719 | 1720 | ||
| 1720 | return mode; | 1721 | return mode; |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 59d6b9bf204b..892ff9f95975 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
| @@ -1544,10 +1544,10 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |||
| 1544 | if (!fb_helper->fb) | 1544 | if (!fb_helper->fb) |
| 1545 | return 0; | 1545 | return 0; |
| 1546 | 1546 | ||
| 1547 | drm_modeset_lock_all(dev); | 1547 | mutex_lock(&fb_helper->dev->mode_config.mutex); |
| 1548 | if (!drm_fb_helper_is_bound(fb_helper)) { | 1548 | if (!drm_fb_helper_is_bound(fb_helper)) { |
| 1549 | fb_helper->delayed_hotplug = true; | 1549 | fb_helper->delayed_hotplug = true; |
| 1550 | drm_modeset_unlock_all(dev); | 1550 | mutex_unlock(&fb_helper->dev->mode_config.mutex); |
| 1551 | return 0; | 1551 | return 0; |
| 1552 | } | 1552 | } |
| 1553 | DRM_DEBUG_KMS("\n"); | 1553 | DRM_DEBUG_KMS("\n"); |
| @@ -1558,9 +1558,11 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |||
| 1558 | 1558 | ||
| 1559 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, | 1559 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, |
| 1560 | max_height); | 1560 | max_height); |
| 1561 | mutex_unlock(&fb_helper->dev->mode_config.mutex); | ||
| 1562 | |||
| 1563 | drm_modeset_lock_all(dev); | ||
| 1561 | drm_setup_crtcs(fb_helper); | 1564 | drm_setup_crtcs(fb_helper); |
| 1562 | drm_modeset_unlock_all(dev); | 1565 | drm_modeset_unlock_all(dev); |
| 1563 | |||
| 1564 | drm_fb_helper_set_par(fb_helper->fbdev); | 1566 | drm_fb_helper_set_par(fb_helper->fbdev); |
| 1565 | 1567 | ||
| 1566 | return 0; | 1568 | return 0; |
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 13fdcd10a605..429e07d0b0f1 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
| @@ -123,6 +123,7 @@ int drm_open(struct inode *inode, struct file *filp) | |||
| 123 | int retcode = 0; | 123 | int retcode = 0; |
| 124 | int need_setup = 0; | 124 | int need_setup = 0; |
| 125 | struct address_space *old_mapping; | 125 | struct address_space *old_mapping; |
| 126 | struct address_space *old_imapping; | ||
| 126 | 127 | ||
| 127 | minor = idr_find(&drm_minors_idr, minor_id); | 128 | minor = idr_find(&drm_minors_idr, minor_id); |
| 128 | if (!minor) | 129 | if (!minor) |
| @@ -137,6 +138,7 @@ int drm_open(struct inode *inode, struct file *filp) | |||
| 137 | if (!dev->open_count++) | 138 | if (!dev->open_count++) |
| 138 | need_setup = 1; | 139 | need_setup = 1; |
| 139 | mutex_lock(&dev->struct_mutex); | 140 | mutex_lock(&dev->struct_mutex); |
| 141 | old_imapping = inode->i_mapping; | ||
| 140 | old_mapping = dev->dev_mapping; | 142 | old_mapping = dev->dev_mapping; |
| 141 | if (old_mapping == NULL) | 143 | if (old_mapping == NULL) |
| 142 | dev->dev_mapping = &inode->i_data; | 144 | dev->dev_mapping = &inode->i_data; |
| @@ -159,8 +161,8 @@ int drm_open(struct inode *inode, struct file *filp) | |||
| 159 | 161 | ||
| 160 | err_undo: | 162 | err_undo: |
| 161 | mutex_lock(&dev->struct_mutex); | 163 | mutex_lock(&dev->struct_mutex); |
| 162 | filp->f_mapping = old_mapping; | 164 | filp->f_mapping = old_imapping; |
| 163 | inode->i_mapping = old_mapping; | 165 | inode->i_mapping = old_imapping; |
| 164 | iput(container_of(dev->dev_mapping, struct inode, i_data)); | 166 | iput(container_of(dev->dev_mapping, struct inode, i_data)); |
| 165 | dev->dev_mapping = old_mapping; | 167 | dev->dev_mapping = old_mapping; |
| 166 | mutex_unlock(&dev->struct_mutex); | 168 | mutex_unlock(&dev->struct_mutex); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 36493ce71f9a..98cc14725ba9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
| @@ -38,11 +38,12 @@ | |||
| 38 | /* position control register for hardware window 0, 2 ~ 4.*/ | 38 | /* position control register for hardware window 0, 2 ~ 4.*/ |
| 39 | #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) | 39 | #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) |
| 40 | #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) | 40 | #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) |
| 41 | /* size control register for hardware window 0. */ | 41 | /* |
| 42 | #define VIDOSD_C_SIZE_W0 (VIDOSD_BASE + 0x08) | 42 | * size control register for hardware windows 0 and alpha control register |
| 43 | /* alpha control register for hardware window 1 ~ 4. */ | 43 | * for hardware windows 1 ~ 4 |
| 44 | #define VIDOSD_C(win) (VIDOSD_BASE + 0x18 + (win) * 16) | 44 | */ |
| 45 | /* size control register for hardware window 1 ~ 4. */ | 45 | #define VIDOSD_C(win) (VIDOSD_BASE + 0x08 + (win) * 16) |
| 46 | /* size control register for hardware windows 1 ~ 2. */ | ||
| 46 | #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) | 47 | #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) |
| 47 | 48 | ||
| 48 | #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) | 49 | #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) |
| @@ -50,9 +51,9 @@ | |||
| 50 | #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) | 51 | #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) |
| 51 | 52 | ||
| 52 | /* color key control register for hardware window 1 ~ 4. */ | 53 | /* color key control register for hardware window 1 ~ 4. */ |
| 53 | #define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + (x * 8)) | 54 | #define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + ((x - 1) * 8)) |
| 54 | /* color key value register for hardware window 1 ~ 4. */ | 55 | /* color key value register for hardware window 1 ~ 4. */ |
| 55 | #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + (x * 8)) | 56 | #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) |
| 56 | 57 | ||
| 57 | /* FIMD has totally five hardware windows. */ | 58 | /* FIMD has totally five hardware windows. */ |
| 58 | #define WINDOWS_NR 5 | 59 | #define WINDOWS_NR 5 |
| @@ -109,9 +110,9 @@ struct fimd_context { | |||
| 109 | 110 | ||
| 110 | #ifdef CONFIG_OF | 111 | #ifdef CONFIG_OF |
| 111 | static const struct of_device_id fimd_driver_dt_match[] = { | 112 | static const struct of_device_id fimd_driver_dt_match[] = { |
| 112 | { .compatible = "samsung,exynos4-fimd", | 113 | { .compatible = "samsung,exynos4210-fimd", |
| 113 | .data = &exynos4_fimd_driver_data }, | 114 | .data = &exynos4_fimd_driver_data }, |
| 114 | { .compatible = "samsung,exynos5-fimd", | 115 | { .compatible = "samsung,exynos5250-fimd", |
| 115 | .data = &exynos5_fimd_driver_data }, | 116 | .data = &exynos5_fimd_driver_data }, |
| 116 | {}, | 117 | {}, |
| 117 | }; | 118 | }; |
| @@ -581,7 +582,7 @@ static void fimd_win_commit(struct device *dev, int zpos) | |||
| 581 | if (win != 3 && win != 4) { | 582 | if (win != 3 && win != 4) { |
| 582 | u32 offset = VIDOSD_D(win); | 583 | u32 offset = VIDOSD_D(win); |
| 583 | if (win == 0) | 584 | if (win == 0) |
| 584 | offset = VIDOSD_C_SIZE_W0; | 585 | offset = VIDOSD_C(win); |
| 585 | val = win_data->ovl_width * win_data->ovl_height; | 586 | val = win_data->ovl_width * win_data->ovl_height; |
| 586 | writel(val, ctx->regs + offset); | 587 | writel(val, ctx->regs + offset); |
| 587 | 588 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 3b0da0378acf..47a493c8a71f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
| @@ -48,8 +48,14 @@ | |||
| 48 | 48 | ||
| 49 | /* registers for base address */ | 49 | /* registers for base address */ |
| 50 | #define G2D_SRC_BASE_ADDR 0x0304 | 50 | #define G2D_SRC_BASE_ADDR 0x0304 |
| 51 | #define G2D_SRC_COLOR_MODE 0x030C | ||
| 52 | #define G2D_SRC_LEFT_TOP 0x0310 | ||
| 53 | #define G2D_SRC_RIGHT_BOTTOM 0x0314 | ||
| 51 | #define G2D_SRC_PLANE2_BASE_ADDR 0x0318 | 54 | #define G2D_SRC_PLANE2_BASE_ADDR 0x0318 |
| 52 | #define G2D_DST_BASE_ADDR 0x0404 | 55 | #define G2D_DST_BASE_ADDR 0x0404 |
| 56 | #define G2D_DST_COLOR_MODE 0x040C | ||
| 57 | #define G2D_DST_LEFT_TOP 0x0410 | ||
| 58 | #define G2D_DST_RIGHT_BOTTOM 0x0414 | ||
| 53 | #define G2D_DST_PLANE2_BASE_ADDR 0x0418 | 59 | #define G2D_DST_PLANE2_BASE_ADDR 0x0418 |
| 54 | #define G2D_PAT_BASE_ADDR 0x0500 | 60 | #define G2D_PAT_BASE_ADDR 0x0500 |
| 55 | #define G2D_MSK_BASE_ADDR 0x0520 | 61 | #define G2D_MSK_BASE_ADDR 0x0520 |
| @@ -82,7 +88,7 @@ | |||
| 82 | #define G2D_DMA_LIST_DONE_COUNT_OFFSET 17 | 88 | #define G2D_DMA_LIST_DONE_COUNT_OFFSET 17 |
| 83 | 89 | ||
| 84 | /* G2D_DMA_HOLD_CMD */ | 90 | /* G2D_DMA_HOLD_CMD */ |
| 85 | #define G2D_USET_HOLD (1 << 2) | 91 | #define G2D_USER_HOLD (1 << 2) |
| 86 | #define G2D_LIST_HOLD (1 << 1) | 92 | #define G2D_LIST_HOLD (1 << 1) |
| 87 | #define G2D_BITBLT_HOLD (1 << 0) | 93 | #define G2D_BITBLT_HOLD (1 << 0) |
| 88 | 94 | ||
| @@ -91,13 +97,27 @@ | |||
| 91 | #define G2D_START_NHOLT (1 << 1) | 97 | #define G2D_START_NHOLT (1 << 1) |
| 92 | #define G2D_START_BITBLT (1 << 0) | 98 | #define G2D_START_BITBLT (1 << 0) |
| 93 | 99 | ||
| 100 | /* buffer color format */ | ||
| 101 | #define G2D_FMT_XRGB8888 0 | ||
| 102 | #define G2D_FMT_ARGB8888 1 | ||
| 103 | #define G2D_FMT_RGB565 2 | ||
| 104 | #define G2D_FMT_XRGB1555 3 | ||
| 105 | #define G2D_FMT_ARGB1555 4 | ||
| 106 | #define G2D_FMT_XRGB4444 5 | ||
| 107 | #define G2D_FMT_ARGB4444 6 | ||
| 108 | #define G2D_FMT_PACKED_RGB888 7 | ||
| 109 | #define G2D_FMT_A8 11 | ||
| 110 | #define G2D_FMT_L8 12 | ||
| 111 | |||
| 112 | /* buffer valid length */ | ||
| 113 | #define G2D_LEN_MIN 1 | ||
| 114 | #define G2D_LEN_MAX 8000 | ||
| 115 | |||
| 94 | #define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) | 116 | #define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) |
| 95 | #define G2D_CMDLIST_NUM 64 | 117 | #define G2D_CMDLIST_NUM 64 |
| 96 | #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) | 118 | #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) |
| 97 | #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) | 119 | #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) |
| 98 | 120 | ||
| 99 | #define MAX_BUF_ADDR_NR 6 | ||
| 100 | |||
| 101 | /* maximum buffer pool size of userptr is 64MB as default */ | 121 | /* maximum buffer pool size of userptr is 64MB as default */ |
| 102 | #define MAX_POOL (64 * 1024 * 1024) | 122 | #define MAX_POOL (64 * 1024 * 1024) |
| 103 | 123 | ||
| @@ -106,6 +126,17 @@ enum { | |||
| 106 | BUF_TYPE_USERPTR, | 126 | BUF_TYPE_USERPTR, |
| 107 | }; | 127 | }; |
| 108 | 128 | ||
| 129 | enum g2d_reg_type { | ||
| 130 | REG_TYPE_NONE = -1, | ||
| 131 | REG_TYPE_SRC, | ||
| 132 | REG_TYPE_SRC_PLANE2, | ||
| 133 | REG_TYPE_DST, | ||
| 134 | REG_TYPE_DST_PLANE2, | ||
| 135 | REG_TYPE_PAT, | ||
| 136 | REG_TYPE_MSK, | ||
| 137 | MAX_REG_TYPE_NR | ||
| 138 | }; | ||
| 139 | |||
| 109 | /* cmdlist data structure */ | 140 | /* cmdlist data structure */ |
| 110 | struct g2d_cmdlist { | 141 | struct g2d_cmdlist { |
| 111 | u32 head; | 142 | u32 head; |
| @@ -113,6 +144,42 @@ struct g2d_cmdlist { | |||
| 113 | u32 last; /* last data offset */ | 144 | u32 last; /* last data offset */ |
| 114 | }; | 145 | }; |
| 115 | 146 | ||
| 147 | /* | ||
| 148 | * A structure of buffer description | ||
| 149 | * | ||
| 150 | * @format: color format | ||
| 151 | * @left_x: the x coordinates of left top corner | ||
| 152 | * @top_y: the y coordinates of left top corner | ||
| 153 | * @right_x: the x coordinates of right bottom corner | ||
| 154 | * @bottom_y: the y coordinates of right bottom corner | ||
| 155 | * | ||
| 156 | */ | ||
| 157 | struct g2d_buf_desc { | ||
| 158 | unsigned int format; | ||
| 159 | unsigned int left_x; | ||
| 160 | unsigned int top_y; | ||
| 161 | unsigned int right_x; | ||
| 162 | unsigned int bottom_y; | ||
| 163 | }; | ||
| 164 | |||
| 165 | /* | ||
| 166 | * A structure of buffer information | ||
| 167 | * | ||
| 168 | * @map_nr: manages the number of mapped buffers | ||
| 169 | * @reg_types: stores regitster type in the order of requested command | ||
| 170 | * @handles: stores buffer handle in its reg_type position | ||
| 171 | * @types: stores buffer type in its reg_type position | ||
| 172 | * @descs: stores buffer description in its reg_type position | ||
| 173 | * | ||
| 174 | */ | ||
| 175 | struct g2d_buf_info { | ||
| 176 | unsigned int map_nr; | ||
| 177 | enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; | ||
| 178 | unsigned long handles[MAX_REG_TYPE_NR]; | ||
| 179 | unsigned int types[MAX_REG_TYPE_NR]; | ||
| 180 | struct g2d_buf_desc descs[MAX_REG_TYPE_NR]; | ||
| 181 | }; | ||
| 182 | |||
| 116 | struct drm_exynos_pending_g2d_event { | 183 | struct drm_exynos_pending_g2d_event { |
| 117 | struct drm_pending_event base; | 184 | struct drm_pending_event base; |
| 118 | struct drm_exynos_g2d_event event; | 185 | struct drm_exynos_g2d_event event; |
| @@ -131,14 +198,11 @@ struct g2d_cmdlist_userptr { | |||
| 131 | bool in_pool; | 198 | bool in_pool; |
| 132 | bool out_of_list; | 199 | bool out_of_list; |
| 133 | }; | 200 | }; |
| 134 | |||
| 135 | struct g2d_cmdlist_node { | 201 | struct g2d_cmdlist_node { |
| 136 | struct list_head list; | 202 | struct list_head list; |
| 137 | struct g2d_cmdlist *cmdlist; | 203 | struct g2d_cmdlist *cmdlist; |
| 138 | unsigned int map_nr; | ||
| 139 | unsigned long handles[MAX_BUF_ADDR_NR]; | ||
| 140 | unsigned int obj_type[MAX_BUF_ADDR_NR]; | ||
| 141 | dma_addr_t dma_addr; | 204 | dma_addr_t dma_addr; |
| 205 | struct g2d_buf_info buf_info; | ||
| 142 | 206 | ||
| 143 | struct drm_exynos_pending_g2d_event *event; | 207 | struct drm_exynos_pending_g2d_event *event; |
| 144 | }; | 208 | }; |
| @@ -188,6 +252,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
| 188 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | 252 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; |
| 189 | int nr; | 253 | int nr; |
| 190 | int ret; | 254 | int ret; |
| 255 | struct g2d_buf_info *buf_info; | ||
| 191 | 256 | ||
| 192 | init_dma_attrs(&g2d->cmdlist_dma_attrs); | 257 | init_dma_attrs(&g2d->cmdlist_dma_attrs); |
| 193 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); | 258 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); |
| @@ -209,11 +274,17 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
| 209 | } | 274 | } |
| 210 | 275 | ||
| 211 | for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { | 276 | for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { |
| 277 | unsigned int i; | ||
| 278 | |||
| 212 | node[nr].cmdlist = | 279 | node[nr].cmdlist = |
| 213 | g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; | 280 | g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; |
| 214 | node[nr].dma_addr = | 281 | node[nr].dma_addr = |
| 215 | g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; | 282 | g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; |
| 216 | 283 | ||
| 284 | buf_info = &node[nr].buf_info; | ||
| 285 | for (i = 0; i < MAX_REG_TYPE_NR; i++) | ||
| 286 | buf_info->reg_types[i] = REG_TYPE_NONE; | ||
| 287 | |||
| 217 | list_add_tail(&node[nr].list, &g2d->free_cmdlist); | 288 | list_add_tail(&node[nr].list, &g2d->free_cmdlist); |
| 218 | } | 289 | } |
| 219 | 290 | ||
| @@ -450,7 +521,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | |||
| 450 | DMA_BIDIRECTIONAL); | 521 | DMA_BIDIRECTIONAL); |
| 451 | if (ret < 0) { | 522 | if (ret < 0) { |
| 452 | DRM_ERROR("failed to map sgt with dma region.\n"); | 523 | DRM_ERROR("failed to map sgt with dma region.\n"); |
| 453 | goto err_free_sgt; | 524 | goto err_sg_free_table; |
| 454 | } | 525 | } |
| 455 | 526 | ||
| 456 | g2d_userptr->dma_addr = sgt->sgl[0].dma_address; | 527 | g2d_userptr->dma_addr = sgt->sgl[0].dma_address; |
| @@ -467,8 +538,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | |||
| 467 | 538 | ||
| 468 | return &g2d_userptr->dma_addr; | 539 | return &g2d_userptr->dma_addr; |
| 469 | 540 | ||
| 470 | err_free_sgt: | 541 | err_sg_free_table: |
| 471 | sg_free_table(sgt); | 542 | sg_free_table(sgt); |
| 543 | |||
| 544 | err_free_sgt: | ||
| 472 | kfree(sgt); | 545 | kfree(sgt); |
| 473 | sgt = NULL; | 546 | sgt = NULL; |
| 474 | 547 | ||
| @@ -506,36 +579,172 @@ static void g2d_userptr_free_all(struct drm_device *drm_dev, | |||
| 506 | g2d->current_pool = 0; | 579 | g2d->current_pool = 0; |
| 507 | } | 580 | } |
| 508 | 581 | ||
| 582 | static enum g2d_reg_type g2d_get_reg_type(int reg_offset) | ||
| 583 | { | ||
| 584 | enum g2d_reg_type reg_type; | ||
| 585 | |||
| 586 | switch (reg_offset) { | ||
| 587 | case G2D_SRC_BASE_ADDR: | ||
| 588 | case G2D_SRC_COLOR_MODE: | ||
| 589 | case G2D_SRC_LEFT_TOP: | ||
| 590 | case G2D_SRC_RIGHT_BOTTOM: | ||
| 591 | reg_type = REG_TYPE_SRC; | ||
| 592 | break; | ||
| 593 | case G2D_SRC_PLANE2_BASE_ADDR: | ||
| 594 | reg_type = REG_TYPE_SRC_PLANE2; | ||
| 595 | break; | ||
| 596 | case G2D_DST_BASE_ADDR: | ||
| 597 | case G2D_DST_COLOR_MODE: | ||
| 598 | case G2D_DST_LEFT_TOP: | ||
| 599 | case G2D_DST_RIGHT_BOTTOM: | ||
| 600 | reg_type = REG_TYPE_DST; | ||
| 601 | break; | ||
| 602 | case G2D_DST_PLANE2_BASE_ADDR: | ||
| 603 | reg_type = REG_TYPE_DST_PLANE2; | ||
| 604 | break; | ||
| 605 | case G2D_PAT_BASE_ADDR: | ||
| 606 | reg_type = REG_TYPE_PAT; | ||
| 607 | break; | ||
| 608 | case G2D_MSK_BASE_ADDR: | ||
| 609 | reg_type = REG_TYPE_MSK; | ||
| 610 | break; | ||
| 611 | default: | ||
| 612 | reg_type = REG_TYPE_NONE; | ||
| 613 | DRM_ERROR("Unknown register offset![%d]\n", reg_offset); | ||
| 614 | break; | ||
| 615 | }; | ||
| 616 | |||
| 617 | return reg_type; | ||
| 618 | } | ||
| 619 | |||
| 620 | static unsigned long g2d_get_buf_bpp(unsigned int format) | ||
| 621 | { | ||
| 622 | unsigned long bpp; | ||
| 623 | |||
| 624 | switch (format) { | ||
| 625 | case G2D_FMT_XRGB8888: | ||
| 626 | case G2D_FMT_ARGB8888: | ||
| 627 | bpp = 4; | ||
| 628 | break; | ||
| 629 | case G2D_FMT_RGB565: | ||
| 630 | case G2D_FMT_XRGB1555: | ||
| 631 | case G2D_FMT_ARGB1555: | ||
| 632 | case G2D_FMT_XRGB4444: | ||
| 633 | case G2D_FMT_ARGB4444: | ||
| 634 | bpp = 2; | ||
| 635 | break; | ||
| 636 | case G2D_FMT_PACKED_RGB888: | ||
| 637 | bpp = 3; | ||
| 638 | break; | ||
| 639 | default: | ||
| 640 | bpp = 1; | ||
| 641 | break; | ||
| 642 | } | ||
| 643 | |||
| 644 | return bpp; | ||
| 645 | } | ||
| 646 | |||
| 647 | static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc, | ||
| 648 | enum g2d_reg_type reg_type, | ||
| 649 | unsigned long size) | ||
| 650 | { | ||
| 651 | unsigned int width, height; | ||
| 652 | unsigned long area; | ||
| 653 | |||
| 654 | /* | ||
| 655 | * check source and destination buffers only. | ||
| 656 | * so the others are always valid. | ||
| 657 | */ | ||
| 658 | if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST) | ||
| 659 | return true; | ||
| 660 | |||
| 661 | width = buf_desc->right_x - buf_desc->left_x; | ||
| 662 | if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) { | ||
| 663 | DRM_ERROR("width[%u] is out of range!\n", width); | ||
| 664 | return false; | ||
| 665 | } | ||
| 666 | |||
| 667 | height = buf_desc->bottom_y - buf_desc->top_y; | ||
| 668 | if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) { | ||
| 669 | DRM_ERROR("height[%u] is out of range!\n", height); | ||
| 670 | return false; | ||
| 671 | } | ||
| 672 | |||
| 673 | area = (unsigned long)width * (unsigned long)height * | ||
| 674 | g2d_get_buf_bpp(buf_desc->format); | ||
| 675 | if (area > size) { | ||
| 676 | DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size); | ||
| 677 | return false; | ||
| 678 | } | ||
| 679 | |||
| 680 | return true; | ||
| 681 | } | ||
| 682 | |||
| 509 | static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | 683 | static int g2d_map_cmdlist_gem(struct g2d_data *g2d, |
| 510 | struct g2d_cmdlist_node *node, | 684 | struct g2d_cmdlist_node *node, |
| 511 | struct drm_device *drm_dev, | 685 | struct drm_device *drm_dev, |
| 512 | struct drm_file *file) | 686 | struct drm_file *file) |
| 513 | { | 687 | { |
| 514 | struct g2d_cmdlist *cmdlist = node->cmdlist; | 688 | struct g2d_cmdlist *cmdlist = node->cmdlist; |
| 689 | struct g2d_buf_info *buf_info = &node->buf_info; | ||
| 515 | int offset; | 690 | int offset; |
| 691 | int ret; | ||
| 516 | int i; | 692 | int i; |
| 517 | 693 | ||
| 518 | for (i = 0; i < node->map_nr; i++) { | 694 | for (i = 0; i < buf_info->map_nr; i++) { |
| 695 | struct g2d_buf_desc *buf_desc; | ||
| 696 | enum g2d_reg_type reg_type; | ||
| 697 | int reg_pos; | ||
| 519 | unsigned long handle; | 698 | unsigned long handle; |
| 520 | dma_addr_t *addr; | 699 | dma_addr_t *addr; |
| 521 | 700 | ||
| 522 | offset = cmdlist->last - (i * 2 + 1); | 701 | reg_pos = cmdlist->last - 2 * (i + 1); |
| 523 | handle = cmdlist->data[offset]; | 702 | |
| 703 | offset = cmdlist->data[reg_pos]; | ||
| 704 | handle = cmdlist->data[reg_pos + 1]; | ||
| 705 | |||
| 706 | reg_type = g2d_get_reg_type(offset); | ||
| 707 | if (reg_type == REG_TYPE_NONE) { | ||
| 708 | ret = -EFAULT; | ||
| 709 | goto err; | ||
| 710 | } | ||
| 711 | |||
| 712 | buf_desc = &buf_info->descs[reg_type]; | ||
| 713 | |||
| 714 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) { | ||
| 715 | unsigned long size; | ||
| 716 | |||
| 717 | size = exynos_drm_gem_get_size(drm_dev, handle, file); | ||
| 718 | if (!size) { | ||
| 719 | ret = -EFAULT; | ||
| 720 | goto err; | ||
| 721 | } | ||
| 722 | |||
| 723 | if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, | ||
| 724 | size)) { | ||
| 725 | ret = -EFAULT; | ||
| 726 | goto err; | ||
| 727 | } | ||
| 524 | 728 | ||
| 525 | if (node->obj_type[i] == BUF_TYPE_GEM) { | ||
| 526 | addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, | 729 | addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, |
| 527 | file); | 730 | file); |
| 528 | if (IS_ERR(addr)) { | 731 | if (IS_ERR(addr)) { |
| 529 | node->map_nr = i; | 732 | ret = -EFAULT; |
| 530 | return -EFAULT; | 733 | goto err; |
| 531 | } | 734 | } |
| 532 | } else { | 735 | } else { |
| 533 | struct drm_exynos_g2d_userptr g2d_userptr; | 736 | struct drm_exynos_g2d_userptr g2d_userptr; |
| 534 | 737 | ||
| 535 | if (copy_from_user(&g2d_userptr, (void __user *)handle, | 738 | if (copy_from_user(&g2d_userptr, (void __user *)handle, |
| 536 | sizeof(struct drm_exynos_g2d_userptr))) { | 739 | sizeof(struct drm_exynos_g2d_userptr))) { |
| 537 | node->map_nr = i; | 740 | ret = -EFAULT; |
| 538 | return -EFAULT; | 741 | goto err; |
| 742 | } | ||
| 743 | |||
| 744 | if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, | ||
| 745 | g2d_userptr.size)) { | ||
| 746 | ret = -EFAULT; | ||
| 747 | goto err; | ||
| 539 | } | 748 | } |
| 540 | 749 | ||
| 541 | addr = g2d_userptr_get_dma_addr(drm_dev, | 750 | addr = g2d_userptr_get_dma_addr(drm_dev, |
| @@ -544,16 +753,21 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | |||
| 544 | file, | 753 | file, |
| 545 | &handle); | 754 | &handle); |
| 546 | if (IS_ERR(addr)) { | 755 | if (IS_ERR(addr)) { |
| 547 | node->map_nr = i; | 756 | ret = -EFAULT; |
| 548 | return -EFAULT; | 757 | goto err; |
| 549 | } | 758 | } |
| 550 | } | 759 | } |
| 551 | 760 | ||
| 552 | cmdlist->data[offset] = *addr; | 761 | cmdlist->data[reg_pos + 1] = *addr; |
| 553 | node->handles[i] = handle; | 762 | buf_info->reg_types[i] = reg_type; |
| 763 | buf_info->handles[reg_type] = handle; | ||
| 554 | } | 764 | } |
| 555 | 765 | ||
| 556 | return 0; | 766 | return 0; |
| 767 | |||
| 768 | err: | ||
| 769 | buf_info->map_nr = i; | ||
| 770 | return ret; | ||
| 557 | } | 771 | } |
| 558 | 772 | ||
| 559 | static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, | 773 | static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, |
| @@ -561,22 +775,33 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, | |||
| 561 | struct drm_file *filp) | 775 | struct drm_file *filp) |
| 562 | { | 776 | { |
| 563 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | 777 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; |
| 778 | struct g2d_buf_info *buf_info = &node->buf_info; | ||
| 564 | int i; | 779 | int i; |
| 565 | 780 | ||
| 566 | for (i = 0; i < node->map_nr; i++) { | 781 | for (i = 0; i < buf_info->map_nr; i++) { |
| 567 | unsigned long handle = node->handles[i]; | 782 | struct g2d_buf_desc *buf_desc; |
| 783 | enum g2d_reg_type reg_type; | ||
| 784 | unsigned long handle; | ||
| 785 | |||
| 786 | reg_type = buf_info->reg_types[i]; | ||
| 787 | |||
| 788 | buf_desc = &buf_info->descs[reg_type]; | ||
| 789 | handle = buf_info->handles[reg_type]; | ||
| 568 | 790 | ||
| 569 | if (node->obj_type[i] == BUF_TYPE_GEM) | 791 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) |
| 570 | exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, | 792 | exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, |
| 571 | filp); | 793 | filp); |
| 572 | else | 794 | else |
| 573 | g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, | 795 | g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, |
| 574 | false); | 796 | false); |
| 575 | 797 | ||
| 576 | node->handles[i] = 0; | 798 | buf_info->reg_types[i] = REG_TYPE_NONE; |
| 799 | buf_info->handles[reg_type] = 0; | ||
| 800 | buf_info->types[reg_type] = 0; | ||
| 801 | memset(buf_desc, 0x00, sizeof(*buf_desc)); | ||
| 577 | } | 802 | } |
| 578 | 803 | ||
| 579 | node->map_nr = 0; | 804 | buf_info->map_nr = 0; |
| 580 | } | 805 | } |
| 581 | 806 | ||
| 582 | static void g2d_dma_start(struct g2d_data *g2d, | 807 | static void g2d_dma_start(struct g2d_data *g2d, |
| @@ -589,10 +814,6 @@ static void g2d_dma_start(struct g2d_data *g2d, | |||
| 589 | pm_runtime_get_sync(g2d->dev); | 814 | pm_runtime_get_sync(g2d->dev); |
| 590 | clk_enable(g2d->gate_clk); | 815 | clk_enable(g2d->gate_clk); |
| 591 | 816 | ||
| 592 | /* interrupt enable */ | ||
| 593 | writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF, | ||
| 594 | g2d->regs + G2D_INTEN); | ||
| 595 | |||
| 596 | writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR); | 817 | writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR); |
| 597 | writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND); | 818 | writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND); |
| 598 | } | 819 | } |
| @@ -643,7 +864,6 @@ static void g2d_runqueue_worker(struct work_struct *work) | |||
| 643 | struct g2d_data *g2d = container_of(work, struct g2d_data, | 864 | struct g2d_data *g2d = container_of(work, struct g2d_data, |
| 644 | runqueue_work); | 865 | runqueue_work); |
| 645 | 866 | ||
| 646 | |||
| 647 | mutex_lock(&g2d->runqueue_mutex); | 867 | mutex_lock(&g2d->runqueue_mutex); |
| 648 | clk_disable(g2d->gate_clk); | 868 | clk_disable(g2d->gate_clk); |
| 649 | pm_runtime_put_sync(g2d->dev); | 869 | pm_runtime_put_sync(g2d->dev); |
| @@ -724,20 +944,14 @@ static int g2d_check_reg_offset(struct device *dev, | |||
| 724 | int i; | 944 | int i; |
| 725 | 945 | ||
| 726 | for (i = 0; i < nr; i++) { | 946 | for (i = 0; i < nr; i++) { |
| 727 | index = cmdlist->last - 2 * (i + 1); | 947 | struct g2d_buf_info *buf_info = &node->buf_info; |
| 948 | struct g2d_buf_desc *buf_desc; | ||
| 949 | enum g2d_reg_type reg_type; | ||
| 950 | unsigned long value; | ||
| 728 | 951 | ||
| 729 | if (for_addr) { | 952 | index = cmdlist->last - 2 * (i + 1); |
| 730 | /* check userptr buffer type. */ | ||
| 731 | reg_offset = (cmdlist->data[index] & | ||
| 732 | ~0x7fffffff) >> 31; | ||
| 733 | if (reg_offset) { | ||
| 734 | node->obj_type[i] = BUF_TYPE_USERPTR; | ||
| 735 | cmdlist->data[index] &= ~G2D_BUF_USERPTR; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | 953 | ||
| 739 | reg_offset = cmdlist->data[index] & ~0xfffff000; | 954 | reg_offset = cmdlist->data[index] & ~0xfffff000; |
| 740 | |||
| 741 | if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) | 955 | if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) |
| 742 | goto err; | 956 | goto err; |
| 743 | if (reg_offset % 4) | 957 | if (reg_offset % 4) |
| @@ -753,8 +967,60 @@ static int g2d_check_reg_offset(struct device *dev, | |||
| 753 | if (!for_addr) | 967 | if (!for_addr) |
| 754 | goto err; | 968 | goto err; |
| 755 | 969 | ||
| 756 | if (node->obj_type[i] != BUF_TYPE_USERPTR) | 970 | reg_type = g2d_get_reg_type(reg_offset); |
| 757 | node->obj_type[i] = BUF_TYPE_GEM; | 971 | if (reg_type == REG_TYPE_NONE) |
| 972 | goto err; | ||
| 973 | |||
| 974 | /* check userptr buffer type. */ | ||
| 975 | if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { | ||
| 976 | buf_info->types[reg_type] = BUF_TYPE_USERPTR; | ||
| 977 | cmdlist->data[index] &= ~G2D_BUF_USERPTR; | ||
| 978 | } else | ||
| 979 | buf_info->types[reg_type] = BUF_TYPE_GEM; | ||
| 980 | break; | ||
| 981 | case G2D_SRC_COLOR_MODE: | ||
| 982 | case G2D_DST_COLOR_MODE: | ||
| 983 | if (for_addr) | ||
| 984 | goto err; | ||
| 985 | |||
| 986 | reg_type = g2d_get_reg_type(reg_offset); | ||
| 987 | if (reg_type == REG_TYPE_NONE) | ||
| 988 | goto err; | ||
| 989 | |||
| 990 | buf_desc = &buf_info->descs[reg_type]; | ||
| 991 | value = cmdlist->data[index + 1]; | ||
| 992 | |||
| 993 | buf_desc->format = value & 0xf; | ||
| 994 | break; | ||
| 995 | case G2D_SRC_LEFT_TOP: | ||
| 996 | case G2D_DST_LEFT_TOP: | ||
| 997 | if (for_addr) | ||
| 998 | goto err; | ||
| 999 | |||
| 1000 | reg_type = g2d_get_reg_type(reg_offset); | ||
| 1001 | if (reg_type == REG_TYPE_NONE) | ||
| 1002 | goto err; | ||
| 1003 | |||
| 1004 | buf_desc = &buf_info->descs[reg_type]; | ||
| 1005 | value = cmdlist->data[index + 1]; | ||
| 1006 | |||
| 1007 | buf_desc->left_x = value & 0x1fff; | ||
| 1008 | buf_desc->top_y = (value & 0x1fff0000) >> 16; | ||
| 1009 | break; | ||
| 1010 | case G2D_SRC_RIGHT_BOTTOM: | ||
| 1011 | case G2D_DST_RIGHT_BOTTOM: | ||
| 1012 | if (for_addr) | ||
| 1013 | goto err; | ||
| 1014 | |||
| 1015 | reg_type = g2d_get_reg_type(reg_offset); | ||
| 1016 | if (reg_type == REG_TYPE_NONE) | ||
| 1017 | goto err; | ||
| 1018 | |||
| 1019 | buf_desc = &buf_info->descs[reg_type]; | ||
| 1020 | value = cmdlist->data[index + 1]; | ||
| 1021 | |||
| 1022 | buf_desc->right_x = value & 0x1fff; | ||
| 1023 | buf_desc->bottom_y = (value & 0x1fff0000) >> 16; | ||
| 758 | break; | 1024 | break; |
| 759 | default: | 1025 | default: |
| 760 | if (for_addr) | 1026 | if (for_addr) |
| @@ -860,9 +1126,23 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
| 860 | cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR; | 1126 | cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR; |
| 861 | cmdlist->data[cmdlist->last++] = 0; | 1127 | cmdlist->data[cmdlist->last++] = 0; |
| 862 | 1128 | ||
| 1129 | /* | ||
| 1130 | * 'LIST_HOLD' command should be set to the DMA_HOLD_CMD_REG | ||
| 1131 | * and GCF bit should be set to INTEN register if user wants | ||
| 1132 | * G2D interrupt event once current command list execution is | ||
| 1133 | * finished. | ||
| 1134 | * Otherwise only ACF bit should be set to INTEN register so | ||
| 1135 | * that one interrupt is occured after all command lists | ||
| 1136 | * have been completed. | ||
| 1137 | */ | ||
| 863 | if (node->event) { | 1138 | if (node->event) { |
| 1139 | cmdlist->data[cmdlist->last++] = G2D_INTEN; | ||
| 1140 | cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF | G2D_INTEN_GCF; | ||
| 864 | cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD; | 1141 | cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD; |
| 865 | cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD; | 1142 | cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD; |
| 1143 | } else { | ||
| 1144 | cmdlist->data[cmdlist->last++] = G2D_INTEN; | ||
| 1145 | cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF; | ||
| 866 | } | 1146 | } |
| 867 | 1147 | ||
| 868 | /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ | 1148 | /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ |
| @@ -887,7 +1167,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
| 887 | if (ret < 0) | 1167 | if (ret < 0) |
| 888 | goto err_free_event; | 1168 | goto err_free_event; |
| 889 | 1169 | ||
| 890 | node->map_nr = req->cmd_buf_nr; | 1170 | node->buf_info.map_nr = req->cmd_buf_nr; |
| 891 | if (req->cmd_buf_nr) { | 1171 | if (req->cmd_buf_nr) { |
| 892 | struct drm_exynos_g2d_cmd *cmd_buf; | 1172 | struct drm_exynos_g2d_cmd *cmd_buf; |
| 893 | 1173 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 67e17ce112b6..0e6fe000578c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c | |||
| @@ -164,6 +164,27 @@ out: | |||
| 164 | exynos_gem_obj = NULL; | 164 | exynos_gem_obj = NULL; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | unsigned long exynos_drm_gem_get_size(struct drm_device *dev, | ||
| 168 | unsigned int gem_handle, | ||
| 169 | struct drm_file *file_priv) | ||
| 170 | { | ||
| 171 | struct exynos_drm_gem_obj *exynos_gem_obj; | ||
| 172 | struct drm_gem_object *obj; | ||
| 173 | |||
| 174 | obj = drm_gem_object_lookup(dev, file_priv, gem_handle); | ||
| 175 | if (!obj) { | ||
| 176 | DRM_ERROR("failed to lookup gem object.\n"); | ||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | exynos_gem_obj = to_exynos_gem_obj(obj); | ||
| 181 | |||
| 182 | drm_gem_object_unreference_unlocked(obj); | ||
| 183 | |||
| 184 | return exynos_gem_obj->buffer->size; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 167 | struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, | 188 | struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, |
| 168 | unsigned long size) | 189 | unsigned long size) |
| 169 | { | 190 | { |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 35ebac47dc2b..468766bee450 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h | |||
| @@ -130,6 +130,11 @@ int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, | |||
| 130 | int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, | 130 | int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, |
| 131 | struct drm_file *file_priv); | 131 | struct drm_file *file_priv); |
| 132 | 132 | ||
| 133 | /* get buffer size to gem handle. */ | ||
| 134 | unsigned long exynos_drm_gem_get_size(struct drm_device *dev, | ||
| 135 | unsigned int gem_handle, | ||
| 136 | struct drm_file *file_priv); | ||
| 137 | |||
| 133 | /* initialize gem object. */ | 138 | /* initialize gem object. */ |
| 134 | int exynos_drm_gem_init_object(struct drm_gem_object *obj); | 139 | int exynos_drm_gem_init_object(struct drm_gem_object *obj); |
| 135 | 140 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 13ccbd4bcfaa..9504b0cd825a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
| @@ -117,13 +117,12 @@ static struct edid *vidi_get_edid(struct device *dev, | |||
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; | 119 | edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; |
| 120 | edid = kzalloc(edid_len, GFP_KERNEL); | 120 | edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL); |
| 121 | if (!edid) { | 121 | if (!edid) { |
| 122 | DRM_DEBUG_KMS("failed to allocate edid\n"); | 122 | DRM_DEBUG_KMS("failed to allocate edid\n"); |
| 123 | return ERR_PTR(-ENOMEM); | 123 | return ERR_PTR(-ENOMEM); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | memcpy(edid, ctx->raw_edid, edid_len); | ||
| 127 | return edid; | 126 | return edid; |
| 128 | } | 127 | } |
| 129 | 128 | ||
| @@ -563,12 +562,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, | |||
| 563 | return -EINVAL; | 562 | return -EINVAL; |
| 564 | } | 563 | } |
| 565 | edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; | 564 | edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; |
| 566 | ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL); | 565 | ctx->raw_edid = kmemdup(raw_edid, edid_len, GFP_KERNEL); |
| 567 | if (!ctx->raw_edid) { | 566 | if (!ctx->raw_edid) { |
| 568 | DRM_DEBUG_KMS("failed to allocate raw_edid.\n"); | 567 | DRM_DEBUG_KMS("failed to allocate raw_edid.\n"); |
| 569 | return -ENOMEM; | 568 | return -ENOMEM; |
| 570 | } | 569 | } |
| 571 | memcpy(ctx->raw_edid, raw_edid, edid_len); | ||
| 572 | } else { | 570 | } else { |
| 573 | /* | 571 | /* |
| 574 | * with connection = 0, free raw_edid | 572 | * with connection = 0, free raw_edid |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e919aba29b3d..2f4f72f07047 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
| @@ -818,7 +818,7 @@ static void mixer_win_disable(void *ctx, int win) | |||
| 818 | mixer_ctx->win_data[win].enabled = false; | 818 | mixer_ctx->win_data[win].enabled = false; |
| 819 | } | 819 | } |
| 820 | 820 | ||
| 821 | int mixer_check_timing(void *ctx, struct fb_videomode *timing) | 821 | static int mixer_check_timing(void *ctx, struct fb_videomode *timing) |
| 822 | { | 822 | { |
| 823 | struct mixer_context *mixer_ctx = ctx; | 823 | struct mixer_context *mixer_ctx = ctx; |
| 824 | u32 w, h; | 824 | u32 w, h; |
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aae31489c893..7299ea45dd03 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
| @@ -103,7 +103,7 @@ static const char *cache_level_str(int type) | |||
| 103 | static void | 103 | static void |
| 104 | describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) | 104 | describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) |
| 105 | { | 105 | { |
| 106 | seq_printf(m, "%p: %s%s %8zdKiB %02x %02x %d %d %d%s%s%s", | 106 | seq_printf(m, "%pK: %s%s %8zdKiB %02x %02x %d %d %d%s%s%s", |
| 107 | &obj->base, | 107 | &obj->base, |
| 108 | get_pin_flag(obj), | 108 | get_pin_flag(obj), |
| 109 | get_tiling_flag(obj), | 109 | get_tiling_flag(obj), |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0a8eceb75902..e9b57893db2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -125,6 +125,11 @@ MODULE_PARM_DESC(preliminary_hw_support, | |||
| 125 | "Enable Haswell and ValleyView Support. " | 125 | "Enable Haswell and ValleyView Support. " |
| 126 | "(default: false)"); | 126 | "(default: false)"); |
| 127 | 127 | ||
| 128 | int i915_disable_power_well __read_mostly = 0; | ||
| 129 | module_param_named(disable_power_well, i915_disable_power_well, int, 0600); | ||
| 130 | MODULE_PARM_DESC(disable_power_well, | ||
| 131 | "Disable the power well when possible (default: false)"); | ||
| 132 | |||
| 128 | static struct drm_driver driver; | 133 | static struct drm_driver driver; |
| 129 | extern int intel_agp_enabled; | 134 | extern int intel_agp_enabled; |
| 130 | 135 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e95337c97459..01769e2a9953 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -1398,6 +1398,7 @@ extern int i915_enable_fbc __read_mostly; | |||
| 1398 | extern bool i915_enable_hangcheck __read_mostly; | 1398 | extern bool i915_enable_hangcheck __read_mostly; |
| 1399 | extern int i915_enable_ppgtt __read_mostly; | 1399 | extern int i915_enable_ppgtt __read_mostly; |
| 1400 | extern unsigned int i915_preliminary_hw_support __read_mostly; | 1400 | extern unsigned int i915_preliminary_hw_support __read_mostly; |
| 1401 | extern int i915_disable_power_well __read_mostly; | ||
| 1401 | 1402 | ||
| 1402 | extern int i915_suspend(struct drm_device *dev, pm_message_t state); | 1403 | extern int i915_suspend(struct drm_device *dev, pm_message_t state); |
| 1403 | extern int i915_resume(struct drm_device *dev); | 1404 | extern int i915_resume(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2f2daebd0eef..9a48e1a2d417 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
| @@ -57,7 +57,7 @@ eb_create(struct drm_i915_gem_execbuffer2 *args) | |||
| 57 | if (eb == NULL) { | 57 | if (eb == NULL) { |
| 58 | int size = args->buffer_count; | 58 | int size = args->buffer_count; |
| 59 | int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; | 59 | int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; |
| 60 | BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); | 60 | BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head)); |
| 61 | while (count > 2*size) | 61 | while (count > 2*size) |
| 62 | count >>= 1; | 62 | count >>= 1; |
| 63 | eb = kzalloc(count*sizeof(struct hlist_head) + | 63 | eb = kzalloc(count*sizeof(struct hlist_head) + |
| @@ -732,6 +732,8 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, | |||
| 732 | int count) | 732 | int count) |
| 733 | { | 733 | { |
| 734 | int i; | 734 | int i; |
| 735 | int relocs_total = 0; | ||
| 736 | int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); | ||
| 735 | 737 | ||
| 736 | for (i = 0; i < count; i++) { | 738 | for (i = 0; i < count; i++) { |
| 737 | char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; | 739 | char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; |
| @@ -740,10 +742,13 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, | |||
| 740 | if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) | 742 | if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) |
| 741 | return -EINVAL; | 743 | return -EINVAL; |
| 742 | 744 | ||
| 743 | /* First check for malicious input causing overflow */ | 745 | /* First check for malicious input causing overflow in |
| 744 | if (exec[i].relocation_count > | 746 | * the worst case where we need to allocate the entire |
| 745 | INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) | 747 | * relocation tree as a single array. |
| 748 | */ | ||
| 749 | if (exec[i].relocation_count > relocs_max - relocs_total) | ||
| 746 | return -EINVAL; | 750 | return -EINVAL; |
| 751 | relocs_total += exec[i].relocation_count; | ||
| 747 | 752 | ||
| 748 | length = exec[i].relocation_count * | 753 | length = exec[i].relocation_count * |
| 749 | sizeof(struct drm_i915_gem_relocation_entry); | 754 | sizeof(struct drm_i915_gem_relocation_entry); |
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 32a3693905ec..1ce45a0a2d3e 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
| @@ -45,6 +45,9 @@ | |||
| 45 | 45 | ||
| 46 | struct intel_crt { | 46 | struct intel_crt { |
| 47 | struct intel_encoder base; | 47 | struct intel_encoder base; |
| 48 | /* DPMS state is stored in the connector, which we need in the | ||
| 49 | * encoder's enable/disable callbacks */ | ||
| 50 | struct intel_connector *connector; | ||
| 48 | bool force_hotplug_required; | 51 | bool force_hotplug_required; |
| 49 | u32 adpa_reg; | 52 | u32 adpa_reg; |
| 50 | }; | 53 | }; |
| @@ -81,29 +84,6 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder, | |||
| 81 | return true; | 84 | return true; |
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | static void intel_disable_crt(struct intel_encoder *encoder) | ||
| 85 | { | ||
| 86 | struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; | ||
| 87 | struct intel_crt *crt = intel_encoder_to_crt(encoder); | ||
| 88 | u32 temp; | ||
| 89 | |||
| 90 | temp = I915_READ(crt->adpa_reg); | ||
| 91 | temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
| 92 | temp &= ~ADPA_DAC_ENABLE; | ||
| 93 | I915_WRITE(crt->adpa_reg, temp); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void intel_enable_crt(struct intel_encoder *encoder) | ||
| 97 | { | ||
| 98 | struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; | ||
| 99 | struct intel_crt *crt = intel_encoder_to_crt(encoder); | ||
| 100 | u32 temp; | ||
| 101 | |||
| 102 | temp = I915_READ(crt->adpa_reg); | ||
| 103 | temp |= ADPA_DAC_ENABLE; | ||
| 104 | I915_WRITE(crt->adpa_reg, temp); | ||
| 105 | } | ||
| 106 | |||
| 107 | /* Note: The caller is required to filter out dpms modes not supported by the | 87 | /* Note: The caller is required to filter out dpms modes not supported by the |
| 108 | * platform. */ | 88 | * platform. */ |
| 109 | static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) | 89 | static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) |
| @@ -135,6 +115,19 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) | |||
| 135 | I915_WRITE(crt->adpa_reg, temp); | 115 | I915_WRITE(crt->adpa_reg, temp); |
| 136 | } | 116 | } |
| 137 | 117 | ||
| 118 | static void intel_disable_crt(struct intel_encoder *encoder) | ||
| 119 | { | ||
| 120 | intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF); | ||
| 121 | } | ||
| 122 | |||
| 123 | static void intel_enable_crt(struct intel_encoder *encoder) | ||
| 124 | { | ||
| 125 | struct intel_crt *crt = intel_encoder_to_crt(encoder); | ||
| 126 | |||
| 127 | intel_crt_set_dpms(encoder, crt->connector->base.dpms); | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 138 | static void intel_crt_dpms(struct drm_connector *connector, int mode) | 131 | static void intel_crt_dpms(struct drm_connector *connector, int mode) |
| 139 | { | 132 | { |
| 140 | struct drm_device *dev = connector->dev; | 133 | struct drm_device *dev = connector->dev; |
| @@ -746,6 +739,7 @@ void intel_crt_init(struct drm_device *dev) | |||
| 746 | } | 739 | } |
| 747 | 740 | ||
| 748 | connector = &intel_connector->base; | 741 | connector = &intel_connector->base; |
| 742 | crt->connector = intel_connector; | ||
| 749 | drm_connector_init(dev, &intel_connector->base, | 743 | drm_connector_init(dev, &intel_connector->base, |
| 750 | &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); | 744 | &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); |
| 751 | 745 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 287b42c9d1a8..b20d50192fcc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -5771,6 +5771,11 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, | |||
| 5771 | num_connectors++; | 5771 | num_connectors++; |
| 5772 | } | 5772 | } |
| 5773 | 5773 | ||
| 5774 | if (is_cpu_edp) | ||
| 5775 | intel_crtc->cpu_transcoder = TRANSCODER_EDP; | ||
| 5776 | else | ||
| 5777 | intel_crtc->cpu_transcoder = pipe; | ||
| 5778 | |||
| 5774 | /* We are not sure yet this won't happen. */ | 5779 | /* We are not sure yet this won't happen. */ |
| 5775 | WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", | 5780 | WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", |
| 5776 | INTEL_PCH_TYPE(dev)); | 5781 | INTEL_PCH_TYPE(dev)); |
| @@ -5837,11 +5842,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
| 5837 | int pipe = intel_crtc->pipe; | 5842 | int pipe = intel_crtc->pipe; |
| 5838 | int ret; | 5843 | int ret; |
| 5839 | 5844 | ||
| 5840 | if (IS_HASWELL(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) | ||
| 5841 | intel_crtc->cpu_transcoder = TRANSCODER_EDP; | ||
| 5842 | else | ||
| 5843 | intel_crtc->cpu_transcoder = pipe; | ||
| 5844 | |||
| 5845 | drm_vblank_pre_modeset(dev, pipe); | 5845 | drm_vblank_pre_modeset(dev, pipe); |
| 5846 | 5846 | ||
| 5847 | ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, | 5847 | ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6f728e5ee793..8fc93f90a7cd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
| @@ -820,6 +820,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, | |||
| 820 | struct intel_link_m_n m_n; | 820 | struct intel_link_m_n m_n; |
| 821 | int pipe = intel_crtc->pipe; | 821 | int pipe = intel_crtc->pipe; |
| 822 | enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; | 822 | enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |
| 823 | int target_clock; | ||
| 823 | 824 | ||
| 824 | /* | 825 | /* |
| 825 | * Find the lane count in the intel_encoder private | 826 | * Find the lane count in the intel_encoder private |
| @@ -835,13 +836,22 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, | |||
| 835 | } | 836 | } |
| 836 | } | 837 | } |
| 837 | 838 | ||
| 839 | target_clock = mode->clock; | ||
| 840 | for_each_encoder_on_crtc(dev, crtc, intel_encoder) { | ||
| 841 | if (intel_encoder->type == INTEL_OUTPUT_EDP) { | ||
| 842 | target_clock = intel_edp_target_clock(intel_encoder, | ||
| 843 | mode); | ||
| 844 | break; | ||
| 845 | } | ||
| 846 | } | ||
| 847 | |||
| 838 | /* | 848 | /* |
| 839 | * Compute the GMCH and Link ratios. The '3' here is | 849 | * Compute the GMCH and Link ratios. The '3' here is |
| 840 | * the number of bytes_per_pixel post-LUT, which we always | 850 | * the number of bytes_per_pixel post-LUT, which we always |
| 841 | * set up for 8-bits of R/G/B, or 3 bytes total. | 851 | * set up for 8-bits of R/G/B, or 3 bytes total. |
| 842 | */ | 852 | */ |
| 843 | intel_link_compute_m_n(intel_crtc->bpp, lane_count, | 853 | intel_link_compute_m_n(intel_crtc->bpp, lane_count, |
| 844 | mode->clock, adjusted_mode->clock, &m_n); | 854 | target_clock, adjusted_mode->clock, &m_n); |
| 845 | 855 | ||
| 846 | if (IS_HASWELL(dev)) { | 856 | if (IS_HASWELL(dev)) { |
| 847 | I915_WRITE(PIPE_DATA_M1(cpu_transcoder), | 857 | I915_WRITE(PIPE_DATA_M1(cpu_transcoder), |
| @@ -1930,7 +1940,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) | |||
| 1930 | for (i = 0; i < intel_dp->lane_count; i++) | 1940 | for (i = 0; i < intel_dp->lane_count; i++) |
| 1931 | if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) | 1941 | if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) |
| 1932 | break; | 1942 | break; |
| 1933 | if (i == intel_dp->lane_count && voltage_tries == 5) { | 1943 | if (i == intel_dp->lane_count) { |
| 1934 | ++loop_tries; | 1944 | ++loop_tries; |
| 1935 | if (loop_tries == 5) { | 1945 | if (loop_tries == 5) { |
| 1936 | DRM_DEBUG_KMS("too many full retries, give up\n"); | 1946 | DRM_DEBUG_KMS("too many full retries, give up\n"); |
| @@ -2549,12 +2559,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) | |||
| 2549 | { | 2559 | { |
| 2550 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); | 2560 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); |
| 2551 | struct intel_dp *intel_dp = &intel_dig_port->dp; | 2561 | struct intel_dp *intel_dp = &intel_dig_port->dp; |
| 2562 | struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||
| 2552 | 2563 | ||
| 2553 | i2c_del_adapter(&intel_dp->adapter); | 2564 | i2c_del_adapter(&intel_dp->adapter); |
| 2554 | drm_encoder_cleanup(encoder); | 2565 | drm_encoder_cleanup(encoder); |
| 2555 | if (is_edp(intel_dp)) { | 2566 | if (is_edp(intel_dp)) { |
| 2556 | cancel_delayed_work_sync(&intel_dp->panel_vdd_work); | 2567 | cancel_delayed_work_sync(&intel_dp->panel_vdd_work); |
| 2568 | mutex_lock(&dev->mode_config.mutex); | ||
| 2557 | ironlake_panel_vdd_off_sync(intel_dp); | 2569 | ironlake_panel_vdd_off_sync(intel_dp); |
| 2570 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2558 | } | 2571 | } |
| 2559 | kfree(intel_dig_port); | 2572 | kfree(intel_dig_port); |
| 2560 | } | 2573 | } |
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index acf8aec9ada7..ef4744e1bf0b 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c | |||
| @@ -203,7 +203,13 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) | |||
| 203 | algo->data = bus; | 203 | algo->data = bus; |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | #define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 4) | 206 | /* |
| 207 | * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI | ||
| 208 | * mode. This results in spurious interrupt warnings if the legacy irq no. is | ||
| 209 | * shared with another device. The kernel then disables that interrupt source | ||
| 210 | * and so prevents the other device from working properly. | ||
| 211 | */ | ||
| 212 | #define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) | ||
| 207 | static int | 213 | static int |
| 208 | gmbus_wait_hw_status(struct drm_i915_private *dev_priv, | 214 | gmbus_wait_hw_status(struct drm_i915_private *dev_priv, |
| 209 | u32 gmbus2_status, | 215 | u32 gmbus2_status, |
| @@ -214,6 +220,9 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv, | |||
| 214 | u32 gmbus2 = 0; | 220 | u32 gmbus2 = 0; |
| 215 | DEFINE_WAIT(wait); | 221 | DEFINE_WAIT(wait); |
| 216 | 222 | ||
| 223 | if (!HAS_GMBUS_IRQ(dev_priv->dev)) | ||
| 224 | gmbus4_irq_en = 0; | ||
| 225 | |||
| 217 | /* Important: The hw handles only the first bit, so set only one! Since | 226 | /* Important: The hw handles only the first bit, so set only one! Since |
| 218 | * we also need to check for NAKs besides the hw ready/idle signal, we | 227 | * we also need to check for NAKs besides the hw ready/idle signal, we |
| 219 | * need to wake up periodically and check that ourselves. */ | 228 | * need to wake up periodically and check that ourselves. */ |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a3730e0289e5..bee8cb6108a7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
| @@ -321,9 +321,6 @@ void intel_panel_enable_backlight(struct drm_device *dev, | |||
| 321 | if (dev_priv->backlight_level == 0) | 321 | if (dev_priv->backlight_level == 0) |
| 322 | dev_priv->backlight_level = intel_panel_get_max_backlight(dev); | 322 | dev_priv->backlight_level = intel_panel_get_max_backlight(dev); |
| 323 | 323 | ||
| 324 | dev_priv->backlight_enabled = true; | ||
| 325 | intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); | ||
| 326 | |||
| 327 | if (INTEL_INFO(dev)->gen >= 4) { | 324 | if (INTEL_INFO(dev)->gen >= 4) { |
| 328 | uint32_t reg, tmp; | 325 | uint32_t reg, tmp; |
| 329 | 326 | ||
| @@ -359,12 +356,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, | |||
| 359 | } | 356 | } |
| 360 | 357 | ||
| 361 | set_level: | 358 | set_level: |
| 362 | /* Check the current backlight level and try to set again if it's zero. | 359 | /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. |
| 363 | * On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically | 360 | * BLC_PWM_CPU_CTL may be cleared to zero automatically when these |
| 364 | * when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written. | 361 | * registers are set. |
| 365 | */ | 362 | */ |
| 366 | if (!intel_panel_get_backlight(dev)) | 363 | dev_priv->backlight_enabled = true; |
| 367 | intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); | 364 | intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); |
| 368 | } | 365 | } |
| 369 | 366 | ||
| 370 | static void intel_panel_init_backlight(struct drm_device *dev) | 367 | static void intel_panel_init_backlight(struct drm_device *dev) |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a1794c6df1bf..adca00783e61 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
| @@ -4079,6 +4079,9 @@ void intel_set_power_well(struct drm_device *dev, bool enable) | |||
| 4079 | if (!IS_HASWELL(dev)) | 4079 | if (!IS_HASWELL(dev)) |
| 4080 | return; | 4080 | return; |
| 4081 | 4081 | ||
| 4082 | if (!i915_disable_power_well && !enable) | ||
| 4083 | return; | ||
| 4084 | |||
| 4082 | tmp = I915_READ(HSW_PWR_WELL_DRIVER); | 4085 | tmp = I915_READ(HSW_PWR_WELL_DRIVER); |
| 4083 | is_enabled = tmp & HSW_PWR_WELL_STATE; | 4086 | is_enabled = tmp & HSW_PWR_WELL_STATE; |
| 4084 | enable_requested = tmp & HSW_PWR_WELL_ENABLE; | 4087 | enable_requested = tmp & HSW_PWR_WELL_ENABLE; |
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index a274b9906ef8..78d8e919509f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c | |||
| @@ -382,19 +382,19 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) | |||
| 382 | m = n = p = 0; | 382 | m = n = p = 0; |
| 383 | vcomax = 800000; | 383 | vcomax = 800000; |
| 384 | vcomin = 400000; | 384 | vcomin = 400000; |
| 385 | pllreffreq = 3333; | 385 | pllreffreq = 33333; |
| 386 | 386 | ||
| 387 | delta = 0xffffffff; | 387 | delta = 0xffffffff; |
| 388 | permitteddelta = clock * 5 / 1000; | 388 | permitteddelta = clock * 5 / 1000; |
| 389 | 389 | ||
| 390 | for (testp = 16; testp > 0; testp--) { | 390 | for (testp = 16; testp > 0; testp >>= 1) { |
| 391 | if (clock * testp > vcomax) | 391 | if (clock * testp > vcomax) |
| 392 | continue; | 392 | continue; |
| 393 | if (clock * testp < vcomin) | 393 | if (clock * testp < vcomin) |
| 394 | continue; | 394 | continue; |
| 395 | 395 | ||
| 396 | for (testm = 1; testm < 33; testm++) { | 396 | for (testm = 1; testm < 33; testm++) { |
| 397 | for (testn = 1; testn < 257; testn++) { | 397 | for (testn = 17; testn < 257; testn++) { |
| 398 | computed = (pllreffreq * testn) / | 398 | computed = (pllreffreq * testn) / |
| 399 | (testm * testp); | 399 | (testm * testp); |
| 400 | if (computed > clock) | 400 | if (computed > clock) |
| @@ -404,11 +404,11 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) | |||
| 404 | if (tmpdelta < delta) { | 404 | if (tmpdelta < delta) { |
| 405 | delta = tmpdelta; | 405 | delta = tmpdelta; |
| 406 | n = testn - 1; | 406 | n = testn - 1; |
| 407 | m = (testm - 1) | ((n >> 1) & 0x80); | 407 | m = (testm - 1); |
| 408 | p = testp - 1; | 408 | p = testp - 1; |
| 409 | } | 409 | } |
| 410 | if ((clock * testp) >= 600000) | 410 | if ((clock * testp) >= 600000) |
| 411 | p |= 80; | 411 | p |= 0x80; |
| 412 | } | 412 | } |
| 413 | } | 413 | } |
| 414 | } | 414 | } |
| @@ -751,8 +751,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, | |||
| 751 | int i; | 751 | int i; |
| 752 | unsigned char misc = 0; | 752 | unsigned char misc = 0; |
| 753 | unsigned char ext_vga[6]; | 753 | unsigned char ext_vga[6]; |
| 754 | unsigned char ext_vga_index24; | ||
| 755 | unsigned char dac_index90 = 0; | ||
| 756 | u8 bppshift; | 754 | u8 bppshift; |
| 757 | 755 | ||
| 758 | static unsigned char dacvalue[] = { | 756 | static unsigned char dacvalue[] = { |
| @@ -803,7 +801,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, | |||
| 803 | option2 = 0x0000b000; | 801 | option2 = 0x0000b000; |
| 804 | break; | 802 | break; |
| 805 | case G200_ER: | 803 | case G200_ER: |
| 806 | dac_index90 = 0; | ||
| 807 | break; | 804 | break; |
| 808 | } | 805 | } |
| 809 | 806 | ||
| @@ -852,10 +849,8 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, | |||
| 852 | WREG_DAC(i, dacvalue[i]); | 849 | WREG_DAC(i, dacvalue[i]); |
| 853 | } | 850 | } |
| 854 | 851 | ||
| 855 | if (mdev->type == G200_ER) { | 852 | if (mdev->type == G200_ER) |
| 856 | WREG_DAC(0x90, dac_index90); | 853 | WREG_DAC(0x90, 0); |
| 857 | } | ||
| 858 | |||
| 859 | 854 | ||
| 860 | if (option) | 855 | if (option) |
| 861 | pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); | 856 | pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); |
| @@ -952,8 +947,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, | |||
| 952 | if (mdev->type == G200_WB) | 947 | if (mdev->type == G200_WB) |
| 953 | ext_vga[1] |= 0x88; | 948 | ext_vga[1] |= 0x88; |
| 954 | 949 | ||
| 955 | ext_vga_index24 = 0x05; | ||
| 956 | |||
| 957 | /* Set pixel clocks */ | 950 | /* Set pixel clocks */ |
| 958 | misc = 0x2d; | 951 | misc = 0x2d; |
| 959 | WREG8(MGA_MISC_OUT, misc); | 952 | WREG8(MGA_MISC_OUT, misc); |
| @@ -965,7 +958,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, | |||
| 965 | } | 958 | } |
| 966 | 959 | ||
| 967 | if (mdev->type == G200_ER) | 960 | if (mdev->type == G200_ER) |
| 968 | WREG_ECRT(24, ext_vga_index24); | 961 | WREG_ECRT(0x24, 0x5); |
| 969 | 962 | ||
| 970 | if (mdev->type == G200_EV) { | 963 | if (mdev->type == G200_EV) { |
| 971 | WREG_ECRT(6, 0); | 964 | WREG_ECRT(6, 0); |
diff --git a/drivers/gpu/drm/nouveau/core/core/object.c b/drivers/gpu/drm/nouveau/core/core/object.c index 0daab62ea14c..3b2e7b6304d3 100644 --- a/drivers/gpu/drm/nouveau/core/core/object.c +++ b/drivers/gpu/drm/nouveau/core/core/object.c | |||
| @@ -278,7 +278,6 @@ nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle) | |||
| 278 | struct nouveau_object *parent = NULL; | 278 | struct nouveau_object *parent = NULL; |
| 279 | struct nouveau_object *namedb = NULL; | 279 | struct nouveau_object *namedb = NULL; |
| 280 | struct nouveau_handle *handle = NULL; | 280 | struct nouveau_handle *handle = NULL; |
| 281 | int ret = -EINVAL; | ||
| 282 | 281 | ||
| 283 | parent = nouveau_handle_ref(client, _parent); | 282 | parent = nouveau_handle_ref(client, _parent); |
| 284 | if (!parent) | 283 | if (!parent) |
| @@ -295,7 +294,7 @@ nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle) | |||
| 295 | } | 294 | } |
| 296 | 295 | ||
| 297 | nouveau_object_ref(NULL, &parent); | 296 | nouveau_object_ref(NULL, &parent); |
| 298 | return ret; | 297 | return handle ? 0 : -EINVAL; |
| 299 | } | 298 | } |
| 300 | 299 | ||
| 301 | int | 300 | int |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 5fa13267bd9f..02e369f80449 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |||
| @@ -544,13 +544,13 @@ nv50_disp_curs_ofuncs = { | |||
| 544 | static void | 544 | static void |
| 545 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) | 545 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) |
| 546 | { | 546 | { |
| 547 | nv_mask(event->priv, 0x61002c, (1 << head), (1 << head)); | 547 | nv_mask(event->priv, 0x61002c, (4 << head), (4 << head)); |
| 548 | } | 548 | } |
| 549 | 549 | ||
| 550 | static void | 550 | static void |
| 551 | nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) | 551 | nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) |
| 552 | { | 552 | { |
| 553 | nv_mask(event->priv, 0x61002c, (1 << head), (0 << head)); | 553 | nv_mask(event->priv, 0x61002c, (4 << head), 0); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | static int | 556 | static int |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h index 6b17b614629f..0b20fc0d19c1 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | #include <core/device.h> | 4 | #include <core/device.h> |
| 5 | #include <core/subdev.h> | 5 | #include <core/subdev.h> |
| 6 | 6 | ||
| 7 | enum nouveau_therm_mode { | 7 | enum nouveau_therm_fan_mode { |
| 8 | NOUVEAU_THERM_CTRL_NONE = 0, | 8 | NOUVEAU_THERM_CTRL_NONE = 0, |
| 9 | NOUVEAU_THERM_CTRL_MANUAL = 1, | 9 | NOUVEAU_THERM_CTRL_MANUAL = 1, |
| 10 | NOUVEAU_THERM_CTRL_AUTO = 2, | 10 | NOUVEAU_THERM_CTRL_AUTO = 2, |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index e816f06637a7..0e2c1a4f1659 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c | |||
| @@ -248,6 +248,22 @@ nouveau_bios_shadow_pci(struct nouveau_bios *bios) | |||
| 248 | } | 248 | } |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | static void | ||
| 252 | nouveau_bios_shadow_platform(struct nouveau_bios *bios) | ||
| 253 | { | ||
| 254 | struct pci_dev *pdev = nv_device(bios)->pdev; | ||
| 255 | size_t size; | ||
| 256 | |||
| 257 | void __iomem *rom = pci_platform_rom(pdev, &size); | ||
| 258 | if (rom && size) { | ||
| 259 | bios->data = kmalloc(size, GFP_KERNEL); | ||
| 260 | if (bios->data) { | ||
| 261 | memcpy_fromio(bios->data, rom, size); | ||
| 262 | bios->size = size; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 251 | static int | 267 | static int |
| 252 | nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) | 268 | nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) |
| 253 | { | 269 | { |
| @@ -288,6 +304,7 @@ nouveau_bios_shadow(struct nouveau_bios *bios) | |||
| 288 | { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL }, | 304 | { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL }, |
| 289 | { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL }, | 305 | { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL }, |
| 290 | { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL }, | 306 | { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL }, |
| 307 | { "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL }, | ||
| 291 | {} | 308 | {} |
| 292 | }; | 309 | }; |
| 293 | struct methods *mthd, *best; | 310 | struct methods *mthd, *best; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c index f794dc89a3b2..a00a5a76e2d6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c | |||
| @@ -134,7 +134,7 @@ nouveau_therm_alarm(struct nouveau_alarm *alarm) | |||
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | int | 136 | int |
| 137 | nouveau_therm_mode(struct nouveau_therm *therm, int mode) | 137 | nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode) |
| 138 | { | 138 | { |
| 139 | struct nouveau_therm_priv *priv = (void *)therm; | 139 | struct nouveau_therm_priv *priv = (void *)therm; |
| 140 | struct nouveau_device *device = nv_device(therm); | 140 | struct nouveau_device *device = nv_device(therm); |
| @@ -149,10 +149,15 @@ nouveau_therm_mode(struct nouveau_therm *therm, int mode) | |||
| 149 | (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0)) | 149 | (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0)) |
| 150 | return -EINVAL; | 150 | return -EINVAL; |
| 151 | 151 | ||
| 152 | /* do not allow automatic fan management if the thermal sensor is | ||
| 153 | * not available */ | ||
| 154 | if (priv->mode == 2 && therm->temp_get(therm) < 0) | ||
| 155 | return -EINVAL; | ||
| 156 | |||
| 152 | if (priv->mode == mode) | 157 | if (priv->mode == mode) |
| 153 | return 0; | 158 | return 0; |
| 154 | 159 | ||
| 155 | nv_info(therm, "Thermal management: %s\n", name[mode]); | 160 | nv_info(therm, "fan management: %s\n", name[mode]); |
| 156 | nouveau_therm_update(therm, mode); | 161 | nouveau_therm_update(therm, mode); |
| 157 | return 0; | 162 | return 0; |
| 158 | } | 163 | } |
| @@ -213,7 +218,7 @@ nouveau_therm_attr_set(struct nouveau_therm *therm, | |||
| 213 | priv->fan->bios.max_duty = value; | 218 | priv->fan->bios.max_duty = value; |
| 214 | return 0; | 219 | return 0; |
| 215 | case NOUVEAU_THERM_ATTR_FAN_MODE: | 220 | case NOUVEAU_THERM_ATTR_FAN_MODE: |
| 216 | return nouveau_therm_mode(therm, value); | 221 | return nouveau_therm_fan_mode(therm, value); |
| 217 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: | 222 | case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: |
| 218 | priv->bios_sensor.thrs_fan_boost.temp = value; | 223 | priv->bios_sensor.thrs_fan_boost.temp = value; |
| 219 | priv->sensor.program_alarms(therm); | 224 | priv->sensor.program_alarms(therm); |
| @@ -263,7 +268,7 @@ _nouveau_therm_init(struct nouveau_object *object) | |||
| 263 | return ret; | 268 | return ret; |
| 264 | 269 | ||
| 265 | if (priv->suspend >= 0) | 270 | if (priv->suspend >= 0) |
| 266 | nouveau_therm_mode(therm, priv->mode); | 271 | nouveau_therm_fan_mode(therm, priv->mode); |
| 267 | priv->sensor.program_alarms(therm); | 272 | priv->sensor.program_alarms(therm); |
| 268 | return 0; | 273 | return 0; |
| 269 | } | 274 | } |
| @@ -313,11 +318,12 @@ nouveau_therm_create_(struct nouveau_object *parent, | |||
| 313 | int | 318 | int |
| 314 | nouveau_therm_preinit(struct nouveau_therm *therm) | 319 | nouveau_therm_preinit(struct nouveau_therm *therm) |
| 315 | { | 320 | { |
| 316 | nouveau_therm_ic_ctor(therm); | ||
| 317 | nouveau_therm_sensor_ctor(therm); | 321 | nouveau_therm_sensor_ctor(therm); |
| 322 | nouveau_therm_ic_ctor(therm); | ||
| 318 | nouveau_therm_fan_ctor(therm); | 323 | nouveau_therm_fan_ctor(therm); |
| 319 | 324 | ||
| 320 | nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_NONE); | 325 | nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_NONE); |
| 326 | nouveau_therm_sensor_preinit(therm); | ||
| 321 | return 0; | 327 | return 0; |
| 322 | } | 328 | } |
| 323 | 329 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c index e24090bac195..8b3adec5fbb1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c | |||
| @@ -32,6 +32,7 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, | |||
| 32 | struct i2c_board_info *info) | 32 | struct i2c_board_info *info) |
| 33 | { | 33 | { |
| 34 | struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c); | 34 | struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c); |
| 35 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; | ||
| 35 | struct i2c_client *client; | 36 | struct i2c_client *client; |
| 36 | 37 | ||
| 37 | request_module("%s%s", I2C_MODULE_PREFIX, info->type); | 38 | request_module("%s%s", I2C_MODULE_PREFIX, info->type); |
| @@ -46,8 +47,9 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, | |||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | nv_info(priv, | 49 | nv_info(priv, |
| 49 | "Found an %s at address 0x%x (controlled by lm_sensors)\n", | 50 | "Found an %s at address 0x%x (controlled by lm_sensors, " |
| 50 | info->type, info->addr); | 51 | "temp offset %+i C)\n", |
| 52 | info->type, info->addr, sensor->offset_constant); | ||
| 51 | priv->ic = client; | 53 | priv->ic = client; |
| 52 | 54 | ||
| 53 | return true; | 55 | return true; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c index 0f5363edb964..a70d1b7e397b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c | |||
| @@ -29,54 +29,83 @@ struct nv40_therm_priv { | |||
| 29 | struct nouveau_therm_priv base; | 29 | struct nouveau_therm_priv base; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 }; | ||
| 33 | |||
| 34 | static enum nv40_sensor_style | ||
| 35 | nv40_sensor_style(struct nouveau_therm *therm) | ||
| 36 | { | ||
| 37 | struct nouveau_device *device = nv_device(therm); | ||
| 38 | |||
| 39 | switch (device->chipset) { | ||
| 40 | case 0x43: | ||
| 41 | case 0x44: | ||
| 42 | case 0x4a: | ||
| 43 | case 0x47: | ||
| 44 | return OLD_STYLE; | ||
| 45 | |||
| 46 | case 0x46: | ||
| 47 | case 0x49: | ||
| 48 | case 0x4b: | ||
| 49 | case 0x4e: | ||
| 50 | case 0x4c: | ||
| 51 | case 0x67: | ||
| 52 | case 0x68: | ||
| 53 | case 0x63: | ||
| 54 | return NEW_STYLE; | ||
| 55 | default: | ||
| 56 | return INVALID_STYLE; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 32 | static int | 60 | static int |
| 33 | nv40_sensor_setup(struct nouveau_therm *therm) | 61 | nv40_sensor_setup(struct nouveau_therm *therm) |
| 34 | { | 62 | { |
| 35 | struct nouveau_device *device = nv_device(therm); | 63 | enum nv40_sensor_style style = nv40_sensor_style(therm); |
| 36 | 64 | ||
| 37 | /* enable ADC readout and disable the ALARM threshold */ | 65 | /* enable ADC readout and disable the ALARM threshold */ |
| 38 | if (device->chipset >= 0x46) { | 66 | if (style == NEW_STYLE) { |
| 39 | nv_mask(therm, 0x15b8, 0x80000000, 0); | 67 | nv_mask(therm, 0x15b8, 0x80000000, 0); |
| 40 | nv_wr32(therm, 0x15b0, 0x80003fff); | 68 | nv_wr32(therm, 0x15b0, 0x80003fff); |
| 41 | mdelay(10); /* wait for the temperature to stabilize */ | 69 | mdelay(20); /* wait for the temperature to stabilize */ |
| 42 | return nv_rd32(therm, 0x15b4) & 0x3fff; | 70 | return nv_rd32(therm, 0x15b4) & 0x3fff; |
| 43 | } else { | 71 | } else if (style == OLD_STYLE) { |
| 44 | nv_wr32(therm, 0x15b0, 0xff); | 72 | nv_wr32(therm, 0x15b0, 0xff); |
| 73 | mdelay(20); /* wait for the temperature to stabilize */ | ||
| 45 | return nv_rd32(therm, 0x15b4) & 0xff; | 74 | return nv_rd32(therm, 0x15b4) & 0xff; |
| 46 | } | 75 | } else |
| 76 | return -ENODEV; | ||
| 47 | } | 77 | } |
| 48 | 78 | ||
| 49 | static int | 79 | static int |
| 50 | nv40_temp_get(struct nouveau_therm *therm) | 80 | nv40_temp_get(struct nouveau_therm *therm) |
| 51 | { | 81 | { |
| 52 | struct nouveau_therm_priv *priv = (void *)therm; | 82 | struct nouveau_therm_priv *priv = (void *)therm; |
| 53 | struct nouveau_device *device = nv_device(therm); | ||
| 54 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; | 83 | struct nvbios_therm_sensor *sensor = &priv->bios_sensor; |
| 84 | enum nv40_sensor_style style = nv40_sensor_style(therm); | ||
| 55 | int core_temp; | 85 | int core_temp; |
| 56 | 86 | ||
| 57 | if (device->chipset >= 0x46) { | 87 | if (style == NEW_STYLE) { |
| 58 | nv_wr32(therm, 0x15b0, 0x80003fff); | 88 | nv_wr32(therm, 0x15b0, 0x80003fff); |
| 59 | core_temp = nv_rd32(therm, 0x15b4) & 0x3fff; | 89 | core_temp = nv_rd32(therm, 0x15b4) & 0x3fff; |
| 60 | } else { | 90 | } else if (style == OLD_STYLE) { |
| 61 | nv_wr32(therm, 0x15b0, 0xff); | 91 | nv_wr32(therm, 0x15b0, 0xff); |
| 62 | core_temp = nv_rd32(therm, 0x15b4) & 0xff; | 92 | core_temp = nv_rd32(therm, 0x15b4) & 0xff; |
| 63 | } | 93 | } else |
| 64 | 94 | return -ENODEV; | |
| 65 | /* Setup the sensor if the temperature is 0 */ | ||
| 66 | if (core_temp == 0) | ||
| 67 | core_temp = nv40_sensor_setup(therm); | ||
| 68 | 95 | ||
| 69 | if (sensor->slope_div == 0) | 96 | /* if the slope or the offset is unset, do no use the sensor */ |
| 70 | sensor->slope_div = 1; | 97 | if (!sensor->slope_div || !sensor->slope_mult || |
| 71 | if (sensor->offset_den == 0) | 98 | !sensor->offset_num || !sensor->offset_den) |
| 72 | sensor->offset_den = 1; | 99 | return -ENODEV; |
| 73 | if (sensor->slope_mult < 1) | ||
| 74 | sensor->slope_mult = 1; | ||
| 75 | 100 | ||
| 76 | core_temp = core_temp * sensor->slope_mult / sensor->slope_div; | 101 | core_temp = core_temp * sensor->slope_mult / sensor->slope_div; |
| 77 | core_temp = core_temp + sensor->offset_num / sensor->offset_den; | 102 | core_temp = core_temp + sensor->offset_num / sensor->offset_den; |
| 78 | core_temp = core_temp + sensor->offset_constant - 8; | 103 | core_temp = core_temp + sensor->offset_constant - 8; |
| 79 | 104 | ||
| 105 | /* reserve negative temperatures for errors */ | ||
| 106 | if (core_temp < 0) | ||
| 107 | core_temp = 0; | ||
| 108 | |||
| 80 | return core_temp; | 109 | return core_temp; |
| 81 | } | 110 | } |
| 82 | 111 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index 06b98706b3fc..438d9824b774 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h | |||
| @@ -102,7 +102,7 @@ struct nouveau_therm_priv { | |||
| 102 | struct i2c_client *ic; | 102 | struct i2c_client *ic; |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | int nouveau_therm_mode(struct nouveau_therm *therm, int mode); | 105 | int nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode); |
| 106 | int nouveau_therm_attr_get(struct nouveau_therm *therm, | 106 | int nouveau_therm_attr_get(struct nouveau_therm *therm, |
| 107 | enum nouveau_therm_attr_type type); | 107 | enum nouveau_therm_attr_type type); |
| 108 | int nouveau_therm_attr_set(struct nouveau_therm *therm, | 108 | int nouveau_therm_attr_set(struct nouveau_therm *therm, |
| @@ -122,6 +122,7 @@ int nouveau_therm_fan_sense(struct nouveau_therm *therm); | |||
| 122 | 122 | ||
| 123 | int nouveau_therm_preinit(struct nouveau_therm *); | 123 | int nouveau_therm_preinit(struct nouveau_therm *); |
| 124 | 124 | ||
| 125 | void nouveau_therm_sensor_preinit(struct nouveau_therm *); | ||
| 125 | void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm, | 126 | void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm, |
| 126 | enum nouveau_therm_thrs thrs, | 127 | enum nouveau_therm_thrs thrs, |
| 127 | enum nouveau_therm_thrs_state st); | 128 | enum nouveau_therm_thrs_state st); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c index b37624af8297..470f6a47b656 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c | |||
| @@ -34,10 +34,6 @@ nouveau_therm_temp_set_defaults(struct nouveau_therm *therm) | |||
| 34 | { | 34 | { |
| 35 | struct nouveau_therm_priv *priv = (void *)therm; | 35 | struct nouveau_therm_priv *priv = (void *)therm; |
| 36 | 36 | ||
| 37 | priv->bios_sensor.slope_mult = 1; | ||
| 38 | priv->bios_sensor.slope_div = 1; | ||
| 39 | priv->bios_sensor.offset_num = 0; | ||
| 40 | priv->bios_sensor.offset_den = 1; | ||
| 41 | priv->bios_sensor.offset_constant = 0; | 37 | priv->bios_sensor.offset_constant = 0; |
| 42 | 38 | ||
| 43 | priv->bios_sensor.thrs_fan_boost.temp = 90; | 39 | priv->bios_sensor.thrs_fan_boost.temp = 90; |
| @@ -60,11 +56,6 @@ nouveau_therm_temp_safety_checks(struct nouveau_therm *therm) | |||
| 60 | struct nouveau_therm_priv *priv = (void *)therm; | 56 | struct nouveau_therm_priv *priv = (void *)therm; |
| 61 | struct nvbios_therm_sensor *s = &priv->bios_sensor; | 57 | struct nvbios_therm_sensor *s = &priv->bios_sensor; |
| 62 | 58 | ||
| 63 | if (!priv->bios_sensor.slope_div) | ||
| 64 | priv->bios_sensor.slope_div = 1; | ||
| 65 | if (!priv->bios_sensor.offset_den) | ||
| 66 | priv->bios_sensor.offset_den = 1; | ||
| 67 | |||
| 68 | /* enforce a minimum hysteresis on thresholds */ | 59 | /* enforce a minimum hysteresis on thresholds */ |
| 69 | s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2); | 60 | s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2); |
| 70 | s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2); | 61 | s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2); |
| @@ -106,16 +97,16 @@ void nouveau_therm_sensor_event(struct nouveau_therm *therm, | |||
| 106 | const char *thresolds[] = { | 97 | const char *thresolds[] = { |
| 107 | "fanboost", "downclock", "critical", "shutdown" | 98 | "fanboost", "downclock", "critical", "shutdown" |
| 108 | }; | 99 | }; |
| 109 | uint8_t temperature = therm->temp_get(therm); | 100 | int temperature = therm->temp_get(therm); |
| 110 | 101 | ||
| 111 | if (thrs < 0 || thrs > 3) | 102 | if (thrs < 0 || thrs > 3) |
| 112 | return; | 103 | return; |
| 113 | 104 | ||
| 114 | if (dir == NOUVEAU_THERM_THRS_FALLING) | 105 | if (dir == NOUVEAU_THERM_THRS_FALLING) |
| 115 | nv_info(therm, "temperature (%u C) went below the '%s' threshold\n", | 106 | nv_info(therm, "temperature (%i C) went below the '%s' threshold\n", |
| 116 | temperature, thresolds[thrs]); | 107 | temperature, thresolds[thrs]); |
| 117 | else | 108 | else |
| 118 | nv_info(therm, "temperature (%u C) hit the '%s' threshold\n", | 109 | nv_info(therm, "temperature (%i C) hit the '%s' threshold\n", |
| 119 | temperature, thresolds[thrs]); | 110 | temperature, thresolds[thrs]); |
| 120 | 111 | ||
| 121 | active = (dir == NOUVEAU_THERM_THRS_RISING); | 112 | active = (dir == NOUVEAU_THERM_THRS_RISING); |
| @@ -123,7 +114,7 @@ void nouveau_therm_sensor_event(struct nouveau_therm *therm, | |||
| 123 | case NOUVEAU_THERM_THRS_FANBOOST: | 114 | case NOUVEAU_THERM_THRS_FANBOOST: |
| 124 | if (active) { | 115 | if (active) { |
| 125 | nouveau_therm_fan_set(therm, true, 100); | 116 | nouveau_therm_fan_set(therm, true, 100); |
| 126 | nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_AUTO); | 117 | nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO); |
| 127 | } | 118 | } |
| 128 | break; | 119 | break; |
| 129 | case NOUVEAU_THERM_THRS_DOWNCLOCK: | 120 | case NOUVEAU_THERM_THRS_DOWNCLOCK: |
| @@ -202,7 +193,7 @@ alarm_timer_callback(struct nouveau_alarm *alarm) | |||
| 202 | NOUVEAU_THERM_THRS_SHUTDOWN); | 193 | NOUVEAU_THERM_THRS_SHUTDOWN); |
| 203 | 194 | ||
| 204 | /* schedule the next poll in one second */ | 195 | /* schedule the next poll in one second */ |
| 205 | if (list_empty(&alarm->head)) | 196 | if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head)) |
| 206 | ptimer->alarm(ptimer, 1000 * 1000 * 1000, alarm); | 197 | ptimer->alarm(ptimer, 1000 * 1000 * 1000, alarm); |
| 207 | 198 | ||
| 208 | spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); | 199 | spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); |
| @@ -225,6 +216,17 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm) | |||
| 225 | alarm_timer_callback(&priv->sensor.therm_poll_alarm); | 216 | alarm_timer_callback(&priv->sensor.therm_poll_alarm); |
| 226 | } | 217 | } |
| 227 | 218 | ||
| 219 | void | ||
| 220 | nouveau_therm_sensor_preinit(struct nouveau_therm *therm) | ||
| 221 | { | ||
| 222 | const char *sensor_avail = "yes"; | ||
| 223 | |||
| 224 | if (therm->temp_get(therm) < 0) | ||
| 225 | sensor_avail = "no"; | ||
| 226 | |||
| 227 | nv_info(therm, "internal sensor: %s\n", sensor_avail); | ||
| 228 | } | ||
| 229 | |||
| 228 | int | 230 | int |
| 229 | nouveau_therm_sensor_ctor(struct nouveau_therm *therm) | 231 | nouveau_therm_sensor_ctor(struct nouveau_therm *therm) |
| 230 | { | 232 | { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 41241922263f..5eb3e0da7c6e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c | |||
| @@ -116,6 +116,11 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, | |||
| 116 | { | 116 | { |
| 117 | struct nouveau_abi16_ntfy *ntfy, *temp; | 117 | struct nouveau_abi16_ntfy *ntfy, *temp; |
| 118 | 118 | ||
| 119 | /* wait for all activity to stop before releasing notify object, which | ||
| 120 | * may be still in use */ | ||
| 121 | if (chan->chan && chan->ntfy) | ||
| 122 | nouveau_channel_idle(chan->chan); | ||
| 123 | |||
| 119 | /* cleanup notifier state */ | 124 | /* cleanup notifier state */ |
| 120 | list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { | 125 | list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { |
| 121 | nouveau_abi16_ntfy_fini(chan, ntfy); | 126 | nouveau_abi16_ntfy_fini(chan, ntfy); |
| @@ -386,7 +391,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) | |||
| 386 | struct nouveau_drm *drm = nouveau_drm(dev); | 391 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 387 | struct nouveau_device *device = nv_device(drm->device); | 392 | struct nouveau_device *device = nv_device(drm->device); |
| 388 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); | 393 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); |
| 389 | struct nouveau_abi16_chan *chan, *temp; | 394 | struct nouveau_abi16_chan *chan = NULL, *temp; |
| 390 | struct nouveau_abi16_ntfy *ntfy; | 395 | struct nouveau_abi16_ntfy *ntfy; |
| 391 | struct nouveau_object *object; | 396 | struct nouveau_object *object; |
| 392 | struct nv_dma_class args = {}; | 397 | struct nv_dma_class args = {}; |
| @@ -399,10 +404,11 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) | |||
| 399 | if (unlikely(nv_device(abi16->device)->card_type >= NV_C0)) | 404 | if (unlikely(nv_device(abi16->device)->card_type >= NV_C0)) |
| 400 | return nouveau_abi16_put(abi16, -EINVAL); | 405 | return nouveau_abi16_put(abi16, -EINVAL); |
| 401 | 406 | ||
| 402 | list_for_each_entry_safe(chan, temp, &abi16->channels, head) { | 407 | list_for_each_entry(temp, &abi16->channels, head) { |
| 403 | if (chan->chan->handle == (NVDRM_CHAN | info->channel)) | 408 | if (temp->chan->handle == (NVDRM_CHAN | info->channel)) { |
| 409 | chan = temp; | ||
| 404 | break; | 410 | break; |
| 405 | chan = NULL; | 411 | } |
| 406 | } | 412 | } |
| 407 | 413 | ||
| 408 | if (!chan) | 414 | if (!chan) |
| @@ -454,17 +460,18 @@ nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) | |||
| 454 | { | 460 | { |
| 455 | struct drm_nouveau_gpuobj_free *fini = data; | 461 | struct drm_nouveau_gpuobj_free *fini = data; |
| 456 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); | 462 | struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); |
| 457 | struct nouveau_abi16_chan *chan, *temp; | 463 | struct nouveau_abi16_chan *chan = NULL, *temp; |
| 458 | struct nouveau_abi16_ntfy *ntfy; | 464 | struct nouveau_abi16_ntfy *ntfy; |
| 459 | int ret; | 465 | int ret; |
| 460 | 466 | ||
| 461 | if (unlikely(!abi16)) | 467 | if (unlikely(!abi16)) |
| 462 | return -ENOMEM; | 468 | return -ENOMEM; |
| 463 | 469 | ||
| 464 | list_for_each_entry_safe(chan, temp, &abi16->channels, head) { | 470 | list_for_each_entry(temp, &abi16->channels, head) { |
| 465 | if (chan->chan->handle == (NVDRM_CHAN | fini->channel)) | 471 | if (temp->chan->handle == (NVDRM_CHAN | fini->channel)) { |
| 472 | chan = temp; | ||
| 466 | break; | 473 | break; |
| 467 | chan = NULL; | 474 | } |
| 468 | } | 475 | } |
| 469 | 476 | ||
| 470 | if (!chan) | 477 | if (!chan) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 11ca82148edc..7ff10711a4d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
| @@ -801,7 +801,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | |||
| 801 | stride = 16 * 4; | 801 | stride = 16 * 4; |
| 802 | height = amount / stride; | 802 | height = amount / stride; |
| 803 | 803 | ||
| 804 | if (new_mem->mem_type == TTM_PL_VRAM && | 804 | if (old_mem->mem_type == TTM_PL_VRAM && |
| 805 | nouveau_bo_tile_layout(nvbo)) { | 805 | nouveau_bo_tile_layout(nvbo)) { |
| 806 | ret = RING_SPACE(chan, 8); | 806 | ret = RING_SPACE(chan, 8); |
| 807 | if (ret) | 807 | if (ret) |
| @@ -823,7 +823,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | |||
| 823 | BEGIN_NV04(chan, NvSubCopy, 0x0200, 1); | 823 | BEGIN_NV04(chan, NvSubCopy, 0x0200, 1); |
| 824 | OUT_RING (chan, 1); | 824 | OUT_RING (chan, 1); |
| 825 | } | 825 | } |
| 826 | if (old_mem->mem_type == TTM_PL_VRAM && | 826 | if (new_mem->mem_type == TTM_PL_VRAM && |
| 827 | nouveau_bo_tile_layout(nvbo)) { | 827 | nouveau_bo_tile_layout(nvbo)) { |
| 828 | ret = RING_SPACE(chan, 8); | 828 | ret = RING_SPACE(chan, 8); |
| 829 | if (ret) | 829 | if (ret) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index d1099365bfc1..c95decf543e9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
| @@ -72,11 +72,25 @@ module_param_named(modeset, nouveau_modeset, int, 0400); | |||
| 72 | static struct drm_driver driver; | 72 | static struct drm_driver driver; |
| 73 | 73 | ||
| 74 | static int | 74 | static int |
| 75 | nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) | ||
| 76 | { | ||
| 77 | struct nouveau_drm *drm = | ||
| 78 | container_of(event, struct nouveau_drm, vblank[head]); | ||
| 79 | drm_handle_vblank(drm->dev, head); | ||
| 80 | return NVKM_EVENT_KEEP; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int | ||
| 75 | nouveau_drm_vblank_enable(struct drm_device *dev, int head) | 84 | nouveau_drm_vblank_enable(struct drm_device *dev, int head) |
| 76 | { | 85 | { |
| 77 | struct nouveau_drm *drm = nouveau_drm(dev); | 86 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 78 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); | 87 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); |
| 79 | nouveau_event_get(pdisp->vblank, head, &drm->vblank); | 88 | |
| 89 | if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank))) | ||
| 90 | return -EIO; | ||
| 91 | WARN_ON_ONCE(drm->vblank[head].func); | ||
| 92 | drm->vblank[head].func = nouveau_drm_vblank_handler; | ||
| 93 | nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]); | ||
| 80 | return 0; | 94 | return 0; |
| 81 | } | 95 | } |
| 82 | 96 | ||
| @@ -85,16 +99,11 @@ nouveau_drm_vblank_disable(struct drm_device *dev, int head) | |||
| 85 | { | 99 | { |
| 86 | struct nouveau_drm *drm = nouveau_drm(dev); | 100 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 87 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); | 101 | struct nouveau_disp *pdisp = nouveau_disp(drm->device); |
| 88 | nouveau_event_put(pdisp->vblank, head, &drm->vblank); | 102 | if (drm->vblank[head].func) |
| 89 | } | 103 | nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]); |
| 90 | 104 | else | |
| 91 | static int | 105 | WARN_ON_ONCE(1); |
| 92 | nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) | 106 | drm->vblank[head].func = NULL; |
| 93 | { | ||
| 94 | struct nouveau_drm *drm = | ||
| 95 | container_of(event, struct nouveau_drm, vblank); | ||
| 96 | drm_handle_vblank(drm->dev, head); | ||
| 97 | return NVKM_EVENT_KEEP; | ||
| 98 | } | 107 | } |
| 99 | 108 | ||
| 100 | static u64 | 109 | static u64 |
| @@ -292,7 +301,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 292 | 301 | ||
| 293 | dev->dev_private = drm; | 302 | dev->dev_private = drm; |
| 294 | drm->dev = dev; | 303 | drm->dev = dev; |
| 295 | drm->vblank.func = nouveau_drm_vblank_handler; | ||
| 296 | 304 | ||
| 297 | INIT_LIST_HEAD(&drm->clients); | 305 | INIT_LIST_HEAD(&drm->clients); |
| 298 | spin_lock_init(&drm->tile.lock); | 306 | spin_lock_init(&drm->tile.lock); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index b25df374c901..9c39bafbef2c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h | |||
| @@ -113,7 +113,7 @@ struct nouveau_drm { | |||
| 113 | struct nvbios vbios; | 113 | struct nvbios vbios; |
| 114 | struct nouveau_display *display; | 114 | struct nouveau_display *display; |
| 115 | struct backlight_device *backlight; | 115 | struct backlight_device *backlight; |
| 116 | struct nouveau_eventh vblank; | 116 | struct nouveau_eventh vblank[4]; |
| 117 | 117 | ||
| 118 | /* power management */ | 118 | /* power management */ |
| 119 | struct nouveau_pm *pm; | 119 | struct nouveau_pm *pm; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index bb54098c6d97..936b442a6ab7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c | |||
| @@ -402,8 +402,12 @@ nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) | |||
| 402 | struct drm_device *dev = dev_get_drvdata(d); | 402 | struct drm_device *dev = dev_get_drvdata(d); |
| 403 | struct nouveau_drm *drm = nouveau_drm(dev); | 403 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 404 | struct nouveau_therm *therm = nouveau_therm(drm->device); | 404 | struct nouveau_therm *therm = nouveau_therm(drm->device); |
| 405 | int temp = therm->temp_get(therm); | ||
| 405 | 406 | ||
| 406 | return snprintf(buf, PAGE_SIZE, "%d\n", therm->temp_get(therm) * 1000); | 407 | if (temp < 0) |
| 408 | return temp; | ||
| 409 | |||
| 410 | return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000); | ||
| 407 | } | 411 | } |
| 408 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, | 412 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, |
| 409 | NULL, 0); | 413 | NULL, 0); |
| @@ -871,7 +875,12 @@ static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, | |||
| 871 | nouveau_hwmon_get_pwm1_max, | 875 | nouveau_hwmon_get_pwm1_max, |
| 872 | nouveau_hwmon_set_pwm1_max, 0); | 876 | nouveau_hwmon_set_pwm1_max, 0); |
| 873 | 877 | ||
| 874 | static struct attribute *hwmon_attributes[] = { | 878 | static struct attribute *hwmon_default_attributes[] = { |
| 879 | &sensor_dev_attr_name.dev_attr.attr, | ||
| 880 | &sensor_dev_attr_update_rate.dev_attr.attr, | ||
| 881 | NULL | ||
| 882 | }; | ||
| 883 | static struct attribute *hwmon_temp_attributes[] = { | ||
| 875 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 884 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
| 876 | &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, | 885 | &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, |
| 877 | &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, | 886 | &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, |
| @@ -882,8 +891,6 @@ static struct attribute *hwmon_attributes[] = { | |||
| 882 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, | 891 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, |
| 883 | &sensor_dev_attr_temp1_emergency.dev_attr.attr, | 892 | &sensor_dev_attr_temp1_emergency.dev_attr.attr, |
| 884 | &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr, | 893 | &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr, |
| 885 | &sensor_dev_attr_name.dev_attr.attr, | ||
| 886 | &sensor_dev_attr_update_rate.dev_attr.attr, | ||
| 887 | NULL | 894 | NULL |
| 888 | }; | 895 | }; |
| 889 | static struct attribute *hwmon_fan_rpm_attributes[] = { | 896 | static struct attribute *hwmon_fan_rpm_attributes[] = { |
| @@ -898,8 +905,11 @@ static struct attribute *hwmon_pwm_fan_attributes[] = { | |||
| 898 | NULL | 905 | NULL |
| 899 | }; | 906 | }; |
| 900 | 907 | ||
| 901 | static const struct attribute_group hwmon_attrgroup = { | 908 | static const struct attribute_group hwmon_default_attrgroup = { |
| 902 | .attrs = hwmon_attributes, | 909 | .attrs = hwmon_default_attributes, |
| 910 | }; | ||
| 911 | static const struct attribute_group hwmon_temp_attrgroup = { | ||
| 912 | .attrs = hwmon_temp_attributes, | ||
| 903 | }; | 913 | }; |
| 904 | static const struct attribute_group hwmon_fan_rpm_attrgroup = { | 914 | static const struct attribute_group hwmon_fan_rpm_attrgroup = { |
| 905 | .attrs = hwmon_fan_rpm_attributes, | 915 | .attrs = hwmon_fan_rpm_attributes, |
| @@ -931,13 +941,22 @@ nouveau_hwmon_init(struct drm_device *dev) | |||
| 931 | } | 941 | } |
| 932 | dev_set_drvdata(hwmon_dev, dev); | 942 | dev_set_drvdata(hwmon_dev, dev); |
| 933 | 943 | ||
| 934 | /* default sysfs entries */ | 944 | /* set the default attributes */ |
| 935 | ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_attrgroup); | 945 | ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup); |
| 936 | if (ret) { | 946 | if (ret) { |
| 937 | if (ret) | 947 | if (ret) |
| 938 | goto error; | 948 | goto error; |
| 939 | } | 949 | } |
| 940 | 950 | ||
| 951 | /* if the card has a working thermal sensor */ | ||
| 952 | if (therm->temp_get(therm) >= 0) { | ||
| 953 | ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup); | ||
| 954 | if (ret) { | ||
| 955 | if (ret) | ||
| 956 | goto error; | ||
| 957 | } | ||
| 958 | } | ||
| 959 | |||
| 941 | /* if the card has a pwm fan */ | 960 | /* if the card has a pwm fan */ |
| 942 | /*XXX: incorrect, need better detection for this, some boards have | 961 | /*XXX: incorrect, need better detection for this, some boards have |
| 943 | * the gpio entries for pwm fan control even when there's no | 962 | * the gpio entries for pwm fan control even when there's no |
| @@ -979,11 +998,10 @@ nouveau_hwmon_fini(struct drm_device *dev) | |||
| 979 | struct nouveau_pm *pm = nouveau_pm(dev); | 998 | struct nouveau_pm *pm = nouveau_pm(dev); |
| 980 | 999 | ||
| 981 | if (pm->hwmon) { | 1000 | if (pm->hwmon) { |
| 982 | sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); | 1001 | sysfs_remove_group(&pm->hwmon->kobj, &hwmon_default_attrgroup); |
| 983 | sysfs_remove_group(&pm->hwmon->kobj, | 1002 | sysfs_remove_group(&pm->hwmon->kobj, &hwmon_temp_attrgroup); |
| 984 | &hwmon_pwm_fan_attrgroup); | 1003 | sysfs_remove_group(&pm->hwmon->kobj, &hwmon_pwm_fan_attrgroup); |
| 985 | sysfs_remove_group(&pm->hwmon->kobj, | 1004 | sysfs_remove_group(&pm->hwmon->kobj, &hwmon_fan_rpm_attrgroup); |
| 986 | &hwmon_fan_rpm_attrgroup); | ||
| 987 | 1005 | ||
| 988 | hwmon_device_unregister(pm->hwmon); | 1006 | hwmon_device_unregister(pm->hwmon); |
| 989 | } | 1007 | } |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 87a5a56ed358..1ddc03e51bf4 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
| @@ -479,7 +479,7 @@ nv50_display_flip_wait(void *data) | |||
| 479 | { | 479 | { |
| 480 | struct nv50_display_flip *flip = data; | 480 | struct nv50_display_flip *flip = data; |
| 481 | if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) == | 481 | if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) == |
| 482 | flip->chan->data); | 482 | flip->chan->data) |
| 483 | return true; | 483 | return true; |
| 484 | usleep_range(1, 2); | 484 | usleep_range(1, 2); |
| 485 | return false; | 485 | return false; |
| @@ -524,6 +524,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 524 | swap_interval <<= 4; | 524 | swap_interval <<= 4; |
| 525 | if (swap_interval == 0) | 525 | if (swap_interval == 0) |
| 526 | swap_interval |= 0x100; | 526 | swap_interval |= 0x100; |
| 527 | if (chan == NULL) | ||
| 528 | evo_sync(crtc->dev); | ||
| 527 | 529 | ||
| 528 | push = evo_wait(sync, 128); | 530 | push = evo_wait(sync, 128); |
| 529 | if (unlikely(push == NULL)) | 531 | if (unlikely(push == NULL)) |
| @@ -586,8 +588,6 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
| 586 | sync->addr ^= 0x10; | 588 | sync->addr ^= 0x10; |
| 587 | sync->data++; | 589 | sync->data++; |
| 588 | FIRE_RING (chan); | 590 | FIRE_RING (chan); |
| 589 | } else { | ||
| 590 | evo_sync(crtc->dev); | ||
| 591 | } | 591 | } |
| 592 | 592 | ||
| 593 | /* queue the flip */ | 593 | /* queue the flip */ |
| @@ -2276,6 +2276,7 @@ nv50_display_create(struct drm_device *dev) | |||
| 2276 | NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", | 2276 | NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", |
| 2277 | dcbe->location, dcbe->type, | 2277 | dcbe->location, dcbe->type, |
| 2278 | ffs(dcbe->or) - 1, ret); | 2278 | ffs(dcbe->or) - 1, ret); |
| 2279 | ret = 0; | ||
| 2279 | } | 2280 | } |
| 2280 | } | 2281 | } |
| 2281 | 2282 | ||
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index d4c633e12863..27769e724b6d 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c | |||
| @@ -468,13 +468,19 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 468 | (rdev->pdev->device == 0x9907) || | 468 | (rdev->pdev->device == 0x9907) || |
| 469 | (rdev->pdev->device == 0x9908) || | 469 | (rdev->pdev->device == 0x9908) || |
| 470 | (rdev->pdev->device == 0x9909) || | 470 | (rdev->pdev->device == 0x9909) || |
| 471 | (rdev->pdev->device == 0x990B) || | ||
| 472 | (rdev->pdev->device == 0x990C) || | ||
| 473 | (rdev->pdev->device == 0x990F) || | ||
| 471 | (rdev->pdev->device == 0x9910) || | 474 | (rdev->pdev->device == 0x9910) || |
| 472 | (rdev->pdev->device == 0x9917)) { | 475 | (rdev->pdev->device == 0x9917) || |
| 476 | (rdev->pdev->device == 0x9999)) { | ||
| 473 | rdev->config.cayman.max_simds_per_se = 6; | 477 | rdev->config.cayman.max_simds_per_se = 6; |
| 474 | rdev->config.cayman.max_backends_per_se = 2; | 478 | rdev->config.cayman.max_backends_per_se = 2; |
| 475 | } else if ((rdev->pdev->device == 0x9903) || | 479 | } else if ((rdev->pdev->device == 0x9903) || |
| 476 | (rdev->pdev->device == 0x9904) || | 480 | (rdev->pdev->device == 0x9904) || |
| 477 | (rdev->pdev->device == 0x990A) || | 481 | (rdev->pdev->device == 0x990A) || |
| 482 | (rdev->pdev->device == 0x990D) || | ||
| 483 | (rdev->pdev->device == 0x990E) || | ||
| 478 | (rdev->pdev->device == 0x9913) || | 484 | (rdev->pdev->device == 0x9913) || |
| 479 | (rdev->pdev->device == 0x9918)) { | 485 | (rdev->pdev->device == 0x9918)) { |
| 480 | rdev->config.cayman.max_simds_per_se = 4; | 486 | rdev->config.cayman.max_simds_per_se = 4; |
| @@ -483,6 +489,9 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 483 | (rdev->pdev->device == 0x9990) || | 489 | (rdev->pdev->device == 0x9990) || |
| 484 | (rdev->pdev->device == 0x9991) || | 490 | (rdev->pdev->device == 0x9991) || |
| 485 | (rdev->pdev->device == 0x9994) || | 491 | (rdev->pdev->device == 0x9994) || |
| 492 | (rdev->pdev->device == 0x9995) || | ||
| 493 | (rdev->pdev->device == 0x9996) || | ||
| 494 | (rdev->pdev->device == 0x999A) || | ||
| 486 | (rdev->pdev->device == 0x99A0)) { | 495 | (rdev->pdev->device == 0x99A0)) { |
| 487 | rdev->config.cayman.max_simds_per_se = 3; | 496 | rdev->config.cayman.max_simds_per_se = 3; |
| 488 | rdev->config.cayman.max_backends_per_se = 1; | 497 | rdev->config.cayman.max_backends_per_se = 1; |
| @@ -616,11 +625,22 @@ static void cayman_gpu_init(struct radeon_device *rdev) | |||
| 616 | WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); | 625 | WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); |
| 617 | WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); | 626 | WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); |
| 618 | 627 | ||
| 619 | tmp = gb_addr_config & NUM_PIPES_MASK; | 628 | if ((rdev->config.cayman.max_backends_per_se == 1) && |
| 620 | tmp = r6xx_remap_render_backend(rdev, tmp, | 629 | (rdev->flags & RADEON_IS_IGP)) { |
| 621 | rdev->config.cayman.max_backends_per_se * | 630 | if ((disabled_rb_mask & 3) == 1) { |
| 622 | rdev->config.cayman.max_shader_engines, | 631 | /* RB0 disabled, RB1 enabled */ |
| 623 | CAYMAN_MAX_BACKENDS, disabled_rb_mask); | 632 | tmp = 0x11111111; |
| 633 | } else { | ||
| 634 | /* RB1 disabled, RB0 enabled */ | ||
| 635 | tmp = 0x00000000; | ||
| 636 | } | ||
| 637 | } else { | ||
| 638 | tmp = gb_addr_config & NUM_PIPES_MASK; | ||
| 639 | tmp = r6xx_remap_render_backend(rdev, tmp, | ||
| 640 | rdev->config.cayman.max_backends_per_se * | ||
| 641 | rdev->config.cayman.max_shader_engines, | ||
| 642 | CAYMAN_MAX_BACKENDS, disabled_rb_mask); | ||
| 643 | } | ||
| 624 | WREG32(GB_BACKEND_MAP, tmp); | 644 | WREG32(GB_BACKEND_MAP, tmp); |
| 625 | 645 | ||
| 626 | cgts_tcc_disable = 0xffff0000; | 646 | cgts_tcc_disable = 0xffff0000; |
| @@ -1771,6 +1791,7 @@ int cayman_resume(struct radeon_device *rdev) | |||
| 1771 | int cayman_suspend(struct radeon_device *rdev) | 1791 | int cayman_suspend(struct radeon_device *rdev) |
| 1772 | { | 1792 | { |
| 1773 | r600_audio_fini(rdev); | 1793 | r600_audio_fini(rdev); |
| 1794 | radeon_vm_manager_fini(rdev); | ||
| 1774 | cayman_cp_enable(rdev, false); | 1795 | cayman_cp_enable(rdev, false); |
| 1775 | cayman_dma_stop(rdev); | 1796 | cayman_dma_stop(rdev); |
| 1776 | evergreen_irq_suspend(rdev); | 1797 | evergreen_irq_suspend(rdev); |
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index bedda9caadd9..6e05a2e75a46 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c | |||
| @@ -122,10 +122,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, | |||
| 122 | goto out_cleanup; | 122 | goto out_cleanup; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | /* r100 doesn't have dma engine so skip the test */ | 125 | if (rdev->asic->copy.dma) { |
| 126 | /* also, VRAM-to-VRAM test doesn't make much sense for DMA */ | ||
| 127 | /* skip it as well if domains are the same */ | ||
| 128 | if ((rdev->asic->copy.dma) && (sdomain != ddomain)) { | ||
| 129 | time = radeon_benchmark_do_move(rdev, size, saddr, daddr, | 126 | time = radeon_benchmark_do_move(rdev, size, saddr, daddr, |
| 130 | RADEON_BENCHMARK_COPY_DMA, n); | 127 | RADEON_BENCHMARK_COPY_DMA, n); |
| 131 | if (time < 0) | 128 | if (time < 0) |
| @@ -135,13 +132,15 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, | |||
| 135 | sdomain, ddomain, "dma"); | 132 | sdomain, ddomain, "dma"); |
| 136 | } | 133 | } |
| 137 | 134 | ||
| 138 | time = radeon_benchmark_do_move(rdev, size, saddr, daddr, | 135 | if (rdev->asic->copy.blit) { |
| 139 | RADEON_BENCHMARK_COPY_BLIT, n); | 136 | time = radeon_benchmark_do_move(rdev, size, saddr, daddr, |
| 140 | if (time < 0) | 137 | RADEON_BENCHMARK_COPY_BLIT, n); |
| 141 | goto out_cleanup; | 138 | if (time < 0) |
| 142 | if (time > 0) | 139 | goto out_cleanup; |
| 143 | radeon_benchmark_log_results(n, size, time, | 140 | if (time > 0) |
| 144 | sdomain, ddomain, "blit"); | 141 | radeon_benchmark_log_results(n, size, time, |
| 142 | sdomain, ddomain, "blit"); | ||
| 143 | } | ||
| 145 | 144 | ||
| 146 | out_cleanup: | 145 | out_cleanup: |
| 147 | if (sobj) { | 146 | if (sobj) { |
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index b8015913d382..fa3c56fba294 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c | |||
| @@ -99,6 +99,29 @@ static bool radeon_read_bios(struct radeon_device *rdev) | |||
| 99 | return true; | 99 | return true; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | static bool radeon_read_platform_bios(struct radeon_device *rdev) | ||
| 103 | { | ||
| 104 | uint8_t __iomem *bios; | ||
| 105 | size_t size; | ||
| 106 | |||
| 107 | rdev->bios = NULL; | ||
| 108 | |||
| 109 | bios = pci_platform_rom(rdev->pdev, &size); | ||
| 110 | if (!bios) { | ||
| 111 | return false; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | rdev->bios = kmemdup(bios, size, GFP_KERNEL); | ||
| 118 | if (rdev->bios == NULL) { | ||
| 119 | return false; | ||
| 120 | } | ||
| 121 | |||
| 122 | return true; | ||
| 123 | } | ||
| 124 | |||
| 102 | #ifdef CONFIG_ACPI | 125 | #ifdef CONFIG_ACPI |
| 103 | /* ATRM is used to get the BIOS on the discrete cards in | 126 | /* ATRM is used to get the BIOS on the discrete cards in |
| 104 | * dual-gpu systems. | 127 | * dual-gpu systems. |
| @@ -620,6 +643,9 @@ bool radeon_get_bios(struct radeon_device *rdev) | |||
| 620 | if (r == false) { | 643 | if (r == false) { |
| 621 | r = radeon_read_disabled_bios(rdev); | 644 | r = radeon_read_disabled_bios(rdev); |
| 622 | } | 645 | } |
| 646 | if (r == false) { | ||
| 647 | r = radeon_read_platform_bios(rdev); | ||
| 648 | } | ||
| 623 | if (r == false || rdev->bios == NULL) { | 649 | if (r == false || rdev->bios == NULL) { |
| 624 | DRM_ERROR("Unable to locate a BIOS ROM\n"); | 650 | DRM_ERROR("Unable to locate a BIOS ROM\n"); |
| 625 | rdev->bios = NULL; | 651 | rdev->bios = NULL; |
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 9128120da044..bafbe3216952 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c | |||
| @@ -4469,6 +4469,7 @@ int si_resume(struct radeon_device *rdev) | |||
| 4469 | 4469 | ||
| 4470 | int si_suspend(struct radeon_device *rdev) | 4470 | int si_suspend(struct radeon_device *rdev) |
| 4471 | { | 4471 | { |
| 4472 | radeon_vm_manager_fini(rdev); | ||
| 4472 | si_cp_enable(rdev, false); | 4473 | si_cp_enable(rdev, false); |
| 4473 | cayman_dma_stop(rdev); | 4474 | cayman_dma_stop(rdev); |
| 4474 | si_irq_suspend(rdev); | 4475 | si_irq_suspend(rdev); |
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index fe5cdbcf2636..b44d548c56f8 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c | |||
| @@ -61,6 +61,10 @@ static int udl_get_modes(struct drm_connector *connector) | |||
| 61 | int ret; | 61 | int ret; |
| 62 | 62 | ||
| 63 | edid = (struct edid *)udl_get_edid(udl); | 63 | edid = (struct edid *)udl_get_edid(udl); |
| 64 | if (!edid) { | ||
| 65 | drm_mode_connector_update_edid_property(connector, NULL); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 64 | 68 | ||
| 65 | /* | 69 | /* |
| 66 | * We only read the main block, but if the monitor reports extension | 70 | * We only read the main block, but if the monitor reports extension |
