omap4 pm changes via Paul Walmsley <paul@pwsan.com>:
Some OMAP4 power management fixes and audio device integration patches. This pull request contains a fix for an issue discovered during branch integration. Basic test logs are available at: http://www.pwsan.com/omap/testlogs/omap4_prcm_devel_a_3.9/20130210112717/ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRGTdOAAoJEBvUPslcq6Vz99AP/2d62cVqYa3Q3cjy2OTOGkxw /A4sezgewvfJLo8s4i4QPUgYD0I6nka09MzkPOzTMfOKCQbWP70jKKrccOkDWH0s /cYW2qb3SOEhfGeDK7Ktnx1Eo55X6V8zpw/KfQI+HWABHPFIJsmy79V1BnLrp2q/ l0nj5QduumAvohbza+L1axs7AkhXW6aD3JKi4F0Oz7wVUIpyNWAW8OfVU1M46D8E IB3uHnx5u7yzKpxgnJhQEWsP75VoDCUuPj4pzdFKMOCGB/eEpDJb6rGbyqa/FJP+ 35sobhlaBXO+bAm1el0ScyTiE6793xeKd8RijiHkI56sh7Cg+6iTrEJpqxsxnfEg wQCpKMk+xldF/pvCatXJtpE9QkzzSkbLjRi4iCb1mmfpo9ZFQaZ9c1tzJax33HIs GJAX8jXp45z93s6iYOo0GlkSLteSj5HtuFZMRXbqY2uebiDo1RO/VXERazul/15o diEIcAS5Yu2sre05Ydyr1f3z5cJyI0bAaUq89zsYlKBCdfUg+WBH3ddIQ20zL3eV uspHsIq2kpfaW8PPB+4Q2LbWUQ+qgqOvejHGFj80bLCV2ntDjzMGg3v6+Ktj7UTs RlGtrdRVy+/G/A3rKBkLL6MxbwGVpcSQprh0naE2XnY53HuHQ9bwXd0ZfilYy7YA bQChElTBohBSrwI4IaqD =Qbkt -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.9/pm-omap4-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into late/omap From Tony Lindgren: omap4 pm changes via Paul Walmsley <paul@pwsan.com>: Some OMAP4 power management fixes and audio device integration patches. This pull request contains a fix for an issue discovered during branch integration. Basic test logs are available at: http://www.pwsan.com/omap/testlogs/omap4_prcm_devel_a_3.9/20130210112717/ * tag 'omap-for-v3.9/pm-omap4-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP4: hwmod data: Enable AESS hwmod device ARM: OMAP4: hwmod data: Update AESS data with memory bank area ARM: OMAP4+: AESS: enable internal auto-gating during initial setup ASoC: TI AESS: add autogating-enable function, callable from architecture code ARM: OMAP2+: hwmod: add enable_preprogram hook ARM: OMAP2+: PM: Fix the dt return condition in pm_late_init() ARM: OMAP4: PM: Warn users about usage of older bootloaders
This commit is contained in:
commit
ebcfe0faf9
@ -8,7 +8,7 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
|
|||||||
omap_device.o sram.o
|
omap_device.o sram.o
|
||||||
|
|
||||||
omap-2-3-common = irq.o
|
omap-2-3-common = irq.o
|
||||||
hwmod-common = omap_hwmod.o \
|
hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
|
||||||
omap_hwmod_common_data.o
|
omap_hwmod_common_data.o
|
||||||
clock-common = clock.o clock_common_data.o \
|
clock-common = clock.o clock_common_data.o \
|
||||||
clkt_dpll.o clkt_clksel.o
|
clkt_dpll.o clkt_clksel.o
|
||||||
|
@ -2054,6 +2054,23 @@ static int _omap4_get_context_lost(struct omap_hwmod *oh)
|
|||||||
return oh->prcm.omap4.context_lost_counter;
|
return oh->prcm.omap4.context_lost_counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _enable_preprogram - Pre-program an IP block during the _enable() process
|
||||||
|
* @oh: struct omap_hwmod *
|
||||||
|
*
|
||||||
|
* Some IP blocks (such as AESS) require some additional programming
|
||||||
|
* after enable before they can enter idle. If a function pointer to
|
||||||
|
* do so is present in the hwmod data, then call it and pass along the
|
||||||
|
* return value; otherwise, return 0.
|
||||||
|
*/
|
||||||
|
static int __init _enable_preprogram(struct omap_hwmod *oh)
|
||||||
|
{
|
||||||
|
if (!oh->class->enable_preprogram)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return oh->class->enable_preprogram(oh);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _enable - enable an omap_hwmod
|
* _enable - enable an omap_hwmod
|
||||||
* @oh: struct omap_hwmod *
|
* @oh: struct omap_hwmod *
|
||||||
@ -2160,6 +2177,7 @@ static int _enable(struct omap_hwmod *oh)
|
|||||||
_update_sysc_cache(oh);
|
_update_sysc_cache(oh);
|
||||||
_enable_sysc(oh);
|
_enable_sysc(oh);
|
||||||
}
|
}
|
||||||
|
r = _enable_preprogram(oh);
|
||||||
} else {
|
} else {
|
||||||
if (soc_ops.disable_module)
|
if (soc_ops.disable_module)
|
||||||
soc_ops.disable_module(oh);
|
soc_ops.disable_module(oh);
|
||||||
|
@ -510,6 +510,7 @@ struct omap_hwmod_omap4_prcm {
|
|||||||
* @rev: revision of the IP class
|
* @rev: revision of the IP class
|
||||||
* @pre_shutdown: ptr to fn to be executed immediately prior to device shutdown
|
* @pre_shutdown: ptr to fn to be executed immediately prior to device shutdown
|
||||||
* @reset: ptr to fn to be executed in place of the standard hwmod reset fn
|
* @reset: ptr to fn to be executed in place of the standard hwmod reset fn
|
||||||
|
* @enable_preprogram: ptr to fn to be executed during device enable
|
||||||
*
|
*
|
||||||
* Represent the class of a OMAP hardware "modules" (e.g. timer,
|
* Represent the class of a OMAP hardware "modules" (e.g. timer,
|
||||||
* smartreflex, gpio, uart...)
|
* smartreflex, gpio, uart...)
|
||||||
@ -533,6 +534,7 @@ struct omap_hwmod_class {
|
|||||||
u32 rev;
|
u32 rev;
|
||||||
int (*pre_shutdown)(struct omap_hwmod *oh);
|
int (*pre_shutdown)(struct omap_hwmod *oh);
|
||||||
int (*reset)(struct omap_hwmod *oh);
|
int (*reset)(struct omap_hwmod *oh);
|
||||||
|
int (*enable_preprogram)(struct omap_hwmod *oh);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -679,6 +681,12 @@ extern void __init omap_hwmod_init(void);
|
|||||||
|
|
||||||
const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh);
|
const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int omap_hwmod_aess_preprogram(struct omap_hwmod *oh);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Chip variant-specific hwmod init routines - XXX should be converted
|
* Chip variant-specific hwmod init routines - XXX should be converted
|
||||||
* to use initcalls once the initial boot ordering is straightened out
|
* to use initcalls once the initial boot ordering is straightened out
|
||||||
|
@ -322,6 +322,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = {
|
|||||||
static struct omap_hwmod_class omap44xx_aess_hwmod_class = {
|
static struct omap_hwmod_class omap44xx_aess_hwmod_class = {
|
||||||
.name = "aess",
|
.name = "aess",
|
||||||
.sysc = &omap44xx_aess_sysc,
|
.sysc = &omap44xx_aess_sysc,
|
||||||
|
.enable_preprogram = omap_hwmod_aess_preprogram,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* aess */
|
/* aess */
|
||||||
@ -348,7 +349,7 @@ static struct omap_hwmod omap44xx_aess_hwmod = {
|
|||||||
.clkdm_name = "abe_clkdm",
|
.clkdm_name = "abe_clkdm",
|
||||||
.mpu_irqs = omap44xx_aess_irqs,
|
.mpu_irqs = omap44xx_aess_irqs,
|
||||||
.sdma_reqs = omap44xx_aess_sdma_reqs,
|
.sdma_reqs = omap44xx_aess_sdma_reqs,
|
||||||
.main_clk = "aess_fck",
|
.main_clk = "aess_fclk",
|
||||||
.prcm = {
|
.prcm = {
|
||||||
.omap4 = {
|
.omap4 = {
|
||||||
.clkctrl_offs = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET,
|
.clkctrl_offs = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET,
|
||||||
@ -4248,6 +4249,27 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ocp_wp_noc = {
|
|||||||
|
|
||||||
static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
|
static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
|
||||||
{
|
{
|
||||||
|
.name = "dmem",
|
||||||
|
.pa_start = 0x40180000,
|
||||||
|
.pa_end = 0x4018ffff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "cmem",
|
||||||
|
.pa_start = 0x401a0000,
|
||||||
|
.pa_end = 0x401a1fff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "smem",
|
||||||
|
.pa_start = 0x401c0000,
|
||||||
|
.pa_end = 0x401c5fff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "pmem",
|
||||||
|
.pa_start = 0x401e0000,
|
||||||
|
.pa_end = 0x401e1fff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mpu",
|
||||||
.pa_start = 0x401f1000,
|
.pa_start = 0x401f1000,
|
||||||
.pa_end = 0x401f13ff,
|
.pa_end = 0x401f13ff,
|
||||||
.flags = ADDR_TYPE_RT
|
.flags = ADDR_TYPE_RT
|
||||||
@ -4266,6 +4288,27 @@ static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_abe__aess = {
|
|||||||
|
|
||||||
static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
|
static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
|
||||||
{
|
{
|
||||||
|
.name = "dmem_dma",
|
||||||
|
.pa_start = 0x49080000,
|
||||||
|
.pa_end = 0x4908ffff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "cmem_dma",
|
||||||
|
.pa_start = 0x490a0000,
|
||||||
|
.pa_end = 0x490a1fff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "smem_dma",
|
||||||
|
.pa_start = 0x490c0000,
|
||||||
|
.pa_end = 0x490c5fff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "pmem_dma",
|
||||||
|
.pa_start = 0x490e0000,
|
||||||
|
.pa_end = 0x490e1fff
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "dma",
|
||||||
.pa_start = 0x490f1000,
|
.pa_start = 0x490f1000,
|
||||||
.pa_end = 0x490f13ff,
|
.pa_end = 0x490f13ff,
|
||||||
.flags = ADDR_TYPE_RT
|
.flags = ADDR_TYPE_RT
|
||||||
@ -6281,7 +6324,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
|
|||||||
&omap44xx_l3_main_1__l3_main_3,
|
&omap44xx_l3_main_1__l3_main_3,
|
||||||
&omap44xx_l3_main_2__l3_main_3,
|
&omap44xx_l3_main_2__l3_main_3,
|
||||||
&omap44xx_l4_cfg__l3_main_3,
|
&omap44xx_l4_cfg__l3_main_3,
|
||||||
/* &omap44xx_aess__l4_abe, */
|
&omap44xx_aess__l4_abe,
|
||||||
&omap44xx_dsp__l4_abe,
|
&omap44xx_dsp__l4_abe,
|
||||||
&omap44xx_l3_main_1__l4_abe,
|
&omap44xx_l3_main_1__l4_abe,
|
||||||
&omap44xx_mpu__l4_abe,
|
&omap44xx_mpu__l4_abe,
|
||||||
@ -6290,8 +6333,8 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
|
|||||||
&omap44xx_l4_cfg__l4_wkup,
|
&omap44xx_l4_cfg__l4_wkup,
|
||||||
&omap44xx_mpu__mpu_private,
|
&omap44xx_mpu__mpu_private,
|
||||||
&omap44xx_l4_cfg__ocp_wp_noc,
|
&omap44xx_l4_cfg__ocp_wp_noc,
|
||||||
/* &omap44xx_l4_abe__aess, */
|
&omap44xx_l4_abe__aess,
|
||||||
/* &omap44xx_l4_abe__aess_dma, */
|
&omap44xx_l4_abe__aess_dma,
|
||||||
&omap44xx_l3_main_2__c2c,
|
&omap44xx_l3_main_2__c2c,
|
||||||
&omap44xx_l4_wkup__counter_32k,
|
&omap44xx_l4_wkup__counter_32k,
|
||||||
&omap44xx_l4_cfg__ctrl_module_core,
|
&omap44xx_l4_cfg__ctrl_module_core,
|
||||||
|
52
arch/arm/mach-omap2/omap_hwmod_reset.c
Normal file
52
arch/arm/mach-omap2/omap_hwmod_reset.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* OMAP IP block custom reset and preprogramming stubs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||||
|
* Paul Walmsley
|
||||||
|
*
|
||||||
|
* A small number of IP blocks need custom reset and preprogramming
|
||||||
|
* functions. The stubs in this file provide a standard way for the
|
||||||
|
* hwmod code to call these functions, which are to be located under
|
||||||
|
* drivers/.
|
||||||
|
*
|
||||||
|
* 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 version 2.
|
||||||
|
*
|
||||||
|
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||||
|
* kind, whether express or implied; 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
#include <sound/aess.h>
|
||||||
|
|
||||||
|
#include "omap_hwmod.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* omap_hwmod_aess_preprogram - enable AESS internal autogating
|
||||||
|
* @oh: struct omap_hwmod *
|
||||||
|
*
|
||||||
|
* The AESS will not IdleAck to the PRCM until its internal autogating
|
||||||
|
* is enabled. Since internal autogating is disabled by default after
|
||||||
|
* AESS reset, we must enable autogating after the hwmod code resets
|
||||||
|
* the AESS. Returns 0.
|
||||||
|
*/
|
||||||
|
int omap_hwmod_aess_preprogram(struct omap_hwmod *oh)
|
||||||
|
{
|
||||||
|
void __iomem *va;
|
||||||
|
|
||||||
|
va = omap_hwmod_get_mpu_rt_va(oh);
|
||||||
|
if (!va)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
aess_enable_autogating(va);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -282,19 +282,19 @@ int __init omap2_common_pm_late_init(void)
|
|||||||
* a completely different mechanism.
|
* a completely different mechanism.
|
||||||
* Disable this part if a DT blob is available.
|
* Disable this part if a DT blob is available.
|
||||||
*/
|
*/
|
||||||
if (of_have_populated_dt())
|
if (!of_have_populated_dt()) {
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Init the voltage layer */
|
/* Init the voltage layer */
|
||||||
omap_pmic_late_init();
|
omap_pmic_late_init();
|
||||||
omap_voltage_late_init();
|
omap_voltage_late_init();
|
||||||
|
|
||||||
/* Initialize the voltages */
|
/* Initialize the voltages */
|
||||||
omap3_init_voltages();
|
omap3_init_voltages();
|
||||||
omap4_init_voltages();
|
omap4_init_voltages();
|
||||||
|
|
||||||
/* Smartreflex device init */
|
/* Smartreflex device init */
|
||||||
omap_devinit_smartreflex();
|
omap_devinit_smartreflex();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SUSPEND
|
#ifdef CONFIG_SUSPEND
|
||||||
suspend_set_ops(&omap_pm_ops);
|
suspend_set_ops(&omap_pm_ops);
|
||||||
|
@ -77,10 +77,20 @@ static int omap4_pm_suspend(void)
|
|||||||
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
|
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
|
||||||
pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
|
pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret) {
|
||||||
pr_crit("Could not enter target state in pm_suspend\n");
|
pr_crit("Could not enter target state in pm_suspend\n");
|
||||||
else
|
/*
|
||||||
|
* OMAP4 chip PM currently works only with certain (newer)
|
||||||
|
* versions of bootloaders. This is due to missing code in the
|
||||||
|
* kernel to properly reset and initialize some devices.
|
||||||
|
* Warn the user about the bootloader version being one of the
|
||||||
|
* possible causes.
|
||||||
|
* http://www.spinics.net/lists/arm-kernel/msg218641.html
|
||||||
|
*/
|
||||||
|
pr_warn("A possible cause could be an old bootloader - try u-boot >= v2012.07\n");
|
||||||
|
} else {
|
||||||
pr_info("Successfully put all powerdomains to target state\n");
|
pr_info("Successfully put all powerdomains to target state\n");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -146,6 +156,13 @@ int __init omap4_pm_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pr_err("Power Management for TI OMAP4.\n");
|
pr_err("Power Management for TI OMAP4.\n");
|
||||||
|
/*
|
||||||
|
* OMAP4 chip PM currently works only with certain (newer)
|
||||||
|
* versions of bootloaders. This is due to missing code in the
|
||||||
|
* kernel to properly reset and initialize some devices.
|
||||||
|
* http://www.spinics.net/lists/arm-kernel/msg218641.html
|
||||||
|
*/
|
||||||
|
pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
|
||||||
|
|
||||||
ret = pwrdm_for_each(pwrdms_setup, NULL);
|
ret = pwrdm_for_each(pwrdms_setup, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
53
include/sound/aess.h
Normal file
53
include/sound/aess.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* AESS IP block reset
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||||
|
* Paul Walmsley
|
||||||
|
*
|
||||||
|
* 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 version 2.
|
||||||
|
*
|
||||||
|
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||||
|
* kind, whether express or implied; 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#ifndef __SOUND_AESS_H__
|
||||||
|
#define __SOUND_AESS_H__
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AESS_AUTO_GATING_ENABLE_OFFSET: offset in bytes of the AESS IP
|
||||||
|
* block's AESS_AUTO_GATING_ENABLE__1 register from the IP block's
|
||||||
|
* base address
|
||||||
|
*/
|
||||||
|
#define AESS_AUTO_GATING_ENABLE_OFFSET 0x07c
|
||||||
|
|
||||||
|
/* Register bitfields in the AESS_AUTO_GATING_ENABLE__1 register */
|
||||||
|
#define AESS_AUTO_GATING_ENABLE_SHIFT 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* aess_enable_autogating - enable AESS internal autogating
|
||||||
|
* @oh: struct omap_hwmod *
|
||||||
|
*
|
||||||
|
* Enable internal autogating on the AESS. This allows the AESS to
|
||||||
|
* indicate that it is idle to the OMAP PRCM. Returns 0.
|
||||||
|
*/
|
||||||
|
static inline void aess_enable_autogating(void __iomem *base)
|
||||||
|
{
|
||||||
|
u32 v;
|
||||||
|
|
||||||
|
/* Set AESS_AUTO_GATING_ENABLE__1.ENABLE to allow idle entry */
|
||||||
|
v = 1 << AESS_AUTO_GATING_ENABLE_SHIFT;
|
||||||
|
writel(v, base + AESS_AUTO_GATING_ENABLE_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SOUND_AESS_H__ */
|
Loading…
Reference in New Issue
Block a user