1/* 2 * Copyright 2014 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 * Authors: Ben Skeggs 23 */ 24 25#include <subdev/i2c.h> 26#include <subdev/bios.h> 27#include <subdev/bios/conn.h> 28 29#include "outp.h" 30 31int 32_nvkm_output_fini(struct nouveau_object *object, bool suspend) 33{ 34 struct nvkm_output *outp = (void *)object; 35 nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend); 36 return nouveau_object_fini(&outp->base, suspend); 37} 38 39int 40_nvkm_output_init(struct nouveau_object *object) 41{ 42 struct nvkm_output *outp = (void *)object; 43 int ret = nouveau_object_init(&outp->base); 44 if (ret == 0) 45 nv_ofuncs(outp->conn)->init(nv_object(outp->conn)); 46 return 0; 47} 48 49void 50_nvkm_output_dtor(struct nouveau_object *object) 51{ 52 struct nvkm_output *outp = (void *)object; 53 list_del(&outp->head); 54 nouveau_object_ref(NULL, (void *)&outp->conn); 55 nouveau_object_destroy(&outp->base); 56} 57 58int 59nvkm_output_create_(struct nouveau_object *parent, 60 struct nouveau_object *engine, 61 struct nouveau_oclass *oclass, 62 struct dcb_output *dcbE, int index, 63 int length, void **pobject) 64{ 65 struct nouveau_bios *bios = nouveau_bios(engine); 66 struct nouveau_i2c *i2c = nouveau_i2c(parent); 67 struct nouveau_disp *disp = (void *)engine; 68 struct nvbios_connE connE; 69 struct nvkm_output *outp; 70 u8 ver, hdr; 71 u32 data; 72 int ret; 73 74 ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject); 75 outp = *pobject; 76 if (ret) 77 return ret; 78 79 outp->info = *dcbE; 80 outp->index = index; 81 outp->or = ffs(outp->info.or) - 1; 82 83 DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n", 84 dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ? 85 dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, 86 dcbE->bus, dcbE->heads); 87 88 outp->port = i2c->find(i2c, outp->info.i2c_index); 89 outp->edid = outp->port; 90 91 data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); 92 if (!data) { 93 DBG("vbios connector data not found\n"); 94 memset(&connE, 0x00, sizeof(connE)); 95 connE.type = DCB_CONNECTOR_NONE; 96 } 97 98 ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass, 99 &connE, outp->info.connector, 100 (struct nouveau_object **)&outp->conn); 101 if (ret < 0) { 102 ERR("error %d creating connector, disabling\n", ret); 103 return ret; 104 } 105 106 list_add_tail(&outp->head, &disp->outp); 107 return 0; 108} 109 110int 111_nvkm_output_ctor(struct nouveau_object *parent, 112 struct nouveau_object *engine, 113 struct nouveau_oclass *oclass, void *dcbE, u32 index, 114 struct nouveau_object **pobject) 115{ 116 struct nvkm_output *outp; 117 int ret; 118 119 ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp); 120 *pobject = nv_object(outp); 121 if (ret) 122 return ret; 123 124 return 0; 125} 126 127struct nouveau_oclass * 128nvkm_output_oclass = &(struct nvkm_output_impl) { 129 .base = { 130 .handle = 0, 131 .ofuncs = &(struct nouveau_ofuncs) { 132 .ctor = _nvkm_output_ctor, 133 .dtor = _nvkm_output_dtor, 134 .init = _nvkm_output_init, 135 .fini = _nvkm_output_fini, 136 }, 137 }, 138}.base; 139