From nobody Tue Nov 4 18:28:43 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1530599394125923.444537790878; Mon, 2 Jul 2018 23:29:54 -0700 (PDT) Received: from localhost ([::1]:38130 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1faEoz-0003cP-Cj for importer@patchew.org; Tue, 03 Jul 2018 02:29:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40051) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1faEKc-0002xx-2t for qemu-devel@nongnu.org; Tue, 03 Jul 2018 01:58:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1faEKY-00076x-Jz for qemu-devel@nongnu.org; Tue, 03 Jul 2018 01:58:30 -0400 Received: from ozlabs.org ([2401:3900:2:1::2]:52265) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1faEKX-000712-RJ; Tue, 03 Jul 2018 01:58:26 -0400 Received: by ozlabs.org (Postfix, from userid 1007) id 41KYMD15rKz9sCJ; Tue, 3 Jul 2018 15:58:14 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gibson.dropbear.id.au; s=201602; t=1530597496; bh=WTI7rZH2s3nixEqIQC0v0kGjQwjCVazLV7BKjI5+XFk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k+qTpMLAWlECzMdiPi9gkw78HeVJD1iZH1kep6KtuZITUlHRbTcWswtzsjWtDzvQC HsKYo3Zpudak07GGvI/GdQj6WJyA2JNSTKuK6E4gzyvB1fMaeQ7J/AE7VlK3nP0h+m kLX0C88BFcL9MOzqQtqTqarTyymrfQDIRWPdgO8s= From: David Gibson To: peter.maydell@linaro.org Date: Tue, 3 Jul 2018 15:57:58 +1000 Message-Id: <20180703055804.13449-30-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180703055804.13449-1-david@gibson.dropbear.id.au> References: <20180703055804.13449-1-david@gibson.dropbear.id.au> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2401:3900:2:1::2 Subject: [Qemu-devel] [PULL 29/35] ppc440_uc: Basic emulation of PPC440 DMA controller X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org, mdroth@linux.vnet.ibm.com, agraf@suse.de, aik@ozlabs.ru, groug@kaod.org, qemu-ppc@nongnu.org, clg@kaod.org, David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: BALATON Zoltan PPC440 SoCs such as the AMCC 460EX have a DMA controller which is used by AmigaOS on the sam460ex. Implement the parts used by AmigaOS so it can get further booting on the sam460ex machine. Signed-off-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/ppc/ppc440.h | 1 + hw/ppc/ppc440_uc.c | 222 +++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/sam460ex.c | 3 + 3 files changed, 226 insertions(+) diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h index ad27db12e4..7cef936125 100644 --- a/hw/ppc/ppc440.h +++ b/hw/ppc/ppc440.h @@ -21,6 +21,7 @@ void ppc440_sdram_init(CPUPPCState *env, int nbanks, hwaddr *ram_bases, hwaddr *ram_sizes, int do_init); void ppc4xx_ahb_init(CPUPPCState *env); +void ppc4xx_dma_init(CPUPPCState *env, int dcr_base); void ppc460ex_pcie_init(CPUPPCState *env); =20 #endif /* PPC440_H */ diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 123f4ac09d..32802d741b 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -13,6 +13,7 @@ #include "qemu/cutils.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/hw.h" #include "exec/address-spaces.h" @@ -802,6 +803,227 @@ void ppc4xx_ahb_init(CPUPPCState *env) qemu_register_reset(ppc4xx_ahb_reset, ahb); } =20 +/*************************************************************************= ****/ +/* DMA controller */ + +#define DMA0_CR_CE (1 << 31) +#define DMA0_CR_PW (1 << 26 | 1 << 25) +#define DMA0_CR_DAI (1 << 24) +#define DMA0_CR_SAI (1 << 23) +#define DMA0_CR_DEC (1 << 2) + +enum { + DMA0_CR =3D 0x00, + DMA0_CT, + DMA0_SAH, + DMA0_SAL, + DMA0_DAH, + DMA0_DAL, + DMA0_SGH, + DMA0_SGL, + + DMA0_SR =3D 0x20, + DMA0_SGC =3D 0x23, + DMA0_SLP =3D 0x25, + DMA0_POL =3D 0x26, +}; + +typedef struct { + uint32_t cr; + uint32_t ct; + uint64_t sa; + uint64_t da; + uint64_t sg; +} PPC4xxDmaChnl; + +typedef struct { + int base; + PPC4xxDmaChnl ch[4]; + uint32_t sr; +} PPC4xxDmaState; + +static uint32_t dcr_read_dma(void *opaque, int dcrn) +{ + PPC4xxDmaState *dma =3D opaque; + uint32_t val =3D 0; + int addr =3D dcrn - dma->base; + int chnl =3D addr / 8; + + switch (addr) { + case 0x00 ... 0x1f: + switch (addr % 8) { + case DMA0_CR: + val =3D dma->ch[chnl].cr; + break; + case DMA0_CT: + val =3D dma->ch[chnl].ct; + break; + case DMA0_SAH: + val =3D dma->ch[chnl].sa >> 32; + break; + case DMA0_SAL: + val =3D dma->ch[chnl].sa; + break; + case DMA0_DAH: + val =3D dma->ch[chnl].da >> 32; + break; + case DMA0_DAL: + val =3D dma->ch[chnl].da; + break; + case DMA0_SGH: + val =3D dma->ch[chnl].sg >> 32; + break; + case DMA0_SGL: + val =3D dma->ch[chnl].sg; + break; + } + break; + case DMA0_SR: + val =3D dma->sr; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n= ", + __func__, dcrn, chnl, addr); + } + + return val; +} + +static void dcr_write_dma(void *opaque, int dcrn, uint32_t val) +{ + PPC4xxDmaState *dma =3D opaque; + int addr =3D dcrn - dma->base; + int chnl =3D addr / 8; + + switch (addr) { + case 0x00 ... 0x1f: + switch (addr % 8) { + case DMA0_CR: + dma->ch[chnl].cr =3D val; + if (val & DMA0_CR_CE) { + int count =3D dma->ch[chnl].ct & 0xffff; + + if (count) { + int width, i, sidx, didx; + uint8_t *rptr, *wptr; + hwaddr rlen, wlen; + + sidx =3D didx =3D 0; + width =3D 1 << ((val & DMA0_CR_PW) >> 25); + rptr =3D cpu_physical_memory_map(dma->ch[chnl].sa, &rl= en, 0); + wptr =3D cpu_physical_memory_map(dma->ch[chnl].da, &wl= en, 1); + if (rptr && wptr) { + if (!(val & DMA0_CR_DEC) && + val & DMA0_CR_SAI && val & DMA0_CR_DAI) { + /* optimise common case */ + memmove(wptr, rptr, count * width); + sidx =3D didx =3D count * width; + } else { + /* do it the slow way */ + for (sidx =3D didx =3D i =3D 0; i < count; i++= ) { + uint64_t v =3D ldn_le_p(rptr + sidx, width= ); + stn_le_p(wptr + didx, width, v); + if (val & DMA0_CR_SAI) { + sidx +=3D width; + } + if (val & DMA0_CR_DAI) { + didx +=3D width; + } + } + } + } + if (wptr) { + cpu_physical_memory_unmap(wptr, wlen, 1, didx); + } + if (wptr) { + cpu_physical_memory_unmap(rptr, rlen, 0, sidx); + } + } + } + break; + case DMA0_CT: + dma->ch[chnl].ct =3D val; + break; + case DMA0_SAH: + dma->ch[chnl].sa &=3D 0xffffffffULL; + dma->ch[chnl].sa |=3D (uint64_t)val << 32; + break; + case DMA0_SAL: + dma->ch[chnl].sa &=3D 0xffffffff00000000ULL; + dma->ch[chnl].sa |=3D val; + break; + case DMA0_DAH: + dma->ch[chnl].da &=3D 0xffffffffULL; + dma->ch[chnl].da |=3D (uint64_t)val << 32; + break; + case DMA0_DAL: + dma->ch[chnl].da &=3D 0xffffffff00000000ULL; + dma->ch[chnl].da |=3D val; + break; + case DMA0_SGH: + dma->ch[chnl].sg &=3D 0xffffffffULL; + dma->ch[chnl].sg |=3D (uint64_t)val << 32; + break; + case DMA0_SGL: + dma->ch[chnl].sg &=3D 0xffffffff00000000ULL; + dma->ch[chnl].sg |=3D val; + break; + } + break; + case DMA0_SR: + dma->sr &=3D ~val; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented register %x (%d, %x)\n= ", + __func__, dcrn, chnl, addr); + } +} + +static void ppc4xx_dma_reset(void *opaque) +{ + PPC4xxDmaState *dma =3D opaque; + int dma_base =3D dma->base; + + memset(dma, 0, sizeof(*dma)); + dma->base =3D dma_base; +} + +void ppc4xx_dma_init(CPUPPCState *env, int dcr_base) +{ + PPC4xxDmaState *dma; + int i; + + dma =3D g_malloc0(sizeof(*dma)); + dma->base =3D dcr_base; + qemu_register_reset(&ppc4xx_dma_reset, dma); + for (i =3D 0; i < 4; i++) { + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CR, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_CT, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAH, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SAL, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAH, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_DAL, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGH, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + i * 8 + DMA0_SGL, + dma, &dcr_read_dma, &dcr_write_dma); + } + ppc_dcr_register(env, dcr_base + DMA0_SR, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + DMA0_SGC, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + DMA0_SLP, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, dcr_base + DMA0_POL, + dma, &dcr_read_dma, &dcr_write_dma); +} + /*************************************************************************= ****/ /* PCI Express controller */ /* FIXME: This is not complete and does not work, only implemented partial= ly diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index a03d12d1dc..80c888c3ef 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -505,6 +505,9 @@ static void sam460ex_init(MachineState *machine) /* MAL */ ppc4xx_mal_init(env, 4, 16, &uic[2][3]); =20 + /* DMA */ + ppc4xx_dma_init(env, 0x200); + /* 256K of L2 cache as memory */ ppc4xx_l2sram_init(env); /* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */ --=20 2.17.1