Received: by 10.192.165.148 with SMTP id m20csp4565492imm; Tue, 8 May 2018 10:24:31 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpUi8kYfKYiyqnL2UzmRr/ganpq1hvxjdJ4cIJIU1hihG/Mh7O245WCHqSwew13QEhokALj X-Received: by 2002:a63:696:: with SMTP id 144-v6mr2802623pgg.212.1525800271819; Tue, 08 May 2018 10:24:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525800271; cv=none; d=google.com; s=arc-20160816; b=efWupMSDH5735qbaVgq36BgzhFlJ1IYonLA+716WY7X+uGsRFruGM1JBUFwABY+G/S iuSShTENhQ2xwrSj9xxUr4uRb6tBHzBACWwKdZ9aaegKxWHbkUypfrzzXVmSamsnNjx4 S/VVzBxekWvFjpDazCVY9G/PMiK3eNAN3zDiZRJFUu4yQAyngFYC1kHjlcF0Y47PReVC sNEneYx0ftv5MoY/9N8A5vvtgyhUaS7yTrbVaTcx7dDNXn/q3rwisPx/isuCSqXifz1Q abSNXHH1JubOJrgfysEvW4GyW1V24ltS7LicqnIhRfNbozQc0ty3sVpSlRkP8BAgWh26 X9RQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:to:references:in-reply-to:message-id:date :subject:cc:from:dkim-signature:arc-authentication-results; bh=aaJfVKzh9wX8gmBNGTKd2rQWN3ddQlDc2IyG8CpGWwU=; b=PPgvelKsJXGiccU/kg/ievbDkMXXpCJ+9dkMvhrHvHZTmEtqgKIQRS5JHoCn/cq7+Y nSGVWKtj6xzBeGVZvBxFWq5x4+8tFxuOEdKc33rqqsmAGFWcKRcBWDeOq+3WVuM8OA/3 QaThIlRw5Z/KhpG+NLgPMAJdvI9gnAZdqkHDJwEBC09Ahb3KMY3hPB1LNmqm2F2BZviy naHzjnhvnbVCfVzfT6jXjIjUHOzUzkT9rh8x35u7HG72tTtXDY82SdnVZoQa1EHlxN1m FBb8pYwjIBujzx8y6bTtAed3+Y0oRc0eahJWFlfrgAIrrqj7I0hoPKNN9NinINphWues QrwA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=gfm+dlDJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u3si26485036pfj.58.2018.05.08.10.24.17; Tue, 08 May 2018 10:24:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=gfm+dlDJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932518AbeEHRU6 (ORCPT + 99 others); Tue, 8 May 2018 13:20:58 -0400 Received: from mail-io0-f195.google.com ([209.85.223.195]:41368 "EHLO mail-io0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932204AbeEHRU4 (ORCPT ); Tue, 8 May 2018 13:20:56 -0400 Received: by mail-io0-f195.google.com with SMTP id e12-v6so39352177iob.8 for ; Tue, 08 May 2018 10:20:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=aaJfVKzh9wX8gmBNGTKd2rQWN3ddQlDc2IyG8CpGWwU=; b=gfm+dlDJTFhoeezTZEBcDtwXg+CBbdOWprrTCOXhxtthqXsFt0684KCM/L+Ma6jZTf NmzNnYQllA+6KaIO2rIv03NBi/AKbAERFIdnOm6DoNXEH+7VVUlmBhL0kXi9ukxKmDfA z58W6M/ZBzfwM8qZW97EJ79Aup2sLI0L4BktonpkgN+1gai5DLmwlqr/r9G3nTnnrGEo V4wrEtxPVtcEAK5ExAFA8Yp3VLTvAf/8s2H6MLHgDrpXV3+ag6McJwm0dG2lk5+g+MgK NE83c37ikSlDQOKvzpmMztHkwm/+LGAgaoNEouWf67LtT2b2l8O6Fv3q3vY2/nJFFkUJ HbPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=aaJfVKzh9wX8gmBNGTKd2rQWN3ddQlDc2IyG8CpGWwU=; b=RiCTBqxhnvY91Yv2VHH5B5kzMopbUobV8yydQ6e2Y//3HbJoKgTEZv1nVzYAlnQBp7 fALO4qQWPGbba9KlFK6kvX9ICXHJQLYV6Y9KYwG4WUv3fCeKjK420TLz1hLxj6O2mAZk dL49I7nMLGxC1yVhnKdT8JLyYt7eldp+mjj+pWkj30UCqR3GH4qWv5tNsz+XTW3RWlrH X7zyYH5UWf5x7+Kh+A1AmiDfK2zAa8jgc7kyRL9QFPiFrbmUVIRa9EIWSjIKDoJr6Gst HWklJ2ajcw78uUMjgUkdTjs9teW71YxvkHAF5iPrNM0nOh36NLDY9LUkE/Y7mXMYEQCW x60w== X-Gm-Message-State: ALQs6tAZisa4hU0Zls/Zz0hH21pLnyrec2ywIZt7bI30J0Y6uQV42KQr gGZZFi3aJVT1KxL4jbPX2pk= X-Received: by 2002:a6b:b513:: with SMTP id e19-v6mr42063583iof.267.1525800055126; Tue, 08 May 2018 10:20:55 -0700 (PDT) Received: from localhost.localdomain ([2605:a000:1316:4462:80cc:335d:e307:b5cb]) by smtp.googlemail.com with ESMTPSA id k62-v6sm13160209ioo.23.2018.05.08.10.20.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 08 May 2018 10:20:54 -0700 (PDT) From: Connor McAdams Cc: o-takashi@sakamocchi.jp, Connor McAdams , Jaroslav Kysela , Takashi Iwai , =?UTF-8?q?J=C3=A9r=C3=A9my=20Lefaure?= , alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 05/13] ALSA: hda/ca0132: add extra init functions for r3di + sbz Date: Tue, 8 May 2018 13:20:05 -0400 Message-Id: <1525800015-2920-6-git-send-email-conmanx360@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1525800015-2920-1-git-send-email-conmanx360@gmail.com> References: <1525800015-2920-1-git-send-email-conmanx360@gmail.com> To: unlisted-recipients:; (no To-header on input) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds extra init functions for the Sound Blaster Z and Recon3Di. It also adds more checks to make sure that the DSP isn't downloaded twice on startup, by checking if the dsp_state is already set to DSP_DOWNLOADED. It also adds the ability to re-download the DSP on a resume. It also changes the init verbs table to apply to all codecs, and takes the two specific end verbs and puts them into a separate function in ca0132_init instead. GPIO functions are also added. Signed-off-by: Connor McAdams --- sound/pci/hda/patch_ca0132.c | 273 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 265 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 5cda7a5..5002311 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -710,6 +710,7 @@ struct ca0132_spec { const struct hda_verb *base_init_verbs; const struct hda_verb *base_exit_verbs; const struct hda_verb *chip_init_verbs; + const struct hda_verb *sbz_init_verbs; struct hda_verb *spec_init_verbs; struct auto_pin_cfg autocfg; @@ -743,6 +744,7 @@ struct ca0132_spec { unsigned int scp_resp_data[4]; unsigned int scp_resp_count; bool alt_firmware_present; + bool dsp_reload; /* mixer and effects related */ unsigned char dmic_ctl; @@ -2740,6 +2742,59 @@ static bool dspload_wait_loaded(struct hda_codec *codec) } /* + * Setup GPIO for the other variants of Core3D. + */ + +/* + * Sets up the GPIO pins so that they are discoverable. If this isn't done, + * the card shows as having no GPIO pins. + */ +static void ca0132_gpio_init(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (spec->quirk) { + case QUIRK_SBZ: + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); + snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23); + break; + case QUIRK_R3DI: + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B); + break; + } + +} + +/* Sets the GPIO for audio output. */ +static void ca0132_gpio_setup(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (spec->quirk) { + case QUIRK_SBZ: + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DIRECTION, 0x07); + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_MASK, 0x07); + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0x04); + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0x06); + break; + case QUIRK_R3DI: + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DIRECTION, 0x1E); + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_MASK, 0x1F); + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0x0C); + break; + } +} + +/* * PCM callbacks */ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -4490,11 +4545,14 @@ static void ca0132_download_dsp(struct hda_codec *codec) return; /* don't retry failures */ chipio_enable_clocks(codec); - spec->dsp_state = DSP_DOWNLOADING; - if (!ca0132_download_dsp_images(codec)) - spec->dsp_state = DSP_DOWNLOAD_FAILED; - else - spec->dsp_state = DSP_DOWNLOADED; + if (spec->dsp_state != DSP_DOWNLOADED) { + spec->dsp_state = DSP_DOWNLOADING; + + if (!ca0132_download_dsp_images(codec)) + spec->dsp_state = DSP_DOWNLOAD_FAILED; + else + spec->dsp_state = DSP_DOWNLOADED; + } if (spec->dsp_state == DSP_DOWNLOADED) ca0132_set_dsp_msr(codec, true); @@ -4569,6 +4627,7 @@ static struct hda_verb ca0132_base_exit_verbs[] = { }; /* Other verbs tables. Sends after DSP download. */ + static struct hda_verb ca0132_init_verbs0[] = { /* chip init verbs */ {0x15, 0x70D, 0xF0}, @@ -4598,8 +4657,27 @@ static struct hda_verb ca0132_init_verbs0[] = { {0x15, 0x546, 0xC9}, {0x15, 0x53B, 0xCE}, {0x15, 0x5E8, 0xC9}, - {0x15, 0x717, 0x0D}, - {0x15, 0x718, 0x20}, + {} +}; + +/* Extra init verbs for SBZ */ +static struct hda_verb sbz_init_verbs[] = { + {0x15, 0x70D, 0x20}, + {0x15, 0x70E, 0x19}, + {0x15, 0x707, 0x00}, + {0x15, 0x539, 0xCE}, + {0x15, 0x546, 0xC9}, + {0x15, 0x70D, 0xB7}, + {0x15, 0x70E, 0x09}, + {0x15, 0x707, 0x10}, + {0x15, 0x70D, 0xAF}, + {0x15, 0x70E, 0x09}, + {0x15, 0x707, 0x01}, + {0x15, 0x707, 0x05}, + {0x15, 0x70D, 0x73}, + {0x15, 0x70E, 0x09}, + {0x15, 0x707, 0x14}, + {0x15, 0x6FF, 0xC4}, {} }; @@ -4758,16 +4836,166 @@ static void ca0132_exit_chip(struct hda_codec *codec) dsp_reset(codec); } +/* + * This is for the extra volume verbs 0x797 (left) and 0x798 (right). These add + * extra precision for decibel values. If you had the dB value in floating point + * you would take the value after the decimal point, multiply by 64, and divide + * by 2. So for 8.59, it's (59 * 64) / 100. Useful if someone wanted to + * implement fixed point or floating point dB volumes. For now, I'll set them + * to 0 just incase a value has lingered from a boot into Windows. + */ +static void ca0132_alt_vol_setup(struct hda_codec *codec) +{ + snd_hda_codec_write(codec, 0x02, 0, 0x797, 0x00); + snd_hda_codec_write(codec, 0x02, 0, 0x798, 0x00); + snd_hda_codec_write(codec, 0x03, 0, 0x797, 0x00); + snd_hda_codec_write(codec, 0x03, 0, 0x798, 0x00); + snd_hda_codec_write(codec, 0x04, 0, 0x797, 0x00); + snd_hda_codec_write(codec, 0x04, 0, 0x798, 0x00); + snd_hda_codec_write(codec, 0x07, 0, 0x797, 0x00); + snd_hda_codec_write(codec, 0x07, 0, 0x798, 0x00); +} + +/* + * Extra commands that don't really fit anywhere else. + */ +static void sbz_pre_dsp_setup(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + writel(0x00820680, spec->mem_base + 0x01C); + writel(0x00820680, spec->mem_base + 0x01C); + + snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc); + snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd); + snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe); + snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff); + + chipio_write(codec, 0x18b0a4, 0x000000c2); + + snd_hda_codec_write(codec, 0x11, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44); +} + +/* + * Extra commands that don't really fit anywhere else. + */ +static void r3di_pre_dsp_setup(struct hda_codec *codec) +{ + chipio_write(codec, 0x18b0a4, 0x000000c2); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x1E); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x1C); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x5B); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x20); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x40); + + snd_hda_codec_write(codec, 0x11, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04); +} + + +/* + * These are sent before the DSP is downloaded. Not sure + * what they do, or if they're necessary. Could possibly + * be removed. Figure they're better to leave in. + */ +static void sbz_region2_startup(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + writel(0x00000000, spec->mem_base + 0x400); + writel(0x00000000, spec->mem_base + 0x408); + writel(0x00000000, spec->mem_base + 0x40C); + writel(0x00880680, spec->mem_base + 0x01C); + writel(0x00000083, spec->mem_base + 0xC0C); + writel(0x00000030, spec->mem_base + 0xC00); + writel(0x00000000, spec->mem_base + 0xC04); + writel(0x00000003, spec->mem_base + 0xC0C); + writel(0x00000003, spec->mem_base + 0xC0C); + writel(0x00000003, spec->mem_base + 0xC0C); + writel(0x00000003, spec->mem_base + 0xC0C); + writel(0x000000C1, spec->mem_base + 0xC08); + writel(0x000000F1, spec->mem_base + 0xC08); + writel(0x00000001, spec->mem_base + 0xC08); + writel(0x000000C7, spec->mem_base + 0xC08); + writel(0x000000C1, spec->mem_base + 0xC08); + writel(0x00000080, spec->mem_base + 0xC04); +} + +/* + * Extra init functions for alternative ca0132 codecs. Done + * here so they don't clutter up the main ca0132_init function + * anymore than they have to. + */ +static void ca0132_alt_init(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + ca0132_alt_vol_setup(codec); + + switch (spec->quirk) { + case QUIRK_SBZ: + codec_dbg(codec, "SBZ alt_init"); + ca0132_gpio_init(codec); + sbz_pre_dsp_setup(codec); + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->sbz_init_verbs); + break; + case QUIRK_R3DI: + codec_dbg(codec, "R3DI alt_init"); + ca0132_gpio_init(codec); + ca0132_gpio_setup(codec); + r3di_pre_dsp_setup(codec); + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x6FF, 0xC4); + break; + } +} + static int ca0132_init(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; int i; + bool dsp_loaded; + + /* + * If the DSP is already downloaded, and init has been entered again, + * there's only two reasons for it. One, the codec has awaken from a + * suspended state, and in that case dspload_is_loaded will return + * false, and the init will be ran again. The other reason it gets + * re entered is on startup for some reason it triggers a suspend and + * resume state. In this case, it will check if the DSP is downloaded, + * and not run the init function again. For codecs using alt_functions, + * it will check if the DSP is loaded properly. + */ + if (spec->dsp_state == DSP_DOWNLOADED) { + dsp_loaded = dspload_is_loaded(codec); + if (!dsp_loaded) { + spec->dsp_reload = true; + spec->dsp_state = DSP_DOWNLOAD_INIT; + } else + return 0; + } if (spec->dsp_state != DSP_DOWNLOAD_FAILED) spec->dsp_state = DSP_DOWNLOAD_INIT; spec->curr_chip_addx = INVALID_CHIP_ADDRESS; + if (spec->quirk == QUIRK_SBZ) + sbz_region2_startup(codec); + snd_hda_power_up_pm(codec); ca0132_init_unsol(codec); @@ -4775,8 +5003,16 @@ static int ca0132_init(struct hda_codec *codec) ca0132_init_params(codec); ca0132_init_flags(codec); snd_hda_sequence_write(codec, spec->base_init_verbs); + + if (spec->quirk != QUIRK_NONE) + ca0132_alt_init(codec); + ca0132_download_dsp(codec); ca0132_refresh_widget_caps(codec); + + if (spec->quirk == QUIRK_SBZ) + writew(0x0107, spec->mem_base + 0x320); + ca0132_setup_defaults(codec); ca0132_init_analog_mic2(codec); ca0132_init_dmic(codec); @@ -4791,7 +5027,17 @@ static int ca0132_init(struct hda_codec *codec) init_input(codec, cfg->dig_in_pin, spec->dig_in); - snd_hda_sequence_write(codec, spec->chip_init_verbs); + if (spec->quirk == QUIRK_ALIENWARE || spec->quirk == QUIRK_NONE) { + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20); + } + + if (spec->quirk == QUIRK_SBZ) + ca0132_gpio_setup(codec); + snd_hda_sequence_write(codec, spec->spec_init_verbs); ca0132_select_out(codec); @@ -4799,6 +5045,15 @@ static int ca0132_init(struct hda_codec *codec) snd_hda_jack_report_sync(codec); + /* + * Re set the PlayEnhancement switch on a resume event, because the + * controls will not be reloaded. + */ + if (spec->dsp_reload) { + spec->dsp_reload = false; + ca0132_pe_switch_set(codec); + } + snd_hda_power_down_pm(codec); return 0; @@ -4985,6 +5240,8 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) struct ca0132_spec *spec = codec->spec; spec->chip_init_verbs = ca0132_init_verbs0; + if (spec->quirk == QUIRK_SBZ) + spec->sbz_init_verbs = sbz_init_verbs; spec->spec_init_verbs = kzalloc(sizeof(struct hda_verb) * NUM_SPEC_VERBS, GFP_KERNEL); if (!spec->spec_init_verbs) return -ENOMEM; -- 2.7.4