Merge tag 'topic/i915-hda-componentized-2015-01-12' of git://anongit.freedesktop.org/drm-intel into for-next

Tento commit je obsažen v:
Takashi Iwai
2015-01-13 07:54:02 +01:00
12 změnil soubory, kde provedl 367 přidání a 231 odebrání

Zobrazit soubor

@@ -18,10 +18,12 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/component.h>
#include <drm/i915_component.h>
#include <sound/core.h>
#include <drm/i915_powerwell.h>
#include "hda_priv.h"
#include "hda_i915.h"
#include "hda_intel.h"
/* Intel HSW/BDW display HDA controller Extended Mode registers.
* EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
@@ -31,32 +33,33 @@
#define AZX_REG_EM4 0x100c
#define AZX_REG_EM5 0x1010
static int (*get_power)(void);
static int (*put_power)(void);
static int (*get_cdclk)(void);
int hda_display_power(bool enable)
int hda_display_power(struct hda_intel *hda, bool enable)
{
if (!get_power || !put_power)
struct i915_audio_component *acomp = &hda->audio_component;
if (!acomp->ops)
return -ENODEV;
pr_debug("HDA display power %s \n",
enable ? "Enable" : "Disable");
dev_dbg(&hda->chip.pci->dev, "display power %s\n",
enable ? "enable" : "disable");
if (enable)
return get_power();
acomp->ops->get_power(acomp->dev);
else
return put_power();
acomp->ops->put_power(acomp->dev);
return 0;
}
void haswell_set_bclk(struct azx *chip)
void haswell_set_bclk(struct hda_intel *hda)
{
int cdclk_freq;
unsigned int bclk_m, bclk_n;
struct i915_audio_component *acomp = &hda->audio_component;
if (!get_cdclk)
if (!acomp->ops)
return;
cdclk_freq = get_cdclk();
cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
switch (cdclk_freq) {
case 337500:
bclk_m = 16;
@@ -80,51 +83,108 @@ void haswell_set_bclk(struct azx *chip)
break;
}
azx_writew(chip, EM4, bclk_m);
azx_writew(chip, EM5, bclk_n);
azx_writew(&hda->chip, EM4, bclk_m);
azx_writew(&hda->chip, EM5, bclk_n);
}
int hda_i915_init(void)
static int hda_component_master_bind(struct device *dev)
{
int err = 0;
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
struct i915_audio_component *acomp = &hda->audio_component;
int ret;
get_power = symbol_request(i915_request_power_well);
if (!get_power) {
pr_warn("hda-i915: get_power symbol get fail\n");
return -ENODEV;
ret = component_bind_all(dev, acomp);
if (ret < 0)
return ret;
if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
ret = -EINVAL;
goto out_unbind;
}
put_power = symbol_request(i915_release_power_well);
if (!put_power) {
symbol_put(i915_request_power_well);
get_power = NULL;
return -ENODEV;
}
get_cdclk = symbol_request(i915_get_cdclk_freq);
if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
pr_warn("hda-i915: get_cdclk symbol get fail\n");
pr_debug("HDA driver get symbol successfully from i915 module\n");
return err;
}
int hda_i915_exit(void)
{
if (get_power) {
symbol_put(i915_request_power_well);
get_power = NULL;
}
if (put_power) {
symbol_put(i915_release_power_well);
put_power = NULL;
}
if (get_cdclk) {
symbol_put(i915_get_cdclk_freq);
get_cdclk = NULL;
/*
* Atm, we don't support dynamic unbinding initiated by the child
* component, so pin its containing module until we unbind.
*/
if (!try_module_get(acomp->ops->owner)) {
ret = -ENODEV;
goto out_unbind;
}
return 0;
out_unbind:
component_unbind_all(dev, acomp);
return ret;
}
static void hda_component_master_unbind(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
struct i915_audio_component *acomp = &hda->audio_component;
module_put(acomp->ops->owner);
component_unbind_all(dev, acomp);
WARN_ON(acomp->ops || acomp->dev);
}
static const struct component_master_ops hda_component_master_ops = {
.bind = hda_component_master_bind,
.unbind = hda_component_master_unbind,
};
static int hda_component_master_match(struct device *dev, void *data)
{
/* i915 is the only supported component */
return !strcmp(dev->driver->name, "i915");
}
int hda_i915_init(struct hda_intel *hda)
{
struct component_match *match = NULL;
struct device *dev = &hda->chip.pci->dev;
struct i915_audio_component *acomp = &hda->audio_component;
int ret;
component_match_add(dev, &match, hda_component_master_match, hda);
ret = component_master_add_with_match(dev, &hda_component_master_ops,
match);
if (ret < 0)
goto out_err;
/*
* Atm, we don't support deferring the component binding, so make sure
* i915 is loaded and that the binding successfully completes.
*/
request_module("i915");
if (!acomp->ops) {
ret = -ENODEV;
goto out_master_del;
}
dev_dbg(dev, "bound to i915 component master\n");
return 0;
out_master_del:
component_master_del(dev, &hda_component_master_ops);
out_err:
dev_err(dev, "failed to add i915 component master (%d)\n", ret);
return ret;
}
int hda_i915_exit(struct hda_intel *hda)
{
struct device *dev = &hda->chip.pci->dev;
component_master_del(dev, &hda_component_master_ops);
return 0;
}

Zobrazit soubor

@@ -1,37 +0,0 @@
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOUND_HDA_I915_H
#define __SOUND_HDA_I915_H
#ifdef CONFIG_SND_HDA_I915
int hda_display_power(bool enable);
void haswell_set_bclk(struct azx *chip);
int hda_i915_init(void);
int hda_i915_exit(void);
#else
static inline int hda_display_power(bool enable) { return 0; }
static inline void haswell_set_bclk(struct azx *chip) { return; }
static inline int hda_i915_init(void)
{
return -ENODEV;
}
static inline int hda_i915_exit(void)
{
return 0;
}
#endif
#endif

Zobrazit soubor

@@ -63,7 +63,7 @@
#include "hda_codec.h"
#include "hda_controller.h"
#include "hda_priv.h"
#include "hda_i915.h"
#include "hda_intel.h"
/* position fix mode */
enum {
@@ -354,31 +354,6 @@ static char *driver_short_names[] = {
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
struct hda_intel {
struct azx chip;
/* for pending irqs */
struct work_struct irq_pending_work;
/* sync probing */
struct completion probe_wait;
struct work_struct probe_work;
/* card list (for power_save trigger) */
struct list_head list;
/* extra flags */
unsigned int irq_pending_warned:1;
/* VGA-switcheroo setup */
unsigned int use_vga_switcheroo:1;
unsigned int vga_switcheroo_registered:1;
unsigned int init_failed:1; /* delayed init failed */
/* secondary power domain for hdmi audio under vga device */
struct dev_pm_domain hdmi_pm_domain;
};
#ifdef CONFIG_X86
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
{
@@ -824,7 +799,7 @@ static int azx_suspend(struct device *dev)
if (chip->msi)
pci_disable_msi(chip->pci);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
hda_display_power(false);
hda_display_power(hda, false);
return 0;
}
@@ -844,8 +819,8 @@ static int azx_resume(struct device *dev)
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(true);
haswell_set_bclk(chip);
hda_display_power(hda, true);
haswell_set_bclk(hda);
}
if (chip->msi)
if (pci_enable_msi(pci) < 0)
@@ -888,7 +863,7 @@ static int azx_runtime_suspend(struct device *dev)
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
hda_display_power(false);
hda_display_power(hda, false);
return 0;
}
@@ -914,8 +889,8 @@ static int azx_runtime_resume(struct device *dev)
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(true);
haswell_set_bclk(chip);
hda_display_power(hda, true);
haswell_set_bclk(hda);
}
/* Read STATESTS before controller reset */
@@ -1136,8 +1111,8 @@ static int azx_free(struct azx *chip)
release_firmware(chip->fw);
#endif
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(false);
hda_i915_exit();
hda_display_power(hda, false);
hda_i915_exit(hda);
}
kfree(hda);
@@ -1615,8 +1590,12 @@ static int azx_first_init(struct azx *chip)
/* initialize chip */
azx_init_pci(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
haswell_set_bclk(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
struct hda_intel *hda;
hda = container_of(chip, struct hda_intel, chip);
haswell_set_bclk(hda);
}
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
@@ -1896,13 +1875,10 @@ static int azx_probe_continue(struct azx *chip)
/* Request power well for Haswell HDA controller and codec */
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
#ifdef CONFIG_SND_HDA_I915
err = hda_i915_init();
if (err < 0) {
dev_err(chip->card->dev,
"Error request power-well from i915\n");
err = hda_i915_init(hda);
if (err < 0)
goto out_free;
}
err = hda_display_power(true);
err = hda_display_power(hda, true);
if (err < 0) {
dev_err(chip->card->dev,
"Cannot turn on display power on i915\n");

71
sound/pci/hda/hda_intel.h Normální soubor
Zobrazit soubor

@@ -0,0 +1,71 @@
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOUND_HDA_INTEL_H
#define __SOUND_HDA_INTEL_H
#include <drm/i915_component.h>
#include "hda_priv.h"
struct hda_intel {
struct azx chip;
/* for pending irqs */
struct work_struct irq_pending_work;
/* sync probing */
struct completion probe_wait;
struct work_struct probe_work;
/* card list (for power_save trigger) */
struct list_head list;
/* extra flags */
unsigned int irq_pending_warned:1;
/* VGA-switcheroo setup */
unsigned int use_vga_switcheroo:1;
unsigned int vga_switcheroo_registered:1;
unsigned int init_failed:1; /* delayed init failed */
/* secondary power domain for hdmi audio under vga device */
struct dev_pm_domain hdmi_pm_domain;
/* i915 component interface */
struct i915_audio_component audio_component;
};
#ifdef CONFIG_SND_HDA_I915
int hda_display_power(struct hda_intel *hda, bool enable);
void haswell_set_bclk(struct hda_intel *hda);
int hda_i915_init(struct hda_intel *hda);
int hda_i915_exit(struct hda_intel *hda);
#else
static inline int hda_display_power(struct hda_intel *hda, bool enable)
{
return 0;
}
static inline void haswell_set_bclk(struct hda_intel *hda) { return; }
static inline int hda_i915_init(struct hda_intel *hda)
{
return -ENODEV;
}
static inline int hda_i915_exit(struct hda_intel *hda)
{
return 0;
}
#endif
#endif