xref: /third_party/ffmpeg/libavutil/ppc/cpu.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci#include "config.h"
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#ifdef __APPLE__
22cabdff1aSopenharmony_ci#include <sys/sysctl.h>
23cabdff1aSopenharmony_ci#elif defined(__linux__)
24cabdff1aSopenharmony_ci#include <asm/cputable.h>
25cabdff1aSopenharmony_ci#include <linux/auxvec.h>
26cabdff1aSopenharmony_ci#include <fcntl.h>
27cabdff1aSopenharmony_ci#if HAVE_UNISTD_H
28cabdff1aSopenharmony_ci#include <unistd.h>
29cabdff1aSopenharmony_ci#endif
30cabdff1aSopenharmony_ci#elif defined(__OpenBSD__)
31cabdff1aSopenharmony_ci#include <sys/types.h>
32cabdff1aSopenharmony_ci#include <sys/sysctl.h>
33cabdff1aSopenharmony_ci#include <machine/cpu.h>
34cabdff1aSopenharmony_ci#elif defined(__AMIGAOS4__)
35cabdff1aSopenharmony_ci#include <exec/exec.h>
36cabdff1aSopenharmony_ci#include <interfaces/exec.h>
37cabdff1aSopenharmony_ci#include <proto/exec.h>
38cabdff1aSopenharmony_ci#endif /* __APPLE__ */
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
41cabdff1aSopenharmony_ci#include "libavutil/cpu.h"
42cabdff1aSopenharmony_ci#include "libavutil/cpu_internal.h"
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci/**
45cabdff1aSopenharmony_ci * This function MAY rely on signal() or fork() in order to make sure AltiVec
46cabdff1aSopenharmony_ci * is present.
47cabdff1aSopenharmony_ci */
48cabdff1aSopenharmony_ciint ff_get_cpu_flags_ppc(void)
49cabdff1aSopenharmony_ci{
50cabdff1aSopenharmony_ci#if HAVE_ALTIVEC
51cabdff1aSopenharmony_ci#ifdef __AMIGAOS4__
52cabdff1aSopenharmony_ci    ULONG result = 0;
53cabdff1aSopenharmony_ci    extern struct ExecIFace *IExec;
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_ci    IExec->GetCPUInfoTags(GCIT_VectorUnit, &result, TAG_DONE);
56cabdff1aSopenharmony_ci    if (result == VECTORTYPE_ALTIVEC)
57cabdff1aSopenharmony_ci        return AV_CPU_FLAG_ALTIVEC;
58cabdff1aSopenharmony_ci    return 0;
59cabdff1aSopenharmony_ci#elif defined(__APPLE__) || defined(__OpenBSD__)
60cabdff1aSopenharmony_ci#ifdef __OpenBSD__
61cabdff1aSopenharmony_ci    int sels[2] = {CTL_MACHDEP, CPU_ALTIVEC};
62cabdff1aSopenharmony_ci#else
63cabdff1aSopenharmony_ci    int sels[2] = {CTL_HW, HW_VECTORUNIT};
64cabdff1aSopenharmony_ci#endif
65cabdff1aSopenharmony_ci    int has_vu = 0;
66cabdff1aSopenharmony_ci    size_t len = sizeof(has_vu);
67cabdff1aSopenharmony_ci    int err;
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci    err = sysctl(sels, 2, &has_vu, &len, NULL, 0);
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    if (err == 0)
72cabdff1aSopenharmony_ci        return has_vu ? AV_CPU_FLAG_ALTIVEC : 0;
73cabdff1aSopenharmony_ci    return 0;
74cabdff1aSopenharmony_ci#elif defined(__linux__)
75cabdff1aSopenharmony_ci    // The linux kernel could have the altivec support disabled
76cabdff1aSopenharmony_ci    // even if the cpu has it.
77cabdff1aSopenharmony_ci    int i, ret = 0;
78cabdff1aSopenharmony_ci    int fd = open("/proc/self/auxv", O_RDONLY);
79cabdff1aSopenharmony_ci    unsigned long buf[64] = { 0 };
80cabdff1aSopenharmony_ci    ssize_t count;
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci    if (fd < 0)
83cabdff1aSopenharmony_ci        return 0;
84cabdff1aSopenharmony_ci
85cabdff1aSopenharmony_ci    while ((count = read(fd, buf, sizeof(buf))) > 0) {
86cabdff1aSopenharmony_ci        for (i = 0; i < count / sizeof(*buf); i += 2) {
87cabdff1aSopenharmony_ci            if (buf[i] == AT_NULL)
88cabdff1aSopenharmony_ci                goto out;
89cabdff1aSopenharmony_ci            if (buf[i] == AT_HWCAP) {
90cabdff1aSopenharmony_ci                if (buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC)
91cabdff1aSopenharmony_ci                    ret = AV_CPU_FLAG_ALTIVEC;
92cabdff1aSopenharmony_ci#ifdef PPC_FEATURE_HAS_VSX
93cabdff1aSopenharmony_ci                if (buf[i + 1] & PPC_FEATURE_HAS_VSX)
94cabdff1aSopenharmony_ci                    ret |= AV_CPU_FLAG_VSX;
95cabdff1aSopenharmony_ci#endif
96cabdff1aSopenharmony_ci                if (ret & AV_CPU_FLAG_VSX)
97cabdff1aSopenharmony_ci                    av_assert0(ret & AV_CPU_FLAG_ALTIVEC);
98cabdff1aSopenharmony_ci            }
99cabdff1aSopenharmony_ci#ifdef AT_HWCAP2 /* not introduced until glibc 2.18 */
100cabdff1aSopenharmony_ci            else if (buf[i] == AT_HWCAP2) {
101cabdff1aSopenharmony_ci#ifdef PPC_FEATURE2_ARCH_2_07
102cabdff1aSopenharmony_ci                if (buf[i + 1] & PPC_FEATURE2_ARCH_2_07)
103cabdff1aSopenharmony_ci                    ret |= AV_CPU_FLAG_POWER8;
104cabdff1aSopenharmony_ci#endif
105cabdff1aSopenharmony_ci            }
106cabdff1aSopenharmony_ci#endif /* AT_HWCAP2 */
107cabdff1aSopenharmony_ci        }
108cabdff1aSopenharmony_ci    }
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ciout:
111cabdff1aSopenharmony_ci    close(fd);
112cabdff1aSopenharmony_ci    return ret;
113cabdff1aSopenharmony_ci#elif CONFIG_RUNTIME_CPUDETECT && defined(__linux__)
114cabdff1aSopenharmony_ci#define PVR_G4_7400  0x000C
115cabdff1aSopenharmony_ci#define PVR_G5_970   0x0039
116cabdff1aSopenharmony_ci#define PVR_G5_970FX 0x003C
117cabdff1aSopenharmony_ci#define PVR_G5_970MP 0x0044
118cabdff1aSopenharmony_ci#define PVR_G5_970GX 0x0045
119cabdff1aSopenharmony_ci#define PVR_POWER6   0x003E
120cabdff1aSopenharmony_ci#define PVR_POWER7   0x003F
121cabdff1aSopenharmony_ci#define PVR_POWER8   0x004B
122cabdff1aSopenharmony_ci#define PVR_CELL_PPU 0x0070
123cabdff1aSopenharmony_ci    int ret = 0;
124cabdff1aSopenharmony_ci    int proc_ver;
125cabdff1aSopenharmony_ci    // Support of mfspr PVR emulation added in Linux 2.6.17.
126cabdff1aSopenharmony_ci    __asm__ volatile("mfspr %0, 287" : "=r" (proc_ver));
127cabdff1aSopenharmony_ci    proc_ver >>= 16;
128cabdff1aSopenharmony_ci    if (proc_ver  & 0x8000 ||
129cabdff1aSopenharmony_ci        proc_ver == PVR_G4_7400  ||
130cabdff1aSopenharmony_ci        proc_ver == PVR_G5_970   ||
131cabdff1aSopenharmony_ci        proc_ver == PVR_G5_970FX ||
132cabdff1aSopenharmony_ci        proc_ver == PVR_G5_970MP ||
133cabdff1aSopenharmony_ci        proc_ver == PVR_G5_970GX ||
134cabdff1aSopenharmony_ci        proc_ver == PVR_POWER6   ||
135cabdff1aSopenharmony_ci        proc_ver == PVR_POWER7   ||
136cabdff1aSopenharmony_ci        proc_ver == PVR_POWER8   ||
137cabdff1aSopenharmony_ci        proc_ver == PVR_CELL_PPU)
138cabdff1aSopenharmony_ci        ret = AV_CPU_FLAG_ALTIVEC;
139cabdff1aSopenharmony_ci    if (proc_ver == PVR_POWER7 ||
140cabdff1aSopenharmony_ci        proc_ver == PVR_POWER8)
141cabdff1aSopenharmony_ci        ret |= AV_CPU_FLAG_VSX;
142cabdff1aSopenharmony_ci    if (proc_ver == PVR_POWER8)
143cabdff1aSopenharmony_ci        ret |= AV_CPU_FLAG_POWER8;
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    return ret;
146cabdff1aSopenharmony_ci#else
147cabdff1aSopenharmony_ci    // Since we were compiled for AltiVec, just assume we have it
148cabdff1aSopenharmony_ci    // until someone comes up with a proper way (not involving signal hacks).
149cabdff1aSopenharmony_ci    return AV_CPU_FLAG_ALTIVEC;
150cabdff1aSopenharmony_ci#endif /* __AMIGAOS4__ */
151cabdff1aSopenharmony_ci#endif /* HAVE_ALTIVEC */
152cabdff1aSopenharmony_ci    return 0;
153cabdff1aSopenharmony_ci}
154cabdff1aSopenharmony_ci
155cabdff1aSopenharmony_cisize_t ff_get_cpu_max_align_ppc(void)
156cabdff1aSopenharmony_ci{
157cabdff1aSopenharmony_ci    int flags = av_get_cpu_flags();
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    if (flags & (AV_CPU_FLAG_ALTIVEC   |
160cabdff1aSopenharmony_ci                 AV_CPU_FLAG_VSX       |
161cabdff1aSopenharmony_ci                 AV_CPU_FLAG_POWER8))
162cabdff1aSopenharmony_ci        return 16;
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    return 8;
165cabdff1aSopenharmony_ci}
166