1*2ca47137SSimon Glass // SPDX-License-Identifier: GPL-2.0 2*2ca47137SSimon Glass /* 3*2ca47137SSimon Glass * Implementation of per-board codec beeping 4*2ca47137SSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 5*2ca47137SSimon Glass * Copyright 2018 Google LLC 6*2ca47137SSimon Glass */ 7*2ca47137SSimon Glass 8*2ca47137SSimon Glass #define LOG_CATEGORY UCLASS_SOUND 9*2ca47137SSimon Glass 10*2ca47137SSimon Glass #include <common.h> 11*2ca47137SSimon Glass #include <dm.h> 12*2ca47137SSimon Glass #include <hda_codec.h> 13*2ca47137SSimon Glass #include <pci.h> 14*2ca47137SSimon Glass #include <sound.h> 15*2ca47137SSimon Glass #include <asm/io.h> 16*2ca47137SSimon Glass #include <dt-bindings/sound/azalia.h> 17*2ca47137SSimon Glass 18*2ca47137SSimon Glass /** 19*2ca47137SSimon Glass * struct hda_regs - HDA registers 20*2ca47137SSimon Glass * 21*2ca47137SSimon Glass * https://wiki.osdev.org/Intel_High_Definition_Audio 22*2ca47137SSimon Glass * https://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html 23*2ca47137SSimon Glass */ 24*2ca47137SSimon Glass struct hda_regs { 25*2ca47137SSimon Glass u16 gcap; 26*2ca47137SSimon Glass u8 vmin; 27*2ca47137SSimon Glass u8 vmaj; 28*2ca47137SSimon Glass u16 outpay; 29*2ca47137SSimon Glass u16 inpay; 30*2ca47137SSimon Glass u32 gctl; 31*2ca47137SSimon Glass u16 wakeen; 32*2ca47137SSimon Glass u16 statests; 33*2ca47137SSimon Glass u8 reserved[0x50]; 34*2ca47137SSimon Glass u32 cmd; /* 0x60 */ 35*2ca47137SSimon Glass u32 resp; 36*2ca47137SSimon Glass u32 icii; 37*2ca47137SSimon Glass }; 38*2ca47137SSimon Glass 39*2ca47137SSimon Glass enum { 40*2ca47137SSimon Glass HDA_ICII_BUSY = BIT(0), 41*2ca47137SSimon Glass HDA_ICII_VALID = BIT(1), 42*2ca47137SSimon Glass 43*2ca47137SSimon Glass /* Common node IDs */ 44*2ca47137SSimon Glass HDA_ROOT_NODE = 0x00, 45*2ca47137SSimon Glass 46*2ca47137SSimon Glass /* HDA verbs fields */ 47*2ca47137SSimon Glass HDA_VERB_NID_S = 20, 48*2ca47137SSimon Glass HDA_VERB_VERB_S = 8, 49*2ca47137SSimon Glass HDA_VERB_PARAM_S = 0, 50*2ca47137SSimon Glass 51*2ca47137SSimon Glass HDA_VERB_GET_PARAMS = 0xf00, 52*2ca47137SSimon Glass HDA_VERB_SET_BEEP = 0x70a, 53*2ca47137SSimon Glass 54*2ca47137SSimon Glass /* GET_PARAMS parameter IDs */ 55*2ca47137SSimon Glass GET_PARAMS_NODE_COUNT = 0x04, 56*2ca47137SSimon Glass GET_PARAMS_AUDIO_GROUP_CAPS = 0x08, 57*2ca47137SSimon Glass GET_PARAMS_AUDIO_WIDGET_CAPS = 0x09, 58*2ca47137SSimon Glass 59*2ca47137SSimon Glass /* Sub-node fields */ 60*2ca47137SSimon Glass NUM_SUB_NODES_S = 0, 61*2ca47137SSimon Glass NUM_SUB_NODES_M = 0xff << NUM_SUB_NODES_S, 62*2ca47137SSimon Glass FIRST_SUB_NODE_S = 16, 63*2ca47137SSimon Glass FIRST_SUB_NODE_M = 0xff << FIRST_SUB_NODE_S, 64*2ca47137SSimon Glass 65*2ca47137SSimon Glass /* Get Audio Function Group Capabilities fields */ 66*2ca47137SSimon Glass AUDIO_GROUP_CAPS_BEEP_GEN = 0x10000, 67*2ca47137SSimon Glass 68*2ca47137SSimon Glass /* Get Audio Widget Capabilities fields */ 69*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_BEEP = 0x7, 70*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_S = 20, 71*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_M = 0xf << AUDIO_WIDGET_TYPE_S, 72*2ca47137SSimon Glass 73*2ca47137SSimon Glass BEEP_FREQ_BASE = 12000, 74*2ca47137SSimon Glass }; 75*2ca47137SSimon Glass 76*2ca47137SSimon Glass static inline uint hda_verb(uint nid, uint verb, uint param) 77*2ca47137SSimon Glass { 78*2ca47137SSimon Glass return nid << HDA_VERB_NID_S | verb << HDA_VERB_VERB_S | 79*2ca47137SSimon Glass param << HDA_VERB_PARAM_S; 80*2ca47137SSimon Glass } 81*2ca47137SSimon Glass 82*2ca47137SSimon Glass int hda_wait_for_ready(struct hda_regs *regs) 83*2ca47137SSimon Glass { 84*2ca47137SSimon Glass int timeout = 1000; /* Use a 1msec timeout */ 85*2ca47137SSimon Glass 86*2ca47137SSimon Glass while (timeout--) { 87*2ca47137SSimon Glass u32 reg32 = readl(®s->icii); 88*2ca47137SSimon Glass 89*2ca47137SSimon Glass if (!(reg32 & HDA_ICII_BUSY)) 90*2ca47137SSimon Glass return 0; 91*2ca47137SSimon Glass udelay(1); 92*2ca47137SSimon Glass } 93*2ca47137SSimon Glass 94*2ca47137SSimon Glass return -ETIMEDOUT; 95*2ca47137SSimon Glass } 96*2ca47137SSimon Glass 97*2ca47137SSimon Glass static int wait_for_response(struct hda_regs *regs, uint *response) 98*2ca47137SSimon Glass { 99*2ca47137SSimon Glass int timeout = 1000; 100*2ca47137SSimon Glass u32 reg32; 101*2ca47137SSimon Glass 102*2ca47137SSimon Glass /* Send the verb to the codec */ 103*2ca47137SSimon Glass setbits_le32(®s->icii, HDA_ICII_BUSY | HDA_ICII_VALID); 104*2ca47137SSimon Glass 105*2ca47137SSimon Glass /* Use a 1msec timeout */ 106*2ca47137SSimon Glass while (timeout--) { 107*2ca47137SSimon Glass reg32 = readl(®s->icii); 108*2ca47137SSimon Glass if ((reg32 & (HDA_ICII_VALID | HDA_ICII_BUSY)) == 109*2ca47137SSimon Glass HDA_ICII_VALID) { 110*2ca47137SSimon Glass if (response) 111*2ca47137SSimon Glass *response = readl(®s->resp); 112*2ca47137SSimon Glass return 0; 113*2ca47137SSimon Glass } 114*2ca47137SSimon Glass udelay(1); 115*2ca47137SSimon Glass } 116*2ca47137SSimon Glass 117*2ca47137SSimon Glass return -ETIMEDOUT; 118*2ca47137SSimon Glass } 119*2ca47137SSimon Glass 120*2ca47137SSimon Glass int hda_wait_for_valid(struct hda_regs *regs) 121*2ca47137SSimon Glass { 122*2ca47137SSimon Glass return wait_for_response(regs, NULL); 123*2ca47137SSimon Glass } 124*2ca47137SSimon Glass 125*2ca47137SSimon Glass static int set_bits(void *port, u32 mask, u32 val) 126*2ca47137SSimon Glass { 127*2ca47137SSimon Glass u32 reg32; 128*2ca47137SSimon Glass int count; 129*2ca47137SSimon Glass 130*2ca47137SSimon Glass /* Write (val & mask) to port */ 131*2ca47137SSimon Glass clrsetbits_le32(port, mask, val); 132*2ca47137SSimon Glass 133*2ca47137SSimon Glass /* Wait for readback of register to match what was just written to it */ 134*2ca47137SSimon Glass count = 50; 135*2ca47137SSimon Glass do { 136*2ca47137SSimon Glass /* Wait 1ms based on BKDG wait time */ 137*2ca47137SSimon Glass mdelay(1); 138*2ca47137SSimon Glass reg32 = readl(port) & mask; 139*2ca47137SSimon Glass } while (reg32 != val && --count); 140*2ca47137SSimon Glass 141*2ca47137SSimon Glass /* Timeout occurred */ 142*2ca47137SSimon Glass if (!count) 143*2ca47137SSimon Glass return -ETIMEDOUT; 144*2ca47137SSimon Glass 145*2ca47137SSimon Glass return 0; 146*2ca47137SSimon Glass } 147*2ca47137SSimon Glass 148*2ca47137SSimon Glass int hda_codec_detect(struct hda_regs *regs) 149*2ca47137SSimon Glass { 150*2ca47137SSimon Glass uint reg8; 151*2ca47137SSimon Glass 152*2ca47137SSimon Glass /* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */ 153*2ca47137SSimon Glass if (set_bits(®s->gctl, 1, 1)) 154*2ca47137SSimon Glass goto no_codec; 155*2ca47137SSimon Glass 156*2ca47137SSimon Glass /* Write back the value once reset bit is set */ 157*2ca47137SSimon Glass writew(readw(®s->gcap), ®s->gcap); 158*2ca47137SSimon Glass 159*2ca47137SSimon Glass /* Read in Codec location */ 160*2ca47137SSimon Glass reg8 = readb(®s->statests) & 0xf; 161*2ca47137SSimon Glass if (!reg8) 162*2ca47137SSimon Glass goto no_codec; 163*2ca47137SSimon Glass 164*2ca47137SSimon Glass return reg8; 165*2ca47137SSimon Glass 166*2ca47137SSimon Glass no_codec: 167*2ca47137SSimon Glass /* Codec Not found - put HDA back in reset */ 168*2ca47137SSimon Glass set_bits(®s->gctl, 1, 0); 169*2ca47137SSimon Glass log_debug("No codec\n"); 170*2ca47137SSimon Glass 171*2ca47137SSimon Glass return 0; 172*2ca47137SSimon Glass } 173*2ca47137SSimon Glass 174*2ca47137SSimon Glass static int find_verb_data(struct udevice *dev, uint id, ofnode *nodep) 175*2ca47137SSimon Glass { 176*2ca47137SSimon Glass ofnode parent = dev_read_subnode(dev, "codecs"); 177*2ca47137SSimon Glass ofnode node; 178*2ca47137SSimon Glass u32 vendor_id, device_id; 179*2ca47137SSimon Glass 180*2ca47137SSimon Glass ofnode_for_each_subnode(node, parent) { 181*2ca47137SSimon Glass if (ofnode_read_u32(node, "vendor-id", &vendor_id) || 182*2ca47137SSimon Glass ofnode_read_u32(node, "device-id", &device_id)) { 183*2ca47137SSimon Glass log_debug("Cannot get IDs for '%s'\n", 184*2ca47137SSimon Glass ofnode_get_name(node)); 185*2ca47137SSimon Glass return -EINVAL; 186*2ca47137SSimon Glass } 187*2ca47137SSimon Glass if (id != (vendor_id << 16 | device_id)) { 188*2ca47137SSimon Glass log_debug("Skip codec node '%s' for %08x\n", 189*2ca47137SSimon Glass ofnode_get_name(node), id); 190*2ca47137SSimon Glass continue; 191*2ca47137SSimon Glass } 192*2ca47137SSimon Glass 193*2ca47137SSimon Glass log_debug("Found codec node '%s' for %08x\n", 194*2ca47137SSimon Glass ofnode_get_name(node), id); 195*2ca47137SSimon Glass *nodep = node; 196*2ca47137SSimon Glass return 0; 197*2ca47137SSimon Glass } 198*2ca47137SSimon Glass 199*2ca47137SSimon Glass return -ENOENT; 200*2ca47137SSimon Glass } 201*2ca47137SSimon Glass 202*2ca47137SSimon Glass static int send_verbs(ofnode node, const char *prop_name, struct hda_regs *regs) 203*2ca47137SSimon Glass { 204*2ca47137SSimon Glass int ret, verb_size, i; 205*2ca47137SSimon Glass const u32 *verb; 206*2ca47137SSimon Glass 207*2ca47137SSimon Glass verb = ofnode_get_property(node, prop_name, &verb_size); 208*2ca47137SSimon Glass if (verb_size < 0) { 209*2ca47137SSimon Glass log_debug("No verb data\n"); 210*2ca47137SSimon Glass return -EINVAL; 211*2ca47137SSimon Glass } 212*2ca47137SSimon Glass log_debug("verb_size: %d\n", verb_size); 213*2ca47137SSimon Glass 214*2ca47137SSimon Glass for (i = 0; i < verb_size / sizeof(*verb); i++) { 215*2ca47137SSimon Glass ret = hda_wait_for_ready(regs); 216*2ca47137SSimon Glass if (ret) { 217*2ca47137SSimon Glass log_debug(" codec ready timeout\n"); 218*2ca47137SSimon Glass return ret; 219*2ca47137SSimon Glass } 220*2ca47137SSimon Glass 221*2ca47137SSimon Glass writel(fdt32_to_cpu(verb[i]), ®s->cmd); 222*2ca47137SSimon Glass 223*2ca47137SSimon Glass ret = hda_wait_for_valid(regs); 224*2ca47137SSimon Glass if (ret) { 225*2ca47137SSimon Glass log_debug(" codec valid timeout\n"); 226*2ca47137SSimon Glass return ret; 227*2ca47137SSimon Glass } 228*2ca47137SSimon Glass } 229*2ca47137SSimon Glass 230*2ca47137SSimon Glass return 0; 231*2ca47137SSimon Glass } 232*2ca47137SSimon Glass 233*2ca47137SSimon Glass static int codec_init(struct udevice *dev, struct hda_regs *regs, uint addr) 234*2ca47137SSimon Glass { 235*2ca47137SSimon Glass ofnode node; 236*2ca47137SSimon Glass uint id; 237*2ca47137SSimon Glass int ret; 238*2ca47137SSimon Glass 239*2ca47137SSimon Glass log_debug("Initializing codec #%d\n", addr); 240*2ca47137SSimon Glass ret = hda_wait_for_ready(regs); 241*2ca47137SSimon Glass if (ret) { 242*2ca47137SSimon Glass log_debug(" codec not ready\n"); 243*2ca47137SSimon Glass return ret; 244*2ca47137SSimon Glass } 245*2ca47137SSimon Glass 246*2ca47137SSimon Glass /* Read the codec's vendor ID */ 247*2ca47137SSimon Glass writel(addr << AZALIA_CODEC_SHIFT | 248*2ca47137SSimon Glass AZALIA_OPCODE_READ_PARAM << AZALIA_VERB_SHIFT | 249*2ca47137SSimon Glass AZALIA_PARAM_VENDOR_ID, ®s->cmd); 250*2ca47137SSimon Glass ret = hda_wait_for_valid(regs); 251*2ca47137SSimon Glass if (ret) { 252*2ca47137SSimon Glass log_debug(" codec not valid\n"); 253*2ca47137SSimon Glass return ret; 254*2ca47137SSimon Glass } 255*2ca47137SSimon Glass 256*2ca47137SSimon Glass id = readl(®s->resp); 257*2ca47137SSimon Glass log_debug("codec vid/did: %08x\n", id); 258*2ca47137SSimon Glass ret = find_verb_data(dev, id, &node); 259*2ca47137SSimon Glass if (ret) { 260*2ca47137SSimon Glass log_debug("No verb (err=%d)\n", ret); 261*2ca47137SSimon Glass return ret; 262*2ca47137SSimon Glass } 263*2ca47137SSimon Glass ret = send_verbs(node, "verbs", regs); 264*2ca47137SSimon Glass if (ret) { 265*2ca47137SSimon Glass log_debug("failed to send verbs (err=%d)\n", ret); 266*2ca47137SSimon Glass return ret; 267*2ca47137SSimon Glass } 268*2ca47137SSimon Glass log_debug("verb loaded\n"); 269*2ca47137SSimon Glass 270*2ca47137SSimon Glass return 0; 271*2ca47137SSimon Glass } 272*2ca47137SSimon Glass 273*2ca47137SSimon Glass int hda_codecs_init(struct udevice *dev, struct hda_regs *regs, u32 codec_mask) 274*2ca47137SSimon Glass { 275*2ca47137SSimon Glass int ret; 276*2ca47137SSimon Glass int i; 277*2ca47137SSimon Glass 278*2ca47137SSimon Glass for (i = 3; i >= 0; i--) { 279*2ca47137SSimon Glass if (codec_mask & (1 << i)) { 280*2ca47137SSimon Glass ret = codec_init(dev, regs, i); 281*2ca47137SSimon Glass if (ret) 282*2ca47137SSimon Glass return ret; 283*2ca47137SSimon Glass } 284*2ca47137SSimon Glass } 285*2ca47137SSimon Glass 286*2ca47137SSimon Glass ret = send_verbs(dev_ofnode(dev), "beep-verbs", regs); 287*2ca47137SSimon Glass if (ret) { 288*2ca47137SSimon Glass log_debug("failed to send beep verbs (err=%d)\n", ret); 289*2ca47137SSimon Glass return ret; 290*2ca47137SSimon Glass } 291*2ca47137SSimon Glass log_debug("beep verbs loaded\n"); 292*2ca47137SSimon Glass 293*2ca47137SSimon Glass return 0; 294*2ca47137SSimon Glass } 295*2ca47137SSimon Glass 296*2ca47137SSimon Glass /** 297*2ca47137SSimon Glass * exec_verb() - Write a verb to the codec 298*2ca47137SSimon Glass * 299*2ca47137SSimon Glass * @regs: HDA registers 300*2ca47137SSimon Glass * @val: Command to write 301*2ca47137SSimon Glass * @response: Set to response from codec 302*2ca47137SSimon Glass * @return 0 if OK, -ve on error 303*2ca47137SSimon Glass */ 304*2ca47137SSimon Glass static int exec_verb(struct hda_regs *regs, uint val, uint *response) 305*2ca47137SSimon Glass { 306*2ca47137SSimon Glass int ret; 307*2ca47137SSimon Glass 308*2ca47137SSimon Glass ret = hda_wait_for_ready(regs); 309*2ca47137SSimon Glass if (ret) 310*2ca47137SSimon Glass return ret; 311*2ca47137SSimon Glass 312*2ca47137SSimon Glass writel(val, ®s->cmd); 313*2ca47137SSimon Glass 314*2ca47137SSimon Glass return wait_for_response(regs, response); 315*2ca47137SSimon Glass } 316*2ca47137SSimon Glass 317*2ca47137SSimon Glass /** 318*2ca47137SSimon Glass * get_subnode_info() - Get subnode information 319*2ca47137SSimon Glass * 320*2ca47137SSimon Glass * @regs: HDA registers 321*2ca47137SSimon Glass * @nid: Parent node ID to check 322*2ca47137SSimon Glass * @num_sub_nodesp: Returns number of subnodes 323*2ca47137SSimon Glass * @start_sub_node_nidp: Returns start subnode number 324*2ca47137SSimon Glass * @return 0 if OK, -ve on error 325*2ca47137SSimon Glass */ 326*2ca47137SSimon Glass static int get_subnode_info(struct hda_regs *regs, uint nid, 327*2ca47137SSimon Glass uint *num_sub_nodesp, uint *start_sub_node_nidp) 328*2ca47137SSimon Glass { 329*2ca47137SSimon Glass uint response; 330*2ca47137SSimon Glass int ret; 331*2ca47137SSimon Glass 332*2ca47137SSimon Glass ret = exec_verb(regs, hda_verb(nid, HDA_VERB_GET_PARAMS, 333*2ca47137SSimon Glass GET_PARAMS_NODE_COUNT), 334*2ca47137SSimon Glass &response); 335*2ca47137SSimon Glass if (ret < 0) { 336*2ca47137SSimon Glass printf("Audio: Error reading sub-node info %d\n", nid); 337*2ca47137SSimon Glass return ret; 338*2ca47137SSimon Glass } 339*2ca47137SSimon Glass 340*2ca47137SSimon Glass *num_sub_nodesp = (response & NUM_SUB_NODES_M) >> NUM_SUB_NODES_S; 341*2ca47137SSimon Glass *start_sub_node_nidp = (response & FIRST_SUB_NODE_M) >> 342*2ca47137SSimon Glass FIRST_SUB_NODE_S; 343*2ca47137SSimon Glass 344*2ca47137SSimon Glass return 0; 345*2ca47137SSimon Glass } 346*2ca47137SSimon Glass 347*2ca47137SSimon Glass /** 348*2ca47137SSimon Glass * find_beep_node_in_group() - Finds the beeping node 349*2ca47137SSimon Glass * 350*2ca47137SSimon Glass * Searches the audio group for a node that supports beeping 351*2ca47137SSimon Glass * 352*2ca47137SSimon Glass * @regs: HDA registers 353*2ca47137SSimon Glass * @group_nid: Group node ID to check 354*2ca47137SSimon Glass * @return 0 if OK, -ve on error 355*2ca47137SSimon Glass */ 356*2ca47137SSimon Glass static uint find_beep_node_in_group(struct hda_regs *regs, uint group_nid) 357*2ca47137SSimon Glass { 358*2ca47137SSimon Glass uint node_count = 0; 359*2ca47137SSimon Glass uint current_nid = 0; 360*2ca47137SSimon Glass uint response; 361*2ca47137SSimon Glass uint end_nid; 362*2ca47137SSimon Glass int ret; 363*2ca47137SSimon Glass 364*2ca47137SSimon Glass ret = get_subnode_info(regs, group_nid, &node_count, ¤t_nid); 365*2ca47137SSimon Glass if (ret < 0) 366*2ca47137SSimon Glass return 0; 367*2ca47137SSimon Glass 368*2ca47137SSimon Glass end_nid = current_nid + node_count; 369*2ca47137SSimon Glass while (current_nid < end_nid) { 370*2ca47137SSimon Glass ret = exec_verb(regs, 371*2ca47137SSimon Glass hda_verb(current_nid, HDA_VERB_GET_PARAMS, 372*2ca47137SSimon Glass GET_PARAMS_AUDIO_WIDGET_CAPS), 373*2ca47137SSimon Glass &response); 374*2ca47137SSimon Glass if (ret < 0) { 375*2ca47137SSimon Glass printf("Audio: Error reading widget caps\n"); 376*2ca47137SSimon Glass return 0; 377*2ca47137SSimon Glass } 378*2ca47137SSimon Glass 379*2ca47137SSimon Glass if ((response & AUDIO_WIDGET_TYPE_M) >> AUDIO_WIDGET_TYPE_S == 380*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_BEEP) 381*2ca47137SSimon Glass return current_nid; 382*2ca47137SSimon Glass 383*2ca47137SSimon Glass current_nid++; 384*2ca47137SSimon Glass } 385*2ca47137SSimon Glass 386*2ca47137SSimon Glass return 0; /* no beep node found */ 387*2ca47137SSimon Glass } 388*2ca47137SSimon Glass 389*2ca47137SSimon Glass /** 390*2ca47137SSimon Glass * audio_group_has_beep_node() - Check if group has a beep node 391*2ca47137SSimon Glass * 392*2ca47137SSimon Glass * Checks if the given audio group contains a beep generator 393*2ca47137SSimon Glass * @regs: HDA registers 394*2ca47137SSimon Glass * @nid: Node ID to check 395*2ca47137SSimon Glass * @return 0 if OK, -ve on error 396*2ca47137SSimon Glass */ 397*2ca47137SSimon Glass static int audio_group_has_beep_node(struct hda_regs *regs, uint nid) 398*2ca47137SSimon Glass { 399*2ca47137SSimon Glass uint response; 400*2ca47137SSimon Glass int ret; 401*2ca47137SSimon Glass 402*2ca47137SSimon Glass ret = exec_verb(regs, hda_verb(nid, HDA_VERB_GET_PARAMS, 403*2ca47137SSimon Glass GET_PARAMS_AUDIO_GROUP_CAPS), 404*2ca47137SSimon Glass &response); 405*2ca47137SSimon Glass if (ret < 0) { 406*2ca47137SSimon Glass printf("Audio: Error reading audio group caps %d\n", nid); 407*2ca47137SSimon Glass return 0; 408*2ca47137SSimon Glass } 409*2ca47137SSimon Glass 410*2ca47137SSimon Glass return !!(response & AUDIO_GROUP_CAPS_BEEP_GEN); 411*2ca47137SSimon Glass } 412*2ca47137SSimon Glass 413*2ca47137SSimon Glass /** 414*2ca47137SSimon Glass * get_hda_beep_nid() - Finds the node ID of the beep node 415*2ca47137SSimon Glass * 416*2ca47137SSimon Glass * Finds the nid of the beep node if it exists. Starts at the root node, for 417*2ca47137SSimon Glass * each sub-node checks if the group contains a beep node. If the group 418*2ca47137SSimon Glass * contains a beep node, polls each node in the group until it is found. 419*2ca47137SSimon Glass * 420*2ca47137SSimon Glass * If the device has a intel,beep-nid property, the value of that is used 421*2ca47137SSimon Glass * instead. 422*2ca47137SSimon Glass * 423*2ca47137SSimon Glass * @dev: Sound device 424*2ca47137SSimon Glass * @return Node ID >0 if found, -ve error code otherwise 425*2ca47137SSimon Glass */ 426*2ca47137SSimon Glass static int get_hda_beep_nid(struct udevice *dev) 427*2ca47137SSimon Glass { 428*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev); 429*2ca47137SSimon Glass uint current_nid = 0; 430*2ca47137SSimon Glass uint node_count = 0; 431*2ca47137SSimon Glass uint end_nid; 432*2ca47137SSimon Glass int ret; 433*2ca47137SSimon Glass 434*2ca47137SSimon Glass /* If the field exists, use the beep nid set in the fdt */ 435*2ca47137SSimon Glass ret = dev_read_u32(dev, "intel,beep-nid", ¤t_nid); 436*2ca47137SSimon Glass if (!ret) 437*2ca47137SSimon Glass return current_nid; 438*2ca47137SSimon Glass 439*2ca47137SSimon Glass ret = get_subnode_info(priv->regs, HDA_ROOT_NODE, &node_count, 440*2ca47137SSimon Glass ¤t_nid); 441*2ca47137SSimon Glass if (ret < 0) 442*2ca47137SSimon Glass return ret; 443*2ca47137SSimon Glass 444*2ca47137SSimon Glass end_nid = current_nid + node_count; 445*2ca47137SSimon Glass while (current_nid < end_nid) { 446*2ca47137SSimon Glass if (audio_group_has_beep_node(priv->regs, current_nid)) 447*2ca47137SSimon Glass return find_beep_node_in_group(priv->regs, 448*2ca47137SSimon Glass current_nid); 449*2ca47137SSimon Glass current_nid++; 450*2ca47137SSimon Glass } 451*2ca47137SSimon Glass /* no beep node found */ 452*2ca47137SSimon Glass 453*2ca47137SSimon Glass return -ENOENT; 454*2ca47137SSimon Glass } 455*2ca47137SSimon Glass 456*2ca47137SSimon Glass /** 457*2ca47137SSimon Glass * set_beep_divisor() - Sets the beep divisor to set the pitch 458*2ca47137SSimon Glass * 459*2ca47137SSimon Glass * @priv: Device's private data 460*2ca47137SSimon Glass * @divider: Divider value (0 to disable the beep) 461*2ca47137SSimon Glass * @return 0 if OK, -ve on error 462*2ca47137SSimon Glass */ 463*2ca47137SSimon Glass static int set_beep_divisor(struct hda_codec_priv *priv, uint divider) 464*2ca47137SSimon Glass { 465*2ca47137SSimon Glass return exec_verb(priv->regs, 466*2ca47137SSimon Glass hda_verb(priv->beep_nid, HDA_VERB_SET_BEEP, divider), 467*2ca47137SSimon Glass NULL); 468*2ca47137SSimon Glass } 469*2ca47137SSimon Glass 470*2ca47137SSimon Glass int hda_codec_init(struct udevice *dev) 471*2ca47137SSimon Glass { 472*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev); 473*2ca47137SSimon Glass ulong base_addr; 474*2ca47137SSimon Glass 475*2ca47137SSimon Glass base_addr = dm_pci_read_bar32(dev, 0); 476*2ca47137SSimon Glass log_debug("base = %08lx\n", base_addr); 477*2ca47137SSimon Glass if (!base_addr) 478*2ca47137SSimon Glass return -EINVAL; 479*2ca47137SSimon Glass 480*2ca47137SSimon Glass priv->regs = (struct hda_regs *)base_addr; 481*2ca47137SSimon Glass 482*2ca47137SSimon Glass return 0; 483*2ca47137SSimon Glass } 484*2ca47137SSimon Glass 485*2ca47137SSimon Glass int hda_codec_finish_init(struct udevice *dev) 486*2ca47137SSimon Glass { 487*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev); 488*2ca47137SSimon Glass int ret; 489*2ca47137SSimon Glass 490*2ca47137SSimon Glass ret = get_hda_beep_nid(dev); 491*2ca47137SSimon Glass if (ret <= 0) { 492*2ca47137SSimon Glass log_warning("Could not find beep NID (err=%d)\n", ret); 493*2ca47137SSimon Glass return ret ? ret : -ENOENT; 494*2ca47137SSimon Glass } 495*2ca47137SSimon Glass priv->beep_nid = ret; 496*2ca47137SSimon Glass 497*2ca47137SSimon Glass return 0; 498*2ca47137SSimon Glass } 499*2ca47137SSimon Glass 500*2ca47137SSimon Glass int hda_codec_start_beep(struct udevice *dev, int frequency_hz) 501*2ca47137SSimon Glass { 502*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev); 503*2ca47137SSimon Glass uint divider_val; 504*2ca47137SSimon Glass 505*2ca47137SSimon Glass if (!priv->beep_nid) { 506*2ca47137SSimon Glass log_err("Failed to find a beep-capable node\n"); 507*2ca47137SSimon Glass return -ENOENT; 508*2ca47137SSimon Glass } 509*2ca47137SSimon Glass 510*2ca47137SSimon Glass if (!frequency_hz) 511*2ca47137SSimon Glass divider_val = 0; /* off */ 512*2ca47137SSimon Glass else if (frequency_hz > BEEP_FREQ_BASE) 513*2ca47137SSimon Glass divider_val = 1; 514*2ca47137SSimon Glass else if (frequency_hz < BEEP_FREQ_BASE / 0xff) 515*2ca47137SSimon Glass divider_val = 0xff; 516*2ca47137SSimon Glass else 517*2ca47137SSimon Glass divider_val = 0xff & (BEEP_FREQ_BASE / frequency_hz); 518*2ca47137SSimon Glass 519*2ca47137SSimon Glass return set_beep_divisor(priv, divider_val); 520*2ca47137SSimon Glass } 521*2ca47137SSimon Glass 522*2ca47137SSimon Glass int hda_codec_stop_beep(struct udevice *dev) 523*2ca47137SSimon Glass { 524*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev); 525*2ca47137SSimon Glass 526*2ca47137SSimon Glass return set_beep_divisor(priv, 0); 527*2ca47137SSimon Glass } 528*2ca47137SSimon Glass 529*2ca47137SSimon Glass static const struct sound_ops hda_codec_ops = { 530*2ca47137SSimon Glass .setup = hda_codec_finish_init, 531*2ca47137SSimon Glass .start_beep = hda_codec_start_beep, 532*2ca47137SSimon Glass .stop_beep = hda_codec_stop_beep, 533*2ca47137SSimon Glass }; 534*2ca47137SSimon Glass 535*2ca47137SSimon Glass U_BOOT_DRIVER(hda_codec) = { 536*2ca47137SSimon Glass .name = "hda_codec", 537*2ca47137SSimon Glass .id = UCLASS_SOUND, 538*2ca47137SSimon Glass .ops = &hda_codec_ops, 539*2ca47137SSimon Glass .priv_auto_alloc_size = sizeof(struct hda_codec_priv), 540*2ca47137SSimon Glass .probe = hda_codec_init, 541*2ca47137SSimon Glass }; 542*2ca47137SSimon Glass 543*2ca47137SSimon Glass static struct pci_device_id hda_supported[] = { 544*2ca47137SSimon Glass { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_HDA}, 545*2ca47137SSimon Glass { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA}, 546*2ca47137SSimon Glass { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 547*2ca47137SSimon Glass PCI_DEVICE_ID_INTEL_WILDCATPOINT_HDA) }, 548*2ca47137SSimon Glass 549*2ca47137SSimon Glass /* 550*2ca47137SSimon Glass * Note this driver is not necessarily generic, but it attempts to 551*2ca47137SSimon Glass * support any codec in the hd-audio class 552*2ca47137SSimon Glass */ 553*2ca47137SSimon Glass { PCI_DEVICE_CLASS(PCI_CLASS_MULTIMEDIA_HD_AUDIO, 0xffffff) }, 554*2ca47137SSimon Glass }; 555*2ca47137SSimon Glass 556*2ca47137SSimon Glass U_BOOT_PCI_DEVICE(hda_codec, hda_supported); 557