cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

disp.c (8866B)


      1/*
      2 * Copyright 2009 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Author: Ben Skeggs
     23 */
     24
     25#include <drm/drm_crtc_helper.h>
     26
     27#include "nouveau_drv.h"
     28#include "nouveau_reg.h"
     29#include "hw.h"
     30#include "nouveau_encoder.h"
     31#include "nouveau_connector.h"
     32#include "nouveau_bo.h"
     33#include "nouveau_gem.h"
     34#include "nouveau_chan.h"
     35
     36#include <nvif/if0004.h>
     37
     38struct nouveau_connector *
     39nv04_encoder_get_connector(struct nouveau_encoder *encoder)
     40{
     41	struct drm_device *dev = to_drm_encoder(encoder)->dev;
     42	struct drm_connector *connector;
     43	struct drm_connector_list_iter conn_iter;
     44	struct nouveau_connector *nv_connector = NULL;
     45
     46	drm_connector_list_iter_begin(dev, &conn_iter);
     47	drm_for_each_connector_iter(connector, &conn_iter) {
     48		if (connector->encoder == to_drm_encoder(encoder))
     49			nv_connector = nouveau_connector(connector);
     50	}
     51	drm_connector_list_iter_end(&conn_iter);
     52
     53	return nv_connector;
     54}
     55
     56static void
     57nv04_display_fini(struct drm_device *dev, bool runtime, bool suspend)
     58{
     59	struct nouveau_drm *drm = nouveau_drm(dev);
     60	struct nv04_display *disp = nv04_display(dev);
     61	struct drm_crtc *crtc;
     62
     63	/* Disable flip completion events. */
     64	nvif_notify_put(&disp->flip);
     65
     66	/* Disable vblank interrupts. */
     67	NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
     68	if (nv_two_heads(dev))
     69		NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
     70
     71	if (!runtime)
     72		cancel_work_sync(&drm->hpd_work);
     73
     74	if (!suspend)
     75		return;
     76
     77	/* Un-pin FB and cursors so they'll be evicted to system memory. */
     78	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
     79		struct drm_framebuffer *fb = crtc->primary->fb;
     80		struct nouveau_bo *nvbo;
     81
     82		if (!fb || !fb->obj[0])
     83			continue;
     84		nvbo = nouveau_gem_object(fb->obj[0]);
     85		nouveau_bo_unpin(nvbo);
     86	}
     87
     88	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
     89		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
     90		if (nv_crtc->cursor.nvbo) {
     91			if (nv_crtc->cursor.set_offset)
     92				nouveau_bo_unmap(nv_crtc->cursor.nvbo);
     93			nouveau_bo_unpin(nv_crtc->cursor.nvbo);
     94		}
     95	}
     96}
     97
     98static int
     99nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
    100{
    101	struct nv04_display *disp = nv04_display(dev);
    102	struct nouveau_drm *drm = nouveau_drm(dev);
    103	struct nouveau_encoder *encoder;
    104	struct drm_crtc *crtc;
    105	int ret;
    106
    107	/* meh.. modeset apparently doesn't setup all the regs and depends
    108	 * on pre-existing state, for now load the state of the card *before*
    109	 * nouveau was loaded, and then do a modeset.
    110	 *
    111	 * best thing to do probably is to make save/restore routines not
    112	 * save/restore "pre-load" state, but more general so we can save
    113	 * on suspend too.
    114	 */
    115	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
    116		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
    117		nv_crtc->save(&nv_crtc->base);
    118	}
    119
    120	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
    121		encoder->enc_save(&encoder->base.base);
    122
    123	/* Enable flip completion events. */
    124	nvif_notify_get(&disp->flip);
    125
    126	if (!resume)
    127		return 0;
    128
    129	/* Re-pin FB/cursors. */
    130	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
    131		struct drm_framebuffer *fb = crtc->primary->fb;
    132		struct nouveau_bo *nvbo;
    133
    134		if (!fb || !fb->obj[0])
    135			continue;
    136		nvbo = nouveau_gem_object(fb->obj[0]);
    137		ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, true);
    138		if (ret)
    139			NV_ERROR(drm, "Could not pin framebuffer\n");
    140	}
    141
    142	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
    143		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
    144		if (!nv_crtc->cursor.nvbo)
    145			continue;
    146
    147		ret = nouveau_bo_pin(nv_crtc->cursor.nvbo,
    148				     NOUVEAU_GEM_DOMAIN_VRAM, true);
    149		if (!ret && nv_crtc->cursor.set_offset)
    150			ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
    151		if (ret)
    152			NV_ERROR(drm, "Could not pin/map cursor.\n");
    153	}
    154
    155	/* Force CLUT to get re-loaded during modeset. */
    156	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
    157		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
    158
    159		nv_crtc->lut.depth = 0;
    160	}
    161
    162	/* This should ensure we don't hit a locking problem when someone
    163	 * wakes us up via a connector.  We should never go into suspend
    164	 * while the display is on anyways.
    165	 */
    166	if (runtime)
    167		return 0;
    168
    169	/* Restore mode. */
    170	drm_helper_resume_force_mode(dev);
    171
    172	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
    173		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
    174
    175		if (!nv_crtc->cursor.nvbo)
    176			continue;
    177
    178		if (nv_crtc->cursor.set_offset)
    179			nv_crtc->cursor.set_offset(nv_crtc,
    180						   nv_crtc->cursor.nvbo->offset);
    181		nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
    182						 nv_crtc->cursor_saved_y);
    183	}
    184
    185	return 0;
    186}
    187
    188static void
    189nv04_display_destroy(struct drm_device *dev)
    190{
    191	struct nv04_display *disp = nv04_display(dev);
    192	struct nouveau_drm *drm = nouveau_drm(dev);
    193	struct nouveau_encoder *encoder;
    194	struct nouveau_crtc *nv_crtc;
    195
    196	/* Restore state */
    197	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
    198		encoder->enc_restore(&encoder->base.base);
    199
    200	list_for_each_entry(nv_crtc, &dev->mode_config.crtc_list, base.head)
    201		nv_crtc->restore(&nv_crtc->base);
    202
    203	nouveau_hw_save_vga_fonts(dev, 0);
    204
    205	nvif_notify_dtor(&disp->flip);
    206
    207	nouveau_display(dev)->priv = NULL;
    208	vfree(disp);
    209
    210	nvif_object_unmap(&drm->client.device.object);
    211}
    212
    213int
    214nv04_display_create(struct drm_device *dev)
    215{
    216	struct nouveau_drm *drm = nouveau_drm(dev);
    217	struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device);
    218	struct dcb_table *dcb = &drm->vbios.dcb;
    219	struct drm_connector *connector, *ct;
    220	struct drm_encoder *encoder;
    221	struct nouveau_encoder *nv_encoder;
    222	struct nouveau_crtc *crtc;
    223	struct nv04_display *disp;
    224	int i, ret;
    225
    226	disp = vzalloc(sizeof(*disp));
    227	if (!disp)
    228		return -ENOMEM;
    229
    230	nvif_object_map(&drm->client.device.object, NULL, 0);
    231
    232	nouveau_display(dev)->priv = disp;
    233	nouveau_display(dev)->dtor = nv04_display_destroy;
    234	nouveau_display(dev)->init = nv04_display_init;
    235	nouveau_display(dev)->fini = nv04_display_fini;
    236
    237	/* Pre-nv50 doesn't support atomic, so don't expose the ioctls */
    238	dev->driver_features &= ~DRIVER_ATOMIC;
    239
    240	/* Request page flip completion event. */
    241	if (drm->channel) {
    242		nvif_notify_ctor(&drm->channel->nvsw, "kmsFlip", nv04_flip_complete,
    243				 false, NV04_NVSW_NTFY_UEVENT,
    244				 NULL, 0, 0, &disp->flip);
    245	}
    246
    247	nouveau_hw_save_vga_fonts(dev, 1);
    248
    249	nv04_crtc_create(dev, 0);
    250	if (nv_two_heads(dev))
    251		nv04_crtc_create(dev, 1);
    252
    253	for (i = 0; i < dcb->entries; i++) {
    254		struct dcb_output *dcbent = &dcb->entry[i];
    255
    256		connector = nouveau_connector_create(dev, dcbent);
    257		if (IS_ERR(connector))
    258			continue;
    259
    260		switch (dcbent->type) {
    261		case DCB_OUTPUT_ANALOG:
    262			ret = nv04_dac_create(connector, dcbent);
    263			break;
    264		case DCB_OUTPUT_LVDS:
    265		case DCB_OUTPUT_TMDS:
    266			ret = nv04_dfp_create(connector, dcbent);
    267			break;
    268		case DCB_OUTPUT_TV:
    269			if (dcbent->location == DCB_LOC_ON_CHIP)
    270				ret = nv17_tv_create(connector, dcbent);
    271			else
    272				ret = nv04_tv_create(connector, dcbent);
    273			break;
    274		default:
    275			NV_WARN(drm, "DCB type %d not known\n", dcbent->type);
    276			continue;
    277		}
    278
    279		if (ret)
    280			continue;
    281	}
    282
    283	list_for_each_entry_safe(connector, ct,
    284				 &dev->mode_config.connector_list, head) {
    285		if (!connector->possible_encoders) {
    286			NV_WARN(drm, "%s has no encoders, removing\n",
    287				connector->name);
    288			connector->funcs->destroy(connector);
    289		}
    290	}
    291
    292	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
    293		struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
    294		struct nvkm_i2c_bus *bus =
    295			nvkm_i2c_bus_find(i2c, nv_encoder->dcb->i2c_index);
    296		nv_encoder->i2c = bus ? &bus->i2c : NULL;
    297	}
    298
    299	/* Save previous state */
    300	list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
    301		crtc->save(&crtc->base);
    302
    303	list_for_each_entry(nv_encoder, &dev->mode_config.encoder_list, base.base.head)
    304		nv_encoder->enc_save(&nv_encoder->base.base);
    305
    306	nouveau_overlay_init(dev);
    307
    308	return 0;
    309}